Ported tcp plugins to 0.9.
[platform/upstream/gstreamer.git] / gst / tcp / gsttcpclientsink.c
1 /* GStreamer
2  * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3  * Copyright (C) <2004> Thomas Vander Stichele <thomas at apestaart dot org>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24 #include <gst/gst-i18n-plugin.h>
25 #include <gst/dataprotocol/dataprotocol.h>
26 #include "gsttcp.h"
27 #include "gsttcpclientsink.h"
28
29 /* elementfactory information */
30 static GstElementDetails gst_tcpclientsink_details =
31 GST_ELEMENT_DETAILS ("TCP Client sink",
32     "Sink/Network",
33     "Send data as a client over the network via TCP",
34     "Thomas Vander Stichele <thomas at apestaart dot org>");
35
36 /* TCPClientSink signals and args */
37 enum
38 {
39   FRAME_ENCODED,
40   /* FILL ME */
41   LAST_SIGNAL
42 };
43
44 GST_DEBUG_CATEGORY (tcpclientsink_debug);
45 #define GST_CAT_DEFAULT (tcpclientsink_debug)
46
47 enum
48 {
49   ARG_0,
50   ARG_HOST,
51   ARG_PORT,
52   ARG_PROTOCOL
53       /* FILL ME */
54 };
55
56 static void gst_tcpclientsink_base_init (gpointer g_class);
57 static void gst_tcpclientsink_class_init (GstTCPClientSink * klass);
58 static void gst_tcpclientsink_init (GstTCPClientSink * tcpclientsink);
59 static void gst_tcpclientsink_finalize (GObject * gobject);
60
61 static gboolean gst_tcpclientsink_setcaps (GstBaseSink * bsink, GstCaps * caps);
62 static GstFlowReturn gst_tcpclientsink_render (GstBaseSink * bsink,
63     GstBuffer * buf);
64 static GstElementStateReturn gst_tcpclientsink_change_state (GstElement *
65     element);
66
67 static void gst_tcpclientsink_set_property (GObject * object, guint prop_id,
68     const GValue * value, GParamSpec * pspec);
69 static void gst_tcpclientsink_get_property (GObject * object, guint prop_id,
70     GValue * value, GParamSpec * pspec);
71
72
73 static GstElementClass *parent_class = NULL;
74
75 /*static guint gst_tcpclientsink_signals[LAST_SIGNAL] = { 0 }; */
76
77 GType
78 gst_tcpclientsink_get_type (void)
79 {
80   static GType tcpclientsink_type = 0;
81
82
83   if (!tcpclientsink_type) {
84     static const GTypeInfo tcpclientsink_info = {
85       sizeof (GstTCPClientSinkClass),
86       gst_tcpclientsink_base_init,
87       NULL,
88       (GClassInitFunc) gst_tcpclientsink_class_init,
89       NULL,
90       NULL,
91       sizeof (GstTCPClientSink),
92       0,
93       (GInstanceInitFunc) gst_tcpclientsink_init,
94       NULL
95     };
96
97     tcpclientsink_type =
98         g_type_register_static (GST_TYPE_ELEMENT, "GstTCPClientSink",
99         &tcpclientsink_info, 0);
100   }
101   return tcpclientsink_type;
102 }
103
104 static void
105 gst_tcpclientsink_base_init (gpointer g_class)
106 {
107   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
108
109   gst_element_class_set_details (element_class, &gst_tcpclientsink_details);
110 }
111
112 static void
113 gst_tcpclientsink_class_init (GstTCPClientSink * klass)
114 {
115   GObjectClass *gobject_class;
116   GstElementClass *gstelement_class;
117   GstBaseSinkClass *gstbasesink_class;
118
119   gobject_class = (GObjectClass *) klass;
120   gstelement_class = (GstElementClass *) klass;
121   gstbasesink_class = (GstBaseSinkClass *) klass;
122
123   parent_class = g_type_class_ref (GST_TYPE_BASESINK);
124
125   gobject_class->set_property = gst_tcpclientsink_set_property;
126   gobject_class->get_property = gst_tcpclientsink_get_property;
127   gobject_class->finalize = gst_tcpclientsink_finalize;
128
129   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_HOST,
130       g_param_spec_string ("host", "Host", "The host/IP to send the packets to",
131           TCP_DEFAULT_HOST, G_PARAM_READWRITE));
132   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_PORT,
133       g_param_spec_int ("port", "Port", "The port to send the packets to",
134           0, TCP_HIGHEST_PORT, TCP_DEFAULT_PORT, G_PARAM_READWRITE));
135   g_object_class_install_property (gobject_class, ARG_PROTOCOL,
136       g_param_spec_enum ("protocol", "Protocol", "The protocol to wrap data in",
137           GST_TYPE_TCP_PROTOCOL_TYPE, GST_TCP_PROTOCOL_TYPE_NONE,
138           G_PARAM_READWRITE));
139
140   gstelement_class->change_state = gst_tcpclientsink_change_state;
141
142   gstbasesink_class->set_caps = gst_tcpclientsink_setcaps;
143   gstbasesink_class->render = gst_tcpclientsink_render;
144
145   GST_DEBUG_CATEGORY_INIT (tcpclientsink_debug, "tcpclientsink", 0, "TCP sink");
146 }
147
148 static void
149 gst_tcpclientsink_init (GstTCPClientSink * this)
150 {
151   this->host = g_strdup (TCP_DEFAULT_HOST);
152   this->port = TCP_DEFAULT_PORT;
153
154   this->sock_fd = -1;
155   this->protocol = GST_TCP_PROTOCOL_TYPE_NONE;
156   GST_FLAG_UNSET (this, GST_TCPCLIENTSINK_OPEN);
157 }
158
159 static void
160 gst_tcpclientsink_finalize (GObject * gobject)
161 {
162   GstTCPClientSink *this = GST_TCPCLIENTSINK (gobject);
163
164   g_free (this->host);
165 }
166
167 static gboolean
168 gst_tcpclientsink_setcaps (GstBaseSink * bsink, GstCaps * caps)
169 {
170   GstTCPClientSink *sink;
171
172   sink = GST_TCPCLIENTSINK (bsink);
173
174   /* write the buffer header if we have one */
175   switch (sink->protocol) {
176     case GST_TCP_PROTOCOL_TYPE_NONE:
177       break;
178
179     case GST_TCP_PROTOCOL_TYPE_GDP:
180       /* if we haven't send caps yet, send them first */
181       if (!sink->caps_sent) {
182         const GstCaps *caps;
183         gchar *string;
184
185         caps = GST_PAD_CAPS (GST_PAD_PEER (GST_BASESINK_PAD (bsink)));
186         string = gst_caps_to_string (caps);
187         GST_DEBUG_OBJECT (sink, "Sending caps %s through GDP", string);
188         g_free (string);
189
190         if (!gst_tcp_gdp_write_caps (GST_ELEMENT (sink), sink->sock_fd, caps,
191                 TRUE, sink->host, sink->port))
192           goto gdp_write_error;
193
194         sink->caps_sent = TRUE;
195       }
196       break;
197     default:
198       g_warning ("Unhandled protocol type");
199       break;
200   }
201
202   return TRUE;
203
204   /* ERRORS */
205 gdp_write_error:
206   {
207     return FALSE;
208   }
209 }
210
211 static GstFlowReturn
212 gst_tcpclientsink_render (GstBaseSink * bsink, GstBuffer * buf)
213 {
214   size_t wrote = 0;
215   GstTCPClientSink *sink;
216   gint size;
217
218   sink = GST_TCPCLIENTSINK (bsink);
219
220   g_return_val_if_fail (GST_FLAG_IS_SET (sink, GST_TCPCLIENTSINK_OPEN),
221       GST_FLOW_WRONG_STATE);
222
223   size = GST_BUFFER_SIZE (buf);
224
225   GST_LOG_OBJECT (sink, "writing %d bytes for buffer data", size);
226
227   /* write the buffer header if we have one */
228   switch (sink->protocol) {
229     case GST_TCP_PROTOCOL_TYPE_NONE:
230       break;
231     case GST_TCP_PROTOCOL_TYPE_GDP:
232       GST_LOG_OBJECT (sink, "Sending buffer header through GDP");
233       if (!gst_tcp_gdp_write_buffer (GST_ELEMENT (sink), sink->sock_fd, buf,
234               TRUE, sink->host, sink->port))
235         goto gdp_write_error;
236       break;
237     default:
238       break;
239   }
240
241   /* write buffer data */
242   wrote = gst_tcp_socket_write (sink->sock_fd, GST_BUFFER_DATA (buf), size);
243
244   if (wrote < size)
245     goto write_error;
246
247   sink->data_written += wrote;
248
249   return GST_FLOW_OK;
250
251   /* ERRORS */
252 gdp_write_error:
253   {
254     return FALSE;
255   }
256 write_error:
257   {
258     GST_ELEMENT_ERROR (sink, RESOURCE, WRITE,
259         (_("Error while sending data to \"%s:%d\"."), sink->host, sink->port),
260         ("Only %d of %d bytes written: %s",
261             wrote, GST_BUFFER_SIZE (buf), g_strerror (errno)));
262     return GST_FLOW_ERROR;
263   }
264 }
265
266 static void
267 gst_tcpclientsink_set_property (GObject * object, guint prop_id,
268     const GValue * value, GParamSpec * pspec)
269 {
270   GstTCPClientSink *tcpclientsink;
271
272   /* it's not null if we got it, but it might not be ours */
273   g_return_if_fail (GST_IS_TCPCLIENTSINK (object));
274   tcpclientsink = GST_TCPCLIENTSINK (object);
275
276   switch (prop_id) {
277     case ARG_HOST:
278       if (!g_value_get_string (value)) {
279         g_warning ("host property cannot be NULL");
280         break;
281       }
282       g_free (tcpclientsink->host);
283       tcpclientsink->host = g_strdup (g_value_get_string (value));
284       break;
285     case ARG_PORT:
286       tcpclientsink->port = g_value_get_int (value);
287       break;
288     case ARG_PROTOCOL:
289       tcpclientsink->protocol = g_value_get_enum (value);
290       break;
291
292     default:
293       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
294       break;
295   }
296 }
297
298 static void
299 gst_tcpclientsink_get_property (GObject * object, guint prop_id, GValue * value,
300     GParamSpec * pspec)
301 {
302   GstTCPClientSink *tcpclientsink;
303
304   /* it's not null if we got it, but it might not be ours */
305   g_return_if_fail (GST_IS_TCPCLIENTSINK (object));
306   tcpclientsink = GST_TCPCLIENTSINK (object);
307
308   switch (prop_id) {
309     case ARG_HOST:
310       g_value_set_string (value, tcpclientsink->host);
311       break;
312     case ARG_PORT:
313       g_value_set_int (value, tcpclientsink->port);
314       break;
315     case ARG_PROTOCOL:
316       g_value_set_enum (value, tcpclientsink->protocol);
317       break;
318
319     default:
320       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
321       break;
322   }
323 }
324
325
326 /* create a socket for sending to remote machine */
327 static gboolean
328 gst_tcpclientsink_start (GstTCPClientSink * this)
329 {
330   int ret;
331   gchar *ip;
332
333   if (GST_FLAG_IS_SET (this, GST_TCPCLIENTSINK_OPEN))
334     return TRUE;
335
336   /* reset caps_sent flag */
337   this->caps_sent = FALSE;
338
339   /* create sending client socket */
340   GST_DEBUG_OBJECT (this, "opening sending client socket to %s:%d", this->host,
341       this->port);
342   if ((this->sock_fd = socket (AF_INET, SOCK_STREAM, 0)) == -1) {
343     GST_ELEMENT_ERROR (this, RESOURCE, OPEN_WRITE, (NULL), GST_ERROR_SYSTEM);
344     return FALSE;
345   }
346   GST_DEBUG_OBJECT (this, "opened sending client socket with fd %d",
347       this->sock_fd);
348
349   /* look up name if we need to */
350   ip = gst_tcp_host_to_ip (GST_ELEMENT (this), this->host);
351   if (!ip) {
352     gst_tcp_socket_close (&this->sock_fd);
353     return FALSE;
354   }
355   GST_DEBUG_OBJECT (this, "IP address for host %s is %s", this->host, ip);
356
357   /* connect to server */
358   memset (&this->server_sin, 0, sizeof (this->server_sin));
359   this->server_sin.sin_family = AF_INET;        /* network socket */
360   this->server_sin.sin_port = htons (this->port);       /* on port */
361   this->server_sin.sin_addr.s_addr = inet_addr (ip);    /* on host ip */
362   g_free (ip);
363
364   GST_DEBUG_OBJECT (this, "connecting to server");
365   ret = connect (this->sock_fd, (struct sockaddr *) &this->server_sin,
366       sizeof (this->server_sin));
367
368   if (ret) {
369     gst_tcp_socket_close (&this->sock_fd);
370     switch (errno) {
371       case ECONNREFUSED:
372         GST_ELEMENT_ERROR (this, RESOURCE, OPEN_WRITE,
373             (_("Connection to %s:%d refused."), this->host, this->port),
374             (NULL));
375         return FALSE;
376         break;
377       default:
378         GST_ELEMENT_ERROR (this, RESOURCE, OPEN_READ, (NULL),
379             ("connect to %s:%d failed: %s", this->host, this->port,
380                 g_strerror (errno)));
381         return FALSE;
382         break;
383     }
384   }
385
386   GST_FLAG_SET (this, GST_TCPCLIENTSINK_OPEN);
387
388   this->data_written = 0;
389
390   return TRUE;
391 }
392
393 static gboolean
394 gst_tcpclientsink_stop (GstTCPClientSink * this)
395 {
396   if (!GST_FLAG_IS_SET (this, GST_TCPCLIENTSINK_OPEN))
397     return TRUE;
398
399   if (this->sock_fd != -1) {
400     close (this->sock_fd);
401     this->sock_fd = -1;
402   }
403
404   GST_FLAG_UNSET (this, GST_TCPCLIENTSINK_OPEN);
405
406   return TRUE;
407 }
408
409 static GstElementStateReturn
410 gst_tcpclientsink_change_state (GstElement * element)
411 {
412   GstTCPClientSink *sink;
413   gint transition;
414   GstElementStateReturn res;
415
416   sink = GST_TCPCLIENTSINK (element);
417   transition = GST_STATE_TRANSITION (element);
418
419   switch (transition) {
420     case GST_STATE_NULL_TO_READY:
421     case GST_STATE_READY_TO_PAUSED:
422       if (!gst_tcpclientsink_start (GST_TCPCLIENTSINK (element)))
423         goto start_failure;
424       break;
425     default:
426       break;
427   }
428   res = GST_ELEMENT_CLASS (parent_class)->change_state (element);
429
430   switch (transition) {
431     case GST_STATE_READY_TO_NULL:
432       gst_tcpclientsink_stop (GST_TCPCLIENTSINK (element));
433     default:
434       break;
435   }
436   return res;
437
438 start_failure:
439   {
440     return GST_STATE_FAILURE;
441   }
442 }