gst/rtpmanager/gstrtpsession.c: Implement forward and reverse reconsideration.
authorWim Taymans <wim.taymans@gmail.com>
Wed, 25 Apr 2007 16:38:03 +0000 (16:38 +0000)
committerTim-Philipp Müller <tim.muller@collabora.co.uk>
Tue, 11 Aug 2009 01:30:26 +0000 (02:30 +0100)
Original commit message from CVS:
* gst/rtpmanager/gstrtpsession.c: (rtcp_thread):
Implement forward and reverse reconsideration.
* gst/rtpmanager/rtpsession.c: (rtp_session_get_num_sources),
(rtp_session_get_num_active_sources), (rtp_session_process_sr),
(session_report_blocks):
* gst/rtpmanager/rtpsession.h:
Small cleanups.

gst/rtpmanager/gstrtpsession.c
gst/rtpmanager/rtpsession.c
gst/rtpmanager/rtpsession.h

index 39c63e3..bc29723 100644 (file)
@@ -293,6 +293,13 @@ rtcp_thread (GstRTPSession * rtpsession)
 {
   GstClock *clock;
   GstClockID id;
+  gdouble interval;
+  GstClockTime current_time;
+  GstClockTime next_rtcp_check_time;
+  GstClockTime new_rtcp_send_time;
+  GstClockTime last_rtcp_send_time;
+  GstClockTimeDiff jitter;
+  guint members, prev_members;
 
   clock = gst_element_get_clock (GST_ELEMENT_CAST (rtpsession));
   if (clock == NULL)
@@ -301,34 +308,83 @@ rtcp_thread (GstRTPSession * rtpsession)
   GST_DEBUG_OBJECT (rtpsession, "entering RTCP thread");
 
   GST_RTP_SESSION_LOCK (rtpsession);
+
+  /* get initial estimate */
+  interval = rtp_session_get_reporting_interval (rtpsession->priv->session);
+  current_time = gst_clock_get_time (clock);
+  last_rtcp_send_time = current_time;
+  next_rtcp_check_time = current_time + (GST_SECOND * interval);
+  /* we keep track of members before and after the timeout to do reverse
+   * reconsideration. */
+  prev_members = rtp_session_get_num_active_sources (rtpsession->priv->session);
+
+  GST_DEBUG_OBJECT (rtpsession, "first RTCP interval: %lf seconds", interval);
+
   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);
+    GST_DEBUG_OBJECT (rtpsession, "next check time %" GST_TIME_FORMAT,
+        GST_TIME_ARGS (next_rtcp_check_time));
 
-    target = gst_clock_get_time (clock);
-    target += GST_SECOND * timeout;
+    id = rtpsession->priv->id =
+        gst_clock_new_single_shot_id (clock, next_rtcp_check_time);
+    GST_RTP_SESSION_UNLOCK (rtpsession);
 
+    res = gst_clock_id_wait (id, &jitter);
 
-    id = rtpsession->priv->id = gst_clock_new_single_shot_id (clock, target);
-    GST_RTP_SESSION_UNLOCK (rtpsession);
+    GST_RTP_SESSION_LOCK (rtpsession);
+    gst_clock_id_unref (id);
+    rtpsession->priv->id = NULL;
+
+    if (rtpsession->priv->stop_thread)
+      break;
+
+    if (res != GST_CLOCK_UNSCHEDULED)
+      if (jitter < 0)
+        current_time = next_rtcp_check_time;
+      else
+        current_time = next_rtcp_check_time - jitter;
+    else
+      current_time = gst_clock_get_time (clock);
+
+    GST_DEBUG_OBJECT (rtpsession, "unlocked %d, jitter %" G_GINT64_FORMAT
+        ", current %" GST_TIME_FORMAT, res, jitter,
+        GST_TIME_ARGS (current_time));
 
-    res = gst_clock_id_wait (id, NULL);
-    if (res != GST_CLOCK_UNSCHEDULED) {
-      GST_DEBUG_OBJECT (rtpsession, "got RTCP timeout");
+    members = rtp_session_get_num_active_sources (rtpsession->priv->session);
+
+    if (members < prev_members) {
+      GstClockTime time_remaining;
+
+      /* some members went away */
+      GST_DEBUG_OBJECT (rtpsession, "reverse reconsideration");
+      time_remaining = next_rtcp_check_time - current_time;
+      new_rtcp_send_time =
+          current_time + (time_remaining * members / prev_members);
+    } else {
+      interval = rtp_session_get_reporting_interval (rtpsession->priv->session);
+      GST_DEBUG_OBJECT (rtpsession, "forward reconsideration: %lf seconds",
+          interval);
+      new_rtcp_send_time = (interval * GST_SECOND) + last_rtcp_send_time;
+    }
+    prev_members = members;
+
+    if (current_time >= new_rtcp_send_time) {
+      GST_DEBUG_OBJECT (rtpsession, "sending RTCP now");
 
       /* make the session manager produce RTCP, we ignore the result. */
       rtp_session_perform_reporting (rtpsession->priv->session);
+
+      interval = rtp_session_get_reporting_interval (rtpsession->priv->session);
+
+      GST_DEBUG_OBJECT (rtpsession, "next RTCP interval: %lf seconds",
+          interval);
+      next_rtcp_check_time = (interval * GST_SECOND) + current_time;
+      last_rtcp_send_time = current_time;
     } else {
-      GST_DEBUG_OBJECT (rtpsession, "got unscheduled");
+      GST_DEBUG_OBJECT (rtpsession, "reconsider RTCP");
+      next_rtcp_check_time = new_rtcp_send_time;
     }
-
-    GST_RTP_SESSION_LOCK (rtpsession);
-    gst_clock_id_unref (id);
-    rtpsession->priv->id = NULL;
   }
   GST_RTP_SESSION_UNLOCK (rtpsession);
 
index 27d6dab..1f6e1eb 100644 (file)
@@ -703,10 +703,10 @@ rtp_session_add_source (RTPSession * sess, RTPSource * src)
  *
  * Returns: The number of sources in @sess.
  */
-gint
+guint
 rtp_session_get_num_sources (RTPSession * sess)
 {
-  gint result;
+  guint result;
 
   g_return_val_if_fail (RTP_IS_SESSION (sess), FALSE);
 
@@ -726,12 +726,12 @@ rtp_session_get_num_sources (RTPSession * sess)
  *
  * Returns: The number of active sources in @sess.
  */
-gint
+guint
 rtp_session_get_num_active_sources (RTPSession * sess)
 {
-  gint result;
+  guint result;
 
-  g_return_val_if_fail (RTP_IS_SESSION (sess), FALSE);
+  g_return_val_if_fail (RTP_IS_SESSION (sess), 0);
 
   RTP_SESSION_LOCK (sess);
   result = sess->stats.active_sources;
index 493387f..3554016 100644 (file)
@@ -216,8 +216,8 @@ gchar*          rtp_session_get_note               (RTPSession *sess);
 
 /* handling sources */
 gboolean        rtp_session_add_source             (RTPSession *sess, RTPSource *src);
-gint            rtp_session_get_num_sources        (RTPSession *sess);
-gint            rtp_session_get_num_active_sources (RTPSession *sess);
+guint           rtp_session_get_num_sources        (RTPSession *sess);
+guint           rtp_session_get_num_active_sources (RTPSession *sess);
 RTPSource*      rtp_session_get_source_by_ssrc     (RTPSession *sess, guint32 ssrc);
 RTPSource*      rtp_session_get_source_by_cname    (RTPSession *sess, const gchar *cname);
 RTPSource*      rtp_session_create_source          (RTPSession *sess);