diff --git a/ext/pulse/pulsesink.c b/ext/pulse/pulsesink.c index 6fcd33787c..7e4f0014f4 100644 --- a/ext/pulse/pulsesink.c +++ b/ext/pulse/pulsesink.c @@ -97,6 +97,7 @@ struct _GstPulseRingBuffer pa_stream *stream; pa_sample_spec sample_spec; + gint64 offset; gboolean corked; gboolean in_commit; @@ -218,7 +219,6 @@ gst_pulsering_destroy_stream (GstPulseRingBuffer * pbuf) /* Make sure we don't get any further callbacks */ pa_stream_set_state_callback (pbuf->stream, NULL, NULL); pa_stream_set_write_callback (pbuf->stream, NULL, NULL); - pa_stream_set_latency_update_callback (pbuf->stream, NULL, NULL); pa_stream_unref (pbuf->stream); pbuf->stream = NULL; @@ -486,20 +486,6 @@ gst_pulsering_stream_request_cb (pa_stream * s, size_t length, void *userdata) } } -static void -gst_pulsering_stream_latency_update_cb (pa_stream * s, void *userdata) -{ - GstPulseSink *psink; - GstPulseRingBuffer *pbuf; - - pbuf = GST_PULSERING_BUFFER_CAST (userdata); - psink = GST_PULSESINK_CAST (GST_OBJECT_PARENT (pbuf)); - - GST_LOG_OBJECT (psink, "got latency update callback"); - - pa_threaded_mainloop_signal (psink->mainloop, 0); -} - /* This method should create a new stream of the given @spec. No playback should * start yet so we start in the corked state. */ static gboolean @@ -514,6 +500,8 @@ gst_pulseringbuffer_acquire (GstRingBuffer * buf, GstRingBufferSpec * spec) pa_cvolume v, *pv; pa_stream_flags_t flags; const gchar *name; + GstAudioClock *clock; + gint64 time_offset; psink = GST_PULSESINK_CAST (GST_OBJECT_PARENT (buf)); pbuf = GST_PULSERING_BUFFER_CAST (buf); @@ -557,8 +545,6 @@ gst_pulseringbuffer_acquire (GstRingBuffer * buf, GstRingBufferSpec * spec) gst_pulsering_stream_state_cb, pbuf); pa_stream_set_write_callback (pbuf->stream, gst_pulsering_stream_request_cb, pbuf); - pa_stream_set_latency_update_callback (pbuf->stream, - gst_pulsering_stream_latency_update_cb, pbuf); /* buffering requirements */ memset (&buf_attr, 0, sizeof (buf_attr)); @@ -584,8 +570,7 @@ gst_pulseringbuffer_acquire (GstRingBuffer * buf, GstRingBufferSpec * spec) } /* construct the flags */ - flags = PA_STREAM_INTERPOLATE_TIMING | - PA_STREAM_AUTO_TIMING_UPDATE | PA_STREAM_NOT_MONOTONOUS | + flags = PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_AUTO_TIMING_UPDATE | #if HAVE_PULSE_0_9_11 PA_STREAM_ADJUST_LATENCY | #endif @@ -618,6 +603,24 @@ gst_pulseringbuffer_acquire (GstRingBuffer * buf, GstRingBufferSpec * spec) pa_threaded_mainloop_wait (psink->mainloop); } + /* our clock will now start from 0 again */ + clock = GST_AUDIO_CLOCK (GST_BASE_AUDIO_SINK (psink)->provided_clock); + gst_audio_clock_reset (clock, 0); + time_offset = clock->abidata.ABI.time_offset; + + GST_LOG_OBJECT (psink, "got time offset %" GST_TIME_FORMAT, + GST_TIME_ARGS (time_offset)); + + /* calculate the sample offset for 0 */ + if (time_offset > 0) + pbuf->offset = gst_util_uint64_scale_int (time_offset, + pbuf->sample_spec.rate, GST_SECOND); + else + pbuf->offset = -gst_util_uint64_scale_int (-time_offset, + pbuf->sample_spec.rate, GST_SECOND); + GST_LOG_OBJECT (psink, "sample offset %" G_GINT64_FORMAT, pbuf->offset); + + GST_LOG_OBJECT (psink, "stream is acquired now"); /* get the actual buffering properties now */ @@ -701,6 +704,18 @@ gst_pulseringbuffer_activate (GstRingBuffer * buf, gboolean active) return TRUE; } +static void +gst_pulsering_success_cb (pa_stream * s, int success, void *userdata) +{ + GstPulseRingBuffer *pbuf; + GstPulseSink *psink; + + pbuf = GST_PULSERING_BUFFER_CAST (userdata); + psink = GST_PULSESINK_CAST (GST_OBJECT_PARENT (pbuf)); + + pa_threaded_mainloop_signal (psink->mainloop, 0); +} + /* update the corked state of a stream, must be called with the mainloop * lock */ static gboolean @@ -714,7 +729,8 @@ gst_pulsering_set_corked (GstPulseRingBuffer * pbuf, gboolean corked) GST_DEBUG_OBJECT (psink, "setting corked state to %d", corked); if (pbuf->corked != corked) { - if (!(o = pa_stream_cork (pbuf->stream, corked, NULL, NULL))) + if (!(o = pa_stream_cork (pbuf->stream, corked, + gst_pulsering_success_cb, pbuf))) goto cork_failed; while (pa_operation_get_state (o) == PA_OPERATION_RUNNING) { @@ -793,18 +809,6 @@ gst_pulseringbuffer_pause (GstRingBuffer * buf) return res; } -static void -gst_pulsering_success_cb (pa_stream * s, int success, void *userdata) -{ - GstPulseRingBuffer *pbuf; - GstPulseSink *psink; - - pbuf = GST_PULSERING_BUFFER_CAST (userdata); - psink = GST_PULSESINK_CAST (GST_OBJECT_PARENT (pbuf)); - - pa_threaded_mainloop_signal (psink->mainloop, 0); -} - /* stop playback, we flush everything. */ static gboolean gst_pulseringbuffer_stop (GstRingBuffer * buf) @@ -1016,12 +1020,25 @@ gst_pulseringbuffer_commit (GstRingBuffer * buf, guint64 * sample, if (avail > out_samples) avail = out_samples; - GST_LOG_OBJECT (psink, "writing %d samples at offset %" G_GUINT64_FORMAT, - avail, *sample); - - offset = *sample * bps; + /* correct for sample offset against the internal clock */ + offset = *sample; + if (pbuf->offset >= 0) { + if (offset > pbuf->offset) + offset -= pbuf->offset; + else + offset = 0; + } else { + if (offset > -pbuf->offset) + offset += pbuf->offset; + else + offset = 0; + } + offset *= bps; towrite = avail * bps; + GST_LOG_OBJECT (psink, "writing %d samples at offset %" G_GUINT64_FORMAT, + avail, offset); + if (G_LIKELY (inr == outr && !reverse)) { /* no rate conversion, simply write out the samples */ if (pa_stream_write (pbuf->stream, data, towrite, NULL, offset, @@ -1290,12 +1307,15 @@ gst_pulse_sink_get_time (GstClock * clock, GstBaseAudioSink * sink) psink = GST_PULSESINK_CAST (GST_OBJECT_PARENT (pbuf)); pa_threaded_mainloop_lock (psink->mainloop); - /* if we don't have enough data to get a timestamp, just return 0 */ - if (pa_stream_get_time (pbuf->stream, &time) < 0) - time = 0; - pa_threaded_mainloop_unlock (psink->mainloop); - time *= 1000; + /* if we don't have enough data to get a timestamp, just return NONE, which + * will return the last reported time */ + if (pa_stream_get_time (pbuf->stream, &time) < 0) { + GST_DEBUG_OBJECT (psink, "could not get time"); + time = GST_CLOCK_TIME_NONE; + } else + time *= 1000; + pa_threaded_mainloop_unlock (psink->mainloop); GST_LOG_OBJECT (psink, "current time is %" GST_TIME_FORMAT, GST_TIME_ARGS (time)); @@ -1318,6 +1338,8 @@ gst_pulsesink_init (GstPulseSink * pulsesink, GstPulseSinkClass * klass) g_assert ((pulsesink->mainloop = pa_threaded_mainloop_new ())); g_assert (pa_threaded_mainloop_start (pulsesink->mainloop) == 0); +// GST_BASE_SINK (pulsesink)->can_activate_pull = TRUE; + pulsesink->probe = gst_pulseprobe_new (G_OBJECT (pulsesink), G_OBJECT_GET_CLASS (pulsesink), PROP_DEVICE, pulsesink->device, TRUE, FALSE); /* TRUE for sinks, FALSE for sources */ /* override with a custom clock */