|
Packit |
0652a1 |
/* GStreamer
|
|
Packit |
0652a1 |
* Copyright (C) 2005 Wim Taymans <wim@fluendo.com>
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* This library is free software; you can redistribute it and/or
|
|
Packit |
0652a1 |
* modify it under the terms of the GNU Library General Public
|
|
Packit |
0652a1 |
* License as published by the Free Software Foundation; either
|
|
Packit |
0652a1 |
* version 2 of the License, or (at your option) any later version.
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* This library is distributed in the hope that it will be useful,
|
|
Packit |
0652a1 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
0652a1 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
0652a1 |
* Library General Public License for more details.
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* You should have received a copy of the GNU Library General Public
|
|
Packit |
0652a1 |
* License along with this library; if not, write to the
|
|
Packit |
0652a1 |
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
|
Packit |
0652a1 |
* Boston, MA 02110-1301, USA.
|
|
Packit |
0652a1 |
*/
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/**
|
|
Packit |
0652a1 |
* SECTION:gstaudioringbuffer
|
|
Packit |
0652a1 |
* @title: GstAudioRingBuffer
|
|
Packit |
0652a1 |
* @short_description: Base class for audio ringbuffer implementations
|
|
Packit |
0652a1 |
* @see_also: #GstAudioBaseSink, #GstAudioSink
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* This object is the base class for audio ringbuffers used by the base
|
|
Packit |
0652a1 |
* audio source and sink classes.
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* The ringbuffer abstracts a circular buffer of data. One reader and
|
|
Packit |
0652a1 |
* one writer can operate on the data from different threads in a lockfree
|
|
Packit |
0652a1 |
* manner. The base class is sufficiently flexible to be used as an
|
|
Packit |
0652a1 |
* abstraction for DMA based ringbuffers as well as a pure software
|
|
Packit |
0652a1 |
* implementations.
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
*/
|
|
Packit |
0652a1 |
#ifdef HAVE_CONFIG_H
|
|
Packit |
0652a1 |
#include "config.h"
|
|
Packit |
0652a1 |
#endif
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
#include <string.h>
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
#include <gst/audio/audio.h>
|
|
Packit |
0652a1 |
#include "gstaudioringbuffer.h"
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
GST_DEBUG_CATEGORY_STATIC (gst_audio_ring_buffer_debug);
|
|
Packit |
0652a1 |
#define GST_CAT_DEFAULT gst_audio_ring_buffer_debug
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
static void gst_audio_ring_buffer_dispose (GObject * object);
|
|
Packit |
0652a1 |
static void gst_audio_ring_buffer_finalize (GObject * object);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
static gboolean gst_audio_ring_buffer_pause_unlocked (GstAudioRingBuffer * buf);
|
|
Packit |
0652a1 |
static void default_clear_all (GstAudioRingBuffer * buf);
|
|
Packit |
0652a1 |
static guint default_commit (GstAudioRingBuffer * buf, guint64 * sample,
|
|
Packit |
0652a1 |
guint8 * data, gint in_samples, gint out_samples, gint * accum);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/* ringbuffer abstract base class */
|
|
Packit |
0652a1 |
G_DEFINE_ABSTRACT_TYPE (GstAudioRingBuffer, gst_audio_ring_buffer,
|
|
Packit |
0652a1 |
GST_TYPE_OBJECT);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
static void
|
|
Packit |
0652a1 |
gst_audio_ring_buffer_class_init (GstAudioRingBufferClass * klass)
|
|
Packit |
0652a1 |
{
|
|
Packit |
0652a1 |
GObjectClass *gobject_class;
|
|
Packit |
0652a1 |
GstAudioRingBufferClass *gstaudioringbuffer_class;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
gobject_class = (GObjectClass *) klass;
|
|
Packit |
0652a1 |
gstaudioringbuffer_class = (GstAudioRingBufferClass *) klass;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
GST_DEBUG_CATEGORY_INIT (gst_audio_ring_buffer_debug, "ringbuffer", 0,
|
|
Packit |
0652a1 |
"ringbuffer class");
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
gobject_class->dispose = gst_audio_ring_buffer_dispose;
|
|
Packit |
0652a1 |
gobject_class->finalize = gst_audio_ring_buffer_finalize;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
gstaudioringbuffer_class->clear_all = GST_DEBUG_FUNCPTR (default_clear_all);
|
|
Packit |
0652a1 |
gstaudioringbuffer_class->commit = GST_DEBUG_FUNCPTR (default_commit);
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
static void
|
|
Packit |
0652a1 |
gst_audio_ring_buffer_init (GstAudioRingBuffer * ringbuffer)
|
|
Packit |
0652a1 |
{
|
|
Packit |
0652a1 |
ringbuffer->open = FALSE;
|
|
Packit |
0652a1 |
ringbuffer->acquired = FALSE;
|
|
Packit |
0652a1 |
ringbuffer->state = GST_AUDIO_RING_BUFFER_STATE_STOPPED;
|
|
Packit |
0652a1 |
g_cond_init (&ringbuffer->cond);
|
|
Packit |
0652a1 |
ringbuffer->waiting = 0;
|
|
Packit |
0652a1 |
ringbuffer->empty_seg = NULL;
|
|
Packit |
0652a1 |
ringbuffer->flushing = TRUE;
|
|
Packit |
0652a1 |
ringbuffer->segbase = 0;
|
|
Packit |
0652a1 |
ringbuffer->segdone = 0;
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
static void
|
|
Packit |
0652a1 |
gst_audio_ring_buffer_dispose (GObject * object)
|
|
Packit |
0652a1 |
{
|
|
Packit |
0652a1 |
GstAudioRingBuffer *ringbuffer = GST_AUDIO_RING_BUFFER (object);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
gst_caps_replace (&ringbuffer->spec.caps, NULL);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
G_OBJECT_CLASS (gst_audio_ring_buffer_parent_class)->dispose (G_OBJECT
|
|
Packit |
0652a1 |
(ringbuffer));
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
static void
|
|
Packit |
0652a1 |
gst_audio_ring_buffer_finalize (GObject * object)
|
|
Packit |
0652a1 |
{
|
|
Packit |
0652a1 |
GstAudioRingBuffer *ringbuffer = GST_AUDIO_RING_BUFFER (object);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
g_cond_clear (&ringbuffer->cond);
|
|
Packit |
0652a1 |
g_free (ringbuffer->empty_seg);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
if (ringbuffer->cb_data_notify != NULL)
|
|
Packit |
0652a1 |
ringbuffer->cb_data_notify (ringbuffer->cb_data);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
G_OBJECT_CLASS (gst_audio_ring_buffer_parent_class)->finalize (G_OBJECT
|
|
Packit |
0652a1 |
(ringbuffer));
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
#ifndef GST_DISABLE_GST_DEBUG
|
|
Packit |
0652a1 |
static const gchar *format_type_names[] = {
|
|
Packit |
0652a1 |
"raw",
|
|
Packit |
0652a1 |
"mu law",
|
|
Packit |
0652a1 |
"a law",
|
|
Packit |
0652a1 |
"ima adpcm",
|
|
Packit |
0652a1 |
"mpeg",
|
|
Packit |
0652a1 |
"gsm",
|
|
Packit |
0652a1 |
"iec958",
|
|
Packit |
0652a1 |
"ac3",
|
|
Packit |
0652a1 |
"eac3",
|
|
Packit |
0652a1 |
"dts",
|
|
Packit |
0652a1 |
"aac mpeg2",
|
|
Packit |
0652a1 |
"aac mpeg4",
|
|
Packit |
0652a1 |
"aac mpeg2 raw",
|
|
Packit |
0652a1 |
"aac mpeg4 raw",
|
|
Packit |
0652a1 |
"flac"
|
|
Packit |
0652a1 |
};
|
|
Packit |
0652a1 |
#endif
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/**
|
|
Packit |
0652a1 |
* gst_audio_ring_buffer_debug_spec_caps:
|
|
Packit |
0652a1 |
* @spec: the spec to debug
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* Print debug info about the parsed caps in @spec to the debug log.
|
|
Packit |
0652a1 |
*/
|
|
Packit |
0652a1 |
void
|
|
Packit |
0652a1 |
gst_audio_ring_buffer_debug_spec_caps (GstAudioRingBufferSpec * spec)
|
|
Packit |
0652a1 |
{
|
|
Packit |
0652a1 |
#if 0
|
|
Packit |
0652a1 |
gint i, bytes;
|
|
Packit |
0652a1 |
#endif
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
GST_DEBUG ("spec caps: %p %" GST_PTR_FORMAT, spec->caps, spec->caps);
|
|
Packit |
0652a1 |
GST_DEBUG ("parsed caps: type: %d, '%s'", spec->type,
|
|
Packit |
0652a1 |
format_type_names[spec->type]);
|
|
Packit |
0652a1 |
#if 0
|
|
Packit |
0652a1 |
GST_DEBUG ("parsed caps: width: %d", spec->width);
|
|
Packit |
0652a1 |
GST_DEBUG ("parsed caps: sign: %d", spec->sign);
|
|
Packit |
0652a1 |
GST_DEBUG ("parsed caps: bigend: %d", spec->bigend);
|
|
Packit |
0652a1 |
GST_DEBUG ("parsed caps: rate: %d", spec->rate);
|
|
Packit |
0652a1 |
GST_DEBUG ("parsed caps: channels: %d", spec->channels);
|
|
Packit |
0652a1 |
GST_DEBUG ("parsed caps: sample bytes: %d", spec->bytes_per_sample);
|
|
Packit |
0652a1 |
bytes = (spec->width >> 3) * spec->channels;
|
|
Packit |
0652a1 |
for (i = 0; i < bytes; i++) {
|
|
Packit |
0652a1 |
GST_DEBUG ("silence byte %d: %02x", i, spec->silence_sample[i]);
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
#endif
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/**
|
|
Packit |
0652a1 |
* gst_audio_ring_buffer_debug_spec_buff:
|
|
Packit |
0652a1 |
* @spec: the spec to debug
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* Print debug info about the buffer sized in @spec to the debug log.
|
|
Packit |
0652a1 |
*/
|
|
Packit |
0652a1 |
void
|
|
Packit |
0652a1 |
gst_audio_ring_buffer_debug_spec_buff (GstAudioRingBufferSpec * spec)
|
|
Packit |
0652a1 |
{
|
|
Packit |
0652a1 |
gint bpf = GST_AUDIO_INFO_BPF (&spec->info);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
GST_DEBUG ("acquire ringbuffer: buffer time: %" G_GINT64_FORMAT " usec",
|
|
Packit |
0652a1 |
spec->buffer_time);
|
|
Packit |
0652a1 |
GST_DEBUG ("acquire ringbuffer: latency time: %" G_GINT64_FORMAT " usec",
|
|
Packit |
0652a1 |
spec->latency_time);
|
|
Packit |
0652a1 |
GST_DEBUG ("acquire ringbuffer: total segments: %d", spec->segtotal);
|
|
Packit |
0652a1 |
GST_DEBUG ("acquire ringbuffer: latency segments: %d", spec->seglatency);
|
|
Packit |
0652a1 |
GST_DEBUG ("acquire ringbuffer: segment size: %d bytes = %d samples",
|
|
Packit |
0652a1 |
spec->segsize, (bpf != 0) ? (spec->segsize / bpf) : -1);
|
|
Packit |
0652a1 |
GST_DEBUG ("acquire ringbuffer: buffer size: %d bytes = %d samples",
|
|
Packit |
0652a1 |
spec->segsize * spec->segtotal,
|
|
Packit |
0652a1 |
(bpf != 0) ? (spec->segsize * spec->segtotal / bpf) : -1);
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/**
|
|
Packit |
0652a1 |
* gst_audio_ring_buffer_parse_caps:
|
|
Packit |
0652a1 |
* @spec: a spec
|
|
Packit |
0652a1 |
* @caps: a #GstCaps
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* Parse @caps into @spec.
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* Returns: TRUE if the caps could be parsed.
|
|
Packit |
0652a1 |
*/
|
|
Packit |
0652a1 |
gboolean
|
|
Packit |
0652a1 |
gst_audio_ring_buffer_parse_caps (GstAudioRingBufferSpec * spec, GstCaps * caps)
|
|
Packit |
0652a1 |
{
|
|
Packit |
0652a1 |
const gchar *mimetype;
|
|
Packit |
0652a1 |
GstStructure *structure;
|
|
Packit |
0652a1 |
gint i;
|
|
Packit |
0652a1 |
GstAudioInfo info;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
structure = gst_caps_get_structure (caps, 0);
|
|
Packit |
0652a1 |
gst_audio_info_init (&info;;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/* we have to differentiate between int and float formats */
|
|
Packit |
0652a1 |
mimetype = gst_structure_get_name (structure);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
if (g_str_equal (mimetype, "audio/x-raw")) {
|
|
Packit |
0652a1 |
if (!gst_audio_info_from_caps (&info, caps))
|
|
Packit |
0652a1 |
goto parse_error;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
spec->type = GST_AUDIO_RING_BUFFER_FORMAT_TYPE_RAW;
|
|
Packit |
0652a1 |
} else if (g_str_equal (mimetype, "audio/x-alaw")) {
|
|
Packit |
0652a1 |
/* extract the needed information from the cap */
|
|
Packit |
0652a1 |
if (!(gst_structure_get_int (structure, "rate", &info.rate) &&
|
|
Packit |
0652a1 |
gst_structure_get_int (structure, "channels", &info.channels)))
|
|
Packit |
0652a1 |
goto parse_error;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
if (!(gst_audio_channel_positions_from_mask (info.channels, 0,
|
|
Packit |
0652a1 |
info.position)))
|
|
Packit |
0652a1 |
goto parse_error;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
spec->type = GST_AUDIO_RING_BUFFER_FORMAT_TYPE_A_LAW;
|
|
Packit |
0652a1 |
info.bpf = info.channels;
|
|
Packit |
0652a1 |
} else if (g_str_equal (mimetype, "audio/x-mulaw")) {
|
|
Packit |
0652a1 |
/* extract the needed information from the cap */
|
|
Packit |
0652a1 |
if (!(gst_structure_get_int (structure, "rate", &info.rate) &&
|
|
Packit |
0652a1 |
gst_structure_get_int (structure, "channels", &info.channels)))
|
|
Packit |
0652a1 |
goto parse_error;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
if (!(gst_audio_channel_positions_from_mask (info.channels, 0,
|
|
Packit |
0652a1 |
info.position)))
|
|
Packit |
0652a1 |
goto parse_error;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
spec->type = GST_AUDIO_RING_BUFFER_FORMAT_TYPE_MU_LAW;
|
|
Packit |
0652a1 |
info.bpf = info.channels;
|
|
Packit |
0652a1 |
} else if (g_str_equal (mimetype, "audio/x-iec958")) {
|
|
Packit |
0652a1 |
/* extract the needed information from the cap */
|
|
Packit |
0652a1 |
if (!(gst_structure_get_int (structure, "rate", &info.rate)))
|
|
Packit |
0652a1 |
goto parse_error;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
spec->type = GST_AUDIO_RING_BUFFER_FORMAT_TYPE_IEC958;
|
|
Packit |
0652a1 |
info.bpf = 4;
|
|
Packit |
0652a1 |
} else if (g_str_equal (mimetype, "audio/x-ac3")) {
|
|
Packit |
0652a1 |
/* extract the needed information from the cap */
|
|
Packit |
0652a1 |
if (!(gst_structure_get_int (structure, "rate", &info.rate)))
|
|
Packit |
0652a1 |
goto parse_error;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
gst_structure_get_int (structure, "channels", &info.channels);
|
|
Packit |
0652a1 |
spec->type = GST_AUDIO_RING_BUFFER_FORMAT_TYPE_AC3;
|
|
Packit |
0652a1 |
info.bpf = 4;
|
|
Packit |
0652a1 |
} else if (g_str_equal (mimetype, "audio/x-eac3")) {
|
|
Packit |
0652a1 |
/* extract the needed information from the cap */
|
|
Packit |
0652a1 |
if (!(gst_structure_get_int (structure, "rate", &info.rate)))
|
|
Packit |
0652a1 |
goto parse_error;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
gst_structure_get_int (structure, "channels", &info.channels);
|
|
Packit |
0652a1 |
spec->type = GST_AUDIO_RING_BUFFER_FORMAT_TYPE_EAC3;
|
|
Packit |
0652a1 |
info.bpf = 16;
|
|
Packit |
0652a1 |
} else if (g_str_equal (mimetype, "audio/x-dts")) {
|
|
Packit |
0652a1 |
/* extract the needed information from the cap */
|
|
Packit |
0652a1 |
if (!(gst_structure_get_int (structure, "rate", &info.rate)))
|
|
Packit |
0652a1 |
goto parse_error;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
gst_structure_get_int (structure, "channels", &info.channels);
|
|
Packit |
0652a1 |
spec->type = GST_AUDIO_RING_BUFFER_FORMAT_TYPE_DTS;
|
|
Packit |
0652a1 |
info.bpf = 4;
|
|
Packit |
0652a1 |
} else if (g_str_equal (mimetype, "audio/mpeg") &&
|
|
Packit |
0652a1 |
gst_structure_get_int (structure, "mpegaudioversion", &i) &&
|
|
Packit |
0652a1 |
(i == 1 || i == 2 || i == 3)) {
|
|
Packit |
0652a1 |
/* Now we know this is MPEG-1, MPEG-2 or MPEG-2.5 (non AAC) */
|
|
Packit |
0652a1 |
/* extract the needed information from the cap */
|
|
Packit |
0652a1 |
if (!(gst_structure_get_int (structure, "rate", &info.rate)))
|
|
Packit |
0652a1 |
goto parse_error;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
gst_structure_get_int (structure, "channels", &info.channels);
|
|
Packit |
0652a1 |
spec->type = GST_AUDIO_RING_BUFFER_FORMAT_TYPE_MPEG;
|
|
Packit |
0652a1 |
info.bpf = 1;
|
|
Packit |
0652a1 |
} else if (g_str_equal (mimetype, "audio/mpeg") &&
|
|
Packit |
0652a1 |
gst_structure_get_int (structure, "mpegversion", &i) &&
|
|
Packit |
0652a1 |
(i == 2 || i == 4) &&
|
|
Packit |
0652a1 |
(!g_strcmp0 (gst_structure_get_string (structure, "stream-format"),
|
|
Packit |
0652a1 |
"adts")
|
|
Packit |
0652a1 |
|| !g_strcmp0 (gst_structure_get_string (structure, "stream-format"),
|
|
Packit |
0652a1 |
"raw"))) {
|
|
Packit |
0652a1 |
/* MPEG-2 AAC or MPEG-4 AAC */
|
|
Packit |
0652a1 |
if (!(gst_structure_get_int (structure, "rate", &info.rate)))
|
|
Packit |
0652a1 |
goto parse_error;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
gst_structure_get_int (structure, "channels", &info.channels);
|
|
Packit |
0652a1 |
if (!g_strcmp0 (gst_structure_get_string (structure, "stream-format"),
|
|
Packit |
0652a1 |
"adts"))
|
|
Packit |
0652a1 |
spec->type = (i == 2) ? GST_AUDIO_RING_BUFFER_FORMAT_TYPE_MPEG2_AAC :
|
|
Packit |
0652a1 |
GST_AUDIO_RING_BUFFER_FORMAT_TYPE_MPEG4_AAC;
|
|
Packit |
0652a1 |
else
|
|
Packit |
0652a1 |
spec->type = (i == 2) ?
|
|
Packit |
0652a1 |
GST_AUDIO_RING_BUFFER_FORMAT_TYPE_MPEG2_AAC_RAW :
|
|
Packit |
0652a1 |
GST_AUDIO_RING_BUFFER_FORMAT_TYPE_MPEG4_AAC_RAW;
|
|
Packit |
0652a1 |
info.bpf = 1;
|
|
Packit |
0652a1 |
} else if (g_str_equal (mimetype, "audio/x-flac")) {
|
|
Packit |
0652a1 |
/* extract the needed information from the cap */
|
|
Packit |
0652a1 |
if (!(gst_structure_get_int (structure, "rate", &info.rate)))
|
|
Packit |
0652a1 |
goto parse_error;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
gst_structure_get_int (structure, "channels", &info.channels);
|
|
Packit |
0652a1 |
spec->type = GST_AUDIO_RING_BUFFER_FORMAT_TYPE_FLAC;
|
|
Packit |
0652a1 |
info.bpf = 1;
|
|
Packit |
0652a1 |
} else {
|
|
Packit |
0652a1 |
goto parse_error;
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
gst_caps_replace (&spec->caps, caps);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
g_return_val_if_fail (spec->latency_time != 0, FALSE);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/* calculate suggested segsize and segtotal. segsize should be one unit
|
|
Packit |
0652a1 |
* of 'latency_time' samples, scaling for the fact that latency_time is
|
|
Packit |
0652a1 |
* currently stored in microseconds (FIXME: in 0.11) */
|
|
Packit |
0652a1 |
spec->segsize = gst_util_uint64_scale (info.rate * info.bpf,
|
|
Packit |
0652a1 |
spec->latency_time, GST_SECOND / GST_USECOND);
|
|
Packit |
0652a1 |
/* Round to an integer number of samples */
|
|
Packit |
0652a1 |
spec->segsize -= spec->segsize % info.bpf;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
spec->segtotal = spec->buffer_time / spec->latency_time;
|
|
Packit |
0652a1 |
/* leave the latency undefined now, implementations can change it but if it's
|
|
Packit |
0652a1 |
* not changed, we assume the same value as segtotal */
|
|
Packit |
0652a1 |
spec->seglatency = -1;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
spec->info = info;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
gst_audio_ring_buffer_debug_spec_caps (spec);
|
|
Packit |
0652a1 |
gst_audio_ring_buffer_debug_spec_buff (spec);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
return TRUE;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/* ERRORS */
|
|
Packit |
0652a1 |
parse_error:
|
|
Packit |
0652a1 |
{
|
|
Packit |
0652a1 |
GST_DEBUG ("could not parse caps");
|
|
Packit |
0652a1 |
return FALSE;
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/**
|
|
Packit |
0652a1 |
* gst_audio_ring_buffer_convert:
|
|
Packit |
0652a1 |
* @buf: the #GstAudioRingBuffer
|
|
Packit |
0652a1 |
* @src_fmt: the source format
|
|
Packit |
0652a1 |
* @src_val: the source value
|
|
Packit |
0652a1 |
* @dest_fmt: the destination format
|
|
Packit |
0652a1 |
* @dest_val: (out): a location to store the converted value
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* Convert @src_val in @src_fmt to the equivalent value in @dest_fmt. The result
|
|
Packit |
0652a1 |
* will be put in @dest_val.
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* Returns: TRUE if the conversion succeeded.
|
|
Packit |
0652a1 |
*/
|
|
Packit |
0652a1 |
gboolean
|
|
Packit |
0652a1 |
gst_audio_ring_buffer_convert (GstAudioRingBuffer * buf,
|
|
Packit |
0652a1 |
GstFormat src_fmt, gint64 src_val, GstFormat dest_fmt, gint64 * dest_val)
|
|
Packit |
0652a1 |
{
|
|
Packit |
0652a1 |
gboolean res;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
GST_OBJECT_LOCK (buf);
|
|
Packit |
0652a1 |
res =
|
|
Packit |
0652a1 |
gst_audio_info_convert (&buf->spec.info, src_fmt, src_val, dest_fmt,
|
|
Packit |
0652a1 |
dest_val);
|
|
Packit |
0652a1 |
GST_OBJECT_UNLOCK (buf);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
return res;
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/**
|
|
Packit |
0652a1 |
* gst_audio_ring_buffer_set_callback: (skip)
|
|
Packit |
0652a1 |
* @buf: the #GstAudioRingBuffer to set the callback on
|
|
Packit |
0652a1 |
* @cb: (allow-none): the callback to set
|
|
Packit |
0652a1 |
* @user_data: user data passed to the callback
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* Sets the given callback function on the buffer. This function
|
|
Packit |
0652a1 |
* will be called every time a segment has been written to a device.
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* MT safe.
|
|
Packit |
0652a1 |
*/
|
|
Packit |
0652a1 |
void
|
|
Packit |
0652a1 |
gst_audio_ring_buffer_set_callback (GstAudioRingBuffer * buf,
|
|
Packit |
0652a1 |
GstAudioRingBufferCallback cb, gpointer user_data)
|
|
Packit |
0652a1 |
{
|
|
Packit |
0652a1 |
gst_audio_ring_buffer_set_callback_full (buf, cb, user_data, NULL);
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/**
|
|
Packit |
0652a1 |
* gst_audio_ring_buffer_set_callback_full: (rename-to gst_audio_ring_buffer_set_callback)
|
|
Packit |
0652a1 |
* @buf: the #GstAudioRingBuffer to set the callback on
|
|
Packit |
0652a1 |
* @cb: (allow-none): the callback to set
|
|
Packit |
0652a1 |
* @user_data: user data passed to the callback
|
|
Packit |
0652a1 |
* @notify: function to be called when @user_data is no longer needed
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* Sets the given callback function on the buffer. This function
|
|
Packit |
0652a1 |
* will be called every time a segment has been written to a device.
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* MT safe.
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* Since: 1.12
|
|
Packit |
0652a1 |
*/
|
|
Packit |
0652a1 |
void
|
|
Packit |
0652a1 |
gst_audio_ring_buffer_set_callback_full (GstAudioRingBuffer * buf,
|
|
Packit |
0652a1 |
GstAudioRingBufferCallback cb, gpointer user_data, GDestroyNotify notify)
|
|
Packit |
0652a1 |
{
|
|
Packit |
0652a1 |
gpointer old_data = NULL;
|
|
Packit |
0652a1 |
GDestroyNotify old_notify;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
g_return_if_fail (GST_IS_AUDIO_RING_BUFFER (buf));
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
GST_OBJECT_LOCK (buf);
|
|
Packit |
0652a1 |
old_notify = buf->cb_data_notify;
|
|
Packit |
0652a1 |
old_data = buf->cb_data;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
buf->callback = cb;
|
|
Packit |
0652a1 |
buf->cb_data = user_data;
|
|
Packit |
0652a1 |
buf->cb_data_notify = notify;
|
|
Packit |
0652a1 |
GST_OBJECT_UNLOCK (buf);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
if (old_notify) {
|
|
Packit |
0652a1 |
old_notify (old_data);
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/**
|
|
Packit |
0652a1 |
* gst_audio_ring_buffer_open_device:
|
|
Packit |
0652a1 |
* @buf: the #GstAudioRingBuffer
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* Open the audio device associated with the ring buffer. Does not perform any
|
|
Packit |
0652a1 |
* setup on the device. You must open the device before acquiring the ring
|
|
Packit |
0652a1 |
* buffer.
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* Returns: TRUE if the device could be opened, FALSE on error.
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* MT safe.
|
|
Packit |
0652a1 |
*/
|
|
Packit |
0652a1 |
gboolean
|
|
Packit |
0652a1 |
gst_audio_ring_buffer_open_device (GstAudioRingBuffer * buf)
|
|
Packit |
0652a1 |
{
|
|
Packit |
0652a1 |
gboolean res = TRUE;
|
|
Packit |
0652a1 |
GstAudioRingBufferClass *rclass;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
g_return_val_if_fail (GST_IS_AUDIO_RING_BUFFER (buf), FALSE);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
GST_DEBUG_OBJECT (buf, "opening device");
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
GST_OBJECT_LOCK (buf);
|
|
Packit |
0652a1 |
if (G_UNLIKELY (buf->open))
|
|
Packit |
0652a1 |
goto was_opened;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
buf->open = TRUE;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/* if this fails, something is wrong in this file */
|
|
Packit |
0652a1 |
g_assert (!buf->acquired);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
rclass = GST_AUDIO_RING_BUFFER_GET_CLASS (buf);
|
|
Packit |
0652a1 |
if (G_LIKELY (rclass->open_device))
|
|
Packit |
0652a1 |
res = rclass->open_device (buf);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
if (G_UNLIKELY (!res))
|
|
Packit |
0652a1 |
goto open_failed;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
GST_DEBUG_OBJECT (buf, "opened device");
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
done:
|
|
Packit |
0652a1 |
GST_OBJECT_UNLOCK (buf);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
return res;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/* ERRORS */
|
|
Packit |
0652a1 |
was_opened:
|
|
Packit |
0652a1 |
{
|
|
Packit |
0652a1 |
GST_DEBUG_OBJECT (buf, "Device for ring buffer already open");
|
|
Packit |
0652a1 |
g_warning ("Device for ring buffer %p already open, fix your code", buf);
|
|
Packit |
0652a1 |
res = TRUE;
|
|
Packit |
0652a1 |
goto done;
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
open_failed:
|
|
Packit |
0652a1 |
{
|
|
Packit |
0652a1 |
buf->open = FALSE;
|
|
Packit |
0652a1 |
GST_DEBUG_OBJECT (buf, "failed opening device");
|
|
Packit |
0652a1 |
goto done;
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/**
|
|
Packit |
0652a1 |
* gst_audio_ring_buffer_close_device:
|
|
Packit |
0652a1 |
* @buf: the #GstAudioRingBuffer
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* Close the audio device associated with the ring buffer. The ring buffer
|
|
Packit |
0652a1 |
* should already have been released via gst_audio_ring_buffer_release().
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* Returns: TRUE if the device could be closed, FALSE on error.
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* MT safe.
|
|
Packit |
0652a1 |
*/
|
|
Packit |
0652a1 |
gboolean
|
|
Packit |
0652a1 |
gst_audio_ring_buffer_close_device (GstAudioRingBuffer * buf)
|
|
Packit |
0652a1 |
{
|
|
Packit |
0652a1 |
gboolean res = TRUE;
|
|
Packit |
0652a1 |
GstAudioRingBufferClass *rclass;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
g_return_val_if_fail (GST_IS_AUDIO_RING_BUFFER (buf), FALSE);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
GST_DEBUG_OBJECT (buf, "closing device");
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
GST_OBJECT_LOCK (buf);
|
|
Packit |
0652a1 |
if (G_UNLIKELY (!buf->open))
|
|
Packit |
0652a1 |
goto was_closed;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
if (G_UNLIKELY (buf->acquired))
|
|
Packit |
0652a1 |
goto was_acquired;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
buf->open = FALSE;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
rclass = GST_AUDIO_RING_BUFFER_GET_CLASS (buf);
|
|
Packit |
0652a1 |
if (G_LIKELY (rclass->close_device))
|
|
Packit |
0652a1 |
res = rclass->close_device (buf);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
if (G_UNLIKELY (!res))
|
|
Packit |
0652a1 |
goto close_error;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
GST_DEBUG_OBJECT (buf, "closed device");
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
done:
|
|
Packit |
0652a1 |
GST_OBJECT_UNLOCK (buf);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
return res;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/* ERRORS */
|
|
Packit |
0652a1 |
was_closed:
|
|
Packit |
0652a1 |
{
|
|
Packit |
0652a1 |
GST_DEBUG_OBJECT (buf, "Device for ring buffer already closed");
|
|
Packit |
0652a1 |
g_warning ("Device for ring buffer %p already closed, fix your code", buf);
|
|
Packit |
0652a1 |
res = TRUE;
|
|
Packit |
0652a1 |
goto done;
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
was_acquired:
|
|
Packit |
0652a1 |
{
|
|
Packit |
0652a1 |
GST_DEBUG_OBJECT (buf, "Resources for ring buffer still acquired");
|
|
Packit |
0652a1 |
g_critical ("Resources for ring buffer %p still acquired", buf);
|
|
Packit |
0652a1 |
res = FALSE;
|
|
Packit |
0652a1 |
goto done;
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
close_error:
|
|
Packit |
0652a1 |
{
|
|
Packit |
0652a1 |
buf->open = TRUE;
|
|
Packit |
0652a1 |
GST_DEBUG_OBJECT (buf, "error closing device");
|
|
Packit |
0652a1 |
goto done;
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/**
|
|
Packit |
0652a1 |
* gst_audio_ring_buffer_device_is_open:
|
|
Packit |
0652a1 |
* @buf: the #GstAudioRingBuffer
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* Checks the status of the device associated with the ring buffer.
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* Returns: TRUE if the device was open, FALSE if it was closed.
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* MT safe.
|
|
Packit |
0652a1 |
*/
|
|
Packit |
0652a1 |
gboolean
|
|
Packit |
0652a1 |
gst_audio_ring_buffer_device_is_open (GstAudioRingBuffer * buf)
|
|
Packit |
0652a1 |
{
|
|
Packit |
0652a1 |
gboolean res = TRUE;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
g_return_val_if_fail (GST_IS_AUDIO_RING_BUFFER (buf), FALSE);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
GST_OBJECT_LOCK (buf);
|
|
Packit |
0652a1 |
res = buf->open;
|
|
Packit |
0652a1 |
GST_OBJECT_UNLOCK (buf);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
return res;
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/**
|
|
Packit |
0652a1 |
* gst_audio_ring_buffer_acquire:
|
|
Packit |
0652a1 |
* @buf: the #GstAudioRingBuffer to acquire
|
|
Packit |
0652a1 |
* @spec: the specs of the buffer
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* Allocate the resources for the ringbuffer. This function fills
|
|
Packit |
0652a1 |
* in the data pointer of the ring buffer with a valid #GstBuffer
|
|
Packit |
0652a1 |
* to which samples can be written.
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* Returns: TRUE if the device could be acquired, FALSE on error.
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* MT safe.
|
|
Packit |
0652a1 |
*/
|
|
Packit |
0652a1 |
gboolean
|
|
Packit |
0652a1 |
gst_audio_ring_buffer_acquire (GstAudioRingBuffer * buf,
|
|
Packit |
0652a1 |
GstAudioRingBufferSpec * spec)
|
|
Packit |
0652a1 |
{
|
|
Packit |
0652a1 |
gboolean res = FALSE;
|
|
Packit |
0652a1 |
GstAudioRingBufferClass *rclass;
|
|
Packit |
0652a1 |
gint segsize, bpf, i;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
g_return_val_if_fail (GST_IS_AUDIO_RING_BUFFER (buf), FALSE);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
GST_DEBUG_OBJECT (buf, "acquiring device %p", buf);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
GST_OBJECT_LOCK (buf);
|
|
Packit |
0652a1 |
if (G_UNLIKELY (!buf->open))
|
|
Packit |
0652a1 |
goto not_opened;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
if (G_UNLIKELY (buf->acquired))
|
|
Packit |
0652a1 |
goto was_acquired;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
buf->acquired = TRUE;
|
|
Packit |
0652a1 |
buf->need_reorder = FALSE;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
rclass = GST_AUDIO_RING_BUFFER_GET_CLASS (buf);
|
|
Packit |
0652a1 |
if (G_LIKELY (rclass->acquire))
|
|
Packit |
0652a1 |
res = rclass->acquire (buf, spec);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/* Only reorder for raw audio */
|
|
Packit |
0652a1 |
buf->need_reorder = (buf->need_reorder
|
|
Packit |
0652a1 |
&& buf->spec.type == GST_AUDIO_RING_BUFFER_FORMAT_TYPE_RAW);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
if (G_UNLIKELY (!res))
|
|
Packit |
0652a1 |
goto acquire_failed;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
GST_INFO_OBJECT (buf, "Allocating an array for %d timestamps",
|
|
Packit |
0652a1 |
spec->segtotal);
|
|
Packit |
0652a1 |
buf->timestamps = g_slice_alloc0 (sizeof (GstClockTime) * spec->segtotal);
|
|
Packit |
0652a1 |
/* initialize array with invalid timestamps */
|
|
Packit |
0652a1 |
for (i = 0; i < spec->segtotal; i++) {
|
|
Packit |
0652a1 |
buf->timestamps[i] = GST_CLOCK_TIME_NONE;
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
if (G_UNLIKELY ((bpf = buf->spec.info.bpf) == 0))
|
|
Packit |
0652a1 |
goto invalid_bpf;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/* if the seglatency was overwritten with something else than -1, use it, else
|
|
Packit |
0652a1 |
* assume segtotal as the latency */
|
|
Packit |
0652a1 |
if (buf->spec.seglatency == -1)
|
|
Packit |
0652a1 |
buf->spec.seglatency = buf->spec.segtotal;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
segsize = buf->spec.segsize;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
buf->samples_per_seg = segsize / bpf;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/* create an empty segment */
|
|
Packit |
0652a1 |
g_free (buf->empty_seg);
|
|
Packit |
0652a1 |
buf->empty_seg = g_malloc (segsize);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
if (buf->spec.type == GST_AUDIO_RING_BUFFER_FORMAT_TYPE_RAW) {
|
|
Packit |
0652a1 |
gst_audio_format_fill_silence (buf->spec.info.finfo, buf->empty_seg,
|
|
Packit |
0652a1 |
segsize);
|
|
Packit |
0652a1 |
} else {
|
|
Packit |
0652a1 |
/* FIXME, non-raw formats get 0 as the empty sample */
|
|
Packit |
0652a1 |
memset (buf->empty_seg, 0, segsize);
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
GST_DEBUG_OBJECT (buf, "acquired device");
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
done:
|
|
Packit |
0652a1 |
GST_OBJECT_UNLOCK (buf);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
return res;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/* ERRORS */
|
|
Packit |
0652a1 |
not_opened:
|
|
Packit |
0652a1 |
{
|
|
Packit |
0652a1 |
GST_DEBUG_OBJECT (buf, "device not opened");
|
|
Packit |
0652a1 |
g_critical ("Device for %p not opened", buf);
|
|
Packit |
0652a1 |
res = FALSE;
|
|
Packit |
0652a1 |
goto done;
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
was_acquired:
|
|
Packit |
0652a1 |
{
|
|
Packit |
0652a1 |
res = TRUE;
|
|
Packit |
0652a1 |
GST_DEBUG_OBJECT (buf, "device was acquired");
|
|
Packit |
0652a1 |
goto done;
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
acquire_failed:
|
|
Packit |
0652a1 |
{
|
|
Packit |
0652a1 |
buf->acquired = FALSE;
|
|
Packit |
0652a1 |
GST_DEBUG_OBJECT (buf, "failed to acquire device");
|
|
Packit |
0652a1 |
goto done;
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
invalid_bpf:
|
|
Packit |
0652a1 |
{
|
|
Packit |
0652a1 |
g_warning
|
|
Packit |
0652a1 |
("invalid bytes_per_frame from acquire ringbuffer %p, fix the element",
|
|
Packit |
0652a1 |
buf);
|
|
Packit |
0652a1 |
buf->acquired = FALSE;
|
|
Packit |
0652a1 |
res = FALSE;
|
|
Packit |
0652a1 |
goto done;
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/**
|
|
Packit |
0652a1 |
* gst_audio_ring_buffer_release:
|
|
Packit |
0652a1 |
* @buf: the #GstAudioRingBuffer to release
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* Free the resources of the ringbuffer.
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* Returns: TRUE if the device could be released, FALSE on error.
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* MT safe.
|
|
Packit |
0652a1 |
*/
|
|
Packit |
0652a1 |
gboolean
|
|
Packit |
0652a1 |
gst_audio_ring_buffer_release (GstAudioRingBuffer * buf)
|
|
Packit |
0652a1 |
{
|
|
Packit |
0652a1 |
gboolean res = FALSE;
|
|
Packit |
0652a1 |
GstAudioRingBufferClass *rclass;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
g_return_val_if_fail (GST_IS_AUDIO_RING_BUFFER (buf), FALSE);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
GST_DEBUG_OBJECT (buf, "releasing device");
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
gst_audio_ring_buffer_stop (buf);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
GST_OBJECT_LOCK (buf);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
if (G_LIKELY (buf->timestamps)) {
|
|
Packit |
0652a1 |
GST_INFO_OBJECT (buf, "Freeing timestamp buffer, %d entries",
|
|
Packit |
0652a1 |
buf->spec.segtotal);
|
|
Packit |
0652a1 |
g_slice_free1 (sizeof (GstClockTime) * buf->spec.segtotal, buf->timestamps);
|
|
Packit |
0652a1 |
buf->timestamps = NULL;
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
if (G_UNLIKELY (!buf->acquired))
|
|
Packit |
0652a1 |
goto was_released;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
buf->acquired = FALSE;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/* if this fails, something is wrong in this file */
|
|
Packit |
0652a1 |
g_assert (buf->open);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
rclass = GST_AUDIO_RING_BUFFER_GET_CLASS (buf);
|
|
Packit |
0652a1 |
if (G_LIKELY (rclass->release))
|
|
Packit |
0652a1 |
res = rclass->release (buf);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/* signal any waiters */
|
|
Packit |
0652a1 |
GST_DEBUG_OBJECT (buf, "signal waiter");
|
|
Packit |
0652a1 |
GST_AUDIO_RING_BUFFER_SIGNAL (buf);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
if (G_UNLIKELY (!res))
|
|
Packit |
0652a1 |
goto release_failed;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
g_atomic_int_set (&buf->segdone, 0);
|
|
Packit |
0652a1 |
buf->segbase = 0;
|
|
Packit |
0652a1 |
g_free (buf->empty_seg);
|
|
Packit |
0652a1 |
buf->empty_seg = NULL;
|
|
Packit |
0652a1 |
gst_caps_replace (&buf->spec.caps, NULL);
|
|
Packit |
0652a1 |
gst_audio_info_init (&buf->spec.info);
|
|
Packit |
0652a1 |
GST_DEBUG_OBJECT (buf, "released device");
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
done:
|
|
Packit |
0652a1 |
GST_OBJECT_UNLOCK (buf);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
return res;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/* ERRORS */
|
|
Packit |
0652a1 |
was_released:
|
|
Packit |
0652a1 |
{
|
|
Packit |
0652a1 |
res = TRUE;
|
|
Packit |
0652a1 |
GST_DEBUG_OBJECT (buf, "device was released");
|
|
Packit |
0652a1 |
goto done;
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
release_failed:
|
|
Packit |
0652a1 |
{
|
|
Packit |
0652a1 |
buf->acquired = TRUE;
|
|
Packit |
0652a1 |
GST_DEBUG_OBJECT (buf, "failed to release device");
|
|
Packit |
0652a1 |
goto done;
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/**
|
|
Packit |
0652a1 |
* gst_audio_ring_buffer_is_acquired:
|
|
Packit |
0652a1 |
* @buf: the #GstAudioRingBuffer to check
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* Check if the ringbuffer is acquired and ready to use.
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* Returns: TRUE if the ringbuffer is acquired, FALSE on error.
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* MT safe.
|
|
Packit |
0652a1 |
*/
|
|
Packit |
0652a1 |
gboolean
|
|
Packit |
0652a1 |
gst_audio_ring_buffer_is_acquired (GstAudioRingBuffer * buf)
|
|
Packit |
0652a1 |
{
|
|
Packit |
0652a1 |
gboolean res;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
g_return_val_if_fail (GST_IS_AUDIO_RING_BUFFER (buf), FALSE);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
GST_OBJECT_LOCK (buf);
|
|
Packit |
0652a1 |
res = buf->acquired;
|
|
Packit |
0652a1 |
GST_OBJECT_UNLOCK (buf);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
return res;
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/**
|
|
Packit |
0652a1 |
* gst_audio_ring_buffer_activate:
|
|
Packit |
0652a1 |
* @buf: the #GstAudioRingBuffer to activate
|
|
Packit |
0652a1 |
* @active: the new mode
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* Activate @buf to start or stop pulling data.
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* MT safe.
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* Returns: TRUE if the device could be activated in the requested mode,
|
|
Packit |
0652a1 |
* FALSE on error.
|
|
Packit |
0652a1 |
*/
|
|
Packit |
0652a1 |
gboolean
|
|
Packit |
0652a1 |
gst_audio_ring_buffer_activate (GstAudioRingBuffer * buf, gboolean active)
|
|
Packit |
0652a1 |
{
|
|
Packit |
0652a1 |
gboolean res = FALSE;
|
|
Packit |
0652a1 |
GstAudioRingBufferClass *rclass;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
g_return_val_if_fail (GST_IS_AUDIO_RING_BUFFER (buf), FALSE);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
GST_DEBUG_OBJECT (buf, "activate device");
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
GST_OBJECT_LOCK (buf);
|
|
Packit |
0652a1 |
if (G_UNLIKELY (active && !buf->acquired))
|
|
Packit |
0652a1 |
goto not_acquired;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
if (G_UNLIKELY (buf->active == active))
|
|
Packit |
0652a1 |
goto was_active;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
rclass = GST_AUDIO_RING_BUFFER_GET_CLASS (buf);
|
|
Packit |
0652a1 |
/* if there is no activate function we assume it was started/released
|
|
Packit |
0652a1 |
* in the acquire method */
|
|
Packit |
0652a1 |
if (G_LIKELY (rclass->activate))
|
|
Packit |
0652a1 |
res = rclass->activate (buf, active);
|
|
Packit |
0652a1 |
else
|
|
Packit |
0652a1 |
res = TRUE;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
if (G_UNLIKELY (!res))
|
|
Packit |
0652a1 |
goto activate_failed;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
buf->active = active;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
done:
|
|
Packit |
0652a1 |
GST_OBJECT_UNLOCK (buf);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
return res;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/* ERRORS */
|
|
Packit |
0652a1 |
not_acquired:
|
|
Packit |
0652a1 |
{
|
|
Packit |
0652a1 |
GST_DEBUG_OBJECT (buf, "device not acquired");
|
|
Packit |
0652a1 |
g_critical ("Device for %p not acquired", buf);
|
|
Packit |
0652a1 |
res = FALSE;
|
|
Packit |
0652a1 |
goto done;
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
was_active:
|
|
Packit |
0652a1 |
{
|
|
Packit |
0652a1 |
res = TRUE;
|
|
Packit |
0652a1 |
GST_DEBUG_OBJECT (buf, "device was active in mode %d", active);
|
|
Packit |
0652a1 |
goto done;
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
activate_failed:
|
|
Packit |
0652a1 |
{
|
|
Packit |
0652a1 |
GST_DEBUG_OBJECT (buf, "failed to activate device");
|
|
Packit |
0652a1 |
goto done;
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/**
|
|
Packit |
0652a1 |
* gst_audio_ring_buffer_is_active:
|
|
Packit |
0652a1 |
* @buf: the #GstAudioRingBuffer
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* Check if @buf is activated.
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* MT safe.
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* Returns: TRUE if the device is active.
|
|
Packit |
0652a1 |
*/
|
|
Packit |
0652a1 |
gboolean
|
|
Packit |
0652a1 |
gst_audio_ring_buffer_is_active (GstAudioRingBuffer * buf)
|
|
Packit |
0652a1 |
{
|
|
Packit |
0652a1 |
gboolean res;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
g_return_val_if_fail (GST_IS_AUDIO_RING_BUFFER (buf), FALSE);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
GST_OBJECT_LOCK (buf);
|
|
Packit |
0652a1 |
res = buf->active;
|
|
Packit |
0652a1 |
GST_OBJECT_UNLOCK (buf);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
return res;
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/**
|
|
Packit |
0652a1 |
* gst_audio_ring_buffer_set_flushing:
|
|
Packit |
0652a1 |
* @buf: the #GstAudioRingBuffer to flush
|
|
Packit |
0652a1 |
* @flushing: the new mode
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* Set the ringbuffer to flushing mode or normal mode.
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* MT safe.
|
|
Packit |
0652a1 |
*/
|
|
Packit |
0652a1 |
void
|
|
Packit |
0652a1 |
gst_audio_ring_buffer_set_flushing (GstAudioRingBuffer * buf, gboolean flushing)
|
|
Packit |
0652a1 |
{
|
|
Packit |
0652a1 |
g_return_if_fail (GST_IS_AUDIO_RING_BUFFER (buf));
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
GST_OBJECT_LOCK (buf);
|
|
Packit |
0652a1 |
buf->flushing = flushing;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
if (flushing) {
|
|
Packit |
0652a1 |
gst_audio_ring_buffer_pause_unlocked (buf);
|
|
Packit |
0652a1 |
} else {
|
|
Packit |
0652a1 |
gst_audio_ring_buffer_clear_all (buf);
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
GST_OBJECT_UNLOCK (buf);
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/**
|
|
Packit |
0652a1 |
* gst_audio_ring_buffer_is_flushing:
|
|
Packit |
0652a1 |
* @buf: the #GstAudioRingBuffer
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* Check if @buf is flushing.
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* MT safe.
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* Returns: TRUE if the device is flushing.
|
|
Packit |
0652a1 |
*/
|
|
Packit |
0652a1 |
gboolean
|
|
Packit |
0652a1 |
gst_audio_ring_buffer_is_flushing (GstAudioRingBuffer * buf)
|
|
Packit |
0652a1 |
{
|
|
Packit |
0652a1 |
gboolean res;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
g_return_val_if_fail (GST_IS_AUDIO_RING_BUFFER (buf), TRUE);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
GST_OBJECT_LOCK (buf);
|
|
Packit |
0652a1 |
res = buf->flushing;
|
|
Packit |
0652a1 |
GST_OBJECT_UNLOCK (buf);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
return res;
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/**
|
|
Packit |
0652a1 |
* gst_audio_ring_buffer_start:
|
|
Packit |
0652a1 |
* @buf: the #GstAudioRingBuffer to start
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* Start processing samples from the ringbuffer.
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* Returns: TRUE if the device could be started, FALSE on error.
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* MT safe.
|
|
Packit |
0652a1 |
*/
|
|
Packit |
0652a1 |
gboolean
|
|
Packit |
0652a1 |
gst_audio_ring_buffer_start (GstAudioRingBuffer * buf)
|
|
Packit |
0652a1 |
{
|
|
Packit |
0652a1 |
gboolean res = FALSE;
|
|
Packit |
0652a1 |
GstAudioRingBufferClass *rclass;
|
|
Packit |
0652a1 |
gboolean resume = FALSE;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
g_return_val_if_fail (GST_IS_AUDIO_RING_BUFFER (buf), FALSE);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
GST_DEBUG_OBJECT (buf, "starting ringbuffer");
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
GST_OBJECT_LOCK (buf);
|
|
Packit |
0652a1 |
if (G_UNLIKELY (buf->flushing))
|
|
Packit |
0652a1 |
goto flushing;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
if (G_UNLIKELY (!buf->acquired))
|
|
Packit |
0652a1 |
goto not_acquired;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
if (G_UNLIKELY (!g_atomic_int_get (&buf->may_start)))
|
|
Packit |
0652a1 |
goto may_not_start;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/* if stopped, set to started */
|
|
Packit |
0652a1 |
res = g_atomic_int_compare_and_exchange (&buf->state,
|
|
Packit |
0652a1 |
GST_AUDIO_RING_BUFFER_STATE_STOPPED, GST_AUDIO_RING_BUFFER_STATE_STARTED);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
if (!res) {
|
|
Packit |
0652a1 |
GST_DEBUG_OBJECT (buf, "was not stopped, try paused");
|
|
Packit |
0652a1 |
/* was not stopped, try from paused */
|
|
Packit |
0652a1 |
res = g_atomic_int_compare_and_exchange (&buf->state,
|
|
Packit |
0652a1 |
GST_AUDIO_RING_BUFFER_STATE_PAUSED,
|
|
Packit |
0652a1 |
GST_AUDIO_RING_BUFFER_STATE_STARTED);
|
|
Packit |
0652a1 |
if (!res) {
|
|
Packit |
0652a1 |
/* was not paused either, must be started then */
|
|
Packit |
0652a1 |
res = TRUE;
|
|
Packit |
0652a1 |
GST_DEBUG_OBJECT (buf, "was not paused, must have been started");
|
|
Packit |
0652a1 |
goto done;
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
resume = TRUE;
|
|
Packit |
0652a1 |
GST_DEBUG_OBJECT (buf, "resuming");
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
rclass = GST_AUDIO_RING_BUFFER_GET_CLASS (buf);
|
|
Packit |
0652a1 |
if (resume) {
|
|
Packit |
0652a1 |
if (G_LIKELY (rclass->resume))
|
|
Packit |
0652a1 |
res = rclass->resume (buf);
|
|
Packit |
0652a1 |
} else {
|
|
Packit |
0652a1 |
if (G_LIKELY (rclass->start))
|
|
Packit |
0652a1 |
res = rclass->start (buf);
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
if (G_UNLIKELY (!res)) {
|
|
Packit |
0652a1 |
buf->state = GST_AUDIO_RING_BUFFER_STATE_PAUSED;
|
|
Packit |
0652a1 |
GST_DEBUG_OBJECT (buf, "failed to start");
|
|
Packit |
0652a1 |
} else {
|
|
Packit |
0652a1 |
GST_DEBUG_OBJECT (buf, "started");
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
done:
|
|
Packit |
0652a1 |
GST_OBJECT_UNLOCK (buf);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
return res;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
flushing:
|
|
Packit |
0652a1 |
{
|
|
Packit |
0652a1 |
GST_DEBUG_OBJECT (buf, "we are flushing");
|
|
Packit |
0652a1 |
GST_OBJECT_UNLOCK (buf);
|
|
Packit |
0652a1 |
return FALSE;
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
not_acquired:
|
|
Packit |
0652a1 |
{
|
|
Packit |
0652a1 |
GST_DEBUG_OBJECT (buf, "we are not acquired");
|
|
Packit |
0652a1 |
GST_OBJECT_UNLOCK (buf);
|
|
Packit |
0652a1 |
return FALSE;
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
may_not_start:
|
|
Packit |
0652a1 |
{
|
|
Packit |
0652a1 |
GST_DEBUG_OBJECT (buf, "we may not start");
|
|
Packit |
0652a1 |
GST_OBJECT_UNLOCK (buf);
|
|
Packit |
0652a1 |
return FALSE;
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
static gboolean
|
|
Packit |
0652a1 |
gst_audio_ring_buffer_pause_unlocked (GstAudioRingBuffer * buf)
|
|
Packit |
0652a1 |
{
|
|
Packit |
0652a1 |
gboolean res = FALSE;
|
|
Packit |
0652a1 |
GstAudioRingBufferClass *rclass;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
GST_DEBUG_OBJECT (buf, "pausing ringbuffer");
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/* if started, set to paused */
|
|
Packit |
0652a1 |
res = g_atomic_int_compare_and_exchange (&buf->state,
|
|
Packit |
0652a1 |
GST_AUDIO_RING_BUFFER_STATE_STARTED, GST_AUDIO_RING_BUFFER_STATE_PAUSED);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
if (!res)
|
|
Packit |
0652a1 |
goto not_started;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/* signal any waiters */
|
|
Packit |
0652a1 |
GST_DEBUG_OBJECT (buf, "signal waiter");
|
|
Packit |
0652a1 |
GST_AUDIO_RING_BUFFER_SIGNAL (buf);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
rclass = GST_AUDIO_RING_BUFFER_GET_CLASS (buf);
|
|
Packit |
0652a1 |
if (G_LIKELY (rclass->pause))
|
|
Packit |
0652a1 |
res = rclass->pause (buf);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
if (G_UNLIKELY (!res)) {
|
|
Packit |
0652a1 |
buf->state = GST_AUDIO_RING_BUFFER_STATE_STARTED;
|
|
Packit |
0652a1 |
GST_DEBUG_OBJECT (buf, "failed to pause");
|
|
Packit |
0652a1 |
} else {
|
|
Packit |
0652a1 |
GST_DEBUG_OBJECT (buf, "paused");
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
return res;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
not_started:
|
|
Packit |
0652a1 |
{
|
|
Packit |
0652a1 |
/* was not started */
|
|
Packit |
0652a1 |
GST_DEBUG_OBJECT (buf, "was not started");
|
|
Packit |
0652a1 |
return TRUE;
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/**
|
|
Packit |
0652a1 |
* gst_audio_ring_buffer_pause:
|
|
Packit |
0652a1 |
* @buf: the #GstAudioRingBuffer to pause
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* Pause processing samples from the ringbuffer.
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* Returns: TRUE if the device could be paused, FALSE on error.
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* MT safe.
|
|
Packit |
0652a1 |
*/
|
|
Packit |
0652a1 |
gboolean
|
|
Packit |
0652a1 |
gst_audio_ring_buffer_pause (GstAudioRingBuffer * buf)
|
|
Packit |
0652a1 |
{
|
|
Packit |
0652a1 |
gboolean res = FALSE;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
g_return_val_if_fail (GST_IS_AUDIO_RING_BUFFER (buf), FALSE);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
GST_OBJECT_LOCK (buf);
|
|
Packit |
0652a1 |
if (G_UNLIKELY (buf->flushing))
|
|
Packit |
0652a1 |
goto flushing;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
if (G_UNLIKELY (!buf->acquired))
|
|
Packit |
0652a1 |
goto not_acquired;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
res = gst_audio_ring_buffer_pause_unlocked (buf);
|
|
Packit |
0652a1 |
GST_OBJECT_UNLOCK (buf);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
return res;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/* ERRORS */
|
|
Packit |
0652a1 |
flushing:
|
|
Packit |
0652a1 |
{
|
|
Packit |
0652a1 |
GST_DEBUG_OBJECT (buf, "we are flushing");
|
|
Packit |
0652a1 |
GST_OBJECT_UNLOCK (buf);
|
|
Packit |
0652a1 |
return FALSE;
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
not_acquired:
|
|
Packit |
0652a1 |
{
|
|
Packit |
0652a1 |
GST_DEBUG_OBJECT (buf, "not acquired");
|
|
Packit |
0652a1 |
GST_OBJECT_UNLOCK (buf);
|
|
Packit |
0652a1 |
return FALSE;
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/**
|
|
Packit |
0652a1 |
* gst_audio_ring_buffer_stop:
|
|
Packit |
0652a1 |
* @buf: the #GstAudioRingBuffer to stop
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* Stop processing samples from the ringbuffer.
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* Returns: TRUE if the device could be stopped, FALSE on error.
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* MT safe.
|
|
Packit |
0652a1 |
*/
|
|
Packit |
0652a1 |
gboolean
|
|
Packit |
0652a1 |
gst_audio_ring_buffer_stop (GstAudioRingBuffer * buf)
|
|
Packit |
0652a1 |
{
|
|
Packit |
0652a1 |
gboolean res = FALSE;
|
|
Packit |
0652a1 |
GstAudioRingBufferClass *rclass;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
g_return_val_if_fail (GST_IS_AUDIO_RING_BUFFER (buf), FALSE);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
GST_DEBUG_OBJECT (buf, "stopping");
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
GST_OBJECT_LOCK (buf);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/* if started, set to stopped */
|
|
Packit |
0652a1 |
res = g_atomic_int_compare_and_exchange (&buf->state,
|
|
Packit |
0652a1 |
GST_AUDIO_RING_BUFFER_STATE_STARTED, GST_AUDIO_RING_BUFFER_STATE_STOPPED);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
if (!res) {
|
|
Packit |
0652a1 |
GST_DEBUG_OBJECT (buf, "was not started, try paused");
|
|
Packit |
0652a1 |
/* was not started, try from paused */
|
|
Packit |
0652a1 |
res = g_atomic_int_compare_and_exchange (&buf->state,
|
|
Packit |
0652a1 |
GST_AUDIO_RING_BUFFER_STATE_PAUSED,
|
|
Packit |
0652a1 |
GST_AUDIO_RING_BUFFER_STATE_STOPPED);
|
|
Packit |
0652a1 |
if (!res) {
|
|
Packit |
0652a1 |
/* was not paused either, must have been stopped then */
|
|
Packit |
0652a1 |
res = TRUE;
|
|
Packit |
0652a1 |
GST_DEBUG_OBJECT (buf, "was not paused, must have been stopped");
|
|
Packit |
0652a1 |
goto done;
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/* signal any waiters */
|
|
Packit |
0652a1 |
GST_DEBUG_OBJECT (buf, "signal waiter");
|
|
Packit |
0652a1 |
GST_AUDIO_RING_BUFFER_SIGNAL (buf);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
rclass = GST_AUDIO_RING_BUFFER_GET_CLASS (buf);
|
|
Packit |
0652a1 |
if (G_LIKELY (rclass->stop))
|
|
Packit |
0652a1 |
res = rclass->stop (buf);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
if (G_UNLIKELY (!res)) {
|
|
Packit |
0652a1 |
buf->state = GST_AUDIO_RING_BUFFER_STATE_STARTED;
|
|
Packit |
0652a1 |
GST_DEBUG_OBJECT (buf, "failed to stop");
|
|
Packit |
0652a1 |
} else {
|
|
Packit |
0652a1 |
GST_DEBUG_OBJECT (buf, "stopped");
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
done:
|
|
Packit |
0652a1 |
GST_OBJECT_UNLOCK (buf);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
return res;
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/**
|
|
Packit |
0652a1 |
* gst_audio_ring_buffer_delay:
|
|
Packit |
0652a1 |
* @buf: the #GstAudioRingBuffer to query
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* Get the number of samples queued in the audio device. This is
|
|
Packit |
0652a1 |
* usually less than the segment size but can be bigger when the
|
|
Packit |
0652a1 |
* implementation uses another internal buffer between the audio
|
|
Packit |
0652a1 |
* device.
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* For playback ringbuffers this is the amount of samples transfered from the
|
|
Packit |
0652a1 |
* ringbuffer to the device but still not played.
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* For capture ringbuffers this is the amount of samples in the device that are
|
|
Packit |
0652a1 |
* not yet transfered to the ringbuffer.
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* Returns: The number of samples queued in the audio device.
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* MT safe.
|
|
Packit |
0652a1 |
*/
|
|
Packit |
0652a1 |
guint
|
|
Packit |
0652a1 |
gst_audio_ring_buffer_delay (GstAudioRingBuffer * buf)
|
|
Packit |
0652a1 |
{
|
|
Packit |
0652a1 |
GstAudioRingBufferClass *rclass;
|
|
Packit |
0652a1 |
guint res;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
g_return_val_if_fail (GST_IS_AUDIO_RING_BUFFER (buf), 0);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/* buffer must be acquired */
|
|
Packit |
0652a1 |
if (G_UNLIKELY (!gst_audio_ring_buffer_is_acquired (buf)))
|
|
Packit |
0652a1 |
goto not_acquired;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
rclass = GST_AUDIO_RING_BUFFER_GET_CLASS (buf);
|
|
Packit |
0652a1 |
if (G_LIKELY (rclass->delay))
|
|
Packit |
0652a1 |
res = rclass->delay (buf);
|
|
Packit |
0652a1 |
else
|
|
Packit |
0652a1 |
res = 0;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
return res;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
not_acquired:
|
|
Packit |
0652a1 |
{
|
|
Packit |
0652a1 |
GST_DEBUG_OBJECT (buf, "not acquired");
|
|
Packit |
0652a1 |
return 0;
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/**
|
|
Packit |
0652a1 |
* gst_audio_ring_buffer_samples_done:
|
|
Packit |
0652a1 |
* @buf: the #GstAudioRingBuffer to query
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* Get the number of samples that were processed by the ringbuffer
|
|
Packit |
0652a1 |
* since it was last started. This does not include the number of samples not
|
|
Packit |
0652a1 |
* yet processed (see gst_audio_ring_buffer_delay()).
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* Returns: The number of samples processed by the ringbuffer.
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* MT safe.
|
|
Packit |
0652a1 |
*/
|
|
Packit |
0652a1 |
guint64
|
|
Packit |
0652a1 |
gst_audio_ring_buffer_samples_done (GstAudioRingBuffer * buf)
|
|
Packit |
0652a1 |
{
|
|
Packit |
0652a1 |
gint segdone;
|
|
Packit |
0652a1 |
guint64 samples;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
g_return_val_if_fail (GST_IS_AUDIO_RING_BUFFER (buf), 0);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/* get the amount of segments we processed */
|
|
Packit |
0652a1 |
segdone = g_atomic_int_get (&buf->segdone);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/* convert to samples */
|
|
Packit |
0652a1 |
samples = ((guint64) segdone) * buf->samples_per_seg;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
return samples;
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/**
|
|
Packit |
0652a1 |
* gst_audio_ring_buffer_set_sample:
|
|
Packit |
0652a1 |
* @buf: the #GstAudioRingBuffer to use
|
|
Packit |
0652a1 |
* @sample: the sample number to set
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* Make sure that the next sample written to the device is
|
|
Packit |
0652a1 |
* accounted for as being the @sample sample written to the
|
|
Packit |
0652a1 |
* device. This value will be used in reporting the current
|
|
Packit |
0652a1 |
* sample position of the ringbuffer.
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* This function will also clear the buffer with silence.
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* MT safe.
|
|
Packit |
0652a1 |
*/
|
|
Packit |
0652a1 |
void
|
|
Packit |
0652a1 |
gst_audio_ring_buffer_set_sample (GstAudioRingBuffer * buf, guint64 sample)
|
|
Packit |
0652a1 |
{
|
|
Packit |
0652a1 |
g_return_if_fail (GST_IS_AUDIO_RING_BUFFER (buf));
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
if (sample == -1)
|
|
Packit |
0652a1 |
sample = 0;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
if (G_UNLIKELY (buf->samples_per_seg == 0))
|
|
Packit |
0652a1 |
return;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/* FIXME, we assume the ringbuffer can restart at a random
|
|
Packit |
0652a1 |
* position, round down to the beginning and keep track of
|
|
Packit |
0652a1 |
* offset when calculating the processed samples. */
|
|
Packit |
0652a1 |
buf->segbase = buf->segdone - sample / buf->samples_per_seg;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
gst_audio_ring_buffer_clear_all (buf);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
GST_DEBUG_OBJECT (buf, "set sample to %" G_GUINT64_FORMAT ", segbase %d",
|
|
Packit |
0652a1 |
sample, buf->segbase);
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
static void
|
|
Packit |
0652a1 |
default_clear_all (GstAudioRingBuffer * buf)
|
|
Packit |
0652a1 |
{
|
|
Packit |
0652a1 |
gint i;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/* not fatal, we just are not negotiated yet */
|
|
Packit |
0652a1 |
if (G_UNLIKELY (buf->spec.segtotal <= 0))
|
|
Packit |
0652a1 |
return;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
GST_DEBUG_OBJECT (buf, "clear all segments");
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
for (i = 0; i < buf->spec.segtotal; i++) {
|
|
Packit |
0652a1 |
gst_audio_ring_buffer_clear (buf, i);
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/**
|
|
Packit |
0652a1 |
* gst_audio_ring_buffer_clear_all:
|
|
Packit |
0652a1 |
* @buf: the #GstAudioRingBuffer to clear
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* Fill the ringbuffer with silence.
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* MT safe.
|
|
Packit |
0652a1 |
*/
|
|
Packit |
0652a1 |
void
|
|
Packit |
0652a1 |
gst_audio_ring_buffer_clear_all (GstAudioRingBuffer * buf)
|
|
Packit |
0652a1 |
{
|
|
Packit |
0652a1 |
GstAudioRingBufferClass *rclass;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
g_return_if_fail (GST_IS_AUDIO_RING_BUFFER (buf));
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
rclass = GST_AUDIO_RING_BUFFER_GET_CLASS (buf);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
if (G_LIKELY (rclass->clear_all))
|
|
Packit |
0652a1 |
rclass->clear_all (buf);
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
static gboolean
|
|
Packit |
0652a1 |
wait_segment (GstAudioRingBuffer * buf)
|
|
Packit |
0652a1 |
{
|
|
Packit |
0652a1 |
gint segments;
|
|
Packit |
0652a1 |
gboolean wait = TRUE;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/* buffer must be started now or we deadlock since nobody is reading */
|
|
Packit |
0652a1 |
if (G_UNLIKELY (g_atomic_int_get (&buf->state) !=
|
|
Packit |
0652a1 |
GST_AUDIO_RING_BUFFER_STATE_STARTED)) {
|
|
Packit |
0652a1 |
/* see if we are allowed to start it */
|
|
Packit |
0652a1 |
if (G_UNLIKELY (!g_atomic_int_get (&buf->may_start)))
|
|
Packit |
0652a1 |
goto no_start;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
GST_DEBUG_OBJECT (buf, "start!");
|
|
Packit |
0652a1 |
segments = g_atomic_int_get (&buf->segdone);
|
|
Packit |
0652a1 |
gst_audio_ring_buffer_start (buf);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/* After starting, the writer may have wrote segments already and then we
|
|
Packit |
0652a1 |
* don't need to wait anymore */
|
|
Packit |
0652a1 |
if (G_LIKELY (g_atomic_int_get (&buf->segdone) != segments))
|
|
Packit |
0652a1 |
wait = FALSE;
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/* take lock first, then update our waiting flag */
|
|
Packit |
0652a1 |
GST_OBJECT_LOCK (buf);
|
|
Packit |
0652a1 |
if (G_UNLIKELY (buf->flushing))
|
|
Packit |
0652a1 |
goto flushing;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
if (G_UNLIKELY (g_atomic_int_get (&buf->state) !=
|
|
Packit |
0652a1 |
GST_AUDIO_RING_BUFFER_STATE_STARTED))
|
|
Packit |
0652a1 |
goto not_started;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
if (G_LIKELY (wait)) {
|
|
Packit |
0652a1 |
if (g_atomic_int_compare_and_exchange (&buf->waiting, 0, 1)) {
|
|
Packit |
0652a1 |
GST_DEBUG_OBJECT (buf, "waiting..");
|
|
Packit |
0652a1 |
GST_AUDIO_RING_BUFFER_WAIT (buf);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
if (G_UNLIKELY (buf->flushing))
|
|
Packit |
0652a1 |
goto flushing;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
if (G_UNLIKELY (g_atomic_int_get (&buf->state) !=
|
|
Packit |
0652a1 |
GST_AUDIO_RING_BUFFER_STATE_STARTED))
|
|
Packit |
0652a1 |
goto not_started;
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
GST_OBJECT_UNLOCK (buf);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
return TRUE;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/* ERROR */
|
|
Packit |
0652a1 |
not_started:
|
|
Packit |
0652a1 |
{
|
|
Packit |
0652a1 |
g_atomic_int_compare_and_exchange (&buf->waiting, 1, 0);
|
|
Packit |
0652a1 |
GST_DEBUG_OBJECT (buf, "stopped processing");
|
|
Packit |
0652a1 |
GST_OBJECT_UNLOCK (buf);
|
|
Packit |
0652a1 |
return FALSE;
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
flushing:
|
|
Packit |
0652a1 |
{
|
|
Packit |
0652a1 |
g_atomic_int_compare_and_exchange (&buf->waiting, 1, 0);
|
|
Packit |
0652a1 |
GST_DEBUG_OBJECT (buf, "flushing");
|
|
Packit |
0652a1 |
GST_OBJECT_UNLOCK (buf);
|
|
Packit |
0652a1 |
return FALSE;
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
no_start:
|
|
Packit |
0652a1 |
{
|
|
Packit |
0652a1 |
GST_DEBUG_OBJECT (buf, "not allowed to start");
|
|
Packit |
0652a1 |
return FALSE;
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
#define REORDER_SAMPLE(d, s, l) \
|
|
Packit |
0652a1 |
G_STMT_START { \
|
|
Packit |
0652a1 |
gint i; \
|
|
Packit |
0652a1 |
for (i = 0; i < channels; i++) { \
|
|
Packit |
0652a1 |
memcpy (d + reorder_map[i] * bps, s + i * bps, bps); \
|
|
Packit |
0652a1 |
} \
|
|
Packit |
0652a1 |
} G_STMT_END
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
#define REORDER_SAMPLES(d, s, len) \
|
|
Packit |
0652a1 |
G_STMT_START { \
|
|
Packit |
0652a1 |
gint i, len_ = len / bpf; \
|
|
Packit |
0652a1 |
guint8 *d_ = d, *s_ = s; \
|
|
Packit |
0652a1 |
for (i = 0; i < len_; i++) { \
|
|
Packit |
0652a1 |
REORDER_SAMPLE(d_, s_, bpf); \
|
|
Packit |
0652a1 |
d_ += bpf; \
|
|
Packit |
0652a1 |
s_ += bpf; \
|
|
Packit |
0652a1 |
} \
|
|
Packit |
0652a1 |
} G_STMT_END
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
#define FWD_SAMPLES(s,se,d,de,F) \
|
|
Packit |
0652a1 |
G_STMT_START { \
|
|
Packit |
0652a1 |
/* no rate conversion */ \
|
|
Packit |
0652a1 |
guint towrite = MIN (se + bpf - s, de - d); \
|
|
Packit |
0652a1 |
/* simple copy */ \
|
|
Packit |
0652a1 |
if (!skip) \
|
|
Packit |
0652a1 |
F (d, s, towrite); \
|
|
Packit |
0652a1 |
in_samples -= towrite / bpf; \
|
|
Packit |
0652a1 |
out_samples -= towrite / bpf; \
|
|
Packit |
0652a1 |
s += towrite; \
|
|
Packit |
0652a1 |
GST_DEBUG ("copy %u bytes", towrite); \
|
|
Packit |
0652a1 |
} G_STMT_END
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/* in_samples >= out_samples, rate > 1.0 */
|
|
Packit |
0652a1 |
#define FWD_UP_SAMPLES(s,se,d,de,F) \
|
|
Packit |
0652a1 |
G_STMT_START { \
|
|
Packit |
0652a1 |
guint8 *sb = s, *db = d; \
|
|
Packit |
0652a1 |
while (s <= se && d < de) { \
|
|
Packit |
0652a1 |
if (!skip) \
|
|
Packit |
0652a1 |
F (d, s, bpf); \
|
|
Packit |
0652a1 |
s += bpf; \
|
|
Packit |
0652a1 |
*accum += outr; \
|
|
Packit |
0652a1 |
if ((*accum << 1) >= inr) { \
|
|
Packit |
0652a1 |
*accum -= inr; \
|
|
Packit |
0652a1 |
d += bpf; \
|
|
Packit |
0652a1 |
} \
|
|
Packit |
0652a1 |
} \
|
|
Packit |
0652a1 |
in_samples -= (s - sb)/bpf; \
|
|
Packit |
0652a1 |
out_samples -= (d - db)/bpf; \
|
|
Packit |
0652a1 |
GST_DEBUG ("fwd_up end %d/%d",*accum,*toprocess); \
|
|
Packit |
0652a1 |
} G_STMT_END
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/* out_samples > in_samples, for rates smaller than 1.0 */
|
|
Packit |
0652a1 |
#define FWD_DOWN_SAMPLES(s,se,d,de,F) \
|
|
Packit |
0652a1 |
G_STMT_START { \
|
|
Packit |
0652a1 |
guint8 *sb = s, *db = d; \
|
|
Packit |
0652a1 |
while (s <= se && d < de) { \
|
|
Packit |
0652a1 |
if (!skip) \
|
|
Packit |
0652a1 |
F (d, s, bpf); \
|
|
Packit |
0652a1 |
d += bpf; \
|
|
Packit |
0652a1 |
*accum += inr; \
|
|
Packit |
0652a1 |
if ((*accum << 1) >= outr) { \
|
|
Packit |
0652a1 |
*accum -= outr; \
|
|
Packit |
0652a1 |
s += bpf; \
|
|
Packit |
0652a1 |
} \
|
|
Packit |
0652a1 |
} \
|
|
Packit |
0652a1 |
in_samples -= (s - sb)/bpf; \
|
|
Packit |
0652a1 |
out_samples -= (d - db)/bpf; \
|
|
Packit |
0652a1 |
GST_DEBUG ("fwd_down end %d/%d",*accum,*toprocess); \
|
|
Packit |
0652a1 |
} G_STMT_END
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
#define REV_UP_SAMPLES(s,se,d,de,F) \
|
|
Packit |
0652a1 |
G_STMT_START { \
|
|
Packit |
0652a1 |
guint8 *sb = se, *db = d; \
|
|
Packit |
0652a1 |
while (s <= se && d < de) { \
|
|
Packit |
0652a1 |
if (!skip) \
|
|
Packit |
0652a1 |
F (d, se, bpf); \
|
|
Packit |
0652a1 |
se -= bpf; \
|
|
Packit |
0652a1 |
*accum += outr; \
|
|
Packit |
0652a1 |
while (d < de && (*accum << 1) >= inr) { \
|
|
Packit |
0652a1 |
*accum -= inr; \
|
|
Packit |
0652a1 |
d += bpf; \
|
|
Packit |
0652a1 |
} \
|
|
Packit |
0652a1 |
} \
|
|
Packit |
0652a1 |
in_samples -= (sb - se)/bpf; \
|
|
Packit |
0652a1 |
out_samples -= (d - db)/bpf; \
|
|
Packit |
0652a1 |
GST_DEBUG ("rev_up end %d/%d",*accum,*toprocess); \
|
|
Packit |
0652a1 |
} G_STMT_END
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
#define REV_DOWN_SAMPLES(s,se,d,de,F) \
|
|
Packit |
0652a1 |
G_STMT_START { \
|
|
Packit |
0652a1 |
guint8 *sb = se, *db = d; \
|
|
Packit |
0652a1 |
while (s <= se && d < de) { \
|
|
Packit |
0652a1 |
if (!skip) \
|
|
Packit |
0652a1 |
F (d, se, bpf); \
|
|
Packit |
0652a1 |
d += bpf; \
|
|
Packit |
0652a1 |
*accum += inr; \
|
|
Packit |
0652a1 |
while (s <= se && (*accum << 1) >= outr) { \
|
|
Packit |
0652a1 |
*accum -= outr; \
|
|
Packit |
0652a1 |
se -= bpf; \
|
|
Packit |
0652a1 |
} \
|
|
Packit |
0652a1 |
} \
|
|
Packit |
0652a1 |
in_samples -= (sb - se)/bpf; \
|
|
Packit |
0652a1 |
out_samples -= (d - db)/bpf; \
|
|
Packit |
0652a1 |
GST_DEBUG ("rev_down end %d/%d",*accum,*toprocess); \
|
|
Packit |
0652a1 |
} G_STMT_END
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
static guint
|
|
Packit |
0652a1 |
default_commit (GstAudioRingBuffer * buf, guint64 * sample,
|
|
Packit |
0652a1 |
guint8 * data, gint in_samples, gint out_samples, gint * accum)
|
|
Packit |
0652a1 |
{
|
|
Packit |
0652a1 |
gint segdone;
|
|
Packit |
0652a1 |
gint segsize, segtotal, channels, bps, bpf, sps;
|
|
Packit |
0652a1 |
guint8 *dest, *data_end;
|
|
Packit |
0652a1 |
gint writeseg, sampleoff;
|
|
Packit |
0652a1 |
gint *toprocess;
|
|
Packit |
0652a1 |
gint inr, outr;
|
|
Packit |
0652a1 |
gboolean reverse;
|
|
Packit |
0652a1 |
gboolean need_reorder;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
g_return_val_if_fail (buf->memory != NULL, -1);
|
|
Packit |
0652a1 |
g_return_val_if_fail (data != NULL, -1);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
need_reorder = buf->need_reorder;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
channels = buf->spec.info.channels;
|
|
Packit |
0652a1 |
dest = buf->memory;
|
|
Packit |
0652a1 |
segsize = buf->spec.segsize;
|
|
Packit |
0652a1 |
segtotal = buf->spec.segtotal;
|
|
Packit |
0652a1 |
bpf = buf->spec.info.bpf;
|
|
Packit |
0652a1 |
bps = bpf / channels;
|
|
Packit |
0652a1 |
sps = buf->samples_per_seg;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
reverse = out_samples < 0;
|
|
Packit |
0652a1 |
out_samples = ABS (out_samples);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
if (in_samples >= out_samples)
|
|
Packit |
0652a1 |
toprocess = &in_samples;
|
|
Packit |
0652a1 |
else
|
|
Packit |
0652a1 |
toprocess = &out_samples;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
inr = in_samples - 1;
|
|
Packit |
0652a1 |
outr = out_samples - 1;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/* data_end points to the last sample we have to write, not past it. This is
|
|
Packit |
0652a1 |
* needed to properly handle reverse playback: it points to the last sample. */
|
|
Packit |
0652a1 |
data_end = data + (bpf * inr);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/* figure out the segment and the offset inside the segment where
|
|
Packit |
0652a1 |
* the first sample should be written. */
|
|
Packit |
0652a1 |
writeseg = *sample / sps;
|
|
Packit |
0652a1 |
sampleoff = (*sample % sps) * bpf;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
GST_DEBUG_OBJECT (buf, "write %d : %d", in_samples, out_samples);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/* write out all samples */
|
|
Packit |
0652a1 |
while (*toprocess > 0) {
|
|
Packit |
0652a1 |
gint avail;
|
|
Packit |
0652a1 |
guint8 *d, *d_end;
|
|
Packit |
0652a1 |
gint ws;
|
|
Packit |
0652a1 |
gboolean skip;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
while (TRUE) {
|
|
Packit |
0652a1 |
gint diff;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/* get the currently processed segment */
|
|
Packit |
0652a1 |
segdone = g_atomic_int_get (&buf->segdone) - buf->segbase;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/* see how far away it is from the write segment */
|
|
Packit |
0652a1 |
diff = writeseg - segdone;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
GST_DEBUG_OBJECT (buf,
|
|
Packit |
0652a1 |
"pointer at %d, write to %d-%d, diff %d, segtotal %d, segsize %d, base %d",
|
|
Packit |
0652a1 |
segdone, writeseg, sampleoff, diff, segtotal, segsize, buf->segbase);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/* segment too far ahead, writer too slow, we need to drop, hopefully UNLIKELY */
|
|
Packit |
0652a1 |
if (G_UNLIKELY (diff < 0)) {
|
|
Packit |
0652a1 |
/* we need to drop one segment at a time, pretend we wrote a segment. */
|
|
Packit |
0652a1 |
skip = TRUE;
|
|
Packit |
0652a1 |
break;
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/* write segment is within writable range, we can break the loop and
|
|
Packit |
0652a1 |
* start writing the data. */
|
|
Packit |
0652a1 |
if (diff < segtotal) {
|
|
Packit |
0652a1 |
skip = FALSE;
|
|
Packit |
0652a1 |
break;
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/* else we need to wait for the segment to become writable. */
|
|
Packit |
0652a1 |
if (!wait_segment (buf))
|
|
Packit |
0652a1 |
goto not_started;
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/* we can write now */
|
|
Packit |
0652a1 |
ws = writeseg % segtotal;
|
|
Packit |
0652a1 |
avail = MIN (segsize - sampleoff, bpf * out_samples);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
d = dest + (ws * segsize) + sampleoff;
|
|
Packit |
0652a1 |
d_end = d + avail;
|
|
Packit |
0652a1 |
*sample += avail / bpf;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
GST_DEBUG_OBJECT (buf, "write @%p seg %d, sps %d, off %d, avail %d",
|
|
Packit |
0652a1 |
dest + ws * segsize, ws, sps, sampleoff, avail);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
if (need_reorder) {
|
|
Packit |
0652a1 |
gint *reorder_map = buf->channel_reorder_map;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
if (G_LIKELY (inr == outr && !reverse)) {
|
|
Packit |
0652a1 |
/* no rate conversion, simply copy samples */
|
|
Packit |
0652a1 |
FWD_SAMPLES (data, data_end, d, d_end, REORDER_SAMPLES);
|
|
Packit |
0652a1 |
} else if (!reverse) {
|
|
Packit |
0652a1 |
if (inr >= outr)
|
|
Packit |
0652a1 |
/* forward speed up */
|
|
Packit |
0652a1 |
FWD_UP_SAMPLES (data, data_end, d, d_end, REORDER_SAMPLE);
|
|
Packit |
0652a1 |
else
|
|
Packit |
0652a1 |
/* forward slow down */
|
|
Packit |
0652a1 |
FWD_DOWN_SAMPLES (data, data_end, d, d_end, REORDER_SAMPLE);
|
|
Packit |
0652a1 |
} else {
|
|
Packit |
0652a1 |
if (inr >= outr)
|
|
Packit |
0652a1 |
/* reverse speed up */
|
|
Packit |
0652a1 |
REV_UP_SAMPLES (data, data_end, d, d_end, REORDER_SAMPLE);
|
|
Packit |
0652a1 |
else
|
|
Packit |
0652a1 |
/* reverse slow down */
|
|
Packit |
0652a1 |
REV_DOWN_SAMPLES (data, data_end, d, d_end, REORDER_SAMPLE);
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
} else {
|
|
Packit |
0652a1 |
if (G_LIKELY (inr == outr && !reverse)) {
|
|
Packit |
0652a1 |
/* no rate conversion, simply copy samples */
|
|
Packit |
0652a1 |
FWD_SAMPLES (data, data_end, d, d_end, memcpy);
|
|
Packit |
0652a1 |
} else if (!reverse) {
|
|
Packit |
0652a1 |
if (inr >= outr)
|
|
Packit |
0652a1 |
/* forward speed up */
|
|
Packit |
0652a1 |
FWD_UP_SAMPLES (data, data_end, d, d_end, memcpy);
|
|
Packit |
0652a1 |
else
|
|
Packit |
0652a1 |
/* forward slow down */
|
|
Packit |
0652a1 |
FWD_DOWN_SAMPLES (data, data_end, d, d_end, memcpy);
|
|
Packit |
0652a1 |
} else {
|
|
Packit |
0652a1 |
if (inr >= outr)
|
|
Packit |
0652a1 |
/* reverse speed up */
|
|
Packit |
0652a1 |
REV_UP_SAMPLES (data, data_end, d, d_end, memcpy);
|
|
Packit |
0652a1 |
else
|
|
Packit |
0652a1 |
/* reverse slow down */
|
|
Packit |
0652a1 |
REV_DOWN_SAMPLES (data, data_end, d, d_end, memcpy);
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/* for the next iteration we write to the next segment at the beginning. */
|
|
Packit |
0652a1 |
writeseg++;
|
|
Packit |
0652a1 |
sampleoff = 0;
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
/* we consumed all samples here */
|
|
Packit |
0652a1 |
data = data_end + bpf;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
done:
|
|
Packit |
0652a1 |
return inr - ((data_end - data) / bpf);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/* ERRORS */
|
|
Packit |
0652a1 |
not_started:
|
|
Packit |
0652a1 |
{
|
|
Packit |
0652a1 |
GST_DEBUG_OBJECT (buf, "stopped processing");
|
|
Packit |
0652a1 |
goto done;
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/**
|
|
Packit |
0652a1 |
* gst_audio_ring_buffer_commit:
|
|
Packit |
0652a1 |
* @buf: the #GstAudioRingBuffer to commit
|
|
Packit |
0652a1 |
* @sample: the sample position of the data
|
|
Packit |
0652a1 |
* @data: (array length=in_samples): the data to commit
|
|
Packit |
0652a1 |
* @in_samples: the number of samples in the data to commit
|
|
Packit |
0652a1 |
* @out_samples: the number of samples to write to the ringbuffer
|
|
Packit |
0652a1 |
* @accum: (inout): accumulator for rate conversion.
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* Commit @in_samples samples pointed to by @data to the ringbuffer @buf.
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* @in_samples and @out_samples define the rate conversion to perform on the
|
|
Packit |
0652a1 |
* samples in @data. For negative rates, @out_samples must be negative and
|
|
Packit |
0652a1 |
* @in_samples positive.
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* When @out_samples is positive, the first sample will be written at position @sample
|
|
Packit |
0652a1 |
* in the ringbuffer. When @out_samples is negative, the last sample will be written to
|
|
Packit |
0652a1 |
* @sample in reverse order.
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* @out_samples does not need to be a multiple of the segment size of the ringbuffer
|
|
Packit |
0652a1 |
* although it is recommended for optimal performance.
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* @accum will hold a temporary accumulator used in rate conversion and should be
|
|
Packit |
0652a1 |
* set to 0 when this function is first called. In case the commit operation is
|
|
Packit |
0652a1 |
* interrupted, one can resume the processing by passing the previously returned
|
|
Packit |
0652a1 |
* @accum value back to this function.
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* MT safe.
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* Returns: The number of samples written to the ringbuffer or -1 on error. The
|
|
Packit |
0652a1 |
* number of samples written can be less than @out_samples when @buf was interrupted
|
|
Packit |
0652a1 |
* with a flush or stop.
|
|
Packit |
0652a1 |
*/
|
|
Packit |
0652a1 |
guint
|
|
Packit |
0652a1 |
gst_audio_ring_buffer_commit (GstAudioRingBuffer * buf, guint64 * sample,
|
|
Packit |
0652a1 |
guint8 * data, gint in_samples, gint out_samples, gint * accum)
|
|
Packit |
0652a1 |
{
|
|
Packit |
0652a1 |
GstAudioRingBufferClass *rclass;
|
|
Packit |
0652a1 |
guint res = -1;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
g_return_val_if_fail (GST_IS_AUDIO_RING_BUFFER (buf), -1);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
if (G_UNLIKELY (in_samples == 0 || out_samples == 0))
|
|
Packit |
0652a1 |
return in_samples;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
rclass = GST_AUDIO_RING_BUFFER_GET_CLASS (buf);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
if (G_LIKELY (rclass->commit))
|
|
Packit |
0652a1 |
res = rclass->commit (buf, sample, data, in_samples, out_samples, accum);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
return res;
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/**
|
|
Packit |
0652a1 |
* gst_audio_ring_buffer_read:
|
|
Packit |
0652a1 |
* @buf: the #GstAudioRingBuffer to read from
|
|
Packit |
0652a1 |
* @sample: the sample position of the data
|
|
Packit |
0652a1 |
* @data: (array length=len): where the data should be read
|
|
Packit |
0652a1 |
* @len: the number of samples in data to read
|
|
Packit |
0652a1 |
* @timestamp: (out): where the timestamp is returned
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* Read @len samples from the ringbuffer into the memory pointed
|
|
Packit |
0652a1 |
* to by @data.
|
|
Packit |
0652a1 |
* The first sample should be read from position @sample in
|
|
Packit |
0652a1 |
* the ringbuffer.
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* @len should not be a multiple of the segment size of the ringbuffer
|
|
Packit |
0652a1 |
* although it is recommended.
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* @timestamp will return the timestamp associated with the data returned.
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* Returns: The number of samples read from the ringbuffer or -1 on
|
|
Packit |
0652a1 |
* error.
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* MT safe.
|
|
Packit |
0652a1 |
*/
|
|
Packit |
0652a1 |
guint
|
|
Packit |
0652a1 |
gst_audio_ring_buffer_read (GstAudioRingBuffer * buf, guint64 sample,
|
|
Packit |
0652a1 |
guint8 * data, guint len, GstClockTime * timestamp)
|
|
Packit |
0652a1 |
{
|
|
Packit |
0652a1 |
gint segdone;
|
|
Packit |
0652a1 |
gint segsize, segtotal, channels, bps, bpf, sps, readseg = 0;
|
|
Packit |
0652a1 |
guint8 *dest;
|
|
Packit |
0652a1 |
guint to_read;
|
|
Packit |
0652a1 |
gboolean need_reorder;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
g_return_val_if_fail (GST_IS_AUDIO_RING_BUFFER (buf), -1);
|
|
Packit |
0652a1 |
g_return_val_if_fail (buf->memory != NULL, -1);
|
|
Packit |
0652a1 |
g_return_val_if_fail (data != NULL, -1);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
need_reorder = buf->need_reorder;
|
|
Packit |
0652a1 |
dest = buf->memory;
|
|
Packit |
0652a1 |
segsize = buf->spec.segsize;
|
|
Packit |
0652a1 |
segtotal = buf->spec.segtotal;
|
|
Packit |
0652a1 |
channels = buf->spec.info.channels;
|
|
Packit |
0652a1 |
bpf = buf->spec.info.bpf;
|
|
Packit |
0652a1 |
bps = bpf / channels;
|
|
Packit |
0652a1 |
sps = buf->samples_per_seg;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
to_read = len;
|
|
Packit |
0652a1 |
/* read enough samples */
|
|
Packit |
0652a1 |
while (to_read > 0) {
|
|
Packit |
0652a1 |
gint sampleslen;
|
|
Packit |
0652a1 |
gint sampleoff;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/* figure out the segment and the offset inside the segment where
|
|
Packit |
0652a1 |
* the sample should be read from. */
|
|
Packit |
0652a1 |
readseg = sample / sps;
|
|
Packit |
0652a1 |
sampleoff = (sample % sps);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
while (TRUE) {
|
|
Packit |
0652a1 |
gint diff;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/* get the currently processed segment */
|
|
Packit |
0652a1 |
segdone = g_atomic_int_get (&buf->segdone) - buf->segbase;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/* see how far away it is from the read segment, normally segdone (where
|
|
Packit |
0652a1 |
* the hardware is writing) is bigger than readseg (where software is
|
|
Packit |
0652a1 |
* reading) */
|
|
Packit |
0652a1 |
diff = segdone - readseg;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
GST_DEBUG_OBJECT
|
|
Packit |
0652a1 |
(buf, "pointer at %d, sample %" G_GUINT64_FORMAT
|
|
Packit |
0652a1 |
", read from %d-%d, to_read %d, diff %d, segtotal %d, segsize %d",
|
|
Packit |
0652a1 |
segdone, sample, readseg, sampleoff, to_read, diff, segtotal,
|
|
Packit |
0652a1 |
segsize);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/* segment too far ahead, reader too slow */
|
|
Packit |
0652a1 |
if (G_UNLIKELY (diff >= segtotal)) {
|
|
Packit |
0652a1 |
/* pretend we read an empty segment. */
|
|
Packit |
0652a1 |
sampleslen = MIN (sps, to_read);
|
|
Packit |
0652a1 |
memcpy (data, buf->empty_seg, sampleslen * bpf);
|
|
Packit |
0652a1 |
goto next;
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/* read segment is within readable range, we can break the loop and
|
|
Packit |
0652a1 |
* start reading the data. */
|
|
Packit |
0652a1 |
if (diff > 0)
|
|
Packit |
0652a1 |
break;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/* else we need to wait for the segment to become readable. */
|
|
Packit |
0652a1 |
if (!wait_segment (buf))
|
|
Packit |
0652a1 |
goto not_started;
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/* we can read now */
|
|
Packit |
0652a1 |
readseg = readseg % segtotal;
|
|
Packit |
0652a1 |
sampleslen = MIN (sps - sampleoff, to_read);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
GST_DEBUG_OBJECT (buf, "read @%p seg %d, off %d, sampleslen %d",
|
|
Packit |
0652a1 |
dest + readseg * segsize, readseg, sampleoff, sampleslen);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
if (need_reorder) {
|
|
Packit |
0652a1 |
guint8 *ptr = dest + (readseg * segsize) + (sampleoff * bpf);
|
|
Packit |
0652a1 |
gint i, j;
|
|
Packit |
0652a1 |
gint *reorder_map = buf->channel_reorder_map;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/* Reorder from device order to GStreamer order */
|
|
Packit |
0652a1 |
for (i = 0; i < sampleslen; i++) {
|
|
Packit |
0652a1 |
for (j = 0; j < channels; j++) {
|
|
Packit |
0652a1 |
memcpy (data + i * bpf + reorder_map[j] * bps, ptr + j * bps, bps);
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
ptr += bpf;
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
} else {
|
|
Packit |
0652a1 |
memcpy (data, dest + (readseg * segsize) + (sampleoff * bpf),
|
|
Packit |
0652a1 |
(sampleslen * bpf));
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
next:
|
|
Packit |
0652a1 |
to_read -= sampleslen;
|
|
Packit |
0652a1 |
sample += sampleslen;
|
|
Packit |
0652a1 |
data += sampleslen * bpf;
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
if (buf->timestamps && timestamp) {
|
|
Packit |
0652a1 |
*timestamp = buf->timestamps[readseg % segtotal];
|
|
Packit |
0652a1 |
GST_DEBUG_OBJECT (buf, "Retrieved timestamp %" GST_TIME_FORMAT
|
|
Packit |
0652a1 |
" @ %d", GST_TIME_ARGS (*timestamp), readseg % segtotal);
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
return len - to_read;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/* ERRORS */
|
|
Packit |
0652a1 |
not_started:
|
|
Packit |
0652a1 |
{
|
|
Packit |
0652a1 |
GST_DEBUG_OBJECT (buf, "stopped processing");
|
|
Packit |
0652a1 |
return len - to_read;
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/**
|
|
Packit |
0652a1 |
* gst_audio_ring_buffer_prepare_read:
|
|
Packit |
0652a1 |
* @buf: the #GstAudioRingBuffer to read from
|
|
Packit |
0652a1 |
* @segment: (out): the segment to read
|
|
Packit |
0652a1 |
* @readptr: (out) (array length=len):
|
|
Packit |
0652a1 |
* the pointer to the memory where samples can be read
|
|
Packit |
0652a1 |
* @len: (out): the number of bytes to read
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* Returns a pointer to memory where the data from segment @segment
|
|
Packit |
0652a1 |
* can be found. This function is mostly used by subclasses.
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* Returns: FALSE if the buffer is not started.
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* MT safe.
|
|
Packit |
0652a1 |
*/
|
|
Packit |
0652a1 |
gboolean
|
|
Packit |
0652a1 |
gst_audio_ring_buffer_prepare_read (GstAudioRingBuffer * buf, gint * segment,
|
|
Packit |
0652a1 |
guint8 ** readptr, gint * len)
|
|
Packit |
0652a1 |
{
|
|
Packit |
0652a1 |
guint8 *data;
|
|
Packit |
0652a1 |
gint segdone;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
g_return_val_if_fail (GST_IS_AUDIO_RING_BUFFER (buf), FALSE);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
if (buf->callback == NULL) {
|
|
Packit |
0652a1 |
/* push mode, fail when nothing is started */
|
|
Packit |
0652a1 |
if (g_atomic_int_get (&buf->state) != GST_AUDIO_RING_BUFFER_STATE_STARTED)
|
|
Packit |
0652a1 |
return FALSE;
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
g_return_val_if_fail (buf->memory != NULL, FALSE);
|
|
Packit |
0652a1 |
g_return_val_if_fail (segment != NULL, FALSE);
|
|
Packit |
0652a1 |
g_return_val_if_fail (readptr != NULL, FALSE);
|
|
Packit |
0652a1 |
g_return_val_if_fail (len != NULL, FALSE);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
data = buf->memory;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/* get the position of the pointer */
|
|
Packit |
0652a1 |
segdone = g_atomic_int_get (&buf->segdone);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
*segment = segdone % buf->spec.segtotal;
|
|
Packit |
0652a1 |
*len = buf->spec.segsize;
|
|
Packit |
0652a1 |
*readptr = data + *segment * *len;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
GST_LOG_OBJECT (buf, "prepare read from segment %d (real %d) @%p",
|
|
Packit |
0652a1 |
*segment, segdone, *readptr);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/* callback to fill the memory with data, for pull based
|
|
Packit |
0652a1 |
* scheduling. */
|
|
Packit |
0652a1 |
if (buf->callback)
|
|
Packit |
0652a1 |
buf->callback (buf, *readptr, *len, buf->cb_data);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
return TRUE;
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/**
|
|
Packit |
0652a1 |
* gst_audio_ring_buffer_advance:
|
|
Packit |
0652a1 |
* @buf: the #GstAudioRingBuffer to advance
|
|
Packit |
0652a1 |
* @advance: the number of segments written
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* Subclasses should call this function to notify the fact that
|
|
Packit |
0652a1 |
* @advance segments are now processed by the device.
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* MT safe.
|
|
Packit |
0652a1 |
*/
|
|
Packit |
0652a1 |
void
|
|
Packit |
0652a1 |
gst_audio_ring_buffer_advance (GstAudioRingBuffer * buf, guint advance)
|
|
Packit |
0652a1 |
{
|
|
Packit |
0652a1 |
g_return_if_fail (GST_IS_AUDIO_RING_BUFFER (buf));
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/* update counter */
|
|
Packit |
0652a1 |
g_atomic_int_add (&buf->segdone, advance);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/* the lock is already taken when the waiting flag is set,
|
|
Packit |
0652a1 |
* we grab the lock as well to make sure the waiter is actually
|
|
Packit |
0652a1 |
* waiting for the signal */
|
|
Packit |
0652a1 |
if (g_atomic_int_compare_and_exchange (&buf->waiting, 1, 0)) {
|
|
Packit |
0652a1 |
GST_OBJECT_LOCK (buf);
|
|
Packit |
0652a1 |
GST_DEBUG_OBJECT (buf, "signal waiter");
|
|
Packit |
0652a1 |
GST_AUDIO_RING_BUFFER_SIGNAL (buf);
|
|
Packit |
0652a1 |
GST_OBJECT_UNLOCK (buf);
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/**
|
|
Packit |
0652a1 |
* gst_audio_ring_buffer_clear:
|
|
Packit |
0652a1 |
* @buf: the #GstAudioRingBuffer to clear
|
|
Packit |
0652a1 |
* @segment: the segment to clear
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* Clear the given segment of the buffer with silence samples.
|
|
Packit |
0652a1 |
* This function is used by subclasses.
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* MT safe.
|
|
Packit |
0652a1 |
*/
|
|
Packit |
0652a1 |
void
|
|
Packit |
0652a1 |
gst_audio_ring_buffer_clear (GstAudioRingBuffer * buf, gint segment)
|
|
Packit |
0652a1 |
{
|
|
Packit |
0652a1 |
guint8 *data;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
g_return_if_fail (GST_IS_AUDIO_RING_BUFFER (buf));
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/* no data means it's already cleared */
|
|
Packit |
0652a1 |
if (G_UNLIKELY (buf->memory == NULL))
|
|
Packit |
0652a1 |
return;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/* no empty_seg means it's not opened */
|
|
Packit |
0652a1 |
if (G_UNLIKELY (buf->empty_seg == NULL))
|
|
Packit |
0652a1 |
return;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
segment %= buf->spec.segtotal;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
data = buf->memory;
|
|
Packit |
0652a1 |
data += segment * buf->spec.segsize;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
GST_LOG_OBJECT (buf, "clear segment %d @%p", segment, data);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
memcpy (data, buf->empty_seg, buf->spec.segsize);
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/**
|
|
Packit |
0652a1 |
* gst_audio_ring_buffer_may_start:
|
|
Packit |
0652a1 |
* @buf: the #GstAudioRingBuffer
|
|
Packit |
0652a1 |
* @allowed: the new value
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* Tell the ringbuffer that it is allowed to start playback when
|
|
Packit |
0652a1 |
* the ringbuffer is filled with samples.
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* MT safe.
|
|
Packit |
0652a1 |
*/
|
|
Packit |
0652a1 |
void
|
|
Packit |
0652a1 |
gst_audio_ring_buffer_may_start (GstAudioRingBuffer * buf, gboolean allowed)
|
|
Packit |
0652a1 |
{
|
|
Packit |
0652a1 |
g_return_if_fail (GST_IS_AUDIO_RING_BUFFER (buf));
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
GST_LOG_OBJECT (buf, "may start: %d", allowed);
|
|
Packit |
0652a1 |
g_atomic_int_set (&buf->may_start, allowed);
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/* GST_AUDIO_CHANNEL_POSITION_NONE is used for position-less
|
|
Packit |
0652a1 |
* mutually exclusive channels. In this case we should not attempt
|
|
Packit |
0652a1 |
* to do any reordering.
|
|
Packit |
0652a1 |
*/
|
|
Packit |
0652a1 |
static gboolean
|
|
Packit |
0652a1 |
position_less_channels (const GstAudioChannelPosition * pos, guint channels)
|
|
Packit |
0652a1 |
{
|
|
Packit |
0652a1 |
guint i;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
for (i = 0; i < channels; i++) {
|
|
Packit |
0652a1 |
if (pos[i] != GST_AUDIO_CHANNEL_POSITION_NONE)
|
|
Packit |
0652a1 |
return FALSE;
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
return TRUE;
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/**
|
|
Packit |
0652a1 |
* gst_audio_ring_buffer_set_channel_positions:
|
|
Packit |
0652a1 |
* @buf: the #GstAudioRingBuffer
|
|
Packit |
0652a1 |
* @position: (array): the device channel positions
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* Tell the ringbuffer about the device's channel positions. This must
|
|
Packit |
0652a1 |
* be called in when the ringbuffer is acquired.
|
|
Packit |
0652a1 |
*/
|
|
Packit |
0652a1 |
void
|
|
Packit |
0652a1 |
gst_audio_ring_buffer_set_channel_positions (GstAudioRingBuffer * buf,
|
|
Packit |
0652a1 |
const GstAudioChannelPosition * position)
|
|
Packit |
0652a1 |
{
|
|
Packit |
0652a1 |
const GstAudioChannelPosition *to;
|
|
Packit |
0652a1 |
gint channels;
|
|
Packit |
0652a1 |
gint i;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
g_return_if_fail (GST_IS_AUDIO_RING_BUFFER (buf));
|
|
Packit |
0652a1 |
g_return_if_fail (buf->acquired);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
channels = buf->spec.info.channels;
|
|
Packit |
0652a1 |
to = buf->spec.info.position;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
if (memcmp (position, to, channels * sizeof (to[0])) == 0)
|
|
Packit |
0652a1 |
return;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
if (position_less_channels (position, channels)) {
|
|
Packit |
0652a1 |
GST_LOG_OBJECT (buf, "position-less channels, no need to reorder");
|
|
Packit |
0652a1 |
return;
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
buf->need_reorder = FALSE;
|
|
Packit |
0652a1 |
if (!gst_audio_get_channel_reorder_map (channels, position, to,
|
|
Packit |
0652a1 |
buf->channel_reorder_map))
|
|
Packit |
0652a1 |
g_return_if_reached ();
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
for (i = 0; i < channels; i++) {
|
|
Packit |
0652a1 |
if (buf->channel_reorder_map[i] != i) {
|
|
Packit |
0652a1 |
#ifndef GST_DISABLE_GST_DEBUG
|
|
Packit |
0652a1 |
{
|
|
Packit |
0652a1 |
gchar *tmp1, *tmp2;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
tmp1 = gst_audio_channel_positions_to_string (position, channels);
|
|
Packit |
0652a1 |
tmp2 = gst_audio_channel_positions_to_string (to, channels);
|
|
Packit |
0652a1 |
GST_LOG_OBJECT (buf, "may have to reorder channels: %s -> %s", tmp1,
|
|
Packit |
0652a1 |
tmp2);
|
|
Packit |
0652a1 |
g_free (tmp1);
|
|
Packit |
0652a1 |
g_free (tmp2);
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
#endif /* GST_DISABLE_GST_DEBUG */
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
buf->need_reorder = TRUE;
|
|
Packit |
0652a1 |
break;
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
/**
|
|
Packit |
0652a1 |
* gst_ring_buffer_set_timestamp:
|
|
Packit |
0652a1 |
* @buf: the #GstRingBuffer
|
|
Packit |
0652a1 |
* @readseg: the current data segment
|
|
Packit |
0652a1 |
* @timestamp: The new timestamp of the buffer.
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* Set a new timestamp on the buffer.
|
|
Packit |
0652a1 |
*
|
|
Packit |
0652a1 |
* MT safe.
|
|
Packit |
0652a1 |
*/
|
|
Packit |
0652a1 |
void
|
|
Packit |
0652a1 |
gst_audio_ring_buffer_set_timestamp (GstAudioRingBuffer * buf, gint readseg,
|
|
Packit |
0652a1 |
GstClockTime timestamp)
|
|
Packit |
0652a1 |
{
|
|
Packit |
0652a1 |
g_return_if_fail (GST_IS_AUDIO_RING_BUFFER (buf));
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
GST_DEBUG_OBJECT (buf, "Storing timestamp %" GST_TIME_FORMAT
|
|
Packit |
0652a1 |
" @ %d", GST_TIME_ARGS (timestamp), readseg);
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
GST_OBJECT_LOCK (buf);
|
|
Packit |
0652a1 |
if (G_UNLIKELY (!buf->acquired))
|
|
Packit |
0652a1 |
goto not_acquired;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
buf->timestamps[readseg] = timestamp;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
done:
|
|
Packit |
0652a1 |
GST_OBJECT_UNLOCK (buf);
|
|
Packit |
0652a1 |
return;
|
|
Packit |
0652a1 |
|
|
Packit |
0652a1 |
not_acquired:
|
|
Packit |
0652a1 |
{
|
|
Packit |
0652a1 |
GST_DEBUG_OBJECT (buf, "we are not acquired");
|
|
Packit |
0652a1 |
goto done;
|
|
Packit |
0652a1 |
}
|
|
Packit |
0652a1 |
}
|