mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-03-30 12:49:40 +00:00
stream: Added a list of multicast client addresses
When media is shared, the same media stream can be sent to multiple multicast groups. Currently, there is no API to retrieve multicast addresses from the stream. When calling gst_rtsp_stream_get_multicast_address() function, only the first multicast address is returned. With this patch, each multicast destination requested in SETUP will be stored in an internal list (call to gst_rtsp_stream_add_multicast_client_address()). The list of multicast groups requested by the clients can be retrieved by calling gst_rtsp_stream_get_multicast_client_addresses(). There still exist some problems with the current implementation in the multicast case: 1) The receiving part is currently only configured with regard to the first multicast client (see https://bugzilla.gnome.org/show_bug.cgi?id=796917). 2) Secondly, of security reasons, some constraints should be put on the requested multicast destinations (see https://bugzilla.gnome.org/show_bug.cgi?id=796916). Change-Id: I6b060746e472a0734cc2fd828ffe4ea2956733ea https://bugzilla.gnome.org/show_bug.cgi?id=793441
This commit is contained in:
parent
4c6cecf5d6
commit
cbe6ae3c48
5 changed files with 486 additions and 41 deletions
|
@ -2030,6 +2030,11 @@ default_configure_client_transport (GstRTSPClient * client,
|
|||
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;
|
||||
|
||||
|
@ -2103,6 +2108,11 @@ no_socket:
|
|||
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 *
|
||||
|
|
|
@ -110,6 +110,7 @@ struct _GstRTSPStreamPrivate
|
|||
GstElement *mcast_udpsink[2];
|
||||
GSocket *mcast_socket_v4[2];
|
||||
GSocket *mcast_socket_v6[2];
|
||||
GList *mcast_clients;
|
||||
|
||||
/* for TCP transport */
|
||||
GstElement *appsrc[2];
|
||||
|
@ -292,6 +293,24 @@ gst_rtsp_stream_init (GstRTSPStream * stream)
|
|||
(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)
|
||||
{
|
||||
|
@ -338,6 +357,7 @@ 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)
|
||||
|
@ -1585,6 +1605,100 @@ cleanup:
|
|||
}
|
||||
}
|
||||
|
||||
/* 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
|
||||
|
@ -3368,38 +3482,29 @@ udpsrc_error:
|
|||
}
|
||||
|
||||
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);
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* We support only one mcast group per family, make sure this transport
|
||||
* matches it. */
|
||||
if (!mcast_addr)
|
||||
if (priv->mcast_clients == NULL)
|
||||
goto no_addr;
|
||||
|
||||
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;
|
||||
if (tr == NULL)
|
||||
goto no_transport;
|
||||
|
||||
return TRUE;
|
||||
if (tr->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, tr->destination) == 0) &&
|
||||
(cli->rtp_port == tr->port.min))
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
|
||||
no_addr:
|
||||
{
|
||||
|
@ -3407,7 +3512,13 @@ 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");
|
||||
|
@ -4084,8 +4195,10 @@ update_transport (GstRTSPStream * stream, GstRTSPStreamTransport * trans,
|
|||
|
||||
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);
|
||||
|
@ -4096,11 +4209,12 @@ update_transport (GstRTSPStream * stream, GstRTSPStreamTransport * trans,
|
|||
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);
|
||||
|
@ -4450,6 +4564,95 @@ gst_rtsp_stream_get_rtcp_multicast_socket (GstRTSPStream * stream,
|
|||
return socket;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
|
|
@ -233,6 +233,16 @@ GST_RTSP_SERVER_API
|
|||
GSocket * gst_rtsp_stream_get_rtcp_multicast_socket (GstRTSPStream *stream,
|
||||
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);
|
||||
|
|
|
@ -980,9 +980,10 @@ GST_START_TEST (test_client_sdp_with_no_bitrate_tags)
|
|||
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, };
|
||||
|
@ -995,6 +996,7 @@ mcast_transport_specific_two_clients (gboolean shared, const gchar * transport1,
|
|||
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 ();
|
||||
|
@ -1054,6 +1056,13 @@ mcast_transport_specific_two_clients (gboolean shared, const gchar * transport1,
|
|||
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;
|
||||
|
||||
|
@ -1099,6 +1108,22 @@ mcast_transport_specific_two_clients (gboolean shared, const gchar * transport1,
|
|||
&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);
|
||||
|
||||
|
@ -1126,13 +1151,16 @@ GST_START_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_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;
|
||||
|
@ -1144,13 +1172,105 @@ 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_specific_two_clients (FALSE, transport_client_1,
|
||||
expected_transport_1, transport_client_2, expected_transport_2);
|
||||
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;
|
||||
|
@ -1162,15 +1282,18 @@ 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_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;
|
||||
|
@ -1182,13 +1305,16 @@ 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_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;
|
||||
|
@ -1259,6 +1385,13 @@ 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);
|
||||
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);
|
||||
|
|
|
@ -486,6 +486,93 @@ GST_START_TEST (test_tcp_transport)
|
|||
|
||||
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)
|
||||
{
|
||||
|
@ -501,6 +588,8 @@ 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;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue