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