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