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