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.
24 /* FIXME 0.11: suppress warnings for deprecated API such as GValueArray
25 * with newer GLib versions (>= 2.31.0) */
26 #define GLIB_DISABLE_DEPRECATION_WARNINGS
31 #include "gstudp-marshal.h"
32 #include "gstdynudpsink.h"
34 #include <gst/net/gstnetaddressmeta.h>
36 GST_DEBUG_CATEGORY_STATIC (dynudpsink_debug);
37 #define GST_CAT_DEFAULT (dynudpsink_debug)
39 static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
44 /* DynUDPSink signals and args */
56 #define UDP_DEFAULT_SOCKET NULL
57 #define UDP_DEFAULT_CLOSE_SOCKET TRUE
66 static void gst_dynudpsink_finalize (GObject * object);
68 static GstFlowReturn gst_dynudpsink_render (GstBaseSink * sink,
70 static gboolean gst_dynudpsink_stop (GstBaseSink * bsink);
71 static gboolean gst_dynudpsink_start (GstBaseSink * bsink);
72 static gboolean gst_dynudpsink_unlock (GstBaseSink * bsink);
73 static gboolean gst_dynudpsink_unlock_stop (GstBaseSink * bsink);
75 static void gst_dynudpsink_set_property (GObject * object, guint prop_id,
76 const GValue * value, GParamSpec * pspec);
77 static void gst_dynudpsink_get_property (GObject * object, guint prop_id,
78 GValue * value, GParamSpec * pspec);
79 static GstStructure *gst_dynudpsink_get_stats (GstDynUDPSink * sink,
80 const gchar * host, gint port);
82 static guint gst_dynudpsink_signals[LAST_SIGNAL] = { 0 };
84 #define gst_dynudpsink_parent_class parent_class
85 G_DEFINE_TYPE (GstDynUDPSink, gst_dynudpsink, GST_TYPE_BASE_SINK);
88 gst_dynudpsink_class_init (GstDynUDPSinkClass * klass)
90 GObjectClass *gobject_class;
91 GstElementClass *gstelement_class;
92 GstBaseSinkClass *gstbasesink_class;
94 gobject_class = (GObjectClass *) klass;
95 gstelement_class = (GstElementClass *) klass;
96 gstbasesink_class = (GstBaseSinkClass *) klass;
98 parent_class = g_type_class_peek_parent (klass);
100 gobject_class->set_property = gst_dynudpsink_set_property;
101 gobject_class->get_property = gst_dynudpsink_get_property;
102 gobject_class->finalize = gst_dynudpsink_finalize;
104 gst_dynudpsink_signals[SIGNAL_GET_STATS] =
105 g_signal_new ("get-stats", G_TYPE_FROM_CLASS (klass),
106 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
107 G_STRUCT_OFFSET (GstDynUDPSinkClass, get_stats),
108 NULL, NULL, gst_udp_marshal_BOXED__STRING_INT, GST_TYPE_STRUCTURE, 2,
109 G_TYPE_STRING, G_TYPE_INT);
111 g_object_class_install_property (gobject_class, PROP_SOCKET,
112 g_param_spec_object ("socket", "Socket",
113 "Socket to use for UDP sending. (NULL == allocate)",
114 G_TYPE_SOCKET, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
115 g_object_class_install_property (gobject_class, PROP_CLOSE_SOCKET,
116 g_param_spec_boolean ("close-socket", "Close socket",
117 "Close socket if passed as property on state change",
118 UDP_DEFAULT_CLOSE_SOCKET,
119 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
121 gst_element_class_add_pad_template (gstelement_class,
122 gst_static_pad_template_get (&sink_template));
124 gst_element_class_set_details_simple (gstelement_class, "UDP packet sender",
126 "Send data over the network via UDP",
127 "Philippe Khalaf <burger@speedy.org>");
129 gstbasesink_class->render = gst_dynudpsink_render;
130 gstbasesink_class->start = gst_dynudpsink_start;
131 gstbasesink_class->stop = gst_dynudpsink_stop;
132 gstbasesink_class->unlock = gst_dynudpsink_unlock;
133 gstbasesink_class->unlock_stop = gst_dynudpsink_unlock_stop;
135 klass->get_stats = gst_dynudpsink_get_stats;
137 GST_DEBUG_CATEGORY_INIT (dynudpsink_debug, "dynudpsink", 0, "UDP sink");
141 gst_dynudpsink_init (GstDynUDPSink * sink)
143 sink->socket = UDP_DEFAULT_SOCKET;
144 sink->close_socket = UDP_DEFAULT_CLOSE_SOCKET;
145 sink->external_socket = FALSE;
147 sink->used_socket = NULL;
148 sink->cancellable = g_cancellable_new ();
149 sink->family = G_SOCKET_FAMILY_IPV6;
153 gst_dynudpsink_finalize (GObject * object)
157 sink = GST_DYNUDPSINK (object);
159 if (sink->cancellable)
160 g_object_unref (sink->cancellable);
161 sink->cancellable = NULL;
164 g_object_unref (sink->socket);
167 if (sink->used_socket)
168 g_object_unref (sink->used_socket);
169 sink->used_socket = NULL;
171 G_OBJECT_CLASS (parent_class)->finalize (object);
175 gst_dynudpsink_render (GstBaseSink * bsink, GstBuffer * buffer)
180 GstNetAddressMeta *meta;
181 GSocketAddress *addr;
183 GSocketFamily family;
185 meta = gst_buffer_get_net_address_meta (buffer);
188 GST_DEBUG ("Received buffer is not a GstNetBuffer, skipping");
192 sink = GST_DYNUDPSINK (bsink);
194 /* let's get the address from the metadata */
197 family = g_socket_address_get_family (addr);
198 if (sink->family != family && family != G_SOCKET_FAMILY_IPV4)
201 gst_buffer_map (buffer, &map, GST_MAP_READ);
203 GST_DEBUG ("about to send %" G_GSIZE_FORMAT " bytes", map.size);
205 #ifndef GST_DISABLE_GST_DEBUG
210 g_inet_address_to_string (g_inet_socket_address_get_address
211 (G_INET_SOCKET_ADDRESS (addr)));
212 GST_DEBUG ("sending %" G_GSIZE_FORMAT " bytes to client %s port %d",
214 g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (addr)));
220 g_socket_send_to (sink->used_socket, addr, (gchar *) map.data, map.size,
221 sink->cancellable, &err);
222 gst_buffer_unmap (buffer, &map);
227 GST_DEBUG ("sent %" G_GSSIZE_FORMAT " bytes", ret);
233 GST_DEBUG ("got send error %s", err->message);
234 g_clear_error (&err);
235 return GST_FLOW_ERROR;
239 GST_DEBUG ("invalid family (got %d, expected %d)",
240 g_socket_address_get_family (addr), sink->family);
241 return GST_FLOW_ERROR;
246 gst_dynudpsink_set_property (GObject * object, guint prop_id,
247 const GValue * value, GParamSpec * pspec)
249 GstDynUDPSink *udpsink;
251 udpsink = GST_DYNUDPSINK (object);
255 if (udpsink->socket != NULL && udpsink->socket != udpsink->used_socket &&
256 udpsink->close_socket) {
259 if (!g_socket_close (udpsink->socket, &err)) {
260 GST_ERROR ("failed to close socket %p: %s", udpsink->socket,
262 g_clear_error (&err);
266 g_object_unref (udpsink->socket);
267 udpsink->socket = g_value_dup_object (value);
268 GST_DEBUG ("setting socket to %p", udpsink->socket);
270 case PROP_CLOSE_SOCKET:
271 udpsink->close_socket = g_value_get_boolean (value);
274 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
280 gst_dynudpsink_get_property (GObject * object, guint prop_id, GValue * value,
283 GstDynUDPSink *udpsink;
285 udpsink = GST_DYNUDPSINK (object);
289 g_value_set_object (value, udpsink->socket);
291 case PROP_CLOSE_SOCKET:
292 g_value_set_boolean (value, udpsink->close_socket);
295 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
300 /* create a socket for sending to remote machine */
302 gst_dynudpsink_start (GstBaseSink * bsink)
304 GstDynUDPSink *udpsink;
307 udpsink = GST_DYNUDPSINK (bsink);
309 if (udpsink->socket == NULL) {
310 /* create sender socket if none available, first try IPv6, then
311 * fall-back to IPv4 */
312 udpsink->family = G_SOCKET_FAMILY_IPV6;
313 if ((udpsink->used_socket =
314 g_socket_new (G_SOCKET_FAMILY_IPV6,
315 G_SOCKET_TYPE_DATAGRAM, G_SOCKET_PROTOCOL_UDP, &err)) == NULL) {
316 udpsink->family = G_SOCKET_FAMILY_IPV4;
317 if ((udpsink->used_socket = g_socket_new (G_SOCKET_FAMILY_IPV4,
318 G_SOCKET_TYPE_DATAGRAM, G_SOCKET_PROTOCOL_UDP, &err)) == NULL)
322 udpsink->external_socket = FALSE;
324 udpsink->used_socket = G_SOCKET (g_object_ref (udpsink->socket));
325 udpsink->external_socket = TRUE;
326 udpsink->family = g_socket_get_family (udpsink->used_socket);
329 g_socket_set_broadcast (udpsink->used_socket, TRUE);
336 GST_ERROR_OBJECT (udpsink, "Failed to create socket: %s", err->message);
337 g_clear_error (&err);
342 static GstStructure *
343 gst_dynudpsink_get_stats (GstDynUDPSink * sink, const gchar * host, gint port)
349 gst_dynudpsink_stop (GstBaseSink * bsink)
351 GstDynUDPSink *udpsink;
353 udpsink = GST_DYNUDPSINK (bsink);
355 if (udpsink->used_socket) {
356 if (udpsink->close_socket || !udpsink->external_socket) {
359 if (!g_socket_close (udpsink->used_socket, &err)) {
360 GST_ERROR_OBJECT (udpsink, "Failed to close socket: %s", err->message);
361 g_clear_error (&err);
365 g_object_unref (udpsink->used_socket);
366 udpsink->used_socket = NULL;
373 gst_dynudpsink_unlock (GstBaseSink * bsink)
375 GstDynUDPSink *udpsink;
377 udpsink = GST_DYNUDPSINK (bsink);
379 g_cancellable_cancel (udpsink->cancellable);
385 gst_dynudpsink_unlock_stop (GstBaseSink * bsink)
387 GstDynUDPSink *udpsink;
389 udpsink = GST_DYNUDPSINK (bsink);
391 g_cancellable_reset (udpsink->cancellable);