GST_DEBUG_CATEGORY_STATIC (dynudpsink_debug);
#define GST_CAT_DEFAULT (dynudpsink_debug)
+#define CLOSE_IF_REQUESTED(udpctx) \
+ if ((!udpctx->externalfd) || (udpctx->externalfd && udpctx->closefd)) \
+ CLOSE_SOCKET(udpctx->sock); \
+ udpctx->sock = -1;
+
static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
LAST_SIGNAL
};
+#define UDP_DEFAULT_SOCKFD -1
+#define UDP_DEFAULT_CLOSEFD TRUE
+
enum
{
PROP_0,
- PROP_SOCKFD
- /* FILL ME */
+ PROP_SOCKFD,
+ PROP_CLOSEFD
};
static void gst_dynudpsink_base_init (gpointer g_class);
g_object_class_install_property (gobject_class, PROP_SOCKFD,
g_param_spec_int ("sockfd", "socket handle",
- "Socket to use for UDP reception.",
- 0, G_MAXINT16, 0, G_PARAM_READWRITE));
+ "Socket to use for UDP sending. (-1 == allocate)",
+ -1, G_MAXINT16, UDP_DEFAULT_SOCKFD, G_PARAM_READWRITE));
+ g_object_class_install_property (gobject_class, PROP_CLOSEFD,
+ g_param_spec_boolean ("closefd", "Close sockfd",
+ "Close sockfd if passed as property on state change",
+ UDP_DEFAULT_CLOSEFD, G_PARAM_READWRITE));
gstelement_class->change_state = gst_dynudpsink_change_state;
GST_DEBUG_CATEGORY_INIT (dynudpsink_debug, "dynudpsink", 0, "UDP sink");
}
-
static void
gst_dynudpsink_init (GstDynUDPSink * sink)
{
udpsink = GST_DYNUDPSINK (sink);
+ sink->sockfd = UDP_DEFAULT_SOCKFD;
+ sink->closefd = UDP_DEFAULT_CLOSEFD;
+ sink->externalfd = FALSE;
+
sink->sock = -1;
}
switch (prop_id) {
case PROP_SOCKFD:
- udpsink->sock = g_value_get_int (value);
- GST_DEBUG ("setting SOCKFD to %d", udpsink->sock);
+ udpsink->sockfd = g_value_get_int (value);
+ GST_DEBUG ("setting SOCKFD to %d", udpsink->sockfd);
+ break;
+ case PROP_CLOSEFD:
+ udpsink->closefd = g_value_get_boolean (value);
break;
default:
switch (prop_id) {
case PROP_SOCKFD:
- g_value_set_int (value, udpsink->sock);
+ g_value_set_int (value, udpsink->sockfd);
+ break;
+ case PROP_CLOSEFD:
+ g_value_set_boolean (value, udpsink->closefd);
break;
-
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
guint bc_val;
gint ret;
- if (sink->sock == -1) {
+ if (sink->sockfd == -1) {
/* create sender socket if none available */
-
if ((sink->sock = socket (AF_INET, SOCK_DGRAM, 0)) == -1)
goto no_socket;
setsockopt (sink->sock, SOL_SOCKET, SO_BROADCAST, &bc_val,
sizeof (bc_val))) < 0)
goto no_broadcast;
- }
+ sink->externalfd = TRUE;
+ } else {
+ sink->sock = sink->sockfd;
+ sink->externalfd = TRUE;
+ }
return TRUE;
/* ERRORS */
no_broadcast:
{
perror ("setsockopt");
+ CLOSE_IF_REQUESTED (sink);
return FALSE;
}
}
static void
gst_dynudpsink_close (GstDynUDPSink * sink)
{
- CLOSE_SOCKET (sink->sock);
+ if (sink->sock != -1)
+ CLOSE_IF_REQUESTED (sink);
}
static GstStateChangeReturn
* because it is blocked by a firewall.
* </para>
* <para>
- * Last reviewed on 2007-03-02 (0.10.6)
+ * A custom file descriptor can be configured with the
+ * <link linkend="GstUDPSrc--sockfd">sockfd property</link>. The socket will be
+ * closed when setting the element to READY by default. This behaviour can be
+ * overriden with the <link linkend="GstUDPSrc--closefd">closefd property</link>,
+ * in which case the application is responsible for closing the file descriptor.
+ * </para>
+ * <para>
+ * Last reviewed on 2007-03-29 (0.10.6)
* </para>
* </refsect2>
*/
res = read(READ_SOCKET(src), &command, 1); \
} G_STMT_END
+#define CLOSE_IF_REQUESTED(udpctx) \
+ if ((!udpctx->externalfd) || (udpctx->externalfd && udpctx->closefd)) \
+ CLOSE_SOCKET(udpctx->sock); \
+ udpctx->sock = -1;
+
static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
#define UDP_DEFAULT_BUFFER_SIZE 0
#define UDP_DEFAULT_TIMEOUT 0
#define UDP_DEFAULT_SKIP_FIRST_BYTES 0
+#define UDP_DEFAULT_CLOSEFD TRUE
enum
{
PROP_SOCKFD,
PROP_BUFFER_SIZE,
PROP_TIMEOUT,
- PROP_SKIP_FIRST_BYTES
+ PROP_SKIP_FIRST_BYTES,
+ PROP_CLOSEFD
};
static void gst_udpsrc_uri_handler_init (gpointer g_iface, gpointer iface_data);
PROP_SKIP_FIRST_BYTES, g_param_spec_int ("skip-first-bytes",
"Skip first bytes", "number of bytes to skip for each udp packet", 0,
G_MAXINT, UDP_DEFAULT_SKIP_FIRST_BYTES, G_PARAM_READWRITE));
+ g_object_class_install_property (gobject_class, PROP_CLOSEFD,
+ g_param_spec_boolean ("closefd", "Close sockfd",
+ "Close sockfd if passed as property on state change",
+ UDP_DEFAULT_CLOSEFD, G_PARAM_READWRITE));
gstbasesrc_class->start = gst_udpsrc_start;
gstbasesrc_class->stop = gst_udpsrc_stop;
gst_base_src_set_live (GST_BASE_SRC (udpsrc), TRUE);
udpsrc->port = UDP_DEFAULT_PORT;
- udpsrc->sock = UDP_DEFAULT_SOCKFD;
+ udpsrc->sockfd = UDP_DEFAULT_SOCKFD;
udpsrc->multi_group = g_strdup (UDP_DEFAULT_MULTICAST_GROUP);
udpsrc->uri = g_strdup (UDP_DEFAULT_URI);
udpsrc->buffer_size = UDP_DEFAULT_BUFFER_SIZE;
udpsrc->timeout = UDP_DEFAULT_TIMEOUT;
udpsrc->skip_first_bytes = UDP_DEFAULT_SKIP_FIRST_BYTES;
+ udpsrc->closefd = UDP_DEFAULT_CLOSEFD;
+ udpsrc->externalfd = (udpsrc->sockfd != -1);
+ udpsrc->sock = -1;
udpsrc->control_sock[0] = -1;
udpsrc->control_sock[1] = -1;
}
break;
}
case PROP_SOCKFD:
- udpsrc->sock = g_value_get_int (value);
- GST_DEBUG ("setting SOCKFD to %d", udpsrc->sock);
+ udpsrc->sockfd = g_value_get_int (value);
+ GST_DEBUG ("setting SOCKFD to %d", udpsrc->sockfd);
break;
case PROP_TIMEOUT:
udpsrc->timeout = g_value_get_uint64 (value);
case PROP_SKIP_FIRST_BYTES:
udpsrc->skip_first_bytes = g_value_get_int (value);
break;
+ case PROP_CLOSEFD:
+ udpsrc->closefd = g_value_get_boolean (value);
+ break;
default:
break;
}
gst_value_set_caps (value, udpsrc->caps);
break;
case PROP_SOCKFD:
- g_value_set_int (value, udpsrc->sock);
+ g_value_set_int (value, udpsrc->sockfd);
break;
case PROP_TIMEOUT:
g_value_set_uint64 (value, udpsrc->timeout);
case PROP_SKIP_FIRST_BYTES:
g_value_set_int (value, udpsrc->skip_first_bytes);
break;
+ case PROP_CLOSEFD:
+ g_value_set_boolean (value, udpsrc->closefd);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
if (!inet_aton (src->multi_group, &(src->multi_addr.imr_multiaddr)))
src->multi_addr.imr_multiaddr.s_addr = 0;
- if (src->sock == -1) {
+ if (src->sockfd == -1) {
+ /* need to allocate a socket */
if ((ret = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
goto no_socket;
src->sock = ret;
+ src->externalfd = FALSE;
reuse = 1;
if ((ret =
if ((ret = bind (src->sock, (struct sockaddr *) &src->myaddr,
sizeof (src->myaddr))) < 0)
goto bind_error;
+ } else {
+ /* we use the configured socket */
+ src->sock = src->sockfd;
+ src->externalfd = TRUE;
}
if (src->multi_addr.imr_multiaddr.s_addr) {
}
setsockopt_error:
{
- CLOSE_SOCKET (src->sock);
- src->sock = -1;
+ CLOSE_IF_REQUESTED (src);
GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, (NULL),
("setsockopt failed %d: %s (%d)", ret, g_strerror (errno), errno));
return FALSE;
}
bind_error:
{
- CLOSE_SOCKET (src->sock);
- src->sock = -1;
+ CLOSE_IF_REQUESTED (src);
GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, (NULL),
("bind failed %d: %s (%d)", ret, g_strerror (errno), errno));
return FALSE;
}
membership:
{
- CLOSE_SOCKET (src->sock);
- src->sock = -1;
+ CLOSE_IF_REQUESTED (src);
GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, (NULL),
("could add membership %d: %s (%d)", ret, g_strerror (errno), errno));
return FALSE;
}
getsockname_error:
{
- CLOSE_SOCKET (src->sock);
- src->sock = -1;
+ CLOSE_IF_REQUESTED (src);
GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, (NULL),
("getsockname failed %d: %s (%d)", ret, g_strerror (errno), errno));
return FALSE;
}
udpbuffer_error:
{
- CLOSE_SOCKET (src->sock);
- src->sock = -1;
+ CLOSE_IF_REQUESTED (src);
GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, (NULL),
("Could not create a buffer of the size requested, %d: %s (%d)", ret,
g_strerror (errno), errno));
}
no_broadcast:
{
- CLOSE_SOCKET (src->sock);
- src->sock = -1;
+ CLOSE_IF_REQUESTED (src);
GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, (NULL),
("could not configure socket for broadcast %d: %s (%d)", ret,
g_strerror (errno), errno));
GST_DEBUG ("stopping, closing sockets");
if (src->sock != -1) {
- CLOSE_SOCKET (src->sock);
- src->sock = -1;
+ CLOSE_IF_REQUESTED (src);
}
/* pipes on WIN32 else sockets */