mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-27 12:11:13 +00:00
rtpjitterbuffer: Limit size to 2^15 packets
If it goes over 2^15 packets, it will think it has rolled over and start dropping all packets. So make sure the seqnum distance is not too big. But let's not limit it to a number that is too small to avoid emptying it needlessly if there is a spurious huge sequence number, let's allow at least 10k packets in any case.
This commit is contained in:
parent
086bad4643
commit
bf00ee46de
3 changed files with 78 additions and 0 deletions
|
@ -200,6 +200,20 @@ enum
|
||||||
(g_mutex_unlock (&(priv)->jbuf_lock)); \
|
(g_mutex_unlock (&(priv)->jbuf_lock)); \
|
||||||
} G_STMT_END
|
} G_STMT_END
|
||||||
|
|
||||||
|
#define JBUF_WAIT_QUEUE(priv) G_STMT_START { \
|
||||||
|
GST_DEBUG ("waiting queue"); \
|
||||||
|
(priv)->waiting_queue++; \
|
||||||
|
g_cond_wait (&(priv)->jbuf_queue, &(priv)->jbuf_lock); \
|
||||||
|
(priv)->waiting_queue--; \
|
||||||
|
GST_DEBUG ("waiting queue done"); \
|
||||||
|
} G_STMT_END
|
||||||
|
#define JBUF_SIGNAL_QUEUE(priv) G_STMT_START { \
|
||||||
|
if (G_UNLIKELY ((priv)->waiting_queue)) { \
|
||||||
|
GST_DEBUG ("signal queue, %d waiters", (priv)->waiting_queue); \
|
||||||
|
g_cond_signal (&(priv)->jbuf_queue); \
|
||||||
|
} \
|
||||||
|
} G_STMT_END
|
||||||
|
|
||||||
#define JBUF_WAIT_TIMER(priv) G_STMT_START { \
|
#define JBUF_WAIT_TIMER(priv) G_STMT_START { \
|
||||||
GST_DEBUG ("waiting timer"); \
|
GST_DEBUG ("waiting timer"); \
|
||||||
(priv)->waiting_timer++; \
|
(priv)->waiting_timer++; \
|
||||||
|
@ -263,6 +277,8 @@ struct _GstRtpJitterBufferPrivate
|
||||||
|
|
||||||
RTPJitterBuffer *jbuf;
|
RTPJitterBuffer *jbuf;
|
||||||
GMutex jbuf_lock;
|
GMutex jbuf_lock;
|
||||||
|
gboolean waiting_queue;
|
||||||
|
GCond jbuf_queue;
|
||||||
gboolean waiting_timer;
|
gboolean waiting_timer;
|
||||||
GCond jbuf_timer;
|
GCond jbuf_timer;
|
||||||
gboolean waiting_event;
|
gboolean waiting_event;
|
||||||
|
@ -1025,6 +1041,7 @@ gst_rtp_jitter_buffer_init (GstRtpJitterBuffer * jitterbuffer)
|
||||||
priv->rtx_stats_timers = timer_queue_new ();
|
priv->rtx_stats_timers = timer_queue_new ();
|
||||||
priv->jbuf = rtp_jitter_buffer_new ();
|
priv->jbuf = rtp_jitter_buffer_new ();
|
||||||
g_mutex_init (&priv->jbuf_lock);
|
g_mutex_init (&priv->jbuf_lock);
|
||||||
|
g_cond_init (&priv->jbuf_queue);
|
||||||
g_cond_init (&priv->jbuf_timer);
|
g_cond_init (&priv->jbuf_timer);
|
||||||
g_cond_init (&priv->jbuf_event);
|
g_cond_init (&priv->jbuf_event);
|
||||||
g_cond_init (&priv->jbuf_query);
|
g_cond_init (&priv->jbuf_query);
|
||||||
|
@ -1130,6 +1147,7 @@ gst_rtp_jitter_buffer_finalize (GObject * object)
|
||||||
g_array_free (priv->timers, TRUE);
|
g_array_free (priv->timers, TRUE);
|
||||||
timer_queue_free (priv->rtx_stats_timers);
|
timer_queue_free (priv->rtx_stats_timers);
|
||||||
g_mutex_clear (&priv->jbuf_lock);
|
g_mutex_clear (&priv->jbuf_lock);
|
||||||
|
g_cond_clear (&priv->jbuf_queue);
|
||||||
g_cond_clear (&priv->jbuf_timer);
|
g_cond_clear (&priv->jbuf_timer);
|
||||||
g_cond_clear (&priv->jbuf_event);
|
g_cond_clear (&priv->jbuf_event);
|
||||||
g_cond_clear (&priv->jbuf_query);
|
g_cond_clear (&priv->jbuf_query);
|
||||||
|
@ -1578,6 +1596,7 @@ gst_rtp_jitter_buffer_flush_start (GstRtpJitterBuffer * jitterbuffer)
|
||||||
/* this unblocks any waiting pops on the src pad task */
|
/* this unblocks any waiting pops on the src pad task */
|
||||||
JBUF_SIGNAL_EVENT (priv);
|
JBUF_SIGNAL_EVENT (priv);
|
||||||
JBUF_SIGNAL_QUERY (priv, FALSE);
|
JBUF_SIGNAL_QUERY (priv, FALSE);
|
||||||
|
JBUF_SIGNAL_QUEUE (priv);
|
||||||
JBUF_UNLOCK (priv);
|
JBUF_UNLOCK (priv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1683,6 +1702,7 @@ gst_rtp_jitter_buffer_change_state (GstElement * element,
|
||||||
/* block until we go to PLAYING */
|
/* block until we go to PLAYING */
|
||||||
priv->blocked = TRUE;
|
priv->blocked = TRUE;
|
||||||
priv->timer_running = TRUE;
|
priv->timer_running = TRUE;
|
||||||
|
priv->srcresult = GST_FLOW_OK;
|
||||||
priv->timer_thread =
|
priv->timer_thread =
|
||||||
g_thread_new ("timer", (GThreadFunc) wait_next_timeout, jitterbuffer);
|
g_thread_new ("timer", (GThreadFunc) wait_next_timeout, jitterbuffer);
|
||||||
JBUF_UNLOCK (priv);
|
JBUF_UNLOCK (priv);
|
||||||
|
@ -1721,9 +1741,11 @@ gst_rtp_jitter_buffer_change_state (GstElement * element,
|
||||||
JBUF_LOCK (priv);
|
JBUF_LOCK (priv);
|
||||||
gst_buffer_replace (&priv->last_sr, NULL);
|
gst_buffer_replace (&priv->last_sr, NULL);
|
||||||
priv->timer_running = FALSE;
|
priv->timer_running = FALSE;
|
||||||
|
priv->srcresult = GST_FLOW_FLUSHING;
|
||||||
unschedule_current_timer (jitterbuffer);
|
unschedule_current_timer (jitterbuffer);
|
||||||
JBUF_SIGNAL_TIMER (priv);
|
JBUF_SIGNAL_TIMER (priv);
|
||||||
JBUF_SIGNAL_QUERY (priv, FALSE);
|
JBUF_SIGNAL_QUERY (priv, FALSE);
|
||||||
|
JBUF_SIGNAL_QUEUE (priv);
|
||||||
JBUF_UNLOCK (priv);
|
JBUF_UNLOCK (priv);
|
||||||
g_thread_join (priv->timer_thread);
|
g_thread_join (priv->timer_thread);
|
||||||
priv->timer_thread = NULL;
|
priv->timer_thread = NULL;
|
||||||
|
@ -3131,6 +3153,17 @@ gst_rtp_jitter_buffer_chain (GstPad * pad, GstObject * parent,
|
||||||
timer->num_rtx_received++;
|
timer->num_rtx_received++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* At 2^15, we would detect a seqnum rollover too early, therefore
|
||||||
|
* limit the queue size. But let's not limit it to a number that is
|
||||||
|
* too small to avoid emptying it needlessly if there is a spurious huge
|
||||||
|
* sequence number, let's allow at least 10k packets in any case. */
|
||||||
|
while (rtp_jitter_buffer_get_seqnum_diff (priv->jbuf) >= 32765 &&
|
||||||
|
rtp_jitter_buffer_num_packets (priv->jbuf) > 10000 &&
|
||||||
|
priv->srcresult == GST_FLOW_OK)
|
||||||
|
JBUF_WAIT_QUEUE (priv);
|
||||||
|
if (priv->srcresult != GST_FLOW_OK)
|
||||||
|
goto out_flushing;
|
||||||
|
|
||||||
/* let's check if this buffer is too late, we can only accept packets with
|
/* let's check if this buffer is too late, we can only accept packets with
|
||||||
* bigger seqnum than the one we last pushed. */
|
* bigger seqnum than the one we last pushed. */
|
||||||
if (G_LIKELY (priv->last_popped_seqnum != -1)) {
|
if (G_LIKELY (priv->last_popped_seqnum != -1)) {
|
||||||
|
@ -4190,6 +4223,7 @@ gst_rtp_jitter_buffer_loop (GstRtpJitterBuffer * jitterbuffer)
|
||||||
JBUF_LOCK_CHECK (priv, flushing);
|
JBUF_LOCK_CHECK (priv, flushing);
|
||||||
do {
|
do {
|
||||||
result = handle_next_buffer (jitterbuffer);
|
result = handle_next_buffer (jitterbuffer);
|
||||||
|
JBUF_SIGNAL_QUEUE (priv);
|
||||||
if (G_LIKELY (result == GST_FLOW_WAIT)) {
|
if (G_LIKELY (result == GST_FLOW_WAIT)) {
|
||||||
/* now wait for the next event */
|
/* now wait for the next event */
|
||||||
JBUF_WAIT_EVENT (priv, flushing);
|
JBUF_WAIT_EVENT (priv, flushing);
|
||||||
|
|
|
@ -1227,6 +1227,49 @@ rtp_jitter_buffer_get_ts_diff (RTPJitterBuffer * jbuf)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* rtp_jitter_buffer_get_seqnum_diff:
|
||||||
|
* @jbuf: an #RTPJitterBuffer
|
||||||
|
*
|
||||||
|
* Get the difference between the seqnum of first and last packet in the
|
||||||
|
* jitterbuffer.
|
||||||
|
*
|
||||||
|
* Returns: The difference expressed in seqnum.
|
||||||
|
*/
|
||||||
|
guint16
|
||||||
|
rtp_jitter_buffer_get_seqnum_diff (RTPJitterBuffer * jbuf)
|
||||||
|
{
|
||||||
|
guint32 high_seqnum, low_seqnum;
|
||||||
|
RTPJitterBufferItem *high_buf, *low_buf;
|
||||||
|
guint16 result;
|
||||||
|
|
||||||
|
g_return_val_if_fail (jbuf != NULL, 0);
|
||||||
|
|
||||||
|
high_buf = (RTPJitterBufferItem *) g_queue_peek_tail_link (jbuf->packets);
|
||||||
|
low_buf = (RTPJitterBufferItem *) g_queue_peek_head_link (jbuf->packets);
|
||||||
|
|
||||||
|
while (high_buf && high_buf->seqnum == -1)
|
||||||
|
high_buf = (RTPJitterBufferItem *) high_buf->prev;
|
||||||
|
|
||||||
|
while (low_buf && low_buf->seqnum == -1)
|
||||||
|
low_buf = (RTPJitterBufferItem *) low_buf->next;
|
||||||
|
|
||||||
|
if (!high_buf || !low_buf || high_buf == low_buf)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
high_seqnum = high_buf->seqnum;
|
||||||
|
low_seqnum = low_buf->seqnum;
|
||||||
|
|
||||||
|
/* it needs to work if ts wraps */
|
||||||
|
if (high_seqnum >= low_seqnum) {
|
||||||
|
result = (guint32) (high_seqnum - low_seqnum);
|
||||||
|
} else {
|
||||||
|
result = (guint32) (high_seqnum + G_MAXUINT16 + 1 - low_seqnum);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* rtp_jitter_buffer_get_sync:
|
* rtp_jitter_buffer_get_sync:
|
||||||
* @jbuf: an #RTPJitterBuffer
|
* @jbuf: an #RTPJitterBuffer
|
||||||
|
|
|
@ -184,6 +184,7 @@ gint rtp_jitter_buffer_get_percent (RTPJitterBuffer * jbuf
|
||||||
|
|
||||||
guint rtp_jitter_buffer_num_packets (RTPJitterBuffer *jbuf);
|
guint rtp_jitter_buffer_num_packets (RTPJitterBuffer *jbuf);
|
||||||
guint32 rtp_jitter_buffer_get_ts_diff (RTPJitterBuffer *jbuf);
|
guint32 rtp_jitter_buffer_get_ts_diff (RTPJitterBuffer *jbuf);
|
||||||
|
guint16 rtp_jitter_buffer_get_seqnum_diff (RTPJitterBuffer * jbuf);
|
||||||
|
|
||||||
void rtp_jitter_buffer_get_sync (RTPJitterBuffer *jbuf, guint64 *rtptime,
|
void rtp_jitter_buffer_get_sync (RTPJitterBuffer *jbuf, guint64 *rtptime,
|
||||||
guint64 *timestamp, guint32 *clock_rate,
|
guint64 *timestamp, guint32 *clock_rate,
|
||||||
|
|
Loading…
Reference in a new issue