diff options
Diffstat (limited to 'variablespeed/jni/variablespeed.cc')
-rw-r--r-- | variablespeed/jni/variablespeed.cc | 864 |
1 files changed, 0 insertions, 864 deletions
diff --git a/variablespeed/jni/variablespeed.cc b/variablespeed/jni/variablespeed.cc deleted file mode 100644 index 8e161fc..0000000 --- a/variablespeed/jni/variablespeed.cc +++ /dev/null @@ -1,864 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <variablespeed.h> - -#include <unistd.h> -#include <stdlib.h> - -#include <sola_time_scaler.h> -#include <ring_buffer.h> - -#include <hlogging.h> - -#include <vector> - -#include <sys/system_properties.h> - -// **************************************************************************** -// Constants, utility methods, structures and other miscellany used throughout -// this file. - -namespace { - -// These variables are used to determine the size of the buffer queue used by -// the decoder. -// This is not the same as the large buffer used to hold the uncompressed data -// - for that see the member variable decodeBuffer_. -// The choice of 1152 corresponds to the number of samples per mp3 frame, so is -// a good choice of size for a decoding buffer in the absence of other -// information (we don't know exactly what formats we will be working with). -const size_t kNumberOfBuffersInQueue = 4; -const size_t kNumberOfSamplesPerBuffer = 1152; -const size_t kBufferSizeInBytes = 2 * kNumberOfSamplesPerBuffer; -const size_t kSampleSizeInBytes = 4; - -// When calculating play buffer size before pushing to audio player. -const size_t kNumberOfBytesPerInt16 = 2; - -// How long to sleep during the main play loop and the decoding callback loop. -// In due course this should be replaced with the better signal and wait on -// condition rather than busy-looping. -const int kSleepTimeMicros = 1000; - -// Used in detecting errors with the OpenSL ES framework. -const SLuint32 kPrefetchErrorCandidate = - SL_PREFETCHEVENT_STATUSCHANGE | SL_PREFETCHEVENT_FILLLEVELCHANGE; - -// Structure used when we perform a decoding callback. -typedef struct CallbackContext_ { - // Pointer to local storage buffers for decoded audio data. - int8_t* pDataBase; - // Pointer to the current buffer within local storage. - int8_t* pData; - // Used to read the sample rate and channels from the decoding stream during - // the first decoding callback. - SLMetadataExtractionItf decoderMetadata; - // The play interface used for reading duration. - SLPlayItf playItf; -} CallbackContext; - -// Local storage for decoded audio data. -int8_t pcmData[kNumberOfBuffersInQueue * kBufferSizeInBytes]; - -#define CheckSLResult(message, result) \ - CheckSLResult_Real(message, result, __LINE__) - -// Helper function for debugging - checks the OpenSL result for success. -void CheckSLResult_Real(const char* message, SLresult result, int line) { - // This can be helpful when debugging. - // LOGD("sl result %d for %s", result, message); - if (SL_RESULT_SUCCESS != result) { - LOGE("slresult was %d at %s file variablespeed line %d", - static_cast<int>(result), message, line); - } - CHECK(SL_RESULT_SUCCESS == result); -} - -// Whether logging should be enabled. Only used if LOG_OPENSL_API_CALL is -// defined to use it. -bool gLogEnabled = false; -// The property to set in order to enable logging. -const char *const kLogTagVariableSpeed = "log.tag.VariableSpeed"; - -bool ShouldLog() { - char buffer[PROP_VALUE_MAX]; - __system_property_get(kLogTagVariableSpeed, buffer); - return strlen(buffer) > 0; -} - -} // namespace - -// **************************************************************************** -// Static instance of audio engine, and methods for getting, setting and -// deleting it. - -// The single global audio engine instance. -AudioEngine* AudioEngine::audioEngine_ = NULL; -android::Mutex publishEngineLock_; - -AudioEngine* AudioEngine::GetEngine() { - android::Mutex::Autolock autoLock(publishEngineLock_); - if (audioEngine_ == NULL) { - LOGE("you haven't initialized the audio engine"); - CHECK(false); - return NULL; - } - return audioEngine_; -} - -void AudioEngine::SetEngine(AudioEngine* engine) { - if (audioEngine_ != NULL) { - LOGE("you have already set the audio engine"); - CHECK(false); - return; - } - audioEngine_ = engine; -} - -bool AudioEngine::CompareAndSetEngine(AudioEngine* expect, AudioEngine* update) { - android::Mutex::Autolock autoLock(publishEngineLock_); - if (audioEngine_ == expect) { - DeleteEngine(); - audioEngine_ = update; - return true; - } - return false; -} - -void AudioEngine::DeleteEngine() { - if (audioEngine_ != NULL) { - delete audioEngine_; - audioEngine_ = NULL; - } -} - -// **************************************************************************** -// The callbacks from the engine require static callback functions. -// Here are the static functions - they just delegate to instance methods on -// the engine. - -static void PlayingBufferQueueCb(SLAndroidSimpleBufferQueueItf, void*) { - AudioEngine::GetEngine()->PlayingBufferQueueCallback(); -} - -static void PrefetchEventCb(SLPrefetchStatusItf caller, void*, SLuint32 event) { - AudioEngine::GetEngine()->PrefetchEventCallback(caller, event); -} - -static void DecodingBufferQueueCb(SLAndroidSimpleBufferQueueItf queueItf, - void *context) { - AudioEngine::GetEngine()->DecodingBufferQueueCallback(queueItf, context); -} - -static void DecodingEventCb(SLPlayItf caller, void*, SLuint32 event) { - AudioEngine::GetEngine()->DecodingEventCallback(caller, event); -} - -// **************************************************************************** -// Macros for making working with OpenSL easier. - -// Log based on the value of a property. -#define LOG_OPENSL_API_CALL(string) (gLogEnabled && LOGV(string)) - -// The regular macro: log an api call, make the api call, check the result. -#define OpenSL(obj, method, ...) \ -{ \ - LOG_OPENSL_API_CALL("OpenSL " #method "(" #obj ", " #__VA_ARGS__ ")"); \ - SLresult result = (*obj)->method(obj, __VA_ARGS__); \ - CheckSLResult("OpenSL " #method "(" #obj ", " #__VA_ARGS__ ")", result); \ -} - -// Special case call for api call that has void return value, can't be checked. -#define VoidOpenSL(obj, method) \ -{ \ - LOG_OPENSL_API_CALL("OpenSL (void) " #method "(" #obj ")"); \ - (*obj)->method(obj); \ -} - -// Special case for api call with checked result but takes no arguments. -#define OpenSL0(obj, method) \ -{ \ - LOG_OPENSL_API_CALL("OpenSL " #method "(" #obj ")"); \ - SLresult result = (*obj)->method(obj); \ - CheckSLResult("OpenSL " #method "(" #obj ")", result); \ -} - -// Special case for api call whose result we want to store, not check. -// We have to encapsulate the two calls in braces, so that this expression -// evaluates to the last expression not the first. -#define ReturnOpenSL(obj, method, ...) \ -( \ - LOG_OPENSL_API_CALL("OpenSL (int) " \ - #method "(" #obj ", " #__VA_ARGS__ ")"), \ - (*obj)->method(obj, __VA_ARGS__) \ -) \ - -// **************************************************************************** -// Static utility methods. - -// Set the audio stream type for the player. -// -// Must be called before it is realized. -// -// The caller must have requested the SL_IID_ANDROIDCONFIGURATION interface when -// creating the player. -static void setAudioStreamType(SLObjectItf audioPlayer, SLint32 audioStreamType) { - SLAndroidConfigurationItf playerConfig; - OpenSL(audioPlayer, GetInterface, SL_IID_ANDROIDCONFIGURATION, &playerConfig); - // The STREAM_XXX constants defined by android.media.AudioManager match the - // corresponding SL_ANDROID_STREAM_XXX constants defined by - // include/SLES/OpenSLES_AndroidConfiguration.h, so we can just pass the - // value across. - OpenSL(playerConfig, SetConfiguration, SL_ANDROID_KEY_STREAM_TYPE, - &audioStreamType, sizeof(audioStreamType)); -} - -// Must be called with callbackLock_ held. -static void ReadSampleRateAndChannelCount(CallbackContext *pContext, - SLuint32 *sampleRateOut, SLuint32 *channelsOut) { - SLMetadataExtractionItf decoderMetadata = pContext->decoderMetadata; - SLuint32 itemCount; - OpenSL(decoderMetadata, GetItemCount, &itemCount); - SLuint32 i, keySize, valueSize; - SLMetadataInfo *keyInfo, *value; - for (i = 0; i < itemCount; ++i) { - keyInfo = value = NULL; - keySize = valueSize = 0; - OpenSL(decoderMetadata, GetKeySize, i, &keySize); - keyInfo = static_cast<SLMetadataInfo*>(malloc(keySize)); - if (keyInfo) { - OpenSL(decoderMetadata, GetKey, i, keySize, keyInfo); - if (keyInfo->encoding == SL_CHARACTERENCODING_ASCII - || keyInfo->encoding == SL_CHARACTERENCODING_UTF8) { - OpenSL(decoderMetadata, GetValueSize, i, &valueSize); - value = static_cast<SLMetadataInfo*>(malloc(valueSize)); - if (value) { - OpenSL(decoderMetadata, GetValue, i, valueSize, value); - if (strcmp((char*) keyInfo->data, ANDROID_KEY_PCMFORMAT_SAMPLERATE) == 0) { - SLuint32 sampleRate = *(reinterpret_cast<SLuint32*>(value->data)); - LOGD("sample Rate: %d", sampleRate); - *sampleRateOut = sampleRate; - } else if (strcmp((char*) keyInfo->data, ANDROID_KEY_PCMFORMAT_NUMCHANNELS) == 0) { - SLuint32 channels = *(reinterpret_cast<SLuint32*>(value->data)); - LOGD("channels: %d", channels); - *channelsOut = channels; - } - free(value); - } - } - free(keyInfo); - } - } -} - -// Must be called with callbackLock_ held. -static void RegisterCallbackContextAndAddEnqueueBuffersToDecoder( - SLAndroidSimpleBufferQueueItf decoderQueue, CallbackContext* context) { - // Register a callback on the decoder queue, so that we will be called - // throughout the decoding process (and can then extract the decoded audio - // for the next bit of the pipeline). - OpenSL(decoderQueue, RegisterCallback, DecodingBufferQueueCb, context); - - // Enqueue buffers to map the region of memory allocated to store the - // decoded data. - for (size_t i = 0; i < kNumberOfBuffersInQueue; i++) { - OpenSL(decoderQueue, Enqueue, context->pData, kBufferSizeInBytes); - context->pData += kBufferSizeInBytes; - } - context->pData = context->pDataBase; -} - -// **************************************************************************** -// Constructor and Destructor. - -AudioEngine::AudioEngine(size_t targetFrames, float windowDuration, - float windowOverlapDuration, size_t maxPlayBufferCount, float initialRate, - size_t decodeInitialSize, size_t decodeMaxSize, size_t startPositionMillis, - int audioStreamType) - : decodeBuffer_(decodeInitialSize, decodeMaxSize), - playingBuffers_(), freeBuffers_(), timeScaler_(NULL), - floatBuffer_(NULL), injectBuffer_(NULL), - mSampleRate(0), mChannels(0), - targetFrames_(targetFrames), - windowDuration_(windowDuration), - windowOverlapDuration_(windowOverlapDuration), - maxPlayBufferCount_(maxPlayBufferCount), initialRate_(initialRate), - startPositionMillis_(startPositionMillis), - audioStreamType_(audioStreamType), - totalDurationMs_(0), decoderCurrentPosition_(0), startRequested_(false), - stopRequested_(false), finishedDecoding_(false) { - // Determine whether we should log calls. - gLogEnabled = ShouldLog(); -} - -AudioEngine::~AudioEngine() { - // destroy the time scaler - if (timeScaler_ != NULL) { - delete timeScaler_; - timeScaler_ = NULL; - } - - // delete all outstanding playing and free buffers - android::Mutex::Autolock autoLock(playBufferLock_); - while (playingBuffers_.size() > 0) { - delete[] playingBuffers_.front(); - playingBuffers_.pop(); - } - while (freeBuffers_.size() > 0) { - delete[] freeBuffers_.top(); - freeBuffers_.pop(); - } - - delete[] floatBuffer_; - floatBuffer_ = NULL; - delete[] injectBuffer_; - injectBuffer_ = NULL; -} - -// **************************************************************************** -// Regular AudioEngine class methods. - -void AudioEngine::SetVariableSpeed(float speed) { - // TODO: Mutex for shared time scaler accesses. - if (HasSampleRateAndChannels()) { - GetTimeScaler()->set_speed(speed); - } else { - // This is being called at a point where we have not yet processed enough - // data to determine the sample rate and number of channels. - // Ignore the call. See http://b/5140693. - LOGD("set varaible speed called, sample rate and channels not ready yet"); - } -} - -void AudioEngine::RequestStart() { - android::Mutex::Autolock autoLock(lock_); - startRequested_ = true; -} - -void AudioEngine::ClearRequestStart() { - android::Mutex::Autolock autoLock(lock_); - startRequested_ = false; -} - -bool AudioEngine::GetWasStartRequested() { - android::Mutex::Autolock autoLock(lock_); - return startRequested_; -} - -void AudioEngine::RequestStop() { - android::Mutex::Autolock autoLock(lock_); - stopRequested_ = true; -} - -int AudioEngine::GetCurrentPosition() { - android::Mutex::Autolock autoLock(decodeBufferLock_); - double result = decodeBuffer_.GetTotalAdvancedCount(); - // TODO: This is horrible, but should be removed soon once the outstanding - // issue with get current position on decoder is fixed. - android::Mutex::Autolock autoLock2(callbackLock_); - return static_cast<int>( - (result * 1000) / mSampleRate / mChannels + startPositionMillis_); -} - -int AudioEngine::GetTotalDuration() { - android::Mutex::Autolock autoLock(lock_); - return static_cast<int>(totalDurationMs_); -} - -video_editing::SolaTimeScaler* AudioEngine::GetTimeScaler() { - if (timeScaler_ == NULL) { - CHECK(HasSampleRateAndChannels()); - android::Mutex::Autolock autoLock(callbackLock_); - timeScaler_ = new video_editing::SolaTimeScaler(); - timeScaler_->Init(mSampleRate, mChannels, initialRate_, windowDuration_, - windowOverlapDuration_); - } - return timeScaler_; -} - -bool AudioEngine::EnqueueNextBufferOfAudio( - SLAndroidSimpleBufferQueueItf audioPlayerQueue) { - size_t channels; - { - android::Mutex::Autolock autoLock(callbackLock_); - channels = mChannels; - } - size_t frameSizeInBytes = kSampleSizeInBytes * channels; - size_t frameCount = 0; - while (frameCount < targetFrames_) { - size_t framesLeft = targetFrames_ - frameCount; - // If there is data already in the time scaler, retrieve it. - if (GetTimeScaler()->available() > 0) { - size_t retrieveCount = min(GetTimeScaler()->available(), framesLeft); - int count = GetTimeScaler()->RetrieveSamples( - floatBuffer_ + frameCount * channels, retrieveCount); - if (count <= 0) { - LOGD("error: count was %d", count); - break; - } - frameCount += count; - continue; - } - // If there is no data in the time scaler, then feed some into it. - android::Mutex::Autolock autoLock(decodeBufferLock_); - size_t framesInDecodeBuffer = - decodeBuffer_.GetSizeInBytes() / frameSizeInBytes; - size_t framesScalerCanHandle = GetTimeScaler()->input_limit(); - size_t framesToInject = min(framesInDecodeBuffer, - min(targetFrames_, framesScalerCanHandle)); - if (framesToInject <= 0) { - // No more frames left to inject. - break; - } - for (size_t i = 0; i < framesToInject * channels; ++i) { - injectBuffer_[i] = decodeBuffer_.GetAtIndex(i); - } - int count = GetTimeScaler()->InjectSamples(injectBuffer_, framesToInject); - if (count <= 0) { - LOGD("error: count was %d", count); - break; - } - decodeBuffer_.AdvanceHeadPointerShorts(count * channels); - } - if (frameCount <= 0) { - // We must have finished playback. - if (GetEndOfDecoderReached()) { - // If we've finished decoding, clear the buffer - so we will terminate. - ClearDecodeBuffer(); - } - return false; - } - - // Get a free playing buffer. - int16* playBuffer; - { - android::Mutex::Autolock autoLock(playBufferLock_); - if (freeBuffers_.size() > 0) { - // If we have a free buffer, recycle it. - playBuffer = freeBuffers_.top(); - freeBuffers_.pop(); - } else { - // Otherwise allocate a new one. - playBuffer = new int16[targetFrames_ * channels]; - } - } - - // Try to play the buffer. - for (size_t i = 0; i < frameCount * channels; ++i) { - playBuffer[i] = floatBuffer_[i]; - } - size_t sizeOfPlayBufferInBytes = - frameCount * channels * kNumberOfBytesPerInt16; - SLresult result = ReturnOpenSL(audioPlayerQueue, Enqueue, playBuffer, - sizeOfPlayBufferInBytes); - if (result == SL_RESULT_SUCCESS) { - android::Mutex::Autolock autoLock(playBufferLock_); - playingBuffers_.push(playBuffer); - } else { - LOGE("could not enqueue audio buffer"); - delete[] playBuffer; - } - - return (result == SL_RESULT_SUCCESS); -} - -bool AudioEngine::GetEndOfDecoderReached() { - android::Mutex::Autolock autoLock(lock_); - return finishedDecoding_; -} - -void AudioEngine::SetEndOfDecoderReached() { - android::Mutex::Autolock autoLock(lock_); - finishedDecoding_ = true; -} - -bool AudioEngine::PlayFileDescriptor(int fd, int64 offset, int64 length) { - SLDataLocator_AndroidFD loc_fd = { - SL_DATALOCATOR_ANDROIDFD, fd, offset, length }; - SLDataFormat_MIME format_mime = { - SL_DATAFORMAT_MIME, NULL, SL_CONTAINERTYPE_UNSPECIFIED }; - SLDataSource audioSrc = { &loc_fd, &format_mime }; - return PlayFromThisSource(audioSrc); -} - -bool AudioEngine::PlayUri(const char* uri) { - // Source of audio data for the decoding - SLDataLocator_URI decUri = { SL_DATALOCATOR_URI, - const_cast<SLchar*>(reinterpret_cast<const SLchar*>(uri)) }; - SLDataFormat_MIME decMime = { - SL_DATAFORMAT_MIME, NULL, SL_CONTAINERTYPE_UNSPECIFIED }; - SLDataSource decSource = { &decUri, &decMime }; - return PlayFromThisSource(decSource); -} - -bool AudioEngine::IsDecodeBufferEmpty() { - android::Mutex::Autolock autoLock(decodeBufferLock_); - return decodeBuffer_.GetSizeInBytes() <= 0; -} - -void AudioEngine::ClearDecodeBuffer() { - android::Mutex::Autolock autoLock(decodeBufferLock_); - decodeBuffer_.Clear(); -} - -static size_t ReadDuration(SLPlayItf playItf) { - SLmillisecond durationInMsec = SL_TIME_UNKNOWN; - OpenSL(playItf, GetDuration, &durationInMsec); - if (durationInMsec == SL_TIME_UNKNOWN) { - LOGE("can't get duration"); - return 0; - } - LOGD("duration: %d", static_cast<int>(durationInMsec)); - return durationInMsec; -} - -static size_t ReadPosition(SLPlayItf playItf) { - SLmillisecond positionInMsec = SL_TIME_UNKNOWN; - OpenSL(playItf, GetPosition, &positionInMsec); - if (positionInMsec == SL_TIME_UNKNOWN) { - LOGE("can't get position"); - return 0; - } - LOGW("decoder position: %d", static_cast<int>(positionInMsec)); - return positionInMsec; -} - -static void CreateAndRealizeEngine(SLObjectItf &engine, - SLEngineItf &engineInterface) { - SLEngineOption EngineOption[] = { { - SL_ENGINEOPTION_THREADSAFE, SL_BOOLEAN_TRUE } }; - SLresult result = slCreateEngine(&engine, 1, EngineOption, 0, NULL, NULL); - CheckSLResult("create engine", result); - OpenSL(engine, Realize, SL_BOOLEAN_FALSE); - OpenSL(engine, GetInterface, SL_IID_ENGINE, &engineInterface); -} - -SLuint32 AudioEngine::GetSLSampleRate() { - android::Mutex::Autolock autoLock(callbackLock_); - return mSampleRate * 1000; -} - -SLuint32 AudioEngine::GetSLChannels() { - android::Mutex::Autolock autoLock(callbackLock_); - switch (mChannels) { - case 2: - return SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT; - case 1: - return SL_SPEAKER_FRONT_CENTER; - default: - LOGE("unknown channels %d, using 2", mChannels); - return SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT; - } -} - -SLuint32 AudioEngine::GetChannelCount() { - android::Mutex::Autolock autoLock(callbackLock_); - return mChannels; -} - -static void CreateAndRealizeAudioPlayer(SLuint32 slSampleRate, - SLuint32 channelCount, SLuint32 slChannels, SLint32 audioStreamType, SLObjectItf &outputMix, - SLObjectItf &audioPlayer, SLEngineItf &engineInterface) { - // Define the source and sink for the audio player: comes from a buffer queue - // and goes to the output mix. - SLDataLocator_AndroidSimpleBufferQueue loc_bufq = { - SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 2 }; - SLDataFormat_PCM format_pcm = {SL_DATAFORMAT_PCM, channelCount, slSampleRate, - SL_PCMSAMPLEFORMAT_FIXED_16, SL_PCMSAMPLEFORMAT_FIXED_16, - slChannels, SL_BYTEORDER_LITTLEENDIAN}; - SLDataSource playingSrc = {&loc_bufq, &format_pcm}; - SLDataLocator_OutputMix loc_outmix = {SL_DATALOCATOR_OUTPUTMIX, outputMix}; - SLDataSink audioSnk = {&loc_outmix, NULL}; - - // Create the audio player, which will play from the buffer queue and send to - // the output mix. - const size_t playerInterfaceCount = 2; - const SLInterfaceID iids[playerInterfaceCount] = { - SL_IID_ANDROIDSIMPLEBUFFERQUEUE, SL_IID_ANDROIDCONFIGURATION }; - const SLboolean reqs[playerInterfaceCount] = { SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE }; - OpenSL(engineInterface, CreateAudioPlayer, &audioPlayer, &playingSrc, - &audioSnk, playerInterfaceCount, iids, reqs); - setAudioStreamType(audioPlayer, audioStreamType); - OpenSL(audioPlayer, Realize, SL_BOOLEAN_FALSE); -} - -bool AudioEngine::HasSampleRateAndChannels() { - android::Mutex::Autolock autoLock(callbackLock_); - return mChannels != 0 && mSampleRate != 0; -} - -bool AudioEngine::PlayFromThisSource(const SLDataSource& audioSrc) { - ClearDecodeBuffer(); - - SLObjectItf engine; - SLEngineItf engineInterface; - CreateAndRealizeEngine(engine, engineInterface); - - // Define the source and sink for the decoding player: comes from the source - // this method was called with, is sent to another buffer queue. - SLDataLocator_AndroidSimpleBufferQueue decBuffQueue; - decBuffQueue.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE; - decBuffQueue.numBuffers = kNumberOfBuffersInQueue; - // A valid value seems required here but is currently ignored. - SLDataFormat_PCM pcm = {SL_DATAFORMAT_PCM, 1, SL_SAMPLINGRATE_44_1, - SL_PCMSAMPLEFORMAT_FIXED_16, 16, - SL_SPEAKER_FRONT_LEFT, SL_BYTEORDER_LITTLEENDIAN}; - SLDataSink decDest = { &decBuffQueue, &pcm }; - - // Create the decoder with the given source and sink. - const size_t decoderInterfaceCount = 5; - SLObjectItf decoder; - const SLInterfaceID decodePlayerInterfaces[decoderInterfaceCount] = { - SL_IID_ANDROIDSIMPLEBUFFERQUEUE, SL_IID_PREFETCHSTATUS, SL_IID_SEEK, - SL_IID_METADATAEXTRACTION, SL_IID_ANDROIDCONFIGURATION }; - const SLboolean decodePlayerRequired[decoderInterfaceCount] = { - SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE }; - SLDataSource sourceCopy(audioSrc); - OpenSL(engineInterface, CreateAudioPlayer, &decoder, &sourceCopy, &decDest, - decoderInterfaceCount, decodePlayerInterfaces, decodePlayerRequired); - // Not sure if this is necessary, but just in case. - setAudioStreamType(decoder, audioStreamType_); - OpenSL(decoder, Realize, SL_BOOLEAN_FALSE); - - // Get the play interface from the decoder, and register event callbacks. - // Get the buffer queue, prefetch and seek interfaces. - SLPlayItf decoderPlay = NULL; - SLAndroidSimpleBufferQueueItf decoderQueue = NULL; - SLPrefetchStatusItf decoderPrefetch = NULL; - SLSeekItf decoderSeek = NULL; - SLMetadataExtractionItf decoderMetadata = NULL; - OpenSL(decoder, GetInterface, SL_IID_PLAY, &decoderPlay); - OpenSL(decoderPlay, SetCallbackEventsMask, SL_PLAYEVENT_HEADATEND); - OpenSL(decoderPlay, RegisterCallback, DecodingEventCb, NULL); - OpenSL(decoder, GetInterface, SL_IID_PREFETCHSTATUS, &decoderPrefetch); - OpenSL(decoder, GetInterface, SL_IID_SEEK, &decoderSeek); - OpenSL(decoder, GetInterface, SL_IID_METADATAEXTRACTION, &decoderMetadata); - OpenSL(decoder, GetInterface, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, - &decoderQueue); - - // Initialize the callback structure, used during the decoding. - CallbackContext callbackContext; - { - android::Mutex::Autolock autoLock(callbackLock_); - callbackContext.pDataBase = pcmData; - callbackContext.pData = pcmData; - callbackContext.decoderMetadata = decoderMetadata; - callbackContext.playItf = decoderPlay; - RegisterCallbackContextAndAddEnqueueBuffersToDecoder( - decoderQueue, &callbackContext); - } - - // Initialize the callback for prefetch errors, if we can't open the - // resource to decode. - OpenSL(decoderPrefetch, SetCallbackEventsMask, kPrefetchErrorCandidate); - OpenSL(decoderPrefetch, RegisterCallback, PrefetchEventCb, &decoderPrefetch); - - // Seek to the start position. - OpenSL(decoderSeek, SetPosition, startPositionMillis_, SL_SEEKMODE_ACCURATE); - - // Start decoding immediately. - OpenSL(decoderPlay, SetPlayState, SL_PLAYSTATE_PLAYING); - - // These variables hold the audio player and its output. - // They will only be constructed once the decoder has invoked the callback, - // and given us the correct sample rate, number of channels and duration. - SLObjectItf outputMix = NULL; - SLObjectItf audioPlayer = NULL; - SLPlayItf audioPlayerPlay = NULL; - SLAndroidSimpleBufferQueueItf audioPlayerQueue = NULL; - - // The main loop - until we're told to stop: if there is audio data coming - // out of the decoder, feed it through the time scaler. - // As it comes out of the time scaler, feed it into the audio player. - while (!Finished()) { - if (GetWasStartRequested() && HasSampleRateAndChannels()) { - // Build the audio player. - // TODO: What happens if I maliciously call start lots of times? - floatBuffer_ = new float[targetFrames_ * mChannels]; - injectBuffer_ = new float[targetFrames_ * mChannels]; - OpenSL(engineInterface, CreateOutputMix, &outputMix, 0, NULL, NULL); - OpenSL(outputMix, Realize, SL_BOOLEAN_FALSE); - CreateAndRealizeAudioPlayer(GetSLSampleRate(), GetChannelCount(), - GetSLChannels(), audioStreamType_, outputMix, audioPlayer, - engineInterface); - OpenSL(audioPlayer, GetInterface, SL_IID_PLAY, &audioPlayerPlay); - OpenSL(audioPlayer, GetInterface, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, - &audioPlayerQueue); - OpenSL(audioPlayerQueue, RegisterCallback, PlayingBufferQueueCb, NULL); - ClearRequestStart(); - OpenSL(audioPlayerPlay, SetPlayState, SL_PLAYSTATE_PLAYING); - } - EnqueueMoreAudioIfNecessary(audioPlayerQueue); - usleep(kSleepTimeMicros); - } - - // Delete the audio player and output mix, iff they have been created. - if (audioPlayer != NULL) { - OpenSL(audioPlayerPlay, SetPlayState, SL_PLAYSTATE_STOPPED); - OpenSL0(audioPlayerQueue, Clear); - OpenSL(audioPlayerQueue, RegisterCallback, NULL, NULL); - VoidOpenSL(audioPlayer, AbortAsyncOperation); - VoidOpenSL(audioPlayer, Destroy); - VoidOpenSL(outputMix, Destroy); - audioPlayer = NULL; - audioPlayerPlay = NULL; - audioPlayerQueue = NULL; - outputMix = NULL; - } - - // Delete the decoder. - OpenSL(decoderPlay, SetPlayState, SL_PLAYSTATE_STOPPED); - OpenSL(decoderPrefetch, RegisterCallback, NULL, NULL); - // This is returning slresult 13 if I do no playback. - // Repro is to comment out all before this line, and all after enqueueing - // my buffers. - // OpenSL0(decoderQueue, Clear); - OpenSL(decoderQueue, RegisterCallback, NULL, NULL); - decoderSeek = NULL; - decoderPrefetch = NULL; - decoderQueue = NULL; - OpenSL(decoderPlay, RegisterCallback, NULL, NULL); - VoidOpenSL(decoder, AbortAsyncOperation); - VoidOpenSL(decoder, Destroy); - decoderPlay = NULL; - - // Delete the engine. - VoidOpenSL(engine, Destroy); - engineInterface = NULL; - - return true; -} - -bool AudioEngine::Finished() { - if (GetWasStopRequested()) { - return true; - } - android::Mutex::Autolock autoLock(playBufferLock_); - return playingBuffers_.size() <= 0 && - IsDecodeBufferEmpty() && - GetEndOfDecoderReached(); -} - -bool AudioEngine::GetWasStopRequested() { - android::Mutex::Autolock autoLock(lock_); - return stopRequested_; -} - -bool AudioEngine::GetHasReachedPlayingBuffersLimit() { - android::Mutex::Autolock autoLock(playBufferLock_); - return playingBuffers_.size() >= maxPlayBufferCount_; -} - -void AudioEngine::EnqueueMoreAudioIfNecessary( - SLAndroidSimpleBufferQueueItf audioPlayerQueue) { - bool keepEnqueueing = true; - while (audioPlayerQueue != NULL && - !GetWasStopRequested() && - !IsDecodeBufferEmpty() && - !GetHasReachedPlayingBuffersLimit() && - keepEnqueueing) { - keepEnqueueing = EnqueueNextBufferOfAudio(audioPlayerQueue); - } -} - -bool AudioEngine::DecodeBufferTooFull() { - android::Mutex::Autolock autoLock(decodeBufferLock_); - return decodeBuffer_.IsTooLarge(); -} - -// **************************************************************************** -// Code for handling the static callbacks. - -void AudioEngine::PlayingBufferQueueCallback() { - // The head playing buffer is done, move it to the free list. - android::Mutex::Autolock autoLock(playBufferLock_); - if (playingBuffers_.size() > 0) { - freeBuffers_.push(playingBuffers_.front()); - playingBuffers_.pop(); - } -} - -void AudioEngine::PrefetchEventCallback( - SLPrefetchStatusItf caller, SLuint32 event) { - // If there was a problem during decoding, then signal the end. - SLpermille level = 0; - SLuint32 status; - OpenSL(caller, GetFillLevel, &level); - OpenSL(caller, GetPrefetchStatus, &status); - if ((kPrefetchErrorCandidate == (event & kPrefetchErrorCandidate)) && - (level == 0) && - (status == SL_PREFETCHSTATUS_UNDERFLOW)) { - LOGI("prefetcheventcallback error while prefetching data"); - SetEndOfDecoderReached(); - } - if (SL_PREFETCHSTATUS_SUFFICIENTDATA == event) { - // android::Mutex::Autolock autoLock(prefetchLock_); - // prefetchCondition_.broadcast(); - } -} - -void AudioEngine::DecodingBufferQueueCallback( - SLAndroidSimpleBufferQueueItf queueItf, void *context) { - if (GetWasStopRequested()) { - return; - } - - CallbackContext *pCntxt; - { - android::Mutex::Autolock autoLock(callbackLock_); - pCntxt = reinterpret_cast<CallbackContext*>(context); - } - { - android::Mutex::Autolock autoLock(decodeBufferLock_); - decodeBuffer_.AddData(pCntxt->pData, kBufferSizeInBytes); - } - - if (!HasSampleRateAndChannels()) { - android::Mutex::Autolock autoLock(callbackLock_); - ReadSampleRateAndChannelCount(pCntxt, &mSampleRate, &mChannels); - } - - { - android::Mutex::Autolock autoLock(lock_); - if (totalDurationMs_ == 0) { - totalDurationMs_ = ReadDuration(pCntxt->playItf); - } - // TODO: This isn't working, it always reports zero. - // ReadPosition(pCntxt->playItf); - } - - OpenSL(queueItf, Enqueue, pCntxt->pData, kBufferSizeInBytes); - - // Increase data pointer by buffer size - pCntxt->pData += kBufferSizeInBytes; - if (pCntxt->pData >= pCntxt->pDataBase + - (kNumberOfBuffersInQueue * kBufferSizeInBytes)) { - pCntxt->pData = pCntxt->pDataBase; - } - - // If we get too much data into the decoder, - // sleep until the playback catches up. - while (!GetWasStopRequested() && DecodeBufferTooFull()) { - usleep(kSleepTimeMicros); - } -} - -void AudioEngine::DecodingEventCallback(SLPlayItf, SLuint32 event) { - if (SL_PLAYEVENT_HEADATEND & event) { - SetEndOfDecoderReached(); - } -} |