• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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