LCOV - code coverage report
Current view: top level - libs/gst/net - gstnetclientclock.c (source / functions) Hit Total Coverage
Test: GStreamer 0.10.32.1 Lines: 156 203 76.8 %
Date: 2011-03-25 Functions: 14 14 100.0 %
Branches: 53 164 32.3 %

           Branch data     Line data    Source code
       1                 :            : /* GStreamer
       2                 :            :  * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
       3                 :            :  *                    2005 Wim Taymans <wim@fluendo.com>
       4                 :            :  *                    2005 Andy Wingo <wingo@pobox.com>
       5                 :            :  *
       6                 :            :  * gstnetclientclock.h: clock that synchronizes itself to a time provider over
       7                 :            :  * the network
       8                 :            :  *
       9                 :            :  * This library is free software; you can redistribute it and/or
      10                 :            :  * modify it under the terms of the GNU Library General Public
      11                 :            :  * License as published by the Free Software Foundation; either
      12                 :            :  * version 2 of the License, or (at your option) any later version.
      13                 :            :  *
      14                 :            :  * This library is distributed in the hope that it will be useful,
      15                 :            :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      16                 :            :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      17                 :            :  * Library General Public License for more details.
      18                 :            :  *
      19                 :            :  * You should have received a copy of the GNU Library General Public
      20                 :            :  * License along with this library; if not, write to the
      21                 :            :  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
      22                 :            :  * Boston, MA 02111-1307, USA.
      23                 :            :  */
      24                 :            : /**
      25                 :            :  * SECTION:gstnetclientclock
      26                 :            :  * @short_description: Special clock that synchronizes to a remote time
      27                 :            :  *                     provider.
      28                 :            :  * @see_also: #GstClock, #GstNetTimeProvider, #GstPipeline
      29                 :            :  *
      30                 :            :  * This object implements a custom #GstClock that synchronizes its time
      31                 :            :  * to a remote time provider such as #GstNetTimeProvider.
      32                 :            :  *
      33                 :            :  * A new clock is created with gst_net_client_clock_new() which takes the
      34                 :            :  * address and port of the remote time provider along with a name and
      35                 :            :  * an initial time.
      36                 :            :  *
      37                 :            :  * This clock will poll the time provider and will update its calibration
      38                 :            :  * parameters based on the local and remote observations.
      39                 :            :  *
      40                 :            :  * Various parameters of the clock can be configured with the parent #GstClock
      41                 :            :  * "timeout", "window-size" and "window-threshold" object properties.
      42                 :            :  *
      43                 :            :  * A #GstNetClientClock is typically set on a #GstPipeline with 
      44                 :            :  * gst_pipeline_use_clock().
      45                 :            :  *
      46                 :            :  * Last reviewed on 2005-11-23 (0.9.5)
      47                 :            :  */
      48                 :            : 
      49                 :            : #ifdef HAVE_CONFIG_H
      50                 :            : #include "config.h"
      51                 :            : #endif
      52                 :            : 
      53                 :            : #include "gstnettimepacket.h"
      54                 :            : #include "gstnetclientclock.h"
      55                 :            : 
      56                 :            : #ifdef HAVE_UNISTD_H
      57                 :            : #include <unistd.h>
      58                 :            : #endif
      59                 :            : 
      60                 :            : #if defined (_MSC_VER) && _MSC_VER >= 1400
      61                 :            : #include <io.h>
      62                 :            : #endif
      63                 :            : 
      64                 :            : GST_DEBUG_CATEGORY_STATIC (ncc_debug);
      65                 :            : #define GST_CAT_DEFAULT (ncc_debug)
      66                 :            : 
      67                 :            : #define DEFAULT_ADDRESS         "127.0.0.1"
      68                 :            : #define DEFAULT_PORT            5637
      69                 :            : #define DEFAULT_TIMEOUT         GST_SECOND
      70                 :            : 
      71                 :            : #ifdef G_OS_WIN32
      72                 :            : #define getsockname(sock,addr,len) getsockname(sock,addr,(int *)len)
      73                 :            : #endif
      74                 :            : 
      75                 :            : enum
      76                 :            : {
      77                 :            :   PROP_0,
      78                 :            :   PROP_ADDRESS,
      79                 :            :   PROP_PORT,
      80                 :            : };
      81                 :            : 
      82                 :            : #define GST_NET_CLIENT_CLOCK_GET_PRIVATE(obj)  \
      83                 :            :   (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_NET_CLIENT_CLOCK, GstNetClientClockPrivate))
      84                 :            : 
      85                 :            : struct _GstNetClientClockPrivate
      86                 :            : {
      87                 :            :   GstPollFD sock;
      88                 :            :   GstPoll *fdset;
      89                 :            : };
      90                 :            : 
      91                 :            : #define _do_init(type) \
      92                 :            :   GST_DEBUG_CATEGORY_INIT (ncc_debug, "netclock", 0, "Network client clock");
      93                 :            : 
      94 [ +  + ][ +  - ]:         13 : GST_BOILERPLATE_FULL (GstNetClientClock, gst_net_client_clock,
      95                 :         13 :     GstSystemClock, GST_TYPE_SYSTEM_CLOCK, _do_init);
      96                 :            : 
      97                 :            : static void gst_net_client_clock_finalize (GObject * object);
      98                 :            : static void gst_net_client_clock_set_property (GObject * object, guint prop_id,
      99                 :            :     const GValue * value, GParamSpec * pspec);
     100                 :            : static void gst_net_client_clock_get_property (GObject * object, guint prop_id,
     101                 :            :     GValue * value, GParamSpec * pspec);
     102                 :            : 
     103                 :            : static void gst_net_client_clock_stop (GstNetClientClock * self);
     104                 :            : 
     105                 :            : #ifdef G_OS_WIN32
     106                 :            : static int
     107                 :            : inet_aton (const char *c, struct in_addr *paddr)
     108                 :            : {
     109                 :            :   /* note that inet_addr is deprecated on unix because
     110                 :            :    * inet_addr returns -1 (INADDR_NONE) for the valid 255.255.255.255
     111                 :            :    * address. */
     112                 :            :   paddr->s_addr = inet_addr (c);
     113                 :            :   if (paddr->s_addr == INADDR_NONE)
     114                 :            :     return 0;
     115                 :            : 
     116                 :            :   return 1;
     117                 :            : }
     118                 :            : #endif
     119                 :            : 
     120                 :            : static void
     121                 :          2 : gst_net_client_clock_base_init (gpointer g_class)
     122                 :            : {
     123                 :            :   /* nop */
     124                 :          2 : }
     125                 :            : 
     126                 :            : static void
     127                 :          2 : gst_net_client_clock_class_init (GstNetClientClockClass * klass)
     128                 :            : {
     129                 :            :   GObjectClass *gobject_class;
     130                 :            : 
     131                 :          2 :   gobject_class = G_OBJECT_CLASS (klass);
     132                 :            : 
     133                 :          2 :   g_type_class_add_private (klass, sizeof (GstNetClientClockPrivate));
     134                 :            : 
     135                 :          2 :   gobject_class->finalize = gst_net_client_clock_finalize;
     136                 :          2 :   gobject_class->get_property = gst_net_client_clock_get_property;
     137                 :          2 :   gobject_class->set_property = gst_net_client_clock_set_property;
     138                 :            : 
     139                 :          2 :   g_object_class_install_property (gobject_class, PROP_ADDRESS,
     140                 :            :       g_param_spec_string ("address", "address",
     141                 :            :           "The address of the machine providing a time server, "
     142                 :            :           "as a dotted quad (x.x.x.x)", DEFAULT_ADDRESS,
     143                 :            :           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
     144                 :          2 :   g_object_class_install_property (gobject_class, PROP_PORT,
     145                 :            :       g_param_spec_int ("port", "port",
     146                 :            :           "The port on which the remote server is listening", 0, G_MAXUINT16,
     147                 :            :           DEFAULT_PORT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
     148                 :          2 : }
     149                 :            : 
     150                 :            : static void
     151                 :          2 : gst_net_client_clock_init (GstNetClientClock * self,
     152                 :            :     GstNetClientClockClass * g_class)
     153                 :            : {
     154                 :          2 :   GstClock *clock = GST_CLOCK_CAST (self);
     155                 :            : 
     156                 :            : #ifdef G_OS_WIN32
     157                 :            :   WSADATA w;
     158                 :            :   int error = WSAStartup (0x0202, &w);
     159                 :            : 
     160                 :            :   if (error) {
     161                 :            :     GST_DEBUG_OBJECT (self, "Error on WSAStartup");
     162                 :            :   }
     163                 :            :   if (w.wVersion != 0x0202) {
     164                 :            :     WSACleanup ();
     165                 :            :   }
     166                 :            : #endif
     167                 :          2 :   self->priv = GST_NET_CLIENT_CLOCK_GET_PRIVATE (self);
     168                 :            : 
     169                 :          2 :   self->port = DEFAULT_PORT;
     170                 :          2 :   self->address = g_strdup (DEFAULT_ADDRESS);
     171                 :            : 
     172                 :          2 :   clock->timeout = DEFAULT_TIMEOUT;
     173                 :            : 
     174                 :          2 :   self->priv->sock.fd = -1;
     175                 :          2 :   self->thread = NULL;
     176                 :            : 
     177                 :          2 :   self->servaddr = NULL;
     178                 :          2 : }
     179                 :            : 
     180                 :            : static void
     181                 :          2 : gst_net_client_clock_finalize (GObject * object)
     182                 :            : {
     183                 :          2 :   GstNetClientClock *self = GST_NET_CLIENT_CLOCK (object);
     184                 :            : 
     185         [ +  - ]:          2 :   if (self->thread) {
     186                 :          2 :     gst_net_client_clock_stop (self);
     187         [ -  + ]:          2 :     g_assert (self->thread == NULL);
     188                 :            :   }
     189                 :            : 
     190         [ +  - ]:          2 :   if (self->priv->fdset) {
     191                 :          2 :     gst_poll_free (self->priv->fdset);
     192                 :          2 :     self->priv->fdset = NULL;
     193                 :            :   }
     194                 :            : 
     195                 :          2 :   g_free (self->address);
     196                 :          2 :   self->address = NULL;
     197                 :            : 
     198                 :          2 :   g_free (self->servaddr);
     199                 :          2 :   self->servaddr = NULL;
     200                 :            : 
     201                 :            : #ifdef G_OS_WIN32
     202                 :            :   WSACleanup ();
     203                 :            : #endif
     204                 :            : 
     205                 :          2 :   G_OBJECT_CLASS (parent_class)->finalize (object);
     206                 :          2 : }
     207                 :            : 
     208                 :            : static void
     209                 :          4 : gst_net_client_clock_set_property (GObject * object, guint prop_id,
     210                 :            :     const GValue * value, GParamSpec * pspec)
     211                 :            : {
     212                 :          4 :   GstNetClientClock *self = GST_NET_CLIENT_CLOCK (object);
     213                 :            : 
     214      [ +  +  - ]:          4 :   switch (prop_id) {
     215                 :            :     case PROP_ADDRESS:
     216                 :          2 :       g_free (self->address);
     217         [ -  + ]:          2 :       if (g_value_get_string (value) == NULL)
     218                 :          0 :         self->address = g_strdup (DEFAULT_ADDRESS);
     219                 :            :       else
     220                 :          2 :         self->address = g_strdup (g_value_get_string (value));
     221                 :          2 :       break;
     222                 :            :     case PROP_PORT:
     223                 :          2 :       self->port = g_value_get_int (value);
     224                 :          2 :       break;
     225                 :            :     default:
     226                 :          0 :       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     227                 :          0 :       break;
     228                 :            :   }
     229                 :          4 : }
     230                 :            : 
     231                 :            : static void
     232                 :          1 : gst_net_client_clock_get_property (GObject * object, guint prop_id,
     233                 :            :     GValue * value, GParamSpec * pspec)
     234                 :            : {
     235                 :          1 :   GstNetClientClock *self = GST_NET_CLIENT_CLOCK (object);
     236                 :            : 
     237      [ -  +  - ]:          1 :   switch (prop_id) {
     238                 :            :     case PROP_ADDRESS:
     239                 :          0 :       g_value_set_string (value, self->address);
     240                 :          0 :       break;
     241                 :            :     case PROP_PORT:
     242                 :          1 :       g_value_set_int (value, self->port);
     243                 :          1 :       break;
     244                 :            :     default:
     245                 :          0 :       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     246                 :          0 :       break;
     247                 :            :   }
     248                 :          1 : }
     249                 :            : 
     250                 :            : static void
     251                 :         32 : gst_net_client_clock_observe_times (GstNetClientClock * self,
     252                 :            :     GstClockTime local_1, GstClockTime remote, GstClockTime local_2)
     253                 :            : {
     254                 :            :   GstClockTime local_avg;
     255                 :            :   gdouble r_squared;
     256                 :            :   GstClock *clock;
     257                 :            : 
     258         [ -  + ]:         32 :   if (local_2 < local_1)
     259                 :          0 :     goto bogus_observation;
     260                 :            : 
     261                 :         32 :   local_avg = (local_2 + local_1) / 2;
     262                 :            : 
     263                 :         32 :   clock = GST_CLOCK_CAST (self);
     264                 :            : 
     265                 :         32 :   gst_clock_add_observation (GST_CLOCK (self), local_avg, remote, &r_squared);
     266                 :            : 
     267                 :         32 :   GST_CLOCK_SLAVE_LOCK (self);
     268         [ +  + ]:         32 :   if (clock->filling) {
     269                 :         31 :     self->current_timeout = 0;
     270                 :            :   } else {
     271                 :            :     /* geto formula */
     272         [ +  - ]:          1 :     self->current_timeout =
     273                 :          2 :         (1e-3 / (1 - MIN (r_squared, 0.99999))) * GST_SECOND;
     274                 :          1 :     self->current_timeout = MIN (self->current_timeout, clock->timeout);
     275                 :            :   }
     276                 :         32 :   GST_CLOCK_SLAVE_UNLOCK (clock);
     277                 :            : 
     278                 :         32 :   return;
     279                 :            : 
     280                 :            : bogus_observation:
     281                 :            :   {
     282 [ #  # ][ #  # ]:          0 :     GST_WARNING_OBJECT (self, "time packet receive time < send time (%"
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     283                 :            :         GST_TIME_FORMAT " < %" GST_TIME_FORMAT ")", GST_TIME_ARGS (local_1),
     284                 :            :         GST_TIME_ARGS (local_2));
     285                 :         32 :     return;
     286                 :            :   }
     287                 :            : }
     288                 :            : 
     289                 :            : static gint
     290                 :         66 : gst_net_client_clock_do_select (GstNetClientClock * self)
     291                 :            : {
     292                 :            :   while (TRUE) {
     293                 :            :     GstClockTime diff;
     294                 :            :     gint ret;
     295                 :            : 
     296         [ -  + ]:         66 :     GST_LOG_OBJECT (self, "doing select");
     297                 :            : 
     298                 :         66 :     diff = gst_clock_get_internal_time (GST_CLOCK (self));
     299                 :         66 :     ret = gst_poll_wait (self->priv->fdset, self->current_timeout);
     300                 :         66 :     diff = gst_clock_get_internal_time (GST_CLOCK (self)) - diff;
     301                 :            : 
     302         [ +  + ]:         66 :     if (diff > self->current_timeout)
     303                 :         33 :       self->current_timeout = 0;
     304                 :            :     else
     305                 :         33 :       self->current_timeout -= diff;
     306                 :            : 
     307         [ -  + ]:         66 :     GST_LOG_OBJECT (self, "select returned %d", ret);
     308                 :            : 
     309 [ +  + ][ -  + ]:         66 :     if (ret < 0 && errno != EBUSY) {
     310 [ #  # ][ #  # ]:          0 :       if (errno != EAGAIN && errno != EINTR)
     311                 :            :         goto select_error;
     312                 :            :       else
     313                 :          0 :         continue;
     314                 :            :     } else {
     315                 :         66 :       return ret;
     316                 :            :     }
     317                 :            : 
     318                 :            :     g_assert_not_reached ();
     319                 :            : 
     320                 :            :     /* log errors and keep going */
     321                 :            :   select_error:
     322                 :            :     {
     323         [ #  # ]:          0 :       GST_WARNING_OBJECT (self, "select error %d: %s (%d)", ret,
     324                 :            :           g_strerror (errno), errno);
     325                 :          0 :       continue;
     326                 :            :     }
     327                 :          0 :   }
     328                 :            : 
     329                 :            :   g_assert_not_reached ();
     330                 :            :   return -1;
     331                 :            : }
     332                 :            : 
     333                 :            : static gpointer
     334                 :          2 : gst_net_client_clock_thread (gpointer data)
     335                 :            : {
     336                 :          2 :   GstNetClientClock *self = data;
     337                 :            :   struct sockaddr_in tmpaddr;
     338                 :            :   socklen_t len;
     339                 :            :   GstNetTimePacket *packet;
     340                 :            :   gint ret;
     341                 :          2 :   GstClock *clock = data;
     342                 :            : 
     343                 :            :   while (TRUE) {
     344                 :         66 :     ret = gst_net_client_clock_do_select (self);
     345                 :            : 
     346 [ +  + ][ +  - ]:         66 :     if (ret < 0 && errno == EBUSY) {
     347         [ -  + ]:          2 :       GST_LOG_OBJECT (self, "stop");
     348                 :          2 :       goto stopped;
     349         [ +  + ]:         64 :     } else if (ret == 0) {
     350                 :            :       /* timed out, let's send another packet */
     351         [ -  + ]:         32 :       GST_DEBUG_OBJECT (self, "timed out");
     352                 :            : 
     353                 :         32 :       packet = gst_net_time_packet_new (NULL);
     354                 :            : 
     355                 :         32 :       packet->local_time = gst_clock_get_internal_time (GST_CLOCK (self));
     356                 :            : 
     357 [ -  + ][ #  # ]:         32 :       GST_DEBUG_OBJECT (self, "sending packet, local time = %" GST_TIME_FORMAT,
         [ #  # ][ #  # ]
                 [ #  # ]
     358                 :            :           GST_TIME_ARGS (packet->local_time));
     359                 :         32 :       gst_net_time_packet_send (packet, self->priv->sock.fd,
     360                 :         32 :           (struct sockaddr *) self->servaddr, sizeof (struct sockaddr_in));
     361                 :            : 
     362                 :         32 :       g_free (packet);
     363                 :            : 
     364                 :            :       /* reset timeout */
     365                 :         32 :       self->current_timeout = clock->timeout;
     366                 :         32 :       continue;
     367         [ +  - ]:         32 :     } else if (gst_poll_fd_can_read (self->priv->fdset, &self->priv->sock)) {
     368                 :            :       /* got data in */
     369                 :         32 :       GstClockTime new_local = gst_clock_get_internal_time (GST_CLOCK (self));
     370                 :            : 
     371                 :         32 :       len = sizeof (struct sockaddr);
     372                 :         32 :       packet = gst_net_time_packet_receive (self->priv->sock.fd,
     373                 :            :           (struct sockaddr *) &tmpaddr, &len);
     374                 :            : 
     375         [ -  + ]:         32 :       if (!packet)
     376                 :          0 :         goto receive_error;
     377                 :            : 
     378         [ -  + ]:         32 :       GST_LOG_OBJECT (self, "got packet back");
     379 [ -  + ][ #  # ]:         32 :       GST_LOG_OBJECT (self, "local_1 = %" GST_TIME_FORMAT,
         [ #  # ][ #  # ]
                 [ #  # ]
     380                 :            :           GST_TIME_ARGS (packet->local_time));
     381 [ -  + ][ #  # ]:         32 :       GST_LOG_OBJECT (self, "remote = %" GST_TIME_FORMAT,
         [ #  # ][ #  # ]
                 [ #  # ]
     382                 :            :           GST_TIME_ARGS (packet->remote_time));
     383 [ -  + ][ #  # ]:         32 :       GST_LOG_OBJECT (self, "local_2 = %" GST_TIME_FORMAT,
         [ #  # ][ #  # ]
                 [ #  # ]
     384                 :            :           GST_TIME_ARGS (new_local));
     385                 :            : 
     386                 :            :       /* observe_times will reset the timeout */
     387                 :         32 :       gst_net_client_clock_observe_times (self, packet->local_time,
     388                 :            :           packet->remote_time, new_local);
     389                 :            : 
     390                 :         32 :       g_free (packet);
     391                 :         32 :       continue;
     392                 :            :     } else {
     393         [ #  # ]:          0 :       GST_WARNING_OBJECT (self, "unhandled select return state?");
     394                 :          0 :       continue;
     395                 :            :     }
     396                 :            : 
     397                 :            :     g_assert_not_reached ();
     398                 :            : 
     399                 :            :   stopped:
     400                 :            :     {
     401         [ -  + ]:          2 :       GST_DEBUG_OBJECT (self, "shutting down");
     402                 :            :       /* socket gets closed in _stop() */
     403                 :          2 :       return NULL;
     404                 :            :     }
     405                 :            :   receive_error:
     406                 :            :     {
     407         [ #  # ]:          0 :       GST_WARNING_OBJECT (self, "receive error");
     408                 :          0 :       continue;
     409                 :            :     }
     410                 :            : 
     411                 :            :     g_assert_not_reached ();
     412                 :            : 
     413                 :         64 :   }
     414                 :            : 
     415                 :            :   g_assert_not_reached ();
     416                 :            : 
     417                 :            :   return NULL;
     418                 :            : }
     419                 :            : 
     420                 :            : static gboolean
     421                 :          2 : gst_net_client_clock_start (GstNetClientClock * self)
     422                 :            : {
     423                 :            :   struct sockaddr_in servaddr, myaddr;
     424                 :            :   socklen_t len;
     425                 :            :   gint ret;
     426                 :            :   GError *error;
     427                 :            : 
     428         [ -  + ]:          2 :   g_return_val_if_fail (self->address != NULL, FALSE);
     429         [ -  + ]:          2 :   g_return_val_if_fail (self->servaddr == NULL, FALSE);
     430                 :            : 
     431         [ -  + ]:          2 :   if ((ret = socket (AF_INET, SOCK_DGRAM, 0)) < 0)
     432                 :          0 :     goto no_socket;
     433                 :            : 
     434                 :          2 :   self->priv->sock.fd = ret;
     435                 :            : 
     436                 :          2 :   len = sizeof (myaddr);
     437                 :          2 :   ret = getsockname (self->priv->sock.fd, (struct sockaddr *) &myaddr, &len);
     438         [ -  + ]:          2 :   if (ret < 0)
     439                 :          0 :     goto getsockname_error;
     440                 :            : 
     441                 :          2 :   memset (&servaddr, 0, sizeof (servaddr));
     442                 :          2 :   servaddr.sin_family = AF_INET;        /* host byte order */
     443                 :          2 :   servaddr.sin_port = htons (self->port);       /* short, network byte order */
     444                 :            : 
     445         [ -  + ]:          2 :   GST_DEBUG_OBJECT (self, "socket opened on UDP port %hd",
     446                 :            :       ntohs (servaddr.sin_port));
     447                 :            : 
     448         [ -  + ]:          2 :   if (!inet_aton (self->address, &servaddr.sin_addr))
     449                 :          0 :     goto bad_address;
     450                 :            : 
     451                 :          2 :   self->servaddr = g_malloc (sizeof (struct sockaddr_in));
     452                 :          2 :   memcpy (self->servaddr, &servaddr, sizeof (servaddr));
     453                 :            : 
     454         [ -  + ]:          2 :   GST_DEBUG_OBJECT (self, "will communicate with %s:%d", self->address,
     455                 :            :       self->port);
     456                 :            : 
     457                 :          2 :   gst_poll_add_fd (self->priv->fdset, &self->priv->sock);
     458                 :          2 :   gst_poll_fd_ctl_read (self->priv->fdset, &self->priv->sock, TRUE);
     459                 :            : 
     460                 :          2 :   self->thread = g_thread_create (gst_net_client_clock_thread, self, TRUE,
     461                 :            :       &error);
     462         [ -  + ]:          2 :   if (!self->thread)
     463                 :          0 :     goto no_thread;
     464                 :            : 
     465                 :          2 :   return TRUE;
     466                 :            : 
     467                 :            :   /* ERRORS */
     468                 :            : no_socket:
     469                 :            :   {
     470         [ #  # ]:          0 :     GST_ERROR_OBJECT (self, "socket failed %d: %s (%d)", ret,
     471                 :            :         g_strerror (errno), errno);
     472                 :          0 :     return FALSE;
     473                 :            :   }
     474                 :            : getsockname_error:
     475                 :            :   {
     476         [ #  # ]:          0 :     GST_ERROR_OBJECT (self, "getsockname failed %d: %s (%d)", ret,
     477                 :            :         g_strerror (errno), errno);
     478                 :          0 :     close (self->priv->sock.fd);
     479                 :          0 :     self->priv->sock.fd = -1;
     480                 :          0 :     return FALSE;
     481                 :            :   }
     482                 :            : bad_address:
     483                 :            :   {
     484         [ #  # ]:          0 :     GST_ERROR_OBJECT (self, "inet_aton failed %d: %s (%d)", ret,
     485                 :            :         g_strerror (errno), errno);
     486                 :          0 :     close (self->priv->sock.fd);
     487                 :          0 :     self->priv->sock.fd = -1;
     488                 :          0 :     return FALSE;
     489                 :            :   }
     490                 :            : no_thread:
     491                 :            :   {
     492         [ #  # ]:          0 :     GST_ERROR_OBJECT (self, "could not create thread: %s", error->message);
     493                 :          0 :     gst_poll_remove_fd (self->priv->fdset, &self->priv->sock);
     494                 :          0 :     close (self->priv->sock.fd);
     495                 :          0 :     self->priv->sock.fd = -1;
     496                 :          0 :     g_free (self->servaddr);
     497                 :          0 :     self->servaddr = NULL;
     498                 :          0 :     g_error_free (error);
     499                 :          2 :     return FALSE;
     500                 :            :   }
     501                 :            : }
     502                 :            : 
     503                 :            : static void
     504                 :          2 : gst_net_client_clock_stop (GstNetClientClock * self)
     505                 :            : {
     506                 :          2 :   gst_poll_set_flushing (self->priv->fdset, TRUE);
     507                 :          2 :   g_thread_join (self->thread);
     508                 :          2 :   self->thread = NULL;
     509                 :            : 
     510         [ +  - ]:          2 :   if (self->priv->sock.fd != -1) {
     511                 :          2 :     gst_poll_remove_fd (self->priv->fdset, &self->priv->sock);
     512                 :          2 :     close (self->priv->sock.fd);
     513                 :          2 :     self->priv->sock.fd = -1;
     514                 :            :   }
     515                 :          2 : }
     516                 :            : 
     517                 :            : /**
     518                 :            :  * gst_net_client_clock_new:
     519                 :            :  * @name: a name for the clock
     520                 :            :  * @remote_address: the address of the remote clock provider
     521                 :            :  * @remote_port: the port of the remote clock provider
     522                 :            :  * @base_time: initial time of the clock
     523                 :            :  *
     524                 :            :  * Create a new #GstNetClientClock that will report the time
     525                 :            :  * provided by the #GstNetTimeProvider on @remote_address and 
     526                 :            :  * @remote_port.
     527                 :            :  *
     528                 :            :  * Returns: a new #GstClock that receives a time from the remote
     529                 :            :  * clock.
     530                 :            :  */
     531                 :            : GstClock *
     532                 :          2 : gst_net_client_clock_new (gchar * name, const gchar * remote_address,
     533                 :            :     gint remote_port, GstClockTime base_time)
     534                 :            : {
     535                 :            :   GstNetClientClock *ret;
     536                 :            :   GstClockTime internal;
     537                 :            : 
     538         [ -  + ]:          2 :   g_return_val_if_fail (remote_address != NULL, NULL);
     539         [ -  + ]:          2 :   g_return_val_if_fail (remote_port > 0, NULL);
     540         [ -  + ]:          2 :   g_return_val_if_fail (remote_port <= G_MAXUINT16, NULL);
     541         [ -  + ]:          2 :   g_return_val_if_fail (base_time != GST_CLOCK_TIME_NONE, NULL);
     542                 :            : 
     543                 :          2 :   ret = g_object_new (GST_TYPE_NET_CLIENT_CLOCK, "address", remote_address,
     544                 :            :       "port", remote_port, NULL);
     545                 :            : 
     546                 :            :   /* gst_clock_get_time() values are guaranteed to be increasing. because no one
     547                 :            :    * has called get_time on this clock yet we are free to adjust to any value
     548                 :            :    * without worrying about worrying about MAX() issues with the clock's
     549                 :            :    * internal time.
     550                 :            :    */
     551                 :            : 
     552                 :            :   /* update our internal time so get_time() give something around base_time.
     553                 :            :      assume that the rate is 1 in the beginning. */
     554                 :          2 :   internal = gst_clock_get_internal_time (GST_CLOCK (ret));
     555                 :          2 :   gst_clock_set_calibration (GST_CLOCK (ret), internal, base_time, 1, 1);
     556                 :            : 
     557                 :            :   {
     558                 :          2 :     GstClockTime now = gst_clock_get_time (GST_CLOCK (ret));
     559                 :            : 
     560 [ +  - ][ -  + ]:          2 :     if (GST_CLOCK_DIFF (now, base_time) > 0 ||
     561                 :          2 :         GST_CLOCK_DIFF (now, base_time + GST_SECOND) < 0) {
     562                 :          0 :       g_warning ("unable to set the base time, expect sync problems!");
     563                 :            :     }
     564                 :            :   }
     565                 :            : 
     566         [ -  + ]:          2 :   if ((ret->priv->fdset = gst_poll_new (TRUE)) == NULL)
     567                 :          0 :     goto no_fdset;
     568                 :            : 
     569         [ -  + ]:          2 :   if (!gst_net_client_clock_start (ret))
     570                 :          0 :     goto failed_start;
     571                 :            : 
     572                 :            :   /* all systems go, cap'n */
     573                 :          2 :   return (GstClock *) ret;
     574                 :            : 
     575                 :            : no_fdset:
     576                 :            :   {
     577         [ #  # ]:          0 :     GST_ERROR_OBJECT (ret, "could not create an fdset: %s (%d)",
     578                 :            :         g_strerror (errno), errno);
     579                 :          0 :     gst_object_unref (ret);
     580                 :          0 :     return NULL;
     581                 :            :   }
     582                 :            : failed_start:
     583                 :            :   {
     584                 :            :     /* already printed a nice error */
     585                 :          0 :     gst_object_unref (ret);
     586                 :          2 :     return NULL;
     587                 :            :   }
     588                 :            : }

Generated by: LCOV version 1.9