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 =
32 GST_ELEMENT_DETAILS ("UDP packet sender",
34 "Send data over the network via UDP",
35 "Wim Taymans <wim.taymans@chello.be>");
37 /* UDPSink signals and args */
55 #define GST_TYPE_UDPSINK_CONTROL (gst_udpsink_control_get_type())
57 gst_udpsink_control_get_type (void)
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},
66 if (!udpsink_control_type) {
67 udpsink_control_type =
68 g_enum_register_static ("GstUDPSinkControl", udpsink_control);
70 return udpsink_control_type;
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);
77 static void gst_udpsink_set_clock (GstElement * element, GstClock * clock);
79 static void gst_udpsink_chain (GstPad * pad, GstData * _data);
80 static GstElementStateReturn gst_udpsink_change_state (GstElement * element);
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);
88 static GstElementClass *parent_class = NULL;
90 /*static guint gst_udpsink_signals[LAST_SIGNAL] = { 0 }; */
93 gst_udpsink_get_type (void)
95 static GType udpsink_type = 0;
98 static const GTypeInfo udpsink_info = {
99 sizeof (GstUDPSinkClass),
100 gst_udpsink_base_init,
102 (GClassInitFunc) gst_udpsink_class_init,
107 (GInstanceInitFunc) gst_udpsink_init,
111 g_type_register_static (GST_TYPE_ELEMENT, "GstUDPSink", &udpsink_info,
118 gst_udpsink_base_init (gpointer g_class)
120 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
122 gst_element_class_set_details (element_class, &gst_udpsink_details);
126 gst_udpsink_class_init (GstUDPSink * klass)
128 GObjectClass *gobject_class;
129 GstElementClass *gstelement_class;
131 gobject_class = (GObjectClass *) klass;
132 gstelement_class = (GstElementClass *) klass;
134 parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
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 */
148 gobject_class->set_property = gst_udpsink_set_property;
149 gobject_class->get_property = gst_udpsink_get_property;
151 gstelement_class->change_state = gst_udpsink_change_state;
152 gstelement_class->set_clock = gst_udpsink_set_clock;
156 static GstPadLinkReturn
157 gst_udpsink_sink_link (GstPad * pad, const GstCaps * caps)
160 struct sockaddr_in serv_addr;
161 struct hostent *serverhost;
166 #ifndef GST_DISABLE_LOADSAVE
171 udpsink = GST_UDPSINK (gst_pad_get_parent (pad));
173 memset (&serv_addr, 0, sizeof (serv_addr));
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;
182 memmove (&serv_addr.sin_addr, serverhost->h_addr, serverhost->h_length);
184 serv_addr.sin_family = AF_INET;
185 serv_addr.sin_port = htons (udpsink->port + 1);
187 doc = xmlNewDoc ("1.0");
188 doc->xmlRootNode = xmlNewDocNode (doc, NULL, "NewCaps", NULL);
190 gst_caps_save_thyself (caps, doc->xmlRootNode);
192 switch (udpsink->control) {
194 if ((fd = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
196 return GST_PAD_LINK_REFUSED;
199 /* We can only do broadcast in udp */
201 setsockopt (fd, SOL_SOCKET, SO_BROADCAST, &bc_val, sizeof (bc_val));
203 xmlDocDumpMemory (doc, &buf, &buf_size);
205 if (sendto (fd, buf, buf_size, 0, (struct sockaddr *) &serv_addr,
206 sizeof (serv_addr)) == -1) {
208 return GST_PAD_LINK_REFUSED;
213 if ((fd = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
215 return GST_PAD_LINK_REFUSED;
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;
224 f = fdopen (dup (fd), "wb");
231 return GST_PAD_LINK_OK;
234 return GST_PAD_LINK_REFUSED;
239 return GST_PAD_LINK_OK;
243 gst_udpsink_set_clock (GstElement * element, GstClock * clock)
247 udpsink = GST_UDPSINK (element);
249 udpsink->clock = clock;
253 gst_udpsink_init (GstUDPSink * udpsink)
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);
261 udpsink->host = g_strdup (UDP_DEFAULT_HOST);
262 udpsink->port = UDP_DEFAULT_PORT;
263 udpsink->control = CONTROL_UDP;
266 udpsink->clock = NULL;
270 gst_udpsink_chain (GstPad * pad, GstData * _data)
272 GstBuffer *buf = GST_BUFFER (_data);
276 g_return_if_fail (pad != NULL);
277 g_return_if_fail (GST_IS_PAD (pad));
278 g_return_if_fail (buf != NULL);
280 udpsink = GST_UDPSINK (GST_OBJECT_PARENT (pad));
282 if (udpsink->clock && GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
283 gst_element_wait (GST_ELEMENT (udpsink), GST_BUFFER_TIMESTAMP (buf));
286 tolen = sizeof (udpsink->theiraddr);
289 if (sendto (udpsink->sock, GST_BUFFER_DATA (buf),
290 GST_BUFFER_SIZE (buf), 0, (struct sockaddr *) &udpsink->theiraddr,
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,
304 if (sendto (udpsink->sock, GST_BUFFER_DATA (buf) + i,
305 GST_BUFFER_SIZE (buf) - i, 0,
306 (struct sockaddr *) &udpsink->theiraddr, tolen) == -1) {
312 gst_buffer_unref (buf);
316 gst_udpsink_set_property (GObject * object, guint prop_id, const GValue * value,
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);
327 if (udpsink->host != NULL)
328 g_free (udpsink->host);
329 if (g_value_get_string (value) == NULL)
330 udpsink->host = NULL;
332 udpsink->host = g_strdup (g_value_get_string (value));
335 udpsink->port = g_value_get_int (value);
338 udpsink->control = g_value_get_enum (value);
341 udpsink->mtu = g_value_get_int (value);
349 gst_udpsink_get_property (GObject * object, guint prop_id, GValue * value,
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);
360 g_value_set_string (value, udpsink->host);
363 g_value_set_int (value, udpsink->port);
366 g_value_set_enum (value, udpsink->control);
369 g_value_set_int (value, udpsink->mtu);
372 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
378 /* create a socket for sending to remote machine */
380 gst_udpsink_init_send (GstUDPSink * sink)
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 */
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;
397 sink->theiraddr.sin_addr = sink->multi_addr.imr_multiaddr;
399 /* Joining the multicast group */
400 setsockopt (sink->sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &sink->multi_addr,
401 sizeof (sink->multi_addr));
405 sink->theiraddr.sin_addr = *((struct in_addr *) &addr);
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);
415 /* if its a hostname */
416 else if ((he = gethostbyname (sink->host))) {
417 sink->theiraddr.sin_addr = *((struct in_addr *) he->h_addr);
421 perror ("hostname lookup error?");
425 if ((sink->sock = socket (AF_INET, SOCK_DGRAM, 0)) == -1) {
431 setsockopt (sink->sock, SOL_SOCKET, SO_BROADCAST, &bc_val, sizeof (bc_val));
433 GST_FLAG_SET (sink, GST_UDPSINK_OPEN);
439 gst_udpsink_close (GstUDPSink * sink)
443 GST_FLAG_UNSET (sink, GST_UDPSINK_OPEN);
446 static GstElementStateReturn
447 gst_udpsink_change_state (GstElement * element)
449 g_return_val_if_fail (GST_IS_UDPSINK (element), GST_STATE_FAILURE);
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));
455 if (!GST_FLAG_IS_SET (element, GST_UDPSINK_OPEN)) {
456 if (!gst_udpsink_init_send (GST_UDPSINK (element)))
457 return GST_STATE_FAILURE;
461 if (GST_ELEMENT_CLASS (parent_class)->change_state)
462 return GST_ELEMENT_CLASS (parent_class)->change_state (element);
464 return GST_STATE_SUCCESS;