📄 gstnetclientclock.c
字号:
/* GStreamer * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu> * 2005 Wim Taymans <wim@fluendo.com> * 2005 Andy Wingo <wingo@pobox.com> * * gstnetclientclock.h: clock that synchronizes itself to a time provider over * the network * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. *//** * SECTION:gstnetclientclock * @short_description: Special clock that synchronizes to a remote time * provider. * @see_also: #GstClock, #GstNetTimeProvider, #GstPipeline * * This object implements a custom #GstClock that synchronizes its time * to a remote time provider such as #GstNetTimeProvider. * * A new clock is created with gst_net_client_clock_new() which takes the * address and port of the remote time provider along with a name and * an initial time. * * This clock will poll the time provider and will update its calibration * parameters based on the local and remote observations. * * Various parameters of the clock can be configured with the parent #GstClock * "timeout", "window-size" and "window-threshold" object properties. * * A #GstNetClientClock is typically set on a #GstPipeline with * gst_pipeline_use_clock(). * * Last reviewed on 2005-11-23 (0.9.5) */#ifdef HAVE_CONFIG_H#include "config.h"#endif#include "gstnettimepacket.h"#include "gstnetclientclock.h"#ifdef HAVE_UNISTD_H#include <unistd.h>#endif#if defined (_MSC_VER) && _MSC_VER >= 1400#include <io.h>#endifGST_DEBUG_CATEGORY_STATIC (ncc_debug);#define GST_CAT_DEFAULT (ncc_debug)/* the select call is also performed on the control sockets, that way * we can send special commands to unblock or restart the select call */#define CONTROL_RESTART 'R' /* restart the select call */#define CONTROL_STOP 'S' /* stop the select call */#define CONTROL_SOCKETS(self) self->control_sock#define WRITE_SOCKET(self) self->control_sock[1]#define READ_SOCKET(self) self->control_sock[0]#define SEND_COMMAND(self, command) \G_STMT_START { \ unsigned char c; c = command; \ write (WRITE_SOCKET(self), &c, 1); \} G_STMT_END#define READ_COMMAND(self, command, res) \G_STMT_START { \ res = read(READ_SOCKET(self), &command, 1); \} G_STMT_END#define DEFAULT_ADDRESS "127.0.0.1"#define DEFAULT_PORT 5637#define DEFAULT_TIMEOUT GST_SECOND#ifdef G_OS_WIN32#define getsockname(sock,addr,len) getsockname(sock,addr,(int *)len)#endifenum{ PROP_0, PROP_ADDRESS, PROP_PORT,};#define _do_init(type) \ GST_DEBUG_CATEGORY_INIT (ncc_debug, "netclock", 0, "Network client clock");GST_BOILERPLATE_FULL (GstNetClientClock, gst_net_client_clock, GstSystemClock, GST_TYPE_SYSTEM_CLOCK, _do_init);static void gst_net_client_clock_finalize (GObject * object);static void gst_net_client_clock_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec);static void gst_net_client_clock_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec);static void gst_net_client_clock_stop (GstNetClientClock * self);#ifdef G_OS_WIN32static intinet_aton (const char *c, struct in_addr *paddr){ /* note that inet_addr is deprecated on unix because * inet_addr returns -1 (INADDR_NONE) for the valid 255.255.255.255 * address. */ paddr->s_addr = inet_addr (c); if (paddr->s_addr == INADDR_NONE) return 0; return 1;}#endifstatic voidgst_net_client_clock_base_init (gpointer g_class){ /* nop */}static voidgst_net_client_clock_class_init (GstNetClientClockClass * klass){ GObjectClass *gobject_class; gobject_class = G_OBJECT_CLASS (klass); gobject_class->finalize = gst_net_client_clock_finalize; gobject_class->get_property = gst_net_client_clock_get_property; gobject_class->set_property = gst_net_client_clock_set_property; g_object_class_install_property (gobject_class, PROP_ADDRESS, g_param_spec_string ("address", "address", "The address of the machine providing a time server, " "as a dotted quad (x.x.x.x)", DEFAULT_ADDRESS, G_PARAM_READWRITE)); g_object_class_install_property (gobject_class, PROP_PORT, g_param_spec_int ("port", "port", "The port on which the remote server is listening", 0, G_MAXUINT16, DEFAULT_PORT, G_PARAM_READWRITE));}static voidgst_net_client_clock_init (GstNetClientClock * self, GstNetClientClockClass * g_class){ GstClock *clock = GST_CLOCK_CAST (self);#ifdef G_OS_WIN32 WSADATA w; int error = WSAStartup (0x0202, &w); if (error) { GST_DEBUG_OBJECT (self, "Error on WSAStartup"); } if (w.wVersion != 0x0202) { WSACleanup (); }#endif self->port = DEFAULT_PORT; self->address = g_strdup (DEFAULT_ADDRESS); clock->timeout = DEFAULT_TIMEOUT; self->sock = -1; self->thread = NULL; self->servaddr = NULL; READ_SOCKET (self) = -1; WRITE_SOCKET (self) = -1;}static voidgst_net_client_clock_finalize (GObject * object){ GstNetClientClock *self = GST_NET_CLIENT_CLOCK (object); if (self->thread) { gst_net_client_clock_stop (self); g_assert (self->thread == NULL); } if (READ_SOCKET (self) != -1) { close (READ_SOCKET (self)); close (WRITE_SOCKET (self)); READ_SOCKET (self) = -1; WRITE_SOCKET (self) = -1; } g_free (self->address); self->address = NULL; g_free (self->servaddr); self->servaddr = NULL;#ifdef G_OS_WIN32 WSACleanup ();#endif G_OBJECT_CLASS (parent_class)->finalize (object);}static voidgst_net_client_clock_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec){ GstNetClientClock *self = GST_NET_CLIENT_CLOCK (object); switch (prop_id) { case PROP_ADDRESS: g_free (self->address); if (g_value_get_string (value) == NULL) self->address = g_strdup (DEFAULT_ADDRESS); else self->address = g_strdup (g_value_get_string (value)); break; case PROP_PORT: self->port = g_value_get_int (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; }}static voidgst_net_client_clock_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec){ GstNetClientClock *self = GST_NET_CLIENT_CLOCK (object); switch (prop_id) { case PROP_ADDRESS: g_value_set_string (value, self->address); break; case PROP_PORT: g_value_set_int (value, self->port); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; }}static voidgst_net_client_clock_observe_times (GstNetClientClock * self, GstClockTime local_1, GstClockTime remote, GstClockTime local_2){ GstClockTime local_avg; gdouble r_squared; GstClock *clock; if (local_2 < local_1) goto bogus_observation; local_avg = (local_2 + local_1) / 2; clock = GST_CLOCK_CAST (self); gst_clock_add_observation (GST_CLOCK (self), local_avg, remote, &r_squared); GST_CLOCK_SLAVE_LOCK (self); if (clock->filling) { self->current_timeout = 0; } else { /* geto formula */ self->current_timeout = (1e-3 / (1 - MIN (r_squared, 0.99999))) * GST_SECOND; self->current_timeout = MIN (self->current_timeout, clock->timeout); } GST_CLOCK_SLAVE_UNLOCK (clock); return;bogus_observation: { GST_WARNING_OBJECT (self, "time packet receive time < send time (%" GST_TIME_FORMAT " < %" GST_TIME_FORMAT ")", GST_TIME_ARGS (local_1), GST_TIME_ARGS (local_2)); return; }}static gintgst_net_client_clock_do_select (GstNetClientClock * self, fd_set * readfds){ gint max_sock; gint ret; while (TRUE) { FD_ZERO (readfds); FD_SET (self->sock, readfds); FD_SET (READ_SOCKET (self), readfds); max_sock = MAX (self->sock, READ_SOCKET (self)); GST_LOG_OBJECT (self, "doing select"); { GstClockTime diff; GTimeVal tv, *ptv = &tv; diff = gst_clock_get_internal_time (GST_CLOCK (self)); GST_TIME_TO_TIMEVAL (self->current_timeout, tv);#ifdef G_OS_WIN32 if (((max_sock + 1) != READ_SOCKET (self)) || ((max_sock + 1) != WRITE_SOCKET (self))) { ret = select (max_sock + 1, readfds, NULL, NULL, (struct timeval *) ptv); } else {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -