+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:
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);
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);
}
static gboolean
-gst_alsasink_open (GstAudioSink * asink, GstRingBufferSpec * spec)
+gst_alsasink_open (GstAudioSink * asink)
{
GstAlsaSink *alsa;
gint err;
alsa = GST_ALSA_SINK (asink);
- 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);
+ 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;
+
+ alsa = GST_ALSA_SINK (asink);
+
+ if (!alsasink_parse_spec (alsa, spec))
+ goto spec_parse;
+
CHECK (snd_pcm_nonblock (alsa->handle, 0), non_block);
CHECK (set_hwparams (alsa), hw_params_failed);
("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,
}
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;
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);
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 =
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)
{
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;
gst_buffer_unref (buf->data);
buf->data = NULL;
- if (csink->close)
- result = csink->close (sink);
+ if (csink->unprepare)
+ result = csink->unprepare (sink);
return result;
}
/* 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);
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;
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;
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 ();
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
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;
}
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);
/*< public >*/ /* with LOCK */
GCond *cond;
+ gboolean open;
gboolean acquired;
GstBuffer *data;
GstRingBufferSpec spec;
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);
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);