xref: /aosp_15_r20/external/oboe/src/opensles/AudioOutputStreamOpenSLES.cpp (revision 05767d913155b055644481607e6fa1e35e2fe72c)
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