1 /*
2 * Copyright 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <cassert>
18
19 #include <SLES/OpenSLES.h>
20 #include <SLES/OpenSLES_Android.h>
21 #include <common/AudioClock.h>
22
23 #include "common/OboeDebug.h"
24 #include "oboe/AudioStreamBuilder.h"
25 #include "AudioOutputStreamOpenSLES.h"
26 #include "AudioStreamOpenSLES.h"
27 #include "OpenSLESUtilities.h"
28 #include "OutputMixerOpenSLES.h"
29
30 using namespace oboe;
31
OpenSLES_convertOutputUsage(Usage oboeUsage)32 static SLuint32 OpenSLES_convertOutputUsage(Usage oboeUsage) {
33 SLuint32 openslStream;
34 switch(oboeUsage) {
35 case Usage::Media:
36 case Usage::Game:
37 openslStream = SL_ANDROID_STREAM_MEDIA;
38 break;
39 case Usage::VoiceCommunication:
40 case Usage::VoiceCommunicationSignalling:
41 openslStream = SL_ANDROID_STREAM_VOICE;
42 break;
43 case Usage::Alarm:
44 openslStream = SL_ANDROID_STREAM_ALARM;
45 break;
46 case Usage::Notification:
47 case Usage::NotificationEvent:
48 openslStream = SL_ANDROID_STREAM_NOTIFICATION;
49 break;
50 case Usage::NotificationRingtone:
51 openslStream = SL_ANDROID_STREAM_RING;
52 break;
53 case Usage::AssistanceAccessibility:
54 case Usage::AssistanceNavigationGuidance:
55 case Usage::AssistanceSonification:
56 case Usage::Assistant:
57 default:
58 openslStream = SL_ANDROID_STREAM_SYSTEM;
59 break;
60 }
61 return openslStream;
62 }
63
AudioOutputStreamOpenSLES(const AudioStreamBuilder & builder)64 AudioOutputStreamOpenSLES::AudioOutputStreamOpenSLES(const AudioStreamBuilder &builder)
65 : AudioStreamOpenSLES(builder) {
66 }
67
68 // These will wind up in <SLES/OpenSLES_Android.h>
69 constexpr int SL_ANDROID_SPEAKER_STEREO = (SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT);
70
71 constexpr int SL_ANDROID_SPEAKER_QUAD = (SL_ANDROID_SPEAKER_STEREO
72 | SL_SPEAKER_BACK_LEFT | SL_SPEAKER_BACK_RIGHT);
73
74 constexpr int SL_ANDROID_SPEAKER_5DOT1 = (SL_ANDROID_SPEAKER_QUAD
75 | SL_SPEAKER_FRONT_CENTER | SL_SPEAKER_LOW_FREQUENCY);
76
77 constexpr int SL_ANDROID_SPEAKER_7DOT1 = (SL_ANDROID_SPEAKER_5DOT1 | SL_SPEAKER_SIDE_LEFT
78 | SL_SPEAKER_SIDE_RIGHT);
79
channelCountToChannelMask(int channelCount) const80 SLuint32 AudioOutputStreamOpenSLES::channelCountToChannelMask(int channelCount) const {
81 SLuint32 channelMask = 0;
82
83 switch (channelCount) {
84 case 1:
85 channelMask = SL_SPEAKER_FRONT_CENTER;
86 break;
87
88 case 2:
89 channelMask = SL_ANDROID_SPEAKER_STEREO;
90 break;
91
92 case 4: // Quad
93 channelMask = SL_ANDROID_SPEAKER_QUAD;
94 break;
95
96 case 6: // 5.1
97 channelMask = SL_ANDROID_SPEAKER_5DOT1;
98 break;
99
100 case 8: // 7.1
101 channelMask = SL_ANDROID_SPEAKER_7DOT1;
102 break;
103
104 default:
105 channelMask = channelCountToChannelMaskDefault(channelCount);
106 break;
107 }
108 return channelMask;
109 }
110
open()111 Result AudioOutputStreamOpenSLES::open() {
112 logUnsupportedAttributes();
113
114 SLAndroidConfigurationItf configItf = nullptr;
115
116
117 if (getSdkVersion() < __ANDROID_API_L__ && mFormat == AudioFormat::Float){
118 // TODO: Allow floating point format on API <21 using float->int16 converter
119 return Result::ErrorInvalidFormat;
120 }
121
122 // If audio format is unspecified then choose a suitable default.
123 // API 21+: FLOAT
124 // API <21: INT16
125 if (mFormat == AudioFormat::Unspecified){
126 mFormat = (getSdkVersion() < __ANDROID_API_L__) ?
127 AudioFormat::I16 : AudioFormat::Float;
128 }
129
130 Result oboeResult = AudioStreamOpenSLES::open();
131 if (Result::OK != oboeResult) return oboeResult;
132
133 SLresult result = OutputMixerOpenSL::getInstance().open();
134 if (SL_RESULT_SUCCESS != result) {
135 AudioStreamOpenSLES::close();
136 return Result::ErrorInternal;
137 }
138
139 SLuint32 bitsPerSample = static_cast<SLuint32>(getBytesPerSample() * kBitsPerByte);
140
141 // configure audio source
142 mBufferQueueLength = calculateOptimalBufferQueueLength();
143 SLDataLocator_AndroidSimpleBufferQueue loc_bufq = {
144 SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, // locatorType
145 static_cast<SLuint32>(mBufferQueueLength)}; // numBuffers
146
147 // Define the audio data format.
148 SLDataFormat_PCM format_pcm = {
149 SL_DATAFORMAT_PCM, // formatType
150 static_cast<SLuint32>(mChannelCount), // numChannels
151 static_cast<SLuint32>(mSampleRate * kMillisPerSecond), // milliSamplesPerSec
152 bitsPerSample, // bitsPerSample
153 bitsPerSample, // containerSize;
154 channelCountToChannelMask(mChannelCount), // channelMask
155 getDefaultByteOrder(),
156 };
157
158 SLDataSource audioSrc = {&loc_bufq, &format_pcm};
159
160 /**
161 * API 21 (Lollipop) introduced support for floating-point data representation and an extended
162 * data format type: SLAndroidDataFormat_PCM_EX. If running on API 21+ use this newer format
163 * type, creating it from our original format.
164 */
165 SLAndroidDataFormat_PCM_EX format_pcm_ex;
166 if (getSdkVersion() >= __ANDROID_API_L__) {
167 SLuint32 representation = OpenSLES_ConvertFormatToRepresentation(getFormat());
168 // Fill in the format structure.
169 format_pcm_ex = OpenSLES_createExtendedFormat(format_pcm, representation);
170 // Use in place of the previous format.
171 audioSrc.pFormat = &format_pcm_ex;
172 }
173
174 result = OutputMixerOpenSL::getInstance().createAudioPlayer(&mObjectInterface,
175 &audioSrc);
176 if (SL_RESULT_SUCCESS != result) {
177 LOGE("createAudioPlayer() result:%s", getSLErrStr(result));
178 goto error;
179 }
180
181 // Configure the stream.
182 result = (*mObjectInterface)->GetInterface(mObjectInterface,
183 SL_IID_ANDROIDCONFIGURATION,
184 (void *)&configItf);
185 if (SL_RESULT_SUCCESS != result) {
186 LOGW("%s() GetInterface(SL_IID_ANDROIDCONFIGURATION) failed with %s",
187 __func__, getSLErrStr(result));
188 } else {
189 result = configurePerformanceMode(configItf);
190 if (SL_RESULT_SUCCESS != result) {
191 goto error;
192 }
193
194 SLuint32 presetValue = OpenSLES_convertOutputUsage(getUsage());
195 result = (*configItf)->SetConfiguration(configItf,
196 SL_ANDROID_KEY_STREAM_TYPE,
197 &presetValue,
198 sizeof(presetValue));
199 if (SL_RESULT_SUCCESS != result) {
200 goto error;
201 }
202 }
203
204 result = (*mObjectInterface)->Realize(mObjectInterface, SL_BOOLEAN_FALSE);
205 if (SL_RESULT_SUCCESS != result) {
206 LOGE("Realize player object result:%s", getSLErrStr(result));
207 goto error;
208 }
209
210 result = (*mObjectInterface)->GetInterface(mObjectInterface, SL_IID_PLAY, &mPlayInterface);
211 if (SL_RESULT_SUCCESS != result) {
212 LOGE("GetInterface PLAY result:%s", getSLErrStr(result));
213 goto error;
214 }
215
216 result = finishCommonOpen(configItf);
217 if (SL_RESULT_SUCCESS != result) {
218 goto error;
219 }
220
221 setState(StreamState::Open);
222 return Result::OK;
223
224 error:
225 close(); // Clean up various OpenSL objects and prevent resource leaks.
226 return Result::ErrorInternal; // TODO convert error from SLES to OBOE
227 }
228
onAfterDestroy()229 Result AudioOutputStreamOpenSLES::onAfterDestroy() {
230 OutputMixerOpenSL::getInstance().close();
231 return Result::OK;
232 }
233
close()234 Result AudioOutputStreamOpenSLES::close() {
235 LOGD("AudioOutputStreamOpenSLES::%s()", __func__);
236 std::lock_guard<std::mutex> lock(mLock);
237 Result result = Result::OK;
238 if (getState() == StreamState::Closed){
239 result = Result::ErrorClosed;
240 } else {
241 (void) requestPause_l();
242 if (OboeGlobals::areWorkaroundsEnabled()) {
243 sleepBeforeClose();
244 }
245 // invalidate any interfaces
246 mPlayInterface = nullptr;
247 result = AudioStreamOpenSLES::close_l();
248 }
249 return result;
250 }
251
setPlayState_l(SLuint32 newState)252 Result AudioOutputStreamOpenSLES::setPlayState_l(SLuint32 newState) {
253
254 LOGD("AudioOutputStreamOpenSLES(): %s() called", __func__);
255 Result result = Result::OK;
256
257 if (mPlayInterface == nullptr){
258 LOGE("AudioOutputStreamOpenSLES::%s() mPlayInterface is null", __func__);
259 return Result::ErrorInvalidState;
260 }
261
262 SLresult slResult = (*mPlayInterface)->SetPlayState(mPlayInterface, newState);
263 if (SL_RESULT_SUCCESS != slResult) {
264 LOGW("AudioOutputStreamOpenSLES(): %s() returned %s", __func__, getSLErrStr(slResult));
265 result = Result::ErrorInternal; // TODO convert slResult to Result::Error
266 }
267 return result;
268 }
269
requestStart()270 Result AudioOutputStreamOpenSLES::requestStart() {
271 LOGD("AudioOutputStreamOpenSLES(): %s() called", __func__);
272
273 mLock.lock();
274 StreamState initialState = getState();
275 switch (initialState) {
276 case StreamState::Starting:
277 case StreamState::Started:
278 mLock.unlock();
279 return Result::OK;
280 case StreamState::Closed:
281 mLock.unlock();
282 return Result::ErrorClosed;
283 default:
284 break;
285 }
286
287 // We use a callback if the user requests one
288 // OR if we have an internal callback to read the blocking IO buffer.
289 setDataCallbackEnabled(true);
290
291 setState(StreamState::Starting);
292 closePerformanceHint();
293
294 if (getBufferDepth(mSimpleBufferQueueInterface) == 0) {
295 // Enqueue the first buffer if needed to start the streaming.
296 // We may need to stop the current stream.
297 bool shouldStopStream = processBufferCallback(mSimpleBufferQueueInterface);
298 if (shouldStopStream) {
299 LOGD("Stopping the current stream.");
300 if (requestStop_l() != Result::OK) {
301 LOGW("Failed to flush the stream. Error %s", convertToText(flush()));
302 }
303 setState(initialState);
304 mLock.unlock();
305 return Result::ErrorClosed;
306 }
307 }
308
309 Result result = setPlayState_l(SL_PLAYSTATE_PLAYING);
310 if (result == Result::OK) {
311 setState(StreamState::Started);
312 mLock.unlock();
313 } else {
314 setState(initialState);
315 mLock.unlock();
316 }
317 return result;
318 }
319
requestPause()320 Result AudioOutputStreamOpenSLES::requestPause() {
321 LOGD("AudioOutputStreamOpenSLES(): %s() called", __func__);
322 std::lock_guard<std::mutex> lock(mLock);
323 return requestPause_l();
324 }
325
326 // Call under mLock
requestPause_l()327 Result AudioOutputStreamOpenSLES::requestPause_l() {
328 StreamState initialState = getState();
329 switch (initialState) {
330 case StreamState::Pausing:
331 case StreamState::Paused:
332 return Result::OK;
333 case StreamState::Uninitialized:
334 case StreamState::Closed:
335 return Result::ErrorClosed;
336 default:
337 break;
338 }
339
340 setState(StreamState::Pausing);
341 Result result = setPlayState_l(SL_PLAYSTATE_PAUSED);
342 if (result == Result::OK) {
343 // Note that OpenSL ES does NOT reset its millisecond position when OUTPUT is paused.
344 int64_t framesWritten = getFramesWritten();
345 if (framesWritten >= 0) {
346 setFramesRead(framesWritten);
347 }
348 setState(StreamState::Paused);
349 } else {
350 setState(initialState);
351 }
352 return result;
353 }
354
355 /**
356 * Flush/clear the queue buffers
357 */
requestFlush()358 Result AudioOutputStreamOpenSLES::requestFlush() {
359 std::lock_guard<std::mutex> lock(mLock);
360 return requestFlush_l();
361 }
362
requestFlush_l()363 Result AudioOutputStreamOpenSLES::requestFlush_l() {
364 LOGD("AudioOutputStreamOpenSLES(): %s() called", __func__);
365 if (getState() == StreamState::Closed) {
366 return Result::ErrorClosed;
367 }
368
369 Result result = Result::OK;
370 if (mPlayInterface == nullptr || mSimpleBufferQueueInterface == nullptr) {
371 result = Result::ErrorInvalidState;
372 } else {
373 SLresult slResult = (*mSimpleBufferQueueInterface)->Clear(mSimpleBufferQueueInterface);
374 if (slResult != SL_RESULT_SUCCESS){
375 LOGW("Failed to clear buffer queue. OpenSLES error: %s", getSLErrStr(slResult));
376 result = Result::ErrorInternal;
377 }
378 }
379 return result;
380 }
381
requestStop()382 Result AudioOutputStreamOpenSLES::requestStop() {
383 std::lock_guard<std::mutex> lock(mLock);
384 return requestStop_l();
385 }
386
requestStop_l()387 Result AudioOutputStreamOpenSLES::requestStop_l() {
388 LOGD("AudioOutputStreamOpenSLES(): %s() called", __func__);
389
390 StreamState initialState = getState();
391 switch (initialState) {
392 case StreamState::Stopping:
393 case StreamState::Stopped:
394 return Result::OK;
395 case StreamState::Uninitialized:
396 case StreamState::Closed:
397 return Result::ErrorClosed;
398 default:
399 break;
400 }
401
402 setState(StreamState::Stopping);
403
404 Result result = setPlayState_l(SL_PLAYSTATE_STOPPED);
405 if (result == Result::OK) {
406
407 // Also clear the buffer queue so the old data won't be played if the stream is restarted.
408 // Call the _l function that expects to already be under a lock.
409 if (requestFlush_l() != Result::OK) {
410 LOGW("Failed to flush the stream. Error %s", convertToText(flush()));
411 }
412
413 mPositionMillis.reset32(); // OpenSL ES resets its millisecond position when stopped.
414 int64_t framesWritten = getFramesWritten();
415 if (framesWritten >= 0) {
416 setFramesRead(framesWritten);
417 }
418 setState(StreamState::Stopped);
419 } else {
420 setState(initialState);
421 }
422 return result;
423 }
424
setFramesRead(int64_t framesRead)425 void AudioOutputStreamOpenSLES::setFramesRead(int64_t framesRead) {
426 int64_t millisWritten = framesRead * kMillisPerSecond / getSampleRate();
427 mPositionMillis.set(millisWritten);
428 }
429
updateFramesRead()430 void AudioOutputStreamOpenSLES::updateFramesRead() {
431 if (usingFIFO()) {
432 AudioStreamBuffered::updateFramesRead();
433 } else {
434 mFramesRead = getFramesProcessedByServer();
435 }
436 }
437
updateServiceFrameCounter()438 Result AudioOutputStreamOpenSLES::updateServiceFrameCounter() {
439 Result result = Result::OK;
440 // Avoid deadlock if another thread is trying to stop or close this stream
441 // and this is being called from a callback.
442 if (mLock.try_lock()) {
443
444 if (mPlayInterface == nullptr) {
445 mLock.unlock();
446 return Result::ErrorNull;
447 }
448 SLmillisecond msec = 0;
449 SLresult slResult = (*mPlayInterface)->GetPosition(mPlayInterface, &msec);
450 if (SL_RESULT_SUCCESS != slResult) {
451 LOGW("%s(): GetPosition() returned %s", __func__, getSLErrStr(slResult));
452 // set result based on SLresult
453 result = Result::ErrorInternal;
454 } else {
455 mPositionMillis.update32(msec);
456 }
457 mLock.unlock();
458 }
459 return result;
460 }
461