diff --git a/gst-libs/gst/audio/gstaudioringbuffer.c b/gst-libs/gst/audio/gstaudioringbuffer.c index 2e9af680a0..203472347f 100644 --- a/gst-libs/gst/audio/gstaudioringbuffer.c +++ b/gst-libs/gst/audio/gstaudioringbuffer.c @@ -1291,6 +1291,12 @@ gst_audio_ring_buffer_set_sample (GstAudioRingBuffer * buf, guint64 sample) sample, buf->segbase); } +/** + * default_clear_all: + * @buf: the #GstAudioRingBuffer to clear + * + * Fill the ringbuffer with silence. + */ static void default_clear_all (GstAudioRingBuffer * buf) { @@ -1311,7 +1317,7 @@ default_clear_all (GstAudioRingBuffer * buf) * gst_audio_ring_buffer_clear_all: * @buf: the #GstAudioRingBuffer to clear * - * Fill the ringbuffer with silence. + * Clear all samples from the ringbuffer. * * MT safe. */ diff --git a/gst-libs/gst/audio/gstaudioringbuffer.h b/gst-libs/gst/audio/gstaudioringbuffer.h index 9dee681b8f..615041f71d 100644 --- a/gst-libs/gst/audio/gstaudioringbuffer.h +++ b/gst-libs/gst/audio/gstaudioringbuffer.h @@ -234,7 +234,10 @@ struct _GstAudioRingBuffer { * @activate: activate the thread that starts pulling and monitoring the * consumed segments in the device. * @commit: write samples into the ringbuffer - * @clear_all: clear the entire ringbuffer. + * @clear_all: Optional. + * Clear the entire ringbuffer. + * Subclasses should chain up to the parent implementation to + * invoke the default handler. * * The vmethods that subclasses can override to implement the ringbuffer. */ diff --git a/gst-libs/gst/audio/gstaudiosink.c b/gst-libs/gst/audio/gstaudiosink.c index 3892432bfd..5eb6039baf 100644 --- a/gst-libs/gst/audio/gstaudiosink.c +++ b/gst-libs/gst/audio/gstaudiosink.c @@ -117,10 +117,12 @@ static gboolean gst_audio_sink_ring_buffer_acquire (GstAudioRingBuffer * buf, static gboolean gst_audio_sink_ring_buffer_release (GstAudioRingBuffer * buf); static gboolean gst_audio_sink_ring_buffer_start (GstAudioRingBuffer * buf); static gboolean gst_audio_sink_ring_buffer_pause (GstAudioRingBuffer * buf); +static gboolean gst_audio_sink_ring_buffer_resume (GstAudioRingBuffer * buf); static gboolean gst_audio_sink_ring_buffer_stop (GstAudioRingBuffer * buf); static guint gst_audio_sink_ring_buffer_delay (GstAudioRingBuffer * buf); static gboolean gst_audio_sink_ring_buffer_activate (GstAudioRingBuffer * buf, gboolean active); +static void gst_audio_sink_ring_buffer_clear_all (GstAudioRingBuffer * buf); /* ringbuffer abstract base class */ static GType @@ -176,14 +178,15 @@ gst_audio_sink_ring_buffer_class_init (GstAudioSinkRingBufferClass * klass) gstringbuffer_class->pause = GST_DEBUG_FUNCPTR (gst_audio_sink_ring_buffer_pause); gstringbuffer_class->resume = - GST_DEBUG_FUNCPTR (gst_audio_sink_ring_buffer_start); + GST_DEBUG_FUNCPTR (gst_audio_sink_ring_buffer_resume); gstringbuffer_class->stop = GST_DEBUG_FUNCPTR (gst_audio_sink_ring_buffer_stop); - gstringbuffer_class->delay = GST_DEBUG_FUNCPTR (gst_audio_sink_ring_buffer_delay); gstringbuffer_class->activate = GST_DEBUG_FUNCPTR (gst_audio_sink_ring_buffer_activate); + gstringbuffer_class->clear_all = + GST_DEBUG_FUNCPTR (gst_audio_sink_ring_buffer_clear_all); } typedef gint (*WriteFunc) (GstAudioSink * sink, gpointer data, guint length); @@ -531,12 +534,36 @@ gst_audio_sink_ring_buffer_pause (GstAudioRingBuffer * buf) csink = GST_AUDIO_SINK_GET_CLASS (sink); /* unblock any pending writes to the audio device */ - if (csink->reset) { + if (csink->pause) { + GST_DEBUG_OBJECT (sink, "pause..."); + csink->pause (sink); + GST_DEBUG_OBJECT (sink, "pause done"); + } else if (csink->reset) { + /* fallback to reset for audio sinks that don't provide pause */ GST_DEBUG_OBJECT (sink, "reset..."); csink->reset (sink); GST_DEBUG_OBJECT (sink, "reset done"); } + return TRUE; +} +static gboolean +gst_audio_sink_ring_buffer_resume (GstAudioRingBuffer * buf) +{ + GstAudioSink *sink; + GstAudioSinkClass *csink; + + sink = GST_AUDIO_SINK (GST_OBJECT_PARENT (buf)); + csink = GST_AUDIO_SINK_GET_CLASS (sink); + + if (csink->resume) { + GST_DEBUG_OBJECT (sink, "resume..."); + csink->resume (sink); + GST_DEBUG_OBJECT (sink, "resume done"); + } else { + /* fallback to start for audio sinks that don't provide resume */ + gst_audio_sink_ring_buffer_start (buf); + } return TRUE; } @@ -550,7 +577,12 @@ gst_audio_sink_ring_buffer_stop (GstAudioRingBuffer * buf) csink = GST_AUDIO_SINK_GET_CLASS (sink); /* unblock any pending writes to the audio device */ - if (csink->reset) { + if (csink->stop) { + GST_DEBUG_OBJECT (sink, "stop..."); + csink->stop (sink); + GST_DEBUG_OBJECT (sink, "stop done"); + } else if (csink->reset) { + /* fallback to reset for audio sinks that don't provide stop */ GST_DEBUG_OBJECT (sink, "reset..."); csink->reset (sink); GST_DEBUG_OBJECT (sink, "reset done"); @@ -582,6 +614,24 @@ gst_audio_sink_ring_buffer_delay (GstAudioRingBuffer * buf) return res; } +static void +gst_audio_sink_ring_buffer_clear_all (GstAudioRingBuffer * buf) +{ + GstAudioSink *sink; + GstAudioSinkClass *csink; + + sink = GST_AUDIO_SINK (GST_OBJECT_PARENT (buf)); + csink = GST_AUDIO_SINK_GET_CLASS (sink); + + if (csink->clear_all) { + GST_DEBUG_OBJECT (sink, "clear all"); + csink->clear_all (sink); + } + + /* chain up to the parent implementation */ + ring_parent_class->clear_all (buf); +} + /* AudioSink signals and args */ enum { diff --git a/gst-libs/gst/audio/gstaudiosink.h b/gst-libs/gst/audio/gstaudiosink.h index f29df97d82..409cf6b017 100644 --- a/gst-libs/gst/audio/gstaudiosink.h +++ b/gst-libs/gst/audio/gstaudiosink.h @@ -66,12 +66,25 @@ struct _GstAudioSink { * @unprepare: Undo operations done in prepare. * @close: Close the device. * @write: Write data to the device. - * @delay: Return how many frames are still in the device. This is used to - * drive the synchronisation. + * This vmethod is allowed to block until all the data is written. + * If such is the case then it is expected that pause, stop and + * reset will unblock the write when called. + * @delay: Return how many frames are still in the device. Participates in + * computing the time for audio clocks and drives the synchronisation. * @reset: Returns as quickly as possible from a write and flush any pending * samples from the device. - * - * #GstAudioSink class. Override the vmethods to implement functionality. + * This vmethod is deprecated. Please provide pause and stop instead. + * @pause: Pause the device and unblock write as fast as possible. + * For retro compatibility, the audio sink will fallback + * to calling reset if this vmethod is not provided. + * @resume: Resume the device. + * For retro compatibility, the audio sink will fallback + * to calling start if this vmethod is not provided. + * @stop: Stop the device and unblock write as fast as possible. + * Pending samples are flushed from the device. + * For retro compatibility, the audio sink will fallback + * to calling reset if this vmethod is not provided. + * @clear-all: Clear the device. */ struct _GstAudioSinkClass { GstAudioBaseSinkClass parent_class; @@ -90,11 +103,19 @@ struct _GstAudioSinkClass { gint (*write) (GstAudioSink *sink, gpointer data, guint length); /* get number of frames queued in the device */ guint (*delay) (GstAudioSink *sink); - /* reset the audio device, unblock from a write */ + /* deprecated: reset the audio device, unblock from a write */ void (*reset) (GstAudioSink *sink); + /* pause the audio device, unblock from a write */ + void (*pause) (GstAudioSink *sink); + /* resume the audio device */ + void (*resume) (GstAudioSink *sink); + /* stop the audio device, unblock from a write */ + void (*stop) (GstAudioSink *sink); + /* clear the audio device */ + void (*clear_all) (GstAudioSink *sink); /*< private >*/ - gpointer _gst_reserved[GST_PADDING]; + gpointer _gst_reserved[GST_PADDING - 4]; }; GST_AUDIO_API