]> git.sesse.net Git - vlc/blob - modules/demux/rtpsession.c
asf: fix compilation warning.
[vlc] / modules / demux / rtpsession.c
1 /**
2  * @file session.c
3  * @brief RTP session handling
4  */
5 /*****************************************************************************
6  * Copyright © 2008 Rémi Denis-Courmont
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2.0
11  * of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
21  ****************************************************************************/
22
23 #ifdef HAVE_CONFIG_H
24 # include <config.h>
25 #endif
26
27 #include <stdlib.h>
28 #include <assert.h>
29 #include <errno.h>
30
31 #include <vlc/vlc.h>
32 #include <vlc_demux.h>
33
34 #include "rtp.h"
35
36 typedef struct rtp_source_t rtp_source_t;
37
38 /** State for a RTP session: */
39 struct rtp_session_t
40 {
41     rtp_source_t **srcv;
42     unsigned       srcc;
43     uint8_t        ptc;
44     rtp_pt_t      *ptv;
45 };
46
47 static rtp_source_t *
48 rtp_source_create (demux_t *, const rtp_session_t *, uint32_t, uint16_t);
49 static void
50 rtp_source_destroy (demux_t *, const rtp_session_t *, rtp_source_t *);
51
52 static void rtp_decode (demux_t *, const rtp_session_t *, rtp_source_t *);
53
54 /**
55  * Creates a new RTP session.
56  */
57 rtp_session_t *
58 rtp_session_create (demux_t *demux)
59 {
60     rtp_session_t *session = malloc (sizeof (*session));
61     if (session == NULL)
62         return NULL;
63
64     session->srcv = NULL;
65     session->srcc = 0;
66     session->ptc = 0;
67     session->ptv = NULL;
68
69     (void)demux;
70     return session;
71 }
72
73
74 /**
75  * Destroys an RTP session.
76  */
77 void rtp_session_destroy (demux_t *demux, rtp_session_t *session)
78 {
79     for (unsigned i = 0; i < session->srcc; i++)
80         rtp_source_destroy (demux, session, session->srcv[i]);
81
82     free (session->srcv);
83     free (session->ptv);
84     free (session);
85     (void)demux;
86 }
87
88 static void *no_init (demux_t *demux)
89 {
90     (void)demux;
91     return NULL;
92 }
93
94 static void no_destroy (demux_t *demux, void *opaque)
95 {
96     (void)demux; (void)opaque;
97 }
98
99 static void no_decode (demux_t *demux, void *opaque, block_t *block)
100 {
101     (void)demux; (void)opaque;
102     block_Release (block);
103 }
104
105 /**
106  * Adds a payload type to an RTP session.
107  */
108 int rtp_add_type (demux_t *demux, rtp_session_t *ses, const rtp_pt_t *pt)
109 {
110     if (ses->srcc > 0)
111     {
112         msg_Err (demux, "cannot change RTP payload formats during session");
113         return EINVAL;
114     }
115
116     rtp_pt_t *ppt = realloc (ses->ptv, (ses->ptc + 1) * sizeof (rtp_pt_t));
117     if (ppt == NULL)
118         return ENOMEM;
119
120     ses->ptv = ppt;
121     ppt += ses->ptc++;
122
123     ppt->init = pt->init ? pt->init : no_init;
124     ppt->destroy = pt->destroy ? pt->destroy : no_destroy;
125     ppt->decode = pt->decode ? pt->decode : no_decode;
126     ppt->frequency = pt->frequency;
127     ppt->number = pt->number;
128     msg_Dbg (demux, "added payload type %"PRIu8" (f = %"PRIu32" Hz)",
129              ppt->number, ppt->frequency);
130
131     assert (ppt->frequency > 0); /* SIGFPE! */
132     (void)demux;
133     return 0;
134 }
135
136 /** State for an RTP source */
137 struct rtp_source_t
138 {
139     uint32_t ssrc;
140     uint32_t jitter;  /* interarrival delay jitter estimate */
141     mtime_t  last_rx; /* last received packet local timestamp */
142     uint32_t last_ts; /* last received packet RTP timestamp */
143
144     uint16_t bad_seq; /* tentatively next expected sequence for resync */
145     uint16_t max_seq; /* next expected sequence */
146
147     uint16_t last_seq; /* sequence of the last dequeued packet */
148     block_t *blocks; /* re-ordered blocks queue */
149     void    *opaque[0]; /* Per-source private payload data */
150 };
151
152 /**
153  * Initializes a new RTP source within an RTP session.
154  */
155 static rtp_source_t *
156 rtp_source_create (demux_t *demux, const rtp_session_t *session,
157                    uint32_t ssrc, uint16_t init_seq)
158 {
159     rtp_source_t *source;
160
161     source = malloc (sizeof (*source) + (sizeof (void *) * session->ptc));
162     if (source == NULL)
163         return NULL;
164
165     source->ssrc = ssrc;
166     source->jitter = 0;
167     source->max_seq = source->bad_seq = init_seq;
168     source->last_seq = init_seq - 1;
169     source->blocks = NULL;
170
171     /* Initializes all payload */
172     for (unsigned i = 0; i < session->ptc; i++)
173         source->opaque[i] = session->ptv[i].init (demux);
174
175     msg_Dbg (demux, "added RTP source (%08x)", ssrc);
176     return source;
177 }
178
179
180 /**
181  * Destroys an RTP source and its associated streams.
182  */
183 static void
184 rtp_source_destroy (demux_t *demux, const rtp_session_t *session,
185                     rtp_source_t *source)
186 {
187     msg_Dbg (demux, "removing RTP source (%08x)", source->ssrc);
188
189     for (unsigned i = 0; i < session->ptc; i++)
190         session->ptv[i].destroy (demux, source->opaque[i]);
191     block_ChainRelease (source->blocks);
192     free (source);
193 }
194
195 static inline uint8_t rtp_ptype (const block_t *block)
196 {
197     return block->p_buffer[1] & 0x7F;
198 }
199
200 static inline uint16_t rtp_seq (const block_t *block)
201 {
202     assert (block->i_buffer >= 4);
203     return GetWBE (block->p_buffer + 2);
204 }
205
206 static inline uint32_t rtp_timestamp (const block_t *block)
207 {
208     assert (block->i_buffer >= 12);
209     return GetDWBE (block->p_buffer + 4);
210 }
211
212 static const struct rtp_pt_t *
213 rtp_find_ptype (const rtp_session_t *session, rtp_source_t *source,
214                 const block_t *block, void **pt_data)
215 {
216     uint8_t ptype = rtp_ptype (block);
217
218     for (unsigned i = 0; i < session->ptc; i++)
219     {
220         if (session->ptv[i].number == ptype)
221         {
222             if (pt_data != NULL)
223                 *pt_data = source->opaque[i];
224             return &session->ptv[i];
225         }
226     }
227     return NULL;
228 }
229
230 /**
231  * Receives an RTP packet and queues it.
232  * @param demux VLC demux object
233  * @param session RTP session receiving the packet
234  * @param block RTP packet including the RTP header
235  */
236 void
237 rtp_receive (demux_t *demux, rtp_session_t *session, block_t *block)
238 {
239     demux_sys_t *p_sys = demux->p_sys;
240
241     /* RTP header sanity checks (see RFC 3550) */
242     if (block->i_buffer < 12)
243         goto drop;
244     if ((block->p_buffer[0] >> 6 ) != 2) /* RTP version number */
245         goto drop;
246
247     /* Remove padding if present */
248     if (block->p_buffer[0] & 0x20)
249     {
250         uint8_t padding = block->p_buffer[block->i_buffer - 1];
251         if ((padding == 0) || (block->i_buffer < (12u + padding)))
252             goto drop; /* illegal value */
253
254         block->i_buffer -= padding;
255     }
256
257     mtime_t        now = mdate ();
258     rtp_source_t  *src  = NULL;
259     const uint16_t seq  = GetWBE (block->p_buffer + 2);
260     const uint32_t ssrc = GetDWBE (block->p_buffer + 8);
261
262     /* In most case, we know this source already */
263     for (unsigned i = 0, max = session->srcc; i < max; i++)
264     {
265         rtp_source_t *tmp = session->srcv[i];
266         if (tmp->ssrc == ssrc)
267         {
268             src = tmp;
269             break;
270         }
271
272         /* RTP source garbage collection */
273         if ((tmp->last_rx + (p_sys->timeout * CLOCK_FREQ)) < now)
274         {
275             rtp_source_destroy (demux, session, tmp);
276             if (--session->srcc > 0)
277                 session->srcv[i] = session->srcv[session->srcc - 1];
278         }
279     }
280
281     if (src == NULL)
282     {
283         /* New source */
284         if (session->srcc >= p_sys->max_src)
285         {
286             msg_Warn (demux, "too many RTP sessions");
287             goto drop;
288         }
289
290         rtp_source_t **tab;
291         tab = realloc (session->srcv, (session->srcc + 1) * sizeof (*tab));
292         if (tab == NULL)
293             goto drop;
294         session->srcv = tab;
295
296         src = rtp_source_create (demux, session, ssrc, seq);
297         if (src == NULL)
298             goto drop;
299
300         tab[session->srcc++] = src;
301         /* Cannot compute jitter yet */
302     }
303     else
304     {
305         const rtp_pt_t *pt = rtp_find_ptype (session, src, block, NULL);
306
307         if (pt != NULL)
308         {
309             /* Recompute jitter estimate.
310              * That is computed from the RTP timestamps and the system clock.
311              * It is independent of RTP sequence. */
312             uint32_t freq = pt->frequency;
313             uint32_t ts = rtp_timestamp (block);
314             int64_t d = ((now - src->last_rx) * freq) / CLOCK_FREQ;
315             d        -=    ts - src->last_ts;
316             if (d < 0) d = -d;
317             src->jitter += ((d - src->jitter) + 8) >> 4;
318         }
319     }
320     src->last_rx = now;
321     src->last_ts = rtp_timestamp (block);
322
323     /* Be optimistic for the first packet. Certain codec, such as Vorbis
324      * do not like loosing the first packet(s), so we cannot just wait
325      * for proper sequence synchronization. And we don't want to assume that
326      * the sender starts at seq=0 either. */
327     if (src->blocks == NULL)
328         src->max_seq = seq - p_sys->max_dropout;
329
330     /* Check sequence number */
331     /* NOTE: the sequence number is per-source,
332      * but is independent from the payload type. */
333     uint16_t delta_seq = seq - (src->max_seq + 1);
334     if ((delta_seq < 0x8000) ? (delta_seq > p_sys->max_dropout)
335                              : ((65535 - delta_seq) > p_sys->max_misorder))
336     {
337         msg_Dbg (demux, "sequence discontinuity (got: %u, expected: %u)",
338                  seq, (src->max_seq + 1) & 0xffff);
339         if (seq == ((src->bad_seq + 1) & 0xffff))
340         {
341             src->max_seq = src->bad_seq = seq;
342             msg_Warn (demux, "sequence resynchronized");
343             block_ChainRelease (src->blocks);
344             src->blocks = NULL;
345         }
346         else
347         {
348             src->bad_seq = seq;
349             goto drop;
350         }
351     }
352     else
353     if (delta_seq < 0x8000)
354         src->max_seq = seq;
355
356     /* Queues the block in sequence order,
357      * hence there is a single queue for all payload types. */
358     block_t **pp = &src->blocks;
359     for (block_t *prev = *pp; prev != NULL; prev = *pp)
360     {
361         int16_t delta_seq = seq - rtp_seq (prev);
362         if (delta_seq < 0)
363             break;
364         if (delta_seq == 0)
365             goto drop; /* duplicate */
366         pp = &prev->p_next;
367     }
368     block->p_next = *pp;
369     *pp = block;
370
371     rtp_decode (demux, session, src);
372     return;
373
374 drop:
375     block_Release (block);
376 }
377
378
379 static void
380 rtp_decode (demux_t *demux, const rtp_session_t *session, rtp_source_t *src)
381 {
382     block_t *block = src->blocks;
383
384     /* Buffer underflow? */
385     if (!block || !block->p_next || !block->p_next->p_next)
386         return;
387     /* TODO: use time rather than packet counts for buffer measurement */
388     src->blocks = block->p_next;
389     block->p_next = NULL;
390
391     /* Discontinuity detection */
392     if (((src->last_seq + 1) & 0xffff) != rtp_seq (block))
393         block->i_flags |= BLOCK_FLAG_DISCONTINUITY;
394     src->last_seq = rtp_seq (block);
395
396     /* Match the payload type */
397     void *pt_data;
398     const rtp_pt_t *pt = rtp_find_ptype (session, src, block, &pt_data);
399     if (pt == NULL)
400     {
401         msg_Dbg (demux, "ignoring unknown payload (%"PRIu8")",
402                  rtp_ptype (block));
403         goto drop;
404     }
405
406     /* Computes the PTS from the RTP timestamp and payload RTP frequency.
407      * DTS is unknown. Also, while the clock frequency depends on the payload
408      * format, a single source MUST only use payloads of a chosen frequency.
409      * Otherwise it would be impossible to compute consistent timestamps. */
410     /* FIXME: handle timestamp wrap properly */
411     /* TODO: sync multiple sources sanely... */
412     const uint32_t timestamp = rtp_timestamp (block);
413     block->i_pts = UINT64_C(1) * CLOCK_FREQ * timestamp / pt->frequency;
414
415     /* CSRC count */
416     size_t skip = 12u + (block->p_buffer[0] & 0x0F) * 4;
417
418     /* Extension header (ignored for now) */
419     if (block->p_buffer[0] & 0x10)
420     {
421         skip += 4;
422         if (block->i_buffer < skip)
423             goto drop;
424
425         skip += 4 * GetWBE (block->p_buffer + skip - 2);
426     }
427
428     if (block->i_buffer < skip)
429         goto drop;
430
431     block->p_buffer += skip;
432     block->i_buffer -= skip;
433
434     pt->decode (demux, pt_data, block);
435     return;
436
437 drop:
438     block_Release (block);
439 }