root/rat/trunk/rtp_callback.c @ 3078

Revision 3078, 8.3 KB (checked in by ucacoxh, 14 years ago)

- Added Id strings to all c file.
- Replaced $Date$ and $Revision$ with $Id$ in headers.

  • 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 "rtp_callback.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/* We need to be able to resolve the rtp session to a rat session in */
33/* order to get persistent participant information, etc.  We use a   */
34/* double linked list with sentinel for this.  We normally don't     */
35/* expect to have more than 2 sessions (i.e. transcoder mode), but   */
36/* layered codecs may require more.                                  */
37
38typedef struct s_rtp_assoc {
39        struct s_rtp_assoc *next;
40        struct s_rtp_assoc *prev;
41        struct rtp         *rtps;
42        struct s_session   *rats;
43} rtp_assoc_t;
44
45/* Sentinel for linked list that is used as small associative array */
46static rtp_assoc_t rtp_as;
47static int rtp_as_inited;
48
49void 
50rtp_callback_init(struct rtp *rtps, struct s_session *rats)
51{
52        rtp_assoc_t *cur, *sentinel;
53
54        if (!rtp_as_inited) {
55                /* First pass sentinel initialization */
56                rtp_as.next = &rtp_as;
57                rtp_as.prev = &rtp_as;
58                rtp_as_inited = 1;
59        }
60
61        sentinel = &rtp_as;
62        cur   = sentinel->next;
63
64        while (cur != sentinel) {
65                if (cur->rtps == rtps) {
66                        /* Association already exists, over-riding */
67                        cur->rats = rats;
68                        return;
69                }
70        }
71
72        cur = (rtp_assoc_t*)xmalloc(sizeof(rtp_assoc_t));
73        cur->rtps   = rtps;
74        cur->rats   = rats;
75
76        cur->next       = sentinel->next;
77        cur->prev       = sentinel;
78        cur->next->prev = cur;
79        cur->prev->next = cur;
80}
81
82void rtp_callback_exit(struct rtp *rtps)
83{
84        rtp_assoc_t *cur, *sentinel;
85       
86        sentinel = &rtp_as;
87        cur = sentinel->next;
88        while(cur != sentinel) {
89                if (cur->rtps == rtps) {
90                        cur->prev->next = cur->next;
91                        cur->next->prev = cur->prev;
92                        xfree(cur);
93                        return;
94                }
95                cur = cur->next;
96        }
97}
98
99/* get_session maps an rtp_session to a rat session */
100static struct s_session *
101get_session(struct rtp *rtps)
102{
103        rtp_assoc_t *cur, *sentinel;
104
105        if (!rtp_as_inited) {
106                return NULL;
107        }
108       
109        sentinel = &rtp_as;
110        cur = sentinel->next;
111        while(cur != sentinel) {
112                if (cur->rtps == rtps) {
113                        return cur->rats;
114                }
115                cur = cur->next;
116        }       
117        return NULL;
118}
119
120/* Callback utility functions                                                */
121
122static void
123process_rtp_data(session_t *sp, uint32_t ssrc, rtp_packet *p)
124{
125        struct s_source *s;
126        pdb_entry_t     *e;
127
128        if (sp->filter_loopback && ssrc == rtp_my_ssrc(sp->rtp_session[0])) {
129                /* This packet is from us and we are filtering our own       */
130                /* packets.                                                  */
131                xfree(p);
132                return;
133        }
134
135        if (pdb_item_get(sp->pdb, ssrc, &e) == FALSE) {
136                debug_msg("Packet discarded: unknown source (0x%08x).\n", ssrc);
137                xfree(p);
138                return;
139        }
140        e->received++;
141       
142        s = source_get_by_ssrc(sp->active_sources, ssrc);
143        if (s == NULL) {
144                s = source_create(sp->active_sources, ssrc, sp->pdb);
145                ui_info_activate(sp, ssrc);
146                debug_msg("Source created\n");
147        }
148
149        /* Calculate the relative playout delay, for this source. Needed for lip-sync. */
150
151        /* Discard packet if output is muted... no point wasting time decoding it... */
152        if ((sp->playing_audio == FALSE) || (e->mute)) {
153                debug_msg("Packet discarded since output muted\n");
154                xfree(p);
155                return;
156        }
157
158        /* Remove any padding */
159        if (p->p) {
160                p->data_len -= p->data[p->data_len - 1];
161                p->p = 0;
162        }
163        source_add_packet(s, p);
164}
165
166static void
167process_rr(session_t *sp, uint32_t ssrc, rtcp_rr *r)
168{
169        uint32_t fract_lost;
170        /* Just update loss statistic in UI for this report if there */
171        /* is somewhere to send them.                                */
172        if (sp->mbus_engine != NULL) {
173                fract_lost = (r->fract_lost * 100) >> 8;
174                ui_update_loss(sp, ssrc, r->ssrc, fract_lost);
175        }
176}
177
178
179static void
180process_rr_timeout(session_t *sp, uint32_t ssrc, rtcp_rr *r)
181{
182        /* Just update loss statistic in UI for this report if there */
183        /* is somewhere to send them.                                */
184        if (sp->mbus_engine != NULL) {
185                ui_update_loss(sp, ssrc, r->ssrc, 101);
186        }
187}
188
189static void
190process_sdes(session_t *sp, uint32_t ssrc, rtcp_sdes_item *d)
191{
192        pdb_entry_t *e;
193
194        assert(pdb_item_get(sp->pdb, ssrc, &e) == TRUE);
195
196        if (sp->mbus_engine == NULL) {
197                /* Nowhere to send updates to, so ignore them.               */
198                return;
199        }
200
201        switch(d->type) {
202        case RTCP_SDES_END:
203                /* This is the end of the SDES list of a packet.  Nothing    */
204                /* for us to deal with.                                      */
205                break;
206        case RTCP_SDES_CNAME:
207                ui_info_update_cname(sp, ssrc);
208                break;
209        case RTCP_SDES_NAME:
210                ui_info_update_name(sp, ssrc);
211                break;
212        case RTCP_SDES_EMAIL:
213                ui_info_update_email(sp, ssrc);
214                break;
215        case RTCP_SDES_PHONE:
216                ui_info_update_phone(sp, ssrc);
217                break;
218        case RTCP_SDES_LOC:
219                ui_info_update_loc(sp, ssrc);
220                break;
221        case RTCP_SDES_TOOL:
222                ui_info_update_tool(sp, ssrc);
223                break;
224        case RTCP_SDES_NOTE:
225                ui_info_update_note(sp, ssrc);
226                break;
227        case RTCP_SDES_PRIV:
228                debug_msg("Discarding private data from (0x%08x)", ssrc);
229                break;
230        default:
231                debug_msg("Ignoring SDES type (0x%02x) from (0x%08x).\n", ssrc);
232        }
233}
234
235static void
236process_create(session_t *sp, uint32_t ssrc)
237{
238        if (pdb_item_create(sp->pdb, sp->clock, (uint16_t)get_freq(sp->device_clock), ssrc) == FALSE) {
239                debug_msg("Unable to create source 0x%08lx\n", ssrc);
240        }
241}
242
243static void
244process_delete(session_t *sp, uint32_t ssrc)
245{
246        if (ssrc != rtp_my_ssrc(sp->rtp_session[0]) &&
247            sp->mbus_engine != NULL) {
248                ui_info_remove(sp, ssrc);
249        }
250}
251
252void 
253rtp_callback(struct rtp *s, rtp_event *e)
254{
255        struct s_session *sp;
256       
257        assert(s != NULL);
258        assert(e != NULL);
259
260        sp = get_session(s);
261        if (sp == NULL) {
262                /* Should only happen when SOURCE_CREATED is generated in */
263                /* rtp_init.                                              */
264                debug_msg("Could not find session (0x%08x)\n", (uint32_t)s);
265                return;
266        }
267
268        switch (e->type) {
269        case RX_RTP:
270                process_rtp_data(sp, e->ssrc, (rtp_packet*)e->data);
271                break;
272        case RX_RTCP_START:
273                break;
274        case RX_RTCP_FINISH:
275                break;
276        case RX_SR:
277                break;
278        case RX_RR:
279                process_rr(sp, e->ssrc, (rtcp_rr*)e->data);
280                break;
281        case RX_RR_EMPTY:
282                break;
283        case RX_SDES:
284                process_sdes(sp, e->ssrc, (rtcp_sdes_item*)e->data);
285                break;
286        case RX_BYE:
287        case SOURCE_DELETED:
288                process_delete(sp, e->ssrc);
289                break;
290        case SOURCE_CREATED:
291                debug_msg("Source create (0x%08x)\n", e->ssrc);
292                process_create(sp, e->ssrc);
293                break;
294        case RR_TIMEOUT:
295                process_rr_timeout(sp, e->ssrc, (rtcp_rr*)e->data);
296                break;
297        default:
298                debug_msg("Unknown RTP event (type=%d)\n", e->type);
299                abort();
300        }
301}
Note: See TracBrowser for help on using the browser.