*
* 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"
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 */
- 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 */
void *opaque[0]; /* Per-source private payload data */
};
source->ssrc = ssrc;
source->jitter = 0;
+ source->ref_rtp = 0;
+ /* TODO: use 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)
}
}
src->last_rx = now;
+ block->i_pts = now; /* store reception time until dequeued */
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. */
break;
if (delta_seq == 0)
{
- msg_Warn (demux, "duplicate packet (sequence: %"PRIu16")",
- seq);
+ msg_Dbg (demux, "duplicate packet (sequence: %"PRIu16")", seq);
goto drop; /* duplicate */
}
pp = &prev->p_next;
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);
* 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 = UINT64_C(1) * CLOCK_FREQ * timestamp / pt->frequency;
+ 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;
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];
*
* 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.
*/
}
/* 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.
+ * match for random gaussian jitter).
*/
- mtime_t deadline = src->last_rx;
+ mtime_t deadline;
const rtp_pt_t *pt = rtp_find_ptype (session, src, block, NULL);
if (pt)
- deadline += UINT64_C(3) * CLOCK_FREQ * src->jitter
- / pt->frequency;
-
+ deadline = CLOCK_FREQ * 3 * src->jitter / pt->frequency;
+ else
+ deadline = 0; /* no jitter estimate with no frequency :( */
+
+ /* Make sure we wait at least for 25 msec */
+ if (deadline < (CLOCK_FREQ / 40))
+ deadline = CLOCK_FREQ / 40;
+
+ /* Additionnaly, we implicitly wait for the packetization time
+ * multiplied by the number of missing packets. block is the first
+ * non-missing packet (lowest sequence number). We have no better
+ * estimated time of arrival, as we do not know the RTP timestamp
+ * of not yet received packets. */
+ deadline += block->i_pts;
if (now >= deadline)
{
rtp_decode (demux, session, src);