mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-11 18:05:37 +00:00
udpsrc: Port to GIO
This commit is contained in:
parent
d55f75f6f4
commit
7f74fc9ef6
7 changed files with 362 additions and 420 deletions
|
@ -15,10 +15,8 @@ BUILT_SOURCES = $(built_sources) $(built_headers)
|
||||||
|
|
||||||
libgstudp_la_SOURCES = gstudp.c gstudpsrc.c gstudpsink.c gstmultiudpsink.c gstdynudpsink.c gstudpnetutils.c
|
libgstudp_la_SOURCES = gstudp.c gstudpsrc.c gstudpsink.c gstmultiudpsink.c gstdynudpsink.c gstudpnetutils.c
|
||||||
|
|
||||||
# adding -D_GNU_SOURCE to get non-POSIX extensions like EAI_ADDRFAMILY
|
libgstudp_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_NET_CFLAGS) $(GST_CFLAGS) $(GIO_CFLAGS) -D_GNU_SOURCE
|
||||||
# with glibc >= 2.8 when including netdb.h (see glibc sources bug 6452)
|
libgstudp_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) $(GST_NET_LIBS) $(GIO_LIBS)
|
||||||
libgstudp_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_NET_CFLAGS) $(GST_CFLAGS) -D_GNU_SOURCE
|
|
||||||
libgstudp_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) $(GST_NET_LIBS) $(WIN32_LIBS)
|
|
||||||
libgstudp_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
|
libgstudp_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
|
||||||
libgstudp_la_LIBTOOLFLAGS = --tag=disable-static
|
libgstudp_la_LIBTOOLFLAGS = --tag=disable-static
|
||||||
|
|
||||||
|
|
|
@ -182,6 +182,7 @@ gst_dynudpsink_render (GstBaseSink * bsink, GstBuffer * buffer)
|
||||||
struct sockaddr_in theiraddr;
|
struct sockaddr_in theiraddr;
|
||||||
guint16 destport;
|
guint16 destport;
|
||||||
guint32 destaddr;
|
guint32 destaddr;
|
||||||
|
const guint8 *destaddr_bytes;
|
||||||
|
|
||||||
memset (&theiraddr, 0, sizeof (theiraddr));
|
memset (&theiraddr, 0, sizeof (theiraddr));
|
||||||
|
|
||||||
|
@ -199,7 +200,12 @@ gst_dynudpsink_render (GstBaseSink * bsink, GstBuffer * buffer)
|
||||||
GST_DEBUG ("about to send %" G_GSIZE_FORMAT " bytes", size);
|
GST_DEBUG ("about to send %" G_GSIZE_FORMAT " bytes", size);
|
||||||
|
|
||||||
/* let's get the address from the metaata */
|
/* let's get the address from the metaata */
|
||||||
gst_net_address_get_ip4_address (&meta->naddr, &destaddr, &destport);
|
destaddr_bytes =
|
||||||
|
g_inet_address_to_bytes (g_inet_socket_address_get_address
|
||||||
|
(G_INET_SOCKET_ADDRESS (meta->addr)));
|
||||||
|
destaddr = GST_READ_UINT32_BE (destaddr_bytes);
|
||||||
|
destport =
|
||||||
|
g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (meta->addr));
|
||||||
|
|
||||||
GST_DEBUG ("sending %" G_GSIZE_FORMAT " bytes to client %d port %d", size,
|
GST_DEBUG ("sending %" G_GSIZE_FORMAT " bytes to client %d port %d", size,
|
||||||
destaddr, destport);
|
destaddr, destport);
|
||||||
|
|
|
@ -367,8 +367,8 @@ gst_udp_uri_update (GstUDPUri * uri, const gchar * host, gint port)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
gboolean
|
||||||
gst_udp_parse_uri (const gchar * uristr, GstUDPUri * uri)
|
gst_udp_parse_uri (const gchar * uristr, gchar ** host, guint16 * port)
|
||||||
{
|
{
|
||||||
gchar *protocol, *location_start;
|
gchar *protocol, *location_start;
|
||||||
gchar *location, *location_end;
|
gchar *location, *location_end;
|
||||||
|
@ -402,49 +402,45 @@ gst_udp_parse_uri (const gchar * uristr, GstUDPUri * uri)
|
||||||
if (location_end == NULL)
|
if (location_end == NULL)
|
||||||
goto wrong_address;
|
goto wrong_address;
|
||||||
|
|
||||||
uri->is_ipv6 = TRUE;
|
*host = g_strndup (location + 1, location_end - location - 1);
|
||||||
g_free (uri->host);
|
|
||||||
uri->host = g_strndup (location + 1, location_end - location - 1);
|
|
||||||
colptr = strrchr (location_end, ':');
|
colptr = strrchr (location_end, ':');
|
||||||
} else {
|
} else {
|
||||||
GST_DEBUG ("parse IPV4 address '%s'", location);
|
GST_DEBUG ("parse IPV4 address '%s'", location);
|
||||||
uri->is_ipv6 = FALSE;
|
|
||||||
colptr = strrchr (location, ':');
|
colptr = strrchr (location, ':');
|
||||||
|
|
||||||
g_free (uri->host);
|
|
||||||
if (colptr != NULL) {
|
if (colptr != NULL) {
|
||||||
uri->host = g_strndup (location, colptr - location);
|
*host = g_strndup (location, colptr - location);
|
||||||
} else {
|
} else {
|
||||||
uri->host = g_strdup (location);
|
*host = g_strdup (location);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
GST_DEBUG ("host set to '%s'", uri->host);
|
GST_DEBUG ("host set to '%s'", *host);
|
||||||
|
|
||||||
if (colptr != NULL) {
|
if (colptr != NULL) {
|
||||||
uri->port = atoi (colptr + 1);
|
*port = atoi (colptr + 1);
|
||||||
}
|
}
|
||||||
g_free (location_start);
|
g_free (location_start);
|
||||||
|
|
||||||
return 0;
|
return TRUE;
|
||||||
|
|
||||||
/* ERRORS */
|
/* ERRORS */
|
||||||
no_protocol:
|
no_protocol:
|
||||||
{
|
{
|
||||||
GST_ERROR ("error parsing uri %s: no protocol", uristr);
|
GST_ERROR ("error parsing uri %s: no protocol", uristr);
|
||||||
return -1;
|
return FALSE;
|
||||||
}
|
}
|
||||||
wrong_protocol:
|
wrong_protocol:
|
||||||
{
|
{
|
||||||
GST_ERROR ("error parsing uri %s: wrong protocol (%s != udp)", uristr,
|
GST_ERROR ("error parsing uri %s: wrong protocol (%s != udp)", uristr,
|
||||||
protocol);
|
protocol);
|
||||||
g_free (protocol);
|
g_free (protocol);
|
||||||
return -1;
|
return FALSE;
|
||||||
}
|
}
|
||||||
wrong_address:
|
wrong_address:
|
||||||
{
|
{
|
||||||
GST_ERROR ("error parsing uri %s", uristr);
|
GST_ERROR ("error parsing uri %s", uristr);
|
||||||
g_free (location);
|
g_free (location);
|
||||||
return -1;
|
return FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -82,7 +82,7 @@ gboolean gst_udp_net_utils_win32_wsa_startup (GstObject * obj);
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
gchar *host;
|
gchar *host;
|
||||||
gint port;
|
guint16 port;
|
||||||
gboolean is_ipv6;
|
gboolean is_ipv6;
|
||||||
} GstUDPUri;
|
} GstUDPUri;
|
||||||
|
|
||||||
|
@ -102,9 +102,10 @@ int gst_udp_leave_group (int sockfd, struct sockaddr_storage *addr)
|
||||||
/* uri handling */
|
/* uri handling */
|
||||||
void gst_udp_uri_init (GstUDPUri *uri, const gchar *host, gint port);
|
void gst_udp_uri_init (GstUDPUri *uri, const gchar *host, gint port);
|
||||||
int gst_udp_uri_update (GstUDPUri *uri, const gchar *host, gint port);
|
int gst_udp_uri_update (GstUDPUri *uri, const gchar *host, gint port);
|
||||||
int gst_udp_parse_uri (const gchar *uristr, GstUDPUri *uri);
|
|
||||||
gchar * gst_udp_uri_string (GstUDPUri *uri);
|
gchar * gst_udp_uri_string (GstUDPUri *uri);
|
||||||
void gst_udp_uri_free (GstUDPUri *uri);
|
void gst_udp_uri_free (GstUDPUri *uri);
|
||||||
|
|
||||||
|
gboolean gst_udp_parse_uri (const gchar *uristr, gchar **host, guint16 *port);
|
||||||
|
|
||||||
#endif /* __GST_UDP_NET_UTILS_H__*/
|
#endif /* __GST_UDP_NET_UTILS_H__*/
|
||||||
|
|
||||||
|
|
|
@ -129,7 +129,7 @@ gst_udpsink_set_uri (GstUDPSink * sink, const gchar * uri, GError ** error)
|
||||||
gst_multiudpsink_remove (GST_MULTIUDPSINK (sink), sink->uri.host,
|
gst_multiudpsink_remove (GST_MULTIUDPSINK (sink), sink->uri.host,
|
||||||
sink->uri.port);
|
sink->uri.port);
|
||||||
|
|
||||||
if (gst_udp_parse_uri (uri, &sink->uri) < 0)
|
if (gst_udp_parse_uri (uri, &sink->uri.host, &sink->uri.port) < 0)
|
||||||
goto wrong_uri;
|
goto wrong_uri;
|
||||||
|
|
||||||
gst_multiudpsink_add (GST_MULTIUDPSINK (sink), sink->uri.host,
|
gst_multiudpsink_add (GST_MULTIUDPSINK (sink), sink->uri.host,
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
/* GStreamer
|
/* GStreamer
|
||||||
* Copyright (C) <2005> Wim Taymans <wim@fluendo.com>
|
* Copyright (C) <2005> Wim Taymans <wim@fluendo.com>
|
||||||
* Copyright (C) <2005> Nokia Corporation <kai.vehmanen@nokia.com>
|
* Copyright (C) <2005> Nokia Corporation <kai.vehmanen@nokia.com>
|
||||||
|
* Copyright (C) <2012> Collabora Ltd.
|
||||||
|
* Author: Sebastian Dröge <sebastian.droege@collabora.co.uk>
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Library General Public
|
* modify it under the terms of the GNU Library General Public
|
||||||
|
@ -107,20 +109,9 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "gstudpsrc.h"
|
#include "gstudpsrc.h"
|
||||||
#ifdef HAVE_UNISTD_H
|
|
||||||
#include <unistd.h>
|
|
||||||
#endif
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
#if defined _MSC_VER && (_MSC_VER >= 1400)
|
|
||||||
#include <io.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <gst/net/gstnetaddressmeta.h>
|
#include <gst/net/gstnetaddressmeta.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
#ifdef HAVE_FIONREAD_IN_SYS_FILIO
|
|
||||||
#include <sys/filio.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
GST_DEBUG_CATEGORY_STATIC (udpsrc_debug);
|
GST_DEBUG_CATEGORY_STATIC (udpsrc_debug);
|
||||||
#define GST_CAT_DEFAULT (udpsrc_debug)
|
#define GST_CAT_DEFAULT (udpsrc_debug)
|
||||||
|
@ -135,12 +126,12 @@ static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
|
||||||
#define UDP_DEFAULT_MULTICAST_IFACE NULL
|
#define UDP_DEFAULT_MULTICAST_IFACE NULL
|
||||||
#define UDP_DEFAULT_URI "udp://"UDP_DEFAULT_MULTICAST_GROUP":"G_STRINGIFY(UDP_DEFAULT_PORT)
|
#define UDP_DEFAULT_URI "udp://"UDP_DEFAULT_MULTICAST_GROUP":"G_STRINGIFY(UDP_DEFAULT_PORT)
|
||||||
#define UDP_DEFAULT_CAPS NULL
|
#define UDP_DEFAULT_CAPS NULL
|
||||||
#define UDP_DEFAULT_SOCKFD -1
|
#define UDP_DEFAULT_SOCKET NULL
|
||||||
#define UDP_DEFAULT_BUFFER_SIZE 0
|
#define UDP_DEFAULT_BUFFER_SIZE 0
|
||||||
#define UDP_DEFAULT_TIMEOUT 0
|
#define UDP_DEFAULT_TIMEOUT 0
|
||||||
#define UDP_DEFAULT_SKIP_FIRST_BYTES 0
|
#define UDP_DEFAULT_SKIP_FIRST_BYTES 0
|
||||||
#define UDP_DEFAULT_CLOSEFD TRUE
|
#define UDP_DEFAULT_CLOSE_SOCKET TRUE
|
||||||
#define UDP_DEFAULT_SOCK -1
|
#define UDP_DEFAULT_USED_SOCKET NULL
|
||||||
#define UDP_DEFAULT_AUTO_MULTICAST TRUE
|
#define UDP_DEFAULT_AUTO_MULTICAST TRUE
|
||||||
#define UDP_DEFAULT_REUSE TRUE
|
#define UDP_DEFAULT_REUSE TRUE
|
||||||
|
|
||||||
|
@ -153,28 +144,18 @@ enum
|
||||||
PROP_MULTICAST_IFACE,
|
PROP_MULTICAST_IFACE,
|
||||||
PROP_URI,
|
PROP_URI,
|
||||||
PROP_CAPS,
|
PROP_CAPS,
|
||||||
PROP_SOCKFD,
|
PROP_SOCKET,
|
||||||
PROP_BUFFER_SIZE,
|
PROP_BUFFER_SIZE,
|
||||||
PROP_TIMEOUT,
|
PROP_TIMEOUT,
|
||||||
PROP_SKIP_FIRST_BYTES,
|
PROP_SKIP_FIRST_BYTES,
|
||||||
PROP_CLOSEFD,
|
PROP_CLOSE_SOCKET,
|
||||||
PROP_SOCK,
|
PROP_USED_SOCKET,
|
||||||
PROP_AUTO_MULTICAST,
|
PROP_AUTO_MULTICAST,
|
||||||
PROP_REUSE,
|
PROP_REUSE,
|
||||||
|
|
||||||
PROP_LAST
|
PROP_LAST
|
||||||
};
|
};
|
||||||
|
|
||||||
#define CLOSE_IF_REQUESTED(udpctx) \
|
|
||||||
G_STMT_START { \
|
|
||||||
if ((!udpctx->externalfd) || (udpctx->externalfd && udpctx->closefd)) { \
|
|
||||||
CLOSE_SOCKET(udpctx->sock.fd); \
|
|
||||||
if (udpctx->sock.fd == udpctx->sockfd) \
|
|
||||||
udpctx->sockfd = UDP_DEFAULT_SOCKFD; \
|
|
||||||
} \
|
|
||||||
udpctx->sock.fd = UDP_DEFAULT_SOCK; \
|
|
||||||
} G_STMT_END
|
|
||||||
|
|
||||||
static void gst_udpsrc_uri_handler_init (gpointer g_iface, gpointer iface_data);
|
static void gst_udpsrc_uri_handler_init (gpointer g_iface, gpointer iface_data);
|
||||||
|
|
||||||
static GstCaps *gst_udpsrc_getcaps (GstBaseSrc * src, GstCaps * filter);
|
static GstCaps *gst_udpsrc_getcaps (GstBaseSrc * src, GstCaps * filter);
|
||||||
|
@ -240,18 +221,17 @@ gst_udpsrc_class_init (GstUDPSrcClass * klass)
|
||||||
g_param_spec_boxed ("caps", "Caps",
|
g_param_spec_boxed ("caps", "Caps",
|
||||||
"The caps of the source pad", GST_TYPE_CAPS,
|
"The caps of the source pad", GST_TYPE_CAPS,
|
||||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||||
g_object_class_install_property (gobject_class, PROP_SOCKFD,
|
g_object_class_install_property (gobject_class, PROP_SOCKET,
|
||||||
g_param_spec_int ("sockfd", "Socket Handle",
|
g_param_spec_object ("socket", "Socket",
|
||||||
"Socket to use for UDP reception. (-1 == allocate)",
|
"Socket to use for UDP reception. (NULL == allocate)",
|
||||||
-1, G_MAXINT, UDP_DEFAULT_SOCKFD,
|
G_TYPE_SOCKET, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
|
||||||
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_BUFFER_SIZE,
|
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_BUFFER_SIZE,
|
||||||
g_param_spec_int ("buffer-size", "Buffer Size",
|
g_param_spec_int ("buffer-size", "Buffer Size",
|
||||||
"Size of the kernel receive buffer in bytes, 0=default", 0, G_MAXINT,
|
"Size of the kernel receive buffer in bytes, 0=default", 0, G_MAXINT,
|
||||||
UDP_DEFAULT_BUFFER_SIZE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
UDP_DEFAULT_BUFFER_SIZE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||||
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_TIMEOUT,
|
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_TIMEOUT,
|
||||||
g_param_spec_uint64 ("timeout", "Timeout",
|
g_param_spec_uint64 ("timeout", "Timeout",
|
||||||
"Post a message after timeout microseconds (0 = disabled)", 0,
|
"Post a message after timeout nanoseconds (0 = disabled)", 0,
|
||||||
G_MAXUINT64, UDP_DEFAULT_TIMEOUT,
|
G_MAXUINT64, UDP_DEFAULT_TIMEOUT,
|
||||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||||
g_object_class_install_property (G_OBJECT_CLASS (klass),
|
g_object_class_install_property (G_OBJECT_CLASS (klass),
|
||||||
|
@ -259,15 +239,15 @@ gst_udpsrc_class_init (GstUDPSrcClass * klass)
|
||||||
"Skip first bytes", "number of bytes to skip for each udp packet", 0,
|
"Skip first bytes", "number of bytes to skip for each udp packet", 0,
|
||||||
G_MAXINT, UDP_DEFAULT_SKIP_FIRST_BYTES,
|
G_MAXINT, UDP_DEFAULT_SKIP_FIRST_BYTES,
|
||||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||||
g_object_class_install_property (gobject_class, PROP_CLOSEFD,
|
g_object_class_install_property (gobject_class, PROP_CLOSE_SOCKET,
|
||||||
g_param_spec_boolean ("closefd", "Close sockfd",
|
g_param_spec_boolean ("close-socket", "Close socket",
|
||||||
"Close sockfd if passed as property on state change",
|
"Close socket if passed as property on state change",
|
||||||
UDP_DEFAULT_CLOSEFD, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
UDP_DEFAULT_CLOSE_SOCKET,
|
||||||
g_object_class_install_property (gobject_class, PROP_SOCK,
|
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||||
g_param_spec_int ("sock", "Socket Handle",
|
g_object_class_install_property (gobject_class, PROP_USED_SOCKET,
|
||||||
"Socket currently in use for UDP reception. (-1 = no socket)",
|
g_param_spec_object ("used-socket", "Socket Handle",
|
||||||
-1, G_MAXINT, UDP_DEFAULT_SOCK,
|
"Socket currently in use for UDP reception. (NULL = no socket)",
|
||||||
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
G_TYPE_SOCKET, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||||
g_object_class_install_property (gobject_class, PROP_AUTO_MULTICAST,
|
g_object_class_install_property (gobject_class, PROP_AUTO_MULTICAST,
|
||||||
g_param_spec_boolean ("auto-multicast", "Auto Multicast",
|
g_param_spec_boolean ("auto-multicast", "Auto Multicast",
|
||||||
"Automatically join/leave multicast groups",
|
"Automatically join/leave multicast groups",
|
||||||
|
@ -300,20 +280,25 @@ gst_udpsrc_init (GstUDPSrc * udpsrc)
|
||||||
{
|
{
|
||||||
WSA_STARTUP (udpsrc);
|
WSA_STARTUP (udpsrc);
|
||||||
|
|
||||||
gst_udp_uri_init (&udpsrc->uri, UDP_DEFAULT_MULTICAST_GROUP,
|
udpsrc->uri =
|
||||||
|
g_strdup_printf ("udp://%s:%u", UDP_DEFAULT_MULTICAST_GROUP,
|
||||||
UDP_DEFAULT_PORT);
|
UDP_DEFAULT_PORT);
|
||||||
|
|
||||||
udpsrc->sockfd = UDP_DEFAULT_SOCKFD;
|
udpsrc->host = g_strdup (UDP_DEFAULT_MULTICAST_GROUP);
|
||||||
|
udpsrc->port = UDP_DEFAULT_PORT;
|
||||||
|
udpsrc->socket = UDP_DEFAULT_SOCKET;
|
||||||
udpsrc->multi_iface = g_strdup (UDP_DEFAULT_MULTICAST_IFACE);
|
udpsrc->multi_iface = g_strdup (UDP_DEFAULT_MULTICAST_IFACE);
|
||||||
udpsrc->buffer_size = UDP_DEFAULT_BUFFER_SIZE;
|
udpsrc->buffer_size = UDP_DEFAULT_BUFFER_SIZE;
|
||||||
udpsrc->timeout = UDP_DEFAULT_TIMEOUT;
|
udpsrc->timeout = UDP_DEFAULT_TIMEOUT;
|
||||||
udpsrc->skip_first_bytes = UDP_DEFAULT_SKIP_FIRST_BYTES;
|
udpsrc->skip_first_bytes = UDP_DEFAULT_SKIP_FIRST_BYTES;
|
||||||
udpsrc->closefd = UDP_DEFAULT_CLOSEFD;
|
udpsrc->close_socket = UDP_DEFAULT_CLOSE_SOCKET;
|
||||||
udpsrc->externalfd = (udpsrc->sockfd != -1);
|
udpsrc->external_socket = (udpsrc->socket != NULL);
|
||||||
udpsrc->auto_multicast = UDP_DEFAULT_AUTO_MULTICAST;
|
udpsrc->auto_multicast = UDP_DEFAULT_AUTO_MULTICAST;
|
||||||
udpsrc->sock.fd = UDP_DEFAULT_SOCK;
|
udpsrc->used_socket = UDP_DEFAULT_USED_SOCKET;
|
||||||
udpsrc->reuse = UDP_DEFAULT_REUSE;
|
udpsrc->reuse = UDP_DEFAULT_REUSE;
|
||||||
|
|
||||||
|
udpsrc->cancellable = g_cancellable_new ();
|
||||||
|
|
||||||
/* configure basesrc to be a live source */
|
/* configure basesrc to be a live source */
|
||||||
gst_base_src_set_live (GST_BASE_SRC (udpsrc), TRUE);
|
gst_base_src_set_live (GST_BASE_SRC (udpsrc), TRUE);
|
||||||
/* make basesrc output a segment in time */
|
/* make basesrc output a segment in time */
|
||||||
|
@ -332,16 +317,25 @@ gst_udpsrc_finalize (GObject * object)
|
||||||
|
|
||||||
if (udpsrc->caps)
|
if (udpsrc->caps)
|
||||||
gst_caps_unref (udpsrc->caps);
|
gst_caps_unref (udpsrc->caps);
|
||||||
|
udpsrc->caps = NULL;
|
||||||
|
|
||||||
g_free (udpsrc->multi_iface);
|
g_free (udpsrc->multi_iface);
|
||||||
|
udpsrc->multi_iface = NULL;
|
||||||
|
|
||||||
gst_udp_uri_free (&udpsrc->uri);
|
g_free (udpsrc->uri);
|
||||||
g_free (udpsrc->uristr);
|
udpsrc->uri = NULL;
|
||||||
|
|
||||||
if (udpsrc->sockfd >= 0 && udpsrc->closefd)
|
if (udpsrc->socket)
|
||||||
CLOSE_SOCKET (udpsrc->sockfd);
|
g_object_unref (udpsrc->socket);
|
||||||
|
udpsrc->socket = NULL;
|
||||||
|
|
||||||
WSA_CLEANUP (object);
|
if (udpsrc->used_socket)
|
||||||
|
g_object_unref (udpsrc->used_socket);
|
||||||
|
udpsrc->used_socket = NULL;
|
||||||
|
|
||||||
|
if (udpsrc->cancellable)
|
||||||
|
g_object_unref (udpsrc->cancellable);
|
||||||
|
udpsrc->cancellable = NULL;
|
||||||
|
|
||||||
G_OBJECT_CLASS (parent_class)->finalize (object);
|
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||||
}
|
}
|
||||||
|
@ -353,112 +347,57 @@ gst_udpsrc_getcaps (GstBaseSrc * src, GstCaps * filter)
|
||||||
|
|
||||||
udpsrc = GST_UDPSRC (src);
|
udpsrc = GST_UDPSRC (src);
|
||||||
|
|
||||||
if (udpsrc->caps)
|
if (udpsrc->caps) {
|
||||||
return gst_caps_ref (udpsrc->caps);
|
return (filter) ? gst_caps_intersect_full (filter, udpsrc->caps,
|
||||||
else
|
GST_CAPS_INTERSECT_FIRST) : gst_caps_ref (udpsrc->caps);
|
||||||
return gst_caps_new_any ();
|
} else {
|
||||||
|
return (filter) ? gst_caps_ref (filter) : gst_caps_new_any ();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* read a message from the error queue */
|
|
||||||
static void
|
|
||||||
clear_error (GstUDPSrc * udpsrc)
|
|
||||||
{
|
|
||||||
#if defined (MSG_ERRQUEUE)
|
|
||||||
struct msghdr cmsg;
|
|
||||||
char cbuf[128];
|
|
||||||
char msgbuf[CMSG_SPACE (128)];
|
|
||||||
struct iovec iov;
|
|
||||||
|
|
||||||
/* Flush ERRORS from fd so next poll will not return at once */
|
|
||||||
/* No need for address : We look for local error */
|
|
||||||
cmsg.msg_name = NULL;
|
|
||||||
cmsg.msg_namelen = 0;
|
|
||||||
|
|
||||||
/* IOV */
|
|
||||||
memset (&cbuf, 0, sizeof (cbuf));
|
|
||||||
iov.iov_base = cbuf;
|
|
||||||
iov.iov_len = sizeof (cbuf);
|
|
||||||
cmsg.msg_iov = &iov;
|
|
||||||
cmsg.msg_iovlen = 1;
|
|
||||||
|
|
||||||
/* msg_control */
|
|
||||||
memset (&msgbuf, 0, sizeof (msgbuf));
|
|
||||||
cmsg.msg_control = &msgbuf;
|
|
||||||
cmsg.msg_controllen = sizeof (msgbuf);
|
|
||||||
|
|
||||||
recvmsg (udpsrc->sock.fd, &cmsg, MSG_ERRQUEUE);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static GstFlowReturn
|
static GstFlowReturn
|
||||||
gst_udpsrc_create (GstPushSrc * psrc, GstBuffer ** buf)
|
gst_udpsrc_create (GstPushSrc * psrc, GstBuffer ** buf)
|
||||||
{
|
{
|
||||||
GstUDPSrc *udpsrc;
|
GstUDPSrc *udpsrc;
|
||||||
GstNetAddressMeta *meta;
|
|
||||||
GstBuffer *outbuf;
|
GstBuffer *outbuf;
|
||||||
union gst_sockaddr
|
GSocketAddress *saddr = NULL;
|
||||||
{
|
|
||||||
struct sockaddr sa;
|
|
||||||
struct sockaddr_in sa_in;
|
|
||||||
struct sockaddr_in6 sa_in6;
|
|
||||||
struct sockaddr_storage sa_stor;
|
|
||||||
} sa;
|
|
||||||
socklen_t slen;
|
|
||||||
guint8 *pktdata;
|
guint8 *pktdata;
|
||||||
gint pktsize;
|
gint pktsize;
|
||||||
gsize offset;
|
gsize offset;
|
||||||
#ifdef G_OS_UNIX
|
gssize readsize;
|
||||||
gint readsize;
|
gssize ret;
|
||||||
#elif defined G_OS_WIN32
|
|
||||||
gulong readsize;
|
|
||||||
#endif
|
|
||||||
GstClockTime timeout;
|
|
||||||
gint ret;
|
|
||||||
gboolean try_again;
|
gboolean try_again;
|
||||||
|
GError *err = NULL;
|
||||||
|
|
||||||
udpsrc = GST_UDPSRC_CAST (psrc);
|
udpsrc = GST_UDPSRC_CAST (psrc);
|
||||||
|
|
||||||
retry:
|
retry:
|
||||||
/* quick check, avoid going in select when we already have data */
|
/* quick check, avoid going in select when we already have data */
|
||||||
readsize = 0;
|
readsize = g_socket_get_available_bytes (udpsrc->used_socket);
|
||||||
if (G_UNLIKELY ((ret =
|
|
||||||
IOCTL_SOCKET (udpsrc->sock.fd, FIONREAD, &readsize)) < 0))
|
|
||||||
goto ioctl_failed;
|
|
||||||
|
|
||||||
if (readsize > 0)
|
if (readsize > 0)
|
||||||
goto no_select;
|
goto no_select;
|
||||||
|
|
||||||
if (udpsrc->timeout > 0) {
|
|
||||||
timeout = udpsrc->timeout * GST_USECOND;
|
|
||||||
} else {
|
|
||||||
timeout = GST_CLOCK_TIME_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
do {
|
do {
|
||||||
try_again = FALSE;
|
try_again = FALSE;
|
||||||
|
|
||||||
GST_LOG_OBJECT (udpsrc, "doing select, timeout %" G_GUINT64_FORMAT,
|
GST_LOG_OBJECT (udpsrc, "doing select, timeout %" G_GUINT64_FORMAT,
|
||||||
udpsrc->timeout);
|
udpsrc->timeout);
|
||||||
|
|
||||||
ret = gst_poll_wait (udpsrc->fdset, timeout);
|
if (!g_socket_condition_wait (udpsrc->used_socket, G_IO_IN | G_IO_PRI,
|
||||||
GST_LOG_OBJECT (udpsrc, "select returned %d", ret);
|
udpsrc->cancellable, &err)) {
|
||||||
if (G_UNLIKELY (ret < 0)) {
|
if (g_error_matches (err, G_IO_ERROR, G_IO_ERROR_BUSY)
|
||||||
if (errno == EBUSY)
|
|| g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
|
||||||
goto stopped;
|
goto stopped;
|
||||||
#ifdef G_OS_WIN32
|
} else if (g_error_matches (err, G_IO_ERROR, G_IO_ERROR_TIMED_OUT)) {
|
||||||
if (WSAGetLastError () != WSAEINTR)
|
|
||||||
goto select_error;
|
|
||||||
#else
|
|
||||||
if (errno != EAGAIN && errno != EINTR)
|
|
||||||
goto select_error;
|
|
||||||
#endif
|
|
||||||
try_again = TRUE;
|
|
||||||
} else if (G_UNLIKELY (ret == 0)) {
|
|
||||||
/* timeout, post element message */
|
/* timeout, post element message */
|
||||||
gst_element_post_message (GST_ELEMENT_CAST (udpsrc),
|
gst_element_post_message (GST_ELEMENT_CAST (udpsrc),
|
||||||
gst_message_new_element (GST_OBJECT_CAST (udpsrc),
|
gst_message_new_element (GST_OBJECT_CAST (udpsrc),
|
||||||
gst_structure_new ("GstUDPSrcTimeout",
|
gst_structure_new ("GstUDPSrcTimeout",
|
||||||
"timeout", G_TYPE_UINT64, udpsrc->timeout, NULL)));
|
"timeout", G_TYPE_UINT64, udpsrc->timeout, NULL)));
|
||||||
|
} else {
|
||||||
|
goto select_error;
|
||||||
|
}
|
||||||
|
|
||||||
try_again = TRUE;
|
try_again = TRUE;
|
||||||
}
|
}
|
||||||
} while (G_UNLIKELY (try_again));
|
} while (G_UNLIKELY (try_again));
|
||||||
|
@ -466,10 +405,9 @@ retry:
|
||||||
/* ask how much is available for reading on the socket, this should be exactly
|
/* ask how much is available for reading on the socket, this should be exactly
|
||||||
* one UDP packet. We will check the return value, though, because in some
|
* one UDP packet. We will check the return value, though, because in some
|
||||||
* case it can return 0 and we don't want a 0 sized buffer. */
|
* case it can return 0 and we don't want a 0 sized buffer. */
|
||||||
readsize = 0;
|
readsize = g_socket_get_available_bytes (udpsrc->used_socket);
|
||||||
if (G_UNLIKELY ((ret =
|
if (G_UNLIKELY (readsize < 0))
|
||||||
IOCTL_SOCKET (udpsrc->sock.fd, FIONREAD, &readsize)) < 0))
|
goto get_available_error;
|
||||||
goto ioctl_failed;
|
|
||||||
|
|
||||||
/* If we get here and the readsize is zero, then either select was woken up
|
/* If we get here and the readsize is zero, then either select was woken up
|
||||||
* by activity that is not a read, or a poll error occurred, or a UDP packet
|
* by activity that is not a read, or a poll error occurred, or a UDP packet
|
||||||
|
@ -479,11 +417,14 @@ retry:
|
||||||
if (G_UNLIKELY (!readsize)) {
|
if (G_UNLIKELY (!readsize)) {
|
||||||
/* try to read a packet (and it will be ignored),
|
/* try to read a packet (and it will be ignored),
|
||||||
* in case a packet with no data arrived */
|
* in case a packet with no data arrived */
|
||||||
slen = sizeof (sa);
|
|
||||||
recvfrom (udpsrc->sock.fd, (char *) &slen, 0, 0, &sa.sa, &slen);
|
|
||||||
|
|
||||||
/* clear any error, in case a poll error occurred */
|
pktdata = NULL;
|
||||||
clear_error (udpsrc);
|
pktsize = 0;
|
||||||
|
ret =
|
||||||
|
g_socket_receive_from (udpsrc->used_socket, NULL, (gchar *) pktdata,
|
||||||
|
pktsize, udpsrc->cancellable, &err);
|
||||||
|
if (G_UNLIKELY (ret < 0))
|
||||||
|
goto receive_error;
|
||||||
|
|
||||||
/* poll again */
|
/* poll again */
|
||||||
goto retry;
|
goto retry;
|
||||||
|
@ -496,33 +437,16 @@ no_select:
|
||||||
pktsize = readsize;
|
pktsize = readsize;
|
||||||
offset = 0;
|
offset = 0;
|
||||||
|
|
||||||
while (TRUE) {
|
if (saddr)
|
||||||
slen = sizeof (sa);
|
g_object_unref (saddr);
|
||||||
#ifdef G_OS_WIN32
|
saddr = NULL;
|
||||||
ret = recvfrom (udpsrc->sock.fd, (char *) pktdata, pktsize, 0, &sa.sa,
|
|
||||||
&slen);
|
ret =
|
||||||
#else
|
g_socket_receive_from (udpsrc->used_socket, &saddr, (gchar *) pktdata,
|
||||||
ret = recvfrom (udpsrc->sock.fd, pktdata, pktsize, 0, &sa.sa, &slen);
|
pktsize, udpsrc->cancellable, &err);
|
||||||
#endif
|
|
||||||
if (G_UNLIKELY (ret < 0)) {
|
if (G_UNLIKELY (ret < 0))
|
||||||
#ifdef G_OS_WIN32
|
|
||||||
/* WSAECONNRESET for a UDP socket means that a packet sent with udpsink
|
|
||||||
* generated a "port unreachable" ICMP response. We ignore that and try
|
|
||||||
* again. */
|
|
||||||
if (WSAGetLastError () == WSAECONNRESET) {
|
|
||||||
g_free (pktdata);
|
|
||||||
pktdata = NULL;
|
|
||||||
goto retry;
|
|
||||||
}
|
|
||||||
if (WSAGetLastError () != WSAEINTR)
|
|
||||||
goto receive_error;
|
goto receive_error;
|
||||||
#else
|
|
||||||
if (errno != EAGAIN && errno != EINTR)
|
|
||||||
goto receive_error;
|
|
||||||
#endif
|
|
||||||
} else
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* patch pktdata and len when stripping off the headers */
|
/* patch pktdata and len when stripping off the headers */
|
||||||
if (G_UNLIKELY (udpsrc->skip_first_bytes != 0)) {
|
if (G_UNLIKELY (udpsrc->skip_first_bytes != 0)) {
|
||||||
|
@ -538,31 +462,12 @@ no_select:
|
||||||
gst_memory_new_wrapped (0, pktdata, g_free, pktsize, offset, ret));
|
gst_memory_new_wrapped (0, pktdata, g_free, pktsize, offset, ret));
|
||||||
|
|
||||||
/* use buffer metadata so receivers can also track the address */
|
/* use buffer metadata so receivers can also track the address */
|
||||||
meta = gst_buffer_add_net_address_meta (outbuf);
|
if (saddr) {
|
||||||
|
gst_buffer_add_net_address_meta (outbuf, saddr);
|
||||||
|
g_object_unref (saddr);
|
||||||
|
}
|
||||||
|
saddr = NULL;
|
||||||
|
|
||||||
switch (sa.sa.sa_family) {
|
|
||||||
case AF_INET:
|
|
||||||
{
|
|
||||||
gst_net_address_set_ip4_address (&meta->naddr, sa.sa_in.sin_addr.s_addr,
|
|
||||||
sa.sa_in.sin_port);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case AF_INET6:
|
|
||||||
{
|
|
||||||
guint8 ip6[16];
|
|
||||||
|
|
||||||
memcpy (ip6, &sa.sa_in6.sin6_addr, sizeof (ip6));
|
|
||||||
gst_net_address_set_ip6_address (&meta->naddr, ip6, sa.sa_in6.sin6_port);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
#ifdef G_OS_WIN32
|
|
||||||
WSASetLastError (WSAEAFNOSUPPORT);
|
|
||||||
#else
|
|
||||||
errno = EAFNOSUPPORT;
|
|
||||||
#endif
|
|
||||||
goto receive_error;
|
|
||||||
}
|
|
||||||
GST_LOG_OBJECT (udpsrc, "read %d bytes", (int) readsize);
|
GST_LOG_OBJECT (udpsrc, "read %d bytes", (int) readsize);
|
||||||
|
|
||||||
*buf = GST_BUFFER_CAST (outbuf);
|
*buf = GST_BUFFER_CAST (outbuf);
|
||||||
|
@ -573,7 +478,8 @@ no_select:
|
||||||
select_error:
|
select_error:
|
||||||
{
|
{
|
||||||
GST_ELEMENT_ERROR (udpsrc, RESOURCE, READ, (NULL),
|
GST_ELEMENT_ERROR (udpsrc, RESOURCE, READ, (NULL),
|
||||||
("select error %d: %s (%d)", ret, g_strerror (errno), errno));
|
("select error: %s", err->message));
|
||||||
|
g_clear_error (&err);
|
||||||
return GST_FLOW_ERROR;
|
return GST_FLOW_ERROR;
|
||||||
}
|
}
|
||||||
stopped:
|
stopped:
|
||||||
|
@ -581,24 +487,27 @@ stopped:
|
||||||
GST_DEBUG ("stop called");
|
GST_DEBUG ("stop called");
|
||||||
return GST_FLOW_WRONG_STATE;
|
return GST_FLOW_WRONG_STATE;
|
||||||
}
|
}
|
||||||
ioctl_failed:
|
get_available_error:
|
||||||
{
|
{
|
||||||
GST_ELEMENT_ERROR (udpsrc, RESOURCE, READ, (NULL),
|
GST_ELEMENT_ERROR (udpsrc, RESOURCE, READ, (NULL),
|
||||||
("ioctl failed %d: %s (%d)", ret, g_strerror (errno), errno));
|
("get available bytes failed"));
|
||||||
return GST_FLOW_ERROR;
|
return GST_FLOW_ERROR;
|
||||||
}
|
}
|
||||||
receive_error:
|
receive_error:
|
||||||
{
|
{
|
||||||
g_free (pktdata);
|
g_free (pktdata);
|
||||||
#ifdef G_OS_WIN32
|
|
||||||
|
if (g_error_matches (err, G_IO_ERROR, G_IO_ERROR_BUSY) ||
|
||||||
|
g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
|
||||||
|
g_clear_error (&err);
|
||||||
|
return GST_FLOW_WRONG_STATE;
|
||||||
|
} else {
|
||||||
GST_ELEMENT_ERROR (udpsrc, RESOURCE, READ, (NULL),
|
GST_ELEMENT_ERROR (udpsrc, RESOURCE, READ, (NULL),
|
||||||
("receive error %d (WSA error: %d)", ret, WSAGetLastError ()));
|
("receive error %d: %s", ret, err->message));
|
||||||
#else
|
g_clear_error (&err);
|
||||||
GST_ELEMENT_ERROR (udpsrc, RESOURCE, READ, (NULL),
|
|
||||||
("receive error %d: %s (%d)", ret, g_strerror (errno), errno));
|
|
||||||
#endif
|
|
||||||
return GST_FLOW_ERROR;
|
return GST_FLOW_ERROR;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
skip_error:
|
skip_error:
|
||||||
{
|
{
|
||||||
GST_ELEMENT_ERROR (udpsrc, STREAM, DECODE, (NULL),
|
GST_ELEMENT_ERROR (udpsrc, STREAM, DECODE, (NULL),
|
||||||
|
@ -610,11 +519,21 @@ skip_error:
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_udpsrc_set_uri (GstUDPSrc * src, const gchar * uri, GError ** error)
|
gst_udpsrc_set_uri (GstUDPSrc * src, const gchar * uri, GError ** error)
|
||||||
{
|
{
|
||||||
if (gst_udp_parse_uri (uri, &src->uri) < 0)
|
gchar *host;
|
||||||
|
guint16 port;
|
||||||
|
|
||||||
|
if (!gst_udp_parse_uri (uri, &host, &port))
|
||||||
goto wrong_uri;
|
goto wrong_uri;
|
||||||
|
|
||||||
if (src->uri.port == -1)
|
if (port == -1)
|
||||||
src->uri.port = UDP_DEFAULT_PORT;
|
port = UDP_DEFAULT_PORT;
|
||||||
|
|
||||||
|
g_free (src->host);
|
||||||
|
src->host = host;
|
||||||
|
src->port = port;
|
||||||
|
|
||||||
|
g_free (src->uri);
|
||||||
|
src->uri = g_strdup (uri);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
|
@ -640,16 +559,22 @@ gst_udpsrc_set_property (GObject * object, guint prop_id, const GValue * value,
|
||||||
udpsrc->buffer_size = g_value_get_int (value);
|
udpsrc->buffer_size = g_value_get_int (value);
|
||||||
break;
|
break;
|
||||||
case PROP_PORT:
|
case PROP_PORT:
|
||||||
gst_udp_uri_update (&udpsrc->uri, NULL, g_value_get_int (value));
|
udpsrc->port = g_value_get_int (value);
|
||||||
|
g_free (udpsrc->uri);
|
||||||
|
udpsrc->uri = g_strdup_printf ("udp://%s:%u", udpsrc->host, udpsrc->port);
|
||||||
break;
|
break;
|
||||||
case PROP_MULTICAST_GROUP:
|
case PROP_MULTICAST_GROUP:
|
||||||
{
|
{
|
||||||
const gchar *group;
|
const gchar *group;
|
||||||
|
|
||||||
|
g_free (udpsrc->host);
|
||||||
if ((group = g_value_get_string (value)))
|
if ((group = g_value_get_string (value)))
|
||||||
gst_udp_uri_update (&udpsrc->uri, group, -1);
|
udpsrc->host = g_strdup (group);
|
||||||
else
|
else
|
||||||
gst_udp_uri_update (&udpsrc->uri, UDP_DEFAULT_MULTICAST_GROUP, -1);
|
udpsrc->host = g_strdup (UDP_DEFAULT_MULTICAST_GROUP);
|
||||||
|
|
||||||
|
g_free (udpsrc->uri);
|
||||||
|
udpsrc->uri = g_strdup_printf ("udp://%s:%u", udpsrc->host, udpsrc->port);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case PROP_MULTICAST_IFACE:
|
case PROP_MULTICAST_IFACE:
|
||||||
|
@ -684,12 +609,21 @@ gst_udpsrc_set_property (GObject * object, guint prop_id, const GValue * value,
|
||||||
gst_pad_set_caps (GST_BASE_SRC (udpsrc)->srcpad, new_caps);
|
gst_pad_set_caps (GST_BASE_SRC (udpsrc)->srcpad, new_caps);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case PROP_SOCKFD:
|
case PROP_SOCKET:
|
||||||
if (udpsrc->sockfd >= 0 && udpsrc->sockfd != udpsrc->sock.fd &&
|
if (udpsrc->socket != NULL && udpsrc->socket != udpsrc->used_socket &&
|
||||||
udpsrc->closefd)
|
udpsrc->close_socket) {
|
||||||
CLOSE_SOCKET (udpsrc->sockfd);
|
GError *err = NULL;
|
||||||
udpsrc->sockfd = g_value_get_int (value);
|
|
||||||
GST_DEBUG ("setting SOCKFD to %d", udpsrc->sockfd);
|
if (!g_socket_close (udpsrc->socket, &err)) {
|
||||||
|
GST_ERROR ("failed to close socket %p: %s", udpsrc->socket,
|
||||||
|
err->message);
|
||||||
|
g_clear_error (&err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (udpsrc->socket)
|
||||||
|
g_object_unref (udpsrc->socket);
|
||||||
|
udpsrc->socket = g_value_dup_object (value);
|
||||||
|
GST_DEBUG ("setting socket to %p", udpsrc->socket);
|
||||||
break;
|
break;
|
||||||
case PROP_TIMEOUT:
|
case PROP_TIMEOUT:
|
||||||
udpsrc->timeout = g_value_get_uint64 (value);
|
udpsrc->timeout = g_value_get_uint64 (value);
|
||||||
|
@ -697,8 +631,8 @@ gst_udpsrc_set_property (GObject * object, guint prop_id, const GValue * value,
|
||||||
case PROP_SKIP_FIRST_BYTES:
|
case PROP_SKIP_FIRST_BYTES:
|
||||||
udpsrc->skip_first_bytes = g_value_get_int (value);
|
udpsrc->skip_first_bytes = g_value_get_int (value);
|
||||||
break;
|
break;
|
||||||
case PROP_CLOSEFD:
|
case PROP_CLOSE_SOCKET:
|
||||||
udpsrc->closefd = g_value_get_boolean (value);
|
udpsrc->close_socket = g_value_get_boolean (value);
|
||||||
break;
|
break;
|
||||||
case PROP_AUTO_MULTICAST:
|
case PROP_AUTO_MULTICAST:
|
||||||
udpsrc->auto_multicast = g_value_get_boolean (value);
|
udpsrc->auto_multicast = g_value_get_boolean (value);
|
||||||
|
@ -722,22 +656,22 @@ gst_udpsrc_get_property (GObject * object, guint prop_id, GValue * value,
|
||||||
g_value_set_int (value, udpsrc->buffer_size);
|
g_value_set_int (value, udpsrc->buffer_size);
|
||||||
break;
|
break;
|
||||||
case PROP_PORT:
|
case PROP_PORT:
|
||||||
g_value_set_int (value, udpsrc->uri.port);
|
g_value_set_int (value, udpsrc->port);
|
||||||
break;
|
break;
|
||||||
case PROP_MULTICAST_GROUP:
|
case PROP_MULTICAST_GROUP:
|
||||||
g_value_set_string (value, udpsrc->uri.host);
|
g_value_set_string (value, udpsrc->host);
|
||||||
break;
|
break;
|
||||||
case PROP_MULTICAST_IFACE:
|
case PROP_MULTICAST_IFACE:
|
||||||
g_value_set_string (value, udpsrc->multi_iface);
|
g_value_set_string (value, udpsrc->multi_iface);
|
||||||
break;
|
break;
|
||||||
case PROP_URI:
|
case PROP_URI:
|
||||||
g_value_take_string (value, gst_udp_uri_string (&udpsrc->uri));
|
g_value_take_string (value, udpsrc->uri);
|
||||||
break;
|
break;
|
||||||
case PROP_CAPS:
|
case PROP_CAPS:
|
||||||
gst_value_set_caps (value, udpsrc->caps);
|
gst_value_set_caps (value, udpsrc->caps);
|
||||||
break;
|
break;
|
||||||
case PROP_SOCKFD:
|
case PROP_SOCKET:
|
||||||
g_value_set_int (value, udpsrc->sockfd);
|
g_value_set_object (value, udpsrc->socket);
|
||||||
break;
|
break;
|
||||||
case PROP_TIMEOUT:
|
case PROP_TIMEOUT:
|
||||||
g_value_set_uint64 (value, udpsrc->timeout);
|
g_value_set_uint64 (value, udpsrc->timeout);
|
||||||
|
@ -745,11 +679,11 @@ gst_udpsrc_get_property (GObject * object, guint prop_id, GValue * value,
|
||||||
case PROP_SKIP_FIRST_BYTES:
|
case PROP_SKIP_FIRST_BYTES:
|
||||||
g_value_set_int (value, udpsrc->skip_first_bytes);
|
g_value_set_int (value, udpsrc->skip_first_bytes);
|
||||||
break;
|
break;
|
||||||
case PROP_CLOSEFD:
|
case PROP_CLOSE_SOCKET:
|
||||||
g_value_set_boolean (value, udpsrc->closefd);
|
g_value_set_boolean (value, udpsrc->close_socket);
|
||||||
break;
|
break;
|
||||||
case PROP_SOCK:
|
case PROP_USED_SOCKET:
|
||||||
g_value_set_int (value, udpsrc->sock.fd);
|
g_value_set_object (value, udpsrc->used_socket);
|
||||||
break;
|
break;
|
||||||
case PROP_AUTO_MULTICAST:
|
case PROP_AUTO_MULTICAST:
|
||||||
g_value_set_boolean (value, udpsrc->auto_multicast);
|
g_value_set_boolean (value, udpsrc->auto_multicast);
|
||||||
|
@ -767,85 +701,93 @@ gst_udpsrc_get_property (GObject * object, guint prop_id, GValue * value,
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_udpsrc_start (GstBaseSrc * bsrc)
|
gst_udpsrc_start (GstBaseSrc * bsrc)
|
||||||
{
|
{
|
||||||
guint bc_val;
|
|
||||||
guint err_val;
|
|
||||||
gint reuse;
|
|
||||||
int port;
|
|
||||||
GstUDPSrc *src;
|
GstUDPSrc *src;
|
||||||
gint ret;
|
GInetAddress *addr, *bind_addr;
|
||||||
int rcvsize;
|
GSocketAddress *bind_saddr;
|
||||||
struct sockaddr_storage bind_address;
|
GResolver *resolver;
|
||||||
socklen_t len;
|
GError *err = NULL;
|
||||||
|
|
||||||
src = GST_UDPSRC (bsrc);
|
src = GST_UDPSRC (bsrc);
|
||||||
|
|
||||||
if (src->sockfd == -1) {
|
if (src->socket == NULL) {
|
||||||
/* need to allocate a socket */
|
/* need to allocate a socket */
|
||||||
GST_DEBUG_OBJECT (src, "allocating socket for %s:%d", src->uri.host,
|
GST_DEBUG_OBJECT (src, "allocating socket for %s:%d", src->host, src->port);
|
||||||
src->uri.port);
|
|
||||||
if ((ret =
|
|
||||||
gst_udp_get_addr (src->uri.host, src->uri.port, &src->myaddr)) < 0)
|
|
||||||
goto getaddrinfo_error;
|
|
||||||
|
|
||||||
if ((ret = socket (src->myaddr.ss_family, SOCK_DGRAM, IPPROTO_UDP)) < 0)
|
addr = g_inet_address_new_from_string (src->host);
|
||||||
goto no_socket;
|
if (!addr) {
|
||||||
|
GList *results;
|
||||||
|
|
||||||
src->sock.fd = ret;
|
resolver = g_resolver_get_default ();
|
||||||
src->externalfd = FALSE;
|
results =
|
||||||
|
g_resolver_lookup_by_name (resolver, src->host, src->cancellable,
|
||||||
|
&err);
|
||||||
|
if (!results)
|
||||||
|
goto name_resolve;
|
||||||
|
addr = G_INET_ADDRESS (g_object_ref (results->data));
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (src, "got socket %d", src->sock.fd);
|
g_resolver_free_addresses (results);
|
||||||
|
g_object_unref (resolver);
|
||||||
GST_DEBUG_OBJECT (src, "setting reuse %d", src->reuse);
|
|
||||||
reuse = src->reuse ? 1 : 0;
|
|
||||||
if ((ret =
|
|
||||||
setsockopt (src->sock.fd, SOL_SOCKET, SO_REUSEADDR, &reuse,
|
|
||||||
sizeof (reuse))) < 0)
|
|
||||||
goto setsockopt_error;
|
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (src, "binding on port %d", src->uri.port);
|
|
||||||
|
|
||||||
/* Take a temporary copy of the address in case we need to fix it for bind */
|
|
||||||
memcpy (&bind_address, &src->myaddr, sizeof (struct sockaddr_storage));
|
|
||||||
|
|
||||||
#ifdef G_OS_WIN32
|
|
||||||
/* Windows does not allow binding to a multicast group so fix source address */
|
|
||||||
if (gst_udp_is_multicast (&src->myaddr)) {
|
|
||||||
switch (((struct sockaddr *) &bind_address)->sa_family) {
|
|
||||||
case AF_INET:
|
|
||||||
((struct sockaddr_in *) &bind_address)->sin_addr.s_addr =
|
|
||||||
htonl (INADDR_ANY);
|
|
||||||
break;
|
|
||||||
case AF_INET6:
|
|
||||||
((struct sockaddr_in6 *) &bind_address)->sin6_addr = in6addr_any;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
#ifndef GST_DISABLE_GST_DEBUG
|
||||||
|
{
|
||||||
|
gchar *ip = g_inet_address_to_string (addr);
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (src, "IP address for host %s is %s", src->host, ip);
|
||||||
|
g_free (ip);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
len = gst_udp_get_sockaddr_length (&bind_address);
|
if ((src->used_socket =
|
||||||
if ((ret = bind (src->sock.fd, (struct sockaddr *) &bind_address, len)) < 0)
|
g_socket_new (g_inet_address_get_family (addr),
|
||||||
|
G_SOCKET_TYPE_DATAGRAM, G_SOCKET_PROTOCOL_UDP, &err)) == NULL)
|
||||||
|
goto no_socket;
|
||||||
|
|
||||||
|
src->external_socket = FALSE;
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (src, "got socket %p", src->used_socket);
|
||||||
|
|
||||||
|
if (src->addr)
|
||||||
|
g_object_unref (src->addr);
|
||||||
|
src->addr =
|
||||||
|
G_INET_SOCKET_ADDRESS (g_inet_socket_address_new (addr, src->port));
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (src, "binding on port %d", src->port);
|
||||||
|
|
||||||
|
if (g_inet_address_get_is_multicast (addr))
|
||||||
|
bind_addr = g_inet_address_new_any (g_inet_address_get_family (addr));
|
||||||
|
else
|
||||||
|
bind_addr = G_INET_ADDRESS (g_object_ref (addr));
|
||||||
|
|
||||||
|
g_object_unref (addr);
|
||||||
|
|
||||||
|
bind_saddr = g_inet_socket_address_new (bind_addr, src->port);
|
||||||
|
g_object_unref (bind_addr);
|
||||||
|
if (!g_socket_bind (src->used_socket, bind_saddr, src->reuse, &err))
|
||||||
goto bind_error;
|
goto bind_error;
|
||||||
|
|
||||||
if (!gst_udp_is_multicast (&src->myaddr)) {
|
g_object_unref (bind_saddr);
|
||||||
len = sizeof (src->myaddr);
|
|
||||||
if ((ret = getsockname (src->sock.fd, (struct sockaddr *) &src->myaddr,
|
|
||||||
&len)) < 0)
|
|
||||||
goto getsockname_error;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
GST_DEBUG_OBJECT (src, "using provided socket %d", src->sockfd);
|
GST_DEBUG_OBJECT (src, "using provided socket %d", src->socket);
|
||||||
/* we use the configured socket, try to get some info about it */
|
/* we use the configured socket, try to get some info about it */
|
||||||
len = sizeof (src->myaddr);
|
src->used_socket = G_SOCKET (g_object_ref (src->socket));
|
||||||
if ((ret =
|
src->external_socket = TRUE;
|
||||||
getsockname (src->sockfd, (struct sockaddr *) &src->myaddr,
|
|
||||||
&len)) < 0)
|
|
||||||
goto getsockname_error;
|
|
||||||
|
|
||||||
src->sock.fd = src->sockfd;
|
if (src->addr)
|
||||||
src->externalfd = TRUE;
|
g_object_unref (src->addr);
|
||||||
|
src->addr =
|
||||||
|
G_INET_SOCKET_ADDRESS (g_socket_get_local_address (src->used_socket,
|
||||||
|
&err));
|
||||||
|
if (!src->addr)
|
||||||
|
goto getsockname_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (src->timeout)
|
||||||
|
g_socket_set_timeout (src->used_socket, src->timeout / GST_SECOND);
|
||||||
|
|
||||||
|
#ifdef SO_RECVBUF
|
||||||
|
{
|
||||||
|
gint rcvsize, ret;
|
||||||
|
|
||||||
len = sizeof (rcvsize);
|
len = sizeof (rcvsize);
|
||||||
if (src->buffer_size != 0) {
|
if (src->buffer_size != 0) {
|
||||||
rcvsize = src->buffer_size;
|
rcvsize = src->buffer_size;
|
||||||
|
@ -855,8 +797,8 @@ gst_udpsrc_start (GstBaseSrc * bsrc)
|
||||||
* maximum of around 100K. Also a minimum of 128 bytes is required on
|
* maximum of around 100K. Also a minimum of 128 bytes is required on
|
||||||
* Linux. */
|
* Linux. */
|
||||||
ret =
|
ret =
|
||||||
setsockopt (src->sock.fd, SOL_SOCKET, SO_RCVBUF, (void *) &rcvsize,
|
setsockopt (g_socket_get_fd (src->used_socket), SOL_SOCKET, SO_RCVBUF,
|
||||||
len);
|
(void *) &rcvsize, len);
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
GST_ELEMENT_WARNING (src, RESOURCE, SETTINGS, (NULL),
|
GST_ELEMENT_WARNING (src, RESOURCE, SETTINGS, (NULL),
|
||||||
("Could not create a buffer of requested %d bytes, %d: %s (%d)",
|
("Could not create a buffer of requested %d bytes, %d: %s (%d)",
|
||||||
|
@ -868,103 +810,92 @@ gst_udpsrc_start (GstBaseSrc * bsrc)
|
||||||
* value we set because the kernel allocates extra memory for metadata.
|
* value we set because the kernel allocates extra memory for metadata.
|
||||||
* The default on Linux is about 100K (which is about 50K without metadata) */
|
* The default on Linux is about 100K (which is about 50K without metadata) */
|
||||||
ret =
|
ret =
|
||||||
getsockopt (src->sock.fd, SOL_SOCKET, SO_RCVBUF, (void *) &rcvsize, &len);
|
getsockopt (g_socket_get_fd (src->used_socket), SOL_SOCKET, SO_RCVBUF,
|
||||||
|
(void *) &rcvsize, &len);
|
||||||
if (ret == 0)
|
if (ret == 0)
|
||||||
GST_DEBUG_OBJECT (src, "have udp buffer of %d bytes", rcvsize);
|
GST_DEBUG_OBJECT (src, "have udp buffer of %d bytes", rcvsize);
|
||||||
else
|
else
|
||||||
GST_DEBUG_OBJECT (src, "could not get udp buffer size");
|
GST_DEBUG_OBJECT (src, "could not get udp buffer size");
|
||||||
|
|
||||||
bc_val = 1;
|
|
||||||
if ((ret = setsockopt (src->sock.fd, SOL_SOCKET, SO_BROADCAST, &bc_val,
|
|
||||||
sizeof (bc_val))) < 0) {
|
|
||||||
GST_ELEMENT_WARNING (src, RESOURCE, SETTINGS, (NULL),
|
|
||||||
("could not configure socket for broadcast %d: %s (%d)", ret,
|
|
||||||
g_strerror (errno), errno));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Accept ERRQUEUE to get and flush icmp errors */
|
|
||||||
err_val = 1;
|
|
||||||
#if defined (IP_RECVERR)
|
|
||||||
if ((ret = setsockopt (src->sock.fd, IPPROTO_IP, IP_RECVERR, &err_val,
|
|
||||||
sizeof (err_val))) < 0) {
|
|
||||||
GST_ELEMENT_WARNING (src, RESOURCE, SETTINGS, (NULL),
|
|
||||||
("could not configure socket for IP_RECVERR %d: %s (%d)", ret,
|
|
||||||
g_strerror (errno), errno));
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (src->auto_multicast && gst_udp_is_multicast (&src->myaddr)) {
|
g_socket_set_broadcast (src->used_socket, TRUE);
|
||||||
GST_DEBUG_OBJECT (src, "joining multicast group %s", src->uri.host);
|
|
||||||
ret = gst_udp_join_group (src->sock.fd, &src->myaddr, src->multi_iface);
|
if (src->auto_multicast
|
||||||
if (ret < 0)
|
&&
|
||||||
|
g_inet_address_get_is_multicast (g_inet_socket_address_get_address
|
||||||
|
(src->addr))) {
|
||||||
|
GST_DEBUG_OBJECT (src, "joining multicast group %s", src->host);
|
||||||
|
if (!g_socket_join_multicast_group (src->used_socket,
|
||||||
|
g_inet_socket_address_get_address (src->addr),
|
||||||
|
FALSE, src->multi_iface, &err))
|
||||||
goto membership;
|
goto membership;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* NOTE: sockaddr_in.sin_port works for ipv4 and ipv6 because sin_port
|
/* NOTE: sockaddr_in.sin_port works for ipv4 and ipv6 because sin_port
|
||||||
* follows ss_family on both */
|
* follows ss_family on both */
|
||||||
port = g_ntohs (((struct sockaddr_in *) &src->myaddr)->sin_port);
|
{
|
||||||
|
GInetSocketAddress *addr;
|
||||||
|
guint16 port;
|
||||||
|
|
||||||
|
addr =
|
||||||
|
G_INET_SOCKET_ADDRESS (g_socket_get_local_address (src->used_socket,
|
||||||
|
&err));
|
||||||
|
if (!addr)
|
||||||
|
goto getsockname_error;
|
||||||
|
|
||||||
|
port = g_inet_socket_address_get_port (addr);
|
||||||
GST_DEBUG_OBJECT (src, "bound, on port %d", port);
|
GST_DEBUG_OBJECT (src, "bound, on port %d", port);
|
||||||
if (port != src->uri.port) {
|
if (port != src->port) {
|
||||||
src->uri.port = port;
|
src->port = port;
|
||||||
GST_DEBUG_OBJECT (src, "notifying port %d", port);
|
GST_DEBUG_OBJECT (src, "notifying port %d", port);
|
||||||
g_object_notify (G_OBJECT (src), "port");
|
g_object_notify (G_OBJECT (src), "port");
|
||||||
}
|
}
|
||||||
|
g_object_unref (addr);
|
||||||
if ((src->fdset = gst_poll_new (TRUE)) == NULL)
|
}
|
||||||
goto no_fdset;
|
|
||||||
|
|
||||||
gst_poll_add_fd (src->fdset, &src->sock);
|
|
||||||
gst_poll_fd_ctl_read (src->fdset, &src->sock, TRUE);
|
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
/* ERRORS */
|
/* ERRORS */
|
||||||
getaddrinfo_error:
|
name_resolve:
|
||||||
{
|
{
|
||||||
GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, (NULL),
|
GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, (NULL),
|
||||||
("getaddrinfo failed: %s (%d)", gai_strerror (ret), ret));
|
("Name resolval failed: %s", err->message));
|
||||||
|
g_clear_error (&err);
|
||||||
|
g_object_unref (resolver);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
no_socket:
|
no_socket:
|
||||||
{
|
{
|
||||||
GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL),
|
GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL),
|
||||||
("no socket error %d: %s (%d)", ret, g_strerror (errno), errno));
|
("no socket error: %s", err->message));
|
||||||
return FALSE;
|
g_clear_error (&err);
|
||||||
}
|
g_object_unref (addr);
|
||||||
setsockopt_error:
|
|
||||||
{
|
|
||||||
CLOSE_IF_REQUESTED (src);
|
|
||||||
GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, (NULL),
|
|
||||||
("setsockopt failed %d: %s (%d)", ret, g_strerror (errno), errno));
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
bind_error:
|
bind_error:
|
||||||
{
|
{
|
||||||
CLOSE_IF_REQUESTED (src);
|
gst_udpsrc_stop (GST_BASE_SRC (src));
|
||||||
GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, (NULL),
|
GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, (NULL),
|
||||||
("bind failed %d: %s (%d)", ret, g_strerror (errno), errno));
|
("bind failed: %s", err->message));
|
||||||
|
g_clear_error (&err);
|
||||||
|
g_object_unref (bind_saddr);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
membership:
|
membership:
|
||||||
{
|
{
|
||||||
CLOSE_IF_REQUESTED (src);
|
gst_udpsrc_stop (GST_BASE_SRC (src));
|
||||||
GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, (NULL),
|
GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, (NULL),
|
||||||
("could add membership %d: %s (%d)", ret, g_strerror (errno), errno));
|
("could add membership: %s", err->message));
|
||||||
|
g_clear_error (&err);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
getsockname_error:
|
getsockname_error:
|
||||||
{
|
{
|
||||||
CLOSE_IF_REQUESTED (src);
|
gst_udpsrc_stop (GST_BASE_SRC (src));
|
||||||
GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, (NULL),
|
GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, (NULL),
|
||||||
("getsockname failed %d: %s (%d)", ret, g_strerror (errno), errno));
|
("getsockname failed: %s", err->message));
|
||||||
return FALSE;
|
g_clear_error (&err);
|
||||||
}
|
|
||||||
no_fdset:
|
|
||||||
{
|
|
||||||
CLOSE_IF_REQUESTED (src);
|
|
||||||
GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ_WRITE, (NULL),
|
|
||||||
("could not create an fdset %d: %s (%d)", ret, g_strerror (errno),
|
|
||||||
errno));
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -977,7 +908,7 @@ gst_udpsrc_unlock (GstBaseSrc * bsrc)
|
||||||
src = GST_UDPSRC (bsrc);
|
src = GST_UDPSRC (bsrc);
|
||||||
|
|
||||||
GST_LOG_OBJECT (src, "Flushing");
|
GST_LOG_OBJECT (src, "Flushing");
|
||||||
gst_poll_set_flushing (src->fdset, TRUE);
|
g_cancellable_cancel (src->cancellable);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
@ -990,7 +921,7 @@ gst_udpsrc_unlock_stop (GstBaseSrc * bsrc)
|
||||||
src = GST_UDPSRC (bsrc);
|
src = GST_UDPSRC (bsrc);
|
||||||
|
|
||||||
GST_LOG_OBJECT (src, "No longer flushing");
|
GST_LOG_OBJECT (src, "No longer flushing");
|
||||||
gst_poll_set_flushing (src->fdset, FALSE);
|
g_cancellable_reset (src->cancellable);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
@ -1004,17 +935,36 @@ gst_udpsrc_stop (GstBaseSrc * bsrc)
|
||||||
|
|
||||||
GST_DEBUG ("stopping, closing sockets");
|
GST_DEBUG ("stopping, closing sockets");
|
||||||
|
|
||||||
if (src->sock.fd >= 0) {
|
if (src->used_socket) {
|
||||||
if (src->auto_multicast && gst_udp_is_multicast (&src->myaddr)) {
|
if (src->auto_multicast
|
||||||
GST_DEBUG_OBJECT (src, "leaving multicast group %s", src->uri.host);
|
&&
|
||||||
gst_udp_leave_group (src->sock.fd, &src->myaddr);
|
g_inet_address_get_is_multicast (g_inet_socket_address_get_address
|
||||||
|
(src->addr))) {
|
||||||
|
GError *err = NULL;
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (src, "leaving multicast group %s", src->host);
|
||||||
|
|
||||||
|
if (!g_socket_leave_multicast_group (src->used_socket,
|
||||||
|
g_inet_socket_address_get_address (src->addr), FALSE,
|
||||||
|
src->multi_iface, NULL)) {
|
||||||
|
GST_ERROR_OBJECT (src, "Failed to leave multicast group: %s",
|
||||||
|
err->message);
|
||||||
|
g_clear_error (&err);
|
||||||
}
|
}
|
||||||
CLOSE_IF_REQUESTED (src);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (src->fdset) {
|
if (src->close_socket || !src->external_socket) {
|
||||||
gst_poll_free (src->fdset);
|
GError *err = NULL;
|
||||||
src->fdset = NULL;
|
if (!g_socket_close (src->used_socket, &err)) {
|
||||||
|
GST_ERROR_OBJECT (src, "Failed to close socket: %s", err->message);
|
||||||
|
g_clear_error (&err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
g_object_unref (src->used_socket);
|
||||||
|
src->used_socket = NULL;
|
||||||
|
g_object_unref (src->addr);
|
||||||
|
src->addr = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
@ -1041,11 +991,7 @@ gst_udpsrc_uri_get_uri (GstURIHandler * handler)
|
||||||
{
|
{
|
||||||
GstUDPSrc *src = GST_UDPSRC (handler);
|
GstUDPSrc *src = GST_UDPSRC (handler);
|
||||||
|
|
||||||
/* FIXME: make thread-safe; maybe we can get rid of this assignment here? */
|
return g_strdup (src->uri);
|
||||||
g_free (src->uristr);
|
|
||||||
src->uristr = gst_udp_uri_string (&src->uri);
|
|
||||||
|
|
||||||
return g_strdup (src->uristr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
|
|
|
@ -23,15 +23,11 @@
|
||||||
|
|
||||||
#include <gst/gst.h>
|
#include <gst/gst.h>
|
||||||
#include <gst/base/gstpushsrc.h>
|
#include <gst/base/gstpushsrc.h>
|
||||||
|
#include <gio/gio.h>
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
#include <errno.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
|
|
||||||
#include "gstudpnetutils.h"
|
#include "gstudpnetutils.h"
|
||||||
|
|
||||||
#include "gstudp.h"
|
#include "gstudp.h"
|
||||||
|
|
||||||
#define GST_TYPE_UDPSRC \
|
#define GST_TYPE_UDPSRC \
|
||||||
|
@ -53,27 +49,26 @@ struct _GstUDPSrc {
|
||||||
GstPushSrc parent;
|
GstPushSrc parent;
|
||||||
|
|
||||||
/* properties */
|
/* properties */
|
||||||
GstUDPUri uri;
|
gchar *host;
|
||||||
|
gint port;
|
||||||
gchar *multi_iface;
|
gchar *multi_iface;
|
||||||
gint ttl;
|
gint ttl;
|
||||||
GstCaps *caps;
|
GstCaps *caps;
|
||||||
gint buffer_size;
|
gint buffer_size;
|
||||||
guint64 timeout;
|
guint64 timeout;
|
||||||
gint skip_first_bytes;
|
gint skip_first_bytes;
|
||||||
int sockfd;
|
GSocket *socket;
|
||||||
gboolean closefd;
|
gboolean close_socket;
|
||||||
gboolean auto_multicast;
|
gboolean auto_multicast;
|
||||||
gboolean reuse;
|
gboolean reuse;
|
||||||
|
|
||||||
/* our sockets */
|
/* our sockets */
|
||||||
GstPollFD sock;
|
GSocket *used_socket;
|
||||||
GstPoll *fdset;
|
GCancellable *cancellable;
|
||||||
gboolean externalfd;
|
GInetSocketAddress *addr;
|
||||||
gboolean is_ipv6;
|
gboolean external_socket;
|
||||||
|
|
||||||
struct sockaddr_storage myaddr;
|
gchar *uri;
|
||||||
|
|
||||||
gchar *uristr;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _GstUDPSrcClass {
|
struct _GstUDPSrcClass {
|
||||||
|
|
Loading…
Reference in a new issue