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