element, GstStateChange transition);
static GstClock *gst_base_audio_sink_provide_clock (GstElement * elem);
-static gboolean gst_base_audio_sink_set_clock (GstElement * elem,
- GstClock * clock);
static GstClockTime gst_base_audio_sink_get_time (GstClock * clock,
GstBaseAudioSink * sink);
static void gst_base_audio_sink_callback (GstRingBuffer * rbuf, guint8 * data,
GST_DEBUG_FUNCPTR (gst_base_audio_sink_change_state);
gstelement_class->provide_clock =
GST_DEBUG_FUNCPTR (gst_base_audio_sink_provide_clock);
- gstelement_class->set_clock =
- GST_DEBUG_FUNCPTR (gst_base_audio_sink_set_clock);
gstbasesink_class->event = GST_DEBUG_FUNCPTR (gst_base_audio_sink_event);
gstbasesink_class->preroll = GST_DEBUG_FUNCPTR (gst_base_audio_sink_preroll);
return clock;
}
-static gboolean
-gst_base_audio_sink_set_clock (GstElement * elem, GstClock * clock)
-{
- GstBaseAudioSink *sink;
- gboolean ret;
-
- sink = GST_BASE_AUDIO_SINK (elem);
-
- GST_OBJECT_LOCK (sink);
- if (clock != sink->provided_clock) {
- ret = gst_clock_set_master (sink->provided_clock, clock);
- } else {
- ret = gst_clock_set_master (sink->provided_clock, NULL);
- }
- GST_OBJECT_UNLOCK (sink);
-
- return ret;
-}
-
static GstClockTime
gst_base_audio_sink_get_time (GstClock * clock, GstBaseAudioSink * sink)
{
break;
case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
{
+ GstClock *clock;
+
+ GST_OBJECT_LOCK (sink);
+ clock = GST_ELEMENT_CLOCK (sink);
/* if we are slaved to a clock, we need to set the initial
* calibration */
- /* FIXME, this is not yet accurate enough for smooth playback */
- if (gst_clock_get_master (sink->provided_clock)) {
+ if (clock != sink->provided_clock) {
GstClockTime time;
GstClockTime rate_num, rate_denom;
GST_DEBUG_OBJECT (sink, "time: %" GST_TIME_FORMAT,
GST_TIME_ARGS (time));
+ gst_clock_set_master (sink->provided_clock, clock);
+ /* FIXME, this is not yet accurate enough for smooth playback */
gst_clock_get_calibration (sink->provided_clock, NULL, NULL, &rate_num,
&rate_denom);
/* Does not work yet. */
gst_clock_set_calibration (sink->provided_clock,
time, element->base_time, rate_num, rate_denom);
}
+ GST_OBJECT_UNLOCK (sink);
break;
}
case GST_STATE_CHANGE_PAUSED_TO_READY:
switch (transition) {
case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
gst_ring_buffer_pause (sink->ringbuffer);
+ /* slop slaving ourselves to the master, if any */
+ gst_clock_set_master (sink->provided_clock, NULL);
break;
case GST_STATE_CHANGE_PAUSED_TO_READY:
gst_ring_buffer_release (sink->ringbuffer);
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
+/**
+ * SECTION:gstringbuffer
+ * @short_description: Base class for audio ringbuffer implementations
+ *
+ * This object is the base class for audio ringbuffers used by the base
+ * audio source and sink classes.
+ *
+ * Last reviewed on 2005-11-24 (0.9.6)
+ */
#include <string.h>
return ((int (*)[2][2]) linear_formats)[depth][!!unsignd][!!big_endian];
}
+/**
+ * gst_ring_buffer_debug_spec_caps:
+ * @spec: the spec to debug
+ *
+ * Print debug info about the parsed caps in @spec to the debug log.
+ */
void
gst_ring_buffer_debug_spec_caps (GstRingBufferSpec * spec)
{
GST_DEBUG ("parsed caps: sample bytes: %d", spec->bytes_per_sample);
}
+/**
+ * gst_ring_buffer_debug_spec_buff:
+ * @spec: the spec to debug
+ *
+ * Print debug info about the buffer sized in @spec to the debug log.
+ */
void
gst_ring_buffer_debug_spec_buff (GstRingBufferSpec * spec)
{
spec->segsize * spec->segtotal / spec->bytes_per_sample);
}
+/**
+ * gst_ring_buffer_parse_caps:
+ * @spec: a spec
+ * @caps: a #GstCaps
+ *
+ * Parse @caps into @spec.
+ *
+ * Returns: TRUE if the caps could be parsed.
+ */
gboolean
gst_ring_buffer_parse_caps (GstRingBufferSpec * spec, GstCaps * caps)
{
GST_DEBUG_OBJECT (buf, "opening device");
GST_OBJECT_LOCK (buf);
- if (buf->open) {
- g_warning ("Device for ring buffer %p already open, fix your code", buf);
- res = TRUE;
- goto done;
- }
+ if (buf->open)
+ goto was_opened;
+
buf->open = TRUE;
/* if this fails, something is wrong in this file */
if (rclass->open_device)
res = rclass->open_device (buf);
- if (!res) {
- buf->open = FALSE;
- GST_DEBUG_OBJECT (buf, "failed opening device");
- } else {
- GST_DEBUG_OBJECT (buf, "opened device");
- }
+ if (!res)
+ goto open_failed;
+
+ GST_DEBUG_OBJECT (buf, "opened device");
done:
GST_OBJECT_UNLOCK (buf);
return res;
+
+ /* ERRORS */
+was_opened:
+ {
+ GST_DEBUG_OBJECT (buf, "Device for ring buffer already open");
+ g_warning ("Device for ring buffer %p already open, fix your code", buf);
+ res = TRUE;
+ goto done;
+ }
+open_failed:
+ {
+ buf->open = FALSE;
+ GST_DEBUG_OBJECT (buf, "failed opening device");
+ goto done;
+ }
}
/**
GST_DEBUG_OBJECT (buf, "closing device");
GST_OBJECT_LOCK (buf);
- if (!buf->open) {
- g_warning ("Device for ring buffer %p already closed, fix your code", buf);
- res = TRUE;
- goto done;
- }
+ if (!buf->open)
+ goto was_closed;
- if (buf->acquired) {
- g_critical ("Resources for ring buffer %p still acquired", buf);
- res = FALSE;
- goto done;
- }
+ if (buf->acquired)
+ goto was_acquired;
buf->open = FALSE;
if (rclass->close_device)
res = rclass->close_device (buf);
- if (!res) {
- buf->open = TRUE;
- GST_DEBUG_OBJECT (buf, "error closing device");
- } else {
- GST_DEBUG_OBJECT (buf, "closed device");
- }
+ if (!res)
+ goto close_error;
+
+ GST_DEBUG_OBJECT (buf, "closed device");
done:
GST_OBJECT_UNLOCK (buf);
return res;
+
+ /* ERRORS */
+was_closed:
+ {
+ GST_DEBUG_OBJECT (buf, "Device for ring buffer already closed");
+ g_warning ("Device for ring buffer %p already closed, fix your code", buf);
+ res = TRUE;
+ goto done;
+ }
+was_acquired:
+ {
+ GST_DEBUG_OBJECT (buf, "Resources for ring buffer still acquired");
+ g_critical ("Resources for ring buffer %p still acquired", buf);
+ res = FALSE;
+ goto done;
+ }
+close_error:
+ {
+ buf->open = TRUE;
+ GST_DEBUG_OBJECT (buf, "error closing device");
+ goto done;
+ }
}
/**
{
gboolean res = FALSE;
GstRingBufferClass *rclass;
+ gint i, j;
+ gint segsize, bps;
g_return_val_if_fail (buf != NULL, FALSE);
GST_DEBUG_OBJECT (buf, "acquiring device");
GST_OBJECT_LOCK (buf);
- if (!buf->open) {
- g_critical ("Device for %p not opened", buf);
- res = FALSE;
- goto done;
- }
- if (buf->acquired) {
- res = TRUE;
- GST_DEBUG_OBJECT (buf, "device was acquired");
- goto done;
- }
+ if (!buf->open)
+ goto not_opened;
+
+ if (buf->acquired)
+ goto was_acquired;
+
buf->acquired = TRUE;
rclass = GST_RING_BUFFER_GET_CLASS (buf);
if (rclass->acquire)
res = rclass->acquire (buf, spec);
- if (!res) {
- buf->acquired = FALSE;
- GST_DEBUG_OBJECT (buf, "failed to acquire device");
- } else {
- if (buf->spec.bytes_per_sample != 0) {
- gint i, j;
+ if (!res)
+ goto acquire_failed;
- buf->samples_per_seg = buf->spec.segsize / buf->spec.bytes_per_sample;
+ if ((bps = buf->spec.bytes_per_sample) == 0)
+ goto invalid_bps;
- /* create an empty segment */
- g_free (buf->empty_seg);
- buf->empty_seg = g_malloc (buf->spec.segsize);
- for (i = 0, j = 0; i < buf->spec.segsize; i++) {
- buf->empty_seg[i] = buf->spec.silence_sample[j];
- j = (j + 1) % buf->spec.bytes_per_sample;
- }
- GST_DEBUG_OBJECT (buf, "acquired device");
- } else {
- g_warning
- ("invalid bytes_per_sample from acquire ringbuffer, fix the element");
- buf->acquired = FALSE;
- res = FALSE;
- }
+ segsize = buf->spec.segsize;
+
+ buf->samples_per_seg = segsize / bps;
+
+ /* create an empty segment */
+ g_free (buf->empty_seg);
+ buf->empty_seg = g_malloc (segsize);
+ for (i = 0, j = 0; i < segsize; i++) {
+ buf->empty_seg[i] = buf->spec.silence_sample[j];
+ j = (j + 1) % bps;
}
+ GST_DEBUG_OBJECT (buf, "acquired device");
+
done:
GST_OBJECT_UNLOCK (buf);
return res;
+
+ /* ERRORS */
+not_opened:
+ {
+ GST_DEBUG_OBJECT (buf, "device not opened");
+ g_critical ("Device for %p not opened", buf);
+ res = FALSE;
+ goto done;
+ }
+was_acquired:
+ {
+ res = TRUE;
+ GST_DEBUG_OBJECT (buf, "device was acquired");
+ goto done;
+ }
+acquire_failed:
+ {
+ buf->acquired = FALSE;
+ GST_DEBUG_OBJECT (buf, "failed to acquire device");
+ goto done;
+ }
+invalid_bps:
+ {
+ g_warning
+ ("invalid bytes_per_sample from acquire ringbuffer, fix the element");
+ buf->acquired = FALSE;
+ res = FALSE;
+ goto done;
+ }
}
/**
gst_ring_buffer_stop (buf);
GST_OBJECT_LOCK (buf);
- if (!buf->acquired) {
- res = TRUE;
- GST_DEBUG_OBJECT (buf, "device was released");
- goto done;
- }
+ if (!buf->acquired)
+ goto was_released;
+
buf->acquired = FALSE;
/* if this fails, something is wrong in this file */
/* signal any waiters */
GST_RING_BUFFER_SIGNAL (buf);
- if (!res) {
- buf->acquired = TRUE;
- GST_DEBUG_OBJECT (buf, "failed to release device");
- } else {
- g_free (buf->empty_seg);
- buf->empty_seg = NULL;
- GST_DEBUG_OBJECT (buf, "released device");
- }
+ if (!res)
+ goto release_failed;
+
+ g_free (buf->empty_seg);
+ buf->empty_seg = NULL;
+ GST_DEBUG_OBJECT (buf, "released device");
done:
GST_OBJECT_UNLOCK (buf);
return res;
+
+ /* ERRORS */
+was_released:
+ {
+ res = TRUE;
+ GST_DEBUG_OBJECT (buf, "device was released");
+ goto done;
+ }
+release_failed:
+ {
+ buf->acquired = TRUE;
+ GST_DEBUG_OBJECT (buf, "failed to release device");
+ goto done;
+ }
}
/**
if (samples >= delay)
samples -= delay;
- GST_DEBUG ("processed samples: raw %llu, delay %u, real %llu", raw, delay,
- samples);
+ GST_DEBUG_OBJECT (buf, "processed samples: raw %llu, delay %u, real %llu",
+ raw, delay, samples);
return samples;
}
gst_ring_buffer_clear_all (buf);
- GST_DEBUG ("set sample to %llu, segbase %d", sample, buf->segbase);
+ GST_DEBUG_OBJECT (buf, "set sample to %llu, segbase %d", sample,
+ buf->segbase);
}
/**
if (buf->spec.segtotal <= 0)
return;
- GST_DEBUG ("clear all segments");
+ GST_DEBUG_OBJECT (buf, "clear all segments");
for (i = 0; i < buf->spec.segtotal; i++) {
gst_ring_buffer_clear (buf, i);
{
/* buffer must be started now or we deadlock since nobody is reading */
if (g_atomic_int_get (&buf->state) != GST_RING_BUFFER_STATE_STARTED) {
- GST_DEBUG ("start!");
+ GST_DEBUG_OBJECT (buf, "start!");
gst_ring_buffer_start (buf);
}
goto flushing;
if (g_atomic_int_compare_and_exchange (&buf->waiting, 0, 1)) {
- GST_DEBUG ("waiting..");
+ GST_DEBUG_OBJECT (buf, "waiting..");
if (g_atomic_int_get (&buf->state) != GST_RING_BUFFER_STATE_STARTED)
goto not_started;
not_started:
{
GST_OBJECT_UNLOCK (buf);
- GST_DEBUG ("stopped processing");
+ GST_DEBUG_OBJECT (buf, "stopped processing");
return FALSE;
}
flushing:
{
GST_OBJECT_UNLOCK (buf);
- GST_DEBUG ("flushing");
+ GST_DEBUG_OBJECT (buf, "flushing");
return FALSE;
}
}
* the ringbuffer.
*
* @len not needs to be a multiple of the segment size of the ringbuffer
- * although it is recommended.
+ * although it is recommended for optimal performance.
*
* Returns: The number of samples written to the ringbuffer or -1 on
* error.
writeseg = writeseg % segtotal;
sampleslen = MIN (sps - sampleoff, len);
- GST_DEBUG ("write @%p seg %d, off %d, len %d",
+ GST_DEBUG_OBJECT (buf, "write @%p seg %d, off %d, len %d",
dest + writeseg * segsize, writeseg, sampleoff, sampleslen);
memcpy (dest + (writeseg * segsize) + (sampleoff * bps), data,
/* ERRORS */
not_started:
{
- GST_DEBUG ("stopped processing");
+ GST_DEBUG_OBJECT (buf, "stopped processing");
return -1;
}
}
readseg = readseg % segtotal;
sampleslen = MIN (sps - sampleoff, len);
- GST_DEBUG ("read @%p seg %d, off %d, len %d",
+ GST_DEBUG_OBJECT (buf, "read @%p seg %d, off %d, len %d",
dest + readseg * segsize, readseg, sampleoff, sampleslen);
memcpy (data, dest + (readseg * segsize) + (sampleoff * bps),
/* ERRORS */
not_started:
{
- GST_DEBUG ("stopped processing");
+ GST_DEBUG_OBJECT (buf, "stopped processing");
return -1;
}
}
* waiting for the signal */
if (g_atomic_int_compare_and_exchange (&buf->waiting, 1, 0)) {
GST_OBJECT_LOCK (buf);
- GST_DEBUG ("signal waiter");
+ GST_DEBUG_OBJECT (buf, "signal waiter");
GST_RING_BUFFER_SIGNAL (buf);
GST_OBJECT_UNLOCK (buf);
}
/* called to fill data with len bytes of samples */
typedef void (*GstRingBufferCallback) (GstRingBuffer *rbuf, guint8* data, guint len, gpointer user_data);
+/**
+ * GstRingBufferState:
+ * @GST_RING_BUFFER_STATE_STOPPED: The ringbuffer is stopped
+ * @GST_RING_BUFFER_STATE_PAUSED: The ringbuffer is paused
+ * @GST_RING_BUFFER_STATE_STARTED: The ringbuffer is started
+ *
+ * The state of the ringbuffer.
+ */
typedef enum {
GST_RING_BUFFER_STATE_STOPPED,
GST_RING_BUFFER_STATE_PAUSED,
GST_RING_BUFFER_STATE_STARTED,
} GstRingBufferState;
+/**
+ * GstRingBufferSegState:
+ * @GST_SEGSTATE_INVALID: The content of the segment is invalid
+ * @GST_SEGSTATE_EMPTY: The segment is empty
+ * @GST_SEGSTATE_FILLED: The segment contains valid data
+ * @GST_SEGSTATE_PARTIAL: The segment partially contains valid data
+ *
+ * The state of a segment in the ringbuffer.
+ */
typedef enum {
GST_SEGSTATE_INVALID,
GST_SEGSTATE_EMPTY,
GST_SEGSTATE_PARTIAL,
} GstRingBufferSegState;
+/**
+ * GstBufferFormatType:
+ * @GST_BUFTYPE_LINEAR: samples in linear PCM
+ * @GST_BUFTYPE_FLOAT: samples in float
+ * @GST_BUFTYPE_MU_LAW: samples in mulaw
+ * @GST_BUFTYPE_A_LAW: samples in alaw
+ * @GST_BUFTYPE_IMA_ADPCM: samples in ima adpcm
+ * @GST_BUFTYPE_MPEG: samples in mpeg audio format
+ * @GST_BUFTYPE_GSM: samples in gsm format
+ *
+ * The format of the samples in the ringbuffer.
+ */
typedef enum
{
GST_BUFTYPE_LINEAR,
} GstBufferFormat;
+/**
+ * GstRingBufferSpec:
+ * @caps: The caps that generated the Spec.
+ * @type: the sample type
+ * @format: the sample format
+ * @sign: the sample sign
+ * @bigend: the endianness of the samples
+ * @width: the width of the samples
+ * @depth: th depth of the samples
+ * @rate: the samplerate
+ * @channels: the number of channels
+ * @latency_time: the latency in time units
+ * @buffer_time: the total buffer size in time units
+ * @segsize: the size of one segment in bytes
+ * @segtotal: the total number of segments
+ * @bytes_per_sample: number of bytes in one sample
+ * @silence_sample: bytes representing one sample of silence
+ *
+ * The structure containing the format specification of the ringbuffer.
+ */
struct _GstRingBufferSpec
{
+ /*< public >*/
/* in */
GstCaps *caps; /* the caps of the buffer */
gpointer user_data);
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);
+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);