/** * gst_audio_clock_new: * @name: the name of the clock * @func: a function * @user_data: user data * * Create a new #GstAudioClock instance. Whenever the clock time should be * calculated it will call @func with @user_data. When @func returns * #GST_CLOCK_TIME_NONE, the clock will return the last reported time. * * Returns: a new #GstAudioClock casted to a #GstClock. */ GstClock * gst_audio_clock_new (gchar * name, GstAudioClockGetTimeFunc func, gpointer user_data) { GstAudioClock *aclock = GST_AUDIO_CLOCK (g_object_new (GST_TYPE_AUDIO_CLOCK, "name", name, NULL)); aclock->func = func; aclock->user_data = user_data; return (GstClock *) aclock; }
static GstClockTime gst_audio_clock_get_internal_time (GstClock * clock) { GstAudioClock *aclock; GstClockTime result; aclock = GST_AUDIO_CLOCK (clock); result = aclock->func (clock, aclock->user_data); if (result == GST_CLOCK_TIME_NONE) result = aclock->last_time; else { result += aclock->abidata.ABI.time_offset; aclock->last_time = result; } return result; }
static GstStateChangeReturn alsaspdifsink_change_state (GstElement * element, GstStateChange transition) { AlsaSPDIFSink *sink = ALSASPDIFSINK (element); GstStateChangeReturn ret; switch (transition) { case GST_STATE_CHANGE_NULL_TO_READY: sink->frames = 0; gst_audio_clock_reset (GST_AUDIO_CLOCK (sink->clock), 0); break; case GST_STATE_CHANGE_READY_TO_PAUSED: if (!alsaspdifsink_open (sink)) { GST_WARNING_OBJECT (sink, "Failed to open alsa device"); return GST_STATE_CHANGE_FAILURE; } break; case GST_STATE_CHANGE_PAUSED_TO_PLAYING: break; default: break; } ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); GST_INFO_OBJECT (sink, "Parent change_state returned %d", ret); switch (transition) { case GST_STATE_CHANGE_PLAYING_TO_PAUSED: break; case GST_STATE_CHANGE_PAUSED_TO_READY: break; case GST_STATE_CHANGE_READY_TO_NULL: alsaspdifsink_close (sink); break; default: break; } return ret; }
static GstStateChangeReturn gst_base_audio_src_change_state (GstElement * element, GstStateChange transition) { GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; GstBaseAudioSrc *src = GST_BASE_AUDIO_SRC (element); switch (transition) { case GST_STATE_CHANGE_NULL_TO_READY: GST_DEBUG_OBJECT (src, "NULL->READY"); GST_OBJECT_LOCK (src); if (src->ringbuffer == NULL) { gst_audio_clock_reset (GST_AUDIO_CLOCK (src->clock), 0); src->ringbuffer = gst_base_audio_src_create_ringbuffer (src); } GST_OBJECT_UNLOCK (src); if (!gst_ring_buffer_open_device (src->ringbuffer)) goto open_failed; break; case GST_STATE_CHANGE_READY_TO_PAUSED: GST_DEBUG_OBJECT (src, "READY->PAUSED"); src->next_sample = -1; gst_ring_buffer_set_flushing (src->ringbuffer, FALSE); gst_ring_buffer_may_start (src->ringbuffer, FALSE); break; case GST_STATE_CHANGE_PAUSED_TO_PLAYING: GST_DEBUG_OBJECT (src, "PAUSED->PLAYING"); gst_ring_buffer_may_start (src->ringbuffer, TRUE); break; case GST_STATE_CHANGE_PLAYING_TO_PAUSED: GST_DEBUG_OBJECT (src, "PLAYING->PAUSED"); gst_ring_buffer_may_start (src->ringbuffer, FALSE); gst_ring_buffer_pause (src->ringbuffer); break; case GST_STATE_CHANGE_PAUSED_TO_READY: GST_DEBUG_OBJECT (src, "PAUSED->READY"); gst_ring_buffer_set_flushing (src->ringbuffer, TRUE); break; default: break; } ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); switch (transition) { case GST_STATE_CHANGE_PAUSED_TO_READY: GST_DEBUG_OBJECT (src, "PAUSED->READY"); gst_ring_buffer_release (src->ringbuffer); break; case GST_STATE_CHANGE_READY_TO_NULL: GST_DEBUG_OBJECT (src, "READY->NULL"); gst_ring_buffer_close_device (src->ringbuffer); GST_OBJECT_LOCK (src); gst_object_unparent (GST_OBJECT_CAST (src->ringbuffer)); src->ringbuffer = NULL; GST_OBJECT_UNLOCK (src); break; default: break; } return ret; /* ERRORS */ open_failed: { /* subclass must post a meaningfull error message */ GST_DEBUG_OBJECT (src, "open failed"); return GST_STATE_CHANGE_FAILURE; } }
static gboolean gst_pulsesrc_prepare (GstAudioSrc * asrc, GstAudioRingBufferSpec * spec) { pa_buffer_attr wanted; const pa_buffer_attr *actual; GstPulseSrc *pulsesrc = GST_PULSESRC_CAST (asrc); pa_stream_flags_t flags; pa_operation *o; GstAudioClock *clock; pa_threaded_mainloop_lock (pulsesrc->mainloop); { GstAudioRingBufferSpec s = *spec; const pa_channel_map *m; m = pa_stream_get_channel_map (pulsesrc->stream); gst_pulse_channel_map_to_gst (m, &s); gst_audio_ring_buffer_set_channel_positions (GST_AUDIO_BASE_SRC (pulsesrc)->ringbuffer, s.info.position); } /* enable event notifications */ GST_LOG_OBJECT (pulsesrc, "subscribing to context events"); if (!(o = pa_context_subscribe (pulsesrc->context, PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT, NULL, NULL))) { GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED, ("pa_context_subscribe() failed: %s", pa_strerror (pa_context_errno (pulsesrc->context))), (NULL)); goto unlock_and_fail; } pa_operation_unref (o); wanted.maxlength = -1; wanted.tlength = -1; wanted.prebuf = 0; wanted.minreq = -1; wanted.fragsize = spec->segsize; GST_INFO_OBJECT (pulsesrc, "maxlength: %d", wanted.maxlength); GST_INFO_OBJECT (pulsesrc, "tlength: %d", wanted.tlength); GST_INFO_OBJECT (pulsesrc, "prebuf: %d", wanted.prebuf); GST_INFO_OBJECT (pulsesrc, "minreq: %d", wanted.minreq); GST_INFO_OBJECT (pulsesrc, "fragsize: %d", wanted.fragsize); flags = PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_AUTO_TIMING_UPDATE | PA_STREAM_NOT_MONOTONIC | PA_STREAM_ADJUST_LATENCY | PA_STREAM_START_CORKED; if (pulsesrc->mute_set && pulsesrc->mute) flags |= PA_STREAM_START_MUTED; if (pa_stream_connect_record (pulsesrc->stream, pulsesrc->device, &wanted, flags) < 0) { goto connect_failed; } /* our clock will now start from 0 again */ clock = GST_AUDIO_CLOCK (GST_AUDIO_BASE_SRC (pulsesrc)->clock); gst_audio_clock_reset (clock, 0); pulsesrc->corked = TRUE; for (;;) { pa_stream_state_t state; state = pa_stream_get_state (pulsesrc->stream); if (!PA_STREAM_IS_GOOD (state)) goto stream_is_bad; if (state == PA_STREAM_READY) break; /* Wait until the stream is ready */ pa_threaded_mainloop_wait (pulsesrc->mainloop); } pulsesrc->stream_connected = TRUE; /* store the source output index so it can be accessed via a property */ pulsesrc->source_output_idx = pa_stream_get_index (pulsesrc->stream); g_object_notify (G_OBJECT (pulsesrc), "source-output-index"); if (pulsesrc->volume_set) { gst_pulsesrc_set_stream_volume (pulsesrc, pulsesrc->volume); pulsesrc->volume_set = FALSE; } /* get the actual buffering properties now */ actual = pa_stream_get_buffer_attr (pulsesrc->stream); GST_INFO_OBJECT (pulsesrc, "maxlength: %d", actual->maxlength); GST_INFO_OBJECT (pulsesrc, "tlength: %d (wanted: %d)", actual->tlength, wanted.tlength); GST_INFO_OBJECT (pulsesrc, "prebuf: %d", actual->prebuf); GST_INFO_OBJECT (pulsesrc, "minreq: %d (wanted %d)", actual->minreq, wanted.minreq); GST_INFO_OBJECT (pulsesrc, "fragsize: %d (wanted %d)", actual->fragsize, wanted.fragsize); if (actual->fragsize >= wanted.fragsize) { spec->segsize = actual->fragsize; } else { spec->segsize = actual->fragsize * (wanted.fragsize / actual->fragsize); } spec->segtotal = actual->maxlength / spec->segsize; if (!pulsesrc->paused) { GST_DEBUG_OBJECT (pulsesrc, "uncorking because we are playing"); gst_pulsesrc_set_corked (pulsesrc, FALSE, FALSE); } pa_threaded_mainloop_unlock (pulsesrc->mainloop); return TRUE; /* ERRORS */ connect_failed: { GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED, ("Failed to connect stream: %s", pa_strerror (pa_context_errno (pulsesrc->context))), (NULL)); goto unlock_and_fail; } stream_is_bad: { GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED, ("Failed to connect stream: %s", pa_strerror (pa_context_errno (pulsesrc->context))), (NULL)); goto unlock_and_fail; } unlock_and_fail: { gst_pulsesrc_destroy_stream (pulsesrc); pa_threaded_mainloop_unlock (pulsesrc->mainloop); return FALSE; } }
static GstStateChangeReturn gst_base_audio_src_change_state (GstElement * element, GstStateChange transition) { GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; GstBaseAudioSrc *src = GST_BASE_AUDIO_SRC (element); switch (transition) { case GST_STATE_CHANGE_NULL_TO_READY: GST_DEBUG_OBJECT (src, "NULL->READY"); GST_OBJECT_LOCK (src); if (src->ringbuffer == NULL) { gst_audio_clock_reset (GST_AUDIO_CLOCK (src->clock), 0); src->ringbuffer = gst_base_audio_src_create_ringbuffer (src); } GST_OBJECT_UNLOCK (src); if (!gst_ring_buffer_open_device (src->ringbuffer)) goto open_failed; break; case GST_STATE_CHANGE_READY_TO_PAUSED: GST_DEBUG_OBJECT (src, "READY->PAUSED"); src->next_sample = -1; gst_ring_buffer_set_flushing (src->ringbuffer, FALSE); gst_ring_buffer_may_start (src->ringbuffer, FALSE); /* Only post clock-provide messages if this is the clock that * we've created. If the subclass has overriden it the subclass * should post this messages whenever necessary */ if (src->clock && GST_IS_AUDIO_CLOCK (src->clock) && GST_AUDIO_CLOCK_CAST (src->clock)->func == (GstAudioClockGetTimeFunc) gst_base_audio_src_get_time) gst_element_post_message (element, gst_message_new_clock_provide (GST_OBJECT_CAST (element), src->clock, TRUE)); break; case GST_STATE_CHANGE_PAUSED_TO_PLAYING: GST_DEBUG_OBJECT (src, "PAUSED->PLAYING"); gst_ring_buffer_may_start (src->ringbuffer, TRUE); break; case GST_STATE_CHANGE_PLAYING_TO_PAUSED: GST_DEBUG_OBJECT (src, "PLAYING->PAUSED"); gst_ring_buffer_may_start (src->ringbuffer, FALSE); gst_ring_buffer_pause (src->ringbuffer); break; case GST_STATE_CHANGE_PAUSED_TO_READY: GST_DEBUG_OBJECT (src, "PAUSED->READY"); /* Only post clock-lost messages if this is the clock that * we've created. If the subclass has overriden it the subclass * should post this messages whenever necessary */ if (src->clock && GST_IS_AUDIO_CLOCK (src->clock) && GST_AUDIO_CLOCK_CAST (src->clock)->func == (GstAudioClockGetTimeFunc) gst_base_audio_src_get_time) gst_element_post_message (element, gst_message_new_clock_lost (GST_OBJECT_CAST (element), src->clock)); gst_ring_buffer_set_flushing (src->ringbuffer, TRUE); break; default: break; } ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); switch (transition) { case GST_STATE_CHANGE_PAUSED_TO_READY: GST_DEBUG_OBJECT (src, "PAUSED->READY"); gst_ring_buffer_release (src->ringbuffer); break; case GST_STATE_CHANGE_READY_TO_NULL: GST_DEBUG_OBJECT (src, "READY->NULL"); gst_ring_buffer_close_device (src->ringbuffer); GST_OBJECT_LOCK (src); gst_object_unparent (GST_OBJECT_CAST (src->ringbuffer)); src->ringbuffer = NULL; GST_OBJECT_UNLOCK (src); break; default: break; } return ret; /* ERRORS */ open_failed: { /* subclass must post a meaningfull error message */ GST_DEBUG_OBJECT (src, "open failed"); return GST_STATE_CHANGE_FAILURE; } }