]> git.sesse.net Git - vlc/blobdiff - modules/access/rtp/session.c
activex: add IID_IVLCControl2 as know interface to IObjectSafety
[vlc] / modules / access / rtp / session.c
index 9756ba84e8305b12bd295bd2d078d78c1c3c3961..fc8d6759155ae1a9a054c36beaf6bc7abbb6cd88 100644 (file)
@@ -7,7 +7,7 @@
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2.0
+ * as published by the Free Software Foundation; either version 2
  * of the License, or (at your option) any later version.
  *
  * This library is distributed in the hope that it will be useful,
@@ -15,7 +15,7 @@
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  *
- * You should have received a copy of the GNU Lesser General Public
+ * You should have received a copy of the GNU General Public
  * License along with this library; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  ****************************************************************************/
@@ -28,7 +28,7 @@
 #include <assert.h>
 #include <errno.h>
 
-#include <vlc/vlc.h>
+#include <vlc_common.h>
 #include <vlc_demux.h>
 
 #include "rtp.h"
@@ -144,8 +144,9 @@ struct rtp_source_t
     uint16_t bad_seq; /* tentatively next expected sequence for resync */
     uint16_t max_seq; /* next expected sequence */
 
-    uint16_t last_seq; /* sequence of the last dequeued packet */
+    uint16_t last_seq; /* sequence of the next dequeued packet */
     block_t *blocks; /* re-ordered blocks queue */
+    mtime_t  ref_ts; /* reference timestamp for reordering */
     void    *opaque[0]; /* Per-source private payload data */
 };
 
@@ -164,6 +165,7 @@ rtp_source_create (demux_t *demux, const rtp_session_t *session,
 
     source->ssrc = ssrc;
     source->jitter = 0;
+    source->ref_ts = 0;
     source->max_seq = source->bad_seq = init_seq;
     source->last_seq = init_seq - 1;
     source->blocks = NULL;
@@ -223,7 +225,8 @@ rtp_find_ptype (const rtp_session_t *session, rtp_source_t *source,
 }
 
 /**
- * Receives an RTP packet and queues it.
+ * Receives an RTP packet and queues it. Not a cancellation point.
+ *
  * @param demux VLC demux object
  * @param session RTP session receiving the packet
  * @param block RTP packet including the RTP header
@@ -251,7 +254,7 @@ rtp_queue (demux_t *demux, rtp_session_t *session, block_t *block)
 
     mtime_t        now = mdate ();
     rtp_source_t  *src  = NULL;
-    const uint16_t seq  = GetWBE (block->p_buffer + 2);
+    const uint16_t seq  = rtp_seq (block);
     const uint32_t ssrc = GetDWBE (block->p_buffer + 8);
 
     /* In most case, we know this source already */
@@ -305,7 +308,7 @@ rtp_queue (demux_t *demux, rtp_session_t *session, block_t *block)
              * 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 ts = rtp_timestamp (block);
             int64_t d = ((now - src->last_rx) * freq) / CLOCK_FREQ;
             d        -=    ts - src->last_ts;
             if (d < 0) d = -d;
@@ -315,38 +318,32 @@ rtp_queue (demux_t *demux, rtp_session_t *session, block_t *block)
     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,
      * but is independent from the payload type. */
-    uint16_t delta_seq = seq - (src->max_seq + 1);
-    if ((delta_seq < 0x8000) ? (delta_seq > p_sys->max_dropout)
-                             : ((65535 - delta_seq) > p_sys->max_misorder))
+    int16_t delta_seq = seq - src->max_seq;
+    if ((delta_seq 0) ? (delta_seq > p_sys->max_dropout)
+                        : (-delta_seq > p_sys->max_misorder))
     {
-        msg_Dbg (demux, "sequence discontinuity (got: %u, expected: %u)",
-                 seq, (src->max_seq + 1) & 0xffff);
-        if (seq == ((src->bad_seq + 1) & 0xffff))
+        msg_Dbg (demux, "sequence discontinuity"
+                 " (got: %"PRIu16", expected: %"PRIu16")", seq, src->max_seq);
+        if (seq == src->bad_seq)
         {
-            src->max_seq = src->bad_seq = seq;
+            src->max_seq = src->bad_seq = seq + 1;
+            src->last_seq = seq - 0x7fffe; /* hack for rtp_decode() */
             msg_Warn (demux, "sequence resynchronized");
             block_ChainRelease (src->blocks);
             src->blocks = NULL;
         }
         else
         {
-            src->bad_seq = seq;
+            src->bad_seq = seq + 1;
             goto drop;
         }
     }
     else
-    if (delta_seq < 0x8000)
-        src->max_seq = seq;
+    if (delta_seq >= 0)
+        src->max_seq = seq + 1;
 
     /* Queues the block in sequence order,
      * hence there is a single queue for all payload types. */
@@ -357,7 +354,10 @@ rtp_queue (demux_t *demux, rtp_session_t *session, block_t *block)
         if (delta_seq < 0)
             break;
         if (delta_seq == 0)
+        {
+            msg_Dbg (demux, "duplicate packet (sequence: %"PRIu16")", seq);
             goto drop; /* duplicate */
+        }
         pp = &prev->p_next;
     }
     block->p_next = *pp;
@@ -385,11 +385,12 @@ rtp_decode (demux_t *demux, const rtp_session_t *session, rtp_source_t *src)
     if (delta_seq != 0)
     {
         if (delta_seq >= 0x8000)
-        {   /* Unrecoverable if later packets have already been dequeued */
-            msg_Warn (demux, "ignoring late packet (sequence: %u)",
+        {   /* Trash too late packets (and PIM Assert duplicates) */
+            msg_Dbg (demux, "ignoring late packet (sequence: %"PRIu16")",
                       rtp_seq (block));
             goto drop;
         }
+        msg_Warn (demux, "%"PRIu16" packet(s) lost", delta_seq);
         block->i_flags |= BLOCK_FLAG_DISCONTINUITY;
     }
     src->last_seq = rtp_seq (block);
@@ -399,7 +400,7 @@ rtp_decode (demux_t *demux, const rtp_session_t *session, rtp_source_t *src)
     const rtp_pt_t *pt = rtp_find_ptype (session, src, block, &pt_data);
     if (pt == NULL)
     {
-        msg_Dbg (demux, "ignoring unknown payload (%"PRIu8")",
+        msg_Dbg (demux, "unknown payload (%"PRIu8")",
                  rtp_ptype (block));
         goto drop;
     }
@@ -411,7 +412,8 @@ rtp_decode (demux_t *demux, const rtp_session_t *session, rtp_source_t *src)
     /* FIXME: handle timestamp wrap properly */
     /* TODO: inter-medias/sessions sync (using RTCP-SR) */
     const uint32_t timestamp = rtp_timestamp (block);
-    block->i_pts = UINT64_C(1) * CLOCK_FREQ * timestamp / pt->frequency;
+    src->ref_ts = 0;
+    block->i_pts = CLOCK_FREQ * timestamp / pt->frequency;
 
     /* CSRC count */
     size_t skip = 12u + (block->p_buffer[0] & 0x0F) * 4;
@@ -440,12 +442,23 @@ drop:
 }
 
 
+/**
+ * Dequeues an RTP packet and pass it to decoder. Not cancellation-safe(?).
+ *
+ * @param demux VLC demux object
+ * @param session RTP session receiving the packet
+ * @param deadlinep pointer to deadline to call rtp_dequeue() again
+ * @return true if the buffer is not empty, false otherwise.
+ * In the later case, *deadlinep is undefined.
+ */
 bool rtp_dequeue (demux_t *demux, const rtp_session_t *session,
                   mtime_t *restrict deadlinep)
 {
     mtime_t now = mdate ();
     bool pending = false;
 
+    *deadlinep = INT64_MAX;
+
     for (unsigned i = 0, max = session->srcc; i < max; i++)
     {
         rtp_source_t *src = session->srcv[i];
@@ -469,22 +482,25 @@ bool rtp_dequeue (demux_t *demux, const rtp_session_t *session,
          */
         while (((block = src->blocks)) != NULL)
         {
-#if 0
-            if (rtp_seq (block) == ((src->last_seq + 1) & 0xffff))
-            {   /* Next block ready, no need to wait */
+            if ((int16_t)(rtp_seq (block) - (src->last_seq + 1)) <= 0)
+            {   /* Next (or earlier) block ready, no need to wait */
                 rtp_decode (demux, session, src);
                 continue;
             }
-#endif
+
             /* Wait for 3 times the inter-arrival delay variance (about 99.7%
              * match for random gaussian jitter). Additionnaly, we implicitly
              * wait for misordering times the packetization time.
              */
-            mtime_t deadline = src->last_rx;
+            mtime_t deadline = src->ref_ts;
             const rtp_pt_t *pt = rtp_find_ptype (session, src, block, NULL);
+            if (!deadline)
+                deadline = src->ref_ts = now;
             if (pt)
-                deadline += UINT64_C(3) * CLOCK_FREQ * src->jitter
-                            / pt->frequency;
+                deadline += CLOCK_FREQ * 3 * src->jitter / pt->frequency;
+
+            /* Make sure we wait at least for 25 msec */
+            deadline = __MAX(deadline, src->ref_ts + CLOCK_FREQ / 40);
 
             if (now >= deadline)
             {