/* server ports for sending/receiving */
GstRTSPRange server_port;
+ GstRTSPAddress *server_addr;
/* multicast addresses */
GstRTSPAddressPool *pool;
if (priv->addr)
gst_rtsp_address_free (priv->addr);
+ if (priv->server_addr)
+ gst_rtsp_address_free (priv->server_addr);
if (priv->pool)
g_object_unref (priv->pool);
gst_object_unref (priv->payloader);
GstStateChangeReturn ret;
GstElement *udpsrc0, *udpsrc1;
GstElement *udpsink0, *udpsink1;
+ GSocket *rtp_socket = NULL;
+ GSocket *rtcp_socket;
gint tmp_rtp, tmp_rtcp;
guint count;
gint rtpport, rtcpport;
- GSocket *socket;
- const gchar *host;
+ GList *rejected_addresses = NULL;
+ GstRTSPAddress *addr = NULL;
+ GSocketFamily family;
+ GInetAddress *inetaddr = NULL;
+ GSocketAddress *rtp_sockaddr = NULL;
+ GSocketAddress *rtcp_sockaddr = NULL;
udpsrc0 = NULL;
udpsrc1 = NULL;
/* Start with random port */
tmp_rtp = 0;
- if (priv->is_ipv6)
- host = "udp://[::0]";
- else
- host = "udp://0.0.0.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,
+ G_SOCKET_PROTOCOL_UDP, NULL);
+ if (!rtcp_socket)
+ goto no_udp_protocol;
+
+ if (priv->server_addr)
+ gst_rtsp_address_free (priv->server_addr);
/* try to allocate 2 UDP ports, the RTP port should be an even
* number and the RTCP port should be the next (uneven) port */
again:
- udpsrc0 = gst_element_make_from_uri (GST_URI_SRC, host, NULL, NULL);
- if (udpsrc0 == NULL)
- goto no_udp_protocol;
- g_object_set (G_OBJECT (udpsrc0), "port", tmp_rtp, NULL);
- ret = gst_element_set_state (udpsrc0, GST_STATE_PAUSED);
- if (ret == GST_STATE_CHANGE_FAILURE) {
+ if (rtp_socket == NULL) {
+ rtp_socket = g_socket_new (family, G_SOCKET_TYPE_DATAGRAM,
+ G_SOCKET_PROTOCOL_UDP, NULL);
+ if (!rtp_socket)
+ goto no_udp_protocol;
+ }
+
+ if (priv->pool && gst_rtsp_address_pool_has_unicast_addresses (priv->pool)) {
+ GstRTSPAddressFlags flags;
+
+ if (addr)
+ rejected_addresses = g_list_prepend (rejected_addresses, addr);
+
+ flags = GST_RTSP_ADDRESS_FLAG_EVEN_PORT | GST_RTSP_ADDRESS_FLAG_UNICAST;
+ if (priv->is_ipv6)
+ flags |= GST_RTSP_ADDRESS_FLAG_IPV6;
+ else
+ flags |= GST_RTSP_ADDRESS_FLAG_IPV4;
+
+ addr = gst_rtsp_address_pool_acquire_address (priv->pool, flags, 2);
+
+ if (addr == NULL)
+ goto no_ports;
+
+ tmp_rtp = addr->port;
+
+ g_clear_object (&inetaddr);
+ inetaddr = g_inet_address_new_from_string (addr->address);
+ } else {
if (tmp_rtp != 0) {
tmp_rtp += 2;
if (++count > 20)
goto no_ports;
+ }
- gst_element_set_state (udpsrc0, GST_STATE_NULL);
- gst_object_unref (udpsrc0);
+ if (inetaddr == NULL)
+ inetaddr = g_inet_address_new_any (family);
+ }
- goto again;
- }
- goto no_udp_protocol;
+ rtp_sockaddr = g_inet_socket_address_new (inetaddr, tmp_rtp);
+ if (!g_socket_bind (rtp_socket, rtp_sockaddr, FALSE, NULL)) {
+ g_object_unref (rtp_sockaddr);
+ goto again;
}
+ g_object_unref (rtp_sockaddr);
- g_object_get (G_OBJECT (udpsrc0), "port", &tmp_rtp, NULL);
+ rtp_sockaddr = g_socket_get_local_address (rtp_socket, NULL);
+ if (rtp_sockaddr == NULL || !G_IS_INET_SOCKET_ADDRESS (rtp_sockaddr)) {
+ g_clear_object (&rtp_sockaddr);
+ goto socket_error;
+ }
+
+ tmp_rtp =
+ g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (rtp_sockaddr));
+ g_object_unref (rtp_sockaddr);
/* check if port is even */
if ((tmp_rtp & 1) != 0) {
/* port not even, close and allocate another */
- if (++count > 20)
- goto no_ports;
-
- gst_element_set_state (udpsrc0, GST_STATE_NULL);
- gst_object_unref (udpsrc0);
-
tmp_rtp++;
+ g_clear_object (&rtp_socket);
goto again;
}
- /* allocate port+1 for RTCP now */
- udpsrc1 = gst_element_make_from_uri (GST_URI_SRC, host, NULL, NULL);
- if (udpsrc1 == NULL)
- goto no_udp_rtcp_protocol;
-
/* set port */
tmp_rtcp = tmp_rtp + 1;
- g_object_set (G_OBJECT (udpsrc1), "port", tmp_rtcp, NULL);
- ret = gst_element_set_state (udpsrc1, GST_STATE_PAUSED);
- /* tmp_rtcp port is busy already : retry to make rtp/rtcp pair */
- if (ret == GST_STATE_CHANGE_FAILURE) {
+ rtcp_sockaddr = g_inet_socket_address_new (inetaddr, tmp_rtcp);
+ if (!g_socket_bind (rtcp_socket, rtcp_sockaddr, FALSE, NULL)) {
+ g_object_unref (rtcp_sockaddr);
+ g_clear_object (&rtp_socket);
+ goto again;
+ }
+ g_object_unref (rtcp_sockaddr);
- if (++count > 20)
- goto no_ports;
+ g_clear_object (&inetaddr);
- gst_element_set_state (udpsrc0, GST_STATE_NULL);
- gst_object_unref (udpsrc0);
+ udpsrc0 = gst_element_factory_make ("udpsrc", NULL);
+ udpsrc1 = gst_element_factory_make ("udpsrc", NULL);
- gst_element_set_state (udpsrc1, GST_STATE_NULL);
- gst_object_unref (udpsrc1);
+ if (udpsrc0 == NULL || udpsrc1 == NULL)
+ goto no_udp_protocol;
+
+ g_object_set (G_OBJECT (udpsrc0), "socket", rtp_socket, NULL);
+ g_object_set (G_OBJECT (udpsrc1), "socket", rtcp_socket, NULL);
+
+ ret = gst_element_set_state (udpsrc0, GST_STATE_PAUSED);
+ if (ret == GST_STATE_CHANGE_FAILURE)
+ goto element_error;
+ ret = gst_element_set_state (udpsrc1, GST_STATE_PAUSED);
+ if (ret == GST_STATE_CHANGE_FAILURE)
+ goto element_error;
- tmp_rtp += 2;
- goto again;
- }
/* all fine, do port check */
g_object_get (G_OBJECT (udpsrc0), "port", &rtpport, NULL);
g_object_get (G_OBJECT (udpsrc1), "port", &rtcpport, NULL);
if (!udpsink0)
goto no_udp_protocol;
- g_object_get (G_OBJECT (udpsrc0), "used-socket", &socket, NULL);
- g_object_set (G_OBJECT (udpsink0), "socket", socket, NULL);
- g_object_unref (socket);
g_object_set (G_OBJECT (udpsink0), "close-socket", FALSE, NULL);
+ g_object_set (G_OBJECT (udpsink0), "socket", rtp_socket, NULL);
udpsink1 = gst_element_factory_make ("multiudpsink", NULL);
if (!udpsink1)
g_object_set (G_OBJECT (udpsink1), "send-duplicates", FALSE, NULL);
g_object_set (G_OBJECT (udpsink0), "buffer-size", priv->buffer_size, NULL);
- g_object_get (G_OBJECT (udpsrc1), "used-socket", &socket, NULL);
- g_object_set (G_OBJECT (udpsink1), "socket", socket, NULL);
- g_object_unref (socket);
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), "sync", FALSE, NULL);
g_object_set (G_OBJECT (udpsink1), "async", FALSE, NULL);
g_object_set (G_OBJECT (udpsink0), "auto-multicast", FALSE, NULL);
priv->server_port.min = rtpport;
priv->server_port.max = rtcpport;
+ priv->server_addr = addr;
+ g_list_free_full (rejected_addresses, (GDestroyNotify) gst_rtsp_address_free);
+
+ g_object_unref (rtp_socket);
+ g_object_unref (rtcp_socket);
+
return TRUE;
/* ERRORS */
{
goto cleanup;
}
-no_udp_rtcp_protocol:
+port_error:
{
goto cleanup;
}
-port_error:
+socket_error:
+ {
+ goto cleanup;
+ }
+element_error:
{
goto cleanup;
}
gst_element_set_state (udpsink1, GST_STATE_NULL);
gst_object_unref (udpsink1);
}
+ if (inetaddr)
+ g_object_unref (inetaddr);
+ g_list_free_full (rejected_addresses,
+ (GDestroyNotify) gst_rtsp_address_free);
+ if (addr)
+ gst_rtsp_address_free (addr);
+ if (rtp_socket)
+ g_object_unref (rtp_socket);
+ if (rtcp_socket)
+ g_object_unref (rtcp_socket);
return FALSE;
}
}