+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)
+{
+ GstRTSPClient *client1, *client2;
+ GstRTSPMessage request = { 0, };
+ gchar *str;
+ GstRTSPSessionPool *session_pool;
+ GstRTSPContext ctx = { NULL };
+ GstRTSPContext ctx2 = { NULL };
+ GstRTSPMountPoints *mount_points;
+ GstRTSPMediaFactory *factory;
+ GstRTSPAddressPool *address_pool;
+ GstRTSPThreadPool *thread_pool;
+ gchar *session_id1;
+ gchar *client_addr = NULL;
+
+ mount_points = gst_rtsp_mount_points_new ();
+ factory = gst_rtsp_media_factory_new ();
+ 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_launch (factory,
+ "audiotestsrc ! audio/x-raw,rate=44100 ! audioconvert ! rtpL16pay name=pay0");
+ address_pool = gst_rtsp_address_pool_new ();
+ fail_unless (gst_rtsp_address_pool_add_range (address_pool,
+ "233.252.0.1", "233.252.0.1", 5000, 5001, 1));
+ gst_rtsp_media_factory_set_address_pool (factory, address_pool);
+ gst_rtsp_media_factory_add_role (factory, "user",
+ "media.factory.access", G_TYPE_BOOLEAN, TRUE,
+ "media.factory.construct", G_TYPE_BOOLEAN, TRUE, NULL);
+ gst_rtsp_mount_points_add_factory (mount_points, "/test", factory);
+ session_pool = gst_rtsp_session_pool_new ();
+ thread_pool = gst_rtsp_thread_pool_new ();
+
+ /* first multicast client with transport specific request */
+ client1 = gst_rtsp_client_new ();
+ gst_rtsp_client_set_session_pool (client1, session_pool);
+ gst_rtsp_client_set_mount_points (client1, mount_points);
+ gst_rtsp_client_set_thread_pool (client1, thread_pool);
+
+ ctx.client = client1;
+ ctx.auth = gst_rtsp_auth_new ();
+ ctx.token =
+ gst_rtsp_token_new (GST_RTSP_TOKEN_TRANSPORT_CLIENT_SETTINGS,
+ G_TYPE_BOOLEAN, TRUE, GST_RTSP_TOKEN_MEDIA_FACTORY_ROLE, G_TYPE_STRING,
+ "user", NULL);
+ gst_rtsp_context_push_current (&ctx);
+
+ expected_transport = expected_transport1;
+
+ /* send SETUP request */
+ fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_SETUP,
+ "rtsp://localhost/test/stream=0") == GST_RTSP_OK);
+ str = g_strdup_printf ("%d", cseq);
+ gst_rtsp_message_take_header (&request, GST_RTSP_HDR_CSEQ, str);
+ gst_rtsp_message_add_header (&request, GST_RTSP_HDR_TRANSPORT, transport1);
+
+ gst_rtsp_client_set_send_func (client1, test_setup_response_200, NULL, NULL);
+ fail_unless (gst_rtsp_client_handle_message (client1,
+ &request) == GST_RTSP_OK);
+ gst_rtsp_message_unset (&request);
+ expected_transport = NULL;
+
+ /* send PLAY request */
+ fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_PLAY,
+ "rtsp://localhost/test") == GST_RTSP_OK);
+ str = g_strdup_printf ("%d", cseq);
+ gst_rtsp_message_take_header (&request, GST_RTSP_HDR_CSEQ, str);
+ gst_rtsp_message_add_header (&request, GST_RTSP_HDR_SESSION, session_id);
+ gst_rtsp_client_set_send_func (client1, test_response_200, NULL, NULL);
+ fail_unless (gst_rtsp_client_handle_message (client1,
+ &request) == GST_RTSP_OK);
+ gst_rtsp_message_unset (&request);
+
+ /* check address */
+ client_addr = gst_rtsp_stream_get_multicast_client_addresses (ctx.stream);
+ fail_if (client_addr == NULL);
+ fail_unless (g_str_equal (client_addr, addr1));
+ g_free (client_addr);
+
+ gst_rtsp_context_pop_current (&ctx);
+ session_id1 = g_strdup (session_id);
+
+ /* second multicast client with transport specific request */
+ cseq = 0;
+ client2 = gst_rtsp_client_new ();
+ gst_rtsp_client_set_session_pool (client2, session_pool);
+ gst_rtsp_client_set_mount_points (client2, mount_points);
+ gst_rtsp_client_set_thread_pool (client2, thread_pool);
+
+ ctx2.client = client2;
+ ctx2.auth = gst_rtsp_auth_new ();
+ ctx2.token =
+ gst_rtsp_token_new (GST_RTSP_TOKEN_TRANSPORT_CLIENT_SETTINGS,
+ G_TYPE_BOOLEAN, TRUE, GST_RTSP_TOKEN_MEDIA_FACTORY_ROLE, G_TYPE_STRING,
+ "user", NULL);
+ gst_rtsp_context_push_current (&ctx2);
+
+ expected_transport = expected_transport2;
+
+ /* send SETUP request */
+ fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_SETUP,
+ "rtsp://localhost/test/stream=0") == GST_RTSP_OK);
+ str = g_strdup_printf ("%d", cseq);
+ gst_rtsp_message_take_header (&request, GST_RTSP_HDR_CSEQ, str);
+ gst_rtsp_message_add_header (&request, GST_RTSP_HDR_TRANSPORT, transport2);
+
+ gst_rtsp_client_set_send_func (client2, test_setup_response_200, NULL, NULL);
+ fail_unless (gst_rtsp_client_handle_message (client2,
+ &request) == GST_RTSP_OK);
+ gst_rtsp_message_unset (&request);
+ expected_transport = NULL;
+
+ /* send PLAY request */
+ fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_PLAY,
+ "rtsp://localhost/test") == GST_RTSP_OK);
+ str = g_strdup_printf ("%d", cseq);
+ gst_rtsp_message_take_header (&request, GST_RTSP_HDR_CSEQ, str);
+ gst_rtsp_message_add_header (&request, GST_RTSP_HDR_SESSION, session_id);
+ gst_rtsp_client_set_send_func (client2, test_response_200, NULL, NULL);
+ fail_unless (gst_rtsp_client_handle_message (client2,
+ &request) == GST_RTSP_OK);
+ gst_rtsp_message_unset (&request);
+
+ /* check addresses */
+ client_addr = gst_rtsp_stream_get_multicast_client_addresses (ctx2.stream);
+ fail_if (client_addr == NULL);
+ if (shared) {
+ if (g_str_equal (addr1, addr2)) {
+ fail_unless (g_str_equal (client_addr, addr1));
+ } else {
+ gchar *addr_str = g_strdup_printf ("%s,%s", addr2, addr1);
+ fail_unless (g_str_equal (client_addr, addr_str));
+ g_free (addr_str);
+ }
+ } else {
+ fail_unless (g_str_equal (client_addr, addr2));
+ }
+ g_free (client_addr);
+
+ send_teardown (client2);
+ gst_rtsp_context_pop_current (&ctx2);
+
+ gst_rtsp_context_push_current (&ctx);
+ session_id = session_id1;
+ send_teardown (client1);
+ gst_rtsp_context_pop_current (&ctx);
+
+ teardown_client (client1);
+ teardown_client (client2);
+ g_object_unref (ctx.auth);
+ g_object_unref (ctx2.auth);
+ gst_rtsp_token_unref (ctx.token);
+ gst_rtsp_token_unref (ctx2.token);
+ g_object_unref (mount_points);
+ g_object_unref (session_pool);
+ g_object_unref (address_pool);
+ g_object_unref (thread_pool);
+}
+
+/* test if two multicast clients can choose different transport settings
+ * CASE: media is shared */
+GST_START_TEST
+ (test_client_multicast_transport_specific_two_clients_shared_media) {
+ const gchar *transport_client_1 = "RTP/AVP;multicast;destination=233.252.0.1;"
+ "ttl=1;port=5000-5001;mode=\"PLAY\"";
+ const gchar *expected_transport_1 = transport_client_1;
+ const gchar *addr_client_1 = "233.252.0.1:5000";
+
+ const gchar *transport_client_2 = "RTP/AVP;multicast;destination=233.252.0.2;"
+ "ttl=1;port=5002-5003;mode=\"PLAY\"";
+ const gchar *expected_transport_2 = transport_client_2;
+ const gchar *addr_client_2 = "233.252.0.2:5002";
+
+ mcast_transport_two_clients (TRUE, transport_client_1,
+ expected_transport_1, addr_client_1, transport_client_2,
+ expected_transport_2, addr_client_2);
+}
+
+GST_END_TEST;
+
+/* test if two multicast clients can choose different transport settings
+ * CASE: media is not shared */
+GST_START_TEST (test_client_multicast_transport_specific_two_clients)
+{
+ const gchar *transport_client_1 = "RTP/AVP;multicast;destination=233.252.0.1;"
+ "ttl=1;port=5000-5001;mode=\"PLAY\"";
+ const gchar *expected_transport_1 = transport_client_1;
+ const gchar *addr_client_1 = "233.252.0.1:5000";
+
+ const gchar *transport_client_2 = "RTP/AVP;multicast;destination=233.252.0.2;"
+ "ttl=1;port=5002-5003;mode=\"PLAY\"";
+ const gchar *expected_transport_2 = transport_client_2;
+ const gchar *addr_client_2 = "233.252.0.2:5002";
+
+ mcast_transport_two_clients (FALSE, transport_client_1,
+ expected_transport_1, addr_client_1, transport_client_2,
+ expected_transport_2, addr_client_2);
+}
+
+GST_END_TEST;
+
+/* test if two multicast clients can choose the same transport settings.
+ * CASE: media is shared */
+GST_START_TEST
+ (test_client_multicast_transport_specific_two_clients_shared_media_same_transport)
+{
+
+ const gchar *transport_client_1 = "RTP/AVP;multicast;destination=233.252.0.1;"
+ "ttl=1;port=5000-5001;mode=\"PLAY\"";
+ const gchar *expected_transport_1 = transport_client_1;
+ const gchar *addr_client_1 = "233.252.0.1:5000";
+
+ const gchar *transport_client_2 = transport_client_1;
+ const gchar *expected_transport_2 = expected_transport_1;
+ const gchar *addr_client_2 = addr_client_1;
+
+ mcast_transport_two_clients (TRUE, transport_client_1,
+ expected_transport_1, addr_client_1, transport_client_2,
+ expected_transport_2, addr_client_2);
+}
+
+GST_END_TEST;
+
+/* test if two multicast clients get the same transport settings without
+ * requesting specific transport.
+ * CASE: media is shared */
+GST_START_TEST (test_client_multicast_two_clients_shared_media)
+{
+ const gchar *transport_client_1 = "RTP/AVP;multicast;mode=\"PLAY\"";
+ const gchar *expected_transport_1 =
+ "RTP/AVP;multicast;destination=233.252.0.1;"
+ "ttl=1;port=5000-5001;mode=\"PLAY\"";
+ const gchar *addr_client_1 = "233.252.0.1:5000";
+
+ const gchar *transport_client_2 = transport_client_1;
+ const gchar *expected_transport_2 = expected_transport_1;
+ const gchar *addr_client_2 = addr_client_1;
+
+ mcast_transport_two_clients (TRUE, transport_client_1,
+ expected_transport_1, addr_client_1, transport_client_2,
+ expected_transport_2, addr_client_2);
+}
+
+GST_END_TEST;
+
+/* test if two multicast clients get the different transport settings: the first client
+ * requests the specific transport configuration while the second client lets
+ * the server select the multicast address and the ports.
+ * CASE: media is shared */
+GST_START_TEST
+ (test_client_multicast_two_clients_first_specific_transport_shared_media) {
+ const gchar *transport_client_1 = "RTP/AVP;multicast;destination=233.252.0.1;"
+ "ttl=1;port=5000-5001;mode=\"PLAY\"";
+ const gchar *expected_transport_1 = transport_client_1;
+ const gchar *addr_client_1 = "233.252.0.1:5000";
+
+ const gchar *transport_client_2 = "RTP/AVP;multicast;mode=\"PLAY\"";
+ const gchar *expected_transport_2 = expected_transport_1;
+ const gchar *addr_client_2 = addr_client_1;
+
+ mcast_transport_two_clients (TRUE, transport_client_1,
+ expected_transport_1, addr_client_1, transport_client_2,
+ expected_transport_2, addr_client_2);
+}
+
+GST_END_TEST;
+/* test if two multicast clients get the different transport settings: the first client lets
+ * the server select the multicast address and the ports while the second client requests
+ * the specific transport configuration.
+ * CASE: media is shared */
+GST_START_TEST
+ (test_client_multicast_two_clients_second_specific_transport_shared_media) {
+ const gchar *transport_client_1 = "RTP/AVP;multicast;mode=\"PLAY\"";
+ const gchar *expected_transport_1 =
+ "RTP/AVP;multicast;destination=233.252.0.1;"
+ "ttl=1;port=5000-5001;mode=\"PLAY\"";
+ const gchar *addr_client_1 = "233.252.0.1:5000";
+
+ const gchar *transport_client_2 = "RTP/AVP;multicast;destination=233.252.0.2;"
+ "ttl=2;port=5004-5005;mode=\"PLAY\"";
+ const gchar *expected_transport_2 = transport_client_2;
+ const gchar *addr_client_2 = "233.252.0.2:5004";
+
+ mcast_transport_two_clients (TRUE, transport_client_1,
+ expected_transport_1, addr_client_1, transport_client_2,
+ expected_transport_2, addr_client_2);
+}
+
+GST_END_TEST;
+
+/* test if the maximum ttl multicast value is chosen by the server
+ * CASE: the first client provides the highest ttl value */
+GST_START_TEST (test_client_multicast_max_ttl_first_client)
+{
+ const gchar *transport_client_1 = "RTP/AVP;multicast;destination=233.252.0.1;"
+ "ttl=3;port=5000-5001;mode=\"PLAY\"";
+ const gchar *expected_transport_1 = transport_client_1;
+ const gchar *addr_client_1 = "233.252.0.1:5000";
+
+ const gchar *transport_client_2 = "RTP/AVP;multicast;destination=233.252.0.2;"
+ "ttl=1;port=5002-5003;mode=\"PLAY\"";
+ const gchar *expected_transport_2 =
+ "RTP/AVP;multicast;destination=233.252.0.2;"
+ "ttl=3;port=5002-5003;mode=\"PLAY\"";
+ const gchar *addr_client_2 = "233.252.0.2:5002";
+
+ mcast_transport_two_clients (TRUE, transport_client_1,
+ expected_transport_1, addr_client_1, transport_client_2,
+ expected_transport_2, addr_client_2);
+}
+
+GST_END_TEST;
+
+/* test if the maximum ttl multicast value is chosen by the server
+ * CASE: the second client provides the highest ttl value */
+GST_START_TEST (test_client_multicast_max_ttl_second_client)
+{
+ const gchar *transport_client_1 = "RTP/AVP;multicast;destination=233.252.0.1;"
+ "ttl=2;port=5000-5001;mode=\"PLAY\"";
+ const gchar *expected_transport_1 = transport_client_1;
+ const gchar *addr_client_1 = "233.252.0.1:5000";
+
+ const gchar *transport_client_2 = "RTP/AVP;multicast;destination=233.252.0.2;"
+ "ttl=4;port=5002-5003;mode=\"PLAY\"";
+ const gchar *expected_transport_2 = transport_client_2;
+ const gchar *addr_client_2 = "233.252.0.2:5002";
+
+ mcast_transport_two_clients (TRUE, transport_client_1,
+ expected_transport_1, addr_client_1, transport_client_2,
+ expected_transport_2, addr_client_2);
+}
+
+GST_END_TEST;
+GST_START_TEST (test_client_multicast_invalid_ttl)
+{
+ GstRTSPClient *client;
+ GstRTSPMessage request = { 0, };
+ gchar *str;
+ GstRTSPSessionPool *session_pool;
+ GstRTSPContext ctx = { NULL };
+
+ client = setup_multicast_client (3);
+
+ ctx.client = client;
+ ctx.auth = gst_rtsp_auth_new ();
+ ctx.token =
+ gst_rtsp_token_new (GST_RTSP_TOKEN_TRANSPORT_CLIENT_SETTINGS,
+ G_TYPE_BOOLEAN, TRUE, GST_RTSP_TOKEN_MEDIA_FACTORY_ROLE, G_TYPE_STRING,
+ "user", NULL);
+ gst_rtsp_context_push_current (&ctx);
+
+ /* simple SETUP with an invalid ttl=0 */
+ fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_SETUP,
+ "rtsp://localhost/test/stream=0") == GST_RTSP_OK);
+ str = g_strdup_printf ("%d", cseq);
+ gst_rtsp_message_take_header (&request, GST_RTSP_HDR_CSEQ, str);
+ gst_rtsp_message_add_header (&request, GST_RTSP_HDR_TRANSPORT,
+ "RTP/AVP;multicast;destination=233.252.0.1;ttl=0;port=5000-5001;");
+
+ gst_rtsp_client_set_send_func (client, test_setup_response_461, NULL, NULL);
+ fail_unless (gst_rtsp_client_handle_message (client,
+ &request) == GST_RTSP_OK);
+ gst_rtsp_message_unset (&request);
+
+ session_pool = gst_rtsp_client_get_session_pool (client);
+ fail_unless (session_pool != NULL);
+ fail_unless (gst_rtsp_session_pool_get_n_sessions (session_pool) == 0);
+ g_object_unref (session_pool);
+
+ teardown_client (client);
+ g_object_unref (ctx.auth);
+ gst_rtsp_token_unref (ctx.token);
+ gst_rtsp_context_pop_current (&ctx);
+}
+
+GST_END_TEST;
+