*
* 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,
* 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
****************************************************************************/
#include <assert.h>
#include <errno.h>
-#include <vlc/vlc.h>
+#include <vlc_common.h>
#include <vlc_demux.h>
#include "rtp.h"
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 */
};
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;
}
/**
- * 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
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 */
* 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;
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. */
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;
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);
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;
}
/* 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;
}
+/**
+ * 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];
*/
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)
{