root/rat/trunk/rtp_callback.c @ 3126

Revision 3126, 10.0 KB (checked in by ucacoxh, 14 years ago)

- Filter junk rtt values. (Little endian VAT does not interop with

big endian machines).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2 * FILE:    rtp_callback.c
3 * PROGRAM: RAT
4 * AUTHOR:  Colin Perkins / Orion Hodson
5 *
6 * Copyright (c) 1999-2000 University College London
7 * All rights reserved.
8 */
9 
10#ifndef HIDE_SOURCE_STRINGS
11static const char cvsid[] =
12        "$Id$";
13#endif /* HIDE_SOURCE_STRINGS */
14
15#include "config_unix.h"
16#include "config_win32.h"
17#include "debug.h"
18#include "audio_types.h"
19#include "auddev.h"
20#include "channel.h"
21#include "codec.h"
22#include "rtp.h"
23#include "ntp.h"
24#include "session.h"
25#include "cushion.h"
26#include "pdb.h"
27#include "source.h"
28#include "playout_calc.h"
29#include "util.h"
30#include "ui.h"
31
32#include "rtp_callback.h"
33
34/* We need to be able to resolve the rtp session to a rat session in */
35/* order to get persistent participant information, etc.  We use a   */
36/* double linked list with sentinel for this.  We normally don't     */
37/* expect to have more than 2 sessions (i.e. transcoder mode), but   */
38/* layered codecs may require more.                                  */
39
40typedef struct s_rtp_assoc {
41        struct s_rtp_assoc *next;
42        struct s_rtp_assoc *prev;
43        struct rtp         *rtps;
44        struct s_session   *rats;
45} rtp_assoc_t;
46
47/* Sentinel for linked list that is used as small associative array */
48static rtp_assoc_t rtp_as;
49static int rtp_as_inited;
50
51void 
52rtp_callback_init(struct rtp *rtps, struct s_session *rats)
53{
54        rtp_assoc_t *cur, *sentinel;
55
56        if (!rtp_as_inited) {
57                /* First pass sentinel initialization */
58                rtp_as.next = &rtp_as;
59                rtp_as.prev = &rtp_as;
60                rtp_as_inited = 1;
61        }
62
63        sentinel = &rtp_as;
64        cur   = sentinel->next;
65
66        while (cur != sentinel) {
67                if (cur->rtps == rtps) {
68                        /* Association already exists, over-riding */
69                        cur->rats = rats;
70                        return;
71                }
72        }
73
74        cur = (rtp_assoc_t*)xmalloc(sizeof(rtp_assoc_t));
75        cur->rtps   = rtps;
76        cur->rats   = rats;
77
78        cur->next       = sentinel->next;
79        cur->prev       = sentinel;
80        cur->next->prev = cur;
81        cur->prev->next = cur;
82}
83
84void rtp_callback_exit(struct rtp *rtps)
85{
86        rtp_assoc_t *cur, *sentinel;
87       
88        sentinel = &rtp_as;
89        cur = sentinel->next;
90        while(cur != sentinel) {
91                if (cur->rtps == rtps) {
92                        cur->prev->next = cur->next;
93                        cur->next->prev = cur->prev;
94                        xfree(cur);
95                        return;
96                }
97                cur = cur->next;
98        }
99}
100
101/* get_session maps an rtp_session to a rat session */
102static struct s_session *
103get_session(struct rtp *rtps)
104{
105        rtp_assoc_t *cur, *sentinel;
106
107        if (!rtp_as_inited) {
108                return NULL;
109        }
110       
111        sentinel = &rtp_as;
112        cur = sentinel->next;
113        while(cur != sentinel) {
114                if (cur->rtps == rtps) {
115                        return cur->rats;
116                }
117                cur = cur->next;
118        }       
119        return NULL;
120}
121
122/* Callback utility functions                                                */
123
124/* rtp_rtt_calc return rtt estimate in seconds */
125static double 
126rtp_rtt_calc(uint32_t arr, uint32_t dep, uint32_t delay)
127{
128        uint32_t delta;
129
130        /* rtt = arr - dep - delay */
131        debug_msg("rtt arr - dep %lu  delay %lu\n", arr - dep, delay);
132        delta = ntp32_sub(arr,   dep);
133        delta = ntp32_sub(delta, delay);
134        /*
135         * 16 high order bits are seconds
136         * 16 low order bits are 1/65536 of sec
137         */
138        return  (double)((delta >> 16) & 0xffff) +
139                (double)(delta & 0xffff) / 65536.0;
140}
141
142static void
143process_rtp_data(session_t *sp, uint32_t ssrc, rtp_packet *p)
144{
145        struct s_source *s;
146        pdb_entry_t     *e;
147
148        if (sp->filter_loopback && ssrc == rtp_my_ssrc(sp->rtp_session[0])) {
149                /* This packet is from us and we are filtering our own       */
150                /* packets.                                                  */
151                xfree(p);
152                return;
153        }
154
155        if (pdb_item_get(sp->pdb, ssrc, &e) == FALSE) {
156                debug_msg("Packet discarded: unknown source (0x%08x).\n", ssrc);
157                xfree(p);
158                return;
159        }
160        e->received++;
161       
162        s = source_get_by_ssrc(sp->active_sources, ssrc);
163        if (s == NULL) {
164                s = source_create(sp->active_sources, ssrc, sp->pdb);
165                ui_info_activate(sp, ssrc);
166                debug_msg("Source created\n");
167        }
168
169        /* Calculate the relative playout delay, for this source. Needed for lip-sync. */
170
171        /* Discard packet if output is muted... no point wasting time decoding it... */
172        if ((sp->playing_audio == FALSE) || (e->mute)) {
173                debug_msg("Packet discarded since output muted\n");
174                xfree(p);
175                return;
176        }
177
178        /* Remove any padding */
179        if (p->p) {
180                p->data_len -= p->data[p->data_len - 1];
181                p->p = 0;
182        }
183        source_add_packet(s, p);
184}
185
186static void
187process_rr(session_t *sp, uint32_t ssrc, rtcp_rr *r)
188{
189        pdb_entry_t  *e;
190        uint32_t fract_lost, my_ssrc;
191
192        /* Calculate rtt estimate */
193        my_ssrc =  rtp_my_ssrc(sp->rtp_session[0]);
194        if (r->ssrc == my_ssrc &&
195            r->ssrc != ssrc    && /* filter self reports */
196            pdb_item_get(sp->pdb, ssrc, &e) &&
197            r->lsr != 0) {
198                uint32_t ntp_sec, ntp_frac, ntp32;
199                double rtt;
200                ntp64_time(&ntp_sec, &ntp_frac);
201                ntp32 = ntp64_to_ntp32(ntp_sec, ntp_frac);
202               
203                rtt = rtp_rtt_calc(ntp32, r->lsr, r->dlsr);
204                /*
205                 * Filter out blatantly wrong rtt values.  Some tools might not
206                 * implement dlsr and lsr (broken) or forget to do byte-swapping (grr)
207                 */
208                if (rtt < 100.0) {
209                        e->last_rtt = rtt;
210                } else {
211                        debug_msg("Junk rtt (%f secs) - receiver rtp misimplementation?\n");
212                }
213                if (e->avg_rtt == 0.0) {
214                        e->avg_rtt = e->last_rtt;
215                } else {
216                        e->avg_rtt += (e->last_rtt - e->avg_rtt) / 8.0;
217                }
218                if (sp->mbus_engine != NULL) {
219                        ui_update_rtt(sp, ssrc, e->avg_rtt);
220                }
221        }
222
223        /* Update loss stats */
224        if (sp->mbus_engine != NULL) {
225                fract_lost = (r->fract_lost * 100) >> 8;
226                ui_update_loss(sp, ssrc, r->ssrc, fract_lost);
227        }
228}
229
230static void
231process_rr_timeout(session_t *sp, uint32_t ssrc, rtcp_rr *r)
232{
233        /* Just update loss statistic in UI for this report if there */
234        /* is somewhere to send them.                                */
235        if (sp->mbus_engine != NULL) {
236                ui_update_loss(sp, ssrc, r->ssrc, 101);
237        }
238}
239
240static void
241process_sdes(session_t *sp, uint32_t ssrc, rtcp_sdes_item *d)
242{
243        pdb_entry_t *e;
244
245        assert(pdb_item_get(sp->pdb, ssrc, &e) == TRUE);
246
247        if (sp->mbus_engine == NULL) {
248                /* Nowhere to send updates to, so ignore them.               */
249                return;
250        }
251
252        switch(d->type) {
253        case RTCP_SDES_END:
254                /* This is the end of the SDES list of a packet.  Nothing    */
255                /* for us to deal with.                                      */
256                break;
257        case RTCP_SDES_CNAME:
258                ui_info_update_cname(sp, ssrc);
259                break;
260        case RTCP_SDES_NAME:
261                ui_info_update_name(sp, ssrc);
262                break;
263        case RTCP_SDES_EMAIL:
264                ui_info_update_email(sp, ssrc);
265                break;
266        case RTCP_SDES_PHONE:
267                ui_info_update_phone(sp, ssrc);
268                break;
269        case RTCP_SDES_LOC:
270                ui_info_update_loc(sp, ssrc);
271                break;
272        case RTCP_SDES_TOOL:
273                ui_info_update_tool(sp, ssrc);
274                break;
275        case RTCP_SDES_NOTE:
276                ui_info_update_note(sp, ssrc);
277                break;
278        case RTCP_SDES_PRIV:
279                debug_msg("Discarding private data from (0x%08x)", ssrc);
280                break;
281        default:
282                debug_msg("Ignoring SDES type (0x%02x) from (0x%08x).\n", ssrc);
283        }
284}
285
286static void
287process_create(session_t *sp, uint32_t ssrc)
288{
289        if (pdb_item_create(sp->pdb, sp->clock, (uint16_t)get_freq(sp->device_clock), ssrc) == FALSE) {
290                debug_msg("Unable to create source 0x%08lx\n", ssrc);
291        }
292}
293
294static void
295process_delete(session_t *sp, uint32_t ssrc)
296{
297        if (ssrc != rtp_my_ssrc(sp->rtp_session[0]) &&
298            sp->mbus_engine != NULL) {
299                ui_info_remove(sp, ssrc);
300        }
301}
302
303void 
304rtp_callback(struct rtp *s, rtp_event *e)
305{
306        struct s_session *sp;
307       
308        assert(s != NULL);
309        assert(e != NULL);
310
311        sp = get_session(s);
312        if (sp == NULL) {
313                /* Should only happen when SOURCE_CREATED is generated in */
314                /* rtp_init.                                              */
315                debug_msg("Could not find session (0x%08x)\n", (uint32_t)s);
316                return;
317        }
318
319        switch (e->type) {
320        case RX_RTP:
321                process_rtp_data(sp, e->ssrc, (rtp_packet*)e->data);
322                break;
323        case RX_RTCP_START:
324                break;
325        case RX_RTCP_FINISH:
326                break;
327        case RX_SR:
328                break;
329        case RX_RR:
330                process_rr(sp, e->ssrc, (rtcp_rr*)e->data);
331                break;
332        case RX_RR_EMPTY:
333                break;
334        case RX_SDES:
335                process_sdes(sp, e->ssrc, (rtcp_sdes_item*)e->data);
336                break;
337        case RX_BYE:
338        case SOURCE_DELETED:
339                process_delete(sp, e->ssrc);
340                break;
341        case SOURCE_CREATED:
342                debug_msg("Source create (0x%08x)\n", e->ssrc);
343                process_create(sp, e->ssrc);
344                break;
345        case RR_TIMEOUT:
346                process_rr_timeout(sp, e->ssrc, (rtcp_rr*)e->data);
347                break;
348        default:
349                debug_msg("Unknown RTP event (type=%d)\n", e->type);
350                abort();
351        }
352}
Note: See TracBrowser for help on using the browser.