Commit 0dc1b604 authored by Philippe Renon's avatar Philippe Renon Committed by Robert Rosengren

audiosink: expose more audioringbuffer vmethods to child sinks

The newly exposed vmethods are pause, resume, stop and clear_all.
The existing reset vmethod is deprecated.

The audio sink will fallback to calling reset if pause or stop
are not provided and will fallback to calling start if
resume is not provided. There is no default clear_all
implementation.
Existing audio sinks continue to work as before.

This change is useful for sinks that need to distinguish
between a pause and a stop (currently both are handled
by a reset) and is needed for https://bugzilla.gnome.org/show_bug.cgi?id=788362

https://bugzilla.gnome.org/show_bug.cgi?id=788361
parent f1d3307e
......@@ -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.
*/
......
......@@ -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.
*/
......
......@@ -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
{
......
......@@ -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
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment