rtpsession: determine if the session is doing point-to-point
authorJulien Isorce <julien.isorce@collabora.co.uk>
Mon, 4 Nov 2013 11:48:21 +0000 (11:48 +0000)
committerWim Taymans <wtaymans@redhat.com>
Tue, 10 Dec 2013 15:57:56 +0000 (16:57 +0100)
In this case T_dither_max is set to 0 according to RFC 4585

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

index 27e3d93..ca89cdb 100644 (file)
@@ -532,6 +532,8 @@ rtp_session_init (RTPSession * sess)
       DEFAULT_RTCP_IMMEDIATE_FEEDBACK_THRESHOLD;
 
   sess->last_keyframe_request = GST_CLOCK_TIME_NONE;
+
+  sess->is_doing_ptp = TRUE;
 }
 
 static void
@@ -1308,11 +1310,88 @@ check_collision (RTPSession * sess, RTPSource * source,
   return TRUE;
 }
 
-static RTPSource *
-find_source (RTPSession * sess, guint32 ssrc)
+typedef struct
 {
-  return g_hash_table_lookup (sess->ssrcs[sess->mask_idx],
-      GINT_TO_POINTER (ssrc));
+  gboolean is_doing_ptp;
+  GSocketAddress *new_addr;
+} CompareAddrData;
+
+/* check if the two given ip addr are the same (do not care about the port) */
+static gboolean
+ip_addr_equal (GSocketAddress * a, GSocketAddress * b)
+{
+  return
+      g_inet_address_equal (g_inet_socket_address_get_address
+      (G_INET_SOCKET_ADDRESS (a)),
+      g_inet_socket_address_get_address (G_INET_SOCKET_ADDRESS (b)));
+}
+
+static void
+compare_rtp_source_addr (const gchar * key, RTPSource * source,
+    CompareAddrData * data)
+{
+  /* only compare ip addr of remote sources which are also not closing */
+  if (!source->internal && !source->closing && source->rtp_from) {
+    /* look for the first rtp source */
+    if (!data->new_addr)
+      data->new_addr = source->rtp_from;
+    /* compare current ip addr with the first one */
+    else
+      data->is_doing_ptp &= ip_addr_equal (data->new_addr, source->rtp_from);
+  }
+}
+
+static void
+compare_rtcp_source_addr (const gchar * key, RTPSource * source,
+    CompareAddrData * data)
+{
+  /* only compare ip addr of remote sources which are also not closing */
+  if (!source->internal && !source->closing && source->rtcp_from) {
+    /* look for the first rtcp source */
+    if (!data->new_addr)
+      data->new_addr = source->rtcp_from;
+    else
+      /* compare current ip addr with the first one */
+      data->is_doing_ptp &= ip_addr_equal (data->new_addr, source->rtcp_from);
+  }
+}
+
+/* loop over our non-internal source to know if the session
+ * is doing point-to-point */
+static void
+session_update_ptp (RTPSession * sess)
+{
+  /* to know if the session is doing point to point, the ip addr
+   * of each non-internal (=remotes) source have to be compared
+   * to each other.
+   */
+  gboolean is_doing_rtp_ptp = FALSE;
+  gboolean is_doing_rtcp_ptp = FALSE;
+  CompareAddrData data;
+
+  /* compare the first remote source's ip addr that receive rtp packets
+   * with other remote rtp source.
+   * it's enough because the session just needs to know if they are all
+   * equals or not
+   */
+  data.is_doing_ptp = TRUE;
+  data.new_addr = NULL;
+  g_hash_table_foreach (sess->ssrcs[sess->mask_idx],
+      (GHFunc) compare_rtp_source_addr, (gpointer) & data);
+  is_doing_rtp_ptp = data.is_doing_ptp;
+
+  /* same but about rtcp */
+  data.is_doing_ptp = TRUE;
+  data.new_addr = NULL;
+  g_hash_table_foreach (sess->ssrcs[sess->mask_idx],
+      (GHFunc) compare_rtcp_source_addr, (gpointer) & data);
+  is_doing_rtcp_ptp = data.is_doing_ptp;
+
+  /* the session is doing point-to-point if all rtp remote have the same
+   * ip addr and if all rtcp remote sources have the same ip addr */
+  sess->is_doing_ptp = is_doing_rtp_ptp && is_doing_rtcp_ptp;
+
+  GST_DEBUG ("doing point-to-point: %d", sess->is_doing_ptp);
 }
 
 static void
@@ -1331,6 +1410,17 @@ add_source (RTPSession * sess, RTPSource * src)
     if (sess->suggested_ssrc != src->ssrc)
       sess->suggested_ssrc = src->ssrc;
   }
+
+  /* update point-to-point status */
+  if (!src->internal)
+    session_update_ptp (sess);
+}
+
+static RTPSource *
+find_source (RTPSession * sess, guint32 ssrc)
+{
+  return g_hash_table_lookup (sess->ssrcs[sess->mask_idx],
+      GINT_TO_POINTER (ssrc));
 }
 
 /* must be called with the session lock, the returned source needs to be
@@ -3489,6 +3579,9 @@ rtp_session_on_timeout (RTPSession * sess, GstClockTime current_time,
   g_hash_table_foreach_remove (sess->ssrcs[sess->mask_idx],
       (GHRFunc) remove_closing_sources, &data);
 
+  /* update point-to-point status */
+  session_update_ptp (sess);
+
   /* see if we need to generate SR or RR packets */
   if (!is_rtcp_time (sess, current_time, &data))
     goto done;
@@ -3586,7 +3679,10 @@ rtp_session_request_early_rtcp (RTPSession * sess, GstClockTime current_time,
 
   /*  RFC 4585 section 3.5.2 step 2b */
   /* If the total sources is <=2, then there is only us and one peer */
-  if (sess->total_sources <= 2) {
+  /* When there is one auxiliary stream the session can still do point
+   * to point.
+   */
+  if (sess->is_doing_ptp) {
     T_dither_max = 0;
   } else {
     /* Divide by 2 because l = 0.5 */
index 3ca6c16..d756bdc 100644 (file)
@@ -252,6 +252,8 @@ struct _RTPSession {
 
   GstClockTime last_keyframe_request;
   gboolean     last_keyframe_all_headers;
+
+  gboolean      is_doing_ptp;
 };
 
 /**