From c394de2348c4cc3add2a9fc9cff30733d95c93b7 Mon Sep 17 00:00:00 2001 From: Patricia Muscalu Date: Thu, 6 Sep 2018 16:17:33 +0200 Subject: [PATCH] New property for socket binding to mcast addresses 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 | 70 ++++++++++++++++++++++++ gst/rtsp-server/rtsp-media-factory.h | 6 +++ gst/rtsp-server/rtsp-media.c | 72 +++++++++++++++++++++++++ gst/rtsp-server/rtsp-media.h | 5 ++ gst/rtsp-server/rtsp-stream.c | 60 +++++++++++++++++++-- gst/rtsp-server/rtsp-stream.h | 6 +++ tests/check/gst/client.c | 81 +++++++++++++++++++++++----- tests/check/gst/mediafactory.c | 50 +++++++++++++++++ 8 files changed, 333 insertions(+), 17 deletions(-) diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c index 904124d1..27825e02 100644 --- a/gst/rtsp-server/rtsp-media-factory.c +++ b/gst/rtsp-server/rtsp-media-factory.c @@ -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); diff --git a/gst/rtsp-server/rtsp-media-factory.h b/gst/rtsp-server/rtsp-media-factory.h index 46d7d551..65edbaa0 100644 --- a/gst/rtsp-server/rtsp-media-factory.h +++ b/gst/rtsp-server/rtsp-media-factory.h @@ -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 diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c index b39fc93a..15ab6a7a 100644 --- a/gst/rtsp-server/rtsp-media.c +++ b/gst/rtsp-server/rtsp-media.c @@ -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); diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h index 92b3866a..c7728c6f 100644 --- a/gst/rtsp-server/rtsp-media.h +++ b/gst/rtsp-server/rtsp-media.h @@ -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 diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 81054e04..18ec2925 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -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 @@ alloc_ports_one_family (GstRTSPStream * stream, GSocketFamily family, 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) diff --git a/gst/rtsp-server/rtsp-stream.h b/gst/rtsp-server/rtsp-stream.h index 0c6804d5..7910bb05 100644 --- a/gst/rtsp-server/rtsp-stream.h +++ b/gst/rtsp-server/rtsp-stream.h @@ -311,6 +311,12 @@ guint gst_rtsp_stream_get_max_mcast_ttl (GstRTSPStream *stream); 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); diff --git a/tests/check/gst/client.c b/tests/check/gst/client.c index aa7893c7..b2e0dd38 100644 --- a/tests/check/gst/client.c +++ b/tests/check/gst/client.c @@ -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); diff --git a/tests/check/gst/mediafactory.c b/tests/check/gst/mediafactory.c index ba1719ea..2fc453cf 100644 --- a/tests/check/gst/mediafactory.c +++ b/tests/check/gst/mediafactory.c @@ -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; }