From ae536e0c8920ca75190d81ec45894f12faceb3c2 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 25 Apr 2007 13:19:36 +0000 Subject: [PATCH] gst/rtpmanager/gstrtpjitterbuffer.c: Report NO_PREROLL when going to PAUSED. Original commit message from CVS: * gst/rtpmanager/gstrtpjitterbuffer.c: (gst_rtp_jitter_buffer_change_state): Report NO_PREROLL when going to PAUSED. * gst/rtpmanager/gstrtpsession.c: (rtcp_thread): Don't send RTCP right before we are shutting down. * gst/rtpmanager/rtpsession.c: (rtp_session_process_rtp), (rtp_session_process_sr), (session_report_blocks), (rtp_session_perform_reporting): Improve report blocks. * gst/rtpmanager/rtpsource.c: (calculate_jitter), (init_seq), (rtp_source_process_rtp), (rtp_source_process_sr), (rtp_source_process_rb), (rtp_source_get_last_sr), (rtp_source_get_last_rb): * gst/rtpmanager/rtpsource.h: * gst/rtpmanager/rtpstats.h: Cleanups, add methods to access stats. --- gst/rtpmanager/gstrtpjitterbuffer.c | 2 + gst/rtpmanager/gstrtpsession.c | 16 ++-- gst/rtpmanager/rtpsession.c | 54 ++++++++----- gst/rtpmanager/rtpsource.c | 120 ++++++++++++++++++++++++---- gst/rtpmanager/rtpsource.h | 8 +- gst/rtpmanager/rtpstats.h | 3 +- 6 files changed, 161 insertions(+), 42 deletions(-) diff --git a/gst/rtpmanager/gstrtpjitterbuffer.c b/gst/rtpmanager/gstrtpjitterbuffer.c index 1973e9b432..cad8324a9e 100644 --- a/gst/rtpmanager/gstrtpjitterbuffer.c +++ b/gst/rtpmanager/gstrtpjitterbuffer.c @@ -553,6 +553,8 @@ gst_rtp_jitter_buffer_change_state (GstElement * element, async_jitter_queue_set_blocking_unlocked (jitterbuffer->priv->queue, TRUE); async_jitter_queue_unlock (priv->queue); + if (ret != GST_STATE_CHANGE_FAILURE) + ret = GST_STATE_CHANGE_NO_PREROLL; break; case GST_STATE_CHANGE_PAUSED_TO_READY: break; diff --git a/gst/rtpmanager/gstrtpsession.c b/gst/rtpmanager/gstrtpsession.c index b11dbbba2e..39c63e3299 100644 --- a/gst/rtpmanager/gstrtpsession.c +++ b/gst/rtpmanager/gstrtpsession.c @@ -304,21 +304,27 @@ rtcp_thread (GstRTPSession * rtpsession) while (!rtpsession->priv->stop_thread) { gdouble timeout; GstClockTime target; + GstClockReturn res; timeout = rtp_session_get_reporting_interval (rtpsession->priv->session); GST_DEBUG_OBJECT (rtpsession, "next RTCP timeout: %lf", timeout); target = gst_clock_get_time (clock); target += GST_SECOND * timeout; + + id = rtpsession->priv->id = gst_clock_new_single_shot_id (clock, target); GST_RTP_SESSION_UNLOCK (rtpsession); - gst_clock_id_wait (id, NULL); + res = gst_clock_id_wait (id, NULL); + if (res != GST_CLOCK_UNSCHEDULED) { + GST_DEBUG_OBJECT (rtpsession, "got RTCP timeout"); - GST_DEBUG_OBJECT (rtpsession, "got RTCP timeout"); - - /* make the session manager produce RTCP, we ignore the result. */ - rtp_session_perform_reporting (rtpsession->priv->session); + /* make the session manager produce RTCP, we ignore the result. */ + rtp_session_perform_reporting (rtpsession->priv->session); + } else { + GST_DEBUG_OBJECT (rtpsession, "got unscheduled"); + } GST_RTP_SESSION_LOCK (rtpsession); gst_clock_id_unref (id); diff --git a/gst/rtpmanager/rtpsession.c b/gst/rtpmanager/rtpsession.c index e4925a2af0..27d6dabb77 100644 --- a/gst/rtpmanager/rtpsession.c +++ b/gst/rtpmanager/rtpsession.c @@ -893,6 +893,7 @@ rtp_session_process_rtp (RTPSession * sess, GstBuffer * buffer) prevsender = RTP_SOURCE_IS_SENDER (source); prevactive = RTP_SOURCE_IS_ACTIVE (source); + /* we need to ref so that we can process the CSRCs later */ gst_buffer_ref (buffer); /* let source process the packet */ @@ -982,7 +983,8 @@ rtp_session_process_sr (RTPSession * sess, GstRTCPPacket * packet, prevsender = RTP_SOURCE_IS_SENDER (source); /* first update the source */ - rtp_source_process_sr (source, ntptime, rtptime, packet_count, octet_count); + rtp_source_process_sr (source, ntptime, rtptime, packet_count, octet_count, + arrival->time); if (prevsender != RTP_SOURCE_IS_SENDER (source)) { sess->stats.sender_sources++; @@ -1004,7 +1006,7 @@ rtp_session_process_sr (RTPSession * sess, GstRTCPPacket * packet, if (ssrc == sess->source->ssrc) { /* only deal with report blocks for our session, we update the stats of - * the sender of the TCP message. We could also compare our stats against + * the sender of the RTCP message. We could also compare our stats against * the other sender to see if we are better or worse. */ rtp_source_process_rb (source, fractionlost, packetslost, exthighestseq, jitter, lsr, dlsr); @@ -1292,6 +1294,7 @@ typedef struct { RTPSession *sess; GstBuffer *rtcp; + GstClockTime time; GstRTCPPacket packet; } ReportData; @@ -1322,29 +1325,25 @@ session_report_blocks (const gchar * key, RTPSource * source, ReportData * data) } } if (gst_rtcp_packet_get_rb_count (packet) < GST_RTCP_MAX_RB_COUNT) { - /* only report about other sources */ - if (source != sess->source) { + /* only report about other sender sources */ + if (source != sess->source && RTP_SOURCE_IS_SENDER (source)) { RTPSourceStats *stats; - guint32 extended_max, expected; - guint32 expected_interval, received_interval; - guint32 lost, lost_interval, fraction; + guint64 extended_max, expected; + guint64 expected_interval, received_interval, ntptime; + gint64 lost, lost_interval; + guint32 fraction, LSR, DLSR; + GstClockTime time; stats = &source->stats; - extended_max = (stats->cycles << 16) + stats->max_seq; + extended_max = stats->cycles + stats->max_seq; expected = extended_max - stats->base_seq + 1; - if (expected > stats->packets_received) { - lost = expected - stats->packets_received; - if (lost > 0x7fffff) - lost = 0x7fffff; - } else { - lost = stats->packets_received - expected; - if (lost > 0x800000) - lost = 0x800000; - else - lost = -lost; - } + GST_DEBUG ("ext_max %d, expected %d, received %d, base_seq %d", + extended_max, expected, stats->packets_received, stats->base_seq); + + lost = expected - stats->packets_received; + lost = CLAMP (lost, -0x800000, 0x7fffff); expected_interval = expected - stats->prev_expected; stats->prev_expected = expected; @@ -1363,9 +1362,21 @@ session_report_blocks (const gchar * key, RTPSource * source, ReportData * data) GST_DEBUG ("fraction %d, lost %d, extseq %u, jitter %d", fraction, lost, extended_max, stats->jitter >> 4); + if (rtp_source_get_last_sr (source, &ntptime, NULL, NULL, NULL, &time)) { + /* LSR is middle bits of the last ntptime */ + LSR = (ntptime >> 16) & 0xffffffff; + /* DLSR, delay since last SR is expressed in 1/65536 second units */ + DLSR = gst_util_uint64_scale_int (data->time - time, 65536, GST_SECOND); + } else { + /* No valid SR received, LSR/DLSR are set to 0 then */ + LSR = 0; + DLSR = 0; + } + GST_DEBUG ("LSR %08x, DLSR %08x", LSR, DLSR); + /* packet is not yet filled, add report block for this source. */ gst_rtcp_packet_add_rb (packet, source->ssrc, fraction, lost, - extended_max, stats->jitter >> 4, 0, 0); + extended_max, stats->jitter >> 4, LSR, DLSR); } } } @@ -1413,6 +1424,9 @@ rtp_session_perform_reporting (RTPSession * sess) data.sess = sess; data.rtcp = NULL; + /* get time so it can be used later */ + data.time = sess->callbacks.get_time (sess, sess->user_data); + RTP_SESSION_LOCK (sess); /* loop over all known sources and do something */ g_hash_table_foreach (sess->ssrcs[sess->mask_idx], diff --git a/gst/rtpmanager/rtpsource.c b/gst/rtpmanager/rtpsource.c index 43acb0847a..e1e6aaca55 100644 --- a/gst/rtpmanager/rtpsource.c +++ b/gst/rtpmanager/rtpsource.c @@ -248,15 +248,19 @@ calculate_jitter (RTPSource * src, GstBuffer * buffer, /* transit time is difference with RTP timestamp */ transit = rtparrival - rtptime; - /* get diff with previous transit time */ - if (src->stats.transit != -1) - diff = transit - src->stats.transit; - else + + /* get ABS diff with previous transit time */ + if (src->stats.transit != -1) { + if (transit > src->stats.transit) + diff = transit - src->stats.transit; + else + diff = src->stats.transit - transit; + } else diff = 0; + src->stats.transit = transit; - if (diff < 0) - diff = -diff; - /* update jitter */ + + /* update jitter, the value we store is scaled up so we can keep precision. */ src->stats.jitter += diff - ((src->stats.jitter + 8) >> 4); src->stats.prev_rtptime = src->stats.last_rtptime; @@ -292,6 +296,8 @@ init_seq (RTPSource * src, guint16 seq) src->stats.bytes_received = 0; src->stats.prev_received = 0; src->stats.prev_expected = 0; + + GST_DEBUG ("base_seq %d", seq); } /** @@ -319,7 +325,7 @@ rtp_source_process_rtp (RTPSource * src, GstBuffer * buffer, seqnr = gst_rtp_buffer_get_seq (buffer); if (stats->cycles == -1) { - GST_DEBUG ("first buffer"); + GST_DEBUG ("received first buffer"); /* first time we heard of this source */ init_seq (src, seqnr); src->stats.max_seq = seqnr - 1; @@ -366,7 +372,7 @@ rtp_source_process_rtp (RTPSource * src, GstBuffer * buffer, /* in order, with permissible gap */ if (seqnr < stats->max_seq) { /* sequence number wrapped - count another 64K cycle. */ - stats->cycles++; + stats->cycles += RTP_SEQ_MOD; } stats->max_seq = seqnr; } else if (udelta <= RTP_SEQ_MOD - RTP_MAX_MISORDER) { @@ -392,8 +398,8 @@ rtp_source_process_rtp (RTPSource * src, GstBuffer * buffer, src->is_sender = TRUE; src->validated = TRUE; - GST_DEBUG ("PC: %" G_GUINT64_FORMAT ", OC: %" G_GUINT64_FORMAT, - src->stats.packets_received, src->stats.octets_received); + GST_DEBUG ("seq %d, PC: %" G_GUINT64_FORMAT ", OC: %" G_GUINT64_FORMAT, + seqnr, src->stats.packets_received, src->stats.octets_received); /* calculate jitter */ calculate_jitter (src, buffer, arrival); @@ -470,20 +476,21 @@ rtp_source_send_rtp (RTPSource * src, GstBuffer * buffer) * @rtptime: the RTP time * @packet_count: the packet count * @octet_count: the octect count + * @time: time of packet arrival * * Update the sender report in @src. */ void rtp_source_process_sr (RTPSource * src, guint64 ntptime, guint32 rtptime, - guint32 packet_count, guint32 octet_count) + guint32 packet_count, guint32 octet_count, GstClockTime time) { RTPSenderReport *curr; gint curridx; g_return_if_fail (RTP_IS_SOURCE (src)); - GST_DEBUG ("got SR packet: SSRC %08x, NTP %" G_GUINT64_FORMAT - ", RTP %u, PC %u, OC %u", src->ssrc, ntptime, rtptime, packet_count, + GST_DEBUG ("got SR packet: SSRC %08x, NTP %08x:%08x, RTP %u, PC %u, OC %u", + src->ssrc, ntptime >> 32, ntptime & 0xffffffff, rtptime, packet_count, octet_count); curridx = src->stats.curr_sr ^ 1; @@ -498,6 +505,7 @@ rtp_source_process_sr (RTPSource * src, guint64 ntptime, guint32 rtptime, curr->rtptime = rtptime; curr->packet_count = packet_count; curr->octet_count = octet_count; + curr->time = time; /* make current */ src->stats.curr_sr = curridx; @@ -525,7 +533,7 @@ rtp_source_process_rb (RTPSource * src, guint8 fractionlost, gint32 packetslost, g_return_if_fail (RTP_IS_SOURCE (src)); GST_DEBUG ("got RB packet %d: SSRC %08x, FL %u" - ", PL %u, HS %u, JITTER %u, LSR %u, DLSR %u", src->ssrc, fractionlost, + ", PL %u, HS %u, JITTER %u, LSR %08x, DLSR %08x", src->ssrc, fractionlost, packetslost, exthighestseq, jitter, lsr, dlsr); curridx = src->stats.curr_rr ^ 1; @@ -543,3 +551,85 @@ rtp_source_process_rb (RTPSource * src, guint8 fractionlost, gint32 packetslost, /* make current */ src->stats.curr_rr = curridx; } + +/** + * rtp_source_get_last_sr: + * @src: an #RTPSource + * @ntptime: the NTP time + * @rtptime: the RTP time + * @packet_count: the packet count + * @octet_count: the octect count + * @time: time of packet arrival + * + * Get the values of the last sender report as set with rtp_source_process_sr(). + * + * Returns: %TRUE if there was a valid SR report. + */ +gboolean +rtp_source_get_last_sr (RTPSource * src, guint64 * ntptime, guint32 * rtptime, + guint32 * packet_count, guint32 * octet_count, GstClockTime * time) +{ + RTPSenderReport *curr; + + g_return_val_if_fail (RTP_IS_SOURCE (src), FALSE); + + curr = &src->stats.sr[src->stats.curr_sr]; + if (!curr->is_valid) + return FALSE; + + if (ntptime) + *ntptime = curr->ntptime; + if (rtptime) + *rtptime = curr->rtptime; + if (packet_count) + *packet_count = curr->packet_count; + if (octet_count) + *octet_count = curr->octet_count; + if (time) + *time = curr->time; + + return TRUE; +} + +/** + * rtp_source_get_last_rb: + * @src: an #RTPSource + * @fractionlost: fraction lost since last SR/RR + * @packetslost: the cumululative number of packets lost + * @exthighestseq: the extended last sequence number received + * @jitter: the interarrival jitter + * @lsr: the last SR packet from this source + * @dlsr: the delay since last SR packet + * + * Get the values of the last RB report set with rtp_source_process_rb(). + * + * Returns: %TRUE if there was a valid SB report. + */ +gboolean +rtp_source_get_last_rb (RTPSource * src, guint8 * fractionlost, + gint32 * packetslost, guint32 * exthighestseq, guint32 * jitter, + guint32 * lsr, guint32 * dlsr) +{ + RTPReceiverReport *curr; + + g_return_val_if_fail (RTP_IS_SOURCE (src), FALSE); + + curr = &src->stats.rr[src->stats.curr_rr]; + if (!curr->is_valid) + return FALSE; + + if (fractionlost) + *fractionlost = curr->fractionlost; + if (packetslost) + *packetslost = curr->packetslost; + if (exthighestseq) + *exthighestseq = curr->exthighestseq; + if (jitter) + *jitter = curr->jitter; + if (lsr) + *lsr = curr->lsr; + if (dlsr) + *dlsr = curr->dlsr; + + return TRUE; +} diff --git a/gst/rtpmanager/rtpsource.h b/gst/rtpmanager/rtpsource.h index 2f997fb5e9..f5ca2a1ced 100644 --- a/gst/rtpmanager/rtpsource.h +++ b/gst/rtpmanager/rtpsource.h @@ -167,9 +167,15 @@ GstFlowReturn rtp_source_send_rtp (RTPSource *src, GstBuffer *buffer); /* RTCP messages */ void rtp_source_process_bye (RTPSource *src, const gchar *reason); void rtp_source_process_sr (RTPSource *src, guint64 ntptime, guint32 rtptime, - guint32 packet_count, guint32 octet_count); + guint32 packet_count, guint32 octet_count, GstClockTime time); void rtp_source_process_rb (RTPSource *src, guint8 fractionlost, gint32 packetslost, guint32 exthighestseq, guint32 jitter, guint32 lsr, guint32 dlsr); +gboolean rtp_source_get_last_sr (RTPSource *src, guint64 *ntptime, guint32 *rtptime, + guint32 *packet_count, guint32 *octet_count, GstClockTime *time); +gboolean rtp_source_get_last_rb (RTPSource *src, guint8 *fractionlost, gint32 *packetslost, + guint32 *exthighestseq, guint32 *jitter, + guint32 *lsr, guint32 *dlsr); + #endif /* __RTP_SOURCE_H__ */ diff --git a/gst/rtpmanager/rtpstats.h b/gst/rtpmanager/rtpstats.h index 6432142782..e8ea981631 100644 --- a/gst/rtpmanager/rtpstats.h +++ b/gst/rtpmanager/rtpstats.h @@ -34,6 +34,7 @@ typedef struct { guint32 rtptime; guint32 packet_count; guint32 octet_count; + GstClockTime time; } RTPSenderReport; /** @@ -100,7 +101,7 @@ typedef struct { guint32 prev_received; guint16 max_seq; - guint32 cycles; + guint64 cycles; guint32 base_seq; guint32 bad_seq; guint32 transit;