gst-indent
[platform/upstream/gst-plugins-good.git] / gst / udp / gstudpsink.c
1 /* GStreamer
2  * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24 #include "gstudpsink.h"
25
26 #define UDP_DEFAULT_HOST        "localhost"
27 #define UDP_DEFAULT_PORT        4951
28 #define UDP_DEFAULT_CONTROL     1
29
30 /* elementfactory information */
31 static GstElementDetails gst_udpsink_details =
32 GST_ELEMENT_DETAILS ("UDP packet sender",
33     "Sink/Network",
34     "Send data over the network via UDP",
35     "Wim Taymans <wim.taymans@chello.be>");
36
37 /* UDPSink signals and args */
38 enum
39 {
40   FRAME_ENCODED,
41   /* FILL ME */
42   LAST_SIGNAL
43 };
44
45 enum
46 {
47   ARG_0,
48   ARG_HOST,
49   ARG_PORT,
50   ARG_CONTROL,
51   ARG_MTU
52       /* FILL ME */
53 };
54
55 #define GST_TYPE_UDPSINK_CONTROL        (gst_udpsink_control_get_type())
56 static GType
57 gst_udpsink_control_get_type (void)
58 {
59   static GType udpsink_control_type = 0;
60   static GEnumValue udpsink_control[] = {
61     {CONTROL_NONE, "1", "none"},
62     {CONTROL_UDP, "2", "udp"},
63     {CONTROL_TCP, "3", "tcp"},
64     {CONTROL_ZERO, NULL, NULL},
65   };
66   if (!udpsink_control_type) {
67     udpsink_control_type =
68         g_enum_register_static ("GstUDPSinkControl", udpsink_control);
69   }
70   return udpsink_control_type;
71 }
72
73 static void gst_udpsink_base_init (gpointer g_class);
74 static void gst_udpsink_class_init (GstUDPSink * klass);
75 static void gst_udpsink_init (GstUDPSink * udpsink);
76
77 static void gst_udpsink_set_clock (GstElement * element, GstClock * clock);
78
79 static void gst_udpsink_chain (GstPad * pad, GstData * _data);
80 static GstElementStateReturn gst_udpsink_change_state (GstElement * element);
81
82 static void gst_udpsink_set_property (GObject * object, guint prop_id,
83     const GValue * value, GParamSpec * pspec);
84 static void gst_udpsink_get_property (GObject * object, guint prop_id,
85     GValue * value, GParamSpec * pspec);
86
87
88 static GstElementClass *parent_class = NULL;
89
90 /*static guint gst_udpsink_signals[LAST_SIGNAL] = { 0 }; */
91
92 GType
93 gst_udpsink_get_type (void)
94 {
95   static GType udpsink_type = 0;
96
97   if (!udpsink_type) {
98     static const GTypeInfo udpsink_info = {
99       sizeof (GstUDPSinkClass),
100       gst_udpsink_base_init,
101       NULL,
102       (GClassInitFunc) gst_udpsink_class_init,
103       NULL,
104       NULL,
105       sizeof (GstUDPSink),
106       0,
107       (GInstanceInitFunc) gst_udpsink_init,
108       NULL
109     };
110     udpsink_type =
111         g_type_register_static (GST_TYPE_ELEMENT, "GstUDPSink", &udpsink_info,
112         0);
113   }
114   return udpsink_type;
115 }
116
117 static void
118 gst_udpsink_base_init (gpointer g_class)
119 {
120   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
121
122   gst_element_class_set_details (element_class, &gst_udpsink_details);
123 }
124
125 static void
126 gst_udpsink_class_init (GstUDPSink * klass)
127 {
128   GObjectClass *gobject_class;
129   GstElementClass *gstelement_class;
130
131   gobject_class = (GObjectClass *) klass;
132   gstelement_class = (GstElementClass *) klass;
133
134   parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
135
136   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_HOST,
137       g_param_spec_string ("host", "host",
138           "The host/IP/Multicast group to send the packets to",
139           UDP_DEFAULT_HOST, G_PARAM_READWRITE));
140   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_PORT,
141       g_param_spec_int ("port", "port", "The port to send the packets to",
142           0, 32768, UDP_DEFAULT_PORT, G_PARAM_READWRITE));
143   g_object_class_install_property (gobject_class, ARG_CONTROL,
144       g_param_spec_enum ("control", "control", "The type of control",
145           GST_TYPE_UDPSINK_CONTROL, CONTROL_UDP, G_PARAM_READWRITE));
146   g_object_class_install_property (gobject_class, ARG_MTU, g_param_spec_int ("mtu", "mtu", "maximun transmit unit", G_MININT, G_MAXINT, 0, G_PARAM_READWRITE)); /* CHECKME */
147
148   gobject_class->set_property = gst_udpsink_set_property;
149   gobject_class->get_property = gst_udpsink_get_property;
150
151   gstelement_class->change_state = gst_udpsink_change_state;
152   gstelement_class->set_clock = gst_udpsink_set_clock;
153 }
154
155
156 static GstPadLinkReturn
157 gst_udpsink_sink_link (GstPad * pad, const GstCaps * caps)
158 {
159   GstUDPSink *udpsink;
160   struct sockaddr_in serv_addr;
161   struct hostent *serverhost;
162   int fd;
163   FILE *f;
164   guint bc_val;
165
166 #ifndef GST_DISABLE_LOADSAVE
167   xmlDocPtr doc;
168   xmlChar *buf;
169   int buf_size;
170
171   udpsink = GST_UDPSINK (gst_pad_get_parent (pad));
172
173   memset (&serv_addr, 0, sizeof (serv_addr));
174
175   /* its a name rather than an ipnum */
176   serverhost = gethostbyname (udpsink->host);
177   if (serverhost == (struct hostent *) 0) {
178     perror ("gethostbyname");
179     return GST_PAD_LINK_REFUSED;
180   }
181
182   memmove (&serv_addr.sin_addr, serverhost->h_addr, serverhost->h_length);
183
184   serv_addr.sin_family = AF_INET;
185   serv_addr.sin_port = htons (udpsink->port + 1);
186
187   doc = xmlNewDoc ("1.0");
188   doc->xmlRootNode = xmlNewDocNode (doc, NULL, "NewCaps", NULL);
189
190   gst_caps_save_thyself (caps, doc->xmlRootNode);
191
192   switch (udpsink->control) {
193     case CONTROL_UDP:
194       if ((fd = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
195         perror ("socket");
196         return GST_PAD_LINK_REFUSED;
197       }
198
199       /* We can only do broadcast in udp */
200       bc_val = 1;
201       setsockopt (fd, SOL_SOCKET, SO_BROADCAST, &bc_val, sizeof (bc_val));
202
203       xmlDocDumpMemory (doc, &buf, &buf_size);
204
205       if (sendto (fd, buf, buf_size, 0, (struct sockaddr *) &serv_addr,
206               sizeof (serv_addr)) == -1) {
207         perror ("sending");
208         return GST_PAD_LINK_REFUSED;
209       }
210       close (fd);
211       break;
212     case CONTROL_TCP:
213       if ((fd = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
214         perror ("socket");
215         return GST_PAD_LINK_REFUSED;
216       }
217
218       if (connect (fd, (struct sockaddr *) &serv_addr, sizeof (serv_addr)) != 0) {
219         g_printerr ("udpsink: connect to %s port %d failed: %s\n",
220             udpsink->host, udpsink->port, g_strerror (errno));
221         return GST_PAD_LINK_REFUSED;
222       }
223
224       f = fdopen (dup (fd), "wb");
225
226       xmlDocDump (f, doc);
227       fclose (f);
228       close (fd);
229       break;
230     case CONTROL_NONE:
231       return GST_PAD_LINK_OK;
232       break;
233     default:
234       return GST_PAD_LINK_REFUSED;
235       break;
236   }
237 #endif
238
239   return GST_PAD_LINK_OK;
240 }
241
242 static void
243 gst_udpsink_set_clock (GstElement * element, GstClock * clock)
244 {
245   GstUDPSink *udpsink;
246
247   udpsink = GST_UDPSINK (element);
248
249   udpsink->clock = clock;
250 }
251
252 static void
253 gst_udpsink_init (GstUDPSink * udpsink)
254 {
255   /* create the sink and src pads */
256   udpsink->sinkpad = gst_pad_new ("sink", GST_PAD_SINK);
257   gst_element_add_pad (GST_ELEMENT (udpsink), udpsink->sinkpad);
258   gst_pad_set_chain_function (udpsink->sinkpad, gst_udpsink_chain);
259   gst_pad_set_link_function (udpsink->sinkpad, gst_udpsink_sink_link);
260
261   udpsink->host = g_strdup (UDP_DEFAULT_HOST);
262   udpsink->port = UDP_DEFAULT_PORT;
263   udpsink->control = CONTROL_UDP;
264   udpsink->mtu = 1024;
265
266   udpsink->clock = NULL;
267 }
268
269 static void
270 gst_udpsink_chain (GstPad * pad, GstData * _data)
271 {
272   GstBuffer *buf = GST_BUFFER (_data);
273   GstUDPSink *udpsink;
274   guint tolen, i;
275
276   g_return_if_fail (pad != NULL);
277   g_return_if_fail (GST_IS_PAD (pad));
278   g_return_if_fail (buf != NULL);
279
280   udpsink = GST_UDPSINK (GST_OBJECT_PARENT (pad));
281
282   if (udpsink->clock && GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
283     gst_element_wait (GST_ELEMENT (udpsink), GST_BUFFER_TIMESTAMP (buf));
284   }
285
286   tolen = sizeof (udpsink->theiraddr);
287
288   /*
289      if (sendto (udpsink->sock, GST_BUFFER_DATA (buf), 
290      GST_BUFFER_SIZE (buf), 0, (struct sockaddr *) &udpsink->theiraddr, 
291      tolen) == -1) {
292      perror("sending");
293      } 
294    */
295   /* MTU */
296   for (i = 0; i < GST_BUFFER_SIZE (buf); i += udpsink->mtu) {
297     if (GST_BUFFER_SIZE (buf) - i > udpsink->mtu) {
298       if (sendto (udpsink->sock, GST_BUFFER_DATA (buf) + i,
299               udpsink->mtu, 0, (struct sockaddr *) &udpsink->theiraddr,
300               tolen) == -1) {
301         perror ("sending");
302       }
303     } else {
304       if (sendto (udpsink->sock, GST_BUFFER_DATA (buf) + i,
305               GST_BUFFER_SIZE (buf) - i, 0,
306               (struct sockaddr *) &udpsink->theiraddr, tolen) == -1) {
307         perror ("sending");
308       }
309     }
310   }
311
312   gst_buffer_unref (buf);
313 }
314
315 static void
316 gst_udpsink_set_property (GObject * object, guint prop_id, const GValue * value,
317     GParamSpec * pspec)
318 {
319   GstUDPSink *udpsink;
320
321   /* it's not null if we got it, but it might not be ours */
322   g_return_if_fail (GST_IS_UDPSINK (object));
323   udpsink = GST_UDPSINK (object);
324
325   switch (prop_id) {
326     case ARG_HOST:
327       if (udpsink->host != NULL)
328         g_free (udpsink->host);
329       if (g_value_get_string (value) == NULL)
330         udpsink->host = NULL;
331       else
332         udpsink->host = g_strdup (g_value_get_string (value));
333       break;
334     case ARG_PORT:
335       udpsink->port = g_value_get_int (value);
336       break;
337     case ARG_CONTROL:
338       udpsink->control = g_value_get_enum (value);
339       break;
340     case ARG_MTU:
341       udpsink->mtu = g_value_get_int (value);
342       break;
343     default:
344       break;
345   }
346 }
347
348 static void
349 gst_udpsink_get_property (GObject * object, guint prop_id, GValue * value,
350     GParamSpec * pspec)
351 {
352   GstUDPSink *udpsink;
353
354   /* it's not null if we got it, but it might not be ours */
355   g_return_if_fail (GST_IS_UDPSINK (object));
356   udpsink = GST_UDPSINK (object);
357
358   switch (prop_id) {
359     case ARG_HOST:
360       g_value_set_string (value, udpsink->host);
361       break;
362     case ARG_PORT:
363       g_value_set_int (value, udpsink->port);
364       break;
365     case ARG_CONTROL:
366       g_value_set_enum (value, udpsink->control);
367       break;
368     case ARG_MTU:
369       g_value_set_int (value, udpsink->mtu);
370       break;
371     default:
372       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
373       break;
374   }
375 }
376
377
378 /* create a socket for sending to remote machine */
379 static gboolean
380 gst_udpsink_init_send (GstUDPSink * sink)
381 {
382   struct hostent *he;
383   struct in_addr addr;
384   guint bc_val;
385
386   memset (&sink->theiraddr, 0, sizeof (sink->theiraddr));
387   sink->theiraddr.sin_family = AF_INET; /* host byte order */
388   sink->theiraddr.sin_port = htons (sink->port);        /* short, network byte order */
389
390   /* if its an IP address */
391   if (inet_aton (sink->host, &addr)) {
392     /* check if its a multicast address */
393     if ((ntohl (addr.s_addr) & 0xe0000000) == 0xe0000000) {
394       sink->multi_addr.imr_multiaddr.s_addr = addr.s_addr;
395       sink->multi_addr.imr_interface.s_addr = INADDR_ANY;
396
397       sink->theiraddr.sin_addr = sink->multi_addr.imr_multiaddr;
398
399       /* Joining the multicast group */
400       setsockopt (sink->sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &sink->multi_addr,
401           sizeof (sink->multi_addr));
402     }
403
404     else {
405       sink->theiraddr.sin_addr = *((struct in_addr *) &addr);
406     }
407   }
408
409   /* we dont need to lookup for localhost */
410   else if (strcmp (sink->host, UDP_DEFAULT_HOST) == 0 &&
411       inet_aton ("127.0.0.1", &addr)) {
412     sink->theiraddr.sin_addr = *((struct in_addr *) &addr);
413   }
414
415   /* if its a hostname */
416   else if ((he = gethostbyname (sink->host))) {
417     sink->theiraddr.sin_addr = *((struct in_addr *) he->h_addr);
418   }
419
420   else {
421     perror ("hostname lookup error?");
422     return FALSE;
423   }
424
425   if ((sink->sock = socket (AF_INET, SOCK_DGRAM, 0)) == -1) {
426     perror ("socket");
427     return FALSE;
428   }
429
430   bc_val = 1;
431   setsockopt (sink->sock, SOL_SOCKET, SO_BROADCAST, &bc_val, sizeof (bc_val));
432
433   GST_FLAG_SET (sink, GST_UDPSINK_OPEN);
434
435   return TRUE;
436 }
437
438 static void
439 gst_udpsink_close (GstUDPSink * sink)
440 {
441   close (sink->sock);
442
443   GST_FLAG_UNSET (sink, GST_UDPSINK_OPEN);
444 }
445
446 static GstElementStateReturn
447 gst_udpsink_change_state (GstElement * element)
448 {
449   g_return_val_if_fail (GST_IS_UDPSINK (element), GST_STATE_FAILURE);
450
451   if (GST_STATE_PENDING (element) == GST_STATE_NULL) {
452     if (GST_FLAG_IS_SET (element, GST_UDPSINK_OPEN))
453       gst_udpsink_close (GST_UDPSINK (element));
454   } else {
455     if (!GST_FLAG_IS_SET (element, GST_UDPSINK_OPEN)) {
456       if (!gst_udpsink_init_send (GST_UDPSINK (element)))
457         return GST_STATE_FAILURE;
458     }
459   }
460
461   if (GST_ELEMENT_CLASS (parent_class)->change_state)
462     return GST_ELEMENT_CLASS (parent_class)->change_state (element);
463
464   return GST_STATE_SUCCESS;
465 }