rtspstream: handle both ipv4 and ipv6 clients

Fixes https://bugzilla.gnome.org/show_bug.cgi?id=701129
This commit is contained in:
Alexander Schrab 2013-05-30 08:07:48 +02:00 committed by Wim Taymans
parent 17b07d1c0e
commit 3e119be829
3 changed files with 116 additions and 49 deletions

View file

@ -1133,6 +1133,8 @@ make_server_transport (GstRTSPClient * client, GstRTSPClientState * state,
GstRTSPTransport * ct) GstRTSPTransport * ct)
{ {
GstRTSPTransport *st; GstRTSPTransport *st;
GInetAddress *addr;
GSocketFamily family;
/* prepare the server transport */ /* prepare the server transport */
gst_rtsp_transport_new (&st); gst_rtsp_transport_new (&st);
@ -1141,10 +1143,22 @@ make_server_transport (GstRTSPClient * client, GstRTSPClientState * state,
st->profile = ct->profile; st->profile = ct->profile;
st->lower_transport = ct->lower_transport; st->lower_transport = ct->lower_transport;
addr = g_inet_address_new_from_string (ct->destination);
if (!addr) {
GST_ERROR ("failed to get inet addr from client destination");
family = G_SOCKET_FAMILY_IPV4;
} else {
family = g_inet_address_get_family (addr);
g_object_unref (addr);
addr = NULL;
}
switch (st->lower_transport) { switch (st->lower_transport) {
case GST_RTSP_LOWER_TRANS_UDP: case GST_RTSP_LOWER_TRANS_UDP:
st->client_port = ct->client_port; st->client_port = ct->client_port;
gst_rtsp_stream_get_server_port (state->stream, &st->server_port); gst_rtsp_stream_get_server_port (state->stream, &st->server_port,
family);
break; break;
case GST_RTSP_LOWER_TRANS_UDP_MCAST: case GST_RTSP_LOWER_TRANS_UDP_MCAST:
st->port = ct->port; st->port = ct->port;

View file

@ -36,7 +36,6 @@ struct _GstRTSPStreamPrivate
guint idx; guint idx;
GstPad *srcpad; GstPad *srcpad;
GstElement *payloader; GstElement *payloader;
gboolean is_ipv6;
guint buffer_size; guint buffer_size;
gboolean is_joined; gboolean is_joined;
@ -48,10 +47,16 @@ struct _GstRTSPStreamPrivate
/* the RTPSession object */ /* the RTPSession object */
GObject *session; GObject *session;
/* sinks used for sending and receiving RTP and RTCP, they share /* sinks used for sending and receiving RTP and RTCP over ipv4, they share
* sockets */ * sockets */
GstElement *udpsrc[2]; GstElement *udpsrc_v4[2];
/* sinks used for sending and receiving RTP and RTCP over ipv6, they share
* sockets */
GstElement *udpsrc_v6[2];
GstElement *udpsink[2]; GstElement *udpsink[2];
/* for TCP transport */ /* for TCP transport */
GstElement *appsrc[2]; GstElement *appsrc[2];
GstElement *appqueue[2]; GstElement *appqueue[2];
@ -60,9 +65,13 @@ struct _GstRTSPStreamPrivate
GstElement *tee[2]; GstElement *tee[2];
GstElement *funnel[2]; GstElement *funnel[2];
/* server ports for sending/receiving */ /* server ports for sending/receiving over ipv4 */
GstRTSPRange server_port; GstRTSPRange server_port_v4;
GstRTSPAddress *server_addr; GstRTSPAddress *server_addr_v4;
/* server ports for sending/receiving over ipv6 */
GstRTSPRange server_port_v6;
GstRTSPAddress *server_addr_v6;
/* multicast addresses */ /* multicast addresses */
GstRTSPAddressPool *pool; GstRTSPAddressPool *pool;
@ -137,8 +146,10 @@ gst_rtsp_stream_finalize (GObject * obj)
if (priv->addr) if (priv->addr)
gst_rtsp_address_free (priv->addr); gst_rtsp_address_free (priv->addr);
if (priv->server_addr) if (priv->server_addr_v4)
gst_rtsp_address_free (priv->server_addr); gst_rtsp_address_free (priv->server_addr_v4);
if (priv->server_addr_v6)
gst_rtsp_address_free (priv->server_addr_v6);
if (priv->pool) if (priv->pool)
g_object_unref (priv->pool); g_object_unref (priv->pool);
gst_object_unref (priv->payloader); gst_object_unref (priv->payloader);
@ -428,11 +439,12 @@ different_address:
} }
} }
/* must be called with lock */
static gboolean static gboolean
alloc_ports (GstRTSPStream * stream) alloc_ports_one_family (GstRTSPAddressPool * pool, gint buffer_size,
GSocketFamily family, GstElement * udpsrc_out[2],
GstElement * udpsink_out[2], GstRTSPRange * server_port_out,
GstRTSPAddress ** server_addr_out)
{ {
GstRTSPStreamPrivate *priv = stream->priv;
GstStateChangeReturn ret; GstStateChangeReturn ret;
GstElement *udpsrc0, *udpsrc1; GstElement *udpsrc0, *udpsrc1;
GstElement *udpsink0, *udpsink1; GstElement *udpsink0, *udpsink1;
@ -443,10 +455,14 @@ alloc_ports (GstRTSPStream * stream)
gint rtpport, rtcpport; gint rtpport, rtcpport;
GList *rejected_addresses = NULL; GList *rejected_addresses = NULL;
GstRTSPAddress *addr = NULL; GstRTSPAddress *addr = NULL;
GSocketFamily family;
GInetAddress *inetaddr = NULL; GInetAddress *inetaddr = NULL;
GSocketAddress *rtp_sockaddr = NULL; GSocketAddress *rtp_sockaddr = NULL;
GSocketAddress *rtcp_sockaddr = NULL; GSocketAddress *rtcp_sockaddr = NULL;
const gchar *multisink_socket = "socket";
if (family == G_SOCKET_FAMILY_IPV6) {
multisink_socket = "socket-v6";
}
udpsrc0 = NULL; udpsrc0 = NULL;
udpsrc1 = NULL; udpsrc1 = NULL;
@ -457,19 +473,13 @@ alloc_ports (GstRTSPStream * stream)
/* Start with random port */ /* Start with random port */
tmp_rtp = 0; tmp_rtp = 0;
if (priv->is_ipv6) {
family = G_SOCKET_FAMILY_IPV6;
} else {
family = G_SOCKET_FAMILY_IPV4;
}
rtcp_socket = g_socket_new (family, G_SOCKET_TYPE_DATAGRAM, rtcp_socket = g_socket_new (family, G_SOCKET_TYPE_DATAGRAM,
G_SOCKET_PROTOCOL_UDP, NULL); G_SOCKET_PROTOCOL_UDP, NULL);
if (!rtcp_socket) if (!rtcp_socket)
goto no_udp_protocol; goto no_udp_protocol;
if (priv->server_addr) if (*server_addr_out)
gst_rtsp_address_free (priv->server_addr); gst_rtsp_address_free (*server_addr_out);
/* try to allocate 2 UDP ports, the RTP port should be an even /* try to allocate 2 UDP ports, the RTP port should be an even
* number and the RTCP port should be the next (uneven) port */ * number and the RTCP port should be the next (uneven) port */
@ -482,19 +492,19 @@ again:
goto no_udp_protocol; goto no_udp_protocol;
} }
if (priv->pool && gst_rtsp_address_pool_has_unicast_addresses (priv->pool)) { if (pool && gst_rtsp_address_pool_has_unicast_addresses (pool)) {
GstRTSPAddressFlags flags; GstRTSPAddressFlags flags;
if (addr) if (addr)
rejected_addresses = g_list_prepend (rejected_addresses, addr); rejected_addresses = g_list_prepend (rejected_addresses, addr);
flags = GST_RTSP_ADDRESS_FLAG_EVEN_PORT | GST_RTSP_ADDRESS_FLAG_UNICAST; flags = GST_RTSP_ADDRESS_FLAG_EVEN_PORT | GST_RTSP_ADDRESS_FLAG_UNICAST;
if (priv->is_ipv6) if (family == G_SOCKET_FAMILY_IPV6)
flags |= GST_RTSP_ADDRESS_FLAG_IPV6; flags |= GST_RTSP_ADDRESS_FLAG_IPV6;
else else
flags |= GST_RTSP_ADDRESS_FLAG_IPV4; flags |= GST_RTSP_ADDRESS_FLAG_IPV4;
addr = gst_rtsp_address_pool_acquire_address (priv->pool, flags, 2); addr = gst_rtsp_address_pool_acquire_address (pool, flags, 2);
if (addr == NULL) if (addr == NULL)
goto no_ports; goto no_ports;
@ -576,23 +586,31 @@ again:
if (rtpport != tmp_rtp || rtcpport != tmp_rtcp) if (rtpport != tmp_rtp || rtcpport != tmp_rtcp)
goto port_error; goto port_error;
udpsink0 = gst_element_factory_make ("multiudpsink", NULL); if (udpsink_out[0])
udpsink0 = udpsink_out[0];
else
udpsink0 = gst_element_factory_make ("multiudpsink", NULL);
if (!udpsink0) if (!udpsink0)
goto no_udp_protocol; goto no_udp_protocol;
g_object_set (G_OBJECT (udpsink0), "close-socket", FALSE, NULL); g_object_set (G_OBJECT (udpsink0), "close-socket", FALSE, NULL);
g_object_set (G_OBJECT (udpsink0), "socket", rtp_socket, NULL); g_object_set (G_OBJECT (udpsink0), multisink_socket, rtp_socket, NULL);
if (udpsink_out[1])
udpsink1 = udpsink_out[1];
else
udpsink1 = gst_element_factory_make ("multiudpsink", NULL);
udpsink1 = gst_element_factory_make ("multiudpsink", NULL);
if (!udpsink1) if (!udpsink1)
goto no_udp_protocol; goto no_udp_protocol;
g_object_set (G_OBJECT (udpsink0), "send-duplicates", FALSE, NULL); g_object_set (G_OBJECT (udpsink0), "send-duplicates", FALSE, NULL);
g_object_set (G_OBJECT (udpsink1), "send-duplicates", FALSE, NULL); g_object_set (G_OBJECT (udpsink1), "send-duplicates", FALSE, NULL);
g_object_set (G_OBJECT (udpsink0), "buffer-size", priv->buffer_size, NULL); g_object_set (G_OBJECT (udpsink0), "buffer-size", buffer_size, NULL);
g_object_set (G_OBJECT (udpsink1), "close-socket", FALSE, NULL); g_object_set (G_OBJECT (udpsink1), "close-socket", FALSE, NULL);
g_object_set (G_OBJECT (udpsink1), "socket", rtcp_socket, NULL); g_object_set (G_OBJECT (udpsink1), multisink_socket, rtcp_socket, NULL);
g_object_set (G_OBJECT (udpsink1), "sync", FALSE, NULL); g_object_set (G_OBJECT (udpsink1), "sync", FALSE, NULL);
g_object_set (G_OBJECT (udpsink1), "async", FALSE, NULL); g_object_set (G_OBJECT (udpsink1), "async", FALSE, NULL);
g_object_set (G_OBJECT (udpsink0), "auto-multicast", FALSE, NULL); g_object_set (G_OBJECT (udpsink0), "auto-multicast", FALSE, NULL);
@ -602,14 +620,14 @@ again:
/* we keep these elements, we will further configure them when the /* we keep these elements, we will further configure them when the
* client told us to really use the UDP ports. */ * client told us to really use the UDP ports. */
priv->udpsrc[0] = udpsrc0; udpsrc_out[0] = udpsrc0;
priv->udpsrc[1] = udpsrc1; udpsrc_out[1] = udpsrc1;
priv->udpsink[0] = udpsink0; udpsink_out[0] = udpsink0;
priv->udpsink[1] = udpsink1; udpsink_out[1] = udpsink1;
priv->server_port.min = rtpport; server_port_out->min = rtpport;
priv->server_port.max = rtcpport; server_port_out->max = rtcpport;
priv->server_addr = addr; *server_addr_out = addr;
g_list_free_full (rejected_addresses, (GDestroyNotify) gst_rtsp_address_free); g_list_free_full (rejected_addresses, (GDestroyNotify) gst_rtsp_address_free);
g_object_unref (rtp_socket); g_object_unref (rtp_socket);
@ -670,6 +688,20 @@ cleanup:
} }
} }
/* must be called with lock */
static gboolean
alloc_ports (GstRTSPStream * stream)
{
GstRTSPStreamPrivate *priv = stream->priv;
return alloc_ports_one_family (priv->pool, priv->buffer_size,
G_SOCKET_FAMILY_IPV4, priv->udpsrc_v4, priv->udpsink,
&priv->server_port_v4, &priv->server_addr_v4) &&
alloc_ports_one_family (priv->pool, priv->buffer_size,
G_SOCKET_FAMILY_IPV6, priv->udpsrc_v6, priv->udpsink,
&priv->server_port_v6, &priv->server_addr_v6);
}
/** /**
* gst_rtsp_stream_get_server_port: * gst_rtsp_stream_get_server_port:
* @stream: a #GstRTSPStream * @stream: a #GstRTSPStream
@ -680,7 +712,7 @@ cleanup:
*/ */
void void
gst_rtsp_stream_get_server_port (GstRTSPStream * stream, gst_rtsp_stream_get_server_port (GstRTSPStream * stream,
GstRTSPRange * server_port) GstRTSPRange * server_port, GSocketFamily family)
{ {
GstRTSPStreamPrivate *priv; GstRTSPStreamPrivate *priv;
@ -689,8 +721,13 @@ gst_rtsp_stream_get_server_port (GstRTSPStream * stream,
g_return_if_fail (priv->is_joined); g_return_if_fail (priv->is_joined);
g_mutex_lock (&priv->lock); g_mutex_lock (&priv->lock);
if (server_port) if (family == G_SOCKET_FAMILY_IPV4) {
*server_port = priv->server_port; if (server_port)
*server_port = priv->server_port_v4;
} else {
if (server_port)
*server_port = priv->server_port_v6;
}
g_mutex_unlock (&priv->lock); g_mutex_unlock (&priv->lock);
} }
@ -1104,13 +1141,23 @@ gst_rtsp_stream_join_bin (GstRTSPStream * stream, GstBin * bin,
/* we set and keep these to playing so that they don't cause NO_PREROLL return /* we set and keep these to playing so that they don't cause NO_PREROLL return
* values */ * values */
gst_element_set_state (priv->udpsrc[i], GST_STATE_PLAYING); gst_element_set_state (priv->udpsrc_v4[i], GST_STATE_PLAYING);
gst_element_set_locked_state (priv->udpsrc[i], TRUE); gst_element_set_state (priv->udpsrc_v6[i], GST_STATE_PLAYING);
gst_element_set_locked_state (priv->udpsrc_v4[i], TRUE);
gst_element_set_locked_state (priv->udpsrc_v6[i], TRUE);
/* add udpsrc */ /* add udpsrc */
gst_bin_add (bin, priv->udpsrc[i]); gst_bin_add (bin, priv->udpsrc_v4[i]);
/* and link to the funnel */ gst_bin_add (bin, priv->udpsrc_v6[i]);
/* and link to the funnel v4 */
selpad = gst_element_get_request_pad (priv->funnel[i], "sink_%u"); selpad = gst_element_get_request_pad (priv->funnel[i], "sink_%u");
pad = gst_element_get_static_pad (priv->udpsrc[i], "src"); pad = gst_element_get_static_pad (priv->udpsrc_v4[i], "src");
gst_pad_link (pad, selpad);
gst_object_unref (pad);
gst_object_unref (selpad);
/* and link to the funnel v6 */
selpad = gst_element_get_request_pad (priv->funnel[i], "sink_%u");
pad = gst_element_get_static_pad (priv->udpsrc_v6[i], "src");
gst_pad_link (pad, selpad); gst_pad_link (pad, selpad);
gst_object_unref (pad); gst_object_unref (pad);
gst_object_unref (selpad); gst_object_unref (selpad);
@ -1213,12 +1260,15 @@ gst_rtsp_stream_leave_bin (GstRTSPStream * stream, GstBin * bin,
gst_element_set_state (priv->funnel[i], GST_STATE_NULL); gst_element_set_state (priv->funnel[i], GST_STATE_NULL);
gst_element_set_state (priv->appsrc[i], GST_STATE_NULL); gst_element_set_state (priv->appsrc[i], GST_STATE_NULL);
/* and set udpsrc to NULL now before removing */ /* and set udpsrc to NULL now before removing */
gst_element_set_locked_state (priv->udpsrc[i], FALSE); gst_element_set_locked_state (priv->udpsrc_v4[i], FALSE);
gst_element_set_state (priv->udpsrc[i], GST_STATE_NULL); gst_element_set_state (priv->udpsrc_v4[i], GST_STATE_NULL);
gst_element_set_locked_state (priv->udpsrc_v6[i], FALSE);
gst_element_set_state (priv->udpsrc_v6[i], GST_STATE_NULL);
/* removing them should also nicely release the request /* removing them should also nicely release the request
* pads when they finalize */ * pads when they finalize */
gst_bin_remove (bin, priv->udpsrc[i]); gst_bin_remove (bin, priv->udpsrc_v4[i]);
gst_bin_remove (bin, priv->udpsrc_v6[i]);
gst_bin_remove (bin, priv->udpsink[i]); gst_bin_remove (bin, priv->udpsink[i]);
gst_bin_remove (bin, priv->appsrc[i]); gst_bin_remove (bin, priv->appsrc[i]);
gst_bin_remove (bin, priv->appsink[i]); gst_bin_remove (bin, priv->appsink[i]);
@ -1230,7 +1280,8 @@ gst_rtsp_stream_leave_bin (GstRTSPStream * stream, GstBin * bin,
gst_object_unref (priv->recv_sink[i]); gst_object_unref (priv->recv_sink[i]);
priv->recv_sink[i] = NULL; priv->recv_sink[i] = NULL;
priv->udpsrc[i] = NULL; priv->udpsrc_v4[i] = NULL;
priv->udpsrc_v6[i] = NULL;
priv->udpsink[i] = NULL; priv->udpsink[i] = NULL;
priv->appsrc[i] = NULL; priv->appsrc[i] = NULL;
priv->appsink[i] = NULL; priv->appsink[i] = NULL;

View file

@ -20,6 +20,7 @@
#include <gst/gst.h> #include <gst/gst.h>
#include <gst/rtsp/gstrtsprange.h> #include <gst/rtsp/gstrtsprange.h>
#include <gst/rtsp/gstrtspurl.h> #include <gst/rtsp/gstrtspurl.h>
#include <gio/gio.h>
#ifndef __GST_RTSP_STREAM_H__ #ifndef __GST_RTSP_STREAM_H__
#define __GST_RTSP_STREAM_H__ #define __GST_RTSP_STREAM_H__
@ -88,7 +89,8 @@ gboolean gst_rtsp_stream_leave_bin (GstRTSPStream *stream,
GstBin *bin, GstElement *rtpbin); GstBin *bin, GstElement *rtpbin);
void gst_rtsp_stream_get_server_port (GstRTSPStream *stream, void gst_rtsp_stream_get_server_port (GstRTSPStream *stream,
GstRTSPRange *server_port); GstRTSPRange *server_port,
GSocketFamily family);
void gst_rtsp_stream_get_ssrc (GstRTSPStream *stream, void gst_rtsp_stream_get_ssrc (GstRTSPStream *stream,
guint *ssrc); guint *ssrc);