gstreamer/sys/opensles/openslesringbuffer.c
Josep Torra 0291953997 opensles: rework on the ringbufffer to properly clear segments
Make the segments bigger (1 second) as it seems to be the minimum size
we need to not introduce noise.
Sink works in my nexus 7 with rates from 8000 to 44100 and some noise
can be noticed on higger sample rates.
2012-10-18 14:03:08 +02:00

719 lines
20 KiB
C

/* GStreamer
* Copyright (C) 2012 Fluendo S.A. <support@fluendo.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "openslesringbuffer.h"
GST_DEBUG_CATEGORY_STATIC (opensles_ringbuffer_debug);
#define GST_CAT_DEFAULT opensles_ringbuffer_debug
static GstRingBufferClass *ring_parent_class = NULL;
static void
_do_init (GType type)
{
GST_DEBUG_CATEGORY_INIT (opensles_ringbuffer_debug,
"opensles_ringbuffer", 0, "OpenSL ES ringbuffer");
}
GST_BOILERPLATE_FULL (GstOpenSLESRingBuffer, gst_opensles_ringbuffer,
GstRingBuffer, GST_TYPE_RING_BUFFER, _do_init);
/* Some generic helper functions */
static inline SLuint32
_opensles_sample_rate (guint rate)
{
switch (rate) {
case 8000:
return SL_SAMPLINGRATE_8;
case 11025:
return SL_SAMPLINGRATE_11_025;
case 12000:
return SL_SAMPLINGRATE_12;
case 16000:
return SL_SAMPLINGRATE_16;
case 22050:
return SL_SAMPLINGRATE_22_05;
case 24000:
return SL_SAMPLINGRATE_24;
case 32000:
return SL_SAMPLINGRATE_32;
case 44100:
return SL_SAMPLINGRATE_44_1;
case 48000:
return SL_SAMPLINGRATE_48;
case 64000:
return SL_SAMPLINGRATE_64;
case 88200:
return SL_SAMPLINGRATE_88_2;
case 96000:
return SL_SAMPLINGRATE_96;
case 192000:
return SL_SAMPLINGRATE_192;
default:
return 0;
}
}
static inline SLuint32
_opensles_channel_mask (GstRingBufferSpec * spec)
{
/* FIXME: handle more than two channels */
switch (spec->channels) {
case 1:
return (SL_SPEAKER_FRONT_CENTER);
case 2:
return (SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT);
default:
return 0;
}
}
static inline void
_opensles_format (GstRingBufferSpec * spec, SLDataFormat_PCM * format)
{
format->formatType = SL_DATAFORMAT_PCM;
format->numChannels = spec->channels;
format->samplesPerSec = _opensles_sample_rate (spec->rate);
format->bitsPerSample = spec->depth;
format->containerSize = spec->width;
format->channelMask = _opensles_channel_mask (spec);
format->endianness =
(spec->bigend ? SL_BYTEORDER_BIGENDIAN : SL_BYTEORDER_LITTLEENDIAN);
}
/* Recorder related functions */
static void
_opensles_recorder_cb (SLAndroidSimpleBufferQueueItf bufferQueue, void *context)
{
#if 0
GstRingBuffer *rb = GST_RING_BUFFER_CAST (context);
GstOpenSLESRingBuffer *thiz = GST_OPENSLES_RING_BUFFER_CAST (rb);
assert (bq == bqRecorderBufferQueue);
assert (NULL == context);
// for streaming recording, here we would call Enqueue to give recorder the next buffer to fill
// but instead, this is a one-time buffer so we stop recording
SLresult result;
result =
(*recorderRecord)->SetRecordState (recorderRecord,
SL_RECORDSTATE_STOPPED);
if (SL_RESULT_SUCCESS == result) {
recorderSize = RECORDER_FRAMES * sizeof (short);
recorderSR = SL_SAMPLINGRATE_16;
}
#endif
}
static gboolean
_opensles_recorder_acquire (GstRingBuffer * rb, GstRingBufferSpec * spec)
{
GstOpenSLESRingBuffer *thiz = GST_OPENSLES_RING_BUFFER_CAST (rb);
SLresult result;
SLDataFormat_PCM format;
/* Configure audio source */
SLDataLocator_IODevice loc_dev =
{ SL_DATALOCATOR_IODEVICE, SL_IODEVICE_AUDIOINPUT,
SL_DEFAULTDEVICEID_AUDIOINPUT, NULL
};
SLDataSource audioSrc = { &loc_dev, NULL };
/* Configure audio sink */
SLDataLocator_AndroidSimpleBufferQueue loc_bq =
{ SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 2 };
SLDataSink audioSink = { &loc_bq, &format };
/* Create audio recorder (requires the RECORD_AUDIO permission) */
const SLInterfaceID id[1] = { SL_IID_ANDROIDSIMPLEBUFFERQUEUE };
const SLboolean req[1] = { SL_BOOLEAN_TRUE };
/* Define the format in OpenSL ES terms */
_opensles_format (spec, &format);
result = (*thiz->engineEngine)->CreateAudioRecorder (thiz->engineEngine,
&thiz->recorderObject, &audioSrc, &audioSink, 1, id, req);
if (result != SL_RESULT_SUCCESS) {
GST_ERROR_OBJECT (thiz, "engine.CreateAudioRecorder failed(0x%08x)",
(guint32) result);
goto failed;
}
/* Realize the audio recorder */
result =
(*thiz->recorderObject)->Realize (thiz->recorderObject, SL_BOOLEAN_FALSE);
if (result != SL_RESULT_SUCCESS) {
GST_ERROR_OBJECT (thiz, "recorder.Realize failed(0x%08x)",
(guint32) result);
goto failed;
}
/* Get the record interface */
result = (*thiz->recorderObject)->GetInterface (thiz->recorderObject,
SL_IID_RECORD, &thiz->recorderRecord);
if (result != SL_RESULT_SUCCESS) {
GST_ERROR_OBJECT (thiz, "recorder.GetInterface(Record) failed(0x%08x)",
(guint32) result);
goto failed;
}
/* Get the buffer queue interface */
result =
(*thiz->recorderObject)->GetInterface (thiz->recorderObject,
SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &thiz->bufferQueue);
if (result != SL_RESULT_SUCCESS) {
GST_ERROR_OBJECT (thiz, "recorder.GetInterface(BufferQueue) failed(0x%08x)",
(guint32) result);
goto failed;
}
/* Register callback on the buffer queue */
result = (*thiz->bufferQueue)->RegisterCallback (thiz->bufferQueue,
_opensles_recorder_cb, rb);
if (result != SL_RESULT_SUCCESS) {
GST_ERROR_OBJECT (thiz, "bufferQueue.RegisterCallback failed(0x%08x)",
(guint32) result);
goto failed;
}
/* Define our ringbuffer in terms of number of buffers and buffer size. */
spec->segsize = (spec->rate * spec->bytes_per_sample) >> 1;
spec->segtotal = 3;
return TRUE;
failed:
return FALSE;
}
static gboolean
_opensles_recorder_start (GstRingBuffer * rb)
{
GstOpenSLESRingBuffer *thiz = GST_OPENSLES_RING_BUFFER_CAST (rb);
SLresult result;
/* in case already recording, stop recording and clear buffer queue */
result =
(*thiz->recorderRecord)->SetRecordState (thiz->recorderRecord,
SL_RECORDSTATE_STOPPED);
if (result != SL_RESULT_SUCCESS) {
GST_ERROR_OBJECT (thiz, "recorder.SetRecordState failed(0x%08x)",
(guint32) result);
return FALSE;
}
result = (*thiz->bufferQueue)->Clear (thiz->bufferQueue);
if (result != SL_RESULT_SUCCESS) {
GST_ERROR_OBJECT (thiz, "bq.Clear failed(0x%08x)", (guint32) result);
return FALSE;
}
/* FIXME: Maybe we should enqueue some buffers here first by calling
* _opensles_recorder_cb */
/* start recording */
result =
(*thiz->recorderRecord)->SetRecordState (thiz->recorderRecord,
SL_RECORDSTATE_RECORDING);
if (result != SL_RESULT_SUCCESS) {
GST_ERROR_OBJECT (thiz, "recorder.SetRecordState failed(0x%08x)",
(guint32) result);
return FALSE;
}
return TRUE;
}
static gboolean
_opensles_recorder_stop (GstRingBuffer * rb)
{
GstOpenSLESRingBuffer *thiz = GST_OPENSLES_RING_BUFFER_CAST (rb);
SLresult result;
result =
(*thiz->recorderRecord)->SetRecordState (thiz->recorderRecord,
SL_RECORDSTATE_STOPPED);
if (result != SL_RESULT_SUCCESS) {
GST_ERROR_OBJECT (thiz, "recorder.SetRecordState failed(0x%08x)",
(guint32) result);
return FALSE;
}
return TRUE;
}
/* Player related functions */
static void
_opensles_player_cb (SLAndroidSimpleBufferQueueItf bufferQueue, void *context)
{
GstRingBuffer *rb = GST_RING_BUFFER_CAST (context);
GstOpenSLESRingBuffer *thiz = GST_OPENSLES_RING_BUFFER_CAST (rb);
SLresult result;
guint8 *readptr;
gint readseg;
gint len;
if (!gst_ring_buffer_prepare_read (rb, &readseg, &readptr, &len)) {
GST_WARNING_OBJECT (rb, "The sink is starving");
return;
}
/* Enqueue a buffer */
GST_LOG_OBJECT (thiz, "enqueue: %p size %d segment: %d",
readptr, len, readseg);
result = (*thiz->bufferQueue)->Enqueue (thiz->bufferQueue, readptr, len);
if (result != SL_RESULT_SUCCESS) {
GST_ERROR_OBJECT (thiz, "bufferQueue.Enqueue failed(0x%08x)",
(guint32) result);
return;
}
if (G_UNLIKELY (thiz->last_clearseg < 0)) {
thiz->last_clearseg++;
} else {
GST_LOG_OBJECT (thiz, "clear segment %d", thiz->last_clearseg);
/* Clear written samples */
gst_ring_buffer_clear (rb, thiz->last_clearseg);
thiz->last_clearseg = (thiz->last_clearseg + 1) % rb->spec.segtotal;
/* We wrote one segment */
}
gst_ring_buffer_advance (rb, 1);
}
static gboolean
_opensles_player_acquire (GstRingBuffer * rb, GstRingBufferSpec * spec)
{
GstOpenSLESRingBuffer *thiz = GST_OPENSLES_RING_BUFFER_CAST (rb);
SLresult result;
SLDataFormat_PCM format;
/* Configure audio source */
SLDataLocator_AndroidSimpleBufferQueue loc_bufq =
{ SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 2 };
SLDataSource audioSrc = { &loc_bufq, &format };
/* Configure audio sink */
SLDataLocator_OutputMix loc_outmix =
{ SL_DATALOCATOR_OUTPUTMIX, thiz->outputMixObject };
SLDataSink audioSink = { &loc_outmix, NULL };
/* Create an audio player */
const SLInterfaceID ids[2] = { SL_IID_BUFFERQUEUE, SL_IID_VOLUME };
const SLboolean req[2] = { SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE };
/* Define the format in OpenSL ES terms */
_opensles_format (spec, &format);
result = (*thiz->engineEngine)->CreateAudioPlayer (thiz->engineEngine,
&thiz->playerObject, &audioSrc, &audioSink, 2, ids, req);
if (result != SL_RESULT_SUCCESS) {
GST_ERROR_OBJECT (thiz, "engine.CreateAudioPlayer failed(0x%08x)",
(guint32) result);
goto failed;
}
/* Realize the player */
result =
(*thiz->playerObject)->Realize (thiz->playerObject, SL_BOOLEAN_FALSE);
if (result != SL_RESULT_SUCCESS) {
GST_ERROR_OBJECT (thiz, "player.Realize failed(0x%08x)", (guint32) result);
goto failed;
}
/* Get the play interface */
result = (*thiz->playerObject)->GetInterface (thiz->playerObject,
SL_IID_PLAY, &thiz->playerPlay);
if (result != SL_RESULT_SUCCESS) {
GST_ERROR_OBJECT (thiz, "player.GetInterface(Play) failed(0x%08x)",
(guint32) result);
goto failed;
}
/* Get the buffer queue interface */
result = (*thiz->playerObject)->GetInterface (thiz->playerObject,
SL_IID_BUFFERQUEUE, &thiz->bufferQueue);
if (result != SL_RESULT_SUCCESS) {
GST_ERROR_OBJECT (thiz, "player.GetInterface(BufferQueue) failed(0x%08x)",
(guint32) result);
goto failed;
}
/* Register callback on the buffer queue */
result = (*thiz->bufferQueue)->RegisterCallback (thiz->bufferQueue,
_opensles_player_cb, rb);
if (result != SL_RESULT_SUCCESS) {
GST_ERROR_OBJECT (thiz, "bufferQueue.RegisterCallback failed(0x%08x)",
(guint32) result);
goto failed;
}
/* Get the volume interface */
result = (*thiz->playerObject)->GetInterface (thiz->playerObject,
SL_IID_VOLUME, &thiz->playerVolume);
if (result != SL_RESULT_SUCCESS) {
GST_ERROR_OBJECT (thiz, "player.GetInterface(Volume) failed(0x%08x)",
(guint32) result);
goto failed;
}
/* Define our ringbuffer in terms of number of buffers and buffer size. */
spec->segsize = (spec->rate * spec->bytes_per_sample);
spec->segtotal = 4;
/* In the Nexus7 device where I'm testing seems that I need buffers of
* min 1 second of audio.
* Then here we created 4 segments of a second and a queue of 2 buffers
* in order to properly clear the older segment */
thiz->last_clearseg = -3;
return TRUE;
failed:
return FALSE;
}
static gboolean
_opensles_player_start (GstRingBuffer * rb)
{
GstOpenSLESRingBuffer *thiz = GST_OPENSLES_RING_BUFFER_CAST (rb);
SLresult result;
result =
(*thiz->playerPlay)->SetPlayState (thiz->playerPlay,
SL_PLAYSTATE_PLAYING);
if (result != SL_RESULT_SUCCESS) {
GST_ERROR_OBJECT (thiz, "player.SetPlayState failed(0x%08x)",
(guint32) result);
return FALSE;
}
/* Fill the queue by enqueing two buffers */
_opensles_player_cb (NULL, rb);
_opensles_player_cb (NULL, rb);
return TRUE;
}
static gboolean
_opensles_player_pause (GstRingBuffer * rb)
{
GstOpenSLESRingBuffer *thiz = GST_OPENSLES_RING_BUFFER_CAST (rb);
SLresult result;
result =
(*thiz->playerPlay)->SetPlayState (thiz->playerPlay, SL_PLAYSTATE_PAUSED);
if (result != SL_RESULT_SUCCESS) {
GST_ERROR_OBJECT (thiz, "player.SetPlayState failed(0x%08x)",
(guint32) result);
return FALSE;
}
return TRUE;
}
static gboolean
_opensles_player_stop (GstRingBuffer * rb)
{
GstOpenSLESRingBuffer *thiz = GST_OPENSLES_RING_BUFFER_CAST (rb);
SLresult result;
result =
(*thiz->playerPlay)->SetPlayState (thiz->playerPlay,
SL_PLAYSTATE_STOPPED);
if (result != SL_RESULT_SUCCESS) {
GST_ERROR_OBJECT (thiz, "player.SetPlayState failed(0x%08x)",
(guint32) result);
return FALSE;
}
return TRUE;
}
/* OpenSL ES ring buffer wrapper */
GstRingBuffer *
gst_opensles_ringbuffer_new (RingBufferMode mode)
{
GstOpenSLESRingBuffer *thiz;
g_return_val_if_fail (mode > RB_MODE_NONE && mode < RB_MODE_LAST, NULL);
thiz = g_object_new (GST_TYPE_OPENSLES_RING_BUFFER, NULL);
if (thiz) {
thiz->mode = mode;
if (mode == RB_MODE_SRC) {
thiz->acquire = _opensles_recorder_acquire;
thiz->start = _opensles_recorder_start;
thiz->pause = _opensles_recorder_stop;
thiz->stop = _opensles_recorder_stop;
} else if (mode == RB_MODE_SINK_PCM) {
thiz->acquire = _opensles_player_acquire;
thiz->start = _opensles_player_start;
thiz->pause = _opensles_player_pause;
thiz->stop = _opensles_player_stop;
}
}
GST_DEBUG_OBJECT (thiz, "ringbuffer created");
return GST_RING_BUFFER (thiz);
}
static gboolean
gst_opensles_ringbuffer_open_device (GstRingBuffer * rb)
{
GstOpenSLESRingBuffer *thiz;
SLresult result;
thiz = GST_OPENSLES_RING_BUFFER_CAST (rb);
/* Create engine */
result = slCreateEngine (&thiz->engineObject, 0, NULL, 0, NULL, NULL);
if (result != SL_RESULT_SUCCESS) {
GST_ERROR_OBJECT (thiz, "slCreateEngine failed(0x%08x)", (guint32) result);
goto failed;
}
/* Realize the engine */
result = (*thiz->engineObject)->Realize (thiz->engineObject,
SL_BOOLEAN_FALSE);
if (result != SL_RESULT_SUCCESS) {
GST_ERROR_OBJECT (thiz, "engine.Realize failed(0x%08x)", (guint32) result);
goto failed;
}
/* Get the engine interface, which is needed in order to
* create other objects */
result = (*thiz->engineObject)->GetInterface (thiz->engineObject,
SL_IID_ENGINE, &thiz->engineEngine);
if (result != SL_RESULT_SUCCESS) {
GST_ERROR_OBJECT (thiz, "engine.GetInterface(Engine) failed(0x%08x)",
(guint32) result);
goto failed;
}
if (thiz->mode == RB_MODE_SINK_PCM) {
/* Create an output mixer */
result = (*thiz->engineEngine)->CreateOutputMix (thiz->engineEngine,
&thiz->outputMixObject, 0, NULL, NULL);
if (result != SL_RESULT_SUCCESS) {
GST_ERROR_OBJECT (thiz, "engine.CreateOutputMix failed(0x%08x)",
(guint32) result);
goto failed;
}
/* Realize the output mixer */
result = (*thiz->outputMixObject)->Realize (thiz->outputMixObject,
SL_BOOLEAN_FALSE);
if (result != SL_RESULT_SUCCESS) {
GST_ERROR_OBJECT (thiz, "outputMix.Realize failed(0x%08x)",
(guint32) result);
goto failed;
}
}
GST_DEBUG_OBJECT (thiz, "device opened");
return TRUE;
failed:
return FALSE;
}
static gboolean
gst_opensles_ringbuffer_close_device (GstRingBuffer * rb)
{
GstOpenSLESRingBuffer *thiz;
thiz = GST_OPENSLES_RING_BUFFER_CAST (rb);
/* Destroy output mix object */
if (thiz->outputMixObject) {
(*thiz->outputMixObject)->Destroy (thiz->outputMixObject);
thiz->outputMixObject = NULL;
}
/* Destroy engine object, and invalidate all associated interfaces */
if (thiz->engineObject) {
(*thiz->engineObject)->Destroy (thiz->engineObject);
thiz->engineObject = NULL;
thiz->engineEngine = NULL;
}
thiz->bufferQueue = NULL;
GST_DEBUG_OBJECT (thiz, "device closed");
return TRUE;
}
static gboolean
gst_opensles_ringbuffer_acquire (GstRingBuffer * rb, GstRingBufferSpec * spec)
{
GstOpenSLESRingBuffer *thiz;
thiz = GST_OPENSLES_RING_BUFFER_CAST (rb);
/* Instantiate and configure the OpenSL ES interfaces */
if (!thiz->acquire (rb, spec)) {
return FALSE;
}
/* Initialize our ringbuffer memory region */
rb->data = gst_buffer_new_and_alloc (spec->segtotal * spec->segsize);
memset (GST_BUFFER_DATA (rb->data), 0, GST_BUFFER_SIZE (rb->data));
GST_DEBUG_OBJECT (thiz, "ringbuffer acquired");
return TRUE;
}
static gboolean
gst_opensles_ringbuffer_release (GstRingBuffer * rb)
{
GstOpenSLESRingBuffer *thiz;
thiz = GST_OPENSLES_RING_BUFFER (rb);
/* Destroy audio player object, and invalidate all associated interfaces */
if (thiz->playerObject) {
(*thiz->playerObject)->Destroy (thiz->playerObject);
thiz->playerObject = NULL;
thiz->playerPlay = NULL;
thiz->playerVolume = NULL;
}
/* Destroy audio recorder object, and invalidate all associated interfaces */
if (thiz->recorderObject) {
(*thiz->recorderObject)->Destroy (thiz->recorderObject);
thiz->recorderObject = NULL;
thiz->recorderRecord = NULL;
}
if (rb->data) {
gst_buffer_unref (rb->data);
rb->data = NULL;
}
GST_DEBUG_OBJECT (thiz, "ringbuffer released");
return TRUE;
}
static gboolean
gst_opensles_ringbuffer_start (GstRingBuffer * rb)
{
GstOpenSLESRingBuffer *thiz;
gboolean res;
thiz = GST_OPENSLES_RING_BUFFER_CAST (rb);
res = thiz->start (rb);
GST_DEBUG_OBJECT (thiz, "ringbuffer %s started", (res ? "" : "not"));
return res;
}
static gboolean
gst_opensles_ringbuffer_pause (GstRingBuffer * rb)
{
GstOpenSLESRingBuffer *thiz;
gboolean res;
thiz = GST_OPENSLES_RING_BUFFER_CAST (rb);
res = thiz->pause (rb);
GST_DEBUG_OBJECT (thiz, "ringbuffer %s paused", (res ? "" : "not"));
return res;
}
static gboolean
gst_opensles_ringbuffer_stop (GstRingBuffer * rb)
{
GstOpenSLESRingBuffer *thiz;
gboolean res;
thiz = GST_OPENSLES_RING_BUFFER_CAST (rb);
res = thiz->stop (rb);
GST_DEBUG_OBJECT (thiz, "ringbuffer %s stopped", (res ? " " : "not"));
return res;
}
static guint
gst_opensles_ringbuffer_delay (GstRingBuffer * rb)
{
return 0;
}
static void
gst_opensles_ringbuffer_dispose (GObject * object)
{
G_OBJECT_CLASS (ring_parent_class)->dispose (object);
}
static void
gst_opensles_ringbuffer_finalize (GObject * object)
{
G_OBJECT_CLASS (ring_parent_class)->finalize (object);
}
static void
gst_opensles_ringbuffer_base_init (gpointer g_class)
{
/* Nothing to do right now */
}
static void
gst_opensles_ringbuffer_class_init (GstOpenSLESRingBufferClass * klass)
{
GObjectClass *gobject_class;
GstRingBufferClass *gstringbuffer_class;
gobject_class = (GObjectClass *) klass;
gstringbuffer_class = (GstRingBufferClass *) klass;
ring_parent_class = g_type_class_peek_parent (klass);
gobject_class->dispose = gst_opensles_ringbuffer_dispose;
gobject_class->finalize = gst_opensles_ringbuffer_finalize;
gstringbuffer_class->open_device =
GST_DEBUG_FUNCPTR (gst_opensles_ringbuffer_open_device);
gstringbuffer_class->close_device =
GST_DEBUG_FUNCPTR (gst_opensles_ringbuffer_close_device);
gstringbuffer_class->acquire =
GST_DEBUG_FUNCPTR (gst_opensles_ringbuffer_acquire);
gstringbuffer_class->release =
GST_DEBUG_FUNCPTR (gst_opensles_ringbuffer_release);
gstringbuffer_class->start =
GST_DEBUG_FUNCPTR (gst_opensles_ringbuffer_start);
gstringbuffer_class->pause =
GST_DEBUG_FUNCPTR (gst_opensles_ringbuffer_pause);
gstringbuffer_class->resume =
GST_DEBUG_FUNCPTR (gst_opensles_ringbuffer_start);
gstringbuffer_class->stop = GST_DEBUG_FUNCPTR (gst_opensles_ringbuffer_stop);
gstringbuffer_class->delay =
GST_DEBUG_FUNCPTR (gst_opensles_ringbuffer_delay);
}
static void
gst_opensles_ringbuffer_init (GstOpenSLESRingBuffer * thiz,
GstOpenSLESRingBufferClass * g_class)
{
thiz->mode = RB_MODE_NONE;
thiz->engineObject = NULL;
thiz->outputMixObject = NULL;
thiz->playerObject = NULL;
thiz->recorderObject = NULL;
}