mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-24 01:00:37 +00:00
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:
parent
074b6a3b64
commit
69d36f02ce
7 changed files with 312 additions and 26 deletions
31
ChangeLog
31
ChangeLog
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -67,7 +67,11 @@ 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);
|
||||
/* write samples to the device */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,6 +204,12 @@ 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);
|
||||
|
|
Loading…
Reference in a new issue