• 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 <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: %d",
76              __func__, 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     SLresult result = registerBufferQueueCallback();
112     if (SL_RESULT_SUCCESS != result) {
113         return result;
114     }
115 
116     result = updateStreamParameters(configItf);
117     if (SL_RESULT_SUCCESS != result) {
118         return result;
119     }
120 
121     Result oboeResult = configureBufferSizes(mSampleRate);
122     if (Result::OK != oboeResult) {
123         return (SLresult) oboeResult;
124     }
125 
126     allocateFifo();
127 
128     calculateDefaultDelayBeforeCloseMillis();
129 
130     return SL_RESULT_SUCCESS;
131 }
132 
roundUpDivideByN(int32_t x,int32_t n)133 static int32_t roundUpDivideByN(int32_t x, int32_t n) {
134     return (x + n - 1) / n;
135 }
136 
calculateOptimalBufferQueueLength()137 int32_t AudioStreamOpenSLES::calculateOptimalBufferQueueLength() {
138     int32_t queueLength = kBufferQueueLengthDefault;
139     int32_t likelyFramesPerBurst = estimateNativeFramesPerBurst();
140     int32_t minCapacity = mBufferCapacityInFrames; // specified by app or zero
141     // The buffer capacity needs to be at least twice the size of the requested callbackSize
142     // so that we can have double buffering.
143     minCapacity = std::max(minCapacity, kDoubleBufferCount * mFramesPerCallback);
144     if (minCapacity > 0) {
145         int32_t queueLengthFromCapacity = roundUpDivideByN(minCapacity, likelyFramesPerBurst);
146         queueLength = std::max(queueLength, queueLengthFromCapacity);
147     }
148     queueLength = std::min(queueLength, kBufferQueueLengthMax); // clip to max
149     // TODO Investigate the effect of queueLength on latency for normal streams. (not low latency)
150     return queueLength;
151 }
152 
153 /**
154  * The best information we have is if DefaultStreamValues::FramesPerBurst
155  * was set by the app based on AudioManager.PROPERTY_OUTPUT_FRAMES_PER_BUFFER.
156  * Without that we just have to guess.
157  * @return
158  */
estimateNativeFramesPerBurst()159 int32_t AudioStreamOpenSLES::estimateNativeFramesPerBurst() {
160     int32_t framesPerBurst = DefaultStreamValues::FramesPerBurst;
161     LOGD("AudioStreamOpenSLES:%s() DefaultStreamValues::FramesPerBurst = %d",
162             __func__, DefaultStreamValues::FramesPerBurst);
163     framesPerBurst = std::max(framesPerBurst, 16);
164     // Calculate the size of a fixed duration high latency buffer based on sample rate.
165     // Estimate sample based on default options in order of priority.
166     int32_t sampleRate = 48000;
167     sampleRate = (DefaultStreamValues::SampleRate > 0)
168             ? DefaultStreamValues::SampleRate : sampleRate;
169     sampleRate = (mSampleRate > 0) ? mSampleRate : sampleRate;
170     int32_t framesPerHighLatencyBuffer =
171             (kHighLatencyBufferSizeMillis * sampleRate) / kMillisPerSecond;
172     // For high latency streams, use a larger buffer size.
173     // Performance Mode support was added in N_MR1 (7.1)
174     if (getSdkVersion() >= __ANDROID_API_N_MR1__
175             && mPerformanceMode != PerformanceMode::LowLatency
176             && framesPerBurst < framesPerHighLatencyBuffer) {
177         // Find a multiple of framesPerBurst >= framesPerHighLatencyBuffer.
178         int32_t numBursts = roundUpDivideByN(framesPerHighLatencyBuffer, framesPerBurst);
179         framesPerBurst *= numBursts;
180         LOGD("AudioStreamOpenSLES:%s() NOT low latency, numBursts = %d, mSampleRate = %d, set framesPerBurst = %d",
181              __func__, numBursts, mSampleRate, framesPerBurst);
182     }
183     return framesPerBurst;
184 }
185 
configureBufferSizes(int32_t sampleRate)186 Result AudioStreamOpenSLES::configureBufferSizes(int32_t sampleRate) {
187     LOGD("AudioStreamOpenSLES:%s(%d) initial mFramesPerBurst = %d, mFramesPerCallback = %d",
188             __func__, mSampleRate, mFramesPerBurst, mFramesPerCallback);
189     mFramesPerBurst = estimateNativeFramesPerBurst();
190     mFramesPerCallback = (mFramesPerCallback > 0) ? mFramesPerCallback : mFramesPerBurst;
191     LOGD("AudioStreamOpenSLES:%s(%d) final mFramesPerBurst = %d, mFramesPerCallback = %d",
192          __func__, mSampleRate, mFramesPerBurst, mFramesPerCallback);
193 
194     mBytesPerCallback = mFramesPerCallback * getBytesPerFrame();
195     if (mBytesPerCallback <= 0) {
196         LOGE("AudioStreamOpenSLES::open() bytesPerCallback < 0 = %d, bad format?",
197              mBytesPerCallback);
198         return Result::ErrorInvalidFormat; // causing bytesPerFrame == 0
199     }
200 
201     for (int i = 0; i < mBufferQueueLength; ++i) {
202         mCallbackBuffer[i] = std::make_unique<uint8_t[]>(mBytesPerCallback);
203     }
204 
205     if (!usingFIFO()) {
206         mBufferCapacityInFrames = mFramesPerBurst * mBufferQueueLength;
207         // Check for overflow.
208         if (mBufferCapacityInFrames <= 0) {
209             mBufferCapacityInFrames = 0;
210             LOGE("AudioStreamOpenSLES::open() numeric overflow because mFramesPerBurst = %d",
211                  mFramesPerBurst);
212             return Result::ErrorOutOfRange;
213         }
214         mBufferSizeInFrames = mBufferCapacityInFrames;
215     }
216 
217     return Result::OK;
218 }
219 
convertPerformanceMode(PerformanceMode oboeMode) const220 SLuint32 AudioStreamOpenSLES::convertPerformanceMode(PerformanceMode oboeMode) const {
221     SLuint32 openslMode = SL_ANDROID_PERFORMANCE_NONE;
222     switch(oboeMode) {
223         case PerformanceMode::None:
224             openslMode =  SL_ANDROID_PERFORMANCE_NONE;
225             break;
226         case PerformanceMode::LowLatency:
227             openslMode =  (getSessionId() == SessionId::None) ?  SL_ANDROID_PERFORMANCE_LATENCY : SL_ANDROID_PERFORMANCE_LATENCY_EFFECTS;
228             break;
229         case PerformanceMode::PowerSaving:
230             openslMode =  SL_ANDROID_PERFORMANCE_POWER_SAVING;
231             break;
232         default:
233             break;
234     }
235     return openslMode;
236 }
237 
convertPerformanceMode(SLuint32 openslMode) const238 PerformanceMode AudioStreamOpenSLES::convertPerformanceMode(SLuint32 openslMode) const {
239     PerformanceMode oboeMode = PerformanceMode::None;
240     switch(openslMode) {
241         case SL_ANDROID_PERFORMANCE_NONE:
242             oboeMode =  PerformanceMode::None;
243             break;
244         case SL_ANDROID_PERFORMANCE_LATENCY:
245         case SL_ANDROID_PERFORMANCE_LATENCY_EFFECTS:
246             oboeMode =  PerformanceMode::LowLatency;
247             break;
248         case SL_ANDROID_PERFORMANCE_POWER_SAVING:
249             oboeMode =  PerformanceMode::PowerSaving;
250             break;
251         default:
252             break;
253     }
254     return oboeMode;
255 }
256 
logUnsupportedAttributes()257 void AudioStreamOpenSLES::logUnsupportedAttributes() {
258     // Log unsupported attributes
259     // only report if changed from the default
260 
261     // Device ID
262     if (mDeviceId != kUnspecified) {
263         LOGW("Device ID [AudioStreamBuilder::setDeviceId()] "
264              "is not supported on OpenSLES streams.");
265     }
266     // Sharing Mode
267     if (mSharingMode != SharingMode::Shared) {
268         LOGW("SharingMode [AudioStreamBuilder::setSharingMode()] "
269              "is not supported on OpenSLES streams.");
270     }
271     // Performance Mode
272     int sdkVersion = getSdkVersion();
273     if (mPerformanceMode != PerformanceMode::None && sdkVersion < __ANDROID_API_N_MR1__) {
274         LOGW("PerformanceMode [AudioStreamBuilder::setPerformanceMode()] "
275              "is not supported on OpenSLES streams running on pre-Android N-MR1 versions.");
276     }
277     // Content Type
278     if (mContentType != ContentType::Music) {
279         LOGW("ContentType [AudioStreamBuilder::setContentType()] "
280              "is not supported on OpenSLES streams.");
281     }
282 
283     // Session Id
284     if (mSessionId != SessionId::None) {
285         LOGW("SessionId [AudioStreamBuilder::setSessionId()] "
286              "is not supported on OpenSLES streams.");
287     }
288 }
289 
configurePerformanceMode(SLAndroidConfigurationItf configItf)290 SLresult AudioStreamOpenSLES::configurePerformanceMode(SLAndroidConfigurationItf configItf) {
291 
292     if (configItf == nullptr) {
293         LOGW("%s() called with NULL configuration", __func__);
294         mPerformanceMode = PerformanceMode::None;
295         return SL_RESULT_INTERNAL_ERROR;
296     }
297     if (getSdkVersion() < __ANDROID_API_N_MR1__) {
298         LOGW("%s() not supported until N_MR1", __func__);
299         mPerformanceMode = PerformanceMode::None;
300         return SL_RESULT_SUCCESS;
301     }
302 
303     SLresult result = SL_RESULT_SUCCESS;
304     SLuint32 performanceMode = convertPerformanceMode(getPerformanceMode());
305     result = (*configItf)->SetConfiguration(configItf, SL_ANDROID_KEY_PERFORMANCE_MODE,
306                                                      &performanceMode, sizeof(performanceMode));
307     if (SL_RESULT_SUCCESS != result) {
308         LOGW("SetConfiguration(PERFORMANCE_MODE, SL %u) returned %s",
309              performanceMode, getSLErrStr(result));
310         mPerformanceMode = PerformanceMode::None;
311     }
312 
313     return result;
314 }
315 
updateStreamParameters(SLAndroidConfigurationItf configItf)316 SLresult AudioStreamOpenSLES::updateStreamParameters(SLAndroidConfigurationItf configItf) {
317     SLresult result = SL_RESULT_SUCCESS;
318     if(getSdkVersion() >= __ANDROID_API_N_MR1__ && configItf != nullptr) {
319         SLuint32 performanceMode = 0;
320         SLuint32 performanceModeSize = sizeof(performanceMode);
321         result = (*configItf)->GetConfiguration(configItf, SL_ANDROID_KEY_PERFORMANCE_MODE,
322                                                 &performanceModeSize, &performanceMode);
323         // A bug in GetConfiguration() before P caused a wrong result code to be returned.
324         if (getSdkVersion() <= __ANDROID_API_O_MR1__) {
325             result = SL_RESULT_SUCCESS; // Ignore actual result before P.
326         }
327 
328         if (SL_RESULT_SUCCESS != result) {
329             LOGW("GetConfiguration(SL_ANDROID_KEY_PERFORMANCE_MODE) returned %d", result);
330             mPerformanceMode = PerformanceMode::None; // If we can't query it then assume None.
331         } else {
332             mPerformanceMode = convertPerformanceMode(performanceMode); // convert SL to Oboe mode
333         }
334     } else {
335         mPerformanceMode = PerformanceMode::None; // If we can't query it then assume None.
336     }
337     return result;
338 }
339 
340 // This is called under mLock.
close_l()341 Result AudioStreamOpenSLES::close_l() {
342     if (mState == StreamState::Closed) {
343         return Result::ErrorClosed;
344     }
345 
346     AudioStreamBuffered::close();
347 
348     onBeforeDestroy();
349 
350     if (mObjectInterface != nullptr) {
351         (*mObjectInterface)->Destroy(mObjectInterface);
352         mObjectInterface = nullptr;
353     }
354 
355     onAfterDestroy();
356 
357     mSimpleBufferQueueInterface = nullptr;
358     EngineOpenSLES::getInstance().close();
359 
360     setState(StreamState::Closed);
361     return Result::OK;
362 }
363 
enqueueCallbackBuffer(SLAndroidSimpleBufferQueueItf bq)364 SLresult AudioStreamOpenSLES::enqueueCallbackBuffer(SLAndroidSimpleBufferQueueItf bq) {
365     SLresult result = (*bq)->Enqueue(
366             bq, mCallbackBuffer[mCallbackBufferIndex].get(), mBytesPerCallback);
367     mCallbackBufferIndex = (mCallbackBufferIndex + 1) % mBufferQueueLength;
368     return result;
369 }
370 
getBufferDepth(SLAndroidSimpleBufferQueueItf bq)371 int32_t AudioStreamOpenSLES::getBufferDepth(SLAndroidSimpleBufferQueueItf bq) {
372     SLAndroidSimpleBufferQueueState queueState;
373     SLresult result = (*bq)->GetState(bq, &queueState);
374     return (result == SL_RESULT_SUCCESS) ? queueState.count : -1;
375 }
376 
processBufferCallback(SLAndroidSimpleBufferQueueItf bq)377 bool AudioStreamOpenSLES::processBufferCallback(SLAndroidSimpleBufferQueueItf bq) {
378     bool shouldStopStream = false;
379     // Ask the app callback to process the buffer.
380     DataCallbackResult result =
381             fireDataCallback(mCallbackBuffer[mCallbackBufferIndex].get(), mFramesPerCallback);
382     if (result == DataCallbackResult::Continue) {
383         // Pass the buffer to OpenSLES.
384         SLresult enqueueResult = enqueueCallbackBuffer(bq);
385         if (enqueueResult != SL_RESULT_SUCCESS) {
386             LOGE("%s() returned %d", __func__, enqueueResult);
387             shouldStopStream = true;
388         }
389         // Update Oboe client position with frames handled by the callback.
390         if (getDirection() == Direction::Input) {
391             mFramesRead += mFramesPerCallback;
392         } else {
393             mFramesWritten += mFramesPerCallback;
394         }
395     } else if (result == DataCallbackResult::Stop) {
396         LOGD("Oboe callback returned Stop");
397         shouldStopStream = true;
398     } else {
399         LOGW("Oboe callback returned unexpected value = %d", result);
400         shouldStopStream = true;
401     }
402     if (shouldStopStream) {
403         mCallbackBufferIndex = 0;
404     }
405     return shouldStopStream;
406 }
407 
408 // This callback handler is called every time a buffer has been processed by OpenSL ES.
bqCallbackGlue(SLAndroidSimpleBufferQueueItf bq,void * context)409 static void bqCallbackGlue(SLAndroidSimpleBufferQueueItf bq, void *context) {
410     bool shouldStopStream = (reinterpret_cast<AudioStreamOpenSLES *>(context))
411             ->processBufferCallback(bq);
412     if (shouldStopStream) {
413         (reinterpret_cast<AudioStreamOpenSLES *>(context))->requestStop();
414     }
415 }
416 
registerBufferQueueCallback()417 SLresult AudioStreamOpenSLES::registerBufferQueueCallback() {
418     // The BufferQueue
419     SLresult result = (*mObjectInterface)->GetInterface(mObjectInterface, SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
420                                                 &mSimpleBufferQueueInterface);
421     if (SL_RESULT_SUCCESS != result) {
422         LOGE("get buffer queue interface:%p result:%s",
423              mSimpleBufferQueueInterface,
424              getSLErrStr(result));
425     } else {
426         // Register the BufferQueue callback
427         result = (*mSimpleBufferQueueInterface)->RegisterCallback(mSimpleBufferQueueInterface,
428                                                                   bqCallbackGlue, this);
429         if (SL_RESULT_SUCCESS != result) {
430             LOGE("RegisterCallback result:%s", getSLErrStr(result));
431         }
432     }
433     return result;
434 }
435 
getFramesProcessedByServer()436 int64_t AudioStreamOpenSLES::getFramesProcessedByServer() {
437     updateServiceFrameCounter();
438     int64_t millis64 = mPositionMillis.get();
439     int64_t framesProcessed = millis64 * getSampleRate() / kMillisPerSecond;
440     return framesProcessed;
441 }
442 
waitForStateChange(StreamState currentState,StreamState * nextState,int64_t timeoutNanoseconds)443 Result AudioStreamOpenSLES::waitForStateChange(StreamState currentState,
444                                                      StreamState *nextState,
445                                                      int64_t timeoutNanoseconds) {
446     Result oboeResult = Result::ErrorTimeout;
447     int64_t sleepTimeNanos = 20 * kNanosPerMillisecond; // arbitrary
448     int64_t timeLeftNanos = timeoutNanoseconds;
449 
450     while (true) {
451         const StreamState state = getState(); // this does not require a lock
452         if (nextState != nullptr) {
453             *nextState = state;
454         }
455         if (currentState != state) { // state changed?
456             oboeResult = Result::OK;
457             break;
458         }
459 
460         // Did we timeout or did user ask for non-blocking?
461         if (timeLeftNanos <= 0) {
462             break;
463         }
464 
465         if (sleepTimeNanos > timeLeftNanos){
466             sleepTimeNanos = timeLeftNanos;
467         }
468         AudioClock::sleepForNanos(sleepTimeNanos);
469         timeLeftNanos -= sleepTimeNanos;
470     }
471 
472     return oboeResult;
473 }
474