From: <wi...@fr...> - 2005-11-16 16:50:03
|
CVS Root: /cvs/gstreamer Module: gstreamer Changes by: wingo Date: Wed Nov 16 2005 08:50:01 PST Log message: 2005-11-16 Andy Wingo <wi...@po...> * gst/net/Makefile.am: * gst/net/gstnet.h: New part of core to hold network elements and objects. Put in core because it exposes API that applications want to use. The library is named libgstnet-tempname right now because of the existing libgstnet in gst-plugins-base. Solution is probably to rename the one in plugins-base; will file a bug for the freeze break. * gst/net/gstnettimeprovider.c: * gst/net/gstnettimeprovider.h: New object to export a GstClock's get_time call over the network. * configure.ac: * gst/Makefile.am (lib_LTLIBRARIES): Add gstnet to the build. * check/Makefile.am: * check/net/gstnettimeprovider.c: A most minimal test suite. Will get additions shortly. Modified files: . : ChangeLog configure.ac check : Makefile.am gst : Makefile.am Added files: check/net : gstnettimeprovider.c gst/net : Makefile.am gstnet.h gstnettimeprovider.c gstnettimeprovider.h Links: http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gstreamer/ChangeLog.diff?r1=1.1900&r2=1.1901 http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gstreamer/configure.ac.diff?r1=1.411&r2=1.412 http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gstreamer/check/Makefile.am.diff?r1=1.67&r2=1.68 http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gstreamer/check/net/gstnettimeprovider.c?rev=1.1&content-type=text/vnd.viewcvs-markup http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gstreamer/gst/Makefile.am.diff?r1=1.199&r2=1.200 http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gstreamer/gst/net/Makefile.am?rev=1.1&content-type=text/vnd.viewcvs-markup http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gstreamer/gst/net/gstnet.h?rev=1.1&content-type=text/vnd.viewcvs-markup http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gstreamer/gst/net/gstnettimeprovider.c?rev=1.1&content-type=text/vnd.viewcvs-markup http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gstreamer/gst/net/gstnettimeprovider.h?rev=1.1&content-type=text/vnd.viewcvs-markup ====Begin Diffs==== Index: ChangeLog =================================================================== RCS file: /cvs/gstreamer/gstreamer/ChangeLog,v retrieving revision 1.1900 retrieving revision 1.1901 diff -u -d -r1.1900 -r1.1901 --- ChangeLog 16 Nov 2005 16:09:49 -0000 1.1900 +++ ChangeLog 16 Nov 2005 16:49:48 -0000 1.1901 @@ -1,3 +1,24 @@ +2005-11-16 Andy Wingo <wi...@po...> + + * gst/net/Makefile.am: + * gst/net/gstnet.h: New part of core to hold network elements and + objects. Put in core because it exposes API that applications want + to use. The library is named libgstnet-tempname right now because + of the existing libgstnet in gst-plugins-base. Solution is + probably to rename the one in plugins-base; will file a bug for + the freeze break. + * gst/net/gstnettimeprovider.c: + * gst/net/gstnettimeprovider.h: New object to export a GstClock's + get_time call over the network. + * configure.ac: + * gst/Makefile.am (lib_LTLIBRARIES): Add gstnet to the build. + * check/Makefile.am: + * check/net/gstnettimeprovider.c: A most minimal test suite. Will + get additions shortly. 2005-11-16 Thomas Vander Stichele <thomas at apestaart dot org> * gst/gstpad.c: (gst_pad_new_from_static_template): Index: configure.ac RCS file: /cvs/gstreamer/gstreamer/configure.ac,v retrieving revision 1.411 retrieving revision 1.412 diff -u -d -r1.411 -r1.412 --- configure.ac 11 Nov 2005 19:26:36 -0000 1.411 +++ configure.ac 16 Nov 2005 16:49:48 -0000 1.412 @@ -76,6 +76,8 @@ AM_CONDITIONAL(GST_DISABLE_ENUMTYPES, test "x$GST_DISABLE_ENUMTYPES" = "xyes") GST_CHECK_SUBSYSTEM_DISABLE(INDEX,[index]) AM_CONDITIONAL(GST_DISABLE_INDEX, test "x$GST_DISABLE_INDEX" = "xyes") +GST_CHECK_SUBSYSTEM_DISABLE(NET,[network distribution]) +AM_CONDITIONAL(GST_DISABLE_NET, test "x$GST_DISABLE_NET" = "xyes") GST_CHECK_SUBSYSTEM_DISABLE(PLUGIN,[plugin]) AM_CONDITIONAL(GST_DISABLE_PLUGIN, test "x$GST_DISABLE_PLUGIN" = "xyes") GST_CHECK_SUBSYSTEM_DISABLE(URI,[uri handlers]) @@ -469,6 +471,7 @@ gst/base/Makefile gst/check/Makefile gst/indexers/Makefile +gst/net/Makefile gst/elements/Makefile gst/parse/Makefile libs/Makefile Index: Makefile.am RCS file: /cvs/gstreamer/gstreamer/check/Makefile.am,v retrieving revision 1.67 retrieving revision 1.68 diff -u -d -r1.67 -r1.68 --- Makefile.am 18 Oct 2005 17:06:28 -0000 1.67 +++ Makefile.am 16 Nov 2005 16:49:48 -0000 1.68 @@ -56,7 +56,8 @@ pipelines/cleanup \ states/sinks \ gst-libs/controller \ - gst-libs/gdp + gst-libs/gdp \ + net/gstnettimeprovider TESTS = $(check_PROGRAMS) @@ -78,6 +79,10 @@ $(top_builddir)/libs/gst/controller/libgstcontroller-@GST_MAJORMINOR@.la \ $(LDADD) +net_gstnettimeprovider_LDADD = \ + $(top_builddir)/gst/net/libgstnet-tempname-@GST_MAJORMINOR@.la \ + $(LDADD) # valgrind testing # these just need valgrind fixing, period VALGRIND_TO_FIX = \ --- NEW FILE: gstnettimeprovider.c --- /* GStreamer * Copyright (C) 2005 Andy Wingo <wi...@po...> * * gstnettimeprovider.c: Unit test for the network time provider * 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. */ #include <gst/check/gstcheck.h> #include <gst/net/gstnet.h> GST_START_TEST (test_refcounts) { GstNetTimeProvider *ntp; GstClock *clock; clock = gst_system_clock_obtain (); fail_unless (clock != NULL, "failed to get system clock"); /* one for gstreamer, one for us */ ASSERT_OBJECT_REFCOUNT (clock, "system clock", 2); ntp = gst_net_time_provider_new (clock, NULL, -1); fail_unless (ntp != NULL, "failed to create net time provider"); /* one for ntp, one for gstreamer, one for us */ ASSERT_OBJECT_REFCOUNT (clock, "system clock", 3); /* one for us */ ASSERT_OBJECT_REFCOUNT (ntp, "net time provider", 1); gst_object_unref (ntp); ASSERT_OBJECT_REFCOUNT (clock, "net time provider", 2); gst_object_unref (clock); } GST_END_TEST; Suite * gst_net_time_provider_suite (void) Suite *s = suite_create ("GstNetTimeProvider"); TCase *tc_chain = tcase_create ("generic tests"); tcase_set_timeout (tc_chain, 0); suite_add_tcase (s, tc_chain); tcase_add_test (tc_chain, test_refcounts); return s; int main (int argc, char **argv) int nf; Suite *s = gst_net_time_provider_suite (); SRunner *sr = srunner_create (s); gst_check_init (&argc, &argv); srunner_run_all (sr, CK_NORMAL); nf = srunner_ntests_failed (sr); srunner_free (sr); return nf; RCS file: /cvs/gstreamer/gstreamer/gst/Makefile.am,v retrieving revision 1.199 retrieving revision 1.200 diff -u -d -r1.199 -r1.200 --- Makefile.am 16 Nov 2005 11:29:57 -0000 1.199 +++ Makefile.am 16 Nov 2005 16:49:49 -0000 1.200 @@ -54,8 +54,22 @@ GST_URI_SRC = gsturi.c endif -SUBDIRS = $(SUBDIRS_PARSE) . base elements $(SUBDIRS_INDEX) $(SUBDIRS_CHECK) -DIST_SUBDIRS = base elements parse indexers check +if GST_DISABLE_NET +SUBDIRS_NET = +else +SUBDIRS_NET = net +endif +SUBDIRS = \ + $(SUBDIRS_PARSE) \ + . \ + base \ + elements \ + $(SUBDIRS_INDEX) \ + $(SUBDIRS_NET) \ + $(SUBDIRS_CHECK) +DIST_SUBDIRS = base elements parse indexers net check # make variables for all generated source and header files to make the # distinction clear --- NEW FILE: Makefile.am --- # tempname needs to be removed as soon as the old gstnet is renamed to # nethelper or something lib_LTLIBRARIES = libgstnet-tempname-@GST_MAJORMINOR@.la libgstnet_tempname_@GST_MAJORMINOR@_includedir = $(includedir)/gstreamer-@GST_MAJORMINOR@/gst/net libgstnet_tempname_@GST_MAJORMINOR@_include_HEADERS = \ gstnet.h \ gstnettimeprovider.h libgstnet_tempname_@GST_MAJORMINOR@_la_SOURCES = \ gstnettimeprovider.c libgstnet_tempname_@GST_MAJORMINOR@_la_CFLAGS = $(GST_OBJ_CFLAGS) libgstnet_tempname_@GST_MAJORMINOR@_la_LIBADD = $(GST_OBJ_LIBS) libgstnet_tempname_@GST_MAJORMINOR@_la_LDFLAGS = $(GST_OBJ_LDFLAGS) --- NEW FILE: gstnet.h --- #ifndef __GST_NET_H__ #define __GST_NET_H__ #include <gst/net/gstnettimeprovider.h> #endif /* __GST_NET_H__ */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "gstnettimeprovider.h" #include <unistd.h> #include <sys/ioctl.h> #ifdef HAVE_FIONREAD_IN_SYS_FILIO #include <sys/filio.h> GST_DEBUG_CATEGORY (ntp_debug); #define GST_CAT_DEFAULT (ntp_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); \ #define DEFAULT_ADDRESS "0.0.0.0" #define DEFAULT_PORT 5637 typedef struct GstClockTime slave_time_sent; GstClockTime master_time_received; } NetworkTimePacket; /* 2 * sizeof(GstClockTime), verified in base_init */ #define NETWORK_TIME_PACKET_SIZE 16 #define NETWORK_TIME_PACKET_SET_MASTER_TIME(p, t) \ GST_WRITE_UINT64_BE(p+8, t) enum PROP_0, PROP_PORT, PROP_ADDRESS, PROP_CLOCK /* FILL ME */ }; static gboolean gst_net_time_provider_start (GstNetTimeProvider * bself); static void gst_net_time_provider_stop (GstNetTimeProvider * bself); static gpointer gst_net_time_provider_thread (gpointer data); static void gst_net_time_provider_finalize (GObject * object); static void gst_net_time_provider_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec); static void gst_net_time_provider_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec); #define _do_init(type) \ GST_DEBUG_CATEGORY_INIT (ntp_debug, "nettime", 0, "Network time provider"); GST_BOILERPLATE_FULL (GstNetTimeProvider, gst_net_time_provider, GstObject, GST_TYPE_OBJECT, _do_init); static void gst_net_time_provider_base_init (gpointer g_class) g_assert (sizeof (GstClockTime) == 8); gst_net_time_provider_class_init (GstNetTimeProviderClass * klass) GObjectClass *gobject_class; gobject_class = (GObjectClass *) klass; gobject_class->finalize = gst_net_time_provider_finalize; gobject_class->set_property = gst_net_time_provider_set_property; gobject_class->get_property = gst_net_time_provider_get_property; g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PORT, g_param_spec_int ("port", "port", "The port to receive the packets from, -1=allocate", -1, 32768, DEFAULT_PORT, G_PARAM_READWRITE)); g_object_class_install_property (gobject_class, PROP_ADDRESS, g_param_spec_string ("address", "address", "The address to bind on, as a dotted quad (x.x.x.x)", DEFAULT_ADDRESS, G_PARAM_READWRITE)); g_object_class_install_property (gobject_class, PROP_CLOCK, g_param_spec_object ("clock", "Clock", "The clock to export over the network", GST_TYPE_CLOCK, G_PARAM_READWRITE)); gst_net_time_provider_init (GstNetTimeProvider * self, GstNetTimeProviderClass * g_class) self->port = DEFAULT_PORT; self->sock = -1; self->address = g_strdup (DEFAULT_ADDRESS); self->thread = NULL; READ_SOCKET (self) = -1; WRITE_SOCKET (self) = -1; gst_net_time_provider_finalize (GObject * object) GstNetTimeProvider *self = GST_NET_TIME_PROVIDER (object); if (self->thread) { gst_net_time_provider_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; if (self->clock) gst_object_unref (self->clock); self->clock = NULL; static gpointer gst_net_time_provider_thread (gpointer data) GstNetTimeProvider *self = data; struct sockaddr_in tmpaddr; socklen_t len; fd_set read_fds; guint max_sock; gchar *pktdata; gint ret; while (TRUE) { FD_ZERO (&read_fds); FD_SET (self->sock, &read_fds); FD_SET (READ_SOCKET (self), &read_fds); max_sock = MAX (self->sock, READ_SOCKET (self)); GST_LOG_OBJECT (self, "doing select"); ret = select (max_sock + 1, &read_fds, NULL, NULL, NULL); GST_LOG_OBJECT (self, "select returned %d", ret); if (ret <= 0) { if (errno != EAGAIN && errno != EINTR) goto select_error; else continue; } else if (FD_ISSET (READ_SOCKET (self), &read_fds)) { /* got control message */ while (TRUE) { gchar command; int res; READ_COMMAND (self, command, res); if (res < 0) { GST_LOG_OBJECT (self, "no more commands"); break; } switch (command) { case CONTROL_STOP: /* break out of the select loop */ GST_LOG_OBJECT (self, "stop"); goto stopped; default: GST_WARNING_OBJECT (self, "unkown"); g_warning ("nettimeprovider: unknown control message received"); continue; g_assert_not_reached (); } continue; } else { /* got data in */ pktdata = g_malloc (NETWORK_TIME_PACKET_SIZE); len = sizeof (struct sockaddr); ret = recvfrom (self->sock, pktdata, NETWORK_TIME_PACKET_SIZE, 0, (struct sockaddr *) &tmpaddr, &len); if (ret < 0) { if (errno != EAGAIN && errno != EINTR) goto receive_error; else } else if (ret < NETWORK_TIME_PACKET_SIZE) { goto short_packet; } else { GstClockTime now; now = gst_clock_get_time (self->clock); NETWORK_TIME_PACKET_SET_MASTER_TIME (pktdata, time); /* ignore errors */ sendto (self->sock, pktdata, ret, MSG_DONTWAIT, (struct sockaddr *) &tmpaddr, len); } g_assert_not_reached (); /* log errors and keep going */ select_error: { GST_DEBUG_OBJECT (self, "select error %d: %s (%d)", ret, g_strerror (errno), errno); short_packet: GST_DEBUG_OBJECT (self, "someone sent us a short packet (%d < %d)", ret, NETWORK_TIME_PACKET_SIZE); stopped: GST_DEBUG_OBJECT (self, "shutting down"); /* close socket */ return NULL; receive_error: g_free (pktdata); GST_DEBUG_OBJECT (self, "receive error %d: %s (%d)", ret, g_assert_not_reached (); return NULL; gst_net_time_provider_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) switch (prop_id) { case PROP_PORT: self->port = g_value_get_int (value); break; case PROP_ADDRESS: g_free (self->address); if (g_value_get_string (value) == NULL) self->address = g_strdup (DEFAULT_ADDRESS); self->address = g_strdup (g_value_get_string (value)); case PROP_CLOCK: gst_object_replace ((GstObject **) & self->clock, (GstObject *) g_value_get_object (value)); default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); gst_net_time_provider_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) g_value_set_int (value, self->port); g_value_set_string (value, self->address); g_value_set_object (value, self->clock); static gboolean gst_net_time_provider_start (GstNetTimeProvider * self) gint ru; struct sockaddr_in my_addr; guint len; int port; GError *error; if ((ret = socket (AF_INET, SOCK_DGRAM, 0)) < 0) goto no_socket; self->sock = ret; ru = 1; ret = setsockopt (self->sock, SOL_SOCKET, SO_REUSEADDR, &ru, sizeof (ru)); if (ret < 0) goto setsockopt_error; memset (&my_addr, 0, sizeof (my_addr)); my_addr.sin_family = AF_INET; /* host byte order */ my_addr.sin_port = htons (self->port); /* short, network byte order */ my_addr.sin_addr.s_addr = INADDR_ANY; if (self->address) inet_aton (self->address, &my_addr.sin_addr); GST_DEBUG_OBJECT (self, "binding on port %d", self->port); ret = bind (self->sock, (struct sockaddr *) &my_addr, sizeof (my_addr)); goto bind_error; len = sizeof (my_addr); ret = getsockname (self->sock, (struct sockaddr *) &my_addr, &len); goto getsockname_error; port = ntohs (my_addr.sin_port); GST_DEBUG_OBJECT (self, "bound, on port %d", port); if (port != self->port) { self->port = port; GST_DEBUG_OBJECT (self, "notifying %d", port); g_object_notify (G_OBJECT (self), "port"); self->thread = g_thread_create (gst_net_time_provider_thread, self, TRUE, &error); if (!self->thread) goto no_thread; return TRUE; /* ERRORS */ no_socket: { GST_ERROR_OBJECT (self, "socket failed %d: %s (%d)", ret, g_strerror (errno), errno); return FALSE; setsockopt_error: close (self->sock); self->sock = -1; GST_ERROR_OBJECT (self, "setsockopt failed %d: %s (%d)", ret, bind_error: GST_ERROR_OBJECT (self, "bind failed %d: %s (%d)", ret, getsockname_error: GST_ERROR_OBJECT (self, "getsockname failed %d: %s (%d)", ret, no_thread: GST_ERROR_OBJECT (self, "could not create thread: %s", error->message); g_error_free (error); gst_net_time_provider_stop (GstNetTimeProvider * self) SEND_COMMAND (self, CONTROL_STOP); g_thread_join (self->thread); if (self->sock != -1) { /** * gst_net_time_provider_new: * @clock: a #GstClock to export over the network * @address: an address to bind on as a dotted quad (xxx.xxx.xxx.xxx), or NULL * to bind to all addresses * @port: a port to bind on, or -1 to let the kernel choose * Allows network clients to get the current time of @clock. * Returns: The new #GstNetTimeProvider, or NULL on error. GstNetTimeProvider * gst_net_time_provider_new (GstClock * clock, const gchar * address, gint port) GstNetTimeProvider *ret; gint iret; g_return_val_if_fail (clock && GST_IS_CLOCK (clock), NULL); g_return_val_if_fail (port == -1 || port >= 0, NULL); ret = g_object_new (GST_TYPE_NET_TIME_PROVIDER, "clock", clock, "address", address, "port", port, NULL); GST_DEBUG_OBJECT (ret, "creating socket pair"); if ((iret = socketpair (PF_UNIX, SOCK_STREAM, 0, CONTROL_SOCKETS (ret))) < 0) goto no_socket_pair; fcntl (READ_SOCKET (ret), F_SETFL, O_NONBLOCK); fcntl (WRITE_SOCKET (ret), F_SETFL, O_NONBLOCK); if (!gst_net_time_provider_start (ret)) goto failed_start; /* all systems go, cap'n */ return ret; no_socket_pair: GST_ERROR_OBJECT (ret, "no socket pair %d: %s (%d)", iret, gst_object_unref (ret); return NULL; failed_start: /* already printed a nice error */ --- NEW FILE: gstnettimeprovider.h --- #ifndef __GST_NET_TIME_PROVIDER_H__ #define __GST_NET_TIME_PROVIDER_H__ #include <gst/gst.h> G_BEGIN_DECLS #include <errno.h> #include <string.h> #include <sys/types.h> #include <netdb.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <fcntl.h> #define GST_TYPE_NET_TIME_PROVIDER \ (gst_net_time_provider_get_type()) #define GST_NET_TIME_PROVIDER(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_NET_TIME_PROVIDER,GstNetTimeProvider)) #define GST_NET_TIME_PROVIDER_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_NET_TIME_PROVIDER,GstNetTimeProvider)) #define GST_IS_NET_TIME_PROVIDER(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_NET_TIME_PROVIDER)) #define GST_IS_NET_TIME_PROVIDER_CLASS(obj) \ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_NET_TIME_PROVIDER)) typedef struct _GstNetTimeProvider GstNetTimeProvider; typedef struct _GstNetTimeProviderClass GstNetTimeProviderClass; struct _GstNetTimeProvider { GstObject parent; gchar *address; int sock; int control_sock[2]; GThread *thread; struct _GstNetTimeProviderClass { GstObjectClass parent_class; GType gst_net_time_provider_get_type (void); GstNetTimeProvider* gst_net_time_provider_new (GstClock *clock, const gchar *address, gint port); G_END_DECLS #endif /* __GST_NET_TIME_PROVIDER_H__ */ |