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
20 #include <SLES/OpenSLES.h>
21 #include <SLES/OpenSLES_Android.h>
22 #include <oboe/AudioStream.h>
23 #include <common/AudioClock.h>
24
25 #include "common/OboeDebug.h"
26 #include "oboe/AudioStreamBuilder.h"
27 #include "AudioStreamOpenSLES.h"
28 #include "OpenSLESUtilities.h"
29
30 using namespace oboe;
31
AudioStreamOpenSLES(const AudioStreamBuilder & builder)32 AudioStreamOpenSLES::AudioStreamOpenSLES(const AudioStreamBuilder &builder)
33 : AudioStreamBuffered(builder) {
34 // OpenSL ES does not support device IDs. So overwrite value from builder.
35 mDeviceId = kUnspecified;
36 // OpenSL ES does not support session IDs. So overwrite value from builder.
37 mSessionId = SessionId::None;
38 }
39
40 static constexpr int32_t kHighLatencyBufferSizeMillis = 20; // typical Android period
41 static constexpr SLuint32 kAudioChannelCountMax = 30; // TODO Why 30?
42 static constexpr SLuint32 SL_ANDROID_UNKNOWN_CHANNELMASK = 0; // Matches name used internally.
43
channelCountToChannelMaskDefault(int channelCount) const44 SLuint32 AudioStreamOpenSLES::channelCountToChannelMaskDefault(int channelCount) const {
45 if (channelCount > kAudioChannelCountMax) {
46 return SL_ANDROID_UNKNOWN_CHANNELMASK;
47 }
48
49 SLuint32 bitfield = (1 << channelCount) - 1;
50
51 // Check for OS at run-time.
52 if(getSdkVersion() >= __ANDROID_API_N__) {
53 return SL_ANDROID_MAKE_INDEXED_CHANNEL_MASK(bitfield);
54 }
55
56 // Indexed channels masks were added in N.
57 // For before N, the best we can do is use a positional channel mask.
58 return bitfield;
59 }
60
s_isLittleEndian()61 static bool s_isLittleEndian() {
62 static uint32_t value = 1;
63 return (*reinterpret_cast<uint8_t *>(&value) == 1); // Does address point to LSB?
64 }
65
getDefaultByteOrder()66 SLuint32 AudioStreamOpenSLES::getDefaultByteOrder() {
67 return s_isLittleEndian() ? SL_BYTEORDER_LITTLEENDIAN : SL_BYTEORDER_BIGENDIAN;
68 }
69
open()70 Result AudioStreamOpenSLES::open() {
71
72 LOGI("AudioStreamOpenSLES::open() chans=%d, rate=%d", mChannelCount, mSampleRate);
73
74 SLresult result = EngineOpenSLES::getInstance().open();
75 if (SL_RESULT_SUCCESS != result) {
76 return Result::ErrorInternal;
77 }
78
79 Result oboeResult = AudioStreamBuffered::open();
80 if (oboeResult != Result::OK) {
81 return oboeResult;
82 }
83 // Convert to defaults if UNSPECIFIED
84 if (mSampleRate == kUnspecified) {
85 mSampleRate = DefaultStreamValues::SampleRate;
86 }
87 if (mChannelCount == kUnspecified) {
88 mChannelCount = DefaultStreamValues::ChannelCount;
89 }
90
91 mSharingMode = SharingMode::Shared;
92
93 return Result::OK;
94 }
95
configureBufferSizes(int32_t sampleRate)96 Result AudioStreamOpenSLES::configureBufferSizes(int32_t sampleRate) {
97 LOGD("AudioStreamOpenSLES:%s(%d) initial mFramesPerBurst = %d, mFramesPerCallback = %d",
98 __func__, sampleRate, mFramesPerBurst, mFramesPerCallback);
99 // Decide frames per burst based on hints from caller.
100 if (mFramesPerCallback != kUnspecified) {
101 // Requested framesPerCallback must be honored.
102 mFramesPerBurst = mFramesPerCallback;
103 } else {
104 mFramesPerBurst = DefaultStreamValues::FramesPerBurst;
105
106 // Calculate the size of a fixed duration high latency buffer based on sample rate.
107 int32_t framesPerHighLatencyBuffer =
108 (kHighLatencyBufferSizeMillis * sampleRate) / kMillisPerSecond;
109
110 // For high latency streams, use a larger buffer size.
111 // Performance Mode support was added in N_MR1 (7.1)
112 if (getSdkVersion() >= __ANDROID_API_N_MR1__
113 && mPerformanceMode != PerformanceMode::LowLatency
114 && mFramesPerBurst < framesPerHighLatencyBuffer) {
115 // Find a multiple of framesPerBurst >= framesPerHighLatencyBuffer.
116 int32_t numBursts = (framesPerHighLatencyBuffer + mFramesPerBurst - 1) / mFramesPerBurst;
117 mFramesPerBurst *= numBursts;
118 LOGD("AudioStreamOpenSLES:%s() NOT low latency, set mFramesPerBurst = %d",
119 __func__, mFramesPerBurst);
120 }
121 mFramesPerCallback = mFramesPerBurst;
122 }
123 LOGD("AudioStreamOpenSLES:%s(%d) final mFramesPerBurst = %d, mFramesPerCallback = %d",
124 __func__, sampleRate, mFramesPerBurst, mFramesPerCallback);
125
126 mBytesPerCallback = mFramesPerCallback * getBytesPerFrame();
127 if (mBytesPerCallback <= 0) {
128 LOGE("AudioStreamOpenSLES::open() bytesPerCallback < 0 = %d, bad format?",
129 mBytesPerCallback);
130 return Result::ErrorInvalidFormat; // causing bytesPerFrame == 0
131 }
132
133 mCallbackBuffer = std::make_unique<uint8_t[]>(mBytesPerCallback);
134
135 if (!usingFIFO()) {
136 mBufferCapacityInFrames = mFramesPerBurst * kBufferQueueLength;
137 // Check for overflow.
138 if (mBufferCapacityInFrames <= 0) {
139 mBufferCapacityInFrames = 0;
140 LOGE("AudioStreamOpenSLES::open() numeric overflow because mFramesPerBurst = %d",
141 mFramesPerBurst);
142 return Result::ErrorOutOfRange;
143 }
144 mBufferSizeInFrames = mBufferCapacityInFrames;
145 }
146
147 return Result::OK;
148 }
149
convertPerformanceMode(PerformanceMode oboeMode) const150 SLuint32 AudioStreamOpenSLES::convertPerformanceMode(PerformanceMode oboeMode) const {
151 SLuint32 openslMode = SL_ANDROID_PERFORMANCE_NONE;
152 switch(oboeMode) {
153 case PerformanceMode::None:
154 openslMode = SL_ANDROID_PERFORMANCE_NONE;
155 break;
156 case PerformanceMode::LowLatency:
157 openslMode = (getSessionId() == SessionId::None) ? SL_ANDROID_PERFORMANCE_LATENCY : SL_ANDROID_PERFORMANCE_LATENCY_EFFECTS;
158 break;
159 case PerformanceMode::PowerSaving:
160 openslMode = SL_ANDROID_PERFORMANCE_POWER_SAVING;
161 break;
162 default:
163 break;
164 }
165 return openslMode;
166 }
167
convertPerformanceMode(SLuint32 openslMode) const168 PerformanceMode AudioStreamOpenSLES::convertPerformanceMode(SLuint32 openslMode) const {
169 PerformanceMode oboeMode = PerformanceMode::None;
170 switch(openslMode) {
171 case SL_ANDROID_PERFORMANCE_NONE:
172 oboeMode = PerformanceMode::None;
173 break;
174 case SL_ANDROID_PERFORMANCE_LATENCY:
175 case SL_ANDROID_PERFORMANCE_LATENCY_EFFECTS:
176 oboeMode = PerformanceMode::LowLatency;
177 break;
178 case SL_ANDROID_PERFORMANCE_POWER_SAVING:
179 oboeMode = PerformanceMode::PowerSaving;
180 break;
181 default:
182 break;
183 }
184 return oboeMode;
185 }
186
logUnsupportedAttributes()187 void AudioStreamOpenSLES::logUnsupportedAttributes() {
188 // Log unsupported attributes
189 // only report if changed from the default
190
191 // Device ID
192 if (mDeviceId != kUnspecified) {
193 LOGW("Device ID [AudioStreamBuilder::setDeviceId()] "
194 "is not supported on OpenSLES streams.");
195 }
196 // Sharing Mode
197 if (mSharingMode != SharingMode::Shared) {
198 LOGW("SharingMode [AudioStreamBuilder::setSharingMode()] "
199 "is not supported on OpenSLES streams.");
200 }
201 // Performance Mode
202 int sdkVersion = getSdkVersion();
203 if (mPerformanceMode != PerformanceMode::None && sdkVersion < __ANDROID_API_N_MR1__) {
204 LOGW("PerformanceMode [AudioStreamBuilder::setPerformanceMode()] "
205 "is not supported on OpenSLES streams running on pre-Android N-MR1 versions.");
206 }
207 // Content Type
208 if (mContentType != ContentType::Music) {
209 LOGW("ContentType [AudioStreamBuilder::setContentType()] "
210 "is not supported on OpenSLES streams.");
211 }
212
213 // Session Id
214 if (mSessionId != SessionId::None) {
215 LOGW("SessionId [AudioStreamBuilder::setSessionId()] "
216 "is not supported on OpenSLES streams.");
217 }
218 }
219
configurePerformanceMode(SLAndroidConfigurationItf configItf)220 SLresult AudioStreamOpenSLES::configurePerformanceMode(SLAndroidConfigurationItf configItf) {
221
222 if (configItf == nullptr) {
223 LOGW("%s() called with NULL configuration", __func__);
224 mPerformanceMode = PerformanceMode::None;
225 return SL_RESULT_INTERNAL_ERROR;
226 }
227 if (getSdkVersion() < __ANDROID_API_N_MR1__) {
228 LOGW("%s() not supported until N_MR1", __func__);
229 mPerformanceMode = PerformanceMode::None;
230 return SL_RESULT_SUCCESS;
231 }
232
233 SLresult result = SL_RESULT_SUCCESS;
234 SLuint32 performanceMode = convertPerformanceMode(getPerformanceMode());
235 result = (*configItf)->SetConfiguration(configItf, SL_ANDROID_KEY_PERFORMANCE_MODE,
236 &performanceMode, sizeof(performanceMode));
237 if (SL_RESULT_SUCCESS != result) {
238 LOGW("SetConfiguration(PERFORMANCE_MODE, SL %u) returned %s",
239 performanceMode, getSLErrStr(result));
240 mPerformanceMode = PerformanceMode::None;
241 }
242
243 return result;
244 }
245
updateStreamParameters(SLAndroidConfigurationItf configItf)246 SLresult AudioStreamOpenSLES::updateStreamParameters(SLAndroidConfigurationItf configItf) {
247 SLresult result = SL_RESULT_SUCCESS;
248 if(getSdkVersion() >= __ANDROID_API_N_MR1__ && configItf != nullptr) {
249 SLuint32 performanceMode = 0;
250 SLuint32 performanceModeSize = sizeof(performanceMode);
251 result = (*configItf)->GetConfiguration(configItf, SL_ANDROID_KEY_PERFORMANCE_MODE,
252 &performanceModeSize, &performanceMode);
253 // A bug in GetConfiguration() before P caused a wrong result code to be returned.
254 if (getSdkVersion() <= __ANDROID_API_O_MR1__) {
255 result = SL_RESULT_SUCCESS; // Ignore actual result before P.
256 }
257
258 if (SL_RESULT_SUCCESS != result) {
259 LOGW("GetConfiguration(SL_ANDROID_KEY_PERFORMANCE_MODE) returned %d", result);
260 mPerformanceMode = PerformanceMode::None; // If we can't query it then assume None.
261 } else {
262 mPerformanceMode = convertPerformanceMode(performanceMode); // convert SL to Oboe mode
263 }
264 } else {
265 mPerformanceMode = PerformanceMode::None; // If we can't query it then assume None.
266 }
267 return result;
268 }
269
270 // This is called under mLock.
close_l()271 Result AudioStreamOpenSLES::close_l() {
272 if (mState == StreamState::Closed) {
273 return Result::ErrorClosed;
274 }
275
276 AudioStreamBuffered::close();
277
278 onBeforeDestroy();
279
280 if (mObjectInterface != nullptr) {
281 (*mObjectInterface)->Destroy(mObjectInterface);
282 mObjectInterface = nullptr;
283 }
284
285 onAfterDestroy();
286
287 mSimpleBufferQueueInterface = nullptr;
288 EngineOpenSLES::getInstance().close();
289
290 setState(StreamState::Closed);
291 return Result::OK;
292 }
293
enqueueCallbackBuffer(SLAndroidSimpleBufferQueueItf bq)294 SLresult AudioStreamOpenSLES::enqueueCallbackBuffer(SLAndroidSimpleBufferQueueItf bq) {
295 return (*bq)->Enqueue(bq, mCallbackBuffer.get(), mBytesPerCallback);
296 }
297
getBufferDepth(SLAndroidSimpleBufferQueueItf bq)298 int32_t AudioStreamOpenSLES::getBufferDepth(SLAndroidSimpleBufferQueueItf bq) {
299 SLAndroidSimpleBufferQueueState queueState;
300 SLresult result = (*bq)->GetState(bq, &queueState);
301 return (result == SL_RESULT_SUCCESS) ? queueState.count : -1;
302 }
303
processBufferCallback(SLAndroidSimpleBufferQueueItf bq)304 void AudioStreamOpenSLES::processBufferCallback(SLAndroidSimpleBufferQueueItf bq) {
305 bool stopStream = false;
306 // Ask the app callback to process the buffer.
307 DataCallbackResult result = fireDataCallback(mCallbackBuffer.get(), mFramesPerCallback);
308 if (result == DataCallbackResult::Continue) {
309 // Pass the buffer to OpenSLES.
310 SLresult enqueueResult = enqueueCallbackBuffer(bq);
311 if (enqueueResult != SL_RESULT_SUCCESS) {
312 LOGE("%s() returned %d", __func__, enqueueResult);
313 stopStream = true;
314 }
315 // Update Oboe client position with frames handled by the callback.
316 if (getDirection() == Direction::Input) {
317 mFramesRead += mFramesPerCallback;
318 } else {
319 mFramesWritten += mFramesPerCallback;
320 }
321 } else if (result == DataCallbackResult::Stop) {
322 LOGD("Oboe callback returned Stop");
323 stopStream = true;
324 } else {
325 LOGW("Oboe callback returned unexpected value = %d", result);
326 stopStream = true;
327 }
328 if (stopStream) {
329 requestStop();
330 }
331 }
332
333 // This callback handler is called every time a buffer has been processed by OpenSL ES.
bqCallbackGlue(SLAndroidSimpleBufferQueueItf bq,void * context)334 static void bqCallbackGlue(SLAndroidSimpleBufferQueueItf bq, void *context) {
335 (reinterpret_cast<AudioStreamOpenSLES *>(context))->processBufferCallback(bq);
336 }
337
registerBufferQueueCallback()338 SLresult AudioStreamOpenSLES::registerBufferQueueCallback() {
339 // The BufferQueue
340 SLresult result = (*mObjectInterface)->GetInterface(mObjectInterface, SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
341 &mSimpleBufferQueueInterface);
342 if (SL_RESULT_SUCCESS != result) {
343 LOGE("get buffer queue interface:%p result:%s",
344 mSimpleBufferQueueInterface,
345 getSLErrStr(result));
346 } else {
347 // Register the BufferQueue callback
348 result = (*mSimpleBufferQueueInterface)->RegisterCallback(mSimpleBufferQueueInterface,
349 bqCallbackGlue, this);
350 if (SL_RESULT_SUCCESS != result) {
351 LOGE("RegisterCallback result:%s", getSLErrStr(result));
352 }
353 }
354 return result;
355 }
356
getFramesPerBurst()357 int32_t AudioStreamOpenSLES::getFramesPerBurst() {
358 return mFramesPerBurst;
359 }
360
getFramesProcessedByServer()361 int64_t AudioStreamOpenSLES::getFramesProcessedByServer() {
362 updateServiceFrameCounter();
363 int64_t millis64 = mPositionMillis.get();
364 int64_t framesProcessed = millis64 * getSampleRate() / kMillisPerSecond;
365 return framesProcessed;
366 }
367
waitForStateChange(StreamState currentState,StreamState * nextState,int64_t timeoutNanoseconds)368 Result AudioStreamOpenSLES::waitForStateChange(StreamState currentState,
369 StreamState *nextState,
370 int64_t timeoutNanoseconds) {
371 Result oboeResult = Result::ErrorTimeout;
372 int64_t sleepTimeNanos = 20 * kNanosPerMillisecond; // arbitrary
373 int64_t timeLeftNanos = timeoutNanoseconds;
374
375 while (true) {
376 const StreamState state = getState(); // this does not require a lock
377 if (nextState != nullptr) {
378 *nextState = state;
379 }
380 if (currentState != state) { // state changed?
381 oboeResult = Result::OK;
382 break;
383 }
384
385 // Did we timeout or did user ask for non-blocking?
386 if (timeLeftNanos <= 0) {
387 break;
388 }
389
390 if (sleepTimeNanos > timeLeftNanos){
391 sleepTimeNanos = timeLeftNanos;
392 }
393 AudioClock::sleepForNanos(sleepTimeNanos);
394 timeLeftNanos -= sleepTimeNanos;
395 }
396
397 return oboeResult;
398 }
399