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