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