X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fdemux%2Frtpsession.c;h=dd8eaff45eee82fbe0c96bc404404994e3148b4e;hb=34aef4ada6758f39d5af2300b1ac74acdc0b567c;hp=62c24fdcce279332b1b9555f466939f80bc4767a;hpb=3e3e4050ad254cdc5c1e60ca860ea71635a9d244;p=vlc diff --git a/modules/demux/rtpsession.c b/modules/demux/rtpsession.c index 62c24fdcce..dd8eaff45e 100644 --- a/modules/demux/rtpsession.c +++ b/modules/demux/rtpsession.c @@ -136,8 +136,11 @@ int rtp_add_type (demux_t *demux, rtp_session_t *ses, const rtp_pt_t *pt) /** State for an RTP source */ struct rtp_source_t { - mtime_t expiry; /* inactivation date */ uint32_t ssrc; + uint32_t jitter; /* interarrival delay jitter estimate */ + mtime_t last_rx; /* last received packet local timestamp */ + uint32_t last_ts; /* last received packet RTP timestamp */ + uint16_t bad_seq; /* tentatively next expected sequence for resync */ uint16_t max_seq; /* next expected sequence */ @@ -160,6 +163,7 @@ rtp_source_create (demux_t *demux, const rtp_session_t *session, return NULL; source->ssrc = ssrc; + source->jitter = 0; source->max_seq = source->bad_seq = init_seq; source->last_seq = init_seq - 1; source->blocks = NULL; @@ -188,6 +192,10 @@ rtp_source_destroy (demux_t *demux, const rtp_session_t *session, free (source); } +static inline uint8_t rtp_ptype (const block_t *block) +{ + return block->p_buffer[1] & 0x7F; +} static inline uint16_t rtp_seq (const block_t *block) { @@ -195,6 +203,30 @@ static inline uint16_t rtp_seq (const block_t *block) return GetWBE (block->p_buffer + 2); } +static inline uint32_t rtp_timestamp (const block_t *block) +{ + assert (block->i_buffer >= 12); + return GetDWBE (block->p_buffer + 4); +} + +static const struct rtp_pt_t * +rtp_find_ptype (const rtp_session_t *session, rtp_source_t *source, + const block_t *block, void **pt_data) +{ + uint8_t ptype = rtp_ptype (block); + + for (unsigned i = 0; i < session->ptc; i++) + { + if (session->ptv[i].number == ptype) + { + if (pt_data != NULL) + *pt_data = source->opaque[i]; + return &session->ptv[i]; + } + } + return NULL; +} + /** * Receives an RTP packet and queues it. * @param demux VLC demux object @@ -238,7 +270,7 @@ rtp_receive (demux_t *demux, rtp_session_t *session, block_t *block) } /* RTP source garbage collection */ - if (tmp->expiry < now) + if ((tmp->last_rx + (p_sys->timeout * CLOCK_FREQ)) < now) { rtp_source_destroy (demux, session, tmp); if (--session->srcc > 0) @@ -266,7 +298,34 @@ rtp_receive (demux_t *demux, rtp_session_t *session, block_t *block) goto drop; tab[session->srcc++] = src; + /* Cannot compute jitter yet */ } + else + { + const rtp_pt_t *pt = rtp_find_ptype (session, src, block, NULL); + + if (pt != NULL) + { + /* Recompute jitter estimate. + * 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 d = ((now - src->last_rx) * freq) / CLOCK_FREQ; + d -= ts - src->last_ts; + if (d < 0) d = -d; + src->jitter += ((d - src->jitter) + 8) >> 4; + } + } + 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, @@ -299,8 +358,11 @@ rtp_receive (demux_t *demux, rtp_session_t *session, block_t *block) block_t **pp = &src->blocks; for (block_t *prev = *pp; prev != NULL; prev = *pp) { - if ((int16_t)(seq - rtp_seq (*pp)) < 0) + int16_t delta_seq = seq - rtp_seq (prev); + if (delta_seq < 0) break; + if (delta_seq == 0) + goto drop; /* duplicate */ pp = &prev->p_next; } block->p_next = *pp; @@ -332,23 +394,12 @@ rtp_decode (demux_t *demux, const rtp_session_t *session, rtp_source_t *src) src->last_seq = rtp_seq (block); /* Match the payload type */ - const rtp_pt_t *pt = NULL; - void *pt_data = NULL; - const uint8_t ptype = block->p_buffer[1] & 0x7F; - - for (unsigned i = 0; i < session->ptc; i++) - { - if (session->ptv[i].number == ptype) - { - pt = &session->ptv[i]; - pt_data = src->opaque[i]; - break; - } - } - + void *pt_data; + const rtp_pt_t *pt = rtp_find_ptype (session, src, block, &pt_data); if (pt == NULL) { - msg_Dbg (demux, "ignoring unknown payload (%"PRIu8")", ptype); + msg_Dbg (demux, "ignoring unknown payload (%"PRIu8")", + rtp_ptype (block)); goto drop; } @@ -358,7 +409,7 @@ rtp_decode (demux_t *demux, const rtp_session_t *session, rtp_source_t *src) * Otherwise it would be impossible to compute consistent timestamps. */ /* FIXME: handle timestamp wrap properly */ /* TODO: sync multiple sources sanely... */ - const uint32_t timestamp = GetDWBE (block->p_buffer + 4); + const uint32_t timestamp = rtp_timestamp (block); block->i_pts = UINT64_C(1) * CLOCK_FREQ * timestamp / pt->frequency; /* CSRC count */