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