mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-06-06 15:38:53 +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_SOCKET NULL
|
||||||
#define UDP_DEFAULT_CLOSE_SOCKET TRUE
|
#define UDP_DEFAULT_CLOSE_SOCKET TRUE
|
||||||
|
#define UDP_DEFAULT_BIND_ADDRESS NULL
|
||||||
|
#define UDP_DEFAULT_BIND_PORT 0
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
PROP_0,
|
PROP_0,
|
||||||
PROP_SOCKET,
|
PROP_SOCKET,
|
||||||
PROP_SOCKET_V6,
|
PROP_SOCKET_V6,
|
||||||
PROP_CLOSE_SOCKET
|
PROP_CLOSE_SOCKET,
|
||||||
|
PROP_BIND_ADDRESS,
|
||||||
|
PROP_BIND_PORT
|
||||||
};
|
};
|
||||||
|
|
||||||
static void gst_dynudpsink_finalize (GObject * object);
|
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",
|
"Close socket if passed as property on state change",
|
||||||
UDP_DEFAULT_CLOSE_SOCKET,
|
UDP_DEFAULT_CLOSE_SOCKET,
|
||||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
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_element_class_add_pad_template (gstelement_class,
|
||||||
gst_static_pad_template_get (&sink_template));
|
gst_static_pad_template_get (&sink_template));
|
||||||
|
@ -148,6 +160,8 @@ gst_dynudpsink_init (GstDynUDPSink * sink)
|
||||||
sink->socket_v6 = UDP_DEFAULT_SOCKET;
|
sink->socket_v6 = UDP_DEFAULT_SOCKET;
|
||||||
sink->close_socket = UDP_DEFAULT_CLOSE_SOCKET;
|
sink->close_socket = UDP_DEFAULT_CLOSE_SOCKET;
|
||||||
sink->external_socket = FALSE;
|
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 = NULL;
|
||||||
sink->used_socket_v6 = NULL;
|
sink->used_socket_v6 = NULL;
|
||||||
|
@ -181,6 +195,9 @@ gst_dynudpsink_finalize (GObject * object)
|
||||||
g_object_unref (sink->used_socket_v6);
|
g_object_unref (sink->used_socket_v6);
|
||||||
sink->used_socket_v6 = NULL;
|
sink->used_socket_v6 = NULL;
|
||||||
|
|
||||||
|
g_free (sink->bind_address);
|
||||||
|
sink->bind_address = NULL;
|
||||||
|
|
||||||
G_OBJECT_CLASS (parent_class)->finalize (object);
|
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -306,6 +323,13 @@ gst_dynudpsink_set_property (GObject * object, guint prop_id,
|
||||||
case PROP_CLOSE_SOCKET:
|
case PROP_CLOSE_SOCKET:
|
||||||
udpsink->close_socket = g_value_get_boolean (value);
|
udpsink->close_socket = g_value_get_boolean (value);
|
||||||
break;
|
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:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
break;
|
break;
|
||||||
|
@ -330,6 +354,12 @@ gst_dynudpsink_get_property (GObject * object, guint prop_id, GValue * value,
|
||||||
case PROP_CLOSE_SOCKET:
|
case PROP_CLOSE_SOCKET:
|
||||||
g_value_set_boolean (value, udpsink->close_socket);
|
g_value_set_boolean (value, udpsink->close_socket);
|
||||||
break;
|
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:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
break;
|
break;
|
||||||
|
@ -376,6 +406,42 @@ gst_dynudpsink_start (GstBaseSink * bsink)
|
||||||
GSocketAddress *bind_addr;
|
GSocketAddress *bind_addr;
|
||||||
GInetAddress *bind_iaddr;
|
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 */
|
/* create sender sockets if none available */
|
||||||
if ((udpsink->used_socket = g_socket_new (G_SOCKET_FAMILY_IPV4,
|
if ((udpsink->used_socket = g_socket_new (G_SOCKET_FAMILY_IPV4,
|
||||||
G_SOCKET_TYPE_DATAGRAM, G_SOCKET_PROTOCOL_UDP, &err)) == NULL)
|
G_SOCKET_TYPE_DATAGRAM, G_SOCKET_PROTOCOL_UDP, &err)) == NULL)
|
||||||
|
@ -390,7 +456,8 @@ gst_dynudpsink_start (GstBaseSink * bsink)
|
||||||
goto bind_error;
|
goto bind_error;
|
||||||
|
|
||||||
if ((udpsink->used_socket_v6 = g_socket_new (G_SOCKET_FAMILY_IPV6,
|
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",
|
GST_INFO_OBJECT (udpsink, "Failed to create IPv6 socket: %s",
|
||||||
err->message);
|
err->message);
|
||||||
g_clear_error (&err);
|
g_clear_error (&err);
|
||||||
|
@ -404,6 +471,7 @@ gst_dynudpsink_start (GstBaseSink * bsink)
|
||||||
goto bind_error;
|
goto bind_error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (udpsink->used_socket)
|
if (udpsink->used_socket)
|
||||||
g_socket_set_broadcast (udpsink->used_socket, TRUE);
|
g_socket_set_broadcast (udpsink->used_socket, TRUE);
|
||||||
|
@ -427,6 +495,14 @@ bind_error:
|
||||||
g_clear_error (&err);
|
g_clear_error (&err);
|
||||||
return FALSE;
|
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 *
|
static GstStructure *
|
||||||
|
|
|
@ -46,6 +46,8 @@ struct _GstDynUDPSink {
|
||||||
/* properties */
|
/* properties */
|
||||||
GSocket *socket, *socket_v6;
|
GSocket *socket, *socket_v6;
|
||||||
gboolean close_socket;
|
gboolean close_socket;
|
||||||
|
gchar *bind_address;
|
||||||
|
gint bind_port;
|
||||||
|
|
||||||
/* the socket in use */
|
/* the socket in use */
|
||||||
GSocket *used_socket, *used_socket_v6;
|
GSocket *used_socket, *used_socket_v6;
|
||||||
|
|
|
@ -92,6 +92,8 @@ enum
|
||||||
#define DEFAULT_QOS_DSCP -1
|
#define DEFAULT_QOS_DSCP -1
|
||||||
#define DEFAULT_SEND_DUPLICATES TRUE
|
#define DEFAULT_SEND_DUPLICATES TRUE
|
||||||
#define DEFAULT_BUFFER_SIZE 0
|
#define DEFAULT_BUFFER_SIZE 0
|
||||||
|
#define DEFAULT_BIND_ADDRESS NULL
|
||||||
|
#define DEFAULT_BIND_PORT 0
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
|
@ -113,6 +115,8 @@ enum
|
||||||
PROP_QOS_DSCP,
|
PROP_QOS_DSCP,
|
||||||
PROP_SEND_DUPLICATES,
|
PROP_SEND_DUPLICATES,
|
||||||
PROP_BUFFER_SIZE,
|
PROP_BUFFER_SIZE,
|
||||||
|
PROP_BIND_ADDRESS,
|
||||||
|
PROP_BIND_PORT,
|
||||||
PROP_LAST
|
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,
|
"Size of the kernel send buffer in bytes, 0=default", 0, G_MAXINT,
|
||||||
DEFAULT_BUFFER_SIZE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
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_element_class_add_pad_template (gstelement_class,
|
||||||
gst_static_pad_template_get (&sink_template));
|
gst_static_pad_template_get (&sink_template));
|
||||||
|
|
||||||
|
@ -493,7 +506,12 @@ gst_multiudpsink_finalize (GObject * object)
|
||||||
sink->multi_iface = NULL;
|
sink->multi_iface = NULL;
|
||||||
|
|
||||||
g_free (sink->vec);
|
g_free (sink->vec);
|
||||||
|
sink->vec = NULL;
|
||||||
g_free (sink->map);
|
g_free (sink->map);
|
||||||
|
sink->map = NULL;
|
||||||
|
|
||||||
|
g_free (sink->bind_address);
|
||||||
|
sink->bind_address = NULL;
|
||||||
|
|
||||||
g_mutex_clear (&sink->client_lock);
|
g_mutex_clear (&sink->client_lock);
|
||||||
|
|
||||||
|
@ -799,6 +817,13 @@ gst_multiudpsink_set_property (GObject * object, guint prop_id,
|
||||||
case PROP_BUFFER_SIZE:
|
case PROP_BUFFER_SIZE:
|
||||||
udpsink->buffer_size = g_value_get_int (value);
|
udpsink->buffer_size = g_value_get_int (value);
|
||||||
break;
|
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:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
break;
|
break;
|
||||||
|
@ -866,6 +891,12 @@ gst_multiudpsink_get_property (GObject * object, guint prop_id, GValue * value,
|
||||||
case PROP_BUFFER_SIZE:
|
case PROP_BUFFER_SIZE:
|
||||||
g_value_set_int (value, udpsink->buffer_size);
|
g_value_set_int (value, udpsink->buffer_size);
|
||||||
break;
|
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:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
break;
|
break;
|
||||||
|
@ -973,6 +1004,42 @@ gst_multiudpsink_start (GstBaseSink * bsink)
|
||||||
GSocketAddress *bind_addr;
|
GSocketAddress *bind_addr;
|
||||||
GInetAddress *bind_iaddr;
|
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 */
|
/* create sender sockets if none available */
|
||||||
if ((sink->used_socket = g_socket_new (G_SOCKET_FAMILY_IPV4,
|
if ((sink->used_socket = g_socket_new (G_SOCKET_FAMILY_IPV4,
|
||||||
G_SOCKET_TYPE_DATAGRAM, G_SOCKET_PROTOCOL_UDP, &err)) == NULL)
|
G_SOCKET_TYPE_DATAGRAM, G_SOCKET_PROTOCOL_UDP, &err)) == NULL)
|
||||||
|
@ -987,8 +1054,10 @@ gst_multiudpsink_start (GstBaseSink * bsink)
|
||||||
goto bind_error;
|
goto bind_error;
|
||||||
|
|
||||||
if ((sink->used_socket_v6 = g_socket_new (G_SOCKET_FAMILY_IPV6,
|
if ((sink->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,
|
||||||
GST_INFO_OBJECT (sink, "Failed to create IPv6 socket: %s", err->message);
|
&err)) == NULL) {
|
||||||
|
GST_INFO_OBJECT (sink, "Failed to create IPv6 socket: %s",
|
||||||
|
err->message);
|
||||||
g_clear_error (&err);
|
g_clear_error (&err);
|
||||||
} else {
|
} else {
|
||||||
bind_iaddr = g_inet_address_new_any (G_SOCKET_FAMILY_IPV6);
|
bind_iaddr = g_inet_address_new_any (G_SOCKET_FAMILY_IPV6);
|
||||||
|
@ -1000,6 +1069,7 @@ gst_multiudpsink_start (GstBaseSink * bsink)
|
||||||
goto bind_error;
|
goto bind_error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
#ifdef SO_SNDBUF
|
#ifdef SO_SNDBUF
|
||||||
{
|
{
|
||||||
socklen_t len;
|
socklen_t len;
|
||||||
|
@ -1098,6 +1168,14 @@ bind_error:
|
||||||
g_clear_error (&err);
|
g_clear_error (&err);
|
||||||
return FALSE;
|
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
|
static gboolean
|
||||||
|
|
|
@ -83,6 +83,8 @@ struct _GstMultiUDPSink {
|
||||||
|
|
||||||
gboolean send_duplicates;
|
gboolean send_duplicates;
|
||||||
gint buffer_size;
|
gint buffer_size;
|
||||||
|
gchar *bind_address;
|
||||||
|
gint bind_port;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _GstMultiUDPSinkClass {
|
struct _GstMultiUDPSinkClass {
|
||||||
|
|
Loading…
Reference in a new issue