gst-libs/gst/audio/gstbaseaudiosink.c

Original commit message from CVS:
2005-08-08  Andy Wingo  <wingo@pobox.com>

* gst-libs/gst/audio/gstbaseaudiosink.c
(gst_base_audio_sink_change_state): Open the device in NULL->READY
like good elements should. Close on READY->NULL too.

* gst-libs/gst/audio/gstaudiosink.c
(gst_audioringbuffer_open_device,
(gst_audioringbuffer_close_device, gst_audioringbuffer_acquire)
(gst_audioringbuffer_release): Updates for new ring buffer API,
hook into the new audio sink api.

* gst-libs/gst/audio/gstaudiosink.h (GstAudioSinkClass.open)
(GstAudioSinkClass.close): Just open and close the device -- no
resource allocation or configuration.
(GstAudioSinkClass.prepare, GstAudioSinkClass.unprepare): New
vmethods, handle device setup and resource allocation.

* ext/alsa/gstalsasink.c (gst_alsasink_open, gst_alsasink_close)
(gst_alsasink_prepare, gst_alsasink_unprepare): Update for new
base class API.

* gst-libs/gst/audio/gstringbuffer.h
(GstRingBufferClass.open_device, GstRingBufferClass.close_device):
New vmethods.

* gst-libs/gst/audio/gstringbuffer.c (gst_ring_buffer_open_device)
(gst_ring_buffer_close_device, gst_ring_buffer_device_is_open):
New API functions. The device should be opened before acquiring
and closed after releasing.
This commit is contained in:
Andy Wingo 2005-08-08 16:42:10 +00:00
parent 074b6a3b64
commit 69d36f02ce
7 changed files with 312 additions and 26 deletions

View file

@ -1,3 +1,34 @@
2005-08-08 Andy Wingo <wingo@pobox.com>
* gst-libs/gst/audio/gstbaseaudiosink.c
(gst_base_audio_sink_change_state): Open the device in NULL->READY
like good elements should. Close on READY->NULL too.
* gst-libs/gst/audio/gstaudiosink.c
(gst_audioringbuffer_open_device,
(gst_audioringbuffer_close_device, gst_audioringbuffer_acquire)
(gst_audioringbuffer_release): Updates for new ring buffer API,
hook into the new audio sink api.
* gst-libs/gst/audio/gstaudiosink.h (GstAudioSinkClass.open)
(GstAudioSinkClass.close): Just open and close the device -- no
resource allocation or configuration.
(GstAudioSinkClass.prepare, GstAudioSinkClass.unprepare): New
vmethods, handle device setup and resource allocation.
* ext/alsa/gstalsasink.c (gst_alsasink_open, gst_alsasink_close)
(gst_alsasink_prepare, gst_alsasink_unprepare): Update for new
base class API.
* gst-libs/gst/audio/gstringbuffer.h
(GstRingBufferClass.open_device, GstRingBufferClass.close_device):
New vmethods.
* gst-libs/gst/audio/gstringbuffer.c (gst_ring_buffer_open_device)
(gst_ring_buffer_close_device, gst_ring_buffer_device_is_open):
New API functions. The device should be opened before acquiring
and closed after releasing.
2005-08-08 Tim-Philipp Müller <tim at centricular dot net>
* gst-libs/gst/interfaces/mixer.h:

View file

@ -57,8 +57,10 @@ static void gst_alsasink_get_property (GObject * object,
static GstCaps *gst_alsasink_getcaps (GstBaseSink * bsink);
static gboolean gst_alsasink_open (GstAudioSink * asink,
static gboolean gst_alsasink_open (GstAudioSink * asink);
static gboolean gst_alsasink_prepare (GstAudioSink * asink,
GstRingBufferSpec * spec);
static gboolean gst_alsasink_unprepare (GstAudioSink * asink);
static gboolean gst_alsasink_close (GstAudioSink * asink);
static guint gst_alsasink_write (GstAudioSink * asink, gpointer data,
guint length);
@ -163,6 +165,8 @@ gst_alsasink_class_init (GstAlsaSinkClass * klass)
gstbasesink_class->get_caps = GST_DEBUG_FUNCPTR (gst_alsasink_getcaps);
gstaudiosink_class->open = GST_DEBUG_FUNCPTR (gst_alsasink_open);
gstaudiosink_class->prepare = GST_DEBUG_FUNCPTR (gst_alsasink_prepare);
gstaudiosink_class->unprepare = GST_DEBUG_FUNCPTR (gst_alsasink_unprepare);
gstaudiosink_class->close = GST_DEBUG_FUNCPTR (gst_alsasink_close);
gstaudiosink_class->write = GST_DEBUG_FUNCPTR (gst_alsasink_write);
gstaudiosink_class->delay = GST_DEBUG_FUNCPTR (gst_alsasink_delay);
@ -480,7 +484,29 @@ error:
}
static gboolean
gst_alsasink_open (GstAudioSink * asink, GstRingBufferSpec * spec)
gst_alsasink_open (GstAudioSink * asink)
{
GstAlsaSink *alsa;
gint err;
alsa = GST_ALSA_SINK (asink);
CHECK (snd_pcm_open (&alsa->handle, alsa->device, SND_PCM_STREAM_PLAYBACK,
SND_PCM_NONBLOCK), open_error);
return TRUE;
/* ERRORS */
open_error:
{
GST_ELEMENT_ERROR (alsa, RESOURCE, OPEN_READ,
("Playback open error: %s", snd_strerror (err)), (NULL));
return FALSE;
}
}
static gboolean
gst_alsasink_prepare (GstAudioSink * asink, GstRingBufferSpec * spec)
{
GstAlsaSink *alsa;
gint err;
@ -490,9 +516,6 @@ gst_alsasink_open (GstAudioSink * asink, GstRingBufferSpec * spec)
if (!alsasink_parse_spec (alsa, spec))
goto spec_parse;
CHECK (snd_pcm_open (&alsa->handle, alsa->device, SND_PCM_STREAM_PLAYBACK,
SND_PCM_NONBLOCK), open_error);
CHECK (snd_pcm_nonblock (alsa->handle, 0), non_block);
CHECK (set_hwparams (alsa), hw_params_failed);
@ -515,12 +538,6 @@ spec_parse:
("Error parsing spec"), (NULL));
return FALSE;
}
open_error:
{
GST_ELEMENT_ERROR (alsa, RESOURCE, OPEN_READ,
("Playback open error: %s", snd_strerror (err)), (NULL));
return FALSE;
}
non_block:
{
GST_ELEMENT_ERROR (alsa, RESOURCE, OPEN_READ,
@ -542,12 +559,48 @@ sw_params_failed:
}
static gboolean
gst_alsasink_close (GstAudioSink * asink)
gst_alsasink_unprepare (GstAudioSink * asink)
{
GstAlsaSink *alsa;
gint err;
alsa = GST_ALSA_SINK (asink);
CHECK (snd_pcm_drop (alsa->handle), drop);
CHECK (snd_pcm_hw_free (alsa->handle), hw_free);
CHECK (snd_pcm_nonblock (alsa->handle, 1), non_block);
return TRUE;
/* ERRORS */
drop:
{
GST_ELEMENT_ERROR (alsa, RESOURCE, OPEN_READ,
("Could not drop samples: %s", snd_strerror (err)), (NULL));
return FALSE;
}
hw_free:
{
GST_ELEMENT_ERROR (alsa, RESOURCE, OPEN_READ,
("Could not free hw params: %s", snd_strerror (err)), (NULL));
return FALSE;
}
non_block:
{
GST_ELEMENT_ERROR (alsa, RESOURCE, OPEN_READ,
("Could not set device to nonblocking: %s", snd_strerror (err)),
(NULL));
return FALSE;
}
}
static gboolean
gst_alsasink_close (GstAudioSink * asink)
{
GstAlsaSink *alsa = GST_ALSA_SINK (asink);
snd_pcm_close (alsa->handle);
return TRUE;

View file

@ -70,6 +70,8 @@ static void gst_audioringbuffer_finalize (GObject * object);
static GstRingBufferClass *ring_parent_class = NULL;
static gboolean gst_audioringbuffer_open_device (GstRingBuffer * buf);
static gboolean gst_audioringbuffer_close_device (GstRingBuffer * buf);
static gboolean gst_audioringbuffer_acquire (GstRingBuffer * buf,
GstRingBufferSpec * spec);
static gboolean gst_audioringbuffer_release (GstRingBuffer * buf);
@ -120,6 +122,10 @@ gst_audioringbuffer_class_init (GstAudioRingBufferClass * klass)
gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_audioringbuffer_dispose);
gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_audioringbuffer_finalize);
gstringbuffer_class->open_device =
GST_DEBUG_FUNCPTR (gst_audioringbuffer_open_device);
gstringbuffer_class->close_device =
GST_DEBUG_FUNCPTR (gst_audioringbuffer_close_device);
gstringbuffer_class->acquire =
GST_DEBUG_FUNCPTR (gst_audioringbuffer_acquire);
gstringbuffer_class->release =
@ -235,6 +241,54 @@ gst_audioringbuffer_finalize (GObject * object)
G_OBJECT_CLASS (ring_parent_class)->finalize (object);
}
static gboolean
gst_audioringbuffer_open_device (GstRingBuffer * buf)
{
GstAudioSink *sink;
GstAudioSinkClass *csink;
gboolean result = TRUE;
sink = GST_AUDIO_SINK (GST_OBJECT_PARENT (buf));
csink = GST_AUDIO_SINK_GET_CLASS (sink);
if (csink->open)
result = csink->open (sink);
if (!result)
goto could_not_open;
return result;
could_not_open:
{
return FALSE;
}
}
static gboolean
gst_audioringbuffer_close_device (GstRingBuffer * buf)
{
GstAudioSink *sink;
GstAudioSinkClass *csink;
gboolean result = TRUE;
sink = GST_AUDIO_SINK (GST_OBJECT_PARENT (buf));
csink = GST_AUDIO_SINK_GET_CLASS (sink);
if (csink->close)
result = csink->close (sink);
if (!result)
goto could_not_open;
return result;
could_not_open:
{
return FALSE;
}
}
static gboolean
gst_audioringbuffer_acquire (GstRingBuffer * buf, GstRingBufferSpec * spec)
{
@ -246,8 +300,8 @@ gst_audioringbuffer_acquire (GstRingBuffer * buf, GstRingBufferSpec * spec)
sink = GST_AUDIO_SINK (GST_OBJECT_PARENT (buf));
csink = GST_AUDIO_SINK_GET_CLASS (sink);
if (csink->open)
result = csink->open (sink, spec);
if (csink->prepare)
result = csink->prepare (sink, spec);
if (!result)
goto could_not_open;
@ -300,8 +354,8 @@ gst_audioringbuffer_release (GstRingBuffer * buf)
gst_buffer_unref (buf->data);
buf->data = NULL;
if (csink->close)
result = csink->close (sink);
if (csink->unprepare)
result = csink->unprepare (sink);
return result;
}

View file

@ -67,15 +67,19 @@ struct _GstAudioSinkClass {
/* vtable */
/* open the device with given specs */
gboolean (*open) (GstAudioSink *sink, GstRingBufferSpec *spec);
gboolean (*open) (GstAudioSink *sink);
/* prepare resources and state to operate with the given specs */
gboolean (*prepare) (GstAudioSink *sink, GstRingBufferSpec *spec);
/* undo anything that was done in prepare() */
gboolean (*unprepare) (GstAudioSink *sink);
/* close the device */
gboolean (*close) (GstAudioSink *sink);
gboolean (*close) (GstAudioSink *sink);
/* write samples to the device */
guint (*write) (GstAudioSink *sink, gpointer data, guint length);
guint (*write) (GstAudioSink *sink, gpointer data, guint length);
/* get number of samples queued in the device */
guint (*delay) (GstAudioSink *sink);
guint (*delay) (GstAudioSink *sink);
/* reset the audio device, unblock from a write */
void (*reset) (GstAudioSink *sink);
void (*reset) (GstAudioSink *sink);
};
GType gst_audio_sink_get_type(void);

View file

@ -419,13 +419,15 @@ gst_base_audio_sink_change_state (GstElement * element)
switch (transition) {
case GST_STATE_NULL_TO_READY:
break;
case GST_STATE_READY_TO_PAUSED:
if (sink->ringbuffer == NULL) {
sink->ringbuffer = gst_base_audio_sink_create_ringbuffer (sink);
gst_ring_buffer_set_callback (sink->ringbuffer,
gst_base_audio_sink_callback, sink);
}
if (!gst_ring_buffer_open_device (sink->ringbuffer))
return GST_STATE_FAILURE;
break;
case GST_STATE_READY_TO_PAUSED:
break;
case GST_STATE_PAUSED_TO_PLAYING:
break;
@ -441,10 +443,11 @@ gst_base_audio_sink_change_state (GstElement * element)
break;
case GST_STATE_PAUSED_TO_READY:
gst_ring_buffer_stop (sink->ringbuffer);
gst_ring_buffer_release (sink->ringbuffer);
gst_pad_set_caps (GST_BASE_SINK_PAD (sink), NULL);
gst_ring_buffer_release (sink->ringbuffer);
break;
case GST_STATE_READY_TO_NULL:
gst_ring_buffer_close_device (sink->ringbuffer);
break;
default:
break;

View file

@ -80,6 +80,7 @@ gst_ring_buffer_class_init (GstRingBufferClass * klass)
static void
gst_ring_buffer_init (GstRingBuffer * ringbuffer)
{
ringbuffer->open = FALSE;
ringbuffer->acquired = FALSE;
ringbuffer->state = GST_RING_BUFFER_STATE_STOPPED;
ringbuffer->cond = g_cond_new ();
@ -327,6 +328,127 @@ gst_ring_buffer_set_callback (GstRingBuffer * buf, GstRingBufferCallback cb,
GST_UNLOCK (buf);
}
/**
* gst_ring_buffer_open_device:
* @buf: the #GstRingBuffer
*
* Open the audio device associated with the ring buffer. Does not perform any
* setup on the device. You must open the device before acquiring the ring
* buffer.
*
* Returns: TRUE if the device could be opened, FALSE on error.
*
* MT safe.
*/
gboolean
gst_ring_buffer_open_device (GstRingBuffer * buf)
{
gboolean res = TRUE;
GstRingBufferClass *rclass;
g_return_val_if_fail (GST_IS_RING_BUFFER (buf), FALSE);
GST_LOCK (buf);
if (buf->open) {
g_warning ("Device for ring buffer %p already open, fix your code", buf);
res = TRUE;
goto done;
}
buf->open = TRUE;
/* if this fails, something is wrong in this file */
g_assert (!buf->acquired);
rclass = GST_RING_BUFFER_GET_CLASS (buf);
if (rclass->open_device)
res = rclass->open_device (buf);
if (!res) {
buf->open = FALSE;
}
done:
GST_UNLOCK (buf);
return res;
}
/**
* gst_ring_buffer_close_device:
* @buf: the #GstRingBuffer
*
* Close the audio device associated with the ring buffer. The ring buffer
* should already have been released via gst_ring_buffer_release().
*
* Returns: TRUE if the device could be closed, FALSE on error.
*
* MT safe.
*/
gboolean
gst_ring_buffer_close_device (GstRingBuffer * buf)
{
gboolean res = TRUE;
GstRingBufferClass *rclass;
g_return_val_if_fail (GST_IS_RING_BUFFER (buf), FALSE);
GST_LOCK (buf);
if (!buf->open) {
g_warning ("Device for ring buffer %p already closed, fix your code", buf);
res = TRUE;
goto done;
}
if (buf->acquired) {
g_critical ("Resources for ring buffer %p still acquired", buf);
res = FALSE;
goto done;
}
buf->open = FALSE;
rclass = GST_RING_BUFFER_GET_CLASS (buf);
if (rclass->close_device)
res = rclass->close_device (buf);
if (!res) {
buf->open = TRUE;
}
done:
GST_UNLOCK (buf);
return res;
}
/**
* gst_ring_buffer_device_is_open:
* @buf: the #GstRingBuffer
*
* Checks the status of the device associated with the ring buffer.
*
* Returns: TRUE if the device was open, FALSE if it was closed.
*
* MT safe.
*/
gboolean
gst_ring_buffer_device_is_open (GstRingBuffer * buf)
{
gboolean res = TRUE;
g_return_val_if_fail (GST_IS_RING_BUFFER (buf), FALSE);
GST_LOCK (buf);
res = buf->open;
GST_UNLOCK (buf);
return res;
}
/**
* gst_ring_buffer_acquire:
* @buf: the #GstRingBuffer to acquire
@ -349,6 +471,11 @@ gst_ring_buffer_acquire (GstRingBuffer * buf, GstRingBufferSpec * spec)
g_return_val_if_fail (buf != NULL, FALSE);
GST_LOCK (buf);
if (!buf->open) {
g_critical ("Device for %p not opened", buf);
res = FALSE;
goto done;
}
if (buf->acquired) {
res = TRUE;
goto done;
@ -414,6 +541,9 @@ gst_ring_buffer_release (GstRingBuffer * buf)
}
buf->acquired = FALSE;
/* if this fails, something is wrong in this file */
g_assert (buf->open == TRUE);
rclass = GST_RING_BUFFER_GET_CLASS (buf);
if (rclass->release)
res = rclass->release (buf);

View file

@ -151,6 +151,7 @@ struct _GstRingBuffer {
/*< public >*/ /* with LOCK */
GCond *cond;
gboolean open;
gboolean acquired;
GstBuffer *data;
GstRingBufferSpec spec;
@ -174,10 +175,14 @@ struct _GstRingBufferClass {
GstObjectClass parent_class;
/*< public >*/
/* just open the device, don't set any params or allocate anything */
gboolean (*open_device) (GstRingBuffer *buf);
/* allocate the resources for the ringbuffer using the given specs */
gboolean (*acquire) (GstRingBuffer *buf, GstRingBufferSpec *spec);
/* free resources of the ringbuffer */
gboolean (*release) (GstRingBuffer *buf);
/* close the device */
gboolean (*close_device) (GstRingBuffer *buf);
/* playback control */
gboolean (*start) (GstRingBuffer *buf);
@ -199,9 +204,15 @@ gboolean gst_ring_buffer_parse_caps (GstRingBufferSpec *spec, GstCaps *caps);
void gst_ring_buffer_debug_spec_caps (GstRingBufferSpec *spec);
void gst_ring_buffer_debug_spec_buff (GstRingBufferSpec *spec);
/* device state */
gboolean gst_ring_buffer_open_device (GstRingBuffer *buf);
gboolean gst_ring_buffer_close_device (GstRingBuffer *buf);
gboolean gst_ring_buffer_device_is_open (GstRingBuffer *buf);
/* allocate resources */
gboolean gst_ring_buffer_acquire (GstRingBuffer *buf, GstRingBufferSpec *spec);
gboolean gst_ring_buffer_release (GstRingBuffer *buf);
gboolean gst_ring_buffer_acquire (GstRingBuffer *buf, GstRingBufferSpec *spec);
gboolean gst_ring_buffer_release (GstRingBuffer *buf);
gboolean gst_ring_buffer_is_acquired (GstRingBuffer *buf);