From 85e26f65468b6407ef753220c70695ef87700045 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 5 Sep 2008 13:52:34 +0000 Subject: gst/rtpmanager/gstrtpbin.*: Add signal to notify listeners when a sender becomes a receiver. Original commit message from CVS: * gst/rtpmanager/gstrtpbin.c: (on_sender_timeout), (create_session), (gst_rtp_bin_associate), (gst_rtp_bin_sync_chain), (gst_rtp_bin_class_init), (gst_rtp_bin_request_new_pad): * gst/rtpmanager/gstrtpbin.h: Add signal to notify listeners when a sender becomes a receiver. Tweak lip-sync code, don't store our own copy of the ts-offset of the jitterbuffer, don't adjust sync if the change is less than 4msec. Get the RTP timestamp <-> GStreamer timestamp relation directly from the jitterbuffer instead of our inaccurate version from the source. * gst/rtpmanager/gstrtpjitterbuffer.c: (gst_rtp_jitter_buffer_chain), (gst_rtp_jitter_buffer_loop), (gst_rtp_jitter_buffer_get_sync): * gst/rtpmanager/gstrtpjitterbuffer.h: Add G_LIKELY macros, use global defines for max packet reorder and dropouts. Reset the jitterbuffer clock skew detection when packets seqnums are changed unexpectedly. * gst/rtpmanager/gstrtpsession.c: (on_sender_timeout), (gst_rtp_session_class_init), (gst_rtp_session_init): * gst/rtpmanager/gstrtpsession.h: Add sender timeout signal. * gst/rtpmanager/rtpjitterbuffer.c: (rtp_jitter_buffer_reset_skew), (calculate_skew), (rtp_jitter_buffer_insert), (rtp_jitter_buffer_get_sync): * gst/rtpmanager/rtpjitterbuffer.h: Add some G_LIKELY macros. Keep track of the extended RTP timestamp so that we can report the RTP timestamp <-> GStreamer timestamp relation for lip-sync. Remove server timestamp gap detection code, the server can sometimes make a huge gap in timestamps (talk spurts,...) see #549774. Detect timetamp weirdness instead by observing the sender/receiver timestamp relation and resync if it changes more than 1 second. Add method to report about the current rtp <-> gst timestamp relation which is needed for lip-sync. * gst/rtpmanager/rtpsession.c: (rtp_session_class_init), (on_sender_timeout), (check_collision), (rtp_session_process_sr), (session_cleanup): * gst/rtpmanager/rtpsession.h: Add sender timeout signal. Remove inaccurate rtp <-> gst timestamp relation code, the jitterbuffer can now do an accurate reporting about this. * gst/rtpmanager/rtpsource.c: (rtp_source_init), (rtp_source_update_caps), (calculate_jitter), (rtp_source_process_rtp): * gst/rtpmanager/rtpsource.h: Remove inaccurate rtp <-> gst timestamp relation code. * gst/rtpmanager/rtpstats.h: Define global max-reorder and max-dropout constants for use in various subsystems. --- gst/rtpmanager/gstrtpbin.c | 60 +++++++++++++++++++++++++++++++++------------- 1 file changed, 44 insertions(+), 16 deletions(-) (limited to 'gst/rtpmanager/gstrtpbin.c') diff --git a/gst/rtpmanager/gstrtpbin.c b/gst/rtpmanager/gstrtpbin.c index 46ef4bb9..7f402c36 100644 --- a/gst/rtpmanager/gstrtpbin.c +++ b/gst/rtpmanager/gstrtpbin.c @@ -120,6 +120,7 @@ #include "gstrtpbin-marshal.h" #include "gstrtpbin.h" #include "gstrtpsession.h" +#include "gstrtpjitterbuffer.h" GST_DEBUG_CATEGORY_STATIC (gst_rtp_bin_debug); #define GST_CAT_DEFAULT gst_rtp_bin_debug @@ -236,6 +237,7 @@ enum SIGNAL_ON_BYE_SSRC, SIGNAL_ON_BYE_TIMEOUT, SIGNAL_ON_TIMEOUT, + SIGNAL_ON_SENDER_TIMEOUT, LAST_SIGNAL }; @@ -323,7 +325,6 @@ struct _GstRtpBinStream guint64 clock_base_time; gint clock_rate; gint64 ts_offset; - gint64 prev_ts_offset; gint last_pt; }; @@ -455,6 +456,13 @@ on_timeout (GstElement * session, guint32 ssrc, GstRtpBinSession * sess) sess->id, ssrc); } +static void +on_sender_timeout (GstElement * session, guint32 ssrc, GstRtpBinSession * sess) +{ + g_signal_emit (sess->bin, gst_rtp_bin_signals[SIGNAL_ON_SENDER_TIMEOUT], 0, + sess->id, ssrc); +} + /* create a session with the given id. Must be called with RTP_BIN_LOCK */ static GstRtpBinSession * create_session (GstRtpBin * rtpbin, gint id) @@ -507,6 +515,8 @@ create_session (GstRtpBin * rtpbin, gint id) g_signal_connect (sess->session, "on-bye-timeout", (GCallback) on_bye_timeout, sess); g_signal_connect (sess->session, "on-timeout", (GCallback) on_timeout, sess); + g_signal_connect (sess->session, "on-sender-timeout", + (GCallback) on_sender_timeout, sess); /* FIXME, change state only to what's needed */ gst_bin_add (GST_BIN_CAST (rtpbin), session); @@ -863,32 +873,31 @@ gst_rtp_bin_associate (GstRtpBin * bin, GstRtpBinStream * stream, guint8 len, /* calculate offsets for each stream */ for (walk = client->streams; walk; walk = g_slist_next (walk)) { GstRtpBinStream *ostream = (GstRtpBinStream *) walk->data; - - if (ostream->unix_delta == 0) - continue; + gint64 prev_ts_offset; ostream->ts_offset = ostream->unix_delta - min; + g_object_get (ostream->buffer, "ts-offset", &prev_ts_offset, NULL); + /* delta changed, see how much */ - if (ostream->prev_ts_offset != ostream->ts_offset) { + if (prev_ts_offset != ostream->ts_offset) { gint64 diff; - if (ostream->prev_ts_offset > ostream->ts_offset) - diff = ostream->prev_ts_offset - ostream->ts_offset; + if (prev_ts_offset > ostream->ts_offset) + diff = prev_ts_offset - ostream->ts_offset; else - diff = ostream->ts_offset - ostream->prev_ts_offset; + diff = ostream->ts_offset - prev_ts_offset; GST_DEBUG_OBJECT (bin, "ts-offset %" G_GUINT64_FORMAT ", prev %" G_GUINT64_FORMAT - ", diff: %" G_GINT64_FORMAT, ostream->ts_offset, - ostream->prev_ts_offset, diff); + ", diff: %" G_GINT64_FORMAT, ostream->ts_offset, prev_ts_offset, + diff); - /* only change diff when it changed more than 1 millisecond. This + /* only change diff when it changed more than 4 milliseconds. This * compensates for rounding errors in NTP to RTP timestamp * conversions */ - if (diff > GST_MSECOND && diff < (3 * GST_SECOND)) { + if (diff > 4 * GST_MSECOND && diff < (3 * GST_SECOND)) { g_object_set (ostream->buffer, "ts-offset", ostream->ts_offset, NULL); - ostream->prev_ts_offset = ostream->ts_offset; } } GST_DEBUG_OBJECT (bin, "stream SSRC %08x, delta %" G_GINT64_FORMAT, @@ -937,8 +946,7 @@ gst_rtp_bin_sync_chain (GstPad * pad, GstBuffer * buffer) gboolean have_sr, have_sdes; gboolean more; guint64 clock_base; - - clock_base = GST_BUFFER_OFFSET (buffer); + guint64 clock_base_time; stream = gst_pad_get_element_private (pad); bin = stream->bin; @@ -948,6 +956,12 @@ gst_rtp_bin_sync_chain (GstPad * pad, GstBuffer * buffer) if (!gst_rtcp_buffer_validate (buffer)) goto invalid_rtcp; + /* get the last relation between the rtp timestamps and the gstreamer + * timestamps. We get this info directly from the jitterbuffer which + * constructs gstreamer timestamps from rtp timestamps */ + gst_rtp_jitter_buffer_get_sync (GST_RTP_JITTER_BUFFER (stream->buffer), + &clock_base, &clock_base_time); + /* clock base changes when there is a huge gap in the timestamps or seqnum. * When this happens we don't want to calculate the extended timestamp based * on the previous one but reset the calculation. */ @@ -1008,7 +1022,7 @@ gst_rtp_bin_sync_chain (GstPad * pad, GstBuffer * buffer) if (type == GST_RTCP_SDES_CNAME) { stream->clock_base = clock_base; - stream->clock_base_time = GST_BUFFER_OFFSET_END (buffer); + stream->clock_base_time = clock_base_time; /* associate the stream to CNAME */ gst_rtp_bin_associate (bin, stream, len, data); } @@ -1328,6 +1342,19 @@ gst_rtp_bin_class_init (GstRtpBinClass * klass) G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpBinClass, on_timeout), NULL, NULL, gst_rtp_bin_marshal_VOID__UINT_UINT, G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_UINT); + /** + * GstRtpBin::on-sender-timeout: + * @rtpbin: the object which received the signal + * @session: the session + * @ssrc: the SSRC + * + * Notify of a sender SSRC that has timed out and became a receiver + */ + gst_rtp_bin_signals[SIGNAL_ON_SENDER_TIMEOUT] = + g_signal_new ("on-sender-timeout", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpBinClass, on_sender_timeout), + NULL, NULL, gst_rtp_bin_marshal_VOID__UINT_UINT, G_TYPE_NONE, 2, + G_TYPE_UINT, G_TYPE_UINT); g_object_class_install_property (gobject_class, PROP_SDES_CNAME, g_param_spec_string ("sdes-cname", "SDES CNAME", @@ -2332,6 +2359,7 @@ gst_rtp_bin_request_new_pad (GstElement * element, GstRtpBin *rtpbin; GstElementClass *klass; GstPad *result; + gchar *pad_name = NULL; g_return_val_if_fail (templ != NULL, NULL); -- cgit