New property for socket binding to mcast addresses
authorPatricia Muscalu <patricia@axis.com>
Thu, 6 Sep 2018 14:17:33 +0000 (16:17 +0200)
committerSebastian Dröge <sebastian@centricular.com>
Fri, 28 Sep 2018 10:27:48 +0000 (13:27 +0300)
By default the multicast sockets are bound to INADDR_ANY,
as it's not allowed to bind sockets to multicast addresses
in Windows. This default behaviour can be changed by setting
bind-mcast-address property on the media-factory object.

https://bugzilla.gnome.org/show_bug.cgi?id=797059

gst/rtsp-server/rtsp-media-factory.c
gst/rtsp-server/rtsp-media-factory.h
gst/rtsp-server/rtsp-media.c
gst/rtsp-server/rtsp-media.h
gst/rtsp-server/rtsp-stream.c
gst/rtsp-server/rtsp-stream.h
tests/check/gst/client.c
tests/check/gst/mediafactory.c

index 904124d..27825e0 100644 (file)
@@ -63,6 +63,7 @@ struct _GstRTSPMediaFactoryPrivate
   gboolean stop_on_disconnect;
   gchar *multicast_iface;
   guint max_mcast_ttl;
+  gboolean bind_mcast_address;
 
   GstClockTime rtx_time;
   guint latency;
@@ -88,6 +89,7 @@ struct _GstRTSPMediaFactoryPrivate
 #define DEFAULT_BUFFER_SIZE     0x80000
 #define DEFAULT_LATENCY         200
 #define DEFAULT_MAX_MCAST_TTL   255
+#define DEFAULT_BIND_MCAST_ADDRESS FALSE
 #define DEFAULT_TRANSPORT_MODE  GST_RTSP_TRANSPORT_MODE_PLAY
 #define DEFAULT_STOP_ON_DISCONNECT TRUE
 #define DEFAULT_DO_RETRANSMISSION FALSE
@@ -107,6 +109,7 @@ enum
   PROP_STOP_ON_DISCONNECT,
   PROP_CLOCK,
   PROP_MAX_MCAST_TTL,
+  PROP_BIND_MCAST_ADDRESS,
   PROP_LAST
 };
 
@@ -234,6 +237,13 @@ gst_rtsp_media_factory_class_init (GstRTSPMediaFactoryClass * klass)
           255, DEFAULT_MAX_MCAST_TTL,
           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
 
+  g_object_class_install_property (gobject_class, PROP_BIND_MCAST_ADDRESS,
+      g_param_spec_boolean ("bind-mcast-address", "Bind mcast address",
+          "Whether the multicast sockets should be bound to multicast addresses "
+          "or INADDR_ANY",
+          DEFAULT_BIND_MCAST_ADDRESS,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
   gst_rtsp_media_factory_signals[SIGNAL_MEDIA_CONSTRUCTED] =
       g_signal_new ("media-constructed", G_TYPE_FROM_CLASS (klass),
       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPMediaFactoryClass,
@@ -276,6 +286,7 @@ gst_rtsp_media_factory_init (GstRTSPMediaFactory * factory)
   priv->publish_clock_mode = GST_RTSP_PUBLISH_CLOCK_MODE_CLOCK;
   priv->do_retransmission = DEFAULT_DO_RETRANSMISSION;
   priv->max_mcast_ttl = DEFAULT_MAX_MCAST_TTL;
+  priv->bind_mcast_address = DEFAULT_BIND_MCAST_ADDRESS;
 
   g_mutex_init (&priv->lock);
   g_mutex_init (&priv->medias_lock);
@@ -354,6 +365,10 @@ gst_rtsp_media_factory_get_property (GObject * object, guint propid,
       g_value_set_uint (value,
           gst_rtsp_media_factory_get_max_mcast_ttl (factory));
       break;
+    case PROP_BIND_MCAST_ADDRESS:
+      g_value_set_boolean (value,
+          gst_rtsp_media_factory_is_bind_mcast_address (factory));
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
   }
@@ -408,6 +423,10 @@ gst_rtsp_media_factory_set_property (GObject * object, guint propid,
       gst_rtsp_media_factory_set_max_mcast_ttl (factory,
           g_value_get_uint (value));
       break;
+    case PROP_BIND_MCAST_ADDRESS:
+      gst_rtsp_media_factory_set_bind_mcast_address (factory,
+          g_value_get_boolean (value));
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
   }
@@ -1540,6 +1559,54 @@ gst_rtsp_media_factory_get_max_mcast_ttl (GstRTSPMediaFactory * factory)
   return result;
 }
 
+/**
+ * gst_rtsp_media_factory_set_bind_mcast_address:
+ * @factory: a #GstRTSPMediaFactory
+ * @bind_mcast_addr: the new value
+ *
+ * Decide whether the multicast socket should be bound to a multicast address or
+ * INADDR_ANY.
+ */
+void
+gst_rtsp_media_factory_set_bind_mcast_address (GstRTSPMediaFactory * factory,
+    gboolean bind_mcast_addr)
+{
+  GstRTSPMediaFactoryPrivate *priv;
+
+  g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory));
+
+  priv = factory->priv;
+
+  GST_RTSP_MEDIA_FACTORY_LOCK (factory);
+  priv->bind_mcast_address = bind_mcast_addr;
+  GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
+}
+
+/**
+ * gst_rtsp_media_factory_is_bind_mcast_address:
+ * @factory: a #GstRTSPMediaFactory
+ *
+ * Check if multicast sockets are configured to be bound to multicast addresses.
+ *
+ * Returns: %TRUE if multicast sockets are configured to be bound to multicast addresses.
+ */
+gboolean
+gst_rtsp_media_factory_is_bind_mcast_address (GstRTSPMediaFactory * factory)
+{
+  GstRTSPMediaFactoryPrivate *priv;
+  gboolean result;
+
+  g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), FALSE);
+
+  priv = factory->priv;
+
+  GST_RTSP_MEDIA_FACTORY_LOCK (factory);
+  result = priv->bind_mcast_address;
+  GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
+
+  return result;
+}
+
 static gchar *
 default_gen_key (GstRTSPMediaFactory * factory, const GstRTSPUrl * url)
 {
@@ -1691,6 +1758,7 @@ default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media)
   gchar *multicast_iface;
   GstRTSPPublishClockMode publish_clock_mode;
   guint ttl;
+  gboolean bind_mcast;
 
   /* configure the sharedness */
   GST_RTSP_MEDIA_FACTORY_LOCK (factory);
@@ -1707,6 +1775,7 @@ default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media)
   clock = priv->clock ? gst_object_ref (priv->clock) : NULL;
   publish_clock_mode = priv->publish_clock_mode;
   ttl = priv->max_mcast_ttl;
+  bind_mcast = priv->bind_mcast_address;
   GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
 
   gst_rtsp_media_set_suspend_mode (media, suspend_mode);
@@ -1722,6 +1791,7 @@ default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media)
   gst_rtsp_media_set_stop_on_disconnect (media, stop_on_disconnect);
   gst_rtsp_media_set_publish_clock_mode (media, publish_clock_mode);
   gst_rtsp_media_set_max_mcast_ttl (media, ttl);
+  gst_rtsp_media_set_bind_mcast_address (media, bind_mcast);
 
   if (clock) {
     gst_rtsp_media_set_clock (media, clock);
index 46d7d55..65edbaa 100644 (file)
@@ -246,6 +246,12 @@ gboolean                gst_rtsp_media_factory_set_max_mcast_ttl (GstRTSPMediaFa
 GST_RTSP_SERVER_API
 guint                 gst_rtsp_media_factory_get_max_mcast_ttl (GstRTSPMediaFactory * factory);
 
+GST_RTSP_SERVER_API
+void                  gst_rtsp_media_factory_set_bind_mcast_address (GstRTSPMediaFactory * factory,
+                                                                     gboolean bind_mcast_addr);
+GST_RTSP_SERVER_API
+gboolean              gst_rtsp_media_factory_is_bind_mcast_address (GstRTSPMediaFactory * factory);
+
 /* creating the media from the factory and a url */
 
 GST_RTSP_SERVER_API
index b39fc93..15ab6a7 100644 (file)
@@ -102,6 +102,7 @@ struct _GstRTSPMediaPrivate
   GstRTSPAddressPool *pool;
   gchar *multicast_iface;
   guint max_mcast_ttl;
+  gboolean bind_mcast_address;
   gboolean blocked;
   GstRTSPTransportMode transport_mode;
   gboolean stop_on_disconnect;
@@ -163,6 +164,7 @@ struct _GstRTSPMediaPrivate
 #define DEFAULT_TRANSPORT_MODE  GST_RTSP_TRANSPORT_MODE_PLAY
 #define DEFAULT_STOP_ON_DISCONNECT TRUE
 #define DEFAULT_MAX_MCAST_TTL   255
+#define DEFAULT_BIND_MCAST_ADDRESS FALSE
 
 #define DEFAULT_DO_RETRANSMISSION FALSE
 
@@ -186,6 +188,7 @@ enum
   PROP_STOP_ON_DISCONNECT,
   PROP_CLOCK,
   PROP_MAX_MCAST_TTL,
+  PROP_BIND_MCAST_ADDRESS,
   PROP_LAST
 };
 
@@ -387,6 +390,13 @@ gst_rtsp_media_class_init (GstRTSPMediaClass * klass)
           255, DEFAULT_MAX_MCAST_TTL,
           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
 
+  g_object_class_install_property (gobject_class, PROP_BIND_MCAST_ADDRESS,
+      g_param_spec_boolean ("bind-mcast-address", "Bind mcast address",
+          "Whether the multicast sockets should be bound to multicast addresses "
+          "or INADDR_ANY",
+          DEFAULT_BIND_MCAST_ADDRESS,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
   gst_rtsp_media_signals[SIGNAL_NEW_STREAM] =
       g_signal_new ("new-stream", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
       G_STRUCT_OFFSET (GstRTSPMediaClass, new_stream), NULL, NULL,
@@ -458,6 +468,7 @@ gst_rtsp_media_init (GstRTSPMedia * media)
   priv->publish_clock_mode = GST_RTSP_PUBLISH_CLOCK_MODE_CLOCK;
   priv->do_retransmission = DEFAULT_DO_RETRANSMISSION;
   priv->max_mcast_ttl = DEFAULT_MAX_MCAST_TTL;
+  priv->bind_mcast_address = DEFAULT_BIND_MCAST_ADDRESS;
 }
 
 static void
@@ -547,6 +558,9 @@ gst_rtsp_media_get_property (GObject * object, guint propid,
     case PROP_MAX_MCAST_TTL:
       g_value_set_uint (value, gst_rtsp_media_get_max_mcast_ttl (media));
       break;
+    case PROP_BIND_MCAST_ADDRESS:
+      g_value_set_boolean (value, gst_rtsp_media_is_bind_mcast_address (media));
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
   }
@@ -603,6 +617,10 @@ gst_rtsp_media_set_property (GObject * object, guint propid,
     case PROP_MAX_MCAST_TTL:
       gst_rtsp_media_set_max_mcast_ttl (media, g_value_get_uint (value));
       break;
+    case PROP_BIND_MCAST_ADDRESS:
+      gst_rtsp_media_set_bind_mcast_address (media,
+          g_value_get_boolean (value));
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
   }
@@ -1906,6 +1924,59 @@ gst_rtsp_media_get_max_mcast_ttl (GstRTSPMedia * media)
   return res;
 }
 
+/**
+ * gst_rtsp_media_set_bind_mcast_address:
+ * @media: a #GstRTSPMedia
+ * @bind_mcast_addr: the new value
+ *
+ * Decide whether the multicast socket should be bound to a multicast address or
+ * INADDR_ANY.
+ */
+void
+gst_rtsp_media_set_bind_mcast_address (GstRTSPMedia * media,
+    gboolean bind_mcast_addr)
+{
+  GstRTSPMediaPrivate *priv;
+  guint i;
+
+  g_return_if_fail (GST_IS_RTSP_MEDIA (media));
+
+  priv = media->priv;
+
+  g_mutex_lock (&priv->lock);
+  priv->bind_mcast_address = bind_mcast_addr;
+  for (i = 0; i < priv->streams->len; i++) {
+    GstRTSPStream *stream = g_ptr_array_index (priv->streams, i);
+    gst_rtsp_stream_set_bind_mcast_address (stream, bind_mcast_addr);
+  }
+  g_mutex_unlock (&priv->lock);
+}
+
+/**
+ * gst_rtsp_media_is_bind_mcast_address:
+ * @media: a #GstRTSPMedia
+ *
+ * Check if multicast sockets are configured to be bound to multicast addresses.
+ *
+ * Returns: %TRUE if multicast sockets are configured to be bound to multicast addresses.
+ */
+gboolean
+gst_rtsp_media_is_bind_mcast_address (GstRTSPMedia * media)
+{
+  GstRTSPMediaPrivate *priv;
+  gboolean result;
+
+  g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
+
+  priv = media->priv;
+
+  g_mutex_lock (&priv->lock);
+  result = priv->bind_mcast_address;
+  g_mutex_unlock (&priv->lock);
+
+  return result;
+}
+
 static GList *
 _find_payload_types (GstRTSPMedia * media)
 {
@@ -2224,6 +2295,7 @@ gst_rtsp_media_create_stream (GstRTSPMedia * media, GstElement * payloader,
     gst_rtsp_stream_set_address_pool (stream, priv->pool);
   gst_rtsp_stream_set_multicast_iface (stream, priv->multicast_iface);
   gst_rtsp_stream_set_max_mcast_ttl (stream, priv->max_mcast_ttl);
+  gst_rtsp_stream_set_bind_mcast_address (stream, priv->bind_mcast_address);
   gst_rtsp_stream_set_profiles (stream, priv->profiles);
   gst_rtsp_stream_set_protocols (stream, priv->protocols);
   gst_rtsp_stream_set_retransmission_time (stream, priv->rtx_time);
index 92b3866..c7728c6 100644 (file)
@@ -320,6 +320,11 @@ gboolean                gst_rtsp_media_set_max_mcast_ttl  (GstRTSPMedia *media,
 GST_RTSP_SERVER_API
 guint                 gst_rtsp_media_get_max_mcast_ttl  (GstRTSPMedia *media);
 
+GST_RTSP_SERVER_API
+void                  gst_rtsp_media_set_bind_mcast_address  (GstRTSPMedia *media, gboolean bind_mcast_addr);
+GST_RTSP_SERVER_API
+gboolean              gst_rtsp_media_is_bind_mcast_address  (GstRTSPMedia *media);
+
 /* prepare the media for playback */
 
 GST_RTSP_SERVER_API
index 81054e0..18ec292 100644 (file)
@@ -150,6 +150,7 @@ struct _GstRTSPStreamPrivate
 
   gchar *multicast_iface;
   guint max_mcast_ttl;
+  gboolean bind_mcast_address;
 
   /* the caps of the stream */
   gulong caps_sig;
@@ -187,6 +188,7 @@ struct _GstRTSPStreamPrivate
 #define DEFAULT_PROTOCOLS       GST_RTSP_LOWER_TRANS_UDP | GST_RTSP_LOWER_TRANS_UDP_MCAST | \
                                         GST_RTSP_LOWER_TRANS_TCP
 #define DEFAULT_MAX_MCAST_TTL   255
+#define DEFAULT_BIND_MCAST_ADDRESS FALSE
 
 enum
 {
@@ -287,6 +289,7 @@ gst_rtsp_stream_init (GstRTSPStream * stream)
   priv->configured_protocols = 0;
   priv->publish_clock_mode = GST_RTSP_PUBLISH_CLOCK_MODE_CLOCK;
   priv->max_mcast_ttl = DEFAULT_MAX_MCAST_TTL;
+  priv->bind_mcast_address = DEFAULT_BIND_MCAST_ADDRESS;
 
   g_mutex_init (&priv->lock);
 
@@ -1381,13 +1384,19 @@ alloc_ports_one_family (GstRTSPStream * stream, GSocketFamily family,
     if (ct->destination != NULL) {
       tmp_rtp = ct->port.min;
       tmp_rtcp = ct->port.max;
+
+      /* check if the provided address is a multicast address */
       inetaddr = g_inet_address_new_from_string (ct->destination);
       if (inetaddr == NULL)
         goto destination_error;
       if (!g_inet_address_get_is_multicast (inetaddr))
         goto destination_no_mcast;
-      g_object_unref (inetaddr);
-      inetaddr = g_inet_address_new_any (family);
+
+
+      if (!priv->bind_mcast_address) {
+        g_clear_object (&inetaddr);
+        inetaddr = g_inet_address_new_any (family);
+      }
 
       GST_DEBUG_OBJECT (stream, "use transport settings");
       transport_settings_defined = TRUE;
@@ -1444,10 +1453,10 @@ again:
       g_clear_object (&inetaddr);
       /* FIXME: Does it really work with the IP_MULTICAST_ALL socket option and
        * socket control message set in udpsrc? */
-      if (multicast)
-        inetaddr = g_inet_address_new_any (family);
-      else
+      if (priv->bind_mcast_address || !multicast)
         inetaddr = g_inet_address_new_from_string (addr->address);
+      else
+        inetaddr = g_inet_address_new_any (family);
     } else {
       if (tmp_rtp != 0) {
         tmp_rtp += 2;
@@ -2152,6 +2161,47 @@ gst_rtsp_stream_verify_mcast_ttl (GstRTSPStream * stream, guint ttl)
   return res;
 }
 
+/**
+ * gst_rtsp_stream_set_bind_mcast_address:
+ * @stream: a #GstRTSPStream,
+ * @bind_mcast_addr: the new value
+ *
+ * Decide whether the multicast socket should be bound to a multicast address or
+ * INADDR_ANY.
+ */
+void
+gst_rtsp_stream_set_bind_mcast_address (GstRTSPStream * stream,
+    gboolean bind_mcast_addr)
+{
+  g_return_if_fail (GST_IS_RTSP_STREAM (stream));
+
+  g_mutex_lock (&stream->priv->lock);
+  stream->priv->bind_mcast_address = bind_mcast_addr;
+  g_mutex_unlock (&stream->priv->lock);
+}
+
+/**
+ * gst_rtsp_stream_is_bind_mcast_address:
+ * @stream: a #GstRTSPStream
+ *
+ * Check if multicast sockets are configured to be bound to multicast addresses.
+ *
+ * Returns: %TRUE if multicast sockets are configured to be bound to multicast addresses.
+ */
+gboolean
+gst_rtsp_stream_is_bind_mcast_address (GstRTSPStream * stream)
+{
+  gboolean result;
+
+  g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE);
+
+  g_mutex_lock (&stream->priv->lock);
+  result = stream->priv->bind_mcast_address;
+  g_mutex_unlock (&stream->priv->lock);
+
+  return result;
+}
+
 /* executed from streaming thread */
 static void
 caps_notify (GstPad * pad, GParamSpec * unused, GstRTSPStream * stream)
index 0c6804d..7910bb0 100644 (file)
@@ -312,6 +312,12 @@ GST_RTSP_SERVER_API
 gboolean          gst_rtsp_stream_verify_mcast_ttl  (GstRTSPStream *stream, guint ttl);
 
 GST_RTSP_SERVER_API
+void              gst_rtsp_stream_set_bind_mcast_address  (GstRTSPStream * stream, gboolean bind_mcast_addr);
+
+GST_RTSP_SERVER_API
+gboolean          gst_rtsp_stream_is_bind_mcast_address (GstRTSPStream * stream);
+
+GST_RTSP_SERVER_API
 gboolean          gst_rtsp_stream_complete_stream (GstRTSPStream * stream, const GstRTSPTransport * transport);
 
 GST_RTSP_SERVER_API
index aa7893c..b2e0dd3 100644 (file)
@@ -875,9 +875,6 @@ multicast_transport_specific (void)
       "user", NULL);
   gst_rtsp_context_push_current (&ctx);
 
-  expected_transport = "RTP/AVP;multicast;destination=233.252.0.1;"
-      "ttl=1;port=5000-5001;mode=\"PLAY\"";
-
   /* simple SETUP with a valid URI */
   fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_SETUP,
           "rtsp://localhost/test/stream=0") == GST_RTSP_OK);
@@ -1081,7 +1078,7 @@ static void
 mcast_transport_two_clients (gboolean shared, const gchar * transport1,
     const gchar * expected_transport1, const gchar * addr1,
     const gchar * transport2, const gchar * expected_transport2,
-    const gchar * addr2)
+    const gchar * addr2, gboolean bind_mcast_address)
 {
   GstRTSPClient *client1, *client2;
   GstRTSPMessage request = { 0, };
@@ -1101,6 +1098,7 @@ mcast_transport_two_clients (gboolean shared, const gchar * transport1,
   if (shared)
     gst_rtsp_media_factory_set_shared (factory, TRUE);
   gst_rtsp_media_factory_set_max_mcast_ttl (factory, 5);
+  gst_rtsp_media_factory_set_bind_mcast_address (factory, bind_mcast_address);
   gst_rtsp_media_factory_set_launch (factory,
       "audiotestsrc ! audio/x-raw,rate=44100 ! audioconvert ! rtpL16pay name=pay0");
   address_pool = gst_rtsp_address_pool_new ();
@@ -1256,7 +1254,7 @@ GST_START_TEST
 
   mcast_transport_two_clients (TRUE, transport_client_1,
       expected_transport_1, addr_client_1, transport_client_2,
-      expected_transport_2, addr_client_2);
+      expected_transport_2, addr_client_2, FALSE);
 }
 
 GST_END_TEST;
@@ -1277,11 +1275,59 @@ GST_START_TEST (test_client_multicast_transport_specific_two_clients)
 
   mcast_transport_two_clients (FALSE, transport_client_1,
       expected_transport_1, addr_client_1, transport_client_2,
-      expected_transport_2, addr_client_2);
+      expected_transport_2, addr_client_2, FALSE);
+}
+
+GST_END_TEST;
+
+/* test if two multicast clients can choose the same ports but different
+ * multicast destinations
+ * CASE: media is not shared */
+GST_START_TEST (test_client_multicast_transport_specific_two_clients_same_ports)
+{
+  const gchar *transport_client_1 = "RTP/AVP;multicast;destination=233.252.0.1;"
+      "ttl=1;port=9000-9001;mode=\"PLAY\"";
+  const gchar *expected_transport_1 = transport_client_1;
+  const gchar *addr_client_1 = "233.252.0.1:9000";
+
+  const gchar *transport_client_2 = "RTP/AVP;multicast;destination=233.252.0.2;"
+      "ttl=1;port=9000-9001;mode=\"PLAY\"";
+  const gchar *expected_transport_2 = transport_client_2;
+  const gchar *addr_client_2 = "233.252.0.2:9000";
+
+  /* configure the multicast socket to be bound to the requested multicast address instead of INADDR_ANY.
+   * The clients request the same rtp/rtcp borts and having the socket that are bound to ANY would result
+   * in bind() failure */
+  gboolean allow_bind_mcast_address = TRUE;
+
+  mcast_transport_two_clients (FALSE, transport_client_1,
+      expected_transport_1, addr_client_1, transport_client_2,
+      expected_transport_2, addr_client_2, allow_bind_mcast_address);
 }
 
 GST_END_TEST;
 
+/* test if two multicast clients can choose the same multicast destination but different
+ * ports
+ * CASE: media is not shared */
+GST_START_TEST
+    (test_client_multicast_transport_specific_two_clients_same_destination) {
+  const gchar *transport_client_1 = "RTP/AVP;multicast;destination=233.252.0.2;"
+      "ttl=1;port=9002-9003;mode=\"PLAY\"";
+  const gchar *expected_transport_1 = transport_client_1;
+  const gchar *addr_client_1 = "233.252.0.2:9002";
+
+  const gchar *transport_client_2 = "RTP/AVP;multicast;destination=233.252.0.2;"
+      "ttl=1;port=9004-9005;mode=\"PLAY\"";
+  const gchar *expected_transport_2 = transport_client_2;
+  const gchar *addr_client_2 = "233.252.0.2:9004";
+
+  mcast_transport_two_clients (FALSE, transport_client_1,
+      expected_transport_1, addr_client_1, transport_client_2,
+      expected_transport_2, addr_client_2, FALSE);
+}
+
+GST_END_TEST;
 /* test if two multicast clients can choose the same transport settings.
  * CASE: media is shared */
 GST_START_TEST
@@ -1299,7 +1345,7 @@ GST_START_TEST
 
   mcast_transport_two_clients (TRUE, transport_client_1,
       expected_transport_1, addr_client_1, transport_client_2,
-      expected_transport_2, addr_client_2);
+      expected_transport_2, addr_client_2, FALSE);
 }
 
 GST_END_TEST;
@@ -1321,7 +1367,7 @@ GST_START_TEST (test_client_multicast_two_clients_shared_media)
 
   mcast_transport_two_clients (TRUE, transport_client_1,
       expected_transport_1, addr_client_1, transport_client_2,
-      expected_transport_2, addr_client_2);
+      expected_transport_2, addr_client_2, FALSE);
 }
 
 GST_END_TEST;
@@ -1343,7 +1389,7 @@ GST_START_TEST
 
   mcast_transport_two_clients (TRUE, transport_client_1,
       expected_transport_1, addr_client_1, transport_client_2,
-      expected_transport_2, addr_client_2);
+      expected_transport_2, addr_client_2, FALSE);
 }
 
 GST_END_TEST;
@@ -1366,7 +1412,7 @@ GST_START_TEST
 
   mcast_transport_two_clients (TRUE, transport_client_1,
       expected_transport_1, addr_client_1, transport_client_2,
-      expected_transport_2, addr_client_2);
+      expected_transport_2, addr_client_2, FALSE);
 }
 
 GST_END_TEST;
@@ -1389,7 +1435,7 @@ GST_START_TEST (test_client_multicast_max_ttl_first_client)
 
   mcast_transport_two_clients (TRUE, transport_client_1,
       expected_transport_1, addr_client_1, transport_client_2,
-      expected_transport_2, addr_client_2);
+      expected_transport_2, addr_client_2, FALSE);
 }
 
 GST_END_TEST;
@@ -1410,7 +1456,7 @@ GST_START_TEST (test_client_multicast_max_ttl_second_client)
 
   mcast_transport_two_clients (TRUE, transport_client_1,
       expected_transport_1, addr_client_1, transport_client_2,
-      expected_transport_2, addr_client_2);
+      expected_transport_2, addr_client_2, FALSE);
 }
 
 GST_END_TEST;
@@ -1483,6 +1529,17 @@ rtspclient_suite (void)
   tcase_add_test (tc,
       test_client_multicast_transport_specific_two_clients_shared_media);
   tcase_add_test (tc, test_client_multicast_transport_specific_two_clients);
+#ifndef G_OS_WIN32
+  tcase_add_test (tc,
+      test_client_multicast_transport_specific_two_clients_same_ports);
+#else
+  /* skip the test on windows as the test restricts the multicast sockets to multicast traffic only,
+   * by specifying the multicast IP as the bind address and this currently doesn't work on Windows */
+  tcase_skip_broken_test (tc,
+      test_client_multicast_transport_specific_two_clients_same_ports);
+#endif
+  tcase_add_test (tc,
+      test_client_multicast_transport_specific_two_clients_same_destination);
   tcase_add_test (tc,
       test_client_multicast_transport_specific_two_clients_shared_media_same_transport);
   tcase_add_test (tc, test_client_multicast_two_clients_shared_media);
index ba1719e..2fc453c 100644 (file)
@@ -371,6 +371,55 @@ GST_START_TEST (test_mcast_ttl)
 
 GST_END_TEST;
 
+
+GST_START_TEST (test_allow_bind_mcast)
+{
+  GstRTSPMediaFactory *factory;
+  GstRTSPMedia *media;
+  GstRTSPUrl *url;
+  GstRTSPStream *stream;
+
+  factory = gst_rtsp_media_factory_new ();
+  gst_rtsp_media_factory_set_shared (factory, TRUE);
+  fail_unless (gst_rtsp_url_parse ("rtsp://localhost:8554/test",
+          &url) == GST_RTSP_OK);
+
+  gst_rtsp_media_factory_set_launch (factory,
+      "( videotestsrc ! rtpvrawpay pt=96 name=pay0 "
+      " audiotestsrc ! audioconvert ! rtpL16pay name=pay1 )");
+
+  /* verify that by default binding sockets to multicast addresses is not enabled */
+  fail_unless (gst_rtsp_media_factory_is_bind_mcast_address (factory) == FALSE);
+
+  /* allow multicast sockets to be bound to multicast addresses */
+  gst_rtsp_media_factory_set_bind_mcast_address (factory, TRUE);
+  /* verify that the socket binding to multicast address has been enabled */
+  fail_unless (gst_rtsp_media_factory_is_bind_mcast_address (factory) == TRUE);
+
+  media = gst_rtsp_media_factory_construct (factory, url);
+  fail_unless (GST_IS_RTSP_MEDIA (media));
+
+  /* verify that the correct socket binding configuration has been propageted to the media */
+  fail_unless (gst_rtsp_media_is_bind_mcast_address (media) == TRUE);
+
+  fail_unless (gst_rtsp_media_n_streams (media) == 2);
+
+  /* verify that the correct socket binding configuration has been propageted to the media streams */
+  stream = gst_rtsp_media_get_stream (media, 0);
+  fail_unless (stream != NULL);
+  fail_unless (gst_rtsp_stream_is_bind_mcast_address (stream) == TRUE);
+
+  stream = gst_rtsp_media_get_stream (media, 1);
+  fail_unless (stream != NULL);
+  fail_unless (gst_rtsp_stream_is_bind_mcast_address (stream) == TRUE);
+
+  g_object_unref (media);
+  gst_rtsp_url_free (url);
+  g_object_unref (factory);
+}
+
+GST_END_TEST;
+
 static Suite *
 rtspmediafactory_suite (void)
 {
@@ -387,6 +436,7 @@ rtspmediafactory_suite (void)
   tcase_add_test (tc, test_permissions);
   tcase_add_test (tc, test_reset);
   tcase_add_test (tc, test_mcast_ttl);
+  tcase_add_test (tc, test_allow_bind_mcast);
 
   return s;
 }