Files
cocos-engine/native/cocos/audio/android/AudioDecoderSLES.cpp

621 lines
24 KiB
C++

#define LOG_TAG "AudioDecoderSLES"
#include "audio/android/AudioDecoderSLES.h"
#include "platform/CCFileUtils.h"
namespace cocos2d { namespace experimental {
/* Explicitly requesting SL_IID_ANDROIDSIMPLEBUFFERQUEUE and SL_IID_PREFETCHSTATUS
* on the UrlAudioPlayer object for decoding, SL_IID_METADATAEXTRACTION for retrieving the
* format of the decoded audio */
#define NUM_EXPLICIT_INTERFACES_FOR_PLAYER 3
/* Size of the decode buffer queue */
#define NB_BUFFERS_IN_QUEUE 4
/* size of the struct to retrieve the PCM format metadata values: the values we're interested in
* are SLuint32, but it is saved in the data field of a SLMetadataInfo, hence the larger size.
* Nate that this size is queried and displayed at l.452 for demonstration/test purposes.
* */
#define PCM_METADATA_VALUE_SIZE 32
/* used to detect errors likely to have occurred when the OpenSL ES framework fails to open
* a resource, for instance because a file URI is invalid, or an HTTP server doesn't respond.
*/
#define PREFETCHEVENT_ERROR_CANDIDATE (SL_PREFETCHEVENT_STATUSCHANGE | SL_PREFETCHEVENT_FILLLEVELCHANGE)
//-----------------------------------------------------------------
static std::mutex __SLPlayerMutex;
static int toBufferSizeInBytes(int bufferSizeInFrames, int sampleSize, int channelCount)
{
return bufferSizeInFrames * sampleSize * channelCount;
}
static int BUFFER_SIZE_IN_BYTES = 0;
static void checkMetaData(int index, const char *key)
{
if (index != -1)
{
ALOGV("Key %s is at index %d", key, index);
}
else
{
ALOGE("Unable to find key %s", key);
}
}
class SLAudioDecoderCallbackProxy
{
public:
//-----------------------------------------------------------------
/* Callback for "prefetch" events, here used to detect audio resource opening errors */
static void prefetchEventCallback(SLPrefetchStatusItf caller, void *context, SLuint32 event)
{
AudioDecoderSLES *thiz = reinterpret_cast<AudioDecoderSLES *>(context);
thiz->prefetchCallback(caller, event);
}
static void decPlayCallback(SLAndroidSimpleBufferQueueItf queueItf, void *context)
{
AudioDecoderSLES *thiz = reinterpret_cast<AudioDecoderSLES *>(context);
thiz->decodeToPcmCallback(queueItf);
}
static void decProgressCallback(SLPlayItf caller, void *context, SLuint32 event)
{
AudioDecoderSLES *thiz = reinterpret_cast<AudioDecoderSLES *>(context);
thiz->decodeProgressCallback(caller, event);
}
};
AudioDecoderSLES::AudioDecoderSLES()
: _engineItf(nullptr), _playObj(nullptr), _formatQueried(false),
_prefetchError(false), _counter(0), _numChannelsKeyIndex(-1), _sampleRateKeyIndex(-1),
_bitsPerSampleKeyIndex(-1), _containerSizeKeyIndex(-1), _channelMaskKeyIndex(-1),
_endiannessKeyIndex(-1), _eos(false), _bufferSizeInFrames(-1),
_assetFd(0), _fdGetterCallback(nullptr), _isDecodingCallbackInvoked(false)
{
ALOGV("Create AudioDecoderSLES");
}
AudioDecoderSLES::~AudioDecoderSLES()
{
{
std::lock_guard<std::mutex> lk(__SLPlayerMutex);
SL_DESTROY_OBJ(_playObj);
}
ALOGV("After destroying SL play object");
if (_assetFd > 0)
{
ALOGV("Closing assetFd: %d", _assetFd);
::close(_assetFd);
_assetFd = 0;
}
free(_pcmData);
}
bool AudioDecoderSLES::init(SLEngineItf engineItf, const std::string &url, int bufferSizeInFrames, int sampleRate, const FdGetterCallback &fdGetterCallback)
{
if (AudioDecoder::init(url, sampleRate))
{
_engineItf = engineItf;
_bufferSizeInFrames = bufferSizeInFrames;
_fdGetterCallback = fdGetterCallback;
BUFFER_SIZE_IN_BYTES = toBufferSizeInBytes(bufferSizeInFrames, 2, 2);
_pcmData = (char*) malloc(NB_BUFFERS_IN_QUEUE * BUFFER_SIZE_IN_BYTES);
memset(_pcmData, 0x00, NB_BUFFERS_IN_QUEUE * BUFFER_SIZE_IN_BYTES);
return true;
}
return false;
}
bool AudioDecoderSLES::decodeToPcm()
{
SLresult result;
/* Objects this application uses: one audio player */
SLObjectItf player;
/* Interfaces for the audio player */
SLAndroidSimpleBufferQueueItf decBuffQueueItf;
SLPrefetchStatusItf prefetchItf;
SLPlayItf playItf;
SLMetadataExtractionItf mdExtrItf;
/* Source of audio data for the decoding */
SLDataSource decSource;
// decUri & locFd should be defined here
SLDataLocator_URI decUri;
SLDataLocator_AndroidFD locFd;
/* Data sink for decoded audio */
SLDataSink decDest;
SLDataLocator_AndroidSimpleBufferQueue decBuffQueue;
SLDataFormat_PCM pcm;
SLboolean required[NUM_EXPLICIT_INTERFACES_FOR_PLAYER];
SLInterfaceID iidArray[NUM_EXPLICIT_INTERFACES_FOR_PLAYER];
/* Initialize arrays required[] and iidArray[] */
for (int i = 0; i < NUM_EXPLICIT_INTERFACES_FOR_PLAYER; i++)
{
required[i] = SL_BOOLEAN_FALSE;
iidArray[i] = SL_IID_NULL;
}
/* ------------------------------------------------------ */
/* Configuration of the player */
/* Request the AndroidSimpleBufferQueue interface */
required[0] = SL_BOOLEAN_TRUE;
iidArray[0] = SL_IID_ANDROIDSIMPLEBUFFERQUEUE;
/* Request the PrefetchStatus interface */
required[1] = SL_BOOLEAN_TRUE;
iidArray[1] = SL_IID_PREFETCHSTATUS;
/* Request the PrefetchStatus interface */
required[2] = SL_BOOLEAN_TRUE;
iidArray[2] = SL_IID_METADATAEXTRACTION;
SLDataFormat_MIME formatMime = {SL_DATAFORMAT_MIME, nullptr, SL_CONTAINERTYPE_UNSPECIFIED};
decSource.pFormat = &formatMime;
if (_url[0] != '/')
{
off_t start = 0, length = 0;
std::string relativePath;
size_t position = _url.find("assets/");
if (0 == position)
{
// "assets/" is at the beginning of the path and we don't want it
relativePath = _url.substr(strlen("assets/"));
} else
{
relativePath = _url;
}
_assetFd = _fdGetterCallback(relativePath, &start, &length);
if (_assetFd <= 0)
{
ALOGE("Failed to open file descriptor for '%s'", _url.c_str());
return false;
}
// configure audio source
locFd = {SL_DATALOCATOR_ANDROIDFD, _assetFd, start, length};
decSource.pLocator = &locFd;
}
else
{
decUri = {SL_DATALOCATOR_URI, (SLchar *) _url.c_str()};
decSource.pLocator = &decUri;
}
/* Setup the data sink */
decBuffQueue.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE;
decBuffQueue.numBuffers = NB_BUFFERS_IN_QUEUE;
/* set up the format of the data in the buffer queue */
pcm.formatType = SL_DATAFORMAT_PCM;
// FIXME valid value required but currently ignored
pcm.numChannels = 2;
pcm.samplesPerSec = SL_SAMPLINGRATE_44_1;
pcm.bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_16;
pcm.containerSize = SL_PCMSAMPLEFORMAT_FIXED_16;
pcm.channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
pcm.endianness = SL_BYTEORDER_LITTLEENDIAN;
decDest.pLocator = (void *) &decBuffQueue;
decDest.pFormat = (void *) &pcm;
{
std::lock_guard<std::mutex> lk(__SLPlayerMutex);
/* Create the audio player */
result = (*_engineItf)->CreateAudioPlayer(_engineItf, &player, &decSource, &decDest,
NUM_EXPLICIT_INTERFACES_FOR_PLAYER, iidArray,
required);
SL_RETURN_VAL_IF_FAILED(result, false, "CreateAudioPlayer failed");
_playObj = player;
/* Realize the player in synchronous mode. */
result = (*player)->Realize(player, SL_BOOLEAN_FALSE);
SL_RETURN_VAL_IF_FAILED(result, false, "Realize failed");
}
/* Get the play interface which is implicit */
result = (*player)->GetInterface(player, SL_IID_PLAY, (void *) &playItf);
SL_RETURN_VAL_IF_FAILED(result, false, "GetInterface SL_IID_PLAY failed");
/* Set up the player callback to get events during the decoding */
// FIXME currently ignored
result = (*playItf)->SetMarkerPosition(playItf, 2000);
SL_RETURN_VAL_IF_FAILED(result, false, "SetMarkerPosition failed");
result = (*playItf)->SetPositionUpdatePeriod(playItf, 500);
SL_RETURN_VAL_IF_FAILED(result, false, "SetPositionUpdatePeriod failed");
result = (*playItf)->SetCallbackEventsMask(playItf,
SL_PLAYEVENT_HEADATMARKER |
SL_PLAYEVENT_HEADATNEWPOS | SL_PLAYEVENT_HEADATEND);
SL_RETURN_VAL_IF_FAILED(result, false, "SetCallbackEventsMask failed");
result = (*playItf)->RegisterCallback(playItf, SLAudioDecoderCallbackProxy::decProgressCallback,
this);
SL_RETURN_VAL_IF_FAILED(result, false, "RegisterCallback failed");
ALOGV("Play callback registered");
/* Get the buffer queue interface which was explicitly requested */
result = (*player)->GetInterface(player, SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
(void *) &decBuffQueueItf);
SL_RETURN_VAL_IF_FAILED(result, false, "GetInterface SL_IID_ANDROIDSIMPLEBUFFERQUEUE failed");
/* Get the prefetch status interface which was explicitly requested */
result = (*player)->GetInterface(player, SL_IID_PREFETCHSTATUS, (void *) &prefetchItf);
SL_RETURN_VAL_IF_FAILED(result, false, "GetInterface SL_IID_PREFETCHSTATUS failed");
/* Get the metadata extraction interface which was explicitly requested */
result = (*player)->GetInterface(player, SL_IID_METADATAEXTRACTION, (void *) &mdExtrItf);
SL_RETURN_VAL_IF_FAILED(result, false, "GetInterface SL_IID_METADATAEXTRACTION failed");
/* ------------------------------------------------------ */
/* Initialize the callback and its context for the decoding buffer queue */
_decContext.playItf = playItf;
_decContext.metaItf = mdExtrItf;
_decContext.pDataBase = (int8_t *) _pcmData;
_decContext.pData = _decContext.pDataBase;
_decContext.size = NB_BUFFERS_IN_QUEUE * BUFFER_SIZE_IN_BYTES;
result = (*decBuffQueueItf)->RegisterCallback(decBuffQueueItf,
SLAudioDecoderCallbackProxy::decPlayCallback,
this);
SL_RETURN_VAL_IF_FAILED(result, false, "decBuffQueueItf RegisterCallback failed");
/* Enqueue buffers to map the region of memory allocated to store the decoded data */
// ALOGV("Enqueueing buffer ");
for (int i = 0; i < NB_BUFFERS_IN_QUEUE; i++)
{
result = (*decBuffQueueItf)->Enqueue(decBuffQueueItf, _decContext.pData,
BUFFER_SIZE_IN_BYTES);
SL_RETURN_VAL_IF_FAILED(result, false, "Enqueue failed");
_decContext.pData += BUFFER_SIZE_IN_BYTES;
}
_decContext.pData = _decContext.pDataBase;
/* ------------------------------------------------------ */
/* Initialize the callback for prefetch errors, if we can't open the resource to decode */
result = (*prefetchItf)->RegisterCallback(prefetchItf,
SLAudioDecoderCallbackProxy::prefetchEventCallback,
this);
SL_RETURN_VAL_IF_FAILED(result, false, "prefetchItf RegisterCallback failed");
result = (*prefetchItf)->SetCallbackEventsMask(prefetchItf, PREFETCHEVENT_ERROR_CANDIDATE);
SL_RETURN_VAL_IF_FAILED(result, false, "prefetchItf SetCallbackEventsMask failed");
/* ------------------------------------------------------ */
/* Prefetch the data so we can get information about the format before starting to decode */
/* 1/ cause the player to prefetch the data */
result = (*playItf)->SetPlayState(playItf, SL_PLAYSTATE_PAUSED);
SL_RETURN_VAL_IF_FAILED(result, false, "SetPlayState SL_PLAYSTATE_PAUSED failed");
/* 2/ block until data has been prefetched */
SLuint32 prefetchStatus = SL_PREFETCHSTATUS_UNDERFLOW;
SLuint32 timeOutIndex = 1000; //cjh time out prefetching after 2s
while ((prefetchStatus != SL_PREFETCHSTATUS_SUFFICIENTDATA) && (timeOutIndex > 0) &&
!_prefetchError)
{
std::this_thread::sleep_for(std::chrono::milliseconds(2));
(*prefetchItf)->GetPrefetchStatus(prefetchItf, &prefetchStatus);
timeOutIndex--;
}
if (timeOutIndex == 0 || _prefetchError)
{
ALOGE("Failure to prefetch data in time, exiting");
SL_RETURN_VAL_IF_FAILED(SL_RESULT_CONTENT_NOT_FOUND, false,
"Failure to prefetch data in time");
}
/* ------------------------------------------------------ */
/* Display duration */
SLmillisecond durationInMsec = SL_TIME_UNKNOWN;
result = (*playItf)->GetDuration(playItf, &durationInMsec);
SL_RETURN_VAL_IF_FAILED(result, false, "GetDuration failed");
if (durationInMsec == SL_TIME_UNKNOWN)
{
ALOGV("Content duration is unknown");
} else
{
ALOGV("Content duration is %dms", (int)durationInMsec);
}
/* ------------------------------------------------------ */
/* Display the metadata obtained from the decoder */
// This is for test / demonstration purposes only where we discover the key and value sizes
// of a PCM decoder. An application that would want to directly get access to those values
// can make assumptions about the size of the keys and their matching values (all SLuint32)
SLuint32 itemCount;
result = (*mdExtrItf)->GetItemCount(mdExtrItf, &itemCount);
SLuint32 i, keySize, valueSize;
SLMetadataInfo *keyInfo, *value;
for (i = 0; i < itemCount; i++)
{
keyInfo = nullptr;
keySize = 0;
value = nullptr;
valueSize = 0;
result = (*mdExtrItf)->GetKeySize(mdExtrItf, i, &keySize);
SL_RETURN_VAL_IF_FAILED(result, false, "GetKeySize(%d) failed", (int)i);
result = (*mdExtrItf)->GetValueSize(mdExtrItf, i, &valueSize);
SL_RETURN_VAL_IF_FAILED(result, false, "GetValueSize(%d) failed", (int)i);
keyInfo = (SLMetadataInfo *) malloc(keySize);
if (nullptr != keyInfo)
{
result = (*mdExtrItf)->GetKey(mdExtrItf, i, keySize, keyInfo);
SL_RETURN_VAL_IF_FAILED(result, false, "GetKey(%d) failed", (int)i);
ALOGV("key[%d] size=%d, name=%s, value size=%d",
(int)i, (int)keyInfo->size, keyInfo->data, (int)valueSize);
/* find out the key index of the metadata we're interested in */
if (!strcmp((char *) keyInfo->data, ANDROID_KEY_PCMFORMAT_NUMCHANNELS))
{
_numChannelsKeyIndex = i;
} else if (!strcmp((char *) keyInfo->data, ANDROID_KEY_PCMFORMAT_SAMPLERATE))
{
_sampleRateKeyIndex = i;
} else if (!strcmp((char *) keyInfo->data, ANDROID_KEY_PCMFORMAT_BITSPERSAMPLE))
{
_bitsPerSampleKeyIndex = i;
} else if (!strcmp((char *) keyInfo->data, ANDROID_KEY_PCMFORMAT_CONTAINERSIZE))
{
_containerSizeKeyIndex = i;
} else if (!strcmp((char *) keyInfo->data, ANDROID_KEY_PCMFORMAT_CHANNELMASK))
{
_channelMaskKeyIndex = i;
} else if (!strcmp((char *) keyInfo->data, ANDROID_KEY_PCMFORMAT_ENDIANNESS))
{
_endiannessKeyIndex = i;
}
free(keyInfo);
}
}
checkMetaData(_numChannelsKeyIndex, ANDROID_KEY_PCMFORMAT_NUMCHANNELS);
checkMetaData(_sampleRateKeyIndex, ANDROID_KEY_PCMFORMAT_SAMPLERATE);
checkMetaData(_bitsPerSampleKeyIndex, ANDROID_KEY_PCMFORMAT_BITSPERSAMPLE);
checkMetaData(_containerSizeKeyIndex, ANDROID_KEY_PCMFORMAT_CONTAINERSIZE);
checkMetaData(_channelMaskKeyIndex, ANDROID_KEY_PCMFORMAT_CHANNELMASK);
checkMetaData(_endiannessKeyIndex, ANDROID_KEY_PCMFORMAT_ENDIANNESS);
/* ------------------------------------------------------ */
/* Start decoding */
result = (*playItf)->SetPlayState(playItf, SL_PLAYSTATE_PLAYING);
SL_RETURN_VAL_IF_FAILED(result, false, "SetPlayState SL_PLAYSTATE_PLAYING failed");
ALOGV("Starting to decode");
/* Decode until the end of the stream is reached */
{
std::unique_lock<std::mutex> autoLock(_eosLock);
while (!_eos)
{
_eosCondition.wait(autoLock);
}
}
ALOGV("EOS signaled");
/* ------------------------------------------------------ */
/* End of decoding */
/* Stop decoding */
result = (*playItf)->SetPlayState(playItf, SL_PLAYSTATE_STOPPED);
SL_RETURN_VAL_IF_FAILED(result, false, "SetPlayState SL_PLAYSTATE_STOPPED failed");
ALOGV("Stopped decoding");
/* Destroy the UrlAudioPlayer object */
{
std::lock_guard<std::mutex> lk(__SLPlayerMutex);
SL_DESTROY_OBJ(_playObj);
}
ALOGV("After destroy player ...");
_result.numFrames =
_result.pcmBuffer->size() / _result.numChannels / (_result.bitsPerSample / 8);
std::string info = _result.toString();
ALOGI("Original audio info: %s, total size: %d", info.c_str(), (int)_result.pcmBuffer->size());
return true;
}
//-----------------------------------------------------------------
void AudioDecoderSLES::signalEos()
{
std::unique_lock<std::mutex> autoLock(_eosLock);
_eos = true;
_eosCondition.notify_one();
}
void AudioDecoderSLES::queryAudioInfo()
{
if (_formatQueried)
{
return;
}
SLresult result;
/* Get duration in callback where we use the callback context for the SLPlayItf*/
SLmillisecond durationInMsec = SL_TIME_UNKNOWN;
result = (*_decContext.playItf)->GetDuration(_decContext.playItf, &durationInMsec);
SL_RETURN_IF_FAILED(result, "decodeProgressCallback,GetDuration failed");
if (durationInMsec == SL_TIME_UNKNOWN)
{
ALOGV("Content duration is unknown (in dec callback)");
} else
{
ALOGV("Content duration is %dms (in dec callback)", (int)durationInMsec);
_result.duration = durationInMsec / 1000.0f;
}
/* used to query metadata values */
SLMetadataInfo pcmMetaData;
result = (*_decContext.metaItf)->GetValue(_decContext.metaItf, _sampleRateKeyIndex,
PCM_METADATA_VALUE_SIZE, &pcmMetaData);
SL_RETURN_IF_FAILED(result, "%s GetValue _sampleRateKeyIndex failed", __FUNCTION__);
// Note: here we could verify the following:
// pcmMetaData->encoding == SL_CHARACTERENCODING_BINARY
// pcmMetaData->size == sizeof(SLuint32)
// but the call was successful for the PCM format keys, so those conditions are implied
_result.sampleRate = *((SLuint32 *) pcmMetaData.data);
result = (*_decContext.metaItf)->GetValue(_decContext.metaItf, _numChannelsKeyIndex,
PCM_METADATA_VALUE_SIZE, &pcmMetaData);
SL_RETURN_IF_FAILED(result, "%s GetValue _numChannelsKeyIndex failed", __FUNCTION__);
_result.numChannels = *((SLuint32 *) pcmMetaData.data);
result = (*_decContext.metaItf)->GetValue(_decContext.metaItf, _bitsPerSampleKeyIndex,
PCM_METADATA_VALUE_SIZE, &pcmMetaData);
SL_RETURN_IF_FAILED(result, "%s GetValue _bitsPerSampleKeyIndex failed", __FUNCTION__)
_result.bitsPerSample = *((SLuint32 *) pcmMetaData.data);
result = (*_decContext.metaItf)->GetValue(_decContext.metaItf, _containerSizeKeyIndex,
PCM_METADATA_VALUE_SIZE, &pcmMetaData);
SL_RETURN_IF_FAILED(result, "%s GetValue _containerSizeKeyIndex failed", __FUNCTION__)
_result.containerSize = *((SLuint32 *) pcmMetaData.data);
result = (*_decContext.metaItf)->GetValue(_decContext.metaItf, _channelMaskKeyIndex,
PCM_METADATA_VALUE_SIZE, &pcmMetaData);
SL_RETURN_IF_FAILED(result, "%s GetValue _channelMaskKeyIndex failed", __FUNCTION__)
_result.channelMask = *((SLuint32 *) pcmMetaData.data);
result = (*_decContext.metaItf)->GetValue(_decContext.metaItf, _endiannessKeyIndex,
PCM_METADATA_VALUE_SIZE, &pcmMetaData);
SL_RETURN_IF_FAILED(result, "%s GetValue _endiannessKeyIndex failed", __FUNCTION__)
_result.endianness = *((SLuint32 *) pcmMetaData.data);
_formatQueried = true;
}
void AudioDecoderSLES::prefetchCallback(SLPrefetchStatusItf caller, SLuint32 event)
{
SLpermille level = 0;
SLresult result;
result = (*caller)->GetFillLevel(caller, &level);
SL_RETURN_IF_FAILED(result, "GetFillLevel failed");
SLuint32 status;
//ALOGV("PrefetchEventCallback: received event %u", event);
result = (*caller)->GetPrefetchStatus(caller, &status);
SL_RETURN_IF_FAILED(result, "GetPrefetchStatus failed");
if ((PREFETCHEVENT_ERROR_CANDIDATE == (event & PREFETCHEVENT_ERROR_CANDIDATE))
&& (level == 0) && (status == SL_PREFETCHSTATUS_UNDERFLOW))
{
ALOGV("PrefetchEventCallback: Error while prefetching data, exiting");
_prefetchError = true;
signalEos();
}
}
/* Callback for "playback" events, i.e. event happening during decoding */
void AudioDecoderSLES::decodeProgressCallback(SLPlayItf caller, SLuint32 event)
{
if (SL_PLAYEVENT_HEADATEND & event)
{
ALOGV("SL_PLAYEVENT_HEADATEND");
if (!_isDecodingCallbackInvoked)
{
queryAudioInfo();
for (int i = 0; i < NB_BUFFERS_IN_QUEUE; ++i)
{
_result.pcmBuffer->insert(_result.pcmBuffer->end(), _decContext.pData,
_decContext.pData + BUFFER_SIZE_IN_BYTES);
/* Increase data pointer by buffer size */
_decContext.pData += BUFFER_SIZE_IN_BYTES;
}
}
signalEos();
}
}
//-----------------------------------------------------------------
/* Callback for decoding buffer queue events */
void AudioDecoderSLES::decodeToPcmCallback(SLAndroidSimpleBufferQueueItf queueItf)
{
_isDecodingCallbackInvoked = true;
ALOGV("%s ...", __FUNCTION__);
_counter++;
SLresult result;
// FIXME: ??
if (_counter % 1000 == 0)
{
SLmillisecond msec;
result = (*_decContext.playItf)->GetPosition(_decContext.playItf, &msec);
SL_RETURN_IF_FAILED(result, "%s, GetPosition failed", __FUNCTION__);
ALOGV("%s called (iteration %d): current position=%d ms", __FUNCTION__, _counter, (int)msec);
}
_result.pcmBuffer->insert(_result.pcmBuffer->end(), _decContext.pData,
_decContext.pData + BUFFER_SIZE_IN_BYTES);
result = (*queueItf)->Enqueue(queueItf, _decContext.pData, BUFFER_SIZE_IN_BYTES);
SL_RETURN_IF_FAILED(result, "%s, Enqueue failed", __FUNCTION__);
/* Increase data pointer by buffer size */
_decContext.pData += BUFFER_SIZE_IN_BYTES;
if (_decContext.pData >= _decContext.pDataBase + (NB_BUFFERS_IN_QUEUE * BUFFER_SIZE_IN_BYTES))
{
_decContext.pData = _decContext.pDataBase;
}
// Note: adding a sleep here or any sync point is a way to slow down the decoding, or
// synchronize it with some other event, as the OpenSL ES framework will block until the
// buffer queue callback return to proceed with the decoding.
#if 0
/* Example: buffer queue state display */
SLAndroidSimpleBufferQueueState decQueueState;
result =(*queueItf)->GetState(queueItf, &decQueueState);
SL_RETURN_IF_FAILED(result, "decQueueState.GetState failed");
ALOGV("DecBufferQueueCallback now has _decContext.pData=%p, _decContext.pDataBase=%p, queue: "
"count=%u playIndex=%u, count: %d",
_decContext.pData, _decContext.pDataBase, decQueueState.count, decQueueState.index, _counter);
#endif
#if 0
/* Example: display position in callback where we use the callback context for the SLPlayItf*/
SLmillisecond posMsec = SL_TIME_UNKNOWN;
result = (*_decContext.playItf)->GetPosition(_decContext.playItf, &posMsec);
SL_RETURN_IF_FAILED(result, "decodeToPcmCallback,GetPosition2 failed");
if (posMsec == SL_TIME_UNKNOWN) {
ALOGV("Content position is unknown (in dec callback)");
} else {
ALOGV("Content position is %ums (in dec callback)",
posMsec);
}
#endif
queryAudioInfo();
}
}} // namespace cocos2d { namespace experimental {