static gpointer gst_net_client_clock_thread (gpointer data) { GstNetClientClock *self = data; GstNetTimePacket *packet; GSocket *socket = self->priv->socket; GError *err = NULL; GstClock *clock = data; GST_INFO_OBJECT (self, "net client clock thread running, socket=%p", socket); g_socket_set_blocking (socket, TRUE); g_socket_set_timeout (socket, 0); while (!g_cancellable_is_cancelled (self->priv->cancel)) { GstClockTime expiration_time = self->priv->timeout_expiration; GstClockTime now = gst_util_get_timestamp (); gint64 socket_timeout; if (now >= expiration_time || (expiration_time - now) <= GST_MSECOND) { socket_timeout = 0; } else { socket_timeout = (expiration_time - now) / GST_USECOND; } GST_TRACE_OBJECT (self, "timeout: %" G_GINT64_FORMAT "us", socket_timeout); if (!g_socket_condition_timed_wait (socket, G_IO_IN, socket_timeout, self->priv->cancel, &err)) { /* cancelled, timeout or error */ if (err->code == G_IO_ERROR_CANCELLED) { GST_INFO_OBJECT (self, "cancelled"); g_clear_error (&err); break; } else if (err->code == G_IO_ERROR_TIMED_OUT) { /* timed out, let's send another packet */ GST_DEBUG_OBJECT (self, "timed out"); packet = gst_net_time_packet_new (NULL); packet->local_time = gst_clock_get_internal_time (GST_CLOCK (self)); GST_DEBUG_OBJECT (self, "sending packet, local time = %" GST_TIME_FORMAT, GST_TIME_ARGS (packet->local_time)); gst_net_time_packet_send (packet, self->priv->socket, self->priv->servaddr, NULL); g_free (packet); /* reset timeout (but are expecting a response sooner anyway) */ self->priv->timeout_expiration = gst_util_get_timestamp () + gst_clock_get_timeout (clock); } else { GST_DEBUG_OBJECT (self, "socket error: %s", err->message); g_usleep (G_USEC_PER_SEC / 10); /* throttle */ } g_clear_error (&err); } else { GstClockTime new_local; /* got packet */ new_local = gst_clock_get_internal_time (GST_CLOCK (self)); packet = gst_net_time_packet_receive (socket, NULL, &err); if (packet != NULL) { GST_LOG_OBJECT (self, "got packet back"); GST_LOG_OBJECT (self, "local_1 = %" GST_TIME_FORMAT, GST_TIME_ARGS (packet->local_time)); GST_LOG_OBJECT (self, "remote = %" GST_TIME_FORMAT, GST_TIME_ARGS (packet->remote_time)); GST_LOG_OBJECT (self, "local_2 = %" GST_TIME_FORMAT, GST_TIME_ARGS (new_local)); /* observe_times will reset the timeout */ gst_net_client_clock_observe_times (self, packet->local_time, packet->remote_time, new_local); g_free (packet); } else if (err != NULL) { GST_WARNING_OBJECT (self, "receive error: %s", err->message); g_clear_error (&err); } } } GST_INFO_OBJECT (self, "shutting down net client clock thread"); return NULL; }
void test_functioning() { GstNetTimeProvider *ntp; GstNetTimePacket *packet; GstClock *clock; GstClockTime local; struct sockaddr_in servaddr; gint port = -1, sockfd, ret; socklen_t len; xmlfile = "test_functioning"; std_log(LOG_FILENAME_LINE, "Test Started test_functioning"); clock = gst_system_clock_obtain (); fail_unless (clock != NULL, "failed to get system clock"); ntp = gst_net_time_provider_new (clock, "127.0.0.1", 0); fail_unless (ntp != NULL, "failed to create net time provider"); g_object_get (ntp, "port", &port, NULL); fail_unless (port > 0); sockfd = socket (AF_INET, SOCK_DGRAM, 0); fail_if (sockfd < 0, "socket failed"); memset (&servaddr, 0, sizeof (servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons (port); inet_aton ("127.0.0.1", &servaddr.sin_addr); packet = gst_net_time_packet_new (NULL); fail_unless (packet != NULL, "failed to create packet"); packet->local_time = local = gst_clock_get_time (clock); len = sizeof (servaddr); ret = gst_net_time_packet_send (packet, sockfd, (struct sockaddr *) &servaddr, len); fail_unless (ret == GST_NET_TIME_PACKET_SIZE, "failed to send packet"); g_free (packet); packet = gst_net_time_packet_receive (sockfd, (struct sockaddr *) &servaddr, &len); fail_unless (packet != NULL, "failed to receive packet"); // fail_unless (packet->local_time == local, "local time is not the same"); //local time has changed fail_unless (packet->remote_time > local, "remote time not after local time"); fail_unless (packet->remote_time < gst_clock_get_time (clock), "remote time in the future"); g_free (packet); close (sockfd); //gst_object_unref (ntp); //thread is blocking gst_object_unref (clock); std_log(LOG_FILENAME_LINE, "Test Successful"); create_xml(0); }
static gpointer gst_net_client_clock_thread (gpointer data) { GstNetClientClock *self = data; GstNetTimePacket *packet; GMainContext *ctx; GSourceFuncs funcs = { NULL, }; GSource *source; GIOCondition cond; gboolean timeout; GSocket *socket = self->priv->socket; GError *err = NULL; GstClock *clock = data; GST_INFO_OBJECT (self, "net client clock thread running, socket=%p", socket); g_socket_set_blocking (socket, TRUE); g_socket_set_timeout (socket, 0); ctx = g_main_context_new (); source = g_socket_create_source (socket, G_IO_IN, self->priv->cancel); g_source_set_name (source, "GStreamer net client clock thread socket"); g_source_set_callback (source, (GSourceFunc) gst_net_client_clock_socket_cb, &cond, NULL); g_source_attach (source, ctx); g_source_unref (source); /* GSocket only support second granularity for timeouts, so roll our own * timeout source (so we don't have to create a new source whenever the * timeout changes, as we would have to do with the default timeout source) */ funcs.prepare = gst_net_client_clock_timeout_source_prepare; funcs.check = gst_net_client_clock_timeout_source_check; funcs.dispatch = gst_net_client_clock_timeout_source_dispatch; funcs.finalize = NULL; source = g_source_new (&funcs, sizeof (GstNetClientClockTimeoutSource)); ((GstNetClientClockTimeoutSource *) source)->clock = self; ((GstNetClientClockTimeoutSource *) source)->p_timeout = &timeout; g_source_set_name (source, "GStreamer net client clock timeout"); g_source_attach (source, ctx); g_source_unref (source); while (!g_cancellable_is_cancelled (self->priv->cancel)) { cond = 0; timeout = FALSE; g_main_context_iteration (ctx, TRUE); if (g_cancellable_is_cancelled (self->priv->cancel)) break; if (timeout) { /* timed out, let's send another packet */ GST_DEBUG_OBJECT (self, "timed out"); packet = gst_net_time_packet_new (NULL); packet->local_time = gst_clock_get_internal_time (GST_CLOCK (self)); GST_DEBUG_OBJECT (self, "sending packet, local time = %" GST_TIME_FORMAT, GST_TIME_ARGS (packet->local_time)); gst_net_time_packet_send (packet, self->priv->socket, self->priv->servaddr, NULL); g_free (packet); /* reset timeout (but are expecting a response sooner anyway) */ self->priv->timeout_expiration = gst_util_get_timestamp () + gst_clock_get_timeout (clock); continue; } /* got data to read? */ if ((cond & G_IO_IN)) { GstClockTime new_local; new_local = gst_clock_get_internal_time (GST_CLOCK (self)); packet = gst_net_time_packet_receive (socket, NULL, &err); if (err != NULL) { GST_WARNING_OBJECT (self, "receive error: %s", err->message); g_error_free (err); err = NULL; continue; } GST_LOG_OBJECT (self, "got packet back"); GST_LOG_OBJECT (self, "local_1 = %" GST_TIME_FORMAT, GST_TIME_ARGS (packet->local_time)); GST_LOG_OBJECT (self, "remote = %" GST_TIME_FORMAT, GST_TIME_ARGS (packet->remote_time)); GST_LOG_OBJECT (self, "local_2 = %" GST_TIME_FORMAT, GST_TIME_ARGS (new_local)); /* observe_times will reset the timeout */ gst_net_client_clock_observe_times (self, packet->local_time, packet->remote_time, new_local); g_free (packet); continue; } if ((cond & (G_IO_ERR | G_IO_HUP))) { GST_DEBUG_OBJECT (self, "socket error?! %s", g_strerror (errno)); g_usleep (G_USEC_PER_SEC / 10); continue; } } GST_INFO_OBJECT (self, "shutting down net client clock thread"); g_main_context_unref (ctx); return NULL; }
static gpointer gst_net_time_provider_thread (gpointer data) { GstNetTimeProvider *self = data; struct sockaddr_in tmpaddr; socklen_t len; GstNetTimePacket *packet; gint ret; while (TRUE) { GST_LOG_OBJECT (self, "doing select"); ret = gst_poll_wait (self->priv->fdset, GST_CLOCK_TIME_NONE); GST_LOG_OBJECT (self, "select returned %d", ret); if (ret <= 0) { if (errno == EBUSY) { GST_LOG_OBJECT (self, "stop"); goto stopped; } else if (errno != EAGAIN && errno != EINTR) goto select_error; else continue; } else { /* got data in */ len = sizeof (struct sockaddr); packet = gst_net_time_packet_receive (self->priv->sock.fd, (struct sockaddr *) &tmpaddr, &len); if (!packet) goto receive_error; if (IS_ACTIVE (self)) { /* do what we were asked to and send the packet back */ packet->remote_time = gst_clock_get_time (self->clock); /* ignore errors */ gst_net_time_packet_send (packet, self->priv->sock.fd, (struct sockaddr *) &tmpaddr, len); } g_free (packet); continue; } 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); continue; } stopped: { GST_DEBUG_OBJECT (self, "shutting down"); /* close socket */ return NULL; } receive_error: { GST_DEBUG_OBJECT (self, "receive error"); continue; } g_assert_not_reached (); } g_assert_not_reached (); return NULL; }
static gpointer gst_net_client_clock_thread (gpointer data) { GstNetClientClock *self = data; struct sockaddr_in tmpaddr; socklen_t len; GstNetTimePacket *packet; gint ret; GstClock *clock = data; while (TRUE) { ret = gst_net_client_clock_do_select (self); if (ret < 0 && errno == EBUSY) { GST_LOG_OBJECT (self, "stop"); goto stopped; } else if (ret == 0) { /* timed out, let's send another packet */ GST_DEBUG_OBJECT (self, "timed out"); packet = gst_net_time_packet_new (NULL); packet->local_time = gst_clock_get_internal_time (GST_CLOCK (self)); GST_DEBUG_OBJECT (self, "sending packet, local time = %" GST_TIME_FORMAT, GST_TIME_ARGS (packet->local_time)); gst_net_time_packet_send (packet, self->priv->sock.fd, (struct sockaddr *) self->servaddr, sizeof (struct sockaddr_in)); g_free (packet); /* reset timeout */ self->current_timeout = clock->timeout; continue; } else if (gst_poll_fd_can_read (self->priv->fdset, &self->priv->sock)) { /* got data in */ GstClockTime new_local = gst_clock_get_internal_time (GST_CLOCK (self)); len = sizeof (struct sockaddr); packet = gst_net_time_packet_receive (self->priv->sock.fd, (struct sockaddr *) &tmpaddr, &len); if (!packet) goto receive_error; GST_LOG_OBJECT (self, "got packet back"); GST_LOG_OBJECT (self, "local_1 = %" GST_TIME_FORMAT, GST_TIME_ARGS (packet->local_time)); GST_LOG_OBJECT (self, "remote = %" GST_TIME_FORMAT, GST_TIME_ARGS (packet->remote_time)); GST_LOG_OBJECT (self, "local_2 = %" GST_TIME_FORMAT, GST_TIME_ARGS (new_local)); /* observe_times will reset the timeout */ gst_net_client_clock_observe_times (self, packet->local_time, packet->remote_time, new_local); g_free (packet); continue; } else { GST_WARNING_OBJECT (self, "unhandled select return state?"); continue; } g_assert_not_reached (); stopped: { GST_DEBUG_OBJECT (self, "shutting down"); /* socket gets closed in _stop() */ return NULL; } receive_error: { GST_WARNING_OBJECT (self, "receive error"); continue; } g_assert_not_reached (); } g_assert_not_reached (); return NULL; }
static gpointer gst_net_client_internal_clock_thread (gpointer data) { GstNetClientInternalClock *self = data; GSocket *socket = self->socket; GError *err = NULL; GST_INFO_OBJECT (self, "net client clock thread running, socket=%p", socket); g_socket_set_blocking (socket, TRUE); g_socket_set_timeout (socket, 0); while (!g_cancellable_is_cancelled (self->cancel)) { GstClockTime expiration_time = self->timeout_expiration; GstClockTime now = gst_util_get_timestamp (); gint64 socket_timeout; if (now >= expiration_time || (expiration_time - now) <= GST_MSECOND) { socket_timeout = 0; } else { socket_timeout = (expiration_time - now) / GST_USECOND; } GST_TRACE_OBJECT (self, "timeout: %" G_GINT64_FORMAT "us", socket_timeout); if (!g_socket_condition_timed_wait (socket, G_IO_IN, socket_timeout, self->cancel, &err)) { /* cancelled, timeout or error */ if (err->code == G_IO_ERROR_CANCELLED) { GST_INFO_OBJECT (self, "cancelled"); g_clear_error (&err); break; } else if (err->code == G_IO_ERROR_TIMED_OUT) { /* timed out, let's send another packet */ GST_DEBUG_OBJECT (self, "timed out"); if (self->is_ntp) { GstNtpPacket *packet; packet = gst_ntp_packet_new (NULL, NULL); packet->transmit_time = gst_clock_get_internal_time (GST_CLOCK_CAST (self)); GST_DEBUG_OBJECT (self, "sending packet, local time = %" GST_TIME_FORMAT, GST_TIME_ARGS (packet->transmit_time)); gst_ntp_packet_send (packet, self->socket, self->servaddr, NULL); g_free (packet); } else { GstNetTimePacket *packet; packet = gst_net_time_packet_new (NULL); packet->local_time = gst_clock_get_internal_time (GST_CLOCK_CAST (self)); GST_DEBUG_OBJECT (self, "sending packet, local time = %" GST_TIME_FORMAT, GST_TIME_ARGS (packet->local_time)); gst_net_time_packet_send (packet, self->socket, self->servaddr, NULL); g_free (packet); } /* reset timeout (but are expecting a response sooner anyway) */ self->timeout_expiration = gst_util_get_timestamp () + gst_clock_get_timeout (GST_CLOCK_CAST (self)); } else { GST_DEBUG_OBJECT (self, "socket error: %s", err->message); g_usleep (G_USEC_PER_SEC / 10); /* throttle */ } g_clear_error (&err); } else { GstClockTime new_local; /* got packet */ new_local = gst_clock_get_internal_time (GST_CLOCK_CAST (self)); if (self->is_ntp) { GstNtpPacket *packet; packet = gst_ntp_packet_receive (socket, NULL, &err); if (packet != NULL) { GST_LOG_OBJECT (self, "got packet back"); GST_LOG_OBJECT (self, "local_1 = %" GST_TIME_FORMAT, GST_TIME_ARGS (packet->origin_time)); GST_LOG_OBJECT (self, "remote_1 = %" GST_TIME_FORMAT, GST_TIME_ARGS (packet->receive_time)); GST_LOG_OBJECT (self, "remote_2 = %" GST_TIME_FORMAT, GST_TIME_ARGS (packet->transmit_time)); GST_LOG_OBJECT (self, "local_2 = %" GST_TIME_FORMAT, GST_TIME_ARGS (new_local)); GST_LOG_OBJECT (self, "poll_interval = %" GST_TIME_FORMAT, GST_TIME_ARGS (packet->poll_interval)); /* Remember the last poll interval we ever got from the server */ if (packet->poll_interval != GST_CLOCK_TIME_NONE) self->last_remote_poll_interval = packet->poll_interval; /* observe_times will reset the timeout */ gst_net_client_internal_clock_observe_times (self, packet->origin_time, packet->receive_time, packet->transmit_time, new_local); g_free (packet); } else if (err != NULL) { if (g_error_matches (err, GST_NTP_ERROR, GST_NTP_ERROR_WRONG_VERSION) || g_error_matches (err, GST_NTP_ERROR, GST_NTP_ERROR_KOD_DENY)) { GST_ERROR_OBJECT (self, "fatal receive error: %s", err->message); g_clear_error (&err); break; } else if (g_error_matches (err, GST_NTP_ERROR, GST_NTP_ERROR_KOD_RATE)) { GST_WARNING_OBJECT (self, "need to limit rate"); /* If the server did not tell us a poll interval before, double * our minimum poll interval. Otherwise we assume that the server * already told us something sensible and that this error here * was just a spurious error */ if (self->last_remote_poll_interval == GST_CLOCK_TIME_NONE) self->minimum_update_interval *= 2; /* And wait a bit before we send the next packet instead of * sending it immediately */ self->timeout_expiration = gst_util_get_timestamp () + gst_clock_get_timeout (GST_CLOCK_CAST (self)); } else { GST_WARNING_OBJECT (self, "receive error: %s", err->message); } g_clear_error (&err); } } else { GstNetTimePacket *packet; packet = gst_net_time_packet_receive (socket, NULL, &err); if (packet != NULL) { GST_LOG_OBJECT (self, "got packet back"); GST_LOG_OBJECT (self, "local_1 = %" GST_TIME_FORMAT, GST_TIME_ARGS (packet->local_time)); GST_LOG_OBJECT (self, "remote = %" GST_TIME_FORMAT, GST_TIME_ARGS (packet->remote_time)); GST_LOG_OBJECT (self, "local_2 = %" GST_TIME_FORMAT, GST_TIME_ARGS (new_local)); /* observe_times will reset the timeout */ gst_net_client_internal_clock_observe_times (self, packet->local_time, packet->remote_time, packet->remote_time, new_local); g_free (packet); } else if (err != NULL) { GST_WARNING_OBJECT (self, "receive error: %s", err->message); g_clear_error (&err); } } } } GST_INFO_OBJECT (self, "shutting down net client clock thread"); return NULL; }