rtsp-media: Add support for setting the multicast interface
authorSebastian Dröge <sebastian@centricular.com>
Wed, 2 Mar 2016 17:42:13 +0000 (19:42 +0200)
committerSebastian Dröge <sebastian@centricular.com>
Fri, 25 Mar 2016 10:52:12 +0000 (12:52 +0200)
https://bugzilla.gnome.org/show_bug.cgi?id=763000

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

index cb4fe75..8bfc422 100644 (file)
@@ -61,6 +61,7 @@ struct _GstRTSPMediaFactoryPrivate
   GstRTSPAddressPool *pool;
   GstRTSPTransportMode transport_mode;
   gboolean stop_on_disconnect;
+  gchar *multicast_iface;
 
   GstClockTime rtx_time;
   guint latency;
@@ -282,6 +283,7 @@ gst_rtsp_media_factory_finalize (GObject * obj)
   g_mutex_clear (&priv->lock);
   if (priv->pool)
     g_object_unref (priv->pool);
+  g_free (priv->multicast_iface);
 
   G_OBJECT_CLASS (gst_rtsp_media_factory_parent_class)->finalize (obj);
 }
@@ -797,6 +799,64 @@ gst_rtsp_media_factory_get_address_pool (GstRTSPMediaFactory * factory)
 }
 
 /**
+ * gst_rtsp_media_factory_set_multicast_iface:
+ * @media_factory: a #GstRTSPMediaFactory
+ * @multicast_iface: (transfer none): a multicast interface
+ *
+ * configure @multicast_iface to be used for @media_factory.
+ */
+void
+gst_rtsp_media_factory_set_multicast_iface (GstRTSPMediaFactory * media_factory,
+    const gchar * multicast_iface)
+{
+  GstRTSPMediaFactoryPrivate *priv;
+  gchar *old;
+
+  g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (media_factory));
+
+  priv = media_factory->priv;
+
+  GST_LOG_OBJECT (media_factory, "set multicast interface %s", multicast_iface);
+
+  g_mutex_lock (&priv->lock);
+  if ((old = priv->multicast_iface) != multicast_iface)
+    priv->multicast_iface = multicast_iface ? g_strdup (multicast_iface) : NULL;
+  else
+    old = NULL;
+  g_mutex_unlock (&priv->lock);
+
+  if (old)
+    g_object_unref (old);
+}
+
+/**
+ * gst_rtsp_media_factory_get_multicast_iface:
+ * @media_factory: a #GstRTSPMediaFactory
+ *
+ * Get the multicast interface used for @media_factory.
+ *
+ * Returns: (transfer full): the multicast interface for @media_factory. g_free() after
+ * usage.
+ */
+gchar *
+gst_rtsp_media_factory_get_multicast_iface (GstRTSPMediaFactory * media_factory)
+{
+  GstRTSPMediaFactoryPrivate *priv;
+  gchar *result;
+
+  g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (media_factory), NULL);
+
+  priv = media_factory->priv;
+
+  g_mutex_lock (&priv->lock);
+  if ((result = priv->multicast_iface))
+    result = g_strdup (result);
+  g_mutex_unlock (&priv->lock);
+
+  return result;
+}
+
+/**
  * gst_rtsp_media_factory_set_profiles:
  * @factory: a #GstRTSPMediaFactory
  * @profiles: the new flags
@@ -1419,6 +1479,7 @@ default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media)
   guint latency;
   GstRTSPTransportMode transport_mode;
   GstClock *clock;
+  gchar *multicast_iface;
 
   /* configure the sharedness */
   GST_RTSP_MEDIA_FACTORY_LOCK (factory);
@@ -1455,6 +1516,10 @@ default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media)
     gst_rtsp_media_set_address_pool (media, pool);
     g_object_unref (pool);
   }
+  if ((multicast_iface = gst_rtsp_media_factory_get_multicast_iface (factory))) {
+    gst_rtsp_media_set_multicast_iface (media, multicast_iface);
+    g_free (multicast_iface);
+  }
   if ((perms = gst_rtsp_media_factory_get_permissions (factory))) {
     gst_rtsp_media_set_permissions (media, perms);
     gst_rtsp_permissions_unref (perms);
index c4e0a8e..f0b6bd5 100644 (file)
@@ -142,6 +142,9 @@ void                  gst_rtsp_media_factory_set_address_pool (GstRTSPMediaFacto
                                                                GstRTSPAddressPool * pool);
 GstRTSPAddressPool *  gst_rtsp_media_factory_get_address_pool (GstRTSPMediaFactory * factory);
 
+void                  gst_rtsp_media_factory_set_multicast_iface (GstRTSPMediaFactory *factory, const gchar *multicast_iface);
+gchar *               gst_rtsp_media_factory_get_multicast_iface (GstRTSPMediaFactory *factory);
+
 void                  gst_rtsp_media_factory_set_buffer_size  (GstRTSPMediaFactory * factory,
                                                                guint size);
 guint                 gst_rtsp_media_factory_get_buffer_size  (GstRTSPMediaFactory * factory);
index 9e49c5d..4fb6d51 100644 (file)
@@ -100,6 +100,7 @@ struct _GstRTSPMediaPrivate
   gboolean eos_shutdown;
   guint buffer_size;
   GstRTSPAddressPool *pool;
+  gchar *multicast_iface;
   gboolean blocked;
   GstRTSPTransportMode transport_mode;
   gboolean stop_on_disconnect;
@@ -443,6 +444,7 @@ gst_rtsp_media_finalize (GObject * obj)
     g_object_unref (priv->pool);
   if (priv->payloads)
     g_list_free (priv->payloads);
+  g_free (priv->multicast_iface);
   g_mutex_clear (&priv->lock);
   g_cond_clear (&priv->cond);
   g_rec_mutex_clear (&priv->state_lock);
@@ -1496,6 +1498,66 @@ gst_rtsp_media_get_address_pool (GstRTSPMedia * media)
   return result;
 }
 
+/**
+ * gst_rtsp_media_set_multicast_iface:
+ * @media: a #GstRTSPMedia
+ * @multicast_iface: (transfer none): a multicast interface
+ *
+ * configure @multicast_iface to be used for @media.
+ */
+void
+gst_rtsp_media_set_multicast_iface (GstRTSPMedia * media,
+    const gchar * multicast_iface)
+{
+  GstRTSPMediaPrivate *priv;
+  gchar *old;
+
+  g_return_if_fail (GST_IS_RTSP_MEDIA (media));
+
+  priv = media->priv;
+
+  GST_LOG_OBJECT (media, "set multicast interface %s", multicast_iface);
+
+  g_mutex_lock (&priv->lock);
+  if ((old = priv->multicast_iface) != multicast_iface)
+    priv->multicast_iface = multicast_iface ? g_strdup (multicast_iface) : NULL;
+  else
+    old = NULL;
+  g_ptr_array_foreach (priv->streams,
+      (GFunc) gst_rtsp_stream_set_multicast_iface, (gchar *) multicast_iface);
+  g_mutex_unlock (&priv->lock);
+
+  if (old)
+    g_object_unref (old);
+}
+
+/**
+ * gst_rtsp_media_get_multicast_iface:
+ * @media: a #GstRTSPMedia
+ *
+ * Get the multicast interface used for @media.
+ *
+ * Returns: (transfer full): the multicast interface for @media. g_free() after
+ * usage.
+ */
+gchar *
+gst_rtsp_media_get_multicast_iface (GstRTSPMedia * media)
+{
+  GstRTSPMediaPrivate *priv;
+  gchar *result;
+
+  g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL);
+
+  priv = media->priv;
+
+  g_mutex_lock (&priv->lock);
+  if ((result = priv->multicast_iface))
+    result = g_strdup (result);
+  g_mutex_unlock (&priv->lock);
+
+  return result;
+}
+
 static GList *
 _find_payload_types (GstRTSPMedia * media)
 {
@@ -1677,6 +1739,7 @@ gst_rtsp_media_create_stream (GstRTSPMedia * media, GstElement * payloader,
   stream = gst_rtsp_stream_new (idx, payloader, ghostpad);
   if (priv->pool)
     gst_rtsp_stream_set_address_pool (stream, priv->pool);
+  gst_rtsp_stream_set_multicast_iface (stream, priv->multicast_iface);
   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 400c123..c0de06c 100644 (file)
@@ -207,6 +207,9 @@ gboolean              gst_rtsp_media_is_eos_shutdown  (GstRTSPMedia *media);
 void                  gst_rtsp_media_set_address_pool (GstRTSPMedia *media, GstRTSPAddressPool *pool);
 GstRTSPAddressPool *  gst_rtsp_media_get_address_pool (GstRTSPMedia *media);
 
+void                  gst_rtsp_media_set_multicast_iface (GstRTSPMedia *media, const gchar *multicast_iface);
+gchar *               gst_rtsp_media_get_multicast_iface (GstRTSPMedia *media);
+
 void                  gst_rtsp_media_set_buffer_size  (GstRTSPMedia *media, guint size);
 guint                 gst_rtsp_media_get_buffer_size  (GstRTSPMedia *media);
 
index faa76fe..9997181 100644 (file)
@@ -140,6 +140,8 @@ struct _GstRTSPStreamPrivate
   gboolean have_ipv4_mcast;
   gboolean have_ipv6_mcast;
 
+  gchar *multicast_iface;
+
   /* the caps of the stream */
   gulong caps_sig;
   GstCaps *caps;
@@ -293,6 +295,8 @@ gst_rtsp_stream_finalize (GObject * obj)
   if (priv->rtxsend)
     g_object_unref (priv->rtxsend);
 
+  g_free (priv->multicast_iface);
+
   gst_object_unref (priv->payloader);
   if (priv->srcpad)
     gst_object_unref (priv->srcpad);
@@ -862,6 +866,65 @@ gst_rtsp_stream_get_address_pool (GstRTSPStream * stream)
 }
 
 /**
+ * gst_rtsp_stream_set_multicast_iface:
+ * @stream: a #GstRTSPStream
+ * @multicast_iface: (transfer none): a multicast interface
+ *
+ * configure @multicast_iface to be used for @stream.
+ */
+void
+gst_rtsp_stream_set_multicast_iface (GstRTSPStream * stream,
+    const gchar * multicast_iface)
+{
+  GstRTSPStreamPrivate *priv;
+  gchar *old;
+
+  g_return_if_fail (GST_IS_RTSP_STREAM (stream));
+
+  priv = stream->priv;
+
+  GST_LOG_OBJECT (stream, "set multicast iface %s",
+      GST_STR_NULL (multicast_iface));
+
+  g_mutex_lock (&priv->lock);
+  if ((old = priv->multicast_iface) != multicast_iface)
+    priv->multicast_iface = multicast_iface ? g_strdup (multicast_iface) : NULL;
+  else
+    old = NULL;
+  g_mutex_unlock (&priv->lock);
+
+  if (old)
+    g_free (old);
+}
+
+/**
+ * gst_rtsp_stream_get_multicast_iface:
+ * @stream: a #GstRTSPStream
+ *
+ * Get the multicast interface used for @stream.
+ *
+ * Returns: (transfer full): the multicast interface for @stream. g_free() after
+ * usage.
+ */
+gchar *
+gst_rtsp_stream_get_multicast_iface (GstRTSPStream * stream)
+{
+  GstRTSPStreamPrivate *priv;
+  gchar *result;
+
+  g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), NULL);
+
+  priv = stream->priv;
+
+  g_mutex_lock (&priv->lock);
+  if ((result = priv->multicast_iface))
+    result = g_strdup (result);
+  g_mutex_unlock (&priv->lock);
+
+  return result;
+}
+
+/**
  * gst_rtsp_stream_get_multicast_address:
  * @stream: a #GstRTSPStream
  * @family: the #GSocketFamily
@@ -1145,7 +1208,7 @@ static gboolean
 create_and_configure_udpsources_one_family (GstElement * udpsrc_out[2],
     GSocket * rtp_socket, GSocket * rtcp_socket, GSocketFamily family,
     const gchar * address, gint rtpport, gint rtcpport,
-    GstRTSPLowerTrans transport)
+    const gchar * multicast_iface, GstRTSPLowerTrans transport)
 {
   GstStateChangeReturn ret;
 
@@ -1160,6 +1223,10 @@ create_and_configure_udpsources_one_family (GstElement * udpsrc_out[2],
     g_object_set (G_OBJECT (udpsrc_out[1]), "address", address, NULL);
     g_object_set (G_OBJECT (udpsrc_out[0]), "port", rtpport, NULL);
     g_object_set (G_OBJECT (udpsrc_out[1]), "port", rtcpport, NULL);
+    g_object_set (G_OBJECT (udpsrc_out[0]), "multicast-iface", multicast_iface,
+        NULL);
+    g_object_set (G_OBJECT (udpsrc_out[1]), "multicast-iface", multicast_iface,
+        NULL);
     g_object_set (G_OBJECT (udpsrc_out[0]), "loop", FALSE, NULL);
     g_object_set (G_OBJECT (udpsrc_out[1]), "loop", FALSE, NULL);
   }
@@ -1208,6 +1275,7 @@ alloc_ports_one_family (GstRTSPStream * stream, GSocketFamily family,
   GSocketAddress *rtcp_sockaddr = NULL;
   GstRTSPAddressPool *pool;
   GstRTSPLowerTrans transport;
+  const gchar *multicast_iface = priv->multicast_iface;
 
   pool = priv->pool;
   count = 0;
@@ -1339,7 +1407,8 @@ again:
   g_clear_object (&inetaddr);
 
   if (!create_and_configure_udpsources_one_family (udpsrc_out, rtp_socket,
-          rtcp_socket, family, addr_str, tmp_rtp, tmp_rtcp, transport)) {
+          rtcp_socket, family, addr_str, tmp_rtp, tmp_rtcp, multicast_iface,
+          transport)) {
     if (addr == NULL)
       g_free (addr_str);
     goto no_udp_protocol;
index 46304ac..c347cb8 100644 (file)
@@ -96,6 +96,9 @@ void              gst_rtsp_stream_set_address_pool (GstRTSPStream *stream, GstRT
 GstRTSPAddressPool *
                   gst_rtsp_stream_get_address_pool (GstRTSPStream *stream);
 
+void              gst_rtsp_stream_set_multicast_iface (GstRTSPStream *stream, const gchar * multicast_iface);
+gchar *           gst_rtsp_stream_get_multicast_iface (GstRTSPStream *stream);
+
 GstRTSPAddress *  gst_rtsp_stream_reserve_address  (GstRTSPStream *stream,
                                                     const gchar * address,
                                                     guint port,