xref: /aosp_15_r20/external/oboe/src/opensles/AudioStreamOpenSLES.cpp (revision 05767d913155b055644481607e6fa1e35e2fe72c)
1 /* Copyright 2015 The Android Open Source Project
2  *
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *      http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #include <sys/types.h>
16 #include <cassert>
17 #include <android/log.h>
18 
19 #include <SLES/OpenSLES.h>
20 #include <SLES/OpenSLES_Android.h>
21 #include <oboe/AudioStream.h>
22 #include <common/AudioClock.h>
23 
24 #include "common/OboeDebug.h"
25 #include "oboe/AudioStreamBuilder.h"
26 #include "AudioStreamOpenSLES.h"
27 #include "OpenSLESUtilities.h"
28 
29 using namespace oboe;
30 
AudioStreamOpenSLES(const AudioStreamBuilder & builder)31 AudioStreamOpenSLES::AudioStreamOpenSLES(const AudioStreamBuilder &builder)
32     : AudioStreamBuffered(builder) {
33     // OpenSL ES does not support device IDs. So overwrite value from builder.
34     mDeviceId = kUnspecified;
35     // OpenSL ES does not support session IDs. So overwrite value from builder.
36     mSessionId = SessionId::None;
37 }
38 
39 static constexpr int32_t   kHighLatencyBufferSizeMillis = 20; // typical Android period
40 static constexpr SLuint32  kAudioChannelCountMax = 30; // TODO Why 30?
41 static constexpr SLuint32  SL_ANDROID_UNKNOWN_CHANNELMASK  = 0; // Matches name used internally.
42 
channelCountToChannelMaskDefault(int channelCount) const43 SLuint32 AudioStreamOpenSLES::channelCountToChannelMaskDefault(int channelCount) const {
44     if (channelCount > kAudioChannelCountMax) {
45         return SL_ANDROID_UNKNOWN_CHANNELMASK;
46     }
47 
48     SLuint32 bitfield = (1 << channelCount) - 1;
49 
50     // Check for OS at run-time.
51     if(getSdkVersion() >= __ANDROID_API_N__) {
52         return SL_ANDROID_MAKE_INDEXED_CHANNEL_MASK(bitfield);
53     }
54 
55     // Indexed channels masks were added in N.
56     // For before N, the best we can do is use a positional channel mask.
57     return bitfield;
58 }
59 
s_isLittleEndian()60 static bool s_isLittleEndian() {
61     static uint32_t value = 1;
62     return (*reinterpret_cast<uint8_t *>(&value) == 1);  // Does address point to LSB?
63 }
64 
getDefaultByteOrder()65 SLuint32 AudioStreamOpenSLES::getDefaultByteOrder() {
66     return s_isLittleEndian() ? SL_BYTEORDER_LITTLEENDIAN : SL_BYTEORDER_BIGENDIAN;
67 }
68 
open()69 Result AudioStreamOpenSLES::open() {
70 
71     LOGI("AudioStreamOpenSLES::open() chans=%d, rate=%d", mChannelCount, mSampleRate);
72 
73     // OpenSL ES only supports I16 and Float
74     if (mFormat != AudioFormat::I16 && mFormat != AudioFormat::Float) {
75         LOGW("%s() Android's OpenSL ES implementation only supports I16 and Float. Format: %s",
76              __func__, oboe::convertToText(mFormat));
77         return Result::ErrorInvalidFormat;
78     }
79 
80     SLresult result = EngineOpenSLES::getInstance().open();
81     if (SL_RESULT_SUCCESS != result) {
82         return Result::ErrorInternal;
83     }
84 
85     Result oboeResult = AudioStreamBuffered::open();
86     if (oboeResult != Result::OK) {
87         EngineOpenSLES::getInstance().close();
88         return oboeResult;
89     }
90     // Convert to defaults if UNSPECIFIED
91     if (mSampleRate == kUnspecified) {
92         mSampleRate = DefaultStreamValues::SampleRate;
93     }
94     if (mChannelCount == kUnspecified) {
95         mChannelCount = DefaultStreamValues::ChannelCount;
96     }
97     if (mContentType == kUnspecified) {
98         mContentType = ContentType::Music;
99     }
100     if (static_cast<const int32_t>(mUsage) == kUnspecified) {
101         mUsage = Usage::Media;
102     }
103 
104     mSharingMode = SharingMode::Shared;
105 
106     return Result::OK;
107 }
108 
109 
finishCommonOpen(SLAndroidConfigurationItf configItf)110 SLresult AudioStreamOpenSLES::finishCommonOpen(SLAndroidConfigurationItf configItf) {
111     // Setting privacy sensitive mode and allowed capture policy are not supported for OpenSL ES.
112     mPrivacySensitiveMode = PrivacySensitiveMode::Unspecified;
113     mAllowedCapturePolicy = AllowedCapturePolicy::Unspecified;
114 
115     // Spatialization Behavior is not supported for OpenSL ES.
116     mSpatializationBehavior = SpatializationBehavior::Never;
117 
118     SLresult result = registerBufferQueueCallback();
119     if (SL_RESULT_SUCCESS != result) {
120         return result;
121     }
122 
123     result = updateStreamParameters(configItf);
124     if (SL_RESULT_SUCCESS != result) {
125         return result;
126     }
127 
128     Result oboeResult = configureBufferSizes(mSampleRate);
129     if (Result::OK != oboeResult) {
130         return (SLresult) oboeResult;
131     }
132 
133     allocateFifo();
134 
135     calculateDefaultDelayBeforeCloseMillis();
136 
137     return SL_RESULT_SUCCESS;
138 }
139 
roundUpDivideByN(int32_t x,int32_t n)140 static int32_t roundUpDivideByN(int32_t x, int32_t n) {
141     return (x + n - 1) / n;
142 }
143 
calculateOptimalBufferQueueLength()144 int32_t AudioStreamOpenSLES::calculateOptimalBufferQueueLength() {
145     int32_t queueLength = kBufferQueueLengthDefault;
146     int32_t likelyFramesPerBurst = estimateNativeFramesPerBurst();
147     int32_t minCapacity = mBufferCapacityInFrames; // specified by app or zero
148     // The buffer capacity needs to be at least twice the size of the requested callbackSize
149     // so that we can have double buffering.
150     minCapacity = std::max(minCapacity, kDoubleBufferCount * mFramesPerCallback);
151     if (minCapacity > 0) {
152         int32_t queueLengthFromCapacity = roundUpDivideByN(minCapacity, likelyFramesPerBurst);
153         queueLength = std::max(queueLength, queueLengthFromCapacity);
154     }
155     queueLength = std::min(queueLength, kBufferQueueLengthMax); // clip to max
156     // TODO Investigate the effect of queueLength on latency for normal streams. (not low latency)
157     return queueLength;
158 }
159 
160 /**
161  * The best information we have is if DefaultStreamValues::FramesPerBurst
162  * was set by the app based on AudioManager.PROPERTY_OUTPUT_FRAMES_PER_BUFFER.
163  * Without that we just have to guess.
164  * @return
165  */
estimateNativeFramesPerBurst()166 int32_t AudioStreamOpenSLES::estimateNativeFramesPerBurst() {
167     int32_t framesPerBurst = DefaultStreamValues::FramesPerBurst;
168     LOGD("AudioStreamOpenSLES:%s() DefaultStreamValues::FramesPerBurst = %d",
169             __func__, DefaultStreamValues::FramesPerBurst);
170     framesPerBurst = std::max(framesPerBurst, 16);
171     // Calculate the size of a fixed duration high latency buffer based on sample rate.
172     // Estimate sample based on default options in order of priority.
173     int32_t sampleRate = 48000;
174     sampleRate = (DefaultStreamValues::SampleRate > 0)
175             ? DefaultStreamValues::SampleRate : sampleRate;
176     sampleRate = (mSampleRate > 0) ? mSampleRate : sampleRate;
177     int32_t framesPerHighLatencyBuffer =
178             (kHighLatencyBufferSizeMillis * sampleRate) / kMillisPerSecond;
179     // For high latency streams, use a larger buffer size.
180     // Performance Mode support was added in N_MR1 (7.1)
181     if (getSdkVersion() >= __ANDROID_API_N_MR1__
182             && mPerformanceMode != PerformanceMode::LowLatency
183             && framesPerBurst < framesPerHighLatencyBuffer) {
184         // Find a multiple of framesPerBurst >= framesPerHighLatencyBuffer.
185         int32_t numBursts = roundUpDivideByN(framesPerHighLatencyBuffer, framesPerBurst);
186         framesPerBurst *= numBursts;
187         LOGD("AudioStreamOpenSLES:%s() NOT low latency, numBursts = %d, mSampleRate = %d, set framesPerBurst = %d",
188              __func__, numBursts, mSampleRate, framesPerBurst);
189     }
190     return framesPerBurst;
191 }
192 
configureBufferSizes(int32_t sampleRate)193 Result AudioStreamOpenSLES::configureBufferSizes(int32_t sampleRate) {
194     LOGD("AudioStreamOpenSLES:%s(%d) initial mFramesPerBurst = %d, mFramesPerCallback = %d",
195             __func__, mSampleRate, mFramesPerBurst, mFramesPerCallback);
196     mFramesPerBurst = estimateNativeFramesPerBurst();
197     mFramesPerCallback = (mFramesPerCallback > 0) ? mFramesPerCallback : mFramesPerBurst;
198     LOGD("AudioStreamOpenSLES:%s(%d) final mFramesPerBurst = %d, mFramesPerCallback = %d",
199          __func__, mSampleRate, mFramesPerBurst, mFramesPerCallback);
200 
201     mBytesPerCallback = mFramesPerCallback * getBytesPerFrame();
202     if (mBytesPerCallback <= 0) {
203         LOGE("AudioStreamOpenSLES::open() bytesPerCallback < 0 = %d, bad format?",
204              mBytesPerCallback);
205         return Result::ErrorInvalidFormat; // causing bytesPerFrame == 0
206     }
207 
208     for (int i = 0; i < mBufferQueueLength; ++i) {
209         mCallbackBuffer[i] = std::make_unique<uint8_t[]>(mBytesPerCallback);
210     }
211 
212     if (!usingFIFO()) {
213         mBufferCapacityInFrames = mFramesPerBurst * mBufferQueueLength;
214         // Check for overflow.
215         if (mBufferCapacityInFrames <= 0) {
216             mBufferCapacityInFrames = 0;
217             LOGE("AudioStreamOpenSLES::open() numeric overflow because mFramesPerBurst = %d",
218                  mFramesPerBurst);
219             return Result::ErrorOutOfRange;
220         }
221         mBufferSizeInFrames = mBufferCapacityInFrames;
222     }
223 
224     return Result::OK;
225 }
226 
convertPerformanceMode(PerformanceMode oboeMode) const227 SLuint32 AudioStreamOpenSLES::convertPerformanceMode(PerformanceMode oboeMode) const {
228     SLuint32 openslMode = SL_ANDROID_PERFORMANCE_NONE;
229     switch(oboeMode) {
230         case PerformanceMode::None:
231             openslMode =  SL_ANDROID_PERFORMANCE_NONE;
232             break;
233         case PerformanceMode::LowLatency:
234             openslMode =  (getSessionId() == SessionId::None) ?  SL_ANDROID_PERFORMANCE_LATENCY : SL_ANDROID_PERFORMANCE_LATENCY_EFFECTS;
235             break;
236         case PerformanceMode::PowerSaving:
237             openslMode =  SL_ANDROID_PERFORMANCE_POWER_SAVING;
238             break;
239         default:
240             break;
241     }
242     return openslMode;
243 }
244 
convertPerformanceMode(SLuint32 openslMode) const245 PerformanceMode AudioStreamOpenSLES::convertPerformanceMode(SLuint32 openslMode) const {
246     PerformanceMode oboeMode = PerformanceMode::None;
247     switch(openslMode) {
248         case SL_ANDROID_PERFORMANCE_NONE:
249             oboeMode =  PerformanceMode::None;
250             break;
251         case SL_ANDROID_PERFORMANCE_LATENCY:
252         case SL_ANDROID_PERFORMANCE_LATENCY_EFFECTS:
253             oboeMode =  PerformanceMode::LowLatency;
254             break;
255         case SL_ANDROID_PERFORMANCE_POWER_SAVING:
256             oboeMode =  PerformanceMode::PowerSaving;
257             break;
258         default:
259             break;
260     }
261     return oboeMode;
262 }
263 
logUnsupportedAttributes()264 void AudioStreamOpenSLES::logUnsupportedAttributes() {
265     // Log unsupported attributes
266     // only report if changed from the default
267 
268     // Device ID
269     if (mDeviceId != kUnspecified) {
270         LOGW("Device ID [AudioStreamBuilder::setDeviceId()] "
271              "is not supported on OpenSLES streams.");
272     }
273     // Sharing Mode
274     if (mSharingMode != SharingMode::Shared) {
275         LOGW("SharingMode [AudioStreamBuilder::setSharingMode()] "
276              "is not supported on OpenSLES streams.");
277     }
278     // Performance Mode
279     int sdkVersion = getSdkVersion();
280     if (mPerformanceMode != PerformanceMode::None && sdkVersion < __ANDROID_API_N_MR1__) {
281         LOGW("PerformanceMode [AudioStreamBuilder::setPerformanceMode()] "
282              "is not supported on OpenSLES streams running on pre-Android N-MR1 versions.");
283     }
284     // Content Type
285     if (mContentType != ContentType::Music) {
286         LOGW("ContentType [AudioStreamBuilder::setContentType()] "
287              "is not supported on OpenSLES streams.");
288     }
289 
290     // Session Id
291     if (mSessionId != SessionId::None) {
292         LOGW("SessionId [AudioStreamBuilder::setSessionId()] "
293              "is not supported on OpenSLES streams.");
294     }
295 
296     // Privacy Sensitive Mode
297     if (mPrivacySensitiveMode != PrivacySensitiveMode::Unspecified) {
298         LOGW("PrivacySensitiveMode [AudioStreamBuilder::setPrivacySensitiveMode()] "
299              "is not supported on OpenSLES streams.");
300     }
301 
302     // Spatialization Behavior
303     if (mSpatializationBehavior != SpatializationBehavior::Unspecified) {
304         LOGW("SpatializationBehavior [AudioStreamBuilder::setSpatializationBehavior()] "
305              "is not supported on OpenSLES streams.");
306     }
307 
308     // Allowed Capture Policy
309     if (mAllowedCapturePolicy != AllowedCapturePolicy::Unspecified) {
310         LOGW("AllowedCapturePolicy [AudioStreamBuilder::setAllowedCapturePolicy()] "
311              "is not supported on OpenSLES streams.");
312     }
313 }
314 
configurePerformanceMode(SLAndroidConfigurationItf configItf)315 SLresult AudioStreamOpenSLES::configurePerformanceMode(SLAndroidConfigurationItf configItf) {
316 
317     if (configItf == nullptr) {
318         LOGW("%s() called with NULL configuration", __func__);
319         mPerformanceMode = PerformanceMode::None;
320         return SL_RESULT_INTERNAL_ERROR;
321     }
322     if (getSdkVersion() < __ANDROID_API_N_MR1__) {
323         LOGW("%s() not supported until N_MR1", __func__);
324         mPerformanceMode = PerformanceMode::None;
325         return SL_RESULT_SUCCESS;
326     }
327 
328     SLresult result = SL_RESULT_SUCCESS;
329     SLuint32 performanceMode = convertPerformanceMode(getPerformanceMode());
330     result = (*configItf)->SetConfiguration(configItf, SL_ANDROID_KEY_PERFORMANCE_MODE,
331                                                      &performanceMode, sizeof(performanceMode));
332     if (SL_RESULT_SUCCESS != result) {
333         LOGW("SetConfiguration(PERFORMANCE_MODE, SL %u) returned %s",
334              performanceMode, getSLErrStr(result));
335         mPerformanceMode = PerformanceMode::None;
336     }
337 
338     return result;
339 }
340 
updateStreamParameters(SLAndroidConfigurationItf configItf)341 SLresult AudioStreamOpenSLES::updateStreamParameters(SLAndroidConfigurationItf configItf) {
342     SLresult result = SL_RESULT_SUCCESS;
343     if(getSdkVersion() >= __ANDROID_API_N_MR1__ && configItf != nullptr) {
344         SLuint32 performanceMode = 0;
345         SLuint32 performanceModeSize = sizeof(performanceMode);
346         result = (*configItf)->GetConfiguration(configItf, SL_ANDROID_KEY_PERFORMANCE_MODE,
347                                                 &performanceModeSize, &performanceMode);
348         // A bug in GetConfiguration() before P caused a wrong result code to be returned.
349         if (getSdkVersion() <= __ANDROID_API_O_MR1__) {
350             result = SL_RESULT_SUCCESS; // Ignore actual result before P.
351         }
352 
353         if (SL_RESULT_SUCCESS != result) {
354             LOGW("GetConfiguration(SL_ANDROID_KEY_PERFORMANCE_MODE) returned %d", result);
355             mPerformanceMode = PerformanceMode::None; // If we can't query it then assume None.
356         } else {
357             mPerformanceMode = convertPerformanceMode(performanceMode); // convert SL to Oboe mode
358         }
359     } else {
360         mPerformanceMode = PerformanceMode::None; // If we can't query it then assume None.
361     }
362     return result;
363 }
364 
365 // This is called under mLock.
close_l()366 Result AudioStreamOpenSLES::close_l() {
367     if (mState == StreamState::Closed) {
368         return Result::ErrorClosed;
369     }
370 
371     AudioStreamBuffered::close();
372 
373     onBeforeDestroy();
374 
375     if (mObjectInterface != nullptr) {
376         (*mObjectInterface)->Destroy(mObjectInterface);
377         mObjectInterface = nullptr;
378     }
379 
380     onAfterDestroy();
381 
382     mSimpleBufferQueueInterface = nullptr;
383     EngineOpenSLES::getInstance().close();
384 
385     setState(StreamState::Closed);
386 
387     return Result::OK;
388 }
389 
enqueueCallbackBuffer(SLAndroidSimpleBufferQueueItf bq)390 SLresult AudioStreamOpenSLES::enqueueCallbackBuffer(SLAndroidSimpleBufferQueueItf bq) {
391     SLresult result = (*bq)->Enqueue(
392             bq, mCallbackBuffer[mCallbackBufferIndex].get(), mBytesPerCallback);
393     mCallbackBufferIndex = (mCallbackBufferIndex + 1) % mBufferQueueLength;
394     return result;
395 }
396 
getBufferDepth(SLAndroidSimpleBufferQueueItf bq)397 int32_t AudioStreamOpenSLES::getBufferDepth(SLAndroidSimpleBufferQueueItf bq) {
398     SLAndroidSimpleBufferQueueState queueState;
399     SLresult result = (*bq)->GetState(bq, &queueState);
400     return (result == SL_RESULT_SUCCESS) ? queueState.count : -1;
401 }
402 
processBufferCallback(SLAndroidSimpleBufferQueueItf bq)403 bool AudioStreamOpenSLES::processBufferCallback(SLAndroidSimpleBufferQueueItf bq) {
404     bool shouldStopStream = false;
405     // Ask the app callback to process the buffer.
406     DataCallbackResult result =
407             fireDataCallback(mCallbackBuffer[mCallbackBufferIndex].get(), mFramesPerCallback);
408     if (result == DataCallbackResult::Continue) {
409         // Pass the buffer to OpenSLES.
410         SLresult enqueueResult = enqueueCallbackBuffer(bq);
411         if (enqueueResult != SL_RESULT_SUCCESS) {
412             LOGE("%s() returned %d", __func__, enqueueResult);
413             shouldStopStream = true;
414         }
415         // Update Oboe client position with frames handled by the callback.
416         if (getDirection() == Direction::Input) {
417             mFramesRead += mFramesPerCallback;
418         } else {
419             mFramesWritten += mFramesPerCallback;
420         }
421     } else if (result == DataCallbackResult::Stop) {
422         LOGD("Oboe callback returned Stop");
423         shouldStopStream = true;
424     } else {
425         LOGW("Oboe callback returned unexpected value = %d", static_cast<int>(result));
426         shouldStopStream = true;
427     }
428     if (shouldStopStream) {
429         mCallbackBufferIndex = 0;
430     }
431     return shouldStopStream;
432 }
433 
434 // This callback handler is called every time a buffer has been processed by OpenSL ES.
bqCallbackGlue(SLAndroidSimpleBufferQueueItf bq,void * context)435 static void bqCallbackGlue(SLAndroidSimpleBufferQueueItf bq, void *context) {
436     bool shouldStopStream = (reinterpret_cast<AudioStreamOpenSLES *>(context))
437             ->processBufferCallback(bq);
438     if (shouldStopStream) {
439         (reinterpret_cast<AudioStreamOpenSLES *>(context))->requestStop();
440     }
441 }
442 
registerBufferQueueCallback()443 SLresult AudioStreamOpenSLES::registerBufferQueueCallback() {
444     // The BufferQueue
445     SLresult result = (*mObjectInterface)->GetInterface(mObjectInterface, SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
446                                                 &mSimpleBufferQueueInterface);
447     if (SL_RESULT_SUCCESS != result) {
448         LOGE("get buffer queue interface:%p result:%s",
449              mSimpleBufferQueueInterface,
450              getSLErrStr(result));
451     } else {
452         // Register the BufferQueue callback
453         result = (*mSimpleBufferQueueInterface)->RegisterCallback(mSimpleBufferQueueInterface,
454                                                                   bqCallbackGlue, this);
455         if (SL_RESULT_SUCCESS != result) {
456             LOGE("RegisterCallback result:%s", getSLErrStr(result));
457         }
458     }
459     return result;
460 }
461 
getFramesProcessedByServer()462 int64_t AudioStreamOpenSLES::getFramesProcessedByServer() {
463     updateServiceFrameCounter();
464     int64_t millis64 = mPositionMillis.get();
465     int64_t framesProcessed = millis64 * getSampleRate() / kMillisPerSecond;
466     return framesProcessed;
467 }
468 
waitForStateChange(StreamState currentState,StreamState * nextState,int64_t timeoutNanoseconds)469 Result AudioStreamOpenSLES::waitForStateChange(StreamState currentState,
470                                                      StreamState *nextState,
471                                                      int64_t timeoutNanoseconds) {
472     Result oboeResult = Result::ErrorTimeout;
473     int64_t sleepTimeNanos = 20 * kNanosPerMillisecond; // arbitrary
474     int64_t timeLeftNanos = timeoutNanoseconds;
475 
476     while (true) {
477         const StreamState state = getState(); // this does not require a lock
478         if (nextState != nullptr) {
479             *nextState = state;
480         }
481         if (currentState != state) { // state changed?
482             oboeResult = Result::OK;
483             break;
484         }
485 
486         // Did we timeout or did user ask for non-blocking?
487         if (timeLeftNanos <= 0) {
488             break;
489         }
490 
491         if (sleepTimeNanos > timeLeftNanos){
492             sleepTimeNanos = timeLeftNanos;
493         }
494         AudioClock::sleepForNanos(sleepTimeNanos);
495         timeLeftNanos -= sleepTimeNanos;
496     }
497 
498     return oboeResult;
499 }
500