123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645 |
- /****************************************************************************
- Copyright (c) 2017 Chukong Technologies Inc.
- http://www.cocos2d-x.org
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
- The above copyright notice and this permission notice shall be included in
- all copies or substantial portions of the Software.
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- THE SOFTWARE.
- ****************************************************************************/
- #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 {
|