root/rat/trunk/statistics.c @ 1708

Revision 1708, 17.3 KB (checked in by ucacmir, 16 years ago)

*** empty log message ***

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2 * FILE:        statistics.c
3 *
4 * PROGRAM:     RAT
5 *
6 * AUTHOR: V.J.Hardman + I.Kouvelas + O.Hodson
7 *
8 * CREATED: 23/03/95
9 *
10 * $Id$
11 *
12 * Copyright (c) 1995-98 University College London
13 * All rights reserved.
14 *
15 * Redistribution and use in source and binary forms, with or without
16 * modification, is permitted, for non-commercial use only, provided
17 * that the following conditions are met:
18 * 1. Redistributions of source code must retain the above copyright
19 *    notice, this list of conditions and the following disclaimer.
20 * 2. Redistributions in binary form must reproduce the above copyright
21 *    notice, this list of conditions and the following disclaimer in the
22 *    documentation and/or other materials provided with the distribution.
23 * 3. All advertising materials mentioning features or use of this software
24 *    must display the following acknowledgement:
25 *      This product includes software developed by the Computer Science
26 *      Department at University College London
27 * 4. Neither the name of the University nor of the Department may be used
28 *    to endorse or promote products derived from this software without
29 *    specific prior written permission.
30 * Use of this software for commercial purposes is explicitly forbidden
31 * unless prior written permission is obtained from the authors.
32 *
33 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
34 * ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
35 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
36 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
37 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
38 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
39 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
40 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
41 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
42 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
43 * SUCH DAMAGE.
44 */
45
46#include "statistics.h"
47#include "session.h"
48#include "receive.h"
49#include "interfaces.h"
50#include "rtcp_pckt.h"
51#include "rtcp_db.h"
52#include "util.h"
53#include "audio.h"
54#include "cushion.h"
55#include "speaker_table.h"
56#include "codec.h"
57#include "channel.h"
58#include "ui_control.h"
59#include "mbus.h"
60
61static rtcp_dbentry *
62update_database(session_struct *sp, u_int32 ssrc, u_int32 cur_time)
63{
64        rtcp_dbentry   *dbe_source;
65
66        /* This function gets the relevant data base entry */
67        dbe_source = rtcp_get_dbentry(sp, ssrc);
68        if (dbe_source == NULL) {
69                /* We haven't received an RTCP packet for this source, so we must throw the   */
70                /* packets away. This seems a little extreme, but there are actually a couple */
71                /* of good reasons for it:                                                    */
72                /*   1) If we're receiving encrypted data, but we don't have the decryption   */
73                /*      key, then every RTP packet we receive will have a different SSRC      */
74                /*      and if we create a new database entry for it, we fill up the database */
75                /*      with garbage (which is then displayed in the list of participants...) */
76                /*   2) The RTP specification says that we should do it this way (sec 6.2.1)  */
77                /*                                                                     [csp]  */
78                return NULL;
79        }
80        dbe_source->last_active = cur_time;
81        dbe_source->is_sender   = 1;
82
83        sp->db->pckts_received++;
84
85        return dbe_source;
86}
87
88static int
89split_block(u_int32 playout_pt,
90            codec_t *cp,
91            char *data_ptr,
92            int len,
93            rtcp_dbentry *src,
94            rx_queue_struct *unitsrx_queue_ptr,
95            int talks,
96            rtp_hdr_t *hdr,
97            session_struct *sp,
98            u_int32 cur_time)
99{
100        int     units, i, j, k, trailing;
101        rx_queue_element_struct *p;
102        cc_unit *ccu;
103
104        /* we no longer break data units across rx elements here.
105         * instead we leave channel coded data in first block and
106         * remove channel coding when we are ready to decode and play
107         * samples.
108         */
109
110        ccu = (cc_unit*)block_alloc(sizeof(cc_unit));
111        memset(ccu,0,sizeof(cc_unit));
112        block_trash_chk();
113        units = validate_and_split(hdr->pt, data_ptr, len, ccu, &trailing, &src->inter_pkt_gap);
114        block_trash_chk();
115        if (units <=0) {
116                debug_msg("Validate and split failed!\n");
117                block_free(ccu,sizeof(cc_unit));
118                return 0;
119        }
120
121        for(i=0;i<ccu->iovc;i++) {
122                ccu->iov[i].iov_base = (caddr_t)block_alloc(ccu->iov[i].iov_len);
123                memcpy(ccu->iov[i].iov_base,
124                       data_ptr,
125                       ccu->iov[i].iov_len);
126                data_ptr += ccu->iov[i].iov_len;
127        }
128
129        for(i=0;i<trailing;i++) {
130                p = new_rx_unit();
131                p->unit_size        = cp->unit_len;
132                p->units_per_pckt   = units;
133                p->mixed            = FALSE;
134                p->dbe_source[0]    = src;
135                p->playoutpt        = playout_pt + i * cp->unit_len;
136                p->src_ts           = hdr->ts + i * cp->unit_len;
137                p->comp_count       = 0;
138                p->cc_pt            = ccu->cc->pt;
139                for (j = 0, k = 1; j < hdr->cc; j++) {
140                        p->dbe_source[k] = update_database(sp, ntohl(hdr->csrc[j]), cur_time);
141                        if (p->dbe_source[k] != NULL) {
142                                mark_active_sender(p->dbe_source[k], sp);
143                                k++;
144                        }
145                }
146                p->dbe_source_count = k;
147                p->native_count = 0;
148                if (i == 0) {
149                    p->ccu[0]  = ccu;
150                    p->ccu_cnt = 1;
151                    p->talk_spurt_start = talks;
152                } else {
153                    p->ccu[0]  = NULL;
154                    p->ccu_cnt = 0;
155                    p->talk_spurt_start = FALSE;
156                }
157                put_on_rx_queue(p, unitsrx_queue_ptr);
158        }
159        mark_active_sender(src, sp);
160        return (units);
161}
162
163
164static u_int32
165adapt_playout(rtp_hdr_t *hdr,
166              int arrival_ts,
167              rtcp_dbentry *src,
168              session_struct *sp,
169              struct s_cushion_struct *cushion,
170              u_int32 cur_time,
171              u_int32 real_time)
172{
173        u_int32 playout, var;
174        u_int32 minv, maxv;
175
176        int     delay, diff;
177        codec_t *cp;
178        u_int32 ntptime, sendtime, play_time;
179        int     ntp_delay;
180        u_int32 rtp_time;
181       
182        arrival_ts = convert_time(arrival_ts, sp->device_clock, src->clock);
183        delay = arrival_ts - hdr->ts;
184       
185        if (src->first_pckt_flag == TRUE) {
186                src->first_pckt_flag = FALSE;
187                diff                 = 0;
188                src->delay           = delay;
189                src->jitter          = 80;
190                src->last_ts         = hdr->ts - 1;
191                src->playout_ceil    = 0;
192                hdr->m               = TRUE;
193                src->msgno = 0;
194        } else {
195                diff       = abs(delay - src->delay);
196                src->delay = delay;
197                /* Jitter calculation as in RTP spec */
198                src->jitter = src->jitter + (((double) diff - src->jitter) / 16);
199        }
200
201        if (sp->sync_on) {
202                //real_time = ntp_time32(); /* cur_time should be passed be adapt_playout instead [dm] */
203                /* calculate delay in absolute (real) time [dm] */ 
204                ntptime = (src->last_ntp_sec & 0xffff) << 16 | src->last_ntp_frac >> 16;
205                if (hdr->ts > src->last_rtp_ts) {
206#ifdef WIN32
207                        sendtime = ntptime + ((__int64)(hdr->ts - src->last_rtp_ts) << 16) / get_freq(src->clock);
208#else
209                        sendtime = ntptime + ((long long)(hdr->ts - src->last_rtp_ts) << 16) / get_freq(src->clock);
210#endif
211                }
212/*              else {
213                        sendtime = ntptime + ((long long)(src->last_rtp_ts - hdr->ts) << 16) / get_freq(src->clock);
214                }
215*/
216                ntp_delay = real_time - sendtime;
217                if (src->first_pckt_flag == TRUE) {
218                        src->sync_playout_delay = ntp_delay;
219                }
220        }
221
222        if (ts_gt(hdr->ts, src->last_ts)) {
223                cp = get_codec(src->enc);
224                /* IF (a) TS start
225                   OR (b) we've thrown 4 consecutive packets away
226                   OR (c) ts have jumped by 8 packets worth
227                   OR (d) playout buffer running dry.
228                   THEN adapt playout and communicate it
229                   */
230                if ((hdr->m) ||
231                    src->cont_toged > 4 ||
232                    ts_gt(hdr->ts, (src->last_ts + (hdr->seq - src->last_seq) * src->inter_pkt_gap * 8 + 1)) ||
233                    src->playout_danger) {
234#ifdef DEBUG
235                        if (hdr->m) {
236                                debug_msg("New talkspurt\n");
237                        } else if (src->cont_toged > 4) {
238                                debug_msg("Cont_toged > 4\n");
239                        } else if (src->playout_danger) {
240                                debug_msg("playout danger\n");
241                        } else {
242                                debug_msg("Time stamp jump %ld %ld\n", hdr->ts, src->last_ts);
243                        }
244#endif
245                        var = (u_int32) src->jitter * 3;
246
247                        minv = sp->min_playout * get_freq(src->clock) / 1000;
248                        maxv = sp->max_playout * get_freq(src->clock) / 1000;
249
250                        assert(maxv > minv);
251                        if (sp->limit_playout) {
252                                var = max(minv, var);
253                                var = min(maxv, var);
254                        }
255
256                        var += cushion_get_size(cushion);
257                        if (src->clock!=sp->device_clock) {
258                                var += cp->unit_len;
259                        }
260
261                        assert(var > 0);
262                        src->playout = src->delay + var;
263
264                        if (sp->sync_on) {
265                                /* use the jitter value as calculated but convert it to a ntp_ts freq [dm] */ 
266                                src->sync_playout_delay = ntp_delay + ((var << 16) / get_freq(src->clock));
267                               
268                                /* Communicate our playout delay to the video tool... */
269                                ui_update_video_playout(src->sentry->cname, src->sync_playout_delay);
270               
271                                /* If the video tool is slower than us, then
272                                 * adjust to match it...  src->video_playout is
273                                 * the delay of the video in real time
274                                */
275                                printf("ad=%d\tvd=%d\n", src->sync_playout_delay, src->video_playout);
276                                if (src->video_playout_received == TRUE &&
277                                    src->video_playout > src->sync_playout_delay) {
278                                        src->sync_playout_delay = src->video_playout;
279                                }
280
281                        }
282                } else {
283                        /* Do not set encoding on TS start packets as they do not show if redundancy is used...   */
284                        /*      src->encoding = hdr->pt; */
285                }
286                src->last_ts        = hdr->ts;
287                src->last_seq       = hdr->seq;
288                src->playout_danger = FALSE;
289        }
290
291        /* Calculate the playout point in local source time for this packet. */
292        if (sp->sync_on) {
293                /*     
294                 * Use the NTP to RTP ts mapping to calculate the playout time converted to
295                 * the clock base of the receiver
296                 */
297                play_time = sendtime + src->sync_playout_delay;
298                rtp_time = sp->db->map_rtp_time + (((play_time - sp->db->map_ntp_time) * get_freq(src->clock)) >> 16);
299                playout = rtp_time;
300                src->playout = playout - hdr->ts;
301        }
302        else {
303                playout = hdr->ts + src->playout;
304        }
305
306        if (src->playout - src->delay > src->playout_ceil) {
307                src->playout_ceil = src->playout - src->delay;
308        }
309
310        if (src->cont_toged > 12) {
311                /* something has gone wrong if this assertion fails*/
312                if (playout < get_time(src->clock)) {
313                        debug_msg("playout before now.\n");
314                        src->first_pckt_flag = TRUE;
315                }
316        }
317        return playout;
318}
319
320static int
321rtp_header_validation(rtp_hdr_t *hdr, int *len, int *extlen)
322{
323        /* This function checks the header info to make sure that the packet */
324        /* is valid. We return TRUE if the packet is valid, FALSE otherwise. */
325        /* This follows from page 52 of RFC1889.            [csp 22-10-1996] */
326
327        /* We only accept RTPv2 packets... */
328        if (hdr->type != 2) {
329                debug_msg("rtp_header_validation: version != 2\n");
330                return FALSE;
331        }
332
333        /* Check for valid audio payload types... */
334        if (((hdr->pt > 23) && (hdr->pt < 96)) || (hdr->pt > 127)) {
335                debug_msg("rtp_header_validation: payload-type out of audio range\n");
336                return FALSE;
337        }
338
339        /* If padding or header-extension is set, we punt on this one... */
340        /* We should really deal with it though...                       */
341        if (hdr->p) {
342                int pad = *((unsigned char *)hdr + *len - 1);
343                if (pad < 1) {
344                        debug_msg("rtp_header_validation: padding but 0 len\n");
345                        return FALSE;
346                }
347                *len -= pad;
348        }
349
350        if (hdr->x) {
351                *extlen = *((u_int32*)((unsigned char*)hdr + 4*(3+hdr->cc)))&0x0000ffff;
352        } else {
353                *extlen = 0;
354        }
355
356        return (TRUE);
357}
358
359static void
360receiver_change_format(rtcp_dbentry *dbe, codec_t *cp)
361{
362        debug_msg("Changing Format. %d %d\n", dbe->enc, cp->pt);
363        dbe->first_pckt_flag = TRUE;
364        dbe->enc             = cp->pt;
365        change_freq(dbe->clock, cp->freq);
366
367
368void
369statistics(session_struct    *sp,
370           pckt_queue_struct *netrx_pckt_queue,
371           rx_queue_struct   *unitsrx_queue_ptr,
372           struct s_cushion_struct    *cushion,
373           u_int32       cur_time,
374           u_int32       real_time)
375{
376        /*
377         * We expect to take in an RTP packet, and decode it - read fields
378         * etc. This module should do statistics, and keep information on
379         * losses, and re-orderings. Duplicates will be dealt with in the
380         * receive buffer module.
381         *
382         * Late packets will not be counted as lost. RTP stats reports count
383         * duplicates in with the number of packets correctly received, thus
384         * sometimes invalidating stats reports. We can, if necessary, keep
385         * track of some duplicates, and throw away in the receive module. It
386         * has not yet been decided whether or not loss will be 'indicated'
387         * to later modules - put a dummy unit(s) on the queue for the receive
388         * buffer
389         */
390
391        rtp_hdr_t       *hdr;
392        u_char          *data_ptr;
393        int             len,extlen,compat;
394        rtcp_dbentry    *src;
395        u_int32         playout_pt;
396        pckt_queue_element_struct *e_ptr;
397        codec_t         *pcp;
398
399        char update_req = FALSE;
400
401        /* Process an incoming packets */
402        while(netrx_pckt_queue->queue_empty == FALSE) {
403                e_ptr = get_pckt_off_queue(netrx_pckt_queue);
404                /* Impose RTP formating on it... */
405                hdr = (rtp_hdr_t *) (e_ptr->pckt_ptr);
406       
407                if (rtp_header_validation(hdr, &e_ptr->len, &extlen) == FALSE) {
408                        debug_msg("RTP Packet failed header validation!\n");
409                        /* XXX log as bad packet */
410                        goto release;
411                }
412       
413                /* Convert from network byte-order */
414                hdr->seq  = ntohs(hdr->seq);
415                hdr->ts   = ntohl(hdr->ts);
416                hdr->ssrc = ntohl(hdr->ssrc);
417       
418                if ((hdr->ssrc == sp->db->myssrc) &&
419                    sp->filter_loopback) {
420                        /* Discard loopback packets...unless we have asked for them ;-) */
421                        goto release;
422                }
423       
424                /* Get database entry of participant that sent this packet */
425                src = update_database(sp, hdr->ssrc, cur_time);
426                if (src == NULL) {
427                        debug_msg("Packet from unknown participant\n");
428                        /* Discard packets from unknown participant */
429                        goto release;
430                }
431                rtcp_update_seq(src, hdr->seq);
432
433                if (sp->have_device == FALSE) {
434                        /* we don't have the audio device so there is no point
435                         * processing data any further.
436                         */
437                        goto release;
438                }
439
440                data_ptr =  (unsigned char *)e_ptr->pckt_ptr + 4 * (3 + hdr->cc) + extlen;
441                len      = e_ptr->len - 4 * (3 + hdr->cc) - extlen;
442       
443                if (!(pcp = get_codec(hdr->pt))) {
444                        /* this is either a channel coded block or we can't decode it */
445                        if (!(pcp = get_codec(get_wrapped_payload(hdr->pt, (char *) data_ptr, len)))) {
446                                debug_msg("Cannot decode data.\n");
447                                goto release;
448                        }
449                }
450       
451                compat = codec_compatible(pcp, get_codec(sp->encodings[0]));
452                if (!compat && !sp->auto_convert) {
453                        debug_msg("Format conversion not enabled (%s received).\n", pcp->name);
454                        goto release;
455                }
456               
457                if ((src->enc == -1) || (src->enc != pcp->pt))
458                        receiver_change_format(src, pcp);
459               
460                if (src->enc != pcp->pt) {
461                        /* we should tell update more about coded format */
462                        src->enc = pcp->pt;
463                        debug_msg("src enc %d pcp enc %d\n", src->enc, pcp->pt);
464                        update_req   = TRUE;
465                }
466               
467                playout_pt = adapt_playout(hdr, e_ptr->arrival_timestamp, src, sp, cushion, cur_time, real_time);
468                src->units_per_packet = split_block(playout_pt, pcp, (char *) data_ptr, len, src, unitsrx_queue_ptr, hdr->m, hdr, sp, cur_time);
469               
470                if (!src->units_per_packet) {
471                        goto release;
472                }
473       
474                if (update_req) ui_update_stats(src, sp);
475        release:
476                free_pckt_queue_element(&e_ptr);
477        }
478}
Note: See TracBrowser for help on using the browser.