mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-11 18:05:37 +00:00
(dyn|multi)udpsink: Add properties to specify the bind address and port
By default we use the any addresses and a random port for binding the socket.
This commit is contained in:
parent
5b79b8ff3c
commit
e26b8c2832
4 changed files with 194 additions and 36 deletions
|
@ -54,13 +54,17 @@ enum
|
|||
|
||||
#define UDP_DEFAULT_SOCKET NULL
|
||||
#define UDP_DEFAULT_CLOSE_SOCKET TRUE
|
||||
#define UDP_DEFAULT_BIND_ADDRESS NULL
|
||||
#define UDP_DEFAULT_BIND_PORT 0
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_SOCKET,
|
||||
PROP_SOCKET_V6,
|
||||
PROP_CLOSE_SOCKET
|
||||
PROP_CLOSE_SOCKET,
|
||||
PROP_BIND_ADDRESS,
|
||||
PROP_BIND_PORT
|
||||
};
|
||||
|
||||
static void gst_dynudpsink_finalize (GObject * object);
|
||||
|
@ -121,6 +125,14 @@ gst_dynudpsink_class_init (GstDynUDPSinkClass * klass)
|
|||
"Close socket if passed as property on state change",
|
||||
UDP_DEFAULT_CLOSE_SOCKET,
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
g_object_class_install_property (gobject_class, PROP_BIND_ADDRESS,
|
||||
g_param_spec_string ("bind-address", "Bind Address",
|
||||
"Address to bind the socket to", UDP_DEFAULT_BIND_ADDRESS,
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
g_object_class_install_property (gobject_class, PROP_BIND_PORT,
|
||||
g_param_spec_int ("bind-port", "Bind Port",
|
||||
"Port to bind the socket to", 0, G_MAXUINT16,
|
||||
UDP_DEFAULT_BIND_PORT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
gst_element_class_add_pad_template (gstelement_class,
|
||||
gst_static_pad_template_get (&sink_template));
|
||||
|
@ -148,6 +160,8 @@ gst_dynudpsink_init (GstDynUDPSink * sink)
|
|||
sink->socket_v6 = UDP_DEFAULT_SOCKET;
|
||||
sink->close_socket = UDP_DEFAULT_CLOSE_SOCKET;
|
||||
sink->external_socket = FALSE;
|
||||
sink->bind_address = UDP_DEFAULT_BIND_ADDRESS;
|
||||
sink->bind_port = UDP_DEFAULT_BIND_PORT;
|
||||
|
||||
sink->used_socket = NULL;
|
||||
sink->used_socket_v6 = NULL;
|
||||
|
@ -181,6 +195,9 @@ gst_dynudpsink_finalize (GObject * object)
|
|||
g_object_unref (sink->used_socket_v6);
|
||||
sink->used_socket_v6 = NULL;
|
||||
|
||||
g_free (sink->bind_address);
|
||||
sink->bind_address = NULL;
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
|
@ -306,6 +323,13 @@ gst_dynudpsink_set_property (GObject * object, guint prop_id,
|
|||
case PROP_CLOSE_SOCKET:
|
||||
udpsink->close_socket = g_value_get_boolean (value);
|
||||
break;
|
||||
case PROP_BIND_ADDRESS:
|
||||
g_free (udpsink->bind_address);
|
||||
udpsink->bind_address = g_value_dup_string (value);
|
||||
break;
|
||||
case PROP_BIND_PORT:
|
||||
udpsink->bind_port = g_value_get_int (value);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
|
@ -330,6 +354,12 @@ gst_dynudpsink_get_property (GObject * object, guint prop_id, GValue * value,
|
|||
case PROP_CLOSE_SOCKET:
|
||||
g_value_set_boolean (value, udpsink->close_socket);
|
||||
break;
|
||||
case PROP_BIND_ADDRESS:
|
||||
g_value_set_string (value, udpsink->bind_address);
|
||||
break;
|
||||
case PROP_BIND_PORT:
|
||||
g_value_set_int (value, udpsink->bind_port);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
|
@ -376,6 +406,42 @@ gst_dynudpsink_start (GstBaseSink * bsink)
|
|||
GSocketAddress *bind_addr;
|
||||
GInetAddress *bind_iaddr;
|
||||
|
||||
if (udpsink->bind_address) {
|
||||
GSocketFamily family;
|
||||
|
||||
bind_iaddr = g_inet_address_new_from_string (udpsink->bind_address);
|
||||
if (!bind_iaddr) {
|
||||
GList *results;
|
||||
GResolver *resolver;
|
||||
|
||||
resolver = g_resolver_get_default ();
|
||||
results =
|
||||
g_resolver_lookup_by_name (resolver, udpsink->bind_address,
|
||||
udpsink->cancellable, &err);
|
||||
if (!results) {
|
||||
g_object_unref (resolver);
|
||||
goto name_resolve;
|
||||
}
|
||||
bind_iaddr = G_INET_ADDRESS (g_object_ref (results->data));
|
||||
g_resolver_free_addresses (results);
|
||||
g_object_unref (resolver);
|
||||
}
|
||||
|
||||
bind_addr = g_inet_socket_address_new (bind_iaddr, udpsink->bind_port);
|
||||
g_object_unref (bind_iaddr);
|
||||
family = g_socket_address_get_family (G_SOCKET_ADDRESS (bind_addr));
|
||||
|
||||
if ((udpsink->used_socket =
|
||||
g_socket_new (family, G_SOCKET_TYPE_DATAGRAM,
|
||||
G_SOCKET_PROTOCOL_UDP, &err)) == NULL) {
|
||||
g_object_unref (bind_addr);
|
||||
goto no_socket;
|
||||
}
|
||||
|
||||
g_socket_bind (udpsink->used_socket, bind_addr, TRUE, &err);
|
||||
if (err != NULL)
|
||||
goto bind_error;
|
||||
} else {
|
||||
/* create sender sockets if none available */
|
||||
if ((udpsink->used_socket = g_socket_new (G_SOCKET_FAMILY_IPV4,
|
||||
G_SOCKET_TYPE_DATAGRAM, G_SOCKET_PROTOCOL_UDP, &err)) == NULL)
|
||||
|
@ -390,7 +456,8 @@ gst_dynudpsink_start (GstBaseSink * bsink)
|
|||
goto bind_error;
|
||||
|
||||
if ((udpsink->used_socket_v6 = g_socket_new (G_SOCKET_FAMILY_IPV6,
|
||||
G_SOCKET_TYPE_DATAGRAM, G_SOCKET_PROTOCOL_UDP, &err)) == NULL) {
|
||||
G_SOCKET_TYPE_DATAGRAM, G_SOCKET_PROTOCOL_UDP,
|
||||
&err)) == NULL) {
|
||||
GST_INFO_OBJECT (udpsink, "Failed to create IPv6 socket: %s",
|
||||
err->message);
|
||||
g_clear_error (&err);
|
||||
|
@ -404,6 +471,7 @@ gst_dynudpsink_start (GstBaseSink * bsink)
|
|||
goto bind_error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (udpsink->used_socket)
|
||||
g_socket_set_broadcast (udpsink->used_socket, TRUE);
|
||||
|
@ -427,6 +495,14 @@ bind_error:
|
|||
g_clear_error (&err);
|
||||
return FALSE;
|
||||
}
|
||||
name_resolve:
|
||||
{
|
||||
GST_ELEMENT_ERROR (udpsink, RESOURCE, FAILED, (NULL),
|
||||
("Failed to resolve bind address %s: %s", udpsink->bind_address,
|
||||
err->message));
|
||||
g_clear_error (&err);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static GstStructure *
|
||||
|
|
|
@ -46,6 +46,8 @@ struct _GstDynUDPSink {
|
|||
/* properties */
|
||||
GSocket *socket, *socket_v6;
|
||||
gboolean close_socket;
|
||||
gchar *bind_address;
|
||||
gint bind_port;
|
||||
|
||||
/* the socket in use */
|
||||
GSocket *used_socket, *used_socket_v6;
|
||||
|
|
|
@ -92,6 +92,8 @@ enum
|
|||
#define DEFAULT_QOS_DSCP -1
|
||||
#define DEFAULT_SEND_DUPLICATES TRUE
|
||||
#define DEFAULT_BUFFER_SIZE 0
|
||||
#define DEFAULT_BIND_ADDRESS NULL
|
||||
#define DEFAULT_BIND_PORT 0
|
||||
|
||||
enum
|
||||
{
|
||||
|
@ -113,6 +115,8 @@ enum
|
|||
PROP_QOS_DSCP,
|
||||
PROP_SEND_DUPLICATES,
|
||||
PROP_BUFFER_SIZE,
|
||||
PROP_BIND_ADDRESS,
|
||||
PROP_BIND_PORT,
|
||||
PROP_LAST
|
||||
};
|
||||
|
||||
|
@ -340,6 +344,15 @@ gst_multiudpsink_class_init (GstMultiUDPSinkClass * klass)
|
|||
"Size of the kernel send buffer in bytes, 0=default", 0, G_MAXINT,
|
||||
DEFAULT_BUFFER_SIZE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_property (gobject_class, PROP_BIND_ADDRESS,
|
||||
g_param_spec_string ("bind-address", "Bind Address",
|
||||
"Address to bind the socket to", DEFAULT_BIND_ADDRESS,
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
g_object_class_install_property (gobject_class, PROP_BIND_PORT,
|
||||
g_param_spec_int ("bind-port", "Bind Port",
|
||||
"Port to bind the socket to", 0, G_MAXUINT16,
|
||||
DEFAULT_BIND_PORT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
gst_element_class_add_pad_template (gstelement_class,
|
||||
gst_static_pad_template_get (&sink_template));
|
||||
|
||||
|
@ -493,7 +506,12 @@ gst_multiudpsink_finalize (GObject * object)
|
|||
sink->multi_iface = NULL;
|
||||
|
||||
g_free (sink->vec);
|
||||
sink->vec = NULL;
|
||||
g_free (sink->map);
|
||||
sink->map = NULL;
|
||||
|
||||
g_free (sink->bind_address);
|
||||
sink->bind_address = NULL;
|
||||
|
||||
g_mutex_clear (&sink->client_lock);
|
||||
|
||||
|
@ -799,6 +817,13 @@ gst_multiudpsink_set_property (GObject * object, guint prop_id,
|
|||
case PROP_BUFFER_SIZE:
|
||||
udpsink->buffer_size = g_value_get_int (value);
|
||||
break;
|
||||
case PROP_BIND_ADDRESS:
|
||||
g_free (udpsink->bind_address);
|
||||
udpsink->bind_address = g_value_dup_string (value);
|
||||
break;
|
||||
case PROP_BIND_PORT:
|
||||
udpsink->bind_port = g_value_get_int (value);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
|
@ -866,6 +891,12 @@ gst_multiudpsink_get_property (GObject * object, guint prop_id, GValue * value,
|
|||
case PROP_BUFFER_SIZE:
|
||||
g_value_set_int (value, udpsink->buffer_size);
|
||||
break;
|
||||
case PROP_BIND_ADDRESS:
|
||||
g_value_set_string (value, udpsink->bind_address);
|
||||
break;
|
||||
case PROP_BIND_PORT:
|
||||
g_value_set_int (value, udpsink->bind_port);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
|
@ -973,6 +1004,42 @@ gst_multiudpsink_start (GstBaseSink * bsink)
|
|||
GSocketAddress *bind_addr;
|
||||
GInetAddress *bind_iaddr;
|
||||
|
||||
if (sink->bind_address) {
|
||||
GSocketFamily family;
|
||||
|
||||
bind_iaddr = g_inet_address_new_from_string (sink->bind_address);
|
||||
if (!bind_iaddr) {
|
||||
GList *results;
|
||||
GResolver *resolver;
|
||||
|
||||
resolver = g_resolver_get_default ();
|
||||
results =
|
||||
g_resolver_lookup_by_name (resolver, sink->bind_address,
|
||||
sink->cancellable, &err);
|
||||
if (!results) {
|
||||
g_object_unref (resolver);
|
||||
goto name_resolve;
|
||||
}
|
||||
bind_iaddr = G_INET_ADDRESS (g_object_ref (results->data));
|
||||
g_resolver_free_addresses (results);
|
||||
g_object_unref (resolver);
|
||||
}
|
||||
|
||||
bind_addr = g_inet_socket_address_new (bind_iaddr, sink->bind_port);
|
||||
g_object_unref (bind_iaddr);
|
||||
family = g_socket_address_get_family (G_SOCKET_ADDRESS (bind_addr));
|
||||
|
||||
if ((sink->used_socket =
|
||||
g_socket_new (family, G_SOCKET_TYPE_DATAGRAM,
|
||||
G_SOCKET_PROTOCOL_UDP, &err)) == NULL) {
|
||||
g_object_unref (bind_addr);
|
||||
goto no_socket;
|
||||
}
|
||||
|
||||
g_socket_bind (sink->used_socket, bind_addr, TRUE, &err);
|
||||
if (err != NULL)
|
||||
goto bind_error;
|
||||
} else {
|
||||
/* create sender sockets if none available */
|
||||
if ((sink->used_socket = g_socket_new (G_SOCKET_FAMILY_IPV4,
|
||||
G_SOCKET_TYPE_DATAGRAM, G_SOCKET_PROTOCOL_UDP, &err)) == NULL)
|
||||
|
@ -987,8 +1054,10 @@ gst_multiudpsink_start (GstBaseSink * bsink)
|
|||
goto bind_error;
|
||||
|
||||
if ((sink->used_socket_v6 = g_socket_new (G_SOCKET_FAMILY_IPV6,
|
||||
G_SOCKET_TYPE_DATAGRAM, G_SOCKET_PROTOCOL_UDP, &err)) == NULL) {
|
||||
GST_INFO_OBJECT (sink, "Failed to create IPv6 socket: %s", err->message);
|
||||
G_SOCKET_TYPE_DATAGRAM, G_SOCKET_PROTOCOL_UDP,
|
||||
&err)) == NULL) {
|
||||
GST_INFO_OBJECT (sink, "Failed to create IPv6 socket: %s",
|
||||
err->message);
|
||||
g_clear_error (&err);
|
||||
} else {
|
||||
bind_iaddr = g_inet_address_new_any (G_SOCKET_FAMILY_IPV6);
|
||||
|
@ -1000,6 +1069,7 @@ gst_multiudpsink_start (GstBaseSink * bsink)
|
|||
goto bind_error;
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef SO_SNDBUF
|
||||
{
|
||||
socklen_t len;
|
||||
|
@ -1098,6 +1168,14 @@ bind_error:
|
|||
g_clear_error (&err);
|
||||
return FALSE;
|
||||
}
|
||||
name_resolve:
|
||||
{
|
||||
GST_ELEMENT_ERROR (sink, RESOURCE, FAILED, (NULL),
|
||||
("Failed to resolve bind address %s: %s", sink->bind_address,
|
||||
err->message));
|
||||
g_clear_error (&err);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
|
|
|
@ -83,6 +83,8 @@ struct _GstMultiUDPSink {
|
|||
|
||||
gboolean send_duplicates;
|
||||
gint buffer_size;
|
||||
gchar *bind_address;
|
||||
gint bind_port;
|
||||
};
|
||||
|
||||
struct _GstMultiUDPSinkClass {
|
||||
|
|
Loading…
Reference in a new issue