From 3122ef4ae3844f7a1e95e8bba811cba27568cb0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Mon, 4 May 2015 11:42:08 +0200 Subject: [PATCH] rtpsession: Add property for selecting RTP profile (AVP/AVPF/etc) And modify our RTCP scheduling algorithm accordingly. We now can send more RTCP packets if needed for feedback, but will throttle full RTCP packets by rtcp-min-interval (t-rr-int from RFC4585). In non-feedback mode, rtcp-min-interval is Tmin from RFC3550, which is statically set to 1s or 0s by RFC4585. Tmin defines how often we should send RTCP packets at most. https://bugzilla.gnome.org/show_bug.cgi?id=746543 --- gst/rtpmanager/gstrtpsession.c | 15 +++++++++++- gst/rtpmanager/rtpsession.c | 43 ++++++++++++++++++++++++++++++---- gst/rtpmanager/rtpsession.h | 2 ++ gst/rtpmanager/rtpsource.h | 2 +- gst/rtpmanager/rtpstats.c | 31 ++++++++++++++++-------- gst/rtpmanager/rtpstats.h | 3 ++- 6 files changed, 78 insertions(+), 18 deletions(-) diff --git a/gst/rtpmanager/gstrtpsession.c b/gst/rtpmanager/gstrtpsession.c index 8838aafaef..1e623cca4a 100644 --- a/gst/rtpmanager/gstrtpsession.c +++ b/gst/rtpmanager/gstrtpsession.c @@ -201,6 +201,7 @@ enum #define DEFAULT_USE_PIPELINE_CLOCK FALSE #define DEFAULT_RTCP_MIN_INTERVAL (RTP_STATS_MIN_INTERVAL * GST_SECOND) #define DEFAULT_PROBATION RTP_DEFAULT_PROBATION +#define DEFAULT_RTP_PROFILE GST_RTP_PROFILE_AVP enum { @@ -216,7 +217,8 @@ enum PROP_USE_PIPELINE_CLOCK, PROP_RTCP_MIN_INTERVAL, PROP_PROBATION, - PROP_STATS + PROP_STATS, + PROP_RTP_PROFILE }; #define GST_RTP_SESSION_GET_PRIVATE(obj) \ @@ -645,6 +647,11 @@ gst_rtp_session_class_init (GstRtpSessionClass * klass) "Various statistics", GST_TYPE_STRUCTURE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_RTP_PROFILE, + g_param_spec_enum ("rtp-profile", "RTP Profile", + "RTP profile to use", GST_TYPE_RTP_PROFILE, DEFAULT_RTP_PROFILE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_rtp_session_change_state); gstelement_class->request_new_pad = @@ -776,6 +783,9 @@ gst_rtp_session_set_property (GObject * object, guint prop_id, case PROP_PROBATION: g_object_set_property (G_OBJECT (priv->session), "probation", value); break; + case PROP_RTP_PROFILE: + g_object_set_property (G_OBJECT (priv->session), "rtp-profile", value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -833,6 +843,9 @@ gst_rtp_session_get_property (GObject * object, guint prop_id, case PROP_STATS: g_value_take_boxed (value, gst_rtp_session_create_stats (rtpsession)); break; + case PROP_RTP_PROFILE: + g_object_get_property (G_OBJECT (priv->session), "rtp-profile", value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; diff --git a/gst/rtpmanager/rtpsession.c b/gst/rtpmanager/rtpsession.c index dafe154939..b405699754 100644 --- a/gst/rtpmanager/rtpsession.c +++ b/gst/rtpmanager/rtpsession.c @@ -68,6 +68,7 @@ enum #define DEFAULT_RTCP_FEEDBACK_RETENTION_WINDOW (2 * GST_SECOND) #define DEFAULT_RTCP_IMMEDIATE_FEEDBACK_THRESHOLD (3) #define DEFAULT_PROBATION RTP_DEFAULT_PROBATION +#define DEFAULT_RTP_PROFILE GST_RTP_PROFILE_AVP enum { @@ -88,7 +89,8 @@ enum PROP_RTCP_FEEDBACK_RETENTION_WINDOW, PROP_RTCP_IMMEDIATE_FEEDBACK_THRESHOLD, PROP_PROBATION, - PROP_STATS + PROP_STATS, + PROP_RTP_PROFILE }; /* update average packet size */ @@ -313,6 +315,8 @@ rtp_session_class_init (RTPSessionClass * klass) * * Requests that the #RTPSession initiate a new RTCP packet as soon as * possible within the requested delay. + * + * This sets feedback to %TRUE if not already done before. */ rtp_session_signals[SIGNAL_SEND_RTCP] = g_signal_new ("send-rtcp", G_TYPE_FROM_CLASS (klass), @@ -329,6 +333,8 @@ rtp_session_class_init (RTPSessionClass * klass) * Requests that the #RTPSession initiate a new RTCP packet as soon as * possible within the requested delay. * + * This sets feedback to %TRUE if not already done before. + * * Returns: TRUE if the new RTCP packet could be scheduled within the * requested delay, FALSE otherwise. * @@ -494,6 +500,11 @@ rtp_session_class_init (RTPSessionClass * klass) "Various statistics", GST_TYPE_STRUCTURE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_RTP_PROFILE, + g_param_spec_enum ("rtp-profile", "RTP Profile", + "RTP profile to use for this session", GST_TYPE_RTP_PROFILE, + DEFAULT_RTP_PROFILE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + klass->get_source_by_ssrc = GST_DEBUG_FUNCPTR (rtp_session_get_source_by_ssrc); klass->send_rtcp = GST_DEBUG_FUNCPTR (rtp_session_send_rtcp); @@ -568,6 +579,7 @@ rtp_session_init (RTPSession * sess) sess->rtcp_feedback_retention_window = DEFAULT_RTCP_FEEDBACK_RETENTION_WINDOW; sess->rtcp_immediate_feedback_threshold = DEFAULT_RTCP_IMMEDIATE_FEEDBACK_THRESHOLD; + sess->rtp_profile = DEFAULT_RTP_PROFILE; sess->last_keyframe_request = GST_CLOCK_TIME_NONE; @@ -706,6 +718,15 @@ rtp_session_set_property (GObject * object, guint prop_id, case PROP_PROBATION: sess->probation = g_value_get_uint (value); break; + case PROP_RTP_PROFILE: + sess->rtp_profile = g_value_get_enum (value); + /* trigger reconsideration */ + RTP_SESSION_LOCK (sess); + sess->next_rtcp_check_time = 0; + RTP_SESSION_UNLOCK (sess); + if (sess->callbacks.reconsider) + sess->callbacks.reconsider (sess, sess->reconsider_user_data); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -770,6 +791,9 @@ rtp_session_get_property (GObject * object, guint prop_id, case PROP_STATS: g_value_take_boxed (value, rtp_session_create_stats (sess)); break; + case PROP_RTP_PROFILE: + g_value_set_enum (value, sess->rtp_profile); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -2816,9 +2840,12 @@ calculate_rtcp_interval (RTPSession * sess, gboolean deterministic, stats = &sess->bye_stats; result = rtp_stats_calculate_bye_interval (stats); } else { + session_update_ptp (sess); + stats = &sess->stats; result = rtp_stats_calculate_rtcp_interval (stats, - stats->internal_sender_sources > 0, first); + stats->internal_sender_sources > 0, sess->rtp_profile, + sess->is_doing_ptp, first); } GST_DEBUG ("next deterministic interval: %" GST_TIME_FORMAT ", first %d", @@ -3561,7 +3588,9 @@ early: sess->next_rtcp_check_time = current_time + interval; } else if (interval != GST_CLOCK_TIME_NONE) { /* Apply the rules from RFC 4585 section 3.5.3 */ - if (stats->min_interval != 0 && !sess->first_rtcp) { + if ((sess->rtp_profile == GST_RTP_PROFILE_AVPF + || sess->rtp_profile == GST_RTP_PROFILE_SAVPF) + && stats->min_interval != 0 && !sess->first_rtcp) { GstClockTime T_rr_current_interval = g_random_double_range (0.5, 1.5) * stats->min_interval * GST_SECOND; @@ -3852,6 +3881,10 @@ rtp_session_request_early_rtcp (RTPSession * sess, GstClockTime current_time, RTP_SESSION_LOCK (sess); + /* We assume a feedback profile if something is requesting RTCP + * to be sent */ + sess->rtp_profile = GST_RTP_PROFILE_AVPF; + /* Check if already requested */ /* RFC 4585 section 3.5.2 step 2 */ if (GST_CLOCK_TIME_IS_VALID (sess->next_early_rtcp_time)) { @@ -3919,7 +3952,7 @@ rtp_session_request_early_rtcp (RTPSession * sess, GstClockTime current_time, } /* RFC 4585 section 3.5.2 step 4a */ - if (sess->allow_early == FALSE) { + if (!sess->allow_early) { /* Ignore the request a scheduled packet will be in time anyway */ if (current_time + max_delay > sess->next_rtcp_check_time) { GST_LOG_OBJECT (sess, @@ -3930,7 +3963,7 @@ rtp_session_request_early_rtcp (RTPSession * sess, GstClockTime current_time, ret = TRUE; } else { GST_LOG_OBJECT (sess, - "can't allow early feedback, next scheduled time is too late %" + "can't allow early feedback and next scheduled time is too late %" GST_TIME_FORMAT " + %" GST_TIME_FORMAT " < %" GST_TIME_FORMAT, GST_TIME_ARGS (current_time), GST_TIME_ARGS (max_delay), GST_TIME_ARGS (sess->next_rtcp_check_time)); diff --git a/gst/rtpmanager/rtpsession.h b/gst/rtpmanager/rtpsession.h index 3f565a601f..b8ea5323b4 100644 --- a/gst/rtpmanager/rtpsession.h +++ b/gst/rtpmanager/rtpsession.h @@ -220,6 +220,8 @@ struct _RTPSession { guint probation; + GstRTPProfile rtp_profile; + /* bandwidths */ gboolean recalc_bandwidth; guint bandwidth; diff --git a/gst/rtpmanager/rtpsource.h b/gst/rtpmanager/rtpsource.h index a2e1f27374..0f47faea02 100644 --- a/gst/rtpmanager/rtpsource.h +++ b/gst/rtpmanager/rtpsource.h @@ -21,7 +21,7 @@ #define __RTP_SOURCE_H__ #include -#include +#include #include #include diff --git a/gst/rtpmanager/rtpstats.c b/gst/rtpmanager/rtpstats.c index 56e58b71db..f9f7c2c79d 100644 --- a/gst/rtpmanager/rtpstats.c +++ b/gst/rtpmanager/rtpstats.c @@ -120,6 +120,8 @@ rtp_stats_set_bandwidths (RTPSessionStats * stats, guint rtp_bw, * rtp_stats_calculate_rtcp_interval: * @stats: an #RTPSessionStats struct * @sender: if we are a sender + * @profile: RTP profile of this session + * @ptp: if this session is a point-to-point session * @first: if this is the first time * * Calculate the RTCP interval. The result of this function is the amount of @@ -129,22 +131,31 @@ rtp_stats_set_bandwidths (RTPSessionStats * stats, guint rtp_bw, */ GstClockTime rtp_stats_calculate_rtcp_interval (RTPSessionStats * stats, gboolean we_send, - gboolean first) + GstRTPProfile profile, gboolean ptp, gboolean first) { gdouble members, senders, n; gdouble avg_rtcp_size, rtcp_bw; gdouble interval; gdouble rtcp_min_time; - /* Very first call at application start-up uses half the min - * delay for quicker notification while still allowing some time - * before reporting for randomization and to learn about other - * sources so the report interval will converge to the correct - * interval more quickly. - */ - rtcp_min_time = stats->min_interval; - if (first) - rtcp_min_time /= 2.0; + if (profile == GST_RTP_PROFILE_AVPF || profile == GST_RTP_PROFILE_SAVPF) { + /* RFC 4585 3.4d), 3.5.1 */ + + if (first && !ptp) + rtcp_min_time = 1.0; + else + rtcp_min_time = 0.0; + } else { + /* Very first call at application start-up uses half the min + * delay for quicker notification while still allowing some time + * before reporting for randomization and to learn about other + * sources so the report interval will converge to the correct + * interval more quickly. + */ + rtcp_min_time = stats->min_interval; + if (first) + rtcp_min_time /= 2.0; + } /* Dedicate a fraction of the RTCP bandwidth to senders unless * the number of senders is large enough that their share is diff --git a/gst/rtpmanager/rtpstats.h b/gst/rtpmanager/rtpstats.h index c54ea0b73a..47c4b823fa 100644 --- a/gst/rtpmanager/rtpstats.h +++ b/gst/rtpmanager/rtpstats.h @@ -22,6 +22,7 @@ #include #include +#include #include /** @@ -222,7 +223,7 @@ void rtp_stats_set_bandwidths (RTPSessionStats *stats, gdouble rtcp_bw, guint rs, guint rr); -GstClockTime rtp_stats_calculate_rtcp_interval (RTPSessionStats *stats, gboolean sender, gboolean first); +GstClockTime rtp_stats_calculate_rtcp_interval (RTPSessionStats *stats, gboolean sender, GstRTPProfile profile, gboolean ptp, gboolean first); GstClockTime rtp_stats_add_rtcp_jitter (RTPSessionStats *stats, GstClockTime interval); GstClockTime rtp_stats_calculate_bye_interval (RTPSessionStats *stats); gint64 rtp_stats_get_packets_lost (const RTPSourceStats *stats);