aboutsummaryrefslogtreecommitdiff
path: root/externals/oboe/src/opensles/AudioStreamOpenSLES.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'externals/oboe/src/opensles/AudioStreamOpenSLES.cpp')
-rw-r--r--externals/oboe/src/opensles/AudioStreamOpenSLES.cpp523
1 files changed, 0 insertions, 523 deletions
diff --git a/externals/oboe/src/opensles/AudioStreamOpenSLES.cpp b/externals/oboe/src/opensles/AudioStreamOpenSLES.cpp
deleted file mode 100644
index 70f78b6647..0000000000
--- a/externals/oboe/src/opensles/AudioStreamOpenSLES.cpp
+++ /dev/null
@@ -1,523 +0,0 @@
-/* Copyright 2015 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 <sys/types.h>
-#include <cassert>
-#include <android/log.h>
-
-#include "common/OboeDebug.h"
-#include "oboe/AudioClock.h"
-#include "oboe/AudioStream.h"
-#include "oboe/AudioStreamBuilder.h"
-#include "EngineOpenSLES.h"
-#include "AudioStreamOpenSLES.h"
-#include "OpenSLESUtilities.h"
-
-using namespace oboe;
-
-AudioStreamOpenSLES::AudioStreamOpenSLES(const AudioStreamBuilder &builder)
- : AudioStreamBuffered(builder) {
- // OpenSL ES does not support device IDs. So overwrite value from builder.
- mDeviceIds.clear();
- // OpenSL ES does not support session IDs. So overwrite value from builder.
- mSessionId = SessionId::None;
-}
-
-static constexpr int32_t kHighLatencyBufferSizeMillis = 20; // typical Android period
-static constexpr SLuint32 kAudioChannelCountMax = 30; // TODO Why 30?
-static constexpr SLuint32 SL_ANDROID_UNKNOWN_CHANNELMASK = 0; // Matches name used internally.
-
-SLuint32 AudioStreamOpenSLES::channelCountToChannelMaskDefault(int channelCount) const {
- if (channelCount > kAudioChannelCountMax) {
- return SL_ANDROID_UNKNOWN_CHANNELMASK;
- }
-
- SLuint32 bitfield = (1 << channelCount) - 1;
-
- // Check for OS at run-time.
- if(getSdkVersion() >= __ANDROID_API_N__) {
- return SL_ANDROID_MAKE_INDEXED_CHANNEL_MASK(bitfield);
- }
-
- // Indexed channels masks were added in N.
- // For before N, the best we can do is use a positional channel mask.
- return bitfield;
-}
-
-static bool s_isLittleEndian() {
- static uint32_t value = 1;
- return (*reinterpret_cast<uint8_t *>(&value) == 1); // Does address point to LSB?
-}
-
-SLuint32 AudioStreamOpenSLES::getDefaultByteOrder() {
- return s_isLittleEndian() ? SL_BYTEORDER_LITTLEENDIAN : SL_BYTEORDER_BIGENDIAN;
-}
-
-Result AudioStreamOpenSLES::open() {
-#ifndef OBOE_SUPPRESS_LOG_SPAM
- LOGI("AudioStreamOpenSLES::open() chans=%d, rate=%d", mChannelCount, mSampleRate);
-#endif
-
- // OpenSL ES only supports I16 and Float
- if (mFormat != AudioFormat::I16 && mFormat != AudioFormat::Float) {
- LOGW("%s() Android's OpenSL ES implementation only supports I16 and Float. Format: %s",
- __func__, oboe::convertToText(mFormat));
- return Result::ErrorInvalidFormat;
- }
-
- SLresult result = EngineOpenSLES::getInstance().open();
- if (SL_RESULT_SUCCESS != result) {
- return Result::ErrorInternal;
- }
-
- Result oboeResult = AudioStreamBuffered::open();
- if (oboeResult != Result::OK) {
- EngineOpenSLES::getInstance().close();
- return oboeResult;
- }
- // Convert to defaults if UNSPECIFIED
- if (mSampleRate == kUnspecified) {
- mSampleRate = DefaultStreamValues::SampleRate;
- }
- if (mChannelCount == kUnspecified) {
- mChannelCount = DefaultStreamValues::ChannelCount;
- }
- if (mContentType == kUnspecified) {
- mContentType = ContentType::Music;
- }
- if (static_cast<const int32_t>(mUsage) == kUnspecified) {
- mUsage = Usage::Media;
- }
-
- mSharingMode = SharingMode::Shared;
-
- return Result::OK;
-}
-
-
-SLresult AudioStreamOpenSLES::finishCommonOpen(SLAndroidConfigurationItf configItf) {
- // Setting privacy sensitive mode and allowed capture policy are not supported for OpenSL ES.
- mPrivacySensitiveMode = PrivacySensitiveMode::Unspecified;
- mAllowedCapturePolicy = AllowedCapturePolicy::Unspecified;
-
- // Spatialization Behavior is not supported for OpenSL ES.
- mSpatializationBehavior = SpatializationBehavior::Never;
-
- SLresult result = registerBufferQueueCallback();
- if (SL_RESULT_SUCCESS != result) {
- return result;
- }
-
- result = updateStreamParameters(configItf);
- if (SL_RESULT_SUCCESS != result) {
- return result;
- }
-
- Result oboeResult = configureBufferSizes(mSampleRate);
- if (Result::OK != oboeResult) {
- return (SLresult) oboeResult;
- }
-
- allocateFifo();
-
- calculateDefaultDelayBeforeCloseMillis();
-
- return SL_RESULT_SUCCESS;
-}
-
-static int32_t roundUpDivideByN(int32_t x, int32_t n) {
- return (x + n - 1) / n;
-}
-
-int32_t AudioStreamOpenSLES::calculateOptimalBufferQueueLength() {
- int32_t queueLength = kBufferQueueLengthDefault;
- int32_t likelyFramesPerBurst = estimateNativeFramesPerBurst();
- int32_t minCapacity = mBufferCapacityInFrames; // specified by app or zero
- // The buffer capacity needs to be at least twice the size of the requested callbackSize
- // so that we can have double buffering.
- minCapacity = std::max(minCapacity, kDoubleBufferCount * mFramesPerCallback);
- if (minCapacity > 0) {
- int32_t queueLengthFromCapacity = roundUpDivideByN(minCapacity, likelyFramesPerBurst);
- queueLength = std::max(queueLength, queueLengthFromCapacity);
- }
- queueLength = std::min(queueLength, kBufferQueueLengthMax); // clip to max
- // TODO Investigate the effect of queueLength on latency for normal streams. (not low latency)
- return queueLength;
-}
-
-/**
- * The best information we have is if DefaultStreamValues::FramesPerBurst
- * was set by the app based on AudioManager.PROPERTY_OUTPUT_FRAMES_PER_BUFFER.
- * Without that we just have to guess.
- * @return
- */
-int32_t AudioStreamOpenSLES::estimateNativeFramesPerBurst() {
- int32_t framesPerBurst = DefaultStreamValues::FramesPerBurst;
- LOGD("AudioStreamOpenSLES:%s() DefaultStreamValues::FramesPerBurst = %d",
- __func__, DefaultStreamValues::FramesPerBurst);
- framesPerBurst = std::max(framesPerBurst, 16);
- // Calculate the size of a fixed duration high latency buffer based on sample rate.
- // Estimate sample based on default options in order of priority.
- int32_t sampleRate = 48000;
- sampleRate = (DefaultStreamValues::SampleRate > 0)
- ? DefaultStreamValues::SampleRate : sampleRate;
- sampleRate = (mSampleRate > 0) ? mSampleRate : sampleRate;
- int32_t framesPerHighLatencyBuffer =
- (kHighLatencyBufferSizeMillis * sampleRate) / kMillisPerSecond;
- // For high latency streams, use a larger buffer size.
- // Performance Mode support was added in N_MR1 (7.1)
- if (getSdkVersion() >= __ANDROID_API_N_MR1__
- && mPerformanceMode != PerformanceMode::LowLatency
- && framesPerBurst < framesPerHighLatencyBuffer) {
- // Find a multiple of framesPerBurst >= framesPerHighLatencyBuffer.
- int32_t numBursts = roundUpDivideByN(framesPerHighLatencyBuffer, framesPerBurst);
- framesPerBurst *= numBursts;
- LOGD("AudioStreamOpenSLES:%s() NOT low latency, numBursts = %d, mSampleRate = %d, set framesPerBurst = %d",
- __func__, numBursts, mSampleRate, framesPerBurst);
- }
- return framesPerBurst;
-}
-
-Result AudioStreamOpenSLES::configureBufferSizes(int32_t sampleRate) {
- LOGD("AudioStreamOpenSLES:%s(%d) initial mFramesPerBurst = %d, mFramesPerCallback = %d",
- __func__, mSampleRate, mFramesPerBurst, mFramesPerCallback);
- mFramesPerBurst = estimateNativeFramesPerBurst();
- mFramesPerCallback = (mFramesPerCallback > 0) ? mFramesPerCallback : mFramesPerBurst;
- LOGD("AudioStreamOpenSLES:%s(%d) final mFramesPerBurst = %d, mFramesPerCallback = %d",
- __func__, mSampleRate, mFramesPerBurst, mFramesPerCallback);
-
- mBytesPerCallback = mFramesPerCallback * getBytesPerFrame();
- if (mBytesPerCallback <= 0) {
- LOGE("AudioStreamOpenSLES::open() bytesPerCallback < 0 = %d, bad format?",
- mBytesPerCallback);
- return Result::ErrorInvalidFormat; // causing bytesPerFrame == 0
- }
-
- for (int i = 0; i < mBufferQueueLength; ++i) {
- mCallbackBuffer[i] = std::make_unique<uint8_t[]>(mBytesPerCallback);
- }
-
- if (!usingFIFO()) {
- mBufferCapacityInFrames = mFramesPerBurst * mBufferQueueLength;
- // Check for overflow.
- if (mBufferCapacityInFrames <= 0) {
- mBufferCapacityInFrames = 0;
- LOGE("AudioStreamOpenSLES::open() numeric overflow because mFramesPerBurst = %d",
- mFramesPerBurst);
- return Result::ErrorOutOfRange;
- }
- mBufferSizeInFrames = mBufferCapacityInFrames;
- }
-
- return Result::OK;
-}
-
-SLuint32 AudioStreamOpenSLES::convertPerformanceMode(PerformanceMode oboeMode) const {
- SLuint32 openslMode = SL_ANDROID_PERFORMANCE_NONE;
- switch(oboeMode) {
- case PerformanceMode::None:
- openslMode = SL_ANDROID_PERFORMANCE_NONE;
- break;
- case PerformanceMode::LowLatency:
- openslMode = (getSessionId() == SessionId::None) ? SL_ANDROID_PERFORMANCE_LATENCY : SL_ANDROID_PERFORMANCE_LATENCY_EFFECTS;
- break;
- case PerformanceMode::PowerSaving:
- openslMode = SL_ANDROID_PERFORMANCE_POWER_SAVING;
- break;
- default:
- break;
- }
- return openslMode;
-}
-
-PerformanceMode AudioStreamOpenSLES::convertPerformanceMode(SLuint32 openslMode) const {
- PerformanceMode oboeMode = PerformanceMode::None;
- switch(openslMode) {
- case SL_ANDROID_PERFORMANCE_NONE:
- oboeMode = PerformanceMode::None;
- break;
- case SL_ANDROID_PERFORMANCE_LATENCY:
- case SL_ANDROID_PERFORMANCE_LATENCY_EFFECTS:
- oboeMode = PerformanceMode::LowLatency;
- break;
- case SL_ANDROID_PERFORMANCE_POWER_SAVING:
- oboeMode = PerformanceMode::PowerSaving;
- break;
- default:
- break;
- }
- return oboeMode;
-}
-
-void AudioStreamOpenSLES::logUnsupportedAttributes() {
- // Log unsupported attributes
- // only report if changed from the default
-
- // Device ID
- if (!mDeviceIds.empty()) {
- LOGW("Device ID [AudioStreamBuilder::setDeviceId()] "
- "is not supported on OpenSLES streams.");
- }
- // Sharing Mode
- if (mSharingMode != SharingMode::Shared) {
- LOGW("SharingMode [AudioStreamBuilder::setSharingMode()] "
- "is not supported on OpenSLES streams.");
- }
- // Performance Mode
- int sdkVersion = getSdkVersion();
- if (mPerformanceMode != PerformanceMode::None && sdkVersion < __ANDROID_API_N_MR1__) {
- LOGW("PerformanceMode [AudioStreamBuilder::setPerformanceMode()] "
- "is not supported on OpenSLES streams running on pre-Android N-MR1 versions.");
- }
- // Content Type
- if (static_cast<const int32_t>(mContentType) != kUnspecified) {
- LOGW("ContentType [AudioStreamBuilder::setContentType()] "
- "is not supported on OpenSLES streams.");
- }
-
- // Session Id
- if (mSessionId != SessionId::None) {
- LOGW("SessionId [AudioStreamBuilder::setSessionId()] "
- "is not supported on OpenSLES streams.");
- }
-
- // Privacy Sensitive Mode
- if (mPrivacySensitiveMode != PrivacySensitiveMode::Unspecified) {
- LOGW("PrivacySensitiveMode [AudioStreamBuilder::setPrivacySensitiveMode()] "
- "is not supported on OpenSLES streams.");
- }
-
- // Spatialization Behavior
- if (mSpatializationBehavior != SpatializationBehavior::Unspecified) {
- LOGW("SpatializationBehavior [AudioStreamBuilder::setSpatializationBehavior()] "
- "is not supported on OpenSLES streams.");
- }
-
- if (mIsContentSpatialized) {
- LOGW("Boolean [AudioStreamBuilder::setIsContentSpatialized()] "
- "is not supported on OpenSLES streams.");
- }
-
- // Allowed Capture Policy
- if (mAllowedCapturePolicy != AllowedCapturePolicy::Unspecified) {
- LOGW("AllowedCapturePolicy [AudioStreamBuilder::setAllowedCapturePolicy()] "
- "is not supported on OpenSLES streams.");
- }
-
- // Package Name
- if (!mPackageName.empty()) {
- LOGW("PackageName [AudioStreamBuilder::setPackageName()] "
- "is not supported on OpenSLES streams.");
- }
-
- // Attribution Tag
- if (!mAttributionTag.empty()) {
- LOGW("AttributionTag [AudioStreamBuilder::setAttributionTag()] "
- "is not supported on OpenSLES streams.");
- }
-}
-
-SLresult AudioStreamOpenSLES::configurePerformanceMode(SLAndroidConfigurationItf configItf) {
-
- if (configItf == nullptr) {
- LOGW("%s() called with NULL configuration", __func__);
- mPerformanceMode = PerformanceMode::None;
- return SL_RESULT_INTERNAL_ERROR;
- }
- if (getSdkVersion() < __ANDROID_API_N_MR1__) {
- LOGW("%s() not supported until N_MR1", __func__);
- mPerformanceMode = PerformanceMode::None;
- return SL_RESULT_SUCCESS;
- }
-
- SLresult result = SL_RESULT_SUCCESS;
- SLuint32 performanceMode = convertPerformanceMode(getPerformanceMode());
- result = (*configItf)->SetConfiguration(configItf, SL_ANDROID_KEY_PERFORMANCE_MODE,
- &performanceMode, sizeof(performanceMode));
- if (SL_RESULT_SUCCESS != result) {
- LOGW("SetConfiguration(PERFORMANCE_MODE, SL %u) returned %s",
- performanceMode, getSLErrStr(result));
- mPerformanceMode = PerformanceMode::None;
- }
-
- return result;
-}
-
-SLresult AudioStreamOpenSLES::updateStreamParameters(SLAndroidConfigurationItf configItf) {
- SLresult result = SL_RESULT_SUCCESS;
- if(getSdkVersion() >= __ANDROID_API_N_MR1__ && configItf != nullptr) {
- SLuint32 performanceMode = 0;
- SLuint32 performanceModeSize = sizeof(performanceMode);
- result = (*configItf)->GetConfiguration(configItf, SL_ANDROID_KEY_PERFORMANCE_MODE,
- &performanceModeSize, &performanceMode);
- // A bug in GetConfiguration() before P caused a wrong result code to be returned.
- if (getSdkVersion() <= __ANDROID_API_O_MR1__) {
- result = SL_RESULT_SUCCESS; // Ignore actual result before P.
- }
-
- if (SL_RESULT_SUCCESS != result) {
- LOGW("GetConfiguration(SL_ANDROID_KEY_PERFORMANCE_MODE) returned %d", result);
- mPerformanceMode = PerformanceMode::None; // If we can't query it then assume None.
- } else {
- mPerformanceMode = convertPerformanceMode(performanceMode); // convert SL to Oboe mode
- }
- } else {
- mPerformanceMode = PerformanceMode::None; // If we can't query it then assume None.
- }
- return result;
-}
-
-// This is called under mLock.
-Result AudioStreamOpenSLES::close_l() {
- LOGD("AudioOutputStreamOpenSLES::%s() called", __func__);
- if (mState == StreamState::Closed) {
- return Result::ErrorClosed;
- }
-
- AudioStreamBuffered::close();
-
- onBeforeDestroy();
-
- // Mark as CLOSED before we unlock for the join.
- // This will prevent other threads from trying to close().
- setState(StreamState::Closed);
-
- SLObjectItf tempObjectInterface = mObjectInterface;
- mObjectInterface = nullptr;
- if (tempObjectInterface != nullptr) {
- // Temporarily unlock so we can join() the callback thread.
- mLock.unlock();
- (*tempObjectInterface)->Destroy(tempObjectInterface); // Will join the callback!
- mLock.lock();
- }
-
- onAfterDestroy();
-
- mSimpleBufferQueueInterface = nullptr;
- EngineOpenSLES::getInstance().close();
-
- return Result::OK;
-}
-
-SLresult AudioStreamOpenSLES::enqueueCallbackBuffer(SLAndroidSimpleBufferQueueItf bq) {
- SLresult result = (*bq)->Enqueue(
- bq, mCallbackBuffer[mCallbackBufferIndex].get(), mBytesPerCallback);
- mCallbackBufferIndex = (mCallbackBufferIndex + 1) % mBufferQueueLength;
- return result;
-}
-
-int32_t AudioStreamOpenSLES::getBufferDepth(SLAndroidSimpleBufferQueueItf bq) {
- SLAndroidSimpleBufferQueueState queueState;
- SLresult result = (*bq)->GetState(bq, &queueState);
- return (result == SL_RESULT_SUCCESS) ? queueState.count : -1;
-}
-
-bool AudioStreamOpenSLES::processBufferCallback(SLAndroidSimpleBufferQueueItf bq) {
- bool shouldStopStream = false;
- // Ask the app callback to process the buffer.
- DataCallbackResult result =
- fireDataCallback(mCallbackBuffer[mCallbackBufferIndex].get(), mFramesPerCallback);
- if (result == DataCallbackResult::Continue) {
- // Pass the buffer to OpenSLES.
- SLresult enqueueResult = enqueueCallbackBuffer(bq);
- if (enqueueResult != SL_RESULT_SUCCESS) {
- LOGE("%s() returned %d", __func__, enqueueResult);
- shouldStopStream = true;
- }
- // Update Oboe client position with frames handled by the callback.
- if (getDirection() == Direction::Input) {
- mFramesRead += mFramesPerCallback;
- } else {
- mFramesWritten += mFramesPerCallback;
- }
- } else if (result == DataCallbackResult::Stop) {
- LOGD("Oboe callback returned Stop");
- shouldStopStream = true;
- } else {
- LOGW("Oboe callback returned unexpected value = %d", static_cast<int>(result));
- shouldStopStream = true;
- }
- if (shouldStopStream) {
- mCallbackBufferIndex = 0;
- }
- return shouldStopStream;
-}
-
-// This callback handler is called every time a buffer has been processed by OpenSL ES.
-static void bqCallbackGlue(SLAndroidSimpleBufferQueueItf bq, void *context) {
- bool shouldStopStream = (reinterpret_cast<AudioStreamOpenSLES *>(context))
- ->processBufferCallback(bq);
- if (shouldStopStream) {
- (reinterpret_cast<AudioStreamOpenSLES *>(context))->requestStop();
- }
-}
-
-SLresult AudioStreamOpenSLES::registerBufferQueueCallback() {
- // The BufferQueue
- SLresult result = (*mObjectInterface)->GetInterface(mObjectInterface,
- EngineOpenSLES::getInstance().getIidAndroidSimpleBufferQueue(),
- &mSimpleBufferQueueInterface);
- if (SL_RESULT_SUCCESS != result) {
- LOGE("get buffer queue interface:%p result:%s",
- mSimpleBufferQueueInterface,
- getSLErrStr(result));
- } else {
- // Register the BufferQueue callback
- result = (*mSimpleBufferQueueInterface)->RegisterCallback(mSimpleBufferQueueInterface,
- bqCallbackGlue, this);
- if (SL_RESULT_SUCCESS != result) {
- LOGE("RegisterCallback result:%s", getSLErrStr(result));
- }
- }
- return result;
-}
-
-int64_t AudioStreamOpenSLES::getFramesProcessedByServer() {
- updateServiceFrameCounter();
- int64_t millis64 = mPositionMillis.get();
- int64_t framesProcessed = millis64 * getSampleRate() / kMillisPerSecond;
- return framesProcessed;
-}
-
-Result AudioStreamOpenSLES::waitForStateChange(StreamState currentState,
- StreamState *nextState,
- int64_t timeoutNanoseconds) {
- Result oboeResult = Result::ErrorTimeout;
- int64_t sleepTimeNanos = 20 * kNanosPerMillisecond; // arbitrary
- int64_t timeLeftNanos = timeoutNanoseconds;
-
- while (true) {
- const StreamState state = getState(); // this does not require a lock
- if (nextState != nullptr) {
- *nextState = state;
- }
- if (currentState != state) { // state changed?
- oboeResult = Result::OK;
- break;
- }
-
- // Did we timeout or did user ask for non-blocking?
- if (timeLeftNanos <= 0) {
- break;
- }
-
- if (sleepTimeNanos > timeLeftNanos){
- sleepTimeNanos = timeLeftNanos;
- }
- AudioClock::sleepForNanos(sleepTimeNanos);
- timeLeftNanos -= sleepTimeNanos;
- }
-
- return oboeResult;
-}