2 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3 * Copyright (C) <2004> Thomas Vander Stichele <thomas at apestaart dot org>
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.
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.
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.
24 #include <gst/gst-i18n-plugin.h>
25 #include <gst/dataprotocol/dataprotocol.h>
27 #include "gsttcpclientsink.h"
29 /* elementfactory information */
30 static GstElementDetails gst_tcpclientsink_details =
31 GST_ELEMENT_DETAILS ("TCP Client sink",
33 "Send data as a client over the network via TCP",
34 "Thomas Vander Stichele <thomas at apestaart dot org>");
36 /* TCPClientSink signals and args */
44 GST_DEBUG_CATEGORY (tcpclientsink_debug);
45 #define GST_CAT_DEFAULT (tcpclientsink_debug)
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);
61 static gboolean gst_tcpclientsink_setcaps (GstBaseSink * bsink, GstCaps * caps);
62 static GstFlowReturn gst_tcpclientsink_render (GstBaseSink * bsink,
64 static GstElementStateReturn gst_tcpclientsink_change_state (GstElement *
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);
73 static GstElementClass *parent_class = NULL;
75 /*static guint gst_tcpclientsink_signals[LAST_SIGNAL] = { 0 }; */
78 gst_tcpclientsink_get_type (void)
80 static GType tcpclientsink_type = 0;
83 if (!tcpclientsink_type) {
84 static const GTypeInfo tcpclientsink_info = {
85 sizeof (GstTCPClientSinkClass),
86 gst_tcpclientsink_base_init,
88 (GClassInitFunc) gst_tcpclientsink_class_init,
91 sizeof (GstTCPClientSink),
93 (GInstanceInitFunc) gst_tcpclientsink_init,
98 g_type_register_static (GST_TYPE_ELEMENT, "GstTCPClientSink",
99 &tcpclientsink_info, 0);
101 return tcpclientsink_type;
105 gst_tcpclientsink_base_init (gpointer g_class)
107 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
109 gst_element_class_set_details (element_class, &gst_tcpclientsink_details);
113 gst_tcpclientsink_class_init (GstTCPClientSink * klass)
115 GObjectClass *gobject_class;
116 GstElementClass *gstelement_class;
117 GstBaseSinkClass *gstbasesink_class;
119 gobject_class = (GObjectClass *) klass;
120 gstelement_class = (GstElementClass *) klass;
121 gstbasesink_class = (GstBaseSinkClass *) klass;
123 parent_class = g_type_class_ref (GST_TYPE_BASESINK);
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;
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,
140 gstelement_class->change_state = gst_tcpclientsink_change_state;
142 gstbasesink_class->set_caps = gst_tcpclientsink_setcaps;
143 gstbasesink_class->render = gst_tcpclientsink_render;
145 GST_DEBUG_CATEGORY_INIT (tcpclientsink_debug, "tcpclientsink", 0, "TCP sink");
149 gst_tcpclientsink_init (GstTCPClientSink * this)
151 this->host = g_strdup (TCP_DEFAULT_HOST);
152 this->port = TCP_DEFAULT_PORT;
155 this->protocol = GST_TCP_PROTOCOL_TYPE_NONE;
156 GST_FLAG_UNSET (this, GST_TCPCLIENTSINK_OPEN);
160 gst_tcpclientsink_finalize (GObject * gobject)
162 GstTCPClientSink *this = GST_TCPCLIENTSINK (gobject);
168 gst_tcpclientsink_setcaps (GstBaseSink * bsink, GstCaps * caps)
170 GstTCPClientSink *sink;
172 sink = GST_TCPCLIENTSINK (bsink);
174 /* write the buffer header if we have one */
175 switch (sink->protocol) {
176 case GST_TCP_PROTOCOL_TYPE_NONE:
179 case GST_TCP_PROTOCOL_TYPE_GDP:
180 /* if we haven't send caps yet, send them first */
181 if (!sink->caps_sent) {
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);
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;
194 sink->caps_sent = TRUE;
198 g_warning ("Unhandled protocol type");
212 gst_tcpclientsink_render (GstBaseSink * bsink, GstBuffer * buf)
215 GstTCPClientSink *sink;
218 sink = GST_TCPCLIENTSINK (bsink);
220 g_return_val_if_fail (GST_FLAG_IS_SET (sink, GST_TCPCLIENTSINK_OPEN),
221 GST_FLOW_WRONG_STATE);
223 size = GST_BUFFER_SIZE (buf);
225 GST_LOG_OBJECT (sink, "writing %d bytes for buffer data", size);
227 /* write the buffer header if we have one */
228 switch (sink->protocol) {
229 case GST_TCP_PROTOCOL_TYPE_NONE:
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;
241 /* write buffer data */
242 wrote = gst_tcp_socket_write (sink->sock_fd, GST_BUFFER_DATA (buf), size);
247 sink->data_written += wrote;
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;
267 gst_tcpclientsink_set_property (GObject * object, guint prop_id,
268 const GValue * value, GParamSpec * pspec)
270 GstTCPClientSink *tcpclientsink;
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);
278 if (!g_value_get_string (value)) {
279 g_warning ("host property cannot be NULL");
282 g_free (tcpclientsink->host);
283 tcpclientsink->host = g_strdup (g_value_get_string (value));
286 tcpclientsink->port = g_value_get_int (value);
289 tcpclientsink->protocol = g_value_get_enum (value);
293 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
299 gst_tcpclientsink_get_property (GObject * object, guint prop_id, GValue * value,
302 GstTCPClientSink *tcpclientsink;
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);
310 g_value_set_string (value, tcpclientsink->host);
313 g_value_set_int (value, tcpclientsink->port);
316 g_value_set_enum (value, tcpclientsink->protocol);
320 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
326 /* create a socket for sending to remote machine */
328 gst_tcpclientsink_start (GstTCPClientSink * this)
333 if (GST_FLAG_IS_SET (this, GST_TCPCLIENTSINK_OPEN))
336 /* reset caps_sent flag */
337 this->caps_sent = FALSE;
339 /* create sending client socket */
340 GST_DEBUG_OBJECT (this, "opening sending client socket to %s:%d", this->host,
342 if ((this->sock_fd = socket (AF_INET, SOCK_STREAM, 0)) == -1) {
343 GST_ELEMENT_ERROR (this, RESOURCE, OPEN_WRITE, (NULL), GST_ERROR_SYSTEM);
346 GST_DEBUG_OBJECT (this, "opened sending client socket with fd %d",
349 /* look up name if we need to */
350 ip = gst_tcp_host_to_ip (GST_ELEMENT (this), this->host);
352 gst_tcp_socket_close (&this->sock_fd);
355 GST_DEBUG_OBJECT (this, "IP address for host %s is %s", this->host, ip);
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 */
364 GST_DEBUG_OBJECT (this, "connecting to server");
365 ret = connect (this->sock_fd, (struct sockaddr *) &this->server_sin,
366 sizeof (this->server_sin));
369 gst_tcp_socket_close (&this->sock_fd);
372 GST_ELEMENT_ERROR (this, RESOURCE, OPEN_WRITE,
373 (_("Connection to %s:%d refused."), this->host, this->port),
378 GST_ELEMENT_ERROR (this, RESOURCE, OPEN_READ, (NULL),
379 ("connect to %s:%d failed: %s", this->host, this->port,
380 g_strerror (errno)));
386 GST_FLAG_SET (this, GST_TCPCLIENTSINK_OPEN);
388 this->data_written = 0;
394 gst_tcpclientsink_stop (GstTCPClientSink * this)
396 if (!GST_FLAG_IS_SET (this, GST_TCPCLIENTSINK_OPEN))
399 if (this->sock_fd != -1) {
400 close (this->sock_fd);
404 GST_FLAG_UNSET (this, GST_TCPCLIENTSINK_OPEN);
409 static GstElementStateReturn
410 gst_tcpclientsink_change_state (GstElement * element)
412 GstTCPClientSink *sink;
414 GstElementStateReturn res;
416 sink = GST_TCPCLIENTSINK (element);
417 transition = GST_STATE_TRANSITION (element);
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)))
428 res = GST_ELEMENT_CLASS (parent_class)->change_state (element);
430 switch (transition) {
431 case GST_STATE_READY_TO_NULL:
432 gst_tcpclientsink_stop (GST_TCPCLIENTSINK (element));
440 return GST_STATE_FAILURE;