rtpsession: Add property for selecting RTP profile (AVP/AVPF/etc)
authorSebastian Dröge <sebastian@centricular.com>
Mon, 4 May 2015 09:42:08 +0000 (11:42 +0200)
committerSebastian Dröge <sebastian@centricular.com>
Tue, 2 Jun 2015 09:38:15 +0000 (11:38 +0200)
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
gst/rtpmanager/rtpsession.c
gst/rtpmanager/rtpsession.h
gst/rtpmanager/rtpsource.h
gst/rtpmanager/rtpstats.c
gst/rtpmanager/rtpstats.h

index 8838aaf..1e623cc 100644 (file)
@@ -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;
index dafe154..b405699 100644 (file)
@@ -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));
index 3f565a6..b8ea532 100644 (file)
@@ -220,6 +220,8 @@ struct _RTPSession {
 
   guint         probation;
 
+  GstRTPProfile rtp_profile;
+
   /* bandwidths */
   gboolean     recalc_bandwidth;
   guint        bandwidth;
index a2e1f27..0f47fae 100644 (file)
@@ -21,7 +21,7 @@
 #define __RTP_SOURCE_H__
 
 #include <gst/gst.h>
-#include <gst/rtp/gstrtcpbuffer.h>
+#include <gst/rtp/rtp.h>
 #include <gst/net/gstnetaddressmeta.h>
 #include <gio/gio.h>
 
index 56e58b7..f9f7c2c 100644 (file)
@@ -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
index c54ea0b..47c4b82 100644 (file)
@@ -22,6 +22,7 @@
 
 #include <gst/gst.h>
 #include <gst/net/gstnetaddressmeta.h>
+#include <gst/rtp/rtp.h>
 #include <gio/gio.h>
 
 /**
@@ -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);