xref: /aosp_15_r20/external/oboe/src/opensles/AudioInputStreamOpenSLES.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 
22 #include "common/OboeDebug.h"
23 #include "oboe/AudioStreamBuilder.h"
24 #include "AudioInputStreamOpenSLES.h"
25 #include "AudioStreamOpenSLES.h"
26 #include "OpenSLESUtilities.h"
27 
28 using namespace oboe;
29 
OpenSLES_convertInputPreset(InputPreset oboePreset)30 static SLuint32 OpenSLES_convertInputPreset(InputPreset oboePreset) {
31     SLuint32 openslPreset = SL_ANDROID_RECORDING_PRESET_NONE;
32     switch(oboePreset) {
33         case InputPreset::Generic:
34             openslPreset =  SL_ANDROID_RECORDING_PRESET_GENERIC;
35             break;
36         case InputPreset::Camcorder:
37             openslPreset =  SL_ANDROID_RECORDING_PRESET_CAMCORDER;
38             break;
39         case InputPreset::VoiceRecognition:
40         case InputPreset::VoicePerformance:
41             openslPreset =  SL_ANDROID_RECORDING_PRESET_VOICE_RECOGNITION;
42             break;
43         case InputPreset::VoiceCommunication:
44             openslPreset =  SL_ANDROID_RECORDING_PRESET_VOICE_COMMUNICATION;
45             break;
46         case InputPreset::Unprocessed:
47             openslPreset =  SL_ANDROID_RECORDING_PRESET_UNPROCESSED;
48             break;
49         default:
50             break;
51     }
52     return openslPreset;
53 }
54 
AudioInputStreamOpenSLES(const AudioStreamBuilder & builder)55 AudioInputStreamOpenSLES::AudioInputStreamOpenSLES(const AudioStreamBuilder &builder)
56         : AudioStreamOpenSLES(builder) {
57 }
58 
~AudioInputStreamOpenSLES()59 AudioInputStreamOpenSLES::~AudioInputStreamOpenSLES() {
60 }
61 
62 // Calculate masks specific to INPUT streams.
channelCountToChannelMask(int channelCount) const63 SLuint32 AudioInputStreamOpenSLES::channelCountToChannelMask(int channelCount) const {
64     // Derived from internal sles_channel_in_mask_from_count(chanCount);
65     // in "frameworks/wilhelm/src/android/channels.cpp".
66     // Yes, it seems strange to use SPEAKER constants to describe inputs.
67     // But that is how OpenSL ES does it internally.
68     switch (channelCount) {
69         case 1:
70             return SL_SPEAKER_FRONT_LEFT;
71         case 2:
72             return SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
73         default:
74             return channelCountToChannelMaskDefault(channelCount);
75     }
76 }
77 
open()78 Result AudioInputStreamOpenSLES::open() {
79     logUnsupportedAttributes();
80 
81     SLAndroidConfigurationItf configItf = nullptr;
82 
83     if (getSdkVersion() < __ANDROID_API_M__ && mFormat == AudioFormat::Float){
84         // TODO: Allow floating point format on API <23 using float->int16 converter
85         return Result::ErrorInvalidFormat;
86     }
87 
88     // If audio format is unspecified then choose a suitable default.
89     // API 23+: FLOAT
90     // API <23: INT16
91     if (mFormat == AudioFormat::Unspecified){
92         mFormat = (getSdkVersion() < __ANDROID_API_M__) ?
93                   AudioFormat::I16 : AudioFormat::Float;
94     }
95 
96     Result oboeResult = AudioStreamOpenSLES::open();
97     if (Result::OK != oboeResult) return oboeResult;
98 
99     SLuint32 bitsPerSample = static_cast<SLuint32>(getBytesPerSample() * kBitsPerByte);
100 
101     // configure audio sink
102     mBufferQueueLength = calculateOptimalBufferQueueLength();
103     SLDataLocator_AndroidSimpleBufferQueue loc_bufq = {
104             SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE,    // locatorType
105             static_cast<SLuint32>(mBufferQueueLength)};   // numBuffers
106 
107     // Define the audio data format.
108     SLDataFormat_PCM format_pcm = {
109             SL_DATAFORMAT_PCM,       // formatType
110             static_cast<SLuint32>(mChannelCount),           // numChannels
111             static_cast<SLuint32>(mSampleRate * kMillisPerSecond), // milliSamplesPerSec
112             bitsPerSample,                      // bitsPerSample
113             bitsPerSample,                      // containerSize;
114             channelCountToChannelMask(mChannelCount), // channelMask
115             getDefaultByteOrder(),
116     };
117 
118     SLDataSink audioSink = {&loc_bufq, &format_pcm};
119 
120     /**
121      * API 23 (Marshmallow) introduced support for floating-point data representation and an
122      * extended data format type: SLAndroidDataFormat_PCM_EX for recording streams (playback streams
123      * got this in API 21). If running on API 23+ use this newer format type, creating it from our
124      * original format.
125      */
126     SLAndroidDataFormat_PCM_EX format_pcm_ex;
127     if (getSdkVersion() >= __ANDROID_API_M__) {
128         SLuint32 representation = OpenSLES_ConvertFormatToRepresentation(getFormat());
129         // Fill in the format structure.
130         format_pcm_ex = OpenSLES_createExtendedFormat(format_pcm, representation);
131         // Use in place of the previous format.
132         audioSink.pFormat = &format_pcm_ex;
133     }
134 
135 
136     // configure audio source
137     SLDataLocator_IODevice loc_dev = {SL_DATALOCATOR_IODEVICE,
138                                       SL_IODEVICE_AUDIOINPUT,
139                                       SL_DEFAULTDEVICEID_AUDIOINPUT,
140                                       NULL};
141     SLDataSource audioSrc = {&loc_dev, NULL};
142 
143     SLresult result = EngineOpenSLES::getInstance().createAudioRecorder(&mObjectInterface,
144                                                                         &audioSrc,
145                                                                         &audioSink);
146 
147     if (SL_RESULT_SUCCESS != result) {
148         LOGE("createAudioRecorder() result:%s", getSLErrStr(result));
149         goto error;
150     }
151 
152     // Configure the stream.
153     result = (*mObjectInterface)->GetInterface(mObjectInterface,
154                                             SL_IID_ANDROIDCONFIGURATION,
155                                             &configItf);
156 
157     if (SL_RESULT_SUCCESS != result) {
158         LOGW("%s() GetInterface(SL_IID_ANDROIDCONFIGURATION) failed with %s",
159              __func__, getSLErrStr(result));
160     } else {
161         if (getInputPreset() == InputPreset::VoicePerformance) {
162             LOGD("OpenSL ES does not support InputPreset::VoicePerformance. Use VoiceRecognition.");
163             mInputPreset = InputPreset::VoiceRecognition;
164         }
165         SLuint32 presetValue = OpenSLES_convertInputPreset(getInputPreset());
166         result = (*configItf)->SetConfiguration(configItf,
167                                          SL_ANDROID_KEY_RECORDING_PRESET,
168                                          &presetValue,
169                                          sizeof(SLuint32));
170         if (SL_RESULT_SUCCESS != result
171                 && presetValue != SL_ANDROID_RECORDING_PRESET_VOICE_RECOGNITION) {
172             presetValue = SL_ANDROID_RECORDING_PRESET_VOICE_RECOGNITION;
173             LOGD("Setting InputPreset %d failed. Using VoiceRecognition instead.", getInputPreset());
174             mInputPreset = InputPreset::VoiceRecognition;
175             (*configItf)->SetConfiguration(configItf,
176                                              SL_ANDROID_KEY_RECORDING_PRESET,
177                                              &presetValue,
178                                              sizeof(SLuint32));
179         }
180 
181         result = configurePerformanceMode(configItf);
182         if (SL_RESULT_SUCCESS != result) {
183             goto error;
184         }
185     }
186 
187     result = (*mObjectInterface)->Realize(mObjectInterface, SL_BOOLEAN_FALSE);
188     if (SL_RESULT_SUCCESS != result) {
189         LOGE("Realize recorder object result:%s", getSLErrStr(result));
190         goto error;
191     }
192 
193     result = (*mObjectInterface)->GetInterface(mObjectInterface, SL_IID_RECORD, &mRecordInterface);
194     if (SL_RESULT_SUCCESS != result) {
195         LOGE("GetInterface RECORD result:%s", getSLErrStr(result));
196         goto error;
197     }
198 
199     result = finishCommonOpen(configItf);
200     if (SL_RESULT_SUCCESS != result) {
201         goto error;
202     }
203 
204     setState(StreamState::Open);
205     return Result::OK;
206 
207 error:
208     close(); // Clean up various OpenSL objects and prevent resource leaks.
209     return Result::ErrorInternal; // TODO convert error from SLES to OBOE
210 }
211 
close()212 Result AudioInputStreamOpenSLES::close() {
213     LOGD("AudioInputStreamOpenSLES::%s()", __func__);
214     std::lock_guard<std::mutex> lock(mLock);
215     Result result = Result::OK;
216     if (getState() == StreamState::Closed){
217         result = Result::ErrorClosed;
218     } else {
219         (void) requestStop_l();
220         if (OboeGlobals::areWorkaroundsEnabled()) {
221             sleepBeforeClose();
222         }
223         // invalidate any interfaces
224         mRecordInterface = nullptr;
225         result = AudioStreamOpenSLES::close_l();
226     }
227     return result;
228 }
229 
setRecordState_l(SLuint32 newState)230 Result AudioInputStreamOpenSLES::setRecordState_l(SLuint32 newState) {
231     LOGD("AudioInputStreamOpenSLES::%s(%u)", __func__, newState);
232     Result result = Result::OK;
233 
234     if (mRecordInterface == nullptr) {
235         LOGW("AudioInputStreamOpenSLES::%s() mRecordInterface is null", __func__);
236         return Result::ErrorInvalidState;
237     }
238     SLresult slResult = (*mRecordInterface)->SetRecordState(mRecordInterface, newState);
239     //LOGD("AudioInputStreamOpenSLES::%s(%u) returned %u", __func__, newState, slResult);
240     if (SL_RESULT_SUCCESS != slResult) {
241         LOGE("AudioInputStreamOpenSLES::%s(%u) returned error %s",
242                 __func__, newState, getSLErrStr(slResult));
243         result = Result::ErrorInternal; // TODO review
244     }
245     return result;
246 }
247 
requestStart()248 Result AudioInputStreamOpenSLES::requestStart() {
249     LOGD("AudioInputStreamOpenSLES(): %s() called", __func__);
250     std::lock_guard<std::mutex> lock(mLock);
251     StreamState initialState = getState();
252     switch (initialState) {
253         case StreamState::Starting:
254         case StreamState::Started:
255             return Result::OK;
256         case StreamState::Closed:
257             return Result::ErrorClosed;
258         default:
259             break;
260     }
261 
262     // We use a callback if the user requests one
263     // OR if we have an internal callback to fill the blocking IO buffer.
264     setDataCallbackEnabled(true);
265 
266     setState(StreamState::Starting);
267 
268     closePerformanceHint();
269 
270     if (getBufferDepth(mSimpleBufferQueueInterface) == 0) {
271         // Enqueue the first buffer to start the streaming.
272         // This does not call the callback function.
273         enqueueCallbackBuffer(mSimpleBufferQueueInterface);
274     }
275 
276     Result result = setRecordState_l(SL_RECORDSTATE_RECORDING);
277     if (result == Result::OK) {
278         setState(StreamState::Started);
279     } else {
280         setState(initialState);
281     }
282     return result;
283 }
284 
285 
requestPause()286 Result AudioInputStreamOpenSLES::requestPause() {
287     LOGW("AudioInputStreamOpenSLES::%s() is intentionally not implemented for input "
288          "streams", __func__);
289     return Result::ErrorUnimplemented; // Matches AAudio behavior.
290 }
291 
requestFlush()292 Result AudioInputStreamOpenSLES::requestFlush() {
293     LOGW("AudioInputStreamOpenSLES::%s() is intentionally not implemented for input "
294          "streams", __func__);
295     return Result::ErrorUnimplemented; // Matches AAudio behavior.
296 }
297 
requestStop()298 Result AudioInputStreamOpenSLES::requestStop() {
299     LOGD("AudioInputStreamOpenSLES(): %s() called", __func__);
300     std::lock_guard<std::mutex> lock(mLock);
301     return requestStop_l();
302 }
303 
304 // Call under mLock
requestStop_l()305 Result AudioInputStreamOpenSLES::requestStop_l() {
306     StreamState initialState = getState();
307     switch (initialState) {
308         case StreamState::Stopping:
309         case StreamState::Stopped:
310             return Result::OK;
311         case StreamState::Uninitialized:
312         case StreamState::Closed:
313             return Result::ErrorClosed;
314         default:
315             break;
316     }
317 
318     setState(StreamState::Stopping);
319 
320     Result result = setRecordState_l(SL_RECORDSTATE_STOPPED);
321     if (result == Result::OK) {
322         mPositionMillis.reset32(); // OpenSL ES resets its millisecond position when stopped.
323         setState(StreamState::Stopped);
324     } else {
325         setState(initialState);
326     }
327     return result;
328 }
329 
updateFramesWritten()330 void AudioInputStreamOpenSLES::updateFramesWritten() {
331     if (usingFIFO()) {
332         AudioStreamBuffered::updateFramesWritten();
333     } else {
334         mFramesWritten = getFramesProcessedByServer();
335     }
336 }
337 
updateServiceFrameCounter()338 Result AudioInputStreamOpenSLES::updateServiceFrameCounter() {
339     Result result = Result::OK;
340     // Avoid deadlock if another thread is trying to stop or close this stream
341     // and this is being called from a callback.
342     if (mLock.try_lock()) {
343 
344         if (mRecordInterface == nullptr) {
345             mLock.unlock();
346             return Result::ErrorNull;
347         }
348         SLmillisecond msec = 0;
349         SLresult slResult = (*mRecordInterface)->GetPosition(mRecordInterface, &msec);
350         if (SL_RESULT_SUCCESS != slResult) {
351             LOGW("%s(): GetPosition() returned %s", __func__, getSLErrStr(slResult));
352             // set result based on SLresult
353             result = Result::ErrorInternal;
354         } else {
355             mPositionMillis.update32(msec);
356         }
357         mLock.unlock();
358     }
359     return result;
360 }
361