summaryrefslogtreecommitdiffstats
path: root/variablespeed/jni/variablespeed.cc
diff options
context:
space:
mode:
Diffstat (limited to 'variablespeed/jni/variablespeed.cc')
-rw-r--r--variablespeed/jni/variablespeed.cc864
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();
- }
-}