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