mtime_t last_rx; /* last received packet local timestamp */
uint32_t last_ts; /* last received packet RTP timestamp */
+ uint32_t ref_rtp; /* sender RTP timestamp reference */
+ mtime_t ref_ntp; /* sender NTP timestamp reference */
+
uint16_t bad_seq; /* tentatively next expected sequence for resync */
uint16_t max_seq; /* next expected sequence */
source->ssrc = ssrc;
source->jitter = 0;
+ source->ref_rtp = 0;
+ /* TODO: use VLC_TS_0, but VLC does not like negative PTS at the moment */
+ source->ref_ntp = UINT64_C (1) << 62;
source->max_seq = source->bad_seq = init_seq;
source->last_seq = init_seq - 1;
source->blocks = NULL;
}
/* RTP source garbage collection */
- if ((tmp->last_rx + (p_sys->timeout * CLOCK_FREQ)) < now)
+ if ((tmp->last_rx + p_sys->timeout) < now)
{
rtp_source_destroy (demux, session, tmp);
if (--session->srcc > 0)
}
-static void
-rtp_decode (demux_t *demux, const rtp_session_t *session, rtp_source_t *src)
-{
- block_t *block = src->blocks;
-
- assert (block);
- src->blocks = block->p_next;
- block->p_next = NULL;
-
- /* Discontinuity detection */
- uint16_t delta_seq = rtp_seq (block) - (src->last_seq + 1);
- if (delta_seq != 0)
- {
- if (delta_seq >= 0x8000)
- { /* 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);
-
- /* Match the payload type */
- void *pt_data;
- const rtp_pt_t *pt = rtp_find_ptype (session, src, block, &pt_data);
- if (pt == NULL)
- {
- msg_Dbg (demux, "unknown payload (%"PRIu8")",
- rtp_ptype (block));
- goto drop;
- }
-
- /* Computes the PTS from the RTP timestamp and payload RTP frequency.
- * DTS is unknown. Also, while the clock frequency depends on the payload
- * format, a single source MUST only use payloads of a chosen frequency.
- * Otherwise it would be impossible to compute consistent timestamps. */
- /* FIXME: handle timestamp wrap properly */
- /* TODO: inter-medias/sessions sync (using RTCP-SR) */
- const uint32_t timestamp = rtp_timestamp (block);
- block->i_pts = CLOCK_FREQ * timestamp / pt->frequency;
-
- /* CSRC count */
- size_t skip = 12u + (block->p_buffer[0] & 0x0F) * 4;
-
- /* Extension header (ignored for now) */
- if (block->p_buffer[0] & 0x10)
- {
- skip += 4;
- if (block->i_buffer < skip)
- goto drop;
-
- skip += 4 * GetWBE (block->p_buffer + skip - 2);
- }
-
- if (block->i_buffer < skip)
- goto drop;
-
- block->p_buffer += skip;
- block->i_buffer -= skip;
-
- pt->decode (demux, pt_data, block);
- return;
-
-drop:
- block_Release (block);
-}
-
+static void rtp_decode (demux_t *, const rtp_session_t *, rtp_source_t *);
/**
- * Dequeues an RTP packet and pass it to decoder. Not cancellation-safe(?).
+ * Dequeues RTP packets and pass them to decoder. Not cancellation-safe(?).
+ * A packet is decoded if it is the next in sequence order, or if we have
+ * given up waiting on the missing packets (time out) from the last one
+ * already decoded.
*
* @param demux VLC demux object
* @param session RTP session receiving the packet
*
* This situation occurs if a packet got lost, or if the network has
* re-ordered packets. Unfortunately, the MSL is 2 minutes, orders of
- * magnitude too long for multimedia. We need a tradeoff.
+ * magnitude too long for multimedia. We need a trade-off.
* If we underestimated IPDV, we may have to discard valid but late
* packets. If we overestimate it, we will either cause too much
* delay, or worse, underflow our downstream buffers, as we wait for
* definitely a lost packets.
*
- * The rest of the "de-jitter buffer" work is done by the interval
+ * The rest of the "de-jitter buffer" work is done by the internal
* LibVLC E/S-out clock synchronization. Here, we need to bother about
* re-ordering packets, as decoders can't cope with mis-ordered data.
*/
}
return pending;
}
+
+/**
+ * Dequeues all RTP packets and pass them to decoder. Not cancellation-safe(?).
+ * This function can be used when the packet source is known not to reorder.
+ */
+void rtp_dequeue_force (demux_t *demux, const rtp_session_t *session)
+{
+ for (unsigned i = 0, max = session->srcc; i < max; i++)
+ {
+ rtp_source_t *src = session->srcv[i];
+ block_t *block;
+
+ while (((block = src->blocks)) != NULL)
+ rtp_decode (demux, session, src);
+ }
+}
+
+/**
+ * Decodes one RTP packet.
+ */
+static void
+rtp_decode (demux_t *demux, const rtp_session_t *session, rtp_source_t *src)
+{
+ block_t *block = src->blocks;
+
+ assert (block);
+ src->blocks = block->p_next;
+ block->p_next = NULL;
+
+ /* Discontinuity detection */
+ uint16_t delta_seq = rtp_seq (block) - (src->last_seq + 1);
+ if (delta_seq != 0)
+ {
+ if (delta_seq >= 0x8000)
+ { /* 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);
+
+ /* Match the payload type */
+ void *pt_data;
+ const rtp_pt_t *pt = rtp_find_ptype (session, src, block, &pt_data);
+ if (pt == NULL)
+ {
+ msg_Dbg (demux, "unknown payload (%"PRIu8")",
+ rtp_ptype (block));
+ goto drop;
+ }
+
+ /* Computes the PTS from the RTP timestamp and payload RTP frequency.
+ * DTS is unknown. Also, while the clock frequency depends on the payload
+ * format, a single source MUST only use payloads of a chosen frequency.
+ * Otherwise it would be impossible to compute consistent timestamps. */
+ const uint32_t timestamp = rtp_timestamp (block);
+ block->i_pts = src->ref_ntp
+ + CLOCK_FREQ * (int32_t)(timestamp - src->ref_rtp) / pt->frequency;
+ /* TODO: proper inter-medias/sessions sync (using RTCP-SR) */
+ src->ref_ntp = block->i_pts;
+ src->ref_rtp = timestamp;
+
+ /* CSRC count */
+ size_t skip = 12u + (block->p_buffer[0] & 0x0F) * 4;
+
+ /* Extension header (ignored for now) */
+ if (block->p_buffer[0] & 0x10)
+ {
+ skip += 4;
+ if (block->i_buffer < skip)
+ goto drop;
+
+ skip += 4 * GetWBE (block->p_buffer + skip - 2);
+ }
+
+ if (block->i_buffer < skip)
+ goto drop;
+
+ block->p_buffer += skip;
+ block->i_buffer -= skip;
+
+ pt->decode (demux, pt_data, block);
+ return;
+
+drop:
+ block_Release (block);
+}