2 * Copyright (C) <2005> Philippe Khalaf <burger@speedy.org>
3 * Copyright (C) <2005> Nokia Corporation <kai.vehmanen@nokia.com>
4 * Copyright (C) <2006> Joni Valtanen <joni.valtanen@movial.fi>
5 * Copyright (C) <2012> Collabora Ltd.
6 * Author: Sebastian Dröge <sebastian.droege@collabora.co.uk>
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
18 * You should have received a copy of the GNU Library General Public
19 * License along with this library; if not, write to the
20 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 * Boston, MA 02111-1307, USA.
27 #include "gstudp-marshal.h"
28 #include "gstdynudpsink.h"
30 #include <gst/net/gstnetaddressmeta.h>
32 GST_DEBUG_CATEGORY_STATIC (dynudpsink_debug);
33 #define GST_CAT_DEFAULT (dynudpsink_debug)
35 static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
40 /* DynUDPSink signals and args */
52 #define UDP_DEFAULT_SOCKET NULL
53 #define UDP_DEFAULT_CLOSE_SOCKET TRUE
62 static void gst_dynudpsink_finalize (GObject * object);
64 static GstFlowReturn gst_dynudpsink_render (GstBaseSink * sink,
66 static gboolean gst_dynudpsink_stop (GstBaseSink * bsink);
67 static gboolean gst_dynudpsink_start (GstBaseSink * bsink);
68 static gboolean gst_dynudpsink_unlock (GstBaseSink * bsink);
69 static gboolean gst_dynudpsink_unlock_stop (GstBaseSink * bsink);
71 static void gst_dynudpsink_set_property (GObject * object, guint prop_id,
72 const GValue * value, GParamSpec * pspec);
73 static void gst_dynudpsink_get_property (GObject * object, guint prop_id,
74 GValue * value, GParamSpec * pspec);
76 static guint gst_dynudpsink_signals[LAST_SIGNAL] = { 0 };
78 #define gst_dynudpsink_parent_class parent_class
79 G_DEFINE_TYPE (GstDynUDPSink, gst_dynudpsink, GST_TYPE_BASE_SINK);
82 gst_dynudpsink_class_init (GstDynUDPSinkClass * klass)
84 GObjectClass *gobject_class;
85 GstElementClass *gstelement_class;
86 GstBaseSinkClass *gstbasesink_class;
88 gobject_class = (GObjectClass *) klass;
89 gstelement_class = (GstElementClass *) klass;
90 gstbasesink_class = (GstBaseSinkClass *) klass;
92 parent_class = g_type_class_peek_parent (klass);
94 gobject_class->set_property = gst_dynudpsink_set_property;
95 gobject_class->get_property = gst_dynudpsink_get_property;
96 gobject_class->finalize = gst_dynudpsink_finalize;
98 gst_dynudpsink_signals[SIGNAL_GET_STATS] =
99 g_signal_new ("get-stats", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
100 G_STRUCT_OFFSET (GstDynUDPSinkClass, get_stats),
101 NULL, NULL, gst_udp_marshal_BOXED__STRING_INT, G_TYPE_VALUE_ARRAY, 2,
102 G_TYPE_STRING, G_TYPE_INT);
104 g_object_class_install_property (gobject_class, PROP_SOCKET,
105 g_param_spec_object ("socket", "Socket",
106 "Socket to use for UDP sending. (NULL == allocate)",
107 G_TYPE_SOCKET, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
108 g_object_class_install_property (gobject_class, PROP_CLOSE_SOCKET,
109 g_param_spec_boolean ("close-socket", "Close socket",
110 "Close socket if passed as property on state change",
111 UDP_DEFAULT_CLOSE_SOCKET,
112 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
114 gst_element_class_add_pad_template (gstelement_class,
115 gst_static_pad_template_get (&sink_template));
117 gst_element_class_set_details_simple (gstelement_class, "UDP packet sender",
119 "Send data over the network via UDP",
120 "Philippe Khalaf <burger@speedy.org>");
122 gstbasesink_class->render = gst_dynudpsink_render;
123 gstbasesink_class->start = gst_dynudpsink_start;
124 gstbasesink_class->stop = gst_dynudpsink_stop;
125 gstbasesink_class->unlock = gst_dynudpsink_unlock;
126 gstbasesink_class->unlock_stop = gst_dynudpsink_unlock_stop;
128 GST_DEBUG_CATEGORY_INIT (dynudpsink_debug, "dynudpsink", 0, "UDP sink");
132 gst_dynudpsink_init (GstDynUDPSink * sink)
134 sink->socket = UDP_DEFAULT_SOCKET;
135 sink->close_socket = UDP_DEFAULT_CLOSE_SOCKET;
136 sink->external_socket = FALSE;
138 sink->used_socket = NULL;
139 sink->cancellable = g_cancellable_new ();
140 sink->family = G_SOCKET_FAMILY_IPV6;
144 gst_dynudpsink_finalize (GObject * object)
148 sink = GST_DYNUDPSINK (object);
150 if (sink->cancellable)
151 g_object_unref (sink->cancellable);
152 sink->cancellable = NULL;
155 g_object_unref (sink->socket);
158 if (sink->used_socket)
159 g_object_unref (sink->used_socket);
160 sink->used_socket = NULL;
162 G_OBJECT_CLASS (parent_class)->finalize (object);
166 gst_dynudpsink_render (GstBaseSink * bsink, GstBuffer * buffer)
172 GstNetAddressMeta *meta;
173 GSocketAddress *addr;
175 GSocketFamily family;
177 meta = gst_buffer_get_net_address_meta (buffer);
180 GST_DEBUG ("Received buffer is not a GstNetBuffer, skipping");
184 sink = GST_DYNUDPSINK (bsink);
186 /* let's get the address from the metadata */
189 family = g_socket_address_get_family (addr);
190 if (sink->family != family && family != G_SOCKET_FAMILY_IPV4)
193 data = gst_buffer_map (buffer, &size, NULL, GST_MAP_READ);
195 GST_DEBUG ("about to send %" G_GSIZE_FORMAT " bytes", size);
197 #ifndef GST_DISABLE_GST_DEBUG
202 g_inet_address_to_string (g_inet_socket_address_get_address
203 (G_INET_SOCKET_ADDRESS (addr)));
204 GST_DEBUG ("sending %" G_GSIZE_FORMAT " bytes to client %s port %d", size,
205 host, g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (addr)));
211 g_socket_send_to (sink->used_socket, addr, (gchar *) data, size,
212 sink->cancellable, &err);
213 gst_buffer_unmap (buffer, data, size);
218 GST_DEBUG ("sent %" G_GSSIZE_FORMAT " bytes", ret);
224 GST_DEBUG ("got send error %s", err->message);
225 g_clear_error (&err);
226 return GST_FLOW_ERROR;
230 GST_DEBUG ("invalid family (got %d, expected %d)",
231 g_socket_address_get_family (addr), sink->family);
232 return GST_FLOW_ERROR;
237 gst_dynudpsink_set_property (GObject * object, guint prop_id,
238 const GValue * value, GParamSpec * pspec)
240 GstDynUDPSink *udpsink;
242 udpsink = GST_DYNUDPSINK (object);
246 if (udpsink->socket != NULL && udpsink->socket != udpsink->used_socket &&
247 udpsink->close_socket) {
250 if (!g_socket_close (udpsink->socket, &err)) {
251 GST_ERROR ("failed to close socket %p: %s", udpsink->socket,
253 g_clear_error (&err);
257 g_object_unref (udpsink->socket);
258 udpsink->socket = g_value_dup_object (value);
259 GST_DEBUG ("setting socket to %p", udpsink->socket);
261 case PROP_CLOSE_SOCKET:
262 udpsink->close_socket = g_value_get_boolean (value);
265 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
271 gst_dynudpsink_get_property (GObject * object, guint prop_id, GValue * value,
274 GstDynUDPSink *udpsink;
276 udpsink = GST_DYNUDPSINK (object);
280 g_value_set_object (value, udpsink->socket);
282 case PROP_CLOSE_SOCKET:
283 g_value_set_boolean (value, udpsink->close_socket);
286 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
291 /* create a socket for sending to remote machine */
293 gst_dynudpsink_start (GstBaseSink * bsink)
295 GstDynUDPSink *udpsink;
298 udpsink = GST_DYNUDPSINK (bsink);
300 if (udpsink->socket == NULL) {
301 /* create sender socket if none available, first try IPv6, then
302 * fall-back to IPv4 */
303 udpsink->family = G_SOCKET_FAMILY_IPV6;
304 if ((udpsink->used_socket =
305 g_socket_new (G_SOCKET_FAMILY_IPV6,
306 G_SOCKET_TYPE_DATAGRAM, G_SOCKET_PROTOCOL_UDP, &err)) == NULL) {
307 udpsink->family = G_SOCKET_FAMILY_IPV4;
308 if ((udpsink->used_socket = g_socket_new (G_SOCKET_FAMILY_IPV4,
309 G_SOCKET_TYPE_DATAGRAM, G_SOCKET_PROTOCOL_UDP, &err)) == NULL)
313 udpsink->external_socket = FALSE;
315 udpsink->used_socket = G_SOCKET (g_object_ref (udpsink->socket));
316 udpsink->external_socket = TRUE;
317 udpsink->family = g_socket_get_family (udpsink->used_socket);
320 g_socket_set_broadcast (udpsink->used_socket, TRUE);
327 GST_ERROR_OBJECT (udpsink, "Failed to create socket: %s", err->message);
328 g_clear_error (&err);
334 gst_dynudpsink_get_stats (GstDynUDPSink * sink, const gchar * host, gint port)
340 gst_dynudpsink_stop (GstBaseSink * bsink)
342 GstDynUDPSink *udpsink;
344 udpsink = GST_DYNUDPSINK (bsink);
346 if (udpsink->used_socket) {
347 if (udpsink->close_socket || !udpsink->external_socket) {
350 if (!g_socket_close (udpsink->used_socket, &err)) {
351 GST_ERROR_OBJECT (udpsink, "Failed to close socket: %s", err->message);
352 g_clear_error (&err);
356 g_object_unref (udpsink->used_socket);
357 udpsink->used_socket = NULL;
364 gst_dynudpsink_unlock (GstBaseSink * bsink)
366 GstDynUDPSink *udpsink;
368 udpsink = GST_DYNUDPSINK (bsink);
370 g_cancellable_cancel (udpsink->cancellable);
376 gst_dynudpsink_unlock_stop (GstBaseSink * bsink)
378 GstDynUDPSink *udpsink;
380 udpsink = GST_DYNUDPSINK (bsink);
382 g_cancellable_reset (udpsink->cancellable);