ct->ttl = addr->ttl;
gst_rtsp_address_free (addr);
}
+
+ if (!gst_rtsp_stream_add_multicast_client_address (ctx->stream,
+ ct->destination, ct->port.min, ct->port.max, family))
+ goto error_mcast_transport;
+
} else {
GstRTSPUrl *url;
GST_ERROR_OBJECT (client, "Failed to get UDP socket");
return FALSE;
}
+error_mcast_transport:
+ {
+ GST_ERROR_OBJECT (client, "Failed to add multicast client transport");
+ return FALSE;
+ }
}
static GstRTSPTransport *
GstElement *mcast_udpsink[2];
GSocket *mcast_socket_v4[2];
GSocket *mcast_socket_v6[2];
+ GList *mcast_clients;
/* for TCP transport */
GstElement *appsrc[2];
(GDestroyNotify) gst_caps_unref);
}
+typedef struct _UdpClientAddrInfo UdpClientAddrInfo;
+
+struct _UdpClientAddrInfo
+{
+ gchar *address;
+ guint rtp_port;
+ guint add_count; /* how often this address has been added */
+};
+
+static void
+free_mcast_client (gpointer data)
+{
+ UdpClientAddrInfo *client = data;
+
+ g_free (client->address);
+ g_free (client);
+}
+
static void
gst_rtsp_stream_finalize (GObject * obj)
{
}
g_free (priv->multicast_iface);
+ g_list_free_full (priv->mcast_clients, (GDestroyNotify) free_mcast_client);
gst_object_unref (priv->payloader);
if (priv->srcpad)
}
}
+/* must be called with lock */
+static gboolean
+add_mcast_client_addr (GstRTSPStream * stream, const gchar * destination,
+ guint rtp_port, guint rtcp_port)
+{
+ GstRTSPStreamPrivate *priv;
+ GList *walk;
+ UdpClientAddrInfo *client;
+ GInetAddress *inet;
+
+ priv = stream->priv;
+
+ if (destination == NULL)
+ return FALSE;
+
+ inet = g_inet_address_new_from_string (destination);
+ if (inet == NULL)
+ goto invalid_address;
+
+ if (!g_inet_address_get_is_multicast (inet)) {
+ g_object_unref (inet);
+ goto invalid_address;
+ }
+ g_object_unref (inet);
+
+ for (walk = priv->mcast_clients; walk; walk = g_list_next (walk)) {
+ UdpClientAddrInfo *cli = walk->data;
+
+ if ((g_strcmp0 (cli->address, destination) == 0) &&
+ (cli->rtp_port == rtp_port)) {
+ GST_DEBUG ("requested destination already exists: %s:%u-%u",
+ destination, rtp_port, rtcp_port);
+ cli->add_count++;
+ return TRUE;
+ }
+ }
+
+ client = g_new0 (UdpClientAddrInfo, 1);
+ client->address = g_strdup (destination);
+ client->rtp_port = rtp_port;
+ client->add_count = 1;
+ priv->mcast_clients = g_list_prepend (priv->mcast_clients, client);
+
+ GST_DEBUG ("added mcast client %s:%u-%u", destination, rtp_port, rtcp_port);
+
+ return TRUE;
+
+invalid_address:
+ {
+ GST_WARNING_OBJECT (stream, "Multicast address is invalid: %s",
+ destination);
+ return FALSE;
+ }
+}
+
+/* must be called with lock */
+static gboolean
+remove_mcast_client_addr (GstRTSPStream * stream, const gchar * destination,
+ guint rtp_port, guint rtcp_port)
+{
+ GstRTSPStreamPrivate *priv;
+ GList *walk;
+
+ priv = stream->priv;
+
+ if (destination == NULL)
+ goto no_destination;
+
+ for (walk = priv->mcast_clients; walk; walk = g_list_next (walk)) {
+ UdpClientAddrInfo *cli = walk->data;
+
+ if ((g_strcmp0 (cli->address, destination) == 0) &&
+ (cli->rtp_port == rtp_port)) {
+ cli->add_count--;
+
+ if (!cli->add_count) {
+ priv->mcast_clients = g_list_remove (priv->mcast_clients, cli);
+ free_mcast_client (cli);
+ }
+ return TRUE;
+ }
+ }
+
+ GST_WARNING_OBJECT (stream, "Address not found");
+ return FALSE;
+
+no_destination:
+ {
+ GST_WARNING_OBJECT (stream, "No destination has been provided");
+ return FALSE;
+ }
+}
+
+
/**
* gst_rtsp_stream_allocate_udp_sockets:
* @stream: a #GstRTSPStream
}
static gboolean
-check_mcast_part_for_transport (GstRTSPStream * stream,
- const GstRTSPTransport * tr)
+check_mcast_client_addr (GstRTSPStream * stream, const GstRTSPTransport * tr)
{
GstRTSPStreamPrivate *priv = stream->priv;
- GInetAddress *inetaddr;
- GSocketFamily family;
- GstRTSPAddress *mcast_addr;
+ GList *walk;
- /* Check if it's a ipv4 or ipv6 transport */
- inetaddr = g_inet_address_new_from_string (tr->destination);
- family = g_inet_address_get_family (inetaddr);
- g_object_unref (inetaddr);
+ if (priv->mcast_clients == NULL)
+ goto no_addr;
- /* Select fields corresponding to the family */
- if (family == G_SOCKET_FAMILY_IPV4) {
- mcast_addr = priv->mcast_addr_v4;
- } else {
- mcast_addr = priv->mcast_addr_v6;
- }
+ if (tr == NULL)
+ goto no_transport;
- /* We support only one mcast group per family, make sure this transport
- * matches it. */
- if (!mcast_addr)
- goto no_addr;
+ if (tr->destination == NULL)
+ goto no_destination;
- if (g_ascii_strcasecmp (tr->destination, mcast_addr->address) != 0 ||
- tr->port.min != mcast_addr->port ||
- tr->port.max != mcast_addr->port + mcast_addr->n_ports - 1 ||
- tr->ttl != mcast_addr->ttl)
- goto wrong_addr;
+ for (walk = priv->mcast_clients; walk; walk = g_list_next (walk)) {
+ UdpClientAddrInfo *cli = walk->data;
- return TRUE;
+ if ((g_strcmp0 (cli->address, tr->destination) == 0) &&
+ (cli->rtp_port == tr->port.min))
+ return TRUE;
+ }
+
+ return FALSE;
no_addr:
{
"has been reserved");
return FALSE;
}
-wrong_addr:
+no_transport:
+ {
+ GST_WARNING_OBJECT (stream, "Adding mcast transport, but no transport "
+ "has been provided");
+ return FALSE;
+ }
+no_destination:
{
GST_WARNING_OBJECT (stream, "Adding mcast transport, but it doesn't match "
"the reserved address");
if (add) {
GST_INFO ("adding %s:%d-%d", dest, min, max);
- if (!check_mcast_part_for_transport (stream, tr))
+ if (!check_mcast_client_addr (stream, tr))
goto mcast_error;
+ add_client (priv->mcast_udpsink[0], priv->mcast_udpsink[1], dest, min,
+ max);
if (tr->ttl > 0) {
GST_INFO ("setting ttl-mc %d", tr->ttl);
g_object_set (G_OBJECT (priv->mcast_udpsink[1]), "ttl-mc", tr->ttl,
NULL);
}
- add_client (priv->mcast_udpsink[0], priv->mcast_udpsink[1], dest, min,
- max);
priv->transports = g_list_prepend (priv->transports, trans);
} else {
GST_INFO ("removing %s:%d-%d", dest, min, max);
+ if (!remove_mcast_client_addr (stream, dest, min, max))
+ GST_WARNING_OBJECT (stream,
+ "Failed to remove multicast address: %s:%d-%d", dest, min, max);
remove_client (priv->mcast_udpsink[0], priv->mcast_udpsink[1], dest,
min, max);
priv->transports = g_list_remove (priv->transports, trans);
}
/**
+ * gst_rtsp_stream_add_multicast_client_address:
+ * @stream: a #GstRTSPStream
+ * @destination: (transfer none): a multicast address to add
+ * @rtp_port: RTP port
+ * @rtcp_port: RTCP port
+ * @family: socket family
+ *
+ * Add multicast client address to stream. At this point, the sockets that
+ * will stream RTP and RTCP data to @destination are supposed to be
+ * allocated.
+ *
+ * Returns: %TRUE if @destination can be addedd and handled by @stream.
+ */
+gboolean
+gst_rtsp_stream_add_multicast_client_address (GstRTSPStream * stream,
+ const gchar * destination, guint rtp_port, guint rtcp_port,
+ GSocketFamily family)
+{
+ GstRTSPStreamPrivate *priv;
+
+ g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE);
+ g_return_val_if_fail (destination != NULL, FALSE);
+
+ priv = stream->priv;
+ g_mutex_lock (&priv->lock);
+ if ((family == G_SOCKET_FAMILY_IPV4) && (priv->mcast_socket_v4[0] == NULL))
+ goto socket_error;
+ else if ((family == G_SOCKET_FAMILY_IPV6) &&
+ (priv->mcast_socket_v6[0] == NULL))
+ goto socket_error;
+
+ if (!add_mcast_client_addr (stream, destination, rtp_port, rtcp_port))
+ goto add_addr_error;
+ g_mutex_unlock (&priv->lock);
+
+ return TRUE;
+
+socket_error:
+ {
+ GST_WARNING_OBJECT (stream,
+ "Failed to add multicast address: no udp socket");
+ g_mutex_unlock (&priv->lock);
+ return FALSE;
+ }
+add_addr_error:
+ {
+ GST_WARNING_OBJECT (stream,
+ "Failed to add multicast address: invalid address");
+ g_mutex_unlock (&priv->lock);
+ return FALSE;
+ }
+}
+
+/**
+ * gst_rtsp_stream_get_multicast_client_addresses
+ * @stream: a #GstRTSPStream
+ *
+ * Get all multicast client addresses that RTP data will be sent to
+ *
+ * Returns: A comma separated list of host:port pairs with destinations
+ */
+gchar *
+gst_rtsp_stream_get_multicast_client_addresses (GstRTSPStream * stream)
+{
+ GstRTSPStreamPrivate *priv;
+ GString *str;
+ GList *clients;
+
+ g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), NULL);
+
+ priv = stream->priv;
+ str = g_string_new ("");
+
+ g_mutex_lock (&priv->lock);
+ clients = priv->mcast_clients;
+ while (clients != NULL) {
+ UdpClientAddrInfo *client;
+
+ client = (UdpClientAddrInfo *) clients->data;
+ clients = g_list_next (clients);
+ g_string_append_printf (str, "%s:%d%s", client->address, client->rtp_port,
+ (clients != NULL ? "," : ""));
+ }
+ g_mutex_unlock (&priv->lock);
+
+ return g_string_free (str, FALSE);
+}
+
+/**
* gst_rtsp_stream_set_seqnum:
* @stream: a #GstRTSPStream
* @seqnum: a new sequence number
GSocketFamily family);
GST_RTSP_SERVER_API
+gboolean gst_rtsp_stream_add_multicast_client_address (GstRTSPStream * stream,
+ const gchar * destination,
+ guint rtp_port,
+ guint rtcp_port,
+ GSocketFamily family);
+
+GST_RTSP_SERVER_API
+gchar * gst_rtsp_stream_get_multicast_client_addresses (GstRTSPStream * stream);
+
+GST_RTSP_SERVER_API
gboolean gst_rtsp_stream_update_crypto (GstRTSPStream * stream,
guint ssrc, GstCaps * crypto);
GST_END_TEST;
static void
-mcast_transport_specific_two_clients (gboolean shared, const gchar * transport1,
- const gchar * expected_transport1, const gchar * transport2,
- const gchar * expected_transport2)
+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, };
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 ();
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 = session_id;
&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);
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_specific_two_clients (TRUE, transport_client_1,
- expected_transport_1, transport_client_2, expected_transport_2);
+ 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;
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_specific_two_clients (FALSE, transport_client_1,
- expected_transport_1, transport_client_2, expected_transport_2);
+ 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;
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_specific_two_clients (TRUE, transport_client_1,
- expected_transport_1, transport_client_2, expected_transport_2);
+ 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;
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_specific_two_clients (TRUE, transport_client_1,
- expected_transport_1, transport_client_2, expected_transport_2);
+ 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_client_multicast_transport_specific_two_clients_shared_media);
tcase_add_test (tc, test_client_multicast_transport_specific_two_clients);
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);
+ tcase_add_test (tc,
+ test_client_multicast_two_clients_first_specific_transport_shared_media);
+ tcase_add_test (tc,
+ test_client_multicast_two_clients_second_specific_transport_shared_media);
+ tcase_add_test (tc,
test_client_multicast_transport_specific_no_address_in_pool);
tcase_add_test (tc, test_client_multicast_max_ttl_first_client);
tcase_add_test (tc, test_client_multicast_max_ttl_second_client);
GST_END_TEST;
+static void
+check_multicast_client_address (const gchar * destination, guint port,
+ const gchar * expected_addr_str, gboolean expected_res)
+{
+ GstPad *srcpad;
+ GstElement *pay;
+ GstRTSPStream *stream;
+ GstBin *bin;
+ GstElement *rtpbin;
+ GstRTSPTransport *transport;
+ GstRTSPRange ports = { 0 };
+ gchar *addr_str = NULL;
+
+ srcpad = gst_pad_new ("testsrcpad", GST_PAD_SRC);
+ fail_unless (srcpad != NULL);
+ gst_pad_set_active (srcpad, TRUE);
+ pay = gst_element_factory_make ("rtpgstpay", "testpayloader");
+ fail_unless (pay != NULL);
+ stream = gst_rtsp_stream_new (0, pay, srcpad);
+ fail_unless (stream != NULL);
+ gst_object_unref (pay);
+ gst_object_unref (srcpad);
+ rtpbin = gst_element_factory_make ("rtpbin", "testrtpbin");
+ fail_unless (rtpbin != NULL);
+ bin = GST_BIN (gst_bin_new ("testbin"));
+ fail_unless (bin != NULL);
+ fail_unless (gst_bin_add (bin, rtpbin));
+
+ fail_unless (gst_rtsp_stream_join_bin (stream, bin, rtpbin, GST_STATE_NULL));
+
+ fail_unless (gst_rtsp_transport_new (&transport) == GST_RTSP_OK);
+ transport->lower_transport = GST_RTSP_LOWER_TRANS_UDP_MCAST;
+ transport->destination = g_strdup (destination);
+ transport->ttl = 1;
+ ports.min = port;
+ ports.max = port + 1;
+ transport->port = ports;
+
+ /* allocate ports */
+ fail_unless (gst_rtsp_stream_allocate_udp_sockets (stream,
+ G_SOCKET_FAMILY_IPV4, transport, TRUE) == expected_res);
+
+ fail_unless (gst_rtsp_stream_add_multicast_client_address (stream,
+ destination, ports.min, ports.max, G_SOCKET_FAMILY_IPV4) == expected_res);
+
+ fail_unless (gst_rtsp_stream_complete_stream (stream, transport) == expected_res);
+
+ fail_unless (gst_rtsp_transport_free (transport) == GST_RTSP_OK);
+ addr_str = gst_rtsp_stream_get_multicast_client_addresses (stream);
+
+ fail_unless (g_str_equal (addr_str, expected_addr_str));
+ g_free (addr_str);
+
+ fail_unless (gst_rtsp_stream_leave_bin (stream, bin, rtpbin));
+
+ gst_object_unref (bin);
+ gst_object_unref (stream);
+}
+
+/* test if the provided transport destination is correct.
+ * CASE: valid multicast address */
+GST_START_TEST (test_multicast_client_address)
+{
+ const gchar *addr = "233.252.0.1";
+ guint port = 50000;
+ const gchar *expected_addr_str = "233.252.0.1:50000";
+ gboolean expected_res = TRUE;
+
+ check_multicast_client_address (addr, port, expected_addr_str, expected_res);
+}
+
+GST_END_TEST;
+
+/* test if the provided transport destination is correct.
+ * CASE: invalid multicast address */
+GST_START_TEST (test_multicast_client_address_invalid)
+{
+ const gchar *addr = "1.2.3.4";
+ guint port = 50000;
+ const gchar *expected_addr_str = "";
+ gboolean expected_res = FALSE;
+
+ check_multicast_client_address (addr, port, expected_addr_str, expected_res);
+}
+
+GST_END_TEST;
+
static Suite *
rtspstream_suite (void)
{
tcase_add_test (tc, test_allocate_udp_ports_multicast);
tcase_add_test (tc, test_allocate_udp_ports_client_settings);
tcase_add_test (tc, test_tcp_transport);
+ tcase_add_test (tc, test_multicast_client_address);
+ tcase_add_test (tc, test_multicast_client_address_invalid);
return s;
}