update for buffer api change
[platform/upstream/gstreamer.git] / gst / udp / gstdynudpsink.c
1 /* GStreamer
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>
7  *
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.
12  *
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.
17  *
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.
22  */
23
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
27
28 #ifdef HAVE_CONFIG_H
29 #include "config.h"
30 #endif
31 #include "gstudp-marshal.h"
32 #include "gstdynudpsink.h"
33
34 #include <gst/net/gstnetaddressmeta.h>
35
36 GST_DEBUG_CATEGORY_STATIC (dynudpsink_debug);
37 #define GST_CAT_DEFAULT (dynudpsink_debug)
38
39 static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
40     GST_PAD_SINK,
41     GST_PAD_ALWAYS,
42     GST_STATIC_CAPS_ANY);
43
44 /* DynUDPSink signals and args */
45 enum
46 {
47   /* methods */
48   SIGNAL_GET_STATS,
49
50   /* signals */
51
52   /* FILL ME */
53   LAST_SIGNAL
54 };
55
56 #define UDP_DEFAULT_SOCKET              NULL
57 #define UDP_DEFAULT_CLOSE_SOCKET        TRUE
58
59 enum
60 {
61   PROP_0,
62   PROP_SOCKET,
63   PROP_CLOSE_SOCKET
64 };
65
66 static void gst_dynudpsink_finalize (GObject * object);
67
68 static GstFlowReturn gst_dynudpsink_render (GstBaseSink * sink,
69     GstBuffer * buffer);
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);
74
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);
81
82 static guint gst_dynudpsink_signals[LAST_SIGNAL] = { 0 };
83
84 #define gst_dynudpsink_parent_class parent_class
85 G_DEFINE_TYPE (GstDynUDPSink, gst_dynudpsink, GST_TYPE_BASE_SINK);
86
87 static void
88 gst_dynudpsink_class_init (GstDynUDPSinkClass * klass)
89 {
90   GObjectClass *gobject_class;
91   GstElementClass *gstelement_class;
92   GstBaseSinkClass *gstbasesink_class;
93
94   gobject_class = (GObjectClass *) klass;
95   gstelement_class = (GstElementClass *) klass;
96   gstbasesink_class = (GstBaseSinkClass *) klass;
97
98   parent_class = g_type_class_peek_parent (klass);
99
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;
103
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);
110
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));
120
121   gst_element_class_add_pad_template (gstelement_class,
122       gst_static_pad_template_get (&sink_template));
123
124   gst_element_class_set_details_simple (gstelement_class, "UDP packet sender",
125       "Sink/Network",
126       "Send data over the network via UDP",
127       "Philippe Khalaf <burger@speedy.org>");
128
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;
134
135   klass->get_stats = gst_dynudpsink_get_stats;
136
137   GST_DEBUG_CATEGORY_INIT (dynudpsink_debug, "dynudpsink", 0, "UDP sink");
138 }
139
140 static void
141 gst_dynudpsink_init (GstDynUDPSink * sink)
142 {
143   sink->socket = UDP_DEFAULT_SOCKET;
144   sink->close_socket = UDP_DEFAULT_CLOSE_SOCKET;
145   sink->external_socket = FALSE;
146
147   sink->used_socket = NULL;
148   sink->cancellable = g_cancellable_new ();
149   sink->family = G_SOCKET_FAMILY_IPV6;
150 }
151
152 static void
153 gst_dynudpsink_finalize (GObject * object)
154 {
155   GstDynUDPSink *sink;
156
157   sink = GST_DYNUDPSINK (object);
158
159   if (sink->cancellable)
160     g_object_unref (sink->cancellable);
161   sink->cancellable = NULL;
162
163   if (sink->socket)
164     g_object_unref (sink->socket);
165   sink->socket = NULL;
166
167   if (sink->used_socket)
168     g_object_unref (sink->used_socket);
169   sink->used_socket = NULL;
170
171   G_OBJECT_CLASS (parent_class)->finalize (object);
172 }
173
174 static GstFlowReturn
175 gst_dynudpsink_render (GstBaseSink * bsink, GstBuffer * buffer)
176 {
177   GstDynUDPSink *sink;
178   gssize ret;
179   GstMapInfo map;
180   GstNetAddressMeta *meta;
181   GSocketAddress *addr;
182   GError *err = NULL;
183   GSocketFamily family;
184
185   meta = gst_buffer_get_net_address_meta (buffer);
186
187   if (meta == NULL) {
188     GST_DEBUG ("Received buffer is not a GstNetBuffer, skipping");
189     return GST_FLOW_OK;
190   }
191
192   sink = GST_DYNUDPSINK (bsink);
193
194   /* let's get the address from the metadata */
195   addr = meta->addr;
196
197   family = g_socket_address_get_family (addr);
198   if (sink->family != family && family != G_SOCKET_FAMILY_IPV4)
199     goto invalid_family;
200
201   gst_buffer_map (buffer, &map, GST_MAP_READ);
202
203   GST_DEBUG ("about to send %" G_GSIZE_FORMAT " bytes", map.size);
204
205 #ifndef GST_DISABLE_GST_DEBUG
206   {
207     gchar *host;
208
209     host =
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",
213         map.size, host,
214         g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (addr)));
215     g_free (host);
216   }
217 #endif
218
219   ret =
220       g_socket_send_to (sink->used_socket, addr, (gchar *) map.data, map.size,
221       sink->cancellable, &err);
222   gst_buffer_unmap (buffer, &map);
223
224   if (ret < 0)
225     goto send_error;
226
227   GST_DEBUG ("sent %" G_GSSIZE_FORMAT " bytes", ret);
228
229   return GST_FLOW_OK;
230
231 send_error:
232   {
233     GST_DEBUG ("got send error %s", err->message);
234     g_clear_error (&err);
235     return GST_FLOW_ERROR;
236   }
237 invalid_family:
238   {
239     GST_DEBUG ("invalid family (got %d, expected %d)",
240         g_socket_address_get_family (addr), sink->family);
241     return GST_FLOW_ERROR;
242   }
243 }
244
245 static void
246 gst_dynudpsink_set_property (GObject * object, guint prop_id,
247     const GValue * value, GParamSpec * pspec)
248 {
249   GstDynUDPSink *udpsink;
250
251   udpsink = GST_DYNUDPSINK (object);
252
253   switch (prop_id) {
254     case PROP_SOCKET:
255       if (udpsink->socket != NULL && udpsink->socket != udpsink->used_socket &&
256           udpsink->close_socket) {
257         GError *err = NULL;
258
259         if (!g_socket_close (udpsink->socket, &err)) {
260           GST_ERROR ("failed to close socket %p: %s", udpsink->socket,
261               err->message);
262           g_clear_error (&err);
263         }
264       }
265       if (udpsink->socket)
266         g_object_unref (udpsink->socket);
267       udpsink->socket = g_value_dup_object (value);
268       GST_DEBUG ("setting socket to %p", udpsink->socket);
269       break;
270     case PROP_CLOSE_SOCKET:
271       udpsink->close_socket = g_value_get_boolean (value);
272       break;
273     default:
274       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
275       break;
276   }
277 }
278
279 static void
280 gst_dynudpsink_get_property (GObject * object, guint prop_id, GValue * value,
281     GParamSpec * pspec)
282 {
283   GstDynUDPSink *udpsink;
284
285   udpsink = GST_DYNUDPSINK (object);
286
287   switch (prop_id) {
288     case PROP_SOCKET:
289       g_value_set_object (value, udpsink->socket);
290       break;
291     case PROP_CLOSE_SOCKET:
292       g_value_set_boolean (value, udpsink->close_socket);
293       break;
294     default:
295       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
296       break;
297   }
298 }
299
300 /* create a socket for sending to remote machine */
301 static gboolean
302 gst_dynudpsink_start (GstBaseSink * bsink)
303 {
304   GstDynUDPSink *udpsink;
305   GError *err = NULL;
306
307   udpsink = GST_DYNUDPSINK (bsink);
308
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)
319         goto no_socket;
320     }
321
322     udpsink->external_socket = FALSE;
323   } else {
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);
327   }
328
329   g_socket_set_broadcast (udpsink->used_socket, TRUE);
330
331   return TRUE;
332
333   /* ERRORS */
334 no_socket:
335   {
336     GST_ERROR_OBJECT (udpsink, "Failed to create socket: %s", err->message);
337     g_clear_error (&err);
338     return FALSE;
339   }
340 }
341
342 static GstStructure *
343 gst_dynudpsink_get_stats (GstDynUDPSink * sink, const gchar * host, gint port)
344 {
345   return NULL;
346 }
347
348 static gboolean
349 gst_dynudpsink_stop (GstBaseSink * bsink)
350 {
351   GstDynUDPSink *udpsink;
352
353   udpsink = GST_DYNUDPSINK (bsink);
354
355   if (udpsink->used_socket) {
356     if (udpsink->close_socket || !udpsink->external_socket) {
357       GError *err = NULL;
358
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);
362       }
363     }
364
365     g_object_unref (udpsink->used_socket);
366     udpsink->used_socket = NULL;
367   }
368
369   return TRUE;
370 }
371
372 static gboolean
373 gst_dynudpsink_unlock (GstBaseSink * bsink)
374 {
375   GstDynUDPSink *udpsink;
376
377   udpsink = GST_DYNUDPSINK (bsink);
378
379   g_cancellable_cancel (udpsink->cancellable);
380
381   return TRUE;
382 }
383
384 static gboolean
385 gst_dynudpsink_unlock_stop (GstBaseSink * bsink)
386 {
387   GstDynUDPSink *udpsink;
388
389   udpsink = GST_DYNUDPSINK (bsink);
390
391   g_cancellable_reset (udpsink->cancellable);
392
393   return TRUE;
394 }