2 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
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.
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.
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.
24 #include "gstudpsink.h"
26 #define UDP_DEFAULT_HOST "localhost"
27 #define UDP_DEFAULT_PORT 4951
28 #define UDP_DEFAULT_CONTROL 1
30 /* elementfactory information */
31 static GstElementDetails gst_udpsink_details = GST_ELEMENT_DETAILS (
34 "Send data over the network via UDP",
35 "Wim Taymans <wim.taymans@chello.be>"
38 /* UDPSink signals and args */
54 #define GST_TYPE_UDPSINK_CONTROL (gst_udpsink_control_get_type())
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},
64 if (!udpsink_control_type) {
65 udpsink_control_type = g_enum_register_static("GstUDPSinkControl", udpsink_control);
67 return udpsink_control_type;
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);
74 static void gst_udpsink_set_clock (GstElement *element, GstClock *clock);
76 static void gst_udpsink_chain (GstPad *pad,GstData *_data);
77 static GstElementStateReturn gst_udpsink_change_state (GstElement *element);
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);
85 static GstElementClass *parent_class = NULL;
86 /*static guint gst_udpsink_signals[LAST_SIGNAL] = { 0 }; */
89 gst_udpsink_get_type (void)
91 static GType udpsink_type = 0;
94 static const GTypeInfo udpsink_info = {
95 sizeof(GstUDPSinkClass),
96 gst_udpsink_base_init,
98 (GClassInitFunc)gst_udpsink_class_init,
103 (GInstanceInitFunc)gst_udpsink_init,
106 udpsink_type = g_type_register_static (GST_TYPE_ELEMENT, "GstUDPSink", &udpsink_info, 0);
112 gst_udpsink_base_init (gpointer g_class)
114 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
116 gst_element_class_set_details (element_class, &gst_udpsink_details);
120 gst_udpsink_class_init (GstUDPSink *klass)
122 GObjectClass *gobject_class;
123 GstElementClass *gstelement_class;
125 gobject_class = (GObjectClass*) klass;
126 gstelement_class = (GstElementClass*) klass;
128 parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
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 */
144 gobject_class->set_property = gst_udpsink_set_property;
145 gobject_class->get_property = gst_udpsink_get_property;
147 gstelement_class->change_state = gst_udpsink_change_state;
148 gstelement_class->set_clock = gst_udpsink_set_clock;
152 static GstPadLinkReturn
153 gst_udpsink_sink_link (GstPad *pad, const GstCaps *caps)
156 struct sockaddr_in serv_addr;
157 struct hostent *serverhost;
161 #ifndef GST_DISABLE_LOADSAVE
166 udpsink = GST_UDPSINK (gst_pad_get_parent (pad));
168 memset(&serv_addr, 0, sizeof(serv_addr));
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;
177 memmove(&serv_addr.sin_addr,serverhost->h_addr, serverhost->h_length);
179 serv_addr.sin_family = AF_INET;
180 serv_addr.sin_port = htons(udpsink->port+1);
182 doc = xmlNewDoc ("1.0");
183 doc->xmlRootNode = xmlNewDocNode (doc, NULL, "NewCaps", NULL);
185 gst_caps_save_thyself (caps, doc->xmlRootNode);
187 switch (udpsink->control) {
189 if ((fd = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
191 return GST_PAD_LINK_REFUSED;
194 /* We can only do broadcast in udp */
196 setsockopt (fd,SOL_SOCKET, SO_BROADCAST, &bc_val, sizeof (bc_val));
198 xmlDocDumpMemory(doc, &buf, &buf_size);
200 if (sendto (fd, buf, buf_size, 0, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) == -1)
203 return GST_PAD_LINK_REFUSED;
208 if ((fd = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
210 return GST_PAD_LINK_REFUSED;
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;
219 f = fdopen (dup (fd), "wb");
226 return GST_PAD_LINK_OK;
229 return GST_PAD_LINK_REFUSED;
234 return GST_PAD_LINK_OK;
238 gst_udpsink_set_clock (GstElement *element, GstClock *clock)
242 udpsink = GST_UDPSINK (element);
244 udpsink->clock = clock;
248 gst_udpsink_init (GstUDPSink *udpsink)
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);
256 udpsink->host = g_strdup (UDP_DEFAULT_HOST);
257 udpsink->port = UDP_DEFAULT_PORT;
258 udpsink->control = CONTROL_UDP;
261 udpsink->clock = NULL;
265 gst_udpsink_chain (GstPad *pad, GstData *_data)
267 GstBuffer *buf = GST_BUFFER (_data);
271 g_return_if_fail (pad != NULL);
272 g_return_if_fail (GST_IS_PAD (pad));
273 g_return_if_fail (buf != NULL);
275 udpsink = GST_UDPSINK (GST_OBJECT_PARENT (pad));
277 if (udpsink->clock && GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
278 gst_element_wait (GST_ELEMENT (udpsink), GST_BUFFER_TIMESTAMP (buf));
281 tolen = sizeof(udpsink->theiraddr);
284 if (sendto (udpsink->sock, GST_BUFFER_DATA (buf),
285 GST_BUFFER_SIZE (buf), 0, (struct sockaddr *) &udpsink->theiraddr,
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,
300 if (sendto (udpsink->sock, GST_BUFFER_DATA (buf) + i,
301 GST_BUFFER_SIZE (buf) -i, 0,
302 (struct sockaddr *) &udpsink->theiraddr, tolen) == -1) {
308 gst_buffer_unref(buf);
312 gst_udpsink_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
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);
322 if (udpsink->host != NULL) g_free(udpsink->host);
323 if (g_value_get_string (value) == NULL)
324 udpsink->host = NULL;
326 udpsink->host = g_strdup (g_value_get_string (value));
329 udpsink->port = g_value_get_int (value);
332 udpsink->control = g_value_get_enum (value);
335 udpsink->mtu = g_value_get_int (value);
343 gst_udpsink_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
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);
353 g_value_set_string (value, udpsink->host);
356 g_value_set_int (value, udpsink->port);
359 g_value_set_enum (value, udpsink->control);
362 g_value_set_int (value, udpsink->mtu);
365 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
371 /* create a socket for sending to remote machine */
373 gst_udpsink_init_send (GstUDPSink *sink)
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 */
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;
390 sink->theiraddr.sin_addr = sink->multi_addr.imr_multiaddr;
392 /* Joining the multicast group */
393 setsockopt (sink->sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &sink->multi_addr, sizeof(sink->multi_addr));
397 sink->theiraddr.sin_addr =
398 *((struct in_addr *) &addr);
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);
409 /* if its a hostname */
410 else if ((he = gethostbyname (sink->host))) {
411 sink->theiraddr.sin_addr = *((struct in_addr *) he->h_addr);
415 perror("hostname lookup error?");
419 if ((sink->sock = socket (AF_INET, SOCK_DGRAM, 0)) == -1) {
425 setsockopt (sink->sock, SOL_SOCKET, SO_BROADCAST, &bc_val, sizeof (bc_val));
427 GST_FLAG_SET (sink, GST_UDPSINK_OPEN);
433 gst_udpsink_close (GstUDPSink *sink)
437 GST_FLAG_UNSET (sink, GST_UDPSINK_OPEN);
440 static GstElementStateReturn
441 gst_udpsink_change_state (GstElement *element)
443 g_return_val_if_fail (GST_IS_UDPSINK (element), GST_STATE_FAILURE);
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));
449 if (!GST_FLAG_IS_SET (element, GST_UDPSINK_OPEN)) {
450 if (!gst_udpsink_init_send (GST_UDPSINK (element)))
451 return GST_STATE_FAILURE;
455 if (GST_ELEMENT_CLASS (parent_class)->change_state)
456 return GST_ELEMENT_CLASS (parent_class)->change_state (element);
458 return GST_STATE_SUCCESS;