From 51b170b470ed587f99a7c2a773e4464687f0d07a Mon Sep 17 00:00:00 2001 From: crueter Date: Mon, 4 Aug 2025 04:50:14 +0200 Subject: [cmake] refactor: Use CPM over submodules (#143) Transfers the majority of submodules and large externals to CPM, using source archives rather than full Git clones. Not only does this save massive amounts of clone and configure time, but dependencies are grabbed on-demand rather than being required by default. Additionally, CPM will (generally) automatically search for system dependencies, though certain dependencies have options to control this. Testing shows gains ranging from 5x to 10x in terms of overall clone/configure time. Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/143 Reviewed-by: CamilleLaVey --- .../oboe/src/opensles/AudioStreamOpenSLES.cpp | 523 --------------------- 1 file changed, 523 deletions(-) delete mode 100644 externals/oboe/src/opensles/AudioStreamOpenSLES.cpp (limited to 'externals/oboe/src/opensles/AudioStreamOpenSLES.cpp') 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 -#include -#include - -#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(&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(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(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(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(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(context)) - ->processBufferCallback(bq); - if (shouldStopStream) { - (reinterpret_cast(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; -} -- cgit v1.2.3