root/rat/trunk/statistics.c @ 2508

Revision 2508, 21.2 KB (checked in by ucacoxh, 15 years ago)

- Fixed ui update when channel coder changed. Was not check for this
previously.
- Update MODS.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2 * FILE:        statistics.c
3 * PROGRAM:     RAT
4 * AUTHOR(S):   O.Hodson, I.Kouvelas, C.Perkins, D.Miras, and V.J.Hardman
5 *
6 * $Revision$
7 * $Date$
8 *
9 * Copyright (c) 1995-99 University College London
10 * All rights reserved.
11 *
12 */
13
14#include "config_unix.h"
15#include "config_win32.h"
16#include "codec_types.h"
17#include "channel.h"
18#include "convert.h"
19#include "codec.h"
20#include "debug.h"
21#include "memory.h"
22#include "util.h"
23#include "ts.h"
24#include "timers.h"
25#include "session.h"
26#include "source.h"
27#include "timers.h"
28#include "pckt_queue.h"
29#include "rtcp_pckt.h"
30#include "rtcp_db.h"
31#include "audio.h"
32#include "mix.h"
33#include "cushion.h"
34#include "codec.h"
35#include "ui.h"
36#include "statistics.h"
37
38static converter_id_t null_converter;
39
40/* We cache jitter between talkspurts unless we have not heard from
41 * source for discard_jitter_period.
42 */
43
44static ts_t discard_jitter_period;
45
46void
47statistics_init()
48{
49        null_converter        = converter_get_null_converter();
50        discard_jitter_period = ts_map32(8000, 3 * 60 * 8000); /* 3 minutes */
51}
52
53static rtcp_dbentry *
54update_database(session_struct *sp, u_int32 ssrc)
55{
56        rtcp_dbentry   *dbe_source;
57
58        /* This function gets the relevant data base entry */
59        dbe_source = rtcp_get_dbentry(sp, ssrc);
60        if (dbe_source == NULL) {
61                /* We haven't received an RTCP packet for this source,
62                 * so we must throw the packets away. This seems a
63                 * little extreme, but there are actually a couple of
64                 * good reasons for it: 1) If we're receiving
65                 * encrypted data, but we don't have the decryption
66                 * key, then every RTP packet we receive will have a
67                 * different SSRC and if we create a new database
68                 * entry for it, we fill up the database with garbage
69                 * (which is then displayed in the list of
70                 * participants...)  2) The RTP specification says
71                 * that we should do it this way (sec 6.2.1) [csp]
72                 */
73
74                return NULL;
75        }
76
77        dbe_source->last_active = get_time(sp->device_clock);
78        dbe_source->is_sender   = 1;
79
80        sp->db->pckts_received++;
81
82        return dbe_source;
83}
84
85static inline u_int32
86statistics_variable_component(rtcp_dbentry            *src,
87                              session_struct          *sp,
88                              struct s_cushion_struct *cushion)
89{
90        u_int32 var, cush;
91        var = (u_int32) src->jitter * 3;
92
93        debug_msg("var (jitter) %d\n", var);
94       
95        if (var < (unsigned)src->inter_pkt_gap) {
96                var = src->inter_pkt_gap;
97                debug_msg("jitter < pkt_gap -> %d\n", var);
98        }
99       
100        cush = cushion_get_size(cushion);
101        if (var < cush) {
102                var = 3 * cush / 2;
103                debug_msg("cushion %d\n", cushion_get_size(cushion));
104        }
105
106        if (sp->limit_playout) {
107                u_int32 minv, maxv;
108                minv = sp->min_playout * get_freq(src->clock) / 1000;
109                maxv = sp->max_playout * get_freq(src->clock) / 1000;
110                assert(maxv > minv);
111                var = max(minv, var);
112                var = min(maxv, var);
113        }
114
115        return var;
116}
117
118/* Returns new playout timestamp */
119
120static ts_t
121adapt_playout(rtp_hdr_t               *hdr,
122              ts_t                     arr_ts,
123              ts_t                     src_ts,
124              rtcp_dbentry            *src,
125              session_struct          *sp,
126              struct s_cushion_struct *cushion,
127              u_int32                  ntp_time)
128{
129        u_int32 var;
130        int     src_freq;
131        codec_id_t            cid;
132        const codec_format_t *cf;
133        u_int32 ntptime, play_time;
134        u_int32 sendtime = 0;
135        int     ntp_delay = 0;
136        u_int32 rtp_time;
137        ts_t    delay_ts, diff_ts, playout;
138
139        int64 since_last_sr;
140
141        /* This is kind of disgusting ... the device clock is a 64-bit 96kHz
142         * clock.  First map it to a 32-bit timestamp of the source
143         */
144   
145        delay_ts = ts_sub(arr_ts, src_ts);
146
147        /* Keep a note a source freq */
148        src_freq = get_freq(src->clock);
149        assert(src_freq % 8000 == 0 || src_freq % 11025 == 0);
150
151        if (src->first_pckt_flag == TRUE) {
152                src->delay                 = delay_ts;
153                src->delay_in_playout_calc = delay_ts;
154                hdr->m                     = TRUE;
155                cid = codec_get_by_payload(src->enc);
156
157                if ((ts_valid(src->last_arr) == FALSE) ||
158                    (ts_gt(ts_sub(arr_ts, src->last_arr), discard_jitter_period))) {
159                        /* Guess suitable playout only if we have not
160                         *  heard from this source recently... 
161                         */
162                       
163                        if (cid) {
164                                u_int32 spf;
165                                cf = codec_get_format(cid);
166                                spf = codec_get_samples_per_frame(cid);
167                                src->jitter  = 1.0 * (double)spf;
168                                debug_msg("jitter (1 frame) %d\n", (int)src->jitter);
169                        } else {
170                                src->jitter  = 160;
171                                debug_msg("jitter (guess) %d\n", (int)src->jitter);
172                        }
173                }
174        } else {
175                if (hdr->seq != src->last_seq) {
176                        diff_ts      = ts_abs_diff(delay_ts, src->delay);
177                        /* Jitter calculation as in RTP spec */
178                        src->jitter += (((double) diff_ts.ticks - src->jitter) / 16.0);
179#ifdef DEBUG
180                        if (src->jitter == 0) {
181                                debug_msg("Jitter zero\n");
182                        }
183#endif
184                        src->delay = delay_ts;
185                }
186        }
187
188        /*
189         * besides having the lip-sync option enabled, we also need to have
190         * a SR received [dm]
191         */     
192        if (sp->sync_on && src->mapping_valid) {
193                /* calculate delay in absolute (real) time [dm] */ 
194                ntptime = (src->last_ntp_sec & 0xffff) << 16 | src->last_ntp_frac >> 16;
195                if (hdr->ts > src->last_rtp_ts) {
196                        since_last_sr = hdr->ts - src->last_rtp_ts;     
197                } else {
198                        since_last_sr = src->last_rtp_ts - hdr->ts;
199                }
200                since_last_sr = (since_last_sr << 16) / get_freq(src->clock);
201                sendtime = (u_int32)(ntptime + since_last_sr); /* (since_last_sr << 16) / get_freq(src->clock); */
202
203                ntp_delay = ntp_time - sendtime;
204
205                if (src->first_pckt_flag == TRUE) {
206                        src->sync_playout_delay = ntp_delay;
207                }
208        }
209
210        if (hdr->seq > src->last_seq) {
211                /* IF (a) TS start
212                   OR (b) we've thrown 4 consecutive packets away
213                   OR (c) ts have jumped by 8 packets worth
214                   OR (e) a new/empty playout buffer.
215                   THEN adapt playout and communicate it
216                   */
217                if (hdr->m ||
218                    src->cont_toged ||
219                    (hdr->seq - src->last_seq > 8) ) {
220#ifdef DEBUG
221                        if (hdr->m) {
222                                debug_msg("New talkspurt\n");
223                        } else if (src->cont_toged) {
224                                debug_msg("Cont_toged\n");
225                        } else {
226                                debug_msg("Seq jump %ld %ld\n", hdr->seq, src->last_seq);
227                        }
228#endif
229                        var = statistics_variable_component(src, sp, cushion);
230                        debug_msg("var = %d\n", var);
231
232                        if (!ts_eq(src->delay_in_playout_calc, src->delay)) {
233                                debug_msg("Old delay (%u) new delay (%u) delta (%u)\n",
234                                          src->delay_in_playout_calc.ticks,
235                                          src->delay.ticks,
236                                          max(src->delay_in_playout_calc.ticks, src->delay.ticks) -
237                                          min(src->delay_in_playout_calc.ticks, src->delay.ticks));
238                        }
239
240                        src->delay_in_playout_calc = src->delay;
241                       
242                        if (src->first_pckt_flag != TRUE &&
243                            source_get_by_rtcp_dbentry(sp->active_sources, src) != 0) {
244                                /* If playout buffer is not empty
245                                 * or, difference in time stamps is less than 1 sec,
246                                 * we don't want playout point to be before that of existing data.
247                                 */
248                                ts_t new_playout;
249                                new_playout = ts_add(src->delay,
250                                                     ts_map32(src_freq, var));
251                                debug_msg("Buf exists (%u) (%u)\n",
252                                          src->playout.ticks,
253                                          new_playout.ticks);
254                                if (ts_gt(new_playout, src->playout)) {
255                                        src->playout = new_playout;
256                                }
257                        } else {
258                                debug_msg("delay (%lu) var (%lu)\n", src->delay.ticks, var);
259                                src->playout = ts_add(src->delay, ts_map32(src_freq, var));
260                                debug_msg("src playout %lu\n", src->playout.ticks);
261                        }
262
263                        if (sp->sync_on && src->mapping_valid) {
264                                /* use the jitter value as calculated
265                                 * but convert it to a ntp_ts freq
266                                 * [dm] */
267                                src->sync_playout_delay = ntp_delay + ((var << 16) / get_freq(src->clock));
268                               
269                                /* Communicate our playout delay to
270                                   the video tool... */
271                                ui_update_video_playout(sp, src->sentry->ssrc, src->sync_playout_delay);
272               
273                                /* If the video tool is slower than
274                                 * us, then adjust to match it...
275                                 * src->video_playout is the delay of
276                                 * the video in real time */
277                                debug_msg("ad=%d\tvd=%d\n", src->sync_playout_delay, src->video_playout);
278                                if (src->video_playout_received == TRUE &&
279                                    src->video_playout > src->sync_playout_delay) {
280                                        src->sync_playout_delay = src->video_playout;
281                                }
282                        }
283                }
284        }
285        src->last_seq       = hdr->seq;
286
287        /* Calculate the playout point in local source time for this packet. */
288        if (sp->sync_on && src->mapping_valid) {
289                /*     
290                 * Use the NTP to RTP ts mapping to calculate the playout time
291                 * converted to the clock base of the receiver
292                 */
293                play_time = sendtime + src->sync_playout_delay;
294                rtp_time = sp->db->map_rtp_time + (((play_time - sp->db->map_ntp_time) * get_freq(src->clock)) >> 16);
295                playout  = ts_map32(src_freq, rtp_time);
296                src->playout = ts_sub(playout, src_ts);
297        } else {
298                playout = ts_add(src_ts, src->playout);
299        }
300
301        if (src->cont_toged > 12) {
302                /* something has gone wrong if this assertion fails*/
303                if (!ts_gt(playout, ts_map32(src_freq, get_time(src->clock)))) {
304                        debug_msg("playout before now.\n");
305                        src->first_pckt_flag = TRUE;
306                }
307        }
308
309        src->first_pckt_flag = FALSE;
310
311        return playout;
312}
313
314static int
315rtp_header_validation(rtp_hdr_t *hdr, int32 *len, int *extlen)
316{
317        /* This function checks the header info to make sure that the packet */
318        /* is valid. We return TRUE if the packet is valid, FALSE otherwise. */
319        /* This follows from page 52 of RFC1889.            [csp 22-10-1996] */
320
321        /* We only accept RTPv2 packets... */
322        if (hdr->type != 2) {
323                debug_msg("rtp_header_validation: version != 2\n");
324                return FALSE;
325        }
326
327        /* Check for valid audio payload types... */
328        if (((hdr->pt > 23) && (hdr->pt < 96)) || (hdr->pt > 127)) {
329                debug_msg("rtp_header_validation: payload-type out of audio range\n");
330                return FALSE;
331        }
332
333        /* If padding or header-extension is set, we punt on this one... */
334        /* We should really deal with it though...                       */
335        if (hdr->p) {
336                int pad = *((unsigned char *)hdr + *len - 1);
337                if (pad < 1) {
338                        debug_msg("rtp_header_validation: padding but 0 len\n");
339                        return FALSE;
340                }
341                *len -= pad;
342        }
343
344        if (hdr->x) {
345                *extlen = *((u_int32*)((unsigned char*)hdr + 4*(3+hdr->cc)))&0x0000ffff;
346        } else {
347                *extlen = 0;
348        }
349
350        return (TRUE);
351}
352
353static int
354statistics_channel_extract(session_struct     *sp,
355                           rtcp_dbentry       *dbe,
356                           const audio_format *afout,
357                           u_int8              pt,
358                           u_char*             data,
359                           u_int32             len)
360{
361        cc_id_t ccid;
362        const codec_format_t *cf;
363        codec_id_t            id;
364        u_int16 upp;
365        u_int8  codec_pt;
366        assert(dbe != NULL);
367
368        ccid = channel_coder_get_by_payload(pt);
369        if (!ccid) {
370                debug_msg("No channel decoder\n");
371                return FALSE;
372        }
373
374        if (!channel_verify_and_stat(ccid,pt,data,len,&upp,&codec_pt)) {
375                debug_msg("Failed verify and stat\n");
376                return FALSE;
377        }
378
379        if (dbe->units_per_packet != upp) {
380                dbe->units_per_packet = upp;
381                dbe->update_req       = TRUE;
382        }
383
384        id = codec_get_by_payload(codec_pt);
385        cf = codec_get_format(id);
386
387        if (mix_compatible(sp->ms, cf->format.sample_rate, cf->format.channels) == FALSE) {
388
389                /* Won't go into mixer without some form of
390                 * conversion.  converter will convert sample_rate and
391                 * sample_channels if enabled and 3d renderer will
392                 * convert number of channels from 1 to 2 if enabled
393                 */
394               
395                if (sp->converter == null_converter &&
396                    !(sp->render_3d == TRUE &&
397                      cf->format.sample_rate == afout->sample_rate &&
398                      afout->channels == 2)) {
399                       
400                        debug_msg("Rejected - needs sample rate conversion\n");
401                        return FALSE;
402                }
403        }
404
405        if (dbe->channel_coder_id != ccid) {
406                debug_msg("Channel coding changed\n");
407                dbe->channel_coder_id = ccid;
408                dbe->update_req = TRUE;
409        }
410
411
412        if (dbe->enc != codec_pt) {
413                debug_msg("Format changed\n");
414                change_freq(dbe->clock, cf->format.sample_rate);
415                dbe->enc             = codec_pt;
416                dbe->inter_pkt_gap   = dbe->units_per_packet * (u_int16)codec_get_samples_per_frame(id);
417                dbe->first_pckt_flag = TRUE;
418                dbe->update_req      = TRUE;
419        }
420
421        if (dbe->update_req) {
422                /* Format len must be long enough for at least 2
423                 * redundant encodings, a separator and a zero */
424                int fmt_len = 2 * CODEC_LONG_NAME_LEN + 2;
425                if (dbe->enc_fmt == NULL) {
426                        dbe->enc_fmt = (char*)xmalloc(fmt_len);
427                }
428                channel_describe_data(ccid, pt, data, len, dbe->enc_fmt, fmt_len);
429                ui_update_stats(sp, dbe);
430                dbe->update_req = FALSE;
431        }
432
433        return TRUE;
434}
435
436void
437statistics_process(session_struct          *sp,
438                   struct s_pckt_queue     *rtp_pckt_queue,
439                   struct s_cushion_struct *cushion,
440                   u_int32                  ntp_time,
441                   ts_t                     curr_ts)
442{
443        /*
444         * We expect to take in an RTP packet, and decode it - read fields
445         * etc. This module should do statistics, and keep information on
446         * losses, and re-orderings. Duplicates will be dealt with in the
447         * receive buffer module.
448         *
449         * Late packets will not be counted as lost. RTP stats reports count
450         * duplicates in with the number of packets correctly received, thus
451         * sometimes invalidating stats reports. We can, if necessary, keep
452         * track of some duplicates, and throw away in the receive module. It
453         * has not yet been decided whether or not loss will be 'indicated'
454         * to later modules - put a dummy unit(s) on the queue for the receive
455         * buffer
456         *
457         */
458
459        ts_t                  arr_ts, src_ts;
460
461        rtp_hdr_t            *hdr;
462        u_char               *data_ptr;
463        int                   len;
464        rtcp_dbentry         *sender = NULL;
465        const audio_format   *afout;
466
467        pckt_queue_element *pckt;
468        struct s_source *src;
469        int pkt_cnt = 0;
470
471        afout = audio_get_ofmt(sp->audio_device);
472
473        /* Process incoming packets */
474        while( (pckt = pckt_dequeue(rtp_pckt_queue)) != NULL ) {
475                pkt_cnt++;
476                block_trash_check();
477                /* Impose RTP formating on it... */
478                hdr = (rtp_hdr_t *) (pckt->pckt_ptr);
479       
480                if (rtp_header_validation(hdr, &pckt->len, (int*)&pckt->extlen) == FALSE) {
481                        debug_msg("RTP Packet failed header validation!\n");
482                        block_trash_check();
483                        goto release;
484                }
485
486                if (sp->playing_audio == FALSE) {
487                        /* Don't decode audio if we are not playing it! */
488                        goto release;
489                }
490       
491                /* Convert from network byte-order */
492                hdr->seq  = ntohs(hdr->seq);
493                hdr->ts   = ntohl(hdr->ts);
494                hdr->ssrc = ntohl(hdr->ssrc);
495       
496                if ((hdr->ssrc == sp->db->myssrc) && sp->filter_loopback) {
497                        /* Discard loopback packets...unless we have asked for them ;-) */
498                        block_trash_check();
499                        goto release;
500                }
501       
502                /* Get database entry of participant that sent this packet */
503                sender = update_database(sp, hdr->ssrc);
504                if (sender == NULL) {
505                        debug_msg("Packet from unknown participant discarded\n");
506                        goto release;
507                }
508                if (sender->mute) {
509                        debug_msg("Packet to muted participant discarded\n");
510                        goto release;
511                }
512
513                rtcp_update_seq(sender, hdr->seq);
514
515                if (hdr->cc) {
516                        int k;
517                        for(k = 0; k < hdr->cc; k++) {
518                                update_database(sp, ntohl(hdr->csrc[k]));
519                        }
520                }
521
522                data_ptr =  (unsigned char *)pckt->pckt_ptr + 4 * (3 + hdr->cc) + pckt->extlen;
523                len      = pckt->len - 4 * (3 + hdr->cc) - pckt->extlen;
524
525                if (statistics_channel_extract(sp,
526                                               sender,
527                                               afout,
528                                               (u_char)hdr->pt,
529                                               data_ptr,
530                                               (u_int32)len) == FALSE) {
531                        debug_msg("Failed channel check\n");
532                        goto release;
533                }
534
535                pckt->sender  = sender;
536
537                if ((src = source_get_by_rtcp_dbentry(sp->active_sources,
538                                                      pckt->sender)) == NULL) {
539                        ui_info_activate(sp, pckt->sender);
540                        src = source_create(sp->active_sources,
541                                            pckt->sender,
542                                            sp->converter,
543                                            sp->render_3d,
544                                            (u_int16)afout->sample_rate,
545                                            (u_int16)afout->channels);
546                        assert(src != NULL);
547                }
548
549                arr_ts = pckt->arrival;
550
551                /* Convert originator timestamp in ts_t */
552                src_ts = ts_seq32_in(source_get_sequencer(src),
553                                     get_freq(sender->clock),
554                                     hdr->ts);
555
556                pckt->playout = adapt_playout(hdr,
557                                              arr_ts,
558                                              src_ts,
559                                              sender,
560                                              sp,
561                                              cushion,
562                                              ntp_time);
563
564                if (source_add_packet(src,
565                                      pckt->pckt_ptr,
566                                      pckt->len,
567                                      data_ptr - pckt->pckt_ptr,
568                                      (u_char)hdr->pt,
569                                      pckt->playout) == TRUE) {
570                        /* Source is now repsonsible for packet so
571                         * empty pointers */
572                        pckt->pckt_ptr = NULL;
573                        pckt->len      = 0;
574                }
575
576                sender->last_arr = curr_ts;
577        release:
578                block_trash_check();
579                pckt_queue_element_free(&pckt);
580        }
581
582        if (pkt_cnt > 5) {
583                debug_msg("Processed lots of packets(%d).\n", pkt_cnt);
584        }
585}
Note: See TracBrowser for help on using the browser.