X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Faccess%2Frtp%2Fsession.c;h=267928e0169b3011bb6ad533c3543845163d43b8;hb=e0fa673d823a064e44e51c04985ba9accdfc5389;hp=e9bf3cb5a76813d2c97955c412f8506f505214f4;hpb=f42519569ab210c229f6bf0dfec7863daa1ec613;p=vlc diff --git a/modules/access/rtp/session.c b/modules/access/rtp/session.c index e9bf3cb5a7..267928e016 100644 --- a/modules/access/rtp/session.c +++ b/modules/access/rtp/session.c @@ -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 #include -#include +#include #include #include "rtp.h" @@ -141,10 +141,13 @@ struct rtp_source_t 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 */ }; @@ -164,6 +167,9 @@ rtp_source_create (demux_t *demux, const rtp_session_t *session, 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; @@ -266,7 +272,7 @@ rtp_queue (demux_t *demux, rtp_session_t *session, block_t *block) } /* 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) @@ -306,7 +312,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; @@ -314,40 +320,35 @@ rtp_queue (demux_t *demux, rtp_session_t *session, block_t *block) } } 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. */ @@ -358,7 +359,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; @@ -386,11 +390,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); @@ -400,7 +405,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; } @@ -409,10 +414,12 @@ rtp_decode (demux_t *demux, const rtp_session_t *session, rtp_source_t *src) * 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; @@ -456,6 +463,8 @@ bool rtp_dequeue (demux_t *demux, const rtp_session_t *session, 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]; @@ -467,35 +476,44 @@ bool rtp_dequeue (demux_t *demux, const rtp_session_t *session, * * 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. */ 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. + * 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);