static void send_5app_1el_1err_2app_messages (guint interval_usecs) { GstMessage *m; GstStructure *s; gint i; for (i = 0; i < 5; i++) { s = gst_structure_new ("test_message", "msg_id", G_TYPE_INT, i, NULL); m = gst_message_new_application (NULL, s); GST_LOG ("posting application message"); gst_bus_post (test_bus, m); g_usleep (interval_usecs); } for (i = 0; i < 1; i++) { s = gst_structure_new ("test_message", "msg_id", G_TYPE_INT, i, NULL); m = gst_message_new_element (NULL, s); GST_LOG ("posting element message"); gst_bus_post (test_bus, m); g_usleep (interval_usecs); } for (i = 0; i < 1; i++) { m = gst_message_new_error (NULL, NULL, "debug string"); GST_LOG ("posting error message"); gst_bus_post (test_bus, m); g_usleep (interval_usecs); } for (i = 0; i < 2; i++) { s = gst_structure_new ("test_message", "msg_id", G_TYPE_INT, i, NULL); m = gst_message_new_application (NULL, s); GST_LOG ("posting application message"); gst_bus_post (test_bus, m); g_usleep (interval_usecs); } }
static void brasero_transcode_error_on_pad_linking (BraseroTranscode *self, const gchar *function_name) { BraseroTranscodePrivate *priv; GstMessage *message; GstBus *bus; priv = BRASERO_TRANSCODE_PRIVATE (self); BRASERO_JOB_LOG (self, "Error on pad linking"); message = gst_message_new_error (GST_OBJECT (priv->pipeline), g_error_new (BRASERO_BURN_ERROR, BRASERO_BURN_ERROR_GENERAL, /* Translators: This message is sent * when brasero could not link together * two gstreamer plugins so that one * sends its data to the second for further * processing. This data transmission is * done through a pad. Maybe this is a bit * too technical and should be removed? */ _("Impossible to link plugin pads")), function_name); bus = gst_pipeline_get_bus (GST_PIPELINE (priv->pipeline)); gst_bus_post (bus, message); g_object_unref (bus); }
static gboolean send_messages (gpointer data) { GstMessage *m; GstStructure *s; gint i; for (i = 0; i < 10; i++) { s = gst_structure_new ("test_message", "msg_id", G_TYPE_INT, i, NULL); m = gst_message_new_application (NULL, s); gst_bus_post (test_bus, m); s = gst_structure_new ("test_message", "msg_id", G_TYPE_INT, i, NULL); m = gst_message_new_custom (GST_MESSAGE_EOS, NULL, s); gst_bus_post (test_bus, m); } return FALSE; }
static gboolean error_timeout (ProgramData * data) { GstBus *bus; bus = gst_element_get_bus (data->sink); gst_bus_post (bus, gst_message_new_error (GST_OBJECT (data->sink), NULL, "test error")); gst_object_unref (bus); return FALSE; }
static void send_extended_messages (guint interval_usecs) { GstMessage *msg; GstDevice *device; device = g_object_new (foo_device_get_type (), NULL); msg = gst_message_new_device_added (NULL, device); GST_LOG ("posting device-added message"); gst_bus_post (test_bus, msg); g_usleep (interval_usecs); msg = gst_message_new_device_removed (NULL, device); GST_LOG ("posting device-removed message"); gst_bus_post (test_bus, msg); g_usleep (interval_usecs); gst_object_unref (device); }
static void send_10_app_messages (void) { GstMessage *m; GstStructure *s; gint i; for (i = 0; i < 10; i++) { s = gst_structure_new ("test_message", "msg_id", G_TYPE_INT, i, NULL); m = gst_message_new_application (NULL, s); gst_bus_post (test_bus, m); } }
static void bus_sync_message (GstBus * bus, GstMessage * message, GstDeviceMonitor * monitor) { GstMessageType type = GST_MESSAGE_TYPE (message); if (type == GST_MESSAGE_DEVICE_ADDED || type == GST_MESSAGE_DEVICE_REMOVED) { gboolean matches; GstDevice *device; GstDeviceProvider *provider; if (type == GST_MESSAGE_DEVICE_ADDED) gst_message_parse_device_added (message, &device); else gst_message_parse_device_removed (message, &device); GST_OBJECT_LOCK (monitor); provider = GST_DEVICE_PROVIDER (gst_object_get_parent (GST_OBJECT (device))); if (is_provider_hidden (monitor, monitor->priv->hidden, provider)) { matches = FALSE; } else if (monitor->priv->filters->len) { guint i; for (i = 0; i < monitor->priv->filters->len; i++) { struct DeviceFilter *filter = g_ptr_array_index (monitor->priv->filters, i); GstCaps *caps; caps = gst_device_get_caps (device); matches = gst_caps_can_intersect (filter->caps, caps) && gst_device_has_classesv (device, filter->classesv); gst_caps_unref (caps); if (matches) break; } } else { matches = TRUE; } GST_OBJECT_UNLOCK (monitor); gst_object_unref (provider); gst_object_unref (device); if (matches) gst_bus_post (monitor->priv->bus, gst_message_ref (message)); } }
static void gstreamer_close_file(struct input_handle* ih) { if (ih->bin) { GstBus *bus = gst_element_get_bus(ih->bin); gst_bus_post(bus, gst_message_new_eos(NULL)); g_object_unref(bus); } g_thread_join(ih->gstreamer_loop); if (ih->message_source) g_source_destroy(ih->message_source); if (ih->bin) { /* cleanup */ gst_element_set_state(ih->bin, GST_STATE_NULL); g_object_unref(ih->bin); ih->bin = NULL; g_main_loop_unref(ih->loop); } }
GstPadProbeReturn eos_event_cb (GstPad *pad, GstPadProbeInfo *info, gpointer data) { if (GST_EVENT_TYPE (GST_PAD_PROBE_INFO_DATA (info)) == GST_EVENT_EOS) { GstElement *bin = NULL; GstMessage *message = NULL; GstStructure *msg_struct = NULL; MbMedia *media; gchar *uri = NULL; int pads = 0; media = (MbMedia *) data; bin = gst_bin_get_by_name (GST_BIN(_mb_global_data.pipeline), media->name); g_assert(bin); g_mutex_lock (&(media->mutex)); pads = --media->valid_pads; g_mutex_unlock (&(media->mutex)); g_object_get (media->decoder, "uri", &uri, NULL); g_debug ("EOS received (%s): %s.\n", media->name, uri); g_debug ("%s still has %d valid pad(s).\n", media->name, pads); if (pads == 0) { MbEvent *event = create_state_change_event (MB_END, media->name); notify_handler (event); free (event); g_hash_table_remove (_mb_global_data.media_table, media->name); msg_struct = gst_structure_new ("end-media", "event_type", G_TYPE_INT, APP_EVT_MEDIA_END, "data", G_TYPE_POINTER, media, /* FILL ME IF NECESSARY */ NULL); message = gst_message_new_application (GST_OBJECT(bin), msg_struct); g_debug ("Posting event\n"); gst_bus_post (_mb_global_data.bus, message); } g_free (uri); } return GST_PAD_PROBE_OK; }
static int gstreamer_open_file(struct input_handle* ih, const char* filename) { GTimeVal beg, end; ih->filename = filename; ih->quit_pipeline = TRUE; ih->main_loop_quit = FALSE; ih->ready = FALSE; ih->bin = NULL; ih->message_source = NULL; ih->gstreamer_loop = g_thread_create((GThreadFunc) gstreamer_loop, ih, TRUE, NULL); g_get_current_time(&beg); while (!ih->ready) { g_thread_yield(); g_get_current_time(&end); if (end.tv_usec + end.tv_sec * G_USEC_PER_SEC - beg.tv_usec - beg.tv_sec * G_USEC_PER_SEC > 1 * G_USEC_PER_SEC) { break; } } if (!ih->quit_pipeline) { if (!query_data(ih)) { ih->quit_pipeline = TRUE; } } if (ih->quit_pipeline) { if (ih->bin) { GstBus *bus = gst_element_get_bus(ih->bin); gst_bus_post(bus, gst_message_new_eos(NULL)); g_object_unref(bus); } g_thread_join(ih->gstreamer_loop); if (ih->message_source) g_source_destroy(ih->message_source); if (ih->bin) { /* cleanup */ gst_element_set_state(ih->bin, GST_STATE_NULL); g_object_unref(ih->bin); ih->bin = NULL; g_main_loop_unref(ih->loop); } return 1; } else { return 0; } }
static gpointer pound_bus_with_messages (gpointer data) { gint thread_id = GPOINTER_TO_INT (data); gint i; for (i = 0; i < NUM_MESSAGES; i++) { GstMessage *m; GstStructure *s; s = gst_structure_new ("test_message", "thread_id", G_TYPE_INT, thread_id, "msg_id", G_TYPE_INT, i, NULL); m = gst_message_new_application (NULL, s); gst_bus_post (test_bus, m); } return NULL; }
static GstFlowReturn gst_nekobus_show_frame (GstBaseSink * sink, GstBuffer * buf) { GstNekoBus *element; element = GST_NEKOBUS (sink); GstStructure *msg = gst_structure_new("nekobus::data", "element", G_TYPE_STRING, gst_element_get_name( GST_ELEMENT(element) ), "buffer", GST_TYPE_BUFFER, buf, NULL ); gst_bus_post( gst_element_get_bus(GST_ELEMENT(sink)), gst_message_new_application( GST_OBJECT(sink), msg ) ); /* we're leaving the buffer unref'ing to the bus receiver :/ -- what if noone receives the msg? FIXME */ return GST_FLOW_OK; }
static void dec_counter (GstPlayRegion *PlayRegion) { if (PlayRegion->prerolled) return; if (g_atomic_int_dec_and_test (&PlayRegion->counter)) { /* all probes blocked and no-more-pads signaled, post * message on the bus. */ PlayRegion->prerolled = TRUE; g_print ("fire application message\n"); gst_bus_post (PlayRegion->bus, gst_message_new_application ( GST_OBJECT_CAST (PlayRegion->pipeline), gst_structure_new_empty ("ExPrerolled"))); } }
static void Lastfmfp_cb_have_data(GstElement *element, GstBuffer *buffer, GstPad *pad, LastfmfpAudio *ma) { gint buffersamples; gint bufferpos; gint i; gint j; gint fill; // if data continues to flow/EOS is not yet processed if (ma->quit) return; // exit on empty buffer if (buffer->size <= 0) return; ma->data_in = (short*)GST_BUFFER_DATA(buffer); //ma->num_samples = (size_t)(GST_BUFFER_OFFSET_END (buffer) - GST_BUFFER_OFFSET (buffer)); ma->num_samples = (size_t)(GST_BUFFER_SIZE (buffer) / sizeof(guint16)); //printf("caps: %s\n", gst_caps_to_string(GST_BUFFER_CAPS(buffer))); //printf(" offset : %llu size: %llu \n", (unsigned long long)GST_BUFFER_OFFSET (buffer), (unsigned long long)GST_BUFFER_OFFSET_END (buffer)); //GST_LOG ("caps are %" GST_PTR_FORMAT, GST_BUFFER_CAPS(buffer)); //extractor.process(const short* pPCM, size_t num_samples, bool end_of_stream = false); //printf("data: %d %d %d %d %d %d %d %d %d %d %d %d \n", ma->data_in[0], ma->data_in[1], ma->data_in[2], ma->data_in[3], ma->data_in[4], ma->data_in[5], ma->data_in[6], ma->data_in[7], ma->data_in[8], ma->data_in[9], ma->data_in[10], ma->data_in[11]); if (ma->extractor->process(ma->data_in, ma->num_samples, false))//TODO check parametters { //stop the gstreamer loop to free all and return fpid GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(ma->pipeline)); GstMessage* eosmsg = gst_message_new_eos(GST_OBJECT(ma->pipeline)); gst_bus_post(bus, eosmsg); g_print("libLastfmfp: EOS Message sent\n"); gst_object_unref(bus); ma->quit = TRUE; return; } return; }
void mirageaudio_canceldecode(MirageAudio *ma) { if (GST_IS_ELEMENT(ma->pipeline)) { GstState state; gst_element_get_state(ma->pipeline, &state, NULL, 100*GST_MSECOND); if (state != GST_STATE_NULL) { g_mutex_lock(ma->decoding_mutex); GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(ma->pipeline)); GstMessage* eosmsg = gst_message_new_eos(GST_OBJECT(ma->pipeline)); gst_bus_post(bus, eosmsg); g_print("libmirageaudio: EOS Message sent\n"); gst_object_unref(bus); ma->invalidate = TRUE; g_mutex_unlock(ma->decoding_mutex); } } }
static void mirageaudio_cb_have_data(GstElement *element, GstBuffer *buffer, GstPad *pad, MirageAudio *ma) { gint buffersamples; gint bufferpos; gint i; gint j; gint fill; GstMapInfo map; // if data continues to flow/EOS is not yet processed if (ma->quit) return; // exit on empty buffer if (gst_buffer_get_size (buffer) <= 0) return; if (!gst_buffer_map (buffer, &map, GST_MAP_READ)) return; ma->src_data.data_in = (float*)map.data; ma->src_data.input_frames = map.size/sizeof(float); do { // set end of input flag if necessary ma->cursample += ma->src_data.input_frames; if (ma->cursample >= ma->seconds * ma->filerate) { ma->src_data.end_of_input = 1; } // resampling int err = src_process(ma->src_state, &ma->src_data); if (err != 0) { g_print("libmirageaudio: SRC Error - %s\n", src_strerror(err)); } // return if no output if (ma->src_data.output_frames_gen == 0) { gst_buffer_unmap (buffer, &map); return; } buffersamples = ma->src_data.output_frames_gen; bufferpos = 0; // FFTW // If buffer does not get filled if (ma->fftwsamples + buffersamples < ma->winsize) { memcpy(ma->fftw+ma->fftwsamples, ma->src_data.data_out, buffersamples*sizeof(float)); ma->fftwsamples += buffersamples; // If buffer gets filled. } else { do { // prepare FFTW fill = ma->winsize - ma->fftwsamples; if (fill <= 0) g_print("libmirageaudio: Logic ERROR! fill <= 0\n"); memcpy(ma->fftw+ma->fftwsamples, ma->src_data.data_out+bufferpos, fill*sizeof(float)); memset(ma->fftw+ma->winsize, 0, ma->winsize*sizeof(float)); for (i = 0; i < ma->winsize; i++) { ma->fftw[i] = ma->fftw[i] * ma->window[i] * 32768.0f; } // Execute FFTW fftwf_execute(ma->fftwplan); // Powerspectrum ma->out[ma->curhop] = powf(ma->fftw[0], 2); for (j = 1; j < ma->winsize/2; j++) { ma->out[j*ma->hops + ma->curhop] = powf(ma->fftw[j*2], 2) + powf(ma->fftw[ma->fftwsize-j*2], 2); } ma->out[(ma->winsize/2)*ma->hops + ma->curhop] = powf(ma->fftw[ma->winsize], 2); ma->fftwsamples = 0; buffersamples -= fill; bufferpos += fill; ma->curhop++; if (ma->curhop == ma->hops) { GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(ma->pipeline)); GstMessage* eosmsg = gst_message_new_eos(GST_OBJECT(ma->pipeline)); gst_bus_post(bus, eosmsg); g_print("libmirageaudio: EOS Message sent\n"); gst_object_unref(bus); ma->quit = TRUE; gst_buffer_unmap (buffer, &map); return; } } while (buffersamples >= ma->winsize); if (buffersamples > 0) { memcpy(ma->fftw, ma->src_data.data_out+bufferpos, buffersamples*sizeof(float)); ma->fftwsamples = buffersamples; } } ma->src_data.data_in += ma->src_data.input_frames_used; ma->src_data.input_frames -= ma->src_data.input_frames_used; } while (ma->src_data.input_frames > 0); gst_buffer_unmap (buffer, &map); return; }
gpointer upload_file (gpointer data) { int err; void* output; // Application key and secret. To get them, create an app here: // https://www.dropbox.com/developers/apps char *c_key = "lmg4kv8jw45nlsr"; //< consumer key char *c_secret = "xmq9x391l0y8nwy"; //< consumer secret char filename[200]; CustomData *cdata=(CustomData*)data; strcpy(filename,cdata->sink_filename); // User key and secret. Leave them NULL or set them with your AccessToken. // char *t_key = NULL; //< access token key // char *t_secret = NULL; //< access token secret char *t_key = "5j55oq1lf8h1zi2w"; //< access token key char *t_secret = "nvv5ps3hy4v4wy3"; //< access token secret // Global initialisation drbInit(); // Create a Dropbox client drbClient* cli = drbCreateClient(c_key, c_secret, t_key, t_secret); // Request a AccessToken if undefined (NULL) if(!t_key || !t_secret) { drbOAuthToken* reqTok = drbObtainRequestToken(cli); if (reqTok) { char* url = drbBuildAuthorizeUrl(reqTok); printf("Please visit %s\nThen press Enter...\n", url); free(url); fgetc(stdin); drbOAuthToken* accTok = drbObtainAccessToken(cli); if (accTok) { // This key and secret can replace the NULL value in t_key and // t_secret for the next time. printf("key: %s\nsecret: %s\n", accTok->key, accTok->secret); } else{ fprintf(stderr, "Failed to obtain an AccessToken...\n"); return NULL; } } else { fprintf(stderr, "Failed to obtain a RequestToken...\n"); return NULL; } } // Set default arguments to not repeat them on each API call drbSetDefault(cli, DRBOPT_ROOT, DRBVAL_ROOT_AUTO, DRBOPT_END); // upload current file FILE *file = fopen(filename, "r"); char fn[200]; memset(fn,0,sizeof(fn)); strcpy(fn,"/"); strcat(fn,filename); output = NULL; err = drbPutFile(cli, &output, DRBOPT_PATH, fn, DRBOPT_IO_DATA, file, DRBOPT_IO_FUNC, fread, DRBOPT_END); printf("File upload: %s\n", err ? "Failed" : "Successful"); fclose(file); output = NULL; //share public link to file drbShare(cli, &output, DRBOPT_PATH, fn, DRBOPT_END); drbLink* url = (drbLink*)output; // strcpy(link,url->url); We should return here!!!! drbDestroyClient(cli); // Global Cleanup drbCleanup(); gst_bus_post(cdata->bus,gst_message_new_application( GST_OBJECT_CAST(cdata->pipeline), gst_structure_new_empty("UploadDone"))); return url->url; }
static void gst_net_client_internal_clock_observe_times (GstNetClientInternalClock * self, GstClockTime local_1, GstClockTime remote_1, GstClockTime remote_2, GstClockTime local_2) { GstClockTime current_timeout = 0; GstClockTime local_avg, remote_avg; gdouble r_squared; GstClock *clock; GstClockTime rtt, rtt_limit, min_update_interval; /* Use for discont tracking */ GstClockTime time_before = 0; GstClockTime min_guess = 0; GstClockTimeDiff time_discont = 0; gboolean synched, now_synched; GstClockTime internal_time, external_time, rate_num, rate_den; GstClockTime orig_internal_time, orig_external_time, orig_rate_num, orig_rate_den; GstClockTime max_discont; GstClockTime last_rtts[MEDIAN_PRE_FILTERING_WINDOW]; GstClockTime median; gint i; GST_OBJECT_LOCK (self); rtt_limit = self->roundtrip_limit; GST_LOG_OBJECT (self, "local1 %" G_GUINT64_FORMAT " remote1 %" G_GUINT64_FORMAT " remote2 %" G_GUINT64_FORMAT " local2 %" G_GUINT64_FORMAT, local_1, remote_1, remote_2, local_2); /* If the server told us a poll interval and it's bigger than the * one configured via the property, use the server's */ if (self->last_remote_poll_interval != GST_CLOCK_TIME_NONE && self->last_remote_poll_interval > self->minimum_update_interval) min_update_interval = self->last_remote_poll_interval; else min_update_interval = self->minimum_update_interval; GST_OBJECT_UNLOCK (self); if (local_2 < local_1) { GST_LOG_OBJECT (self, "Dropping observation: receive time %" GST_TIME_FORMAT " < send time %" GST_TIME_FORMAT, GST_TIME_ARGS (local_1), GST_TIME_ARGS (local_2)); goto bogus_observation; } if (remote_2 < remote_1) { GST_LOG_OBJECT (self, "Dropping observation: remote receive time %" GST_TIME_FORMAT " < send time %" GST_TIME_FORMAT, GST_TIME_ARGS (remote_1), GST_TIME_ARGS (remote_2)); goto bogus_observation; } /* The round trip time is (assuming symmetric path delays) * delta = (local_2 - local_1) - (remote_2 - remote_1) */ rtt = GST_CLOCK_DIFF (local_1, local_2) - GST_CLOCK_DIFF (remote_1, remote_2); if ((rtt_limit > 0) && (rtt > rtt_limit)) { GST_LOG_OBJECT (self, "Dropping observation: RTT %" GST_TIME_FORMAT " > limit %" GST_TIME_FORMAT, GST_TIME_ARGS (rtt), GST_TIME_ARGS (rtt_limit)); goto bogus_observation; } for (i = 1; i < MEDIAN_PRE_FILTERING_WINDOW; i++) self->last_rtts[i - 1] = self->last_rtts[i]; self->last_rtts[i - 1] = rtt; if (self->last_rtts_missing) { self->last_rtts_missing--; } else { memcpy (&last_rtts, &self->last_rtts, sizeof (last_rtts)); g_qsort_with_data (&last_rtts, MEDIAN_PRE_FILTERING_WINDOW, sizeof (GstClockTime), (GCompareDataFunc) compare_clock_time, NULL); median = last_rtts[MEDIAN_PRE_FILTERING_WINDOW / 2]; /* FIXME: We might want to use something else here, like only allowing * things in the interquartile range, or also filtering away delays that * are too small compared to the median. This here worked well enough * in tests so far. */ if (rtt > 2 * median) { GST_LOG_OBJECT (self, "Dropping observation, long RTT %" GST_TIME_FORMAT " > 2 * median %" GST_TIME_FORMAT, GST_TIME_ARGS (rtt), GST_TIME_ARGS (median)); goto bogus_observation; } } /* Track an average round trip time, for a bit of smoothing */ /* Always update before discarding a sample, so genuine changes in * the network get picked up, eventually */ if (self->rtt_avg == GST_CLOCK_TIME_NONE) self->rtt_avg = rtt; else if (rtt < self->rtt_avg) /* Shorter RTTs carry more weight than longer */ self->rtt_avg = (3 * self->rtt_avg + rtt) / 4; else self->rtt_avg = (15 * self->rtt_avg + rtt) / 16; if (rtt > 2 * self->rtt_avg) { GST_LOG_OBJECT (self, "Dropping observation, long RTT %" GST_TIME_FORMAT " > 2 * avg %" GST_TIME_FORMAT, GST_TIME_ARGS (rtt), GST_TIME_ARGS (self->rtt_avg)); goto bogus_observation; } /* The difference between the local and remote clock (again assuming * symmetric path delays): * * local_1 + delta / 2 - remote_1 = theta * or * local_2 - delta / 2 - remote_2 = theta * * which gives after some simple algebraic transformations: * * (remote_1 - local_1) + (remote_2 - local_2) * theta = ------------------------------------------- * 2 * * * Thus remote time at local_avg is equal to: * * local_avg + theta = * * local_1 + local_2 (remote_1 - local_1) + (remote_2 - local_2) * ----------------- + ------------------------------------------- * 2 2 * * = * * remote_1 + remote_2 * ------------------- = remote_avg * 2 * * We use this for our clock estimation, i.e. local_avg at remote clock * being the same as remote_avg. */ local_avg = (local_2 + local_1) / 2; remote_avg = (remote_2 + remote_1) / 2; GST_LOG_OBJECT (self, "remoteavg %" G_GUINT64_FORMAT " localavg %" G_GUINT64_FORMAT, remote_avg, local_avg); clock = GST_CLOCK_CAST (self); /* Store what the clock produced as 'now' before this update */ gst_clock_get_calibration (GST_CLOCK_CAST (self), &orig_internal_time, &orig_external_time, &orig_rate_num, &orig_rate_den); internal_time = orig_internal_time; external_time = orig_external_time; rate_num = orig_rate_num; rate_den = orig_rate_den; min_guess = gst_clock_adjust_with_calibration (GST_CLOCK_CAST (self), local_1, internal_time, external_time, rate_num, rate_den); time_before = gst_clock_adjust_with_calibration (GST_CLOCK_CAST (self), local_2, internal_time, external_time, rate_num, rate_den); /* Maximum discontinuity, when we're synched with the master. Could make this a property, * but this value seems to work fine */ max_discont = self->rtt_avg / 4; /* If the remote observation was within a max_discont window around our min/max estimates, we're synched */ synched = (GST_CLOCK_DIFF (remote_avg, min_guess) < (GstClockTimeDiff) (max_discont) && GST_CLOCK_DIFF (time_before, remote_avg) < (GstClockTimeDiff) (max_discont)); if (gst_clock_add_observation_unapplied (GST_CLOCK_CAST (self), local_avg, remote_avg, &r_squared, &internal_time, &external_time, &rate_num, &rate_den)) { /* Now compare the difference (discont) in the clock * after this observation */ time_discont = GST_CLOCK_DIFF (time_before, gst_clock_adjust_with_calibration (GST_CLOCK_CAST (self), local_2, internal_time, external_time, rate_num, rate_den)); /* If we were in sync with the remote clock, clamp the allowed * discontinuity to within quarter of one RTT. In sync means our send/receive estimates * of remote time correctly windowed the actual remote time observation */ if (synched && ABS (time_discont) > max_discont) { GstClockTimeDiff offset; GST_DEBUG_OBJECT (clock, "Too large a discont, clamping to 1/4 average RTT = %" GST_TIME_FORMAT, GST_TIME_ARGS (max_discont)); if (time_discont > 0) { /* Too large a forward step - add a -ve offset */ offset = max_discont - time_discont; if (-offset > external_time) external_time = 0; else external_time += offset; } else { /* Too large a backward step - add a +ve offset */ offset = -(max_discont + time_discont); external_time += offset; } time_discont += offset; } /* Check if the new clock params would have made our observation within range */ now_synched = (GST_CLOCK_DIFF (remote_avg, gst_clock_adjust_with_calibration (GST_CLOCK_CAST (self), local_1, internal_time, external_time, rate_num, rate_den)) < (GstClockTimeDiff) (max_discont)) && (GST_CLOCK_DIFF (gst_clock_adjust_with_calibration (GST_CLOCK_CAST (self), local_2, internal_time, external_time, rate_num, rate_den), remote_avg) < (GstClockTimeDiff) (max_discont)); /* Only update the clock if we had synch or just gained it */ if (synched || now_synched || self->skipped_updates > MAX_SKIPPED_UPDATES) { gst_clock_set_calibration (GST_CLOCK_CAST (self), internal_time, external_time, rate_num, rate_den); /* ghetto formula - shorter timeout for bad correlations */ current_timeout = (1e-3 / (1 - MIN (r_squared, 0.99999))) * GST_SECOND; current_timeout = MIN (current_timeout, gst_clock_get_timeout (GST_CLOCK_CAST (self))); self->skipped_updates = 0; /* FIXME: When do we consider the clock absolutely not synced anymore? */ gst_clock_set_synced (GST_CLOCK (self), TRUE); } else { /* Restore original calibration vars for the report, we're not changing the clock */ internal_time = orig_internal_time; external_time = orig_external_time; rate_num = orig_rate_num; rate_den = orig_rate_den; time_discont = 0; self->skipped_updates++; } } /* Limit the polling to at most one per minimum_update_interval */ if (rtt < min_update_interval) current_timeout = MAX (min_update_interval - rtt, current_timeout); GST_OBJECT_LOCK (self); if (self->busses) { GstStructure *s; GstMessage *msg; GList *l; /* Output a stats message, whether we updated the clock or not */ s = gst_structure_new ("gst-netclock-statistics", "synchronised", G_TYPE_BOOLEAN, synched, "rtt", G_TYPE_UINT64, rtt, "rtt-average", G_TYPE_UINT64, self->rtt_avg, "local", G_TYPE_UINT64, local_avg, "remote", G_TYPE_UINT64, remote_avg, "discontinuity", G_TYPE_INT64, time_discont, "remote-min-estimate", G_TYPE_UINT64, min_guess, "remote-max-estimate", G_TYPE_UINT64, time_before, "remote-min-error", G_TYPE_INT64, GST_CLOCK_DIFF (remote_avg, min_guess), "remote-max-error", G_TYPE_INT64, GST_CLOCK_DIFF (remote_avg, time_before), "request-send", G_TYPE_UINT64, local_1, "request-receive", G_TYPE_UINT64, local_2, "r-squared", G_TYPE_DOUBLE, r_squared, "timeout", G_TYPE_UINT64, current_timeout, "internal-time", G_TYPE_UINT64, internal_time, "external-time", G_TYPE_UINT64, external_time, "rate-num", G_TYPE_UINT64, rate_num, "rate-den", G_TYPE_UINT64, rate_den, "rate", G_TYPE_DOUBLE, (gdouble) (rate_num) / rate_den, "local-clock-offset", G_TYPE_INT64, GST_CLOCK_DIFF (internal_time, external_time), NULL); msg = gst_message_new_element (GST_OBJECT (self), s); for (l = self->busses; l; l = l->next) gst_bus_post (l->data, gst_message_ref (msg)); gst_message_unref (msg); } GST_OBJECT_UNLOCK (self); GST_INFO ("next timeout: %" GST_TIME_FORMAT, GST_TIME_ARGS (current_timeout)); self->timeout_expiration = gst_util_get_timestamp () + current_timeout; return; bogus_observation: /* Schedule a new packet again soon */ self->timeout_expiration = gst_util_get_timestamp () + (GST_SECOND / 4); return; }