rtpsource: doesn't handle probation and rtp gap in case of sender

https://bugzilla.gnome.org/show_bug.cgi?id=754548
This commit is contained in:
Hyunjun Ko 2015-10-02 16:18:15 +09:00 committed by Sebastian Dröge
parent 2b1f52755d
commit b814d7ed25

View file

@ -1005,7 +1005,8 @@ do_bitrate_estimation (RTPSource * src, GstClockTime running_time,
} }
static gboolean static gboolean
update_receiver_stats (RTPSource * src, RTPPacketInfo * pinfo) update_receiver_stats (RTPSource * src, RTPPacketInfo * pinfo,
gboolean is_receive)
{ {
guint16 seqnr, expected; guint16 seqnr, expected;
RTPSourceStats *stats; RTPSourceStats *stats;
@ -1023,80 +1024,82 @@ update_receiver_stats (RTPSource * src, RTPPacketInfo * pinfo)
src->curr_probation = src->probation; src->curr_probation = src->probation;
} }
expected = src->stats.max_seq + 1; if (is_receive) {
delta = gst_rtp_buffer_compare_seqnum (expected, seqnr); expected = src->stats.max_seq + 1;
delta = gst_rtp_buffer_compare_seqnum (expected, seqnr);
/* if we are still on probation, check seqnum */ /* if we are still on probation, check seqnum */
if (src->curr_probation) { if (src->curr_probation) {
/* when in probation, we require consecutive seqnums */ /* when in probation, we require consecutive seqnums */
if (delta == 0) { if (delta == 0) {
/* expected packet */ /* expected packet */
GST_DEBUG ("probation: seqnr %d == expected %d", seqnr, expected); GST_DEBUG ("probation: seqnr %d == expected %d", seqnr, expected);
src->curr_probation--; src->curr_probation--;
if (seqnr < stats->max_seq) {
/* sequence number wrapped - count another 64K cycle. */
stats->cycles += RTP_SEQ_MOD;
}
src->stats.max_seq = seqnr;
if (src->curr_probation == 0) {
GST_DEBUG ("probation done!");
init_seq (src, seqnr);
} else {
GstBuffer *q;
GST_DEBUG ("probation %d: queue packet", src->curr_probation);
/* when still in probation, keep packets in a list. */
g_queue_push_tail (src->packets, pinfo->data);
pinfo->data = NULL;
/* remove packets from queue if there are too many */
while (g_queue_get_length (src->packets) > RTP_MAX_PROBATION_LEN) {
q = g_queue_pop_head (src->packets);
gst_buffer_unref (q);
}
goto done;
}
} else {
/* unexpected seqnum in probation */
goto probation_seqnum;
}
} else if (delta >= 0 && delta < RTP_MAX_DROPOUT) {
/* Clear bad packets */
stats->bad_seq = RTP_SEQ_MOD + 1; /* so seq == bad_seq is false */
g_queue_foreach (src->packets, (GFunc) gst_buffer_unref, NULL);
g_queue_clear (src->packets);
/* in order, with permissible gap */
if (seqnr < stats->max_seq) { if (seqnr < stats->max_seq) {
/* sequence number wrapped - count another 64K cycle. */ /* sequence number wrapped - count another 64K cycle. */
stats->cycles += RTP_SEQ_MOD; stats->cycles += RTP_SEQ_MOD;
} }
src->stats.max_seq = seqnr; stats->max_seq = seqnr;
} else if (delta < -RTP_MAX_MISORDER || delta >= RTP_MAX_DROPOUT) {
if (src->curr_probation == 0) { /* the sequence number made a very large jump */
GST_DEBUG ("probation done!"); if (seqnr == stats->bad_seq && src->packets->head) {
/* two sequential packets -- assume that the other side
* restarted without telling us so just re-sync
* (i.e., pretend this was the first packet). */
init_seq (src, seqnr); init_seq (src, seqnr);
} else { } else {
GstBuffer *q; /* unacceptable jump */
stats->bad_seq = (seqnr + 1) & (RTP_SEQ_MOD - 1);
GST_DEBUG ("probation %d: queue packet", src->curr_probation); g_queue_foreach (src->packets, (GFunc) gst_buffer_unref, NULL);
/* when still in probation, keep packets in a list. */ g_queue_clear (src->packets);
g_queue_push_tail (src->packets, pinfo->data); g_queue_push_tail (src->packets, pinfo->data);
pinfo->data = NULL; pinfo->data = NULL;
/* remove packets from queue if there are too many */ goto bad_sequence;
while (g_queue_get_length (src->packets) > RTP_MAX_PROBATION_LEN) {
q = g_queue_pop_head (src->packets);
gst_buffer_unref (q);
}
goto done;
} }
} else { } else { /* delta < 0 && delta >= -RTP_MAX_MISORDER */
/* unexpected seqnum in probation */ /* Clear bad packets */
goto probation_seqnum; stats->bad_seq = RTP_SEQ_MOD + 1; /* so seq == bad_seq is false */
}
} else if (delta >= 0 && delta < RTP_MAX_DROPOUT) {
/* Clear bad packets */
stats->bad_seq = RTP_SEQ_MOD + 1; /* so seq == bad_seq is false */
g_queue_foreach (src->packets, (GFunc) gst_buffer_unref, NULL);
g_queue_clear (src->packets);
/* in order, with permissible gap */
if (seqnr < stats->max_seq) {
/* sequence number wrapped - count another 64K cycle. */
stats->cycles += RTP_SEQ_MOD;
}
stats->max_seq = seqnr;
} else if (delta < -RTP_MAX_MISORDER || delta >= RTP_MAX_DROPOUT) {
/* the sequence number made a very large jump */
if (seqnr == stats->bad_seq && src->packets->head) {
/* two sequential packets -- assume that the other side
* restarted without telling us so just re-sync
* (i.e., pretend this was the first packet). */
init_seq (src, seqnr);
} else {
/* unacceptable jump */
stats->bad_seq = (seqnr + 1) & (RTP_SEQ_MOD - 1);
g_queue_foreach (src->packets, (GFunc) gst_buffer_unref, NULL); g_queue_foreach (src->packets, (GFunc) gst_buffer_unref, NULL);
g_queue_clear (src->packets); g_queue_clear (src->packets);
g_queue_push_tail (src->packets, pinfo->data);
pinfo->data = NULL;
goto bad_sequence;
}
} else { /* delta < 0 && delta >= -RTP_MAX_MISORDER */
/* Clear bad packets */
stats->bad_seq = RTP_SEQ_MOD + 1; /* so seq == bad_seq is false */
g_queue_foreach (src->packets, (GFunc) gst_buffer_unref, NULL);
g_queue_clear (src->packets);
/* duplicate or reordered packet, will be filtered by jitterbuffer. */ /* duplicate or reordered packet, will be filtered by jitterbuffer. */
GST_WARNING ("duplicate or reordered packet (seqnr %u, expected %u)", seqnr, GST_WARNING ("duplicate or reordered packet (seqnr %u, expected %u)",
expected); seqnr, expected);
}
} }
src->stats.octets_received += pinfo->payload_len; src->stats.octets_received += pinfo->payload_len;
@ -1146,7 +1149,7 @@ rtp_source_process_rtp (RTPSource * src, RTPPacketInfo * pinfo)
g_return_val_if_fail (RTP_IS_SOURCE (src), GST_FLOW_ERROR); g_return_val_if_fail (RTP_IS_SOURCE (src), GST_FLOW_ERROR);
g_return_val_if_fail (pinfo != NULL, GST_FLOW_ERROR); g_return_val_if_fail (pinfo != NULL, GST_FLOW_ERROR);
if (!update_receiver_stats (src, pinfo)) if (!update_receiver_stats (src, pinfo, TRUE))
return GST_FLOW_OK; return GST_FLOW_OK;
/* the source that sent the packet must be a sender */ /* the source that sent the packet must be a sender */
@ -1217,7 +1220,7 @@ rtp_source_send_rtp (RTPSource * src, RTPPacketInfo * pinfo)
src->is_sender = TRUE; src->is_sender = TRUE;
/* we are also a receiver of our packets */ /* we are also a receiver of our packets */
if (!update_receiver_stats (src, pinfo)) if (!update_receiver_stats (src, pinfo, FALSE))
return GST_FLOW_OK; return GST_FLOW_OK;
/* update stats for the SR */ /* update stats for the SR */