opensles: sprinkle comments and cosmetic fixes

This commit is contained in:
Josep Torra 2012-09-29 19:00:13 +02:00 committed by Sebastian Dröge
parent 78e3b9f428
commit 920354eb0d
4 changed files with 112 additions and 43 deletions

View file

@ -40,7 +40,9 @@ GST_BOILERPLATE_FULL (GstOpenSLESRingBuffer, gst_opensles_ringbuffer,
#define RECORDER_QUEUE_SIZE 2 #define RECORDER_QUEUE_SIZE 2
/* Some generic helper functions */ /*
* Some generic helper functions
*/
static inline SLuint32 static inline SLuint32
_opensles_sample_rate (guint rate) _opensles_sample_rate (guint rate)
@ -80,7 +82,6 @@ _opensles_sample_rate (guint rate)
static inline SLuint32 static inline SLuint32
_opensles_channel_mask (GstRingBufferSpec * spec) _opensles_channel_mask (GstRingBufferSpec * spec)
{ {
/* FIXME: handle more than two channels */
switch (spec->channels) { switch (spec->channels) {
case 1: case 1:
return (SL_SPEAKER_FRONT_CENTER); return (SL_SPEAKER_FRONT_CENTER);
@ -104,7 +105,9 @@ _opensles_format (GstRingBufferSpec * spec, SLDataFormat_PCM * format)
(spec->bigend ? SL_BYTEORDER_BIGENDIAN : SL_BYTEORDER_LITTLEENDIAN); (spec->bigend ? SL_BYTEORDER_BIGENDIAN : SL_BYTEORDER_LITTLEENDIAN);
} }
/* Recorder related functions */ /*
* Recorder related functions
*/
static gboolean static gboolean
_opensles_recorder_acquire (GstRingBuffer * rb, GstRingBufferSpec * spec) _opensles_recorder_acquire (GstRingBuffer * rb, GstRingBufferSpec * spec)
@ -126,13 +129,14 @@ _opensles_recorder_acquire (GstRingBuffer * rb, GstRingBufferSpec * spec)
}; };
SLDataSink audioSink = { &loc_bq, &format }; SLDataSink audioSink = { &loc_bq, &format };
/* Required optional interfaces */
const SLInterfaceID id[1] = { SL_IID_ANDROIDSIMPLEBUFFERQUEUE }; const SLInterfaceID id[1] = { SL_IID_ANDROIDSIMPLEBUFFERQUEUE };
const SLboolean req[1] = { SL_BOOLEAN_TRUE }; const SLboolean req[1] = { SL_BOOLEAN_TRUE };
/* Define the format in OpenSL ES terms */ /* Define the audio format in OpenSL ES terminology */
_opensles_format (spec, &format); _opensles_format (spec, &format);
/* Create audio recorder (requires the RECORD_AUDIO permission) */ /* Create the audio recorder object (requires the RECORD_AUDIO permission) */
result = (*thiz->engineEngine)->CreateAudioRecorder (thiz->engineEngine, result = (*thiz->engineEngine)->CreateAudioRecorder (thiz->engineEngine,
&thiz->recorderObject, &audioSrc, &audioSink, 1, id, req); &thiz->recorderObject, &audioSrc, &audioSink, 1, id, req);
if (result != SL_RESULT_SUCCESS) { if (result != SL_RESULT_SUCCESS) {
@ -141,7 +145,7 @@ _opensles_recorder_acquire (GstRingBuffer * rb, GstRingBufferSpec * spec)
goto failed; goto failed;
} }
/* Realize the audio recorder */ /* Realize the audio recorder object */
result = result =
(*thiz->recorderObject)->Realize (thiz->recorderObject, SL_BOOLEAN_FALSE); (*thiz->recorderObject)->Realize (thiz->recorderObject, SL_BOOLEAN_FALSE);
if (result != SL_RESULT_SUCCESS) { if (result != SL_RESULT_SUCCESS) {
@ -179,6 +183,11 @@ failed:
return FALSE; return FALSE;
} }
/* This callback function is executed when the ringbuffer is started to preroll
* the output buffer queue with empty buffers, from app thread, and each time
* there's a filled buffer, from audio device processing thread,
* the callback behaviour.
*/
static void static void
_opensles_recorder_cb (SLAndroidSimpleBufferQueueItf bufferQueue, void *context) _opensles_recorder_cb (SLAndroidSimpleBufferQueueItf bufferQueue, void *context)
{ {
@ -189,21 +198,24 @@ _opensles_recorder_cb (SLAndroidSimpleBufferQueueItf bufferQueue, void *context)
gint seg; gint seg;
gint len; gint len;
/* Get a segment form the GStreamer ringbuffer to write in */
if (!gst_ring_buffer_prepare_read (rb, &seg, &ptr, &len)) { if (!gst_ring_buffer_prepare_read (rb, &seg, &ptr, &len)) {
GST_WARNING_OBJECT (rb, "No segment available"); GST_WARNING_OBJECT (rb, "No segment available");
return; return;
} }
/* Enqueue a buffer */
GST_LOG_OBJECT (thiz, "enqueue: %p size %d segment: %d", ptr, len, seg); GST_LOG_OBJECT (thiz, "enqueue: %p size %d segment: %d", ptr, len, seg);
result = (*thiz->bufferQueue)->Enqueue (thiz->bufferQueue, ptr, len);
/* Enqueue the sefment as buffer to be written */
result = (*thiz->bufferQueue)->Enqueue (thiz->bufferQueue, ptr, len);
if (result != SL_RESULT_SUCCESS) { if (result != SL_RESULT_SUCCESS) {
GST_ERROR_OBJECT (thiz, "bufferQueue.Enqueue failed(0x%08x)", GST_ERROR_OBJECT (thiz, "bufferQueue.Enqueue failed(0x%08x)",
(guint32) result); (guint32) result);
return; return;
} }
/* FIXME: we advance here and behaviour might be racy with the reading
* thread */
gst_ring_buffer_advance (rb, 1); gst_ring_buffer_advance (rb, 1);
} }
@ -226,7 +238,7 @@ _opensles_recorder_start (GstRingBuffer * rb)
thiz->is_queue_callback_registered = TRUE; thiz->is_queue_callback_registered = TRUE;
} }
/* Fill the queue by enqueing buffers */ /* Preroll the buffer queue by enqueing segments */
for (i = 0; i < RECORDER_QUEUE_SIZE; i++) { for (i = 0; i < RECORDER_QUEUE_SIZE; i++) {
_opensles_recorder_cb (NULL, rb); _opensles_recorder_cb (NULL, rb);
} }
@ -240,6 +252,7 @@ _opensles_recorder_start (GstRingBuffer * rb)
(guint32) result); (guint32) result);
return FALSE; return FALSE;
} }
return TRUE; return TRUE;
} }
@ -280,7 +293,9 @@ _opensles_recorder_stop (GstRingBuffer * rb)
return TRUE; return TRUE;
} }
/* Player related functions */ /*
* Player related functions
*/
static gboolean static gboolean
_opensles_player_change_volume (GstRingBuffer * rb) _opensles_player_change_volume (GstRingBuffer * rb)
@ -326,6 +341,8 @@ _opensles_player_change_mute (GstRingBuffer * rb)
return TRUE; return TRUE;
} }
/* This is a callback function invoked by the playback device thread and
* it's used to monitor position changes */
static void static void
_opensles_player_event_cb (SLPlayItf caller, void *context, SLuint32 event) _opensles_player_event_cb (SLPlayItf caller, void *context, SLuint32 event)
{ {
@ -338,8 +355,6 @@ _opensles_player_event_cb (SLPlayItf caller, void *context, SLuint32 event)
(*caller)->GetPosition (caller, &position); (*caller)->GetPosition (caller, &position);
GST_LOG_OBJECT (thiz, "at position=%u ms", (guint) position); GST_LOG_OBJECT (thiz, "at position=%u ms", (guint) position);
} else if (event & SL_PLAYEVENT_HEADSTALLED) {
GST_WARNING_OBJECT (thiz, "head stalled");
} }
} }
@ -363,13 +378,14 @@ _opensles_player_acquire (GstRingBuffer * rb, GstRingBufferSpec * spec)
}; };
SLDataSink audioSink = { &loc_outmix, NULL }; SLDataSink audioSink = { &loc_outmix, NULL };
/* Create an audio player */ /* Define the required interfaces */
const SLInterfaceID ids[2] = { SL_IID_BUFFERQUEUE, SL_IID_VOLUME }; const SLInterfaceID ids[2] = { SL_IID_BUFFERQUEUE, SL_IID_VOLUME };
const SLboolean req[2] = { SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE }; const SLboolean req[2] = { SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE };
/* Define the format in OpenSL ES terms */ /* Define the format in OpenSL ES terminology */
_opensles_format (spec, &format); _opensles_format (spec, &format);
/* Create the player object */
result = (*thiz->engineEngine)->CreateAudioPlayer (thiz->engineEngine, result = (*thiz->engineEngine)->CreateAudioPlayer (thiz->engineEngine,
&thiz->playerObject, &audioSrc, &audioSink, 2, ids, req); &thiz->playerObject, &audioSrc, &audioSink, 2, ids, req);
if (result != SL_RESULT_SUCCESS) { if (result != SL_RESULT_SUCCESS) {
@ -378,7 +394,7 @@ _opensles_player_acquire (GstRingBuffer * rb, GstRingBufferSpec * spec)
goto failed; goto failed;
} }
/* Realize the player */ /* Realize the player object */
result = result =
(*thiz->playerObject)->Realize (thiz->playerObject, SL_BOOLEAN_FALSE); (*thiz->playerObject)->Realize (thiz->playerObject, SL_BOOLEAN_FALSE);
if (result != SL_RESULT_SUCCESS) { if (result != SL_RESULT_SUCCESS) {
@ -413,8 +429,8 @@ _opensles_player_acquire (GstRingBuffer * rb, GstRingBufferSpec * spec)
goto failed; goto failed;
} }
/* Request position update events at each 10 ms */ /* Request position update events at each 20 ms */
result = (*thiz->playerPlay)->SetPositionUpdatePeriod (thiz->playerPlay, 10); result = (*thiz->playerPlay)->SetPositionUpdatePeriod (thiz->playerPlay, 20);
if (result != SL_RESULT_SUCCESS) { if (result != SL_RESULT_SUCCESS) {
GST_ERROR_OBJECT (thiz, "player.SetPositionUpdatePeriod failed(0x%08x)", GST_ERROR_OBJECT (thiz, "player.SetPositionUpdatePeriod failed(0x%08x)",
(guint32) result); (guint32) result);
@ -423,7 +439,7 @@ _opensles_player_acquire (GstRingBuffer * rb, GstRingBufferSpec * spec)
/* Define the event mask to be monitorized */ /* Define the event mask to be monitorized */
result = (*thiz->playerPlay)->SetCallbackEventsMask (thiz->playerPlay, result = (*thiz->playerPlay)->SetCallbackEventsMask (thiz->playerPlay,
SL_PLAYEVENT_HEADATNEWPOS | SL_PLAYEVENT_HEADSTALLED); SL_PLAYEVENT_HEADATNEWPOS);
if (result != SL_RESULT_SUCCESS) { if (result != SL_RESULT_SUCCESS) {
GST_ERROR_OBJECT (thiz, "player.SetCallbackEventsMask failed(0x%08x)", GST_ERROR_OBJECT (thiz, "player.SetCallbackEventsMask failed(0x%08x)",
(guint32) result); (guint32) result);
@ -443,7 +459,7 @@ _opensles_player_acquire (GstRingBuffer * rb, GstRingBufferSpec * spec)
_opensles_player_change_volume (rb); _opensles_player_change_volume (rb);
_opensles_player_change_mute (rb); _opensles_player_change_mute (rb);
/* Define our queue data buffer */ /* Allocate the queue associated ringbuffer memory */
thiz->data_segtotal = loc_bufq.numBuffers; thiz->data_segtotal = loc_bufq.numBuffers;
thiz->data = g_malloc (spec->segsize * thiz->data_segtotal); thiz->data = g_malloc (spec->segsize * thiz->data_segtotal);
thiz->cursor = 0; thiz->cursor = 0;
@ -454,6 +470,16 @@ failed:
return FALSE; return FALSE;
} }
/* This callback function is executed when the ringbuffer is started to preroll
* the input buffer queue with few buffers, from app thread, and each time
* that rendering of one buffer finishes, from audio device processing thread,
* the callback behaviour.
*
* We wrap the queue behaviour with an appropriate chunk of memory (queue len *
* ringbuffer segment size) which is used to hold the audio data while it's
* being processed in the queue. The memory region is used whit a ringbuffer
* behaviour.
*/
static void static void
_opensles_player_cb (SLAndroidSimpleBufferQueueItf bufferQueue, void *context) _opensles_player_cb (SLAndroidSimpleBufferQueueItf bufferQueue, void *context)
{ {
@ -464,29 +490,33 @@ _opensles_player_cb (SLAndroidSimpleBufferQueueItf bufferQueue, void *context)
gint seg; gint seg;
gint len; gint len;
/* Get a segment form the GStreamer ringbuffer to read some samples */
if (!gst_ring_buffer_prepare_read (rb, &seg, &ptr, &len)) { if (!gst_ring_buffer_prepare_read (rb, &seg, &ptr, &len)) {
GST_WARNING_OBJECT (rb, "No segment available"); GST_WARNING_OBJECT (rb, "No segment available");
return; return;
} }
/* copy data to our queue ringbuffer */ /* copy the segment data to our queue associated ringbuffer memory */
cur = thiz->data + (thiz->cursor * rb->spec.segsize); cur = thiz->data + (thiz->cursor * rb->spec.segsize);
memcpy (cur, ptr, len); memcpy (cur, ptr, len);
g_atomic_int_inc (&thiz->segqueued); g_atomic_int_inc (&thiz->segqueued);
/* Enqueue a buffer */
GST_LOG_OBJECT (thiz, "enqueue: %p size %d segment: %d in queue[%d]", GST_LOG_OBJECT (thiz, "enqueue: %p size %d segment: %d in queue[%d]",
cur, len, seg, thiz->cursor); cur, len, seg, thiz->cursor);
result = (*thiz->bufferQueue)->Enqueue (thiz->bufferQueue, cur, len); /* advance the cursor in our queue associated ringbuffer */
thiz->cursor = (thiz->cursor + 1) % thiz->data_segtotal; thiz->cursor = (thiz->cursor + 1) % thiz->data_segtotal;
/* Enqueue the buffer to be rendered */
result = (*thiz->bufferQueue)->Enqueue (thiz->bufferQueue, cur, len);
if (result != SL_RESULT_SUCCESS) { if (result != SL_RESULT_SUCCESS) {
GST_ERROR_OBJECT (thiz, "bufferQueue.Enqueue failed(0x%08x)", GST_ERROR_OBJECT (thiz, "bufferQueue.Enqueue failed(0x%08x)",
(guint32) result); (guint32) result);
return; return;
} }
/* Fill with silence samples the segment of the GStreamer ringbuffer */
gst_ring_buffer_clear (rb, seg); gst_ring_buffer_clear (rb, seg);
/* Make the segment reusable */
gst_ring_buffer_advance (rb, 1); gst_ring_buffer_advance (rb, 1);
} }
@ -540,6 +570,7 @@ _opensles_player_pause (GstRingBuffer * rb)
(guint32) result); (guint32) result);
return FALSE; return FALSE;
} }
return TRUE; return TRUE;
} }
@ -553,7 +584,6 @@ _opensles_player_stop (GstRingBuffer * rb)
result = result =
(*thiz->playerPlay)->SetPlayState (thiz->playerPlay, (*thiz->playerPlay)->SetPlayState (thiz->playerPlay,
SL_PLAYSTATE_STOPPED); SL_PLAYSTATE_STOPPED);
if (result != SL_RESULT_SUCCESS) { if (result != SL_RESULT_SUCCESS) {
GST_ERROR_OBJECT (thiz, "player.SetPlayState failed(0x%08x)", GST_ERROR_OBJECT (thiz, "player.SetPlayState failed(0x%08x)",
(guint32) result); (guint32) result);
@ -578,13 +608,17 @@ _opensles_player_stop (GstRingBuffer * rb)
return FALSE; return FALSE;
} }
/* Reset our state */
g_atomic_int_set (&thiz->segqueued, 0); g_atomic_int_set (&thiz->segqueued, 0);
thiz->cursor = 0; thiz->cursor = 0;
return TRUE; return TRUE;
} }
/* OpenSL ES ring buffer wrapper */ /*
* OpenSL ES ringbuffer wrapper
*/
GstRingBuffer * GstRingBuffer *
gst_opensles_ringbuffer_new (RingBufferMode mode) gst_opensles_ringbuffer_new (RingBufferMode mode)
@ -613,6 +647,7 @@ gst_opensles_ringbuffer_new (RingBufferMode mode)
} }
GST_DEBUG_OBJECT (thiz, "ringbuffer created"); GST_DEBUG_OBJECT (thiz, "ringbuffer created");
return GST_RING_BUFFER (thiz); return GST_RING_BUFFER (thiz);
} }
@ -652,14 +687,14 @@ gst_opensles_ringbuffer_open_device (GstRingBuffer * rb)
thiz = GST_OPENSLES_RING_BUFFER_CAST (rb); thiz = GST_OPENSLES_RING_BUFFER_CAST (rb);
/* Create engine */ /* Create the engine object */
result = slCreateEngine (&thiz->engineObject, 0, NULL, 0, NULL, NULL); result = slCreateEngine (&thiz->engineObject, 0, NULL, 0, NULL, NULL);
if (result != SL_RESULT_SUCCESS) { if (result != SL_RESULT_SUCCESS) {
GST_ERROR_OBJECT (thiz, "slCreateEngine failed(0x%08x)", (guint32) result); GST_ERROR_OBJECT (thiz, "slCreateEngine failed(0x%08x)", (guint32) result);
goto failed; goto failed;
} }
/* Realize the engine */ /* Realize the engine object */
result = (*thiz->engineObject)->Realize (thiz->engineObject, result = (*thiz->engineObject)->Realize (thiz->engineObject,
SL_BOOLEAN_FALSE); SL_BOOLEAN_FALSE);
if (result != SL_RESULT_SUCCESS) { if (result != SL_RESULT_SUCCESS) {
@ -667,8 +702,7 @@ gst_opensles_ringbuffer_open_device (GstRingBuffer * rb)
goto failed; goto failed;
} }
/* Get the engine interface, which is needed in order to /* Get the engine interface, which is needed in order to create other objects */
* create other objects */
result = (*thiz->engineObject)->GetInterface (thiz->engineObject, result = (*thiz->engineObject)->GetInterface (thiz->engineObject,
SL_IID_ENGINE, &thiz->engineEngine); SL_IID_ENGINE, &thiz->engineEngine);
if (result != SL_RESULT_SUCCESS) { if (result != SL_RESULT_SUCCESS) {
@ -680,7 +714,7 @@ gst_opensles_ringbuffer_open_device (GstRingBuffer * rb)
if (thiz->mode == RB_MODE_SINK_PCM) { if (thiz->mode == RB_MODE_SINK_PCM) {
SLOutputMixItf outputMix; SLOutputMixItf outputMix;
/* Create an output mixer */ /* Create an output mixer object */
result = (*thiz->engineEngine)->CreateOutputMix (thiz->engineEngine, result = (*thiz->engineEngine)->CreateOutputMix (thiz->engineEngine,
&thiz->outputMixObject, 0, NULL, NULL); &thiz->outputMixObject, 0, NULL, NULL);
if (result != SL_RESULT_SUCCESS) { if (result != SL_RESULT_SUCCESS) {
@ -689,7 +723,7 @@ gst_opensles_ringbuffer_open_device (GstRingBuffer * rb)
goto failed; goto failed;
} }
/* Realize the output mixer */ /* Realize the output mixer object */
result = (*thiz->outputMixObject)->Realize (thiz->outputMixObject, result = (*thiz->outputMixObject)->Realize (thiz->outputMixObject,
SL_BOOLEAN_FALSE); SL_BOOLEAN_FALSE);
if (result != SL_RESULT_SUCCESS) { if (result != SL_RESULT_SUCCESS) {
@ -698,16 +732,18 @@ gst_opensles_ringbuffer_open_device (GstRingBuffer * rb)
goto failed; goto failed;
} }
/* Check for output device options */ /* Get the mixer interface */
result = (*thiz->outputMixObject)->GetInterface (thiz->outputMixObject, result = (*thiz->outputMixObject)->GetInterface (thiz->outputMixObject,
SL_IID_OUTPUTMIX, &outputMix); SL_IID_OUTPUTMIX, &outputMix);
if (result != SL_RESULT_SUCCESS) { if (result != SL_RESULT_SUCCESS) {
GST_WARNING_OBJECT (thiz, "outputMix.GetInterface failed(0x%08x)", GST_WARNING_OBJECT (thiz, "outputMix.GetInterface failed(0x%08x)",
(guint32) result); (guint32) result);
} else { } else {
SLint32 numDevices; SLint32 numDevices = 0;
SLuint32 deviceIDs[16]; SLuint32 deviceIDs[MAX_NUMBER_OUTPUT_DEVICES];
gint i; gint i;
/* Query the list of output devices */
(*outputMix)->GetDestinationOutputDeviceIDs (outputMix, &numDevices, (*outputMix)->GetDestinationOutputDeviceIDs (outputMix, &numDevices,
deviceIDs); deviceIDs);
GST_DEBUG_OBJECT (thiz, "Found %d output devices", (gint) numDevices); GST_DEBUG_OBJECT (thiz, "Found %d output devices", (gint) numDevices);
@ -731,13 +767,13 @@ gst_opensles_ringbuffer_close_device (GstRingBuffer * rb)
thiz = GST_OPENSLES_RING_BUFFER_CAST (rb); thiz = GST_OPENSLES_RING_BUFFER_CAST (rb);
/* Destroy output mix object */ /* Destroy the output mix object */
if (thiz->outputMixObject) { if (thiz->outputMixObject) {
(*thiz->outputMixObject)->Destroy (thiz->outputMixObject); (*thiz->outputMixObject)->Destroy (thiz->outputMixObject);
thiz->outputMixObject = NULL; thiz->outputMixObject = NULL;
} }
/* Destroy engine object, and invalidate all associated interfaces */ /* Destroy the engine object and invalidate all associated interfaces */
if (thiz->engineObject) { if (thiz->engineObject) {
(*thiz->engineObject)->Destroy (thiz->engineObject); (*thiz->engineObject)->Destroy (thiz->engineObject);
thiz->engineObject = NULL; thiz->engineObject = NULL;
@ -801,6 +837,7 @@ gst_opensles_ringbuffer_release (GstRingBuffer * rb)
gst_buffer_unref (rb->data); gst_buffer_unref (rb->data);
rb->data = NULL; rb->data = NULL;
} }
GST_DEBUG_OBJECT (thiz, "ringbuffer released"); GST_DEBUG_OBJECT (thiz, "ringbuffer released");
return TRUE; return TRUE;
} }

View file

@ -28,6 +28,8 @@
G_BEGIN_DECLS G_BEGIN_DECLS
#define MAX_NUMBER_OUTPUT_DEVICES 16
#define GST_TYPE_OPENSLES_RING_BUFFER \ #define GST_TYPE_OPENSLES_RING_BUFFER \
(gst_opensles_ringbuffer_get_type()) (gst_opensles_ringbuffer_get_type())
#define GST_OPENSLES_RING_BUFFER(obj) \ #define GST_OPENSLES_RING_BUFFER(obj) \

View file

@ -17,6 +17,21 @@
* Boston, MA 02111-1307, USA. * Boston, MA 02111-1307, USA.
*/ */
/**
* SECTION:element-openslessink
* @see_also: openslessrc
*
* This element renders raw audio samples using the OpenSL ES API in Android OS.
*
* <refsect2>
* <title>Example pipelines</title>
* |[
* gst-launch -v filesrc location=music.ogg ! oggdemux ! vorbisdec ! audioconvert ! audioresample ! opeslessink
* ]| Play an Ogg/Vorbis file.
* </refsect2>
*
*/
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
# include <config.h> # include <config.h>
#endif #endif
@ -40,6 +55,9 @@ enum
/* According to Android's NDK doc the following are the supported rates */ /* According to Android's NDK doc the following are the supported rates */
#define RATES "8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100" #define RATES "8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100"
/* 48000 Hz is also claimed to be supported but the AudioFlinger downsampling
* doesn't seems to work properly so we relay GStreamer audioresample element
* to cope with this samplerate. */
static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink", static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK, GST_PAD_SINK,
@ -106,11 +124,6 @@ gst_opensles_sink_create_ringbuffer (GstBaseAudioSink * base)
(gint) (aod)->maxSampleRate, (gint) (aod)->isFreqRangeContinuous, \ (gint) (aod)->maxSampleRate, (gint) (aod)->isFreqRangeContinuous, \
(gint) (aod)->maxChannels (gint) (aod)->maxChannels
/* Next it's not defined in Android */
#ifndef MAX_NUMBER_OUTPUT_DEVICES
#define MAX_NUMBER_OUTPUT_DEVICES 16
#endif
static gboolean static gboolean
_opensles_query_capabilities (GstOpenSLESSink * sink) _opensles_query_capabilities (GstOpenSLESSink * sink)
{ {
@ -136,8 +149,7 @@ _opensles_query_capabilities (GstOpenSLESSink * sink)
goto beach; goto beach;
} }
/* Get the engine interface, which is needed in order to /* Get the engine interface, which is needed in order to create other objects */
* create other objects */
result = (*engineObject)->GetInterface (engineObject, result = (*engineObject)->GetInterface (engineObject,
SL_IID_AUDIOIODEVICECAPABILITIES, &audioIODeviceCapabilities); SL_IID_AUDIOIODEVICECAPABILITIES, &audioIODeviceCapabilities);
if (result != SL_RESULT_SUCCESS) { if (result != SL_RESULT_SUCCESS) {
@ -147,6 +159,7 @@ _opensles_query_capabilities (GstOpenSLESSink * sink)
goto beach; goto beach;
} }
/* Query the list of available audio outputs */
result = (*audioIODeviceCapabilities)->GetAvailableAudioOutputs result = (*audioIODeviceCapabilities)->GetAvailableAudioOutputs
(audioIODeviceCapabilities, &numOutputs, outputDeviceIDs); (audioIODeviceCapabilities, &numOutputs, outputDeviceIDs);
if (result != SL_RESULT_SUCCESS) { if (result != SL_RESULT_SUCCESS) {
@ -182,7 +195,7 @@ _opensles_query_capabilities (GstOpenSLESSink * sink)
res = TRUE; res = TRUE;
beach: beach:
/* Destroy engine object */ /* Destroy the engine object */
if (engineObject) { if (engineObject) {
(*engineObject)->Destroy (engineObject); (*engineObject)->Destroy (engineObject);
} }
@ -269,6 +282,8 @@ gst_opensles_sink_init (GstOpenSLESSink * sink, GstOpenSLESSinkClass * gclass)
_opensles_query_capabilities (sink); _opensles_query_capabilities (sink);
gst_base_audio_sink_set_provide_clock (GST_BASE_AUDIO_SINK (sink), TRUE); gst_base_audio_sink_set_provide_clock (GST_BASE_AUDIO_SINK (sink), TRUE);
/* Override some default values to fit on the AudioFlinger behaviour of
* processing 20ms buffers as minimum buffer size. */
GST_BASE_AUDIO_SINK (sink)->buffer_time = 400000; GST_BASE_AUDIO_SINK (sink)->buffer_time = 400000;
GST_BASE_AUDIO_SINK (sink)->latency_time = 20000; GST_BASE_AUDIO_SINK (sink)->latency_time = 20000;
} }

View file

@ -17,6 +17,21 @@
* Boston, MA 02111-1307, USA. * Boston, MA 02111-1307, USA.
*/ */
/**
* SECTION:element-openslessrc
* @see_also: openslessink
*
* This element reads data from default audio input using the OpenSL ES API in Android OS.
*
* <refsect2>
* <title>Example pipelines</title>
* |[
* gst-launch -v openslessrc ! audioconvert ! vorbisenc ! oggmux ! filesink location=recorded.ogg
* ]| Record from default audio input and encode to Ogg/Vorbis.
* </refsect2>
*
*/
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
# include <config.h> # include <config.h>
#endif #endif