mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-04-26 06:54:49 +00:00
opensles: sprinkle comments and cosmetic fixes
This commit is contained in:
parent
78e3b9f428
commit
920354eb0d
4 changed files with 112 additions and 43 deletions
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) \
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue