]> git.sesse.net Git - vlc/blobdiff - modules/demux/rtpsession.c
mmap: Correct [cbc1122ac4551505181ea048ca14a5f87041090f]
[vlc] / modules / demux / rtpsession.c
index 62c24fdcce279332b1b9555f466939f80bc4767a..dd8eaff45eee82fbe0c96bc404404994e3148b4e 100644 (file)
@@ -136,8 +136,11 @@ int rtp_add_type (demux_t *demux, rtp_session_t *ses, const rtp_pt_t *pt)
 /** State for an RTP source */
 struct rtp_source_t
 {
-    mtime_t  expiry;  /* inactivation date */
     uint32_t ssrc;
+    uint32_t jitter;  /* interarrival delay jitter estimate */
+    mtime_t  last_rx; /* last received packet local timestamp */
+    uint32_t last_ts; /* last received packet RTP timestamp */
+
     uint16_t bad_seq; /* tentatively next expected sequence for resync */
     uint16_t max_seq; /* next expected sequence */
 
@@ -160,6 +163,7 @@ rtp_source_create (demux_t *demux, const rtp_session_t *session,
         return NULL;
 
     source->ssrc = ssrc;
+    source->jitter = 0;
     source->max_seq = source->bad_seq = init_seq;
     source->last_seq = init_seq - 1;
     source->blocks = NULL;
@@ -188,6 +192,10 @@ rtp_source_destroy (demux_t *demux, const rtp_session_t *session,
     free (source);
 }
 
+static inline uint8_t rtp_ptype (const block_t *block)
+{
+    return block->p_buffer[1] & 0x7F;
+}
 
 static inline uint16_t rtp_seq (const block_t *block)
 {
@@ -195,6 +203,30 @@ static inline uint16_t rtp_seq (const block_t *block)
     return GetWBE (block->p_buffer + 2);
 }
 
+static inline uint32_t rtp_timestamp (const block_t *block)
+{
+    assert (block->i_buffer >= 12);
+    return GetDWBE (block->p_buffer + 4);
+}
+
+static const struct rtp_pt_t *
+rtp_find_ptype (const rtp_session_t *session, rtp_source_t *source,
+                const block_t *block, void **pt_data)
+{
+    uint8_t ptype = rtp_ptype (block);
+
+    for (unsigned i = 0; i < session->ptc; i++)
+    {
+        if (session->ptv[i].number == ptype)
+        {
+            if (pt_data != NULL)
+                *pt_data = source->opaque[i];
+            return &session->ptv[i];
+        }
+    }
+    return NULL;
+}
+
 /**
  * Receives an RTP packet and queues it.
  * @param demux VLC demux object
@@ -238,7 +270,7 @@ rtp_receive (demux_t *demux, rtp_session_t *session, block_t *block)
         }
 
         /* RTP source garbage collection */
-        if (tmp->expiry < now)
+        if ((tmp->last_rx + (p_sys->timeout * CLOCK_FREQ)) < now)
         {
             rtp_source_destroy (demux, session, tmp);
             if (--session->srcc > 0)
@@ -266,7 +298,34 @@ rtp_receive (demux_t *demux, rtp_session_t *session, block_t *block)
             goto drop;
 
         tab[session->srcc++] = src;
+        /* Cannot compute jitter yet */
     }
+    else
+    {
+        const rtp_pt_t *pt = rtp_find_ptype (session, src, block, NULL);
+
+        if (pt != NULL)
+        {
+            /* Recompute jitter estimate.
+             * That is computed from the RTP timestamps and the system clock.
+             * It is independent of RTP sequence. */
+            uint32_t freq = pt->frequency;
+            uint32_t ts = rtp_timestamp (block);
+            int64_t d = ((now - src->last_rx) * freq) / CLOCK_FREQ;
+            d        -=    ts - src->last_ts;
+            if (d < 0) d = -d;
+            src->jitter += ((d - src->jitter) + 8) >> 4;
+        }
+    }
+    src->last_rx = now;
+    src->last_ts = rtp_timestamp (block);
+
+    /* Be optimistic for the first packet. Certain codec, such as Vorbis
+     * do not like loosing the first packet(s), so we cannot just wait
+     * for proper sequence synchronization. And we don't want to assume that
+     * the sender starts at seq=0 either. */
+    if (src->blocks == NULL)
+        src->max_seq = seq - p_sys->max_dropout;
 
     /* Check sequence number */
     /* NOTE: the sequence number is per-source,
@@ -299,8 +358,11 @@ rtp_receive (demux_t *demux, rtp_session_t *session, block_t *block)
     block_t **pp = &src->blocks;
     for (block_t *prev = *pp; prev != NULL; prev = *pp)
     {
-        if ((int16_t)(seq - rtp_seq (*pp)) < 0)
+        int16_t delta_seq = seq - rtp_seq (prev);
+        if (delta_seq < 0)
             break;
+        if (delta_seq == 0)
+            goto drop; /* duplicate */
         pp = &prev->p_next;
     }
     block->p_next = *pp;
@@ -332,23 +394,12 @@ rtp_decode (demux_t *demux, const rtp_session_t *session, rtp_source_t *src)
     src->last_seq = rtp_seq (block);
 
     /* Match the payload type */
-    const rtp_pt_t *pt = NULL;
-    void *pt_data = NULL;
-    const uint8_t   ptype = block->p_buffer[1] & 0x7F;
-
-    for (unsigned i = 0; i < session->ptc; i++)
-    {
-        if (session->ptv[i].number == ptype)
-        {
-            pt = &session->ptv[i];
-            pt_data = src->opaque[i];
-            break;
-        }
-    }
-
+    void *pt_data;
+    const rtp_pt_t *pt = rtp_find_ptype (session, src, block, &pt_data);
     if (pt == NULL)
     {
-        msg_Dbg (demux, "ignoring unknown payload (%"PRIu8")", ptype);
+        msg_Dbg (demux, "ignoring unknown payload (%"PRIu8")",
+                 rtp_ptype (block));
         goto drop;
     }
 
@@ -358,7 +409,7 @@ rtp_decode (demux_t *demux, const rtp_session_t *session, rtp_source_t *src)
      * Otherwise it would be impossible to compute consistent timestamps. */
     /* FIXME: handle timestamp wrap properly */
     /* TODO: sync multiple sources sanely... */
-    const uint32_t timestamp = GetDWBE (block->p_buffer + 4);
+    const uint32_t timestamp = rtp_timestamp (block);
     block->i_pts = UINT64_C(1) * CLOCK_FREQ * timestamp / pt->frequency;
 
     /* CSRC count */