root/rat/trunk/rtp_callback.c @ 3106

Revision 3106, 9.4 KB (checked in by ucacoxh, 14 years ago)

- Added common/ntp.h common/ntp.c which do basic ntp timestamp get, conversion,

and differencing.

- Changed rtp library to use ntp.h ntp.c.
- Add rtt calculation to rat on reception of sr with lsr != 0.
- Add fields in pdb.h for last_rtt and avg_rtt.

Still have to add field to ui and probably decide an mbus message
name, for moment it's rtp.source.rtt.

  • 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        delta = ntp32_sub(arr,   dep);
132        delta = ntp32_sub(delta, delay);
133        /*
134         * 16 high order bits are seconds
135         * 16 low order bits are 1/65536 of sec
136         */
137        return  (double)((delta >> 16) & 0xffff) +
138                (double)(delta & 0xffff) / 65536.0;
139}
140
141static void
142process_rtp_data(session_t *sp, uint32_t ssrc, rtp_packet *p)
143{
144        struct s_source *s;
145        pdb_entry_t     *e;
146
147        if (sp->filter_loopback && ssrc == rtp_my_ssrc(sp->rtp_session[0])) {
148                /* This packet is from us and we are filtering our own       */
149                /* packets.                                                  */
150                xfree(p);
151                return;
152        }
153
154        if (pdb_item_get(sp->pdb, ssrc, &e) == FALSE) {
155                debug_msg("Packet discarded: unknown source (0x%08x).\n", ssrc);
156                xfree(p);
157                return;
158        }
159        e->received++;
160       
161        s = source_get_by_ssrc(sp->active_sources, ssrc);
162        if (s == NULL) {
163                s = source_create(sp->active_sources, ssrc, sp->pdb);
164                ui_info_activate(sp, ssrc);
165                debug_msg("Source created\n");
166        }
167
168        /* Calculate the relative playout delay, for this source. Needed for lip-sync. */
169
170        /* Discard packet if output is muted... no point wasting time decoding it... */
171        if ((sp->playing_audio == FALSE) || (e->mute)) {
172                debug_msg("Packet discarded since output muted\n");
173                xfree(p);
174                return;
175        }
176
177        /* Remove any padding */
178        if (p->p) {
179                p->data_len -= p->data[p->data_len - 1];
180                p->p = 0;
181        }
182        source_add_packet(s, p);
183}
184
185static void
186process_rr(session_t *sp, uint32_t ssrc, rtcp_rr *r)
187{
188        pdb_entry_t  *e;
189        uint32_t fract_lost;
190
191        /* Calculate rtt estimate */
192
193        if (pdb_item_get(sp->pdb, ssrc, &e) &&
194            r->ssrc == rtp_my_ssrc(sp->rtp_session[0]) &&
195            r->lsr != 0) {
196                uint32_t ntp_sec, ntp_frac, ntp32;
197
198                ntp64_time(&ntp_sec, &ntp_frac);
199                ntp32 = ntp64_to_ntp32(ntp_sec, ntp_frac);
200               
201                e->last_rtt = rtp_rtt_calc(ntp32, r->lsr, r->dlsr);
202                if (e->avg_rtt == 0.0) {
203                        e->avg_rtt = e->last_rtt;
204                } else {
205                        e->avg_rtt += (e->last_rtt - e->avg_rtt) / 8.0;
206                }
207
208                if (sp->mbus_engine != NULL) {
209                        ui_update_rtt(sp,  ssrc, e->avg_rtt);
210                }
211        }
212
213        /* Update loss stats */
214        if (sp->mbus_engine != NULL) {
215                fract_lost = (r->fract_lost * 100) >> 8;
216                ui_update_loss(sp, ssrc, r->ssrc, fract_lost);
217        }
218}
219
220static void
221process_rr_timeout(session_t *sp, uint32_t ssrc, rtcp_rr *r)
222{
223        /* Just update loss statistic in UI for this report if there */
224        /* is somewhere to send them.                                */
225        if (sp->mbus_engine != NULL) {
226                ui_update_loss(sp, ssrc, r->ssrc, 101);
227        }
228}
229
230static void
231process_sdes(session_t *sp, uint32_t ssrc, rtcp_sdes_item *d)
232{
233        pdb_entry_t *e;
234
235        assert(pdb_item_get(sp->pdb, ssrc, &e) == TRUE);
236
237        if (sp->mbus_engine == NULL) {
238                /* Nowhere to send updates to, so ignore them.               */
239                return;
240        }
241
242        switch(d->type) {
243        case RTCP_SDES_END:
244                /* This is the end of the SDES list of a packet.  Nothing    */
245                /* for us to deal with.                                      */
246                break;
247        case RTCP_SDES_CNAME:
248                ui_info_update_cname(sp, ssrc);
249                break;
250        case RTCP_SDES_NAME:
251                ui_info_update_name(sp, ssrc);
252                break;
253        case RTCP_SDES_EMAIL:
254                ui_info_update_email(sp, ssrc);
255                break;
256        case RTCP_SDES_PHONE:
257                ui_info_update_phone(sp, ssrc);
258                break;
259        case RTCP_SDES_LOC:
260                ui_info_update_loc(sp, ssrc);
261                break;
262        case RTCP_SDES_TOOL:
263                ui_info_update_tool(sp, ssrc);
264                break;
265        case RTCP_SDES_NOTE:
266                ui_info_update_note(sp, ssrc);
267                break;
268        case RTCP_SDES_PRIV:
269                debug_msg("Discarding private data from (0x%08x)", ssrc);
270                break;
271        default:
272                debug_msg("Ignoring SDES type (0x%02x) from (0x%08x).\n", ssrc);
273        }
274}
275
276static void
277process_create(session_t *sp, uint32_t ssrc)
278{
279        if (pdb_item_create(sp->pdb, sp->clock, (uint16_t)get_freq(sp->device_clock), ssrc) == FALSE) {
280                debug_msg("Unable to create source 0x%08lx\n", ssrc);
281        }
282}
283
284static void
285process_delete(session_t *sp, uint32_t ssrc)
286{
287        if (ssrc != rtp_my_ssrc(sp->rtp_session[0]) &&
288            sp->mbus_engine != NULL) {
289                ui_info_remove(sp, ssrc);
290        }
291}
292
293void 
294rtp_callback(struct rtp *s, rtp_event *e)
295{
296        struct s_session *sp;
297       
298        assert(s != NULL);
299        assert(e != NULL);
300
301        sp = get_session(s);
302        if (sp == NULL) {
303                /* Should only happen when SOURCE_CREATED is generated in */
304                /* rtp_init.                                              */
305                debug_msg("Could not find session (0x%08x)\n", (uint32_t)s);
306                return;
307        }
308
309        switch (e->type) {
310        case RX_RTP:
311                process_rtp_data(sp, e->ssrc, (rtp_packet*)e->data);
312                break;
313        case RX_RTCP_START:
314                break;
315        case RX_RTCP_FINISH:
316                break;
317        case RX_SR:
318                break;
319        case RX_RR:
320                process_rr(sp, e->ssrc, (rtcp_rr*)e->data);
321                break;
322        case RX_RR_EMPTY:
323                break;
324        case RX_SDES:
325                process_sdes(sp, e->ssrc, (rtcp_sdes_item*)e->data);
326                break;
327        case RX_BYE:
328        case SOURCE_DELETED:
329                process_delete(sp, e->ssrc);
330                break;
331        case SOURCE_CREATED:
332                debug_msg("Source create (0x%08x)\n", e->ssrc);
333                process_create(sp, e->ssrc);
334                break;
335        case RR_TIMEOUT:
336                process_rr_timeout(sp, e->ssrc, (rtcp_rr*)e->data);
337                break;
338        default:
339                debug_msg("Unknown RTP event (type=%d)\n", e->type);
340                abort();
341        }
342}
Note: See TracBrowser for help on using the browser.