gst_plugins_base/gst/tcp/gsttcpclientsink.c
changeset 0 0e761a78d257
child 8 4a7fac7dd34a
equal deleted inserted replaced
-1:000000000000 0:0e761a78d257
       
     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 #ifdef __SYMBIAN32__
       
    25 #include "gst/gst-i18n-plugin.h"
       
    26 #else
       
    27 #include <gst/gst-i18n-plugin.h>
       
    28 #endif
       
    29 #include <gst/dataprotocol/dataprotocol.h>
       
    30 #include "gsttcp.h"
       
    31 #include "gsttcpclientsink.h"
       
    32 #include <string.h>             /* memset */
       
    33 
       
    34 /* elementfactory information */
       
    35 static const GstElementDetails gst_tcp_client_sink_details =
       
    36 GST_ELEMENT_DETAILS ("TCP client sink",
       
    37     "Sink/Network",
       
    38     "Send data as a client over the network via TCP",
       
    39     "Thomas Vander Stichele <thomas at apestaart dot org>");
       
    40 
       
    41 /* TCPClientSink signals and args */
       
    42 enum
       
    43 {
       
    44   FRAME_ENCODED,
       
    45   /* FILL ME */
       
    46   LAST_SIGNAL
       
    47 };
       
    48 
       
    49 GST_DEBUG_CATEGORY_STATIC (tcpclientsink_debug);
       
    50 #define GST_CAT_DEFAULT (tcpclientsink_debug)
       
    51 
       
    52 enum
       
    53 {
       
    54   ARG_0,
       
    55   ARG_HOST,
       
    56   ARG_PORT,
       
    57   ARG_PROTOCOL
       
    58       /* FILL ME */
       
    59 };
       
    60 
       
    61 static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
       
    62     GST_PAD_SINK,
       
    63     GST_PAD_ALWAYS,
       
    64     GST_STATIC_CAPS_ANY);
       
    65 
       
    66 static void gst_tcp_client_sink_base_init (gpointer g_class);
       
    67 static void gst_tcp_client_sink_class_init (GstTCPClientSink * klass);
       
    68 static void gst_tcp_client_sink_init (GstTCPClientSink * tcpclientsink);
       
    69 static void gst_tcp_client_sink_finalize (GObject * gobject);
       
    70 
       
    71 static gboolean gst_tcp_client_sink_setcaps (GstBaseSink * bsink,
       
    72     GstCaps * caps);
       
    73 static GstFlowReturn gst_tcp_client_sink_render (GstBaseSink * bsink,
       
    74     GstBuffer * buf);
       
    75 static GstStateChangeReturn gst_tcp_client_sink_change_state (GstElement *
       
    76     element, GstStateChange transition);
       
    77 
       
    78 static void gst_tcp_client_sink_set_property (GObject * object, guint prop_id,
       
    79     const GValue * value, GParamSpec * pspec);
       
    80 static void gst_tcp_client_sink_get_property (GObject * object, guint prop_id,
       
    81     GValue * value, GParamSpec * pspec);
       
    82 
       
    83 
       
    84 static GstElementClass *parent_class = NULL;
       
    85 
       
    86 /*static guint gst_tcp_client_sink_signals[LAST_SIGNAL] = { 0 }; */
       
    87 #ifdef __SYMBIAN32__
       
    88 EXPORT_C
       
    89 #endif
       
    90 
       
    91 
       
    92 GType
       
    93 gst_tcp_client_sink_get_type (void)
       
    94 {
       
    95   static GType tcpclientsink_type = 0;
       
    96 
       
    97 
       
    98   if (!tcpclientsink_type) {
       
    99     static const GTypeInfo tcpclientsink_info = {
       
   100       sizeof (GstTCPClientSinkClass),
       
   101       gst_tcp_client_sink_base_init,
       
   102       NULL,
       
   103       (GClassInitFunc) gst_tcp_client_sink_class_init,
       
   104       NULL,
       
   105       NULL,
       
   106       sizeof (GstTCPClientSink),
       
   107       0,
       
   108       (GInstanceInitFunc) gst_tcp_client_sink_init,
       
   109       NULL
       
   110     };
       
   111 
       
   112     tcpclientsink_type =
       
   113         g_type_register_static (GST_TYPE_BASE_SINK, "GstTCPClientSink",
       
   114         &tcpclientsink_info, 0);
       
   115   }
       
   116   return tcpclientsink_type;
       
   117 }
       
   118 
       
   119 static void
       
   120 gst_tcp_client_sink_base_init (gpointer g_class)
       
   121 {
       
   122   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
       
   123 
       
   124   gst_element_class_add_pad_template (element_class,
       
   125       gst_static_pad_template_get (&sinktemplate));
       
   126 
       
   127   gst_element_class_set_details (element_class, &gst_tcp_client_sink_details);
       
   128 }
       
   129 
       
   130 static void
       
   131 gst_tcp_client_sink_class_init (GstTCPClientSink * klass)
       
   132 {
       
   133   GObjectClass *gobject_class;
       
   134   GstElementClass *gstelement_class;
       
   135   GstBaseSinkClass *gstbasesink_class;
       
   136 
       
   137   gobject_class = (GObjectClass *) klass;
       
   138   gstelement_class = (GstElementClass *) klass;
       
   139   gstbasesink_class = (GstBaseSinkClass *) klass;
       
   140 
       
   141   parent_class = g_type_class_peek_parent (klass);
       
   142 
       
   143   gobject_class->set_property = gst_tcp_client_sink_set_property;
       
   144   gobject_class->get_property = gst_tcp_client_sink_get_property;
       
   145   gobject_class->finalize = gst_tcp_client_sink_finalize;
       
   146 
       
   147   g_object_class_install_property (gobject_class, ARG_HOST,
       
   148       g_param_spec_string ("host", "Host", "The host/IP to send the packets to",
       
   149           TCP_DEFAULT_HOST, G_PARAM_READWRITE));
       
   150   g_object_class_install_property (gobject_class, ARG_PORT,
       
   151       g_param_spec_int ("port", "Port", "The port to send the packets to",
       
   152           0, TCP_HIGHEST_PORT, TCP_DEFAULT_PORT, G_PARAM_READWRITE));
       
   153   g_object_class_install_property (gobject_class, ARG_PROTOCOL,
       
   154       g_param_spec_enum ("protocol", "Protocol", "The protocol to wrap data in",
       
   155           GST_TYPE_TCP_PROTOCOL, GST_TCP_PROTOCOL_NONE, G_PARAM_READWRITE));
       
   156 
       
   157   gstelement_class->change_state = gst_tcp_client_sink_change_state;
       
   158 
       
   159   gstbasesink_class->set_caps = gst_tcp_client_sink_setcaps;
       
   160   gstbasesink_class->render = gst_tcp_client_sink_render;
       
   161 
       
   162   GST_DEBUG_CATEGORY_INIT (tcpclientsink_debug, "tcpclientsink", 0, "TCP sink");
       
   163 }
       
   164 
       
   165 static void
       
   166 gst_tcp_client_sink_init (GstTCPClientSink * this)
       
   167 {
       
   168   this->host = g_strdup (TCP_DEFAULT_HOST);
       
   169   this->port = TCP_DEFAULT_PORT;
       
   170 
       
   171   this->sock_fd.fd = -1;
       
   172   this->protocol = GST_TCP_PROTOCOL_NONE;
       
   173   GST_OBJECT_FLAG_UNSET (this, GST_TCP_CLIENT_SINK_OPEN);
       
   174 }
       
   175 
       
   176 static void
       
   177 gst_tcp_client_sink_finalize (GObject * gobject)
       
   178 {
       
   179   GstTCPClientSink *this = GST_TCP_CLIENT_SINK (gobject);
       
   180 
       
   181   g_free (this->host);
       
   182 
       
   183   G_OBJECT_CLASS (parent_class)->finalize (gobject);
       
   184 }
       
   185 
       
   186 static gboolean
       
   187 gst_tcp_client_sink_setcaps (GstBaseSink * bsink, GstCaps * caps)
       
   188 {
       
   189   GstTCPClientSink *sink;
       
   190 
       
   191   sink = GST_TCP_CLIENT_SINK (bsink);
       
   192 
       
   193   /* write the buffer header if we have one */
       
   194   switch (sink->protocol) {
       
   195     case GST_TCP_PROTOCOL_NONE:
       
   196       break;
       
   197 
       
   198     case GST_TCP_PROTOCOL_GDP:
       
   199       /* if we haven't send caps yet, send them first */
       
   200       if (!sink->caps_sent) {
       
   201         const GstCaps *caps;
       
   202         gchar *string;
       
   203 
       
   204         caps = GST_PAD_CAPS (GST_PAD_PEER (GST_BASE_SINK_PAD (bsink)));
       
   205         string = gst_caps_to_string (caps);
       
   206         GST_DEBUG_OBJECT (sink, "Sending caps %s through GDP", string);
       
   207         g_free (string);
       
   208 
       
   209         if (!gst_tcp_gdp_write_caps (GST_ELEMENT (sink), sink->sock_fd.fd,
       
   210                 caps, TRUE, sink->host, sink->port))
       
   211           goto gdp_write_error;
       
   212 
       
   213         sink->caps_sent = TRUE;
       
   214       }
       
   215       break;
       
   216     default:
       
   217       g_warning ("Unhandled protocol type");
       
   218       break;
       
   219   }
       
   220 
       
   221   return TRUE;
       
   222 
       
   223   /* ERRORS */
       
   224 gdp_write_error:
       
   225   {
       
   226     return FALSE;
       
   227   }
       
   228 }
       
   229 
       
   230 static GstFlowReturn
       
   231 gst_tcp_client_sink_render (GstBaseSink * bsink, GstBuffer * buf)
       
   232 {
       
   233   size_t wrote = 0;
       
   234   GstTCPClientSink *sink;
       
   235   gint size;
       
   236 
       
   237   sink = GST_TCP_CLIENT_SINK (bsink);
       
   238 
       
   239   g_return_val_if_fail (GST_OBJECT_FLAG_IS_SET (sink, GST_TCP_CLIENT_SINK_OPEN),
       
   240       GST_FLOW_WRONG_STATE);
       
   241 
       
   242   size = GST_BUFFER_SIZE (buf);
       
   243 
       
   244   GST_LOG_OBJECT (sink, "writing %d bytes for buffer data", size);
       
   245 
       
   246   /* write the buffer header if we have one */
       
   247   switch (sink->protocol) {
       
   248     case GST_TCP_PROTOCOL_NONE:
       
   249       break;
       
   250     case GST_TCP_PROTOCOL_GDP:
       
   251       GST_LOG_OBJECT (sink, "Sending buffer header through GDP");
       
   252       if (!gst_tcp_gdp_write_buffer (GST_ELEMENT (sink), sink->sock_fd.fd, buf,
       
   253               TRUE, sink->host, sink->port))
       
   254         goto gdp_write_error;
       
   255       break;
       
   256     default:
       
   257       break;
       
   258   }
       
   259 
       
   260   /* write buffer data */
       
   261   wrote = gst_tcp_socket_write (sink->sock_fd.fd, GST_BUFFER_DATA (buf), size);
       
   262 
       
   263   if (wrote < size)
       
   264     goto write_error;
       
   265 
       
   266   sink->data_written += wrote;
       
   267 
       
   268   return GST_FLOW_OK;
       
   269 
       
   270   /* ERRORS */
       
   271 gdp_write_error:
       
   272   {
       
   273     return FALSE;
       
   274   }
       
   275 write_error:
       
   276   {
       
   277     GST_ELEMENT_ERROR (sink, RESOURCE, WRITE,
       
   278         (_("Error while sending data to \"%s:%d\"."), sink->host, sink->port),
       
   279         ("Only %" G_GSIZE_FORMAT " of %u bytes written: %s",
       
   280             wrote, GST_BUFFER_SIZE (buf), g_strerror (errno)));
       
   281     return GST_FLOW_ERROR;
       
   282   }
       
   283 }
       
   284 
       
   285 static void
       
   286 gst_tcp_client_sink_set_property (GObject * object, guint prop_id,
       
   287     const GValue * value, GParamSpec * pspec)
       
   288 {
       
   289   GstTCPClientSink *tcpclientsink;
       
   290 
       
   291   g_return_if_fail (GST_IS_TCP_CLIENT_SINK (object));
       
   292   tcpclientsink = GST_TCP_CLIENT_SINK (object);
       
   293 
       
   294   switch (prop_id) {
       
   295     case ARG_HOST:
       
   296       if (!g_value_get_string (value)) {
       
   297         g_warning ("host property cannot be NULL");
       
   298         break;
       
   299       }
       
   300       g_free (tcpclientsink->host);
       
   301       tcpclientsink->host = g_strdup (g_value_get_string (value));
       
   302       break;
       
   303     case ARG_PORT:
       
   304       tcpclientsink->port = g_value_get_int (value);
       
   305       break;
       
   306     case ARG_PROTOCOL:
       
   307       tcpclientsink->protocol = g_value_get_enum (value);
       
   308       break;
       
   309 
       
   310     default:
       
   311       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       
   312       break;
       
   313   }
       
   314 }
       
   315 
       
   316 static void
       
   317 gst_tcp_client_sink_get_property (GObject * object, guint prop_id,
       
   318     GValue * value, GParamSpec * pspec)
       
   319 {
       
   320   GstTCPClientSink *tcpclientsink;
       
   321 
       
   322   g_return_if_fail (GST_IS_TCP_CLIENT_SINK (object));
       
   323   tcpclientsink = GST_TCP_CLIENT_SINK (object);
       
   324 
       
   325   switch (prop_id) {
       
   326     case ARG_HOST:
       
   327       g_value_set_string (value, tcpclientsink->host);
       
   328       break;
       
   329     case ARG_PORT:
       
   330       g_value_set_int (value, tcpclientsink->port);
       
   331       break;
       
   332     case ARG_PROTOCOL:
       
   333       g_value_set_enum (value, tcpclientsink->protocol);
       
   334       break;
       
   335 
       
   336     default:
       
   337       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       
   338       break;
       
   339   }
       
   340 }
       
   341 
       
   342 
       
   343 /* create a socket for sending to remote machine */
       
   344 static gboolean
       
   345 gst_tcp_client_sink_start (GstTCPClientSink * this)
       
   346 {
       
   347   int ret;
       
   348   gchar *ip;
       
   349 
       
   350   if (GST_OBJECT_FLAG_IS_SET (this, GST_TCP_CLIENT_SINK_OPEN))
       
   351     return TRUE;
       
   352 
       
   353   /* reset caps_sent flag */
       
   354   this->caps_sent = FALSE;
       
   355 
       
   356   /* create sending client socket */
       
   357   GST_DEBUG_OBJECT (this, "opening sending client socket to %s:%d", this->host,
       
   358       this->port);
       
   359   if ((this->sock_fd.fd = socket (AF_INET, SOCK_STREAM, 0)) == -1) {
       
   360     GST_ELEMENT_ERROR (this, RESOURCE, OPEN_WRITE, (NULL), GST_ERROR_SYSTEM);
       
   361     return FALSE;
       
   362   }
       
   363   GST_DEBUG_OBJECT (this, "opened sending client socket with fd %d",
       
   364       this->sock_fd.fd);
       
   365 
       
   366   /* look up name if we need to */
       
   367   ip = gst_tcp_host_to_ip (GST_ELEMENT (this), this->host);
       
   368   if (!ip) {
       
   369     gst_tcp_socket_close (&this->sock_fd);
       
   370     return FALSE;
       
   371   }
       
   372   GST_DEBUG_OBJECT (this, "IP address for host %s is %s", this->host, ip);
       
   373 
       
   374   /* connect to server */
       
   375   memset (&this->server_sin, 0, sizeof (this->server_sin));
       
   376   this->server_sin.sin_family = AF_INET;        /* network socket */
       
   377   this->server_sin.sin_port = htons (this->port);       /* on port */
       
   378   this->server_sin.sin_addr.s_addr = inet_addr (ip);    /* on host ip */
       
   379   g_free (ip);
       
   380 
       
   381   GST_DEBUG_OBJECT (this, "connecting to server");
       
   382   ret = connect (this->sock_fd.fd, (struct sockaddr *) &this->server_sin,
       
   383       sizeof (this->server_sin));
       
   384 
       
   385   if (ret) {
       
   386     gst_tcp_socket_close (&this->sock_fd);
       
   387     switch (errno) {
       
   388       case ECONNREFUSED:
       
   389         GST_ELEMENT_ERROR (this, RESOURCE, OPEN_WRITE,
       
   390             (_("Connection to %s:%d refused."), this->host, this->port),
       
   391             (NULL));
       
   392         return FALSE;
       
   393         break;
       
   394       default:
       
   395         GST_ELEMENT_ERROR (this, RESOURCE, OPEN_READ, (NULL),
       
   396             ("connect to %s:%d failed: %s", this->host, this->port,
       
   397                 g_strerror (errno)));
       
   398         return FALSE;
       
   399         break;
       
   400     }
       
   401   }
       
   402 
       
   403   GST_OBJECT_FLAG_SET (this, GST_TCP_CLIENT_SINK_OPEN);
       
   404 
       
   405   this->data_written = 0;
       
   406 
       
   407   return TRUE;
       
   408 }
       
   409 
       
   410 static gboolean
       
   411 gst_tcp_client_sink_stop (GstTCPClientSink * this)
       
   412 {
       
   413   if (!GST_OBJECT_FLAG_IS_SET (this, GST_TCP_CLIENT_SINK_OPEN))
       
   414     return TRUE;
       
   415 
       
   416   gst_tcp_socket_close (&this->sock_fd);
       
   417 
       
   418   GST_OBJECT_FLAG_UNSET (this, GST_TCP_CLIENT_SINK_OPEN);
       
   419 
       
   420   return TRUE;
       
   421 }
       
   422 
       
   423 static GstStateChangeReturn
       
   424 gst_tcp_client_sink_change_state (GstElement * element,
       
   425     GstStateChange transition)
       
   426 {
       
   427   GstTCPClientSink *sink;
       
   428   GstStateChangeReturn res;
       
   429 
       
   430   sink = GST_TCP_CLIENT_SINK (element);
       
   431 
       
   432   switch (transition) {
       
   433     case GST_STATE_CHANGE_NULL_TO_READY:
       
   434     case GST_STATE_CHANGE_READY_TO_PAUSED:
       
   435       if (!gst_tcp_client_sink_start (GST_TCP_CLIENT_SINK (element)))
       
   436         goto start_failure;
       
   437       break;
       
   438     default:
       
   439       break;
       
   440   }
       
   441   res = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
       
   442 
       
   443   switch (transition) {
       
   444     case GST_STATE_CHANGE_READY_TO_NULL:
       
   445       gst_tcp_client_sink_stop (GST_TCP_CLIENT_SINK (element));
       
   446     default:
       
   447       break;
       
   448   }
       
   449   return res;
       
   450 
       
   451 start_failure:
       
   452   {
       
   453     return GST_STATE_CHANGE_FAILURE;
       
   454   }
       
   455 }