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