FreeRDP
Loading...
Searching...
No Matches
audin/client/opensles/opensl_io.c
1/*
2opensl_io.c:
3Android OpenSL input/output module
4Copyright (c) 2012, Victor Lazzarini
5All rights reserved.
6
7Redistribution and use in source and binary forms, with or without
8modification, are permitted provided that the following conditions are met:
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above copyright
12 notice, this list of conditions and the following disclaimer in the
13 documentation and/or other materials provided with the distribution.
14 * Neither the name of the <organization> nor the
15 names of its contributors may be used to endorse or promote products
16 derived from this software without specific prior written permission.
17
18THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
22DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28*/
29
30#include <winpr/assert.h>
31
32#include "audin_main.h"
33#include "opensl_io.h"
34#define CONV16BIT 32768
35#define CONVMYFLT (1. / 32768.)
36
37typedef struct
38{
39 size_t size;
40 void* data;
41} queue_element;
42
43struct opensl_stream
44{
45 // engine interfaces
46 SLObjectItf engineObject;
47 SLEngineItf engineEngine;
48
49 // device interfaces
50 SLDeviceVolumeItf deviceVolume;
51
52 // recorder interfaces
53 SLObjectItf recorderObject;
54 SLRecordItf recorderRecord;
55 SLAndroidSimpleBufferQueueItf recorderBufferQueue;
56
57 unsigned int inchannels;
58 unsigned int sr;
59 unsigned int buffersize;
60 unsigned int bits_per_sample;
61
62 queue_element* prep;
63 queue_element* next;
64
65 void* context;
66 opensl_receive_t receive;
67};
68
69static void bqRecorderCallback(SLAndroidSimpleBufferQueueItf bq, void* context);
70
71// creates the OpenSL ES audio engine
72static SLresult openSLCreateEngine(OPENSL_STREAM* p)
73{
74 SLresult result;
75 // create engine
76 result = slCreateEngine(&(p->engineObject), 0, nullptr, 0, nullptr, nullptr);
77
78 if (result != SL_RESULT_SUCCESS)
79 goto engine_end;
80
81 // realize the engine
82 result = (*p->engineObject)->Realize(p->engineObject, SL_BOOLEAN_FALSE);
83
84 if (result != SL_RESULT_SUCCESS)
85 goto engine_end;
86
87 // get the engine interface, which is needed in order to create other objects
88 result = (*p->engineObject)->GetInterface(p->engineObject, SL_IID_ENGINE, &(p->engineEngine));
89
90 if (result != SL_RESULT_SUCCESS)
91 goto engine_end;
92
93 // get the volume interface - important, this is optional!
94 result =
95 (*p->engineObject)->GetInterface(p->engineObject, SL_IID_DEVICEVOLUME, &(p->deviceVolume));
96
97 if (result != SL_RESULT_SUCCESS)
98 {
99 p->deviceVolume = nullptr;
100 result = SL_RESULT_SUCCESS;
101 }
102
103engine_end:
104 return result;
105}
106
107// Open the OpenSL ES device for input
108static SLresult openSLRecOpen(OPENSL_STREAM* p)
109{
110 SLresult result;
111 SLuint32 sr = p->sr;
112 SLuint32 channels = p->inchannels;
113 WINPR_ASSERT(!p->recorderObject);
114
115 if (channels)
116 {
117 switch (sr)
118 {
119 case 8000:
120 sr = SL_SAMPLINGRATE_8;
121 break;
122
123 case 11025:
124 sr = SL_SAMPLINGRATE_11_025;
125 break;
126
127 case 16000:
128 sr = SL_SAMPLINGRATE_16;
129 break;
130
131 case 22050:
132 sr = SL_SAMPLINGRATE_22_05;
133 break;
134
135 case 24000:
136 sr = SL_SAMPLINGRATE_24;
137 break;
138
139 case 32000:
140 sr = SL_SAMPLINGRATE_32;
141 break;
142
143 case 44100:
144 sr = SL_SAMPLINGRATE_44_1;
145 break;
146
147 case 48000:
148 sr = SL_SAMPLINGRATE_48;
149 break;
150
151 case 64000:
152 sr = SL_SAMPLINGRATE_64;
153 break;
154
155 case 88200:
156 sr = SL_SAMPLINGRATE_88_2;
157 break;
158
159 case 96000:
160 sr = SL_SAMPLINGRATE_96;
161 break;
162
163 case 192000:
164 sr = SL_SAMPLINGRATE_192;
165 break;
166
167 default:
168 WLog_ERR(TAG, "Sample rate %" PRIu32 " unsupported", sr);
169 return -1;
170 }
171
172 // configure audio source
173 SLDataLocator_IODevice loc_dev = { SL_DATALOCATOR_IODEVICE, SL_IODEVICE_AUDIOINPUT,
174 SL_DEFAULTDEVICEID_AUDIOINPUT, nullptr };
175 SLDataSource audioSrc = { &loc_dev, nullptr };
176 // configure audio sink
177 int speakers;
178
179 if (channels > 1)
180 speakers = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
181 else
182 speakers = SL_SPEAKER_FRONT_CENTER;
183
184 SLDataLocator_AndroidSimpleBufferQueue loc_bq = { SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE,
185 2 };
186 SLDataFormat_PCM format_pcm = WINPR_C_ARRAY_INIT;
187 format_pcm.formatType = SL_DATAFORMAT_PCM;
188 format_pcm.numChannels = channels;
189 format_pcm.samplesPerSec = sr;
190 format_pcm.channelMask = speakers;
191 format_pcm.endianness = SL_BYTEORDER_LITTLEENDIAN;
192
193 if (16 == p->bits_per_sample)
194 {
195 format_pcm.bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_16;
196 format_pcm.containerSize = 16;
197 }
198 else if (8 == p->bits_per_sample)
199 {
200 format_pcm.bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_8;
201 format_pcm.containerSize = 8;
202 }
203 else
204 {
205 WLog_ERR(TAG, "bits_per_sample=%" PRIu32, p->bits_per_sample);
206 return -1;
207 }
208
209 SLDataSink audioSnk = { &loc_bq, &format_pcm };
210 // create audio recorder
211 // (requires the RECORD_AUDIO permission)
212 const SLInterfaceID id[] = { SL_IID_ANDROIDSIMPLEBUFFERQUEUE };
213 const SLboolean req[] = { SL_BOOLEAN_TRUE };
214 result = (*p->engineEngine)
215 ->CreateAudioRecorder(p->engineEngine, &(p->recorderObject), &audioSrc,
216 &audioSnk, 1, id, req);
217 if (SL_RESULT_SUCCESS != result)
218 {
219 WLog_ERR(TAG, "CreateAudioRecorder failed with %d", result);
220 goto end_recopen;
221 }
222
223 // realize the audio recorder
224 result = (*p->recorderObject)->Realize(p->recorderObject, SL_BOOLEAN_FALSE);
225 if (SL_RESULT_SUCCESS != result)
226 {
227 WLog_ERR(TAG, "recorderObject failed with %d", result);
228 goto end_recopen;
229 }
230
231 // get the record interface
232 result = (*p->recorderObject)
233 ->GetInterface(p->recorderObject, SL_IID_RECORD, &(p->recorderRecord));
234 if (SL_RESULT_SUCCESS != result)
235 {
236 WLog_ERR(TAG, "GetInterface(SL_IID_RECORD) failed with %d", result);
237 goto end_recopen;
238 }
239
240 // get the buffer queue interface
241 result = (*p->recorderObject)
242 ->GetInterface(p->recorderObject, SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
243 &(p->recorderBufferQueue));
244 if (SL_RESULT_SUCCESS != result)
245 {
246 WLog_ERR(TAG, "GetInterface(SL_IID_ANDROIDSIMPLEBUFFERQUEUE) failed with %d", result);
247 goto end_recopen;
248 }
249
250 // register callback on the buffer queue
251 result = (*p->recorderBufferQueue)
252 ->RegisterCallback(p->recorderBufferQueue, bqRecorderCallback, p);
253 if (SL_RESULT_SUCCESS != result)
254 {
255 WLog_ERR(TAG, "RegisterCallback failed with %d", result);
256 goto end_recopen;
257 }
258
259 end_recopen:
260 return result;
261 }
262 else
263 return SL_RESULT_SUCCESS;
264}
265
266// close the OpenSL IO and destroy the audio engine
267static void openSLDestroyEngine(OPENSL_STREAM* p)
268{
269 // destroy audio recorder object, and invalidate all associated interfaces
270 if (p->recorderObject != nullptr)
271 {
272 (*p->recorderObject)->Destroy(p->recorderObject);
273 p->recorderObject = nullptr;
274 p->recorderRecord = nullptr;
275 p->recorderBufferQueue = nullptr;
276 }
277
278 // destroy engine object, and invalidate all associated interfaces
279 if (p->engineObject != nullptr)
280 {
281 (*p->engineObject)->Destroy(p->engineObject);
282 p->engineObject = nullptr;
283 p->engineEngine = nullptr;
284 }
285}
286
287static queue_element* opensles_queue_element_new(size_t size)
288{
289 queue_element* q = calloc(1, sizeof(queue_element));
290
291 if (!q)
292 goto fail;
293
294 q->size = size;
295 q->data = malloc(size);
296
297 if (!q->data)
298 goto fail;
299
300 return q;
301fail:
302 free(q);
303 return nullptr;
304}
305
306static void opensles_queue_element_free(void* obj)
307{
308 queue_element* e = (queue_element*)obj;
309
310 if (e)
311 free(e->data);
312
313 free(e);
314}
315
316// open the android audio device for input
317OPENSL_STREAM* android_OpenRecDevice(void* context, opensl_receive_t receive, int sr,
318 int inchannels, int bufferframes, int bits_per_sample)
319{
320 OPENSL_STREAM* p;
321
322 if (!context || !receive)
323 return nullptr;
324
325 p = (OPENSL_STREAM*)calloc(1, sizeof(OPENSL_STREAM));
326
327 if (!p)
328 return nullptr;
329
330 p->context = context;
331 p->receive = receive;
332 p->inchannels = inchannels;
333 p->sr = sr;
334 p->buffersize = bufferframes;
335 p->bits_per_sample = bits_per_sample;
336
337 if ((p->bits_per_sample != 8) && (p->bits_per_sample != 16))
338 goto fail;
339
340 if (openSLCreateEngine(p) != SL_RESULT_SUCCESS)
341 goto fail;
342
343 if (openSLRecOpen(p) != SL_RESULT_SUCCESS)
344 goto fail;
345
346 /* Create receive buffers, prepare them and start recording */
347 p->prep = opensles_queue_element_new(p->buffersize * p->bits_per_sample / 8);
348 p->next = opensles_queue_element_new(p->buffersize * p->bits_per_sample / 8);
349
350 if (!p->prep || !p->next)
351 goto fail;
352
353 (*p->recorderBufferQueue)->Enqueue(p->recorderBufferQueue, p->next->data, p->next->size);
354 (*p->recorderBufferQueue)->Enqueue(p->recorderBufferQueue, p->prep->data, p->prep->size);
355 (*p->recorderRecord)->SetRecordState(p->recorderRecord, SL_RECORDSTATE_RECORDING);
356 return p;
357fail:
358 android_CloseRecDevice(p);
359 return nullptr;
360}
361
362// close the android audio device
363void android_CloseRecDevice(OPENSL_STREAM* p)
364{
365 if (p == nullptr)
366 return;
367
368 opensles_queue_element_free(p->next);
369 opensles_queue_element_free(p->prep);
370 openSLDestroyEngine(p);
371 free(p);
372}
373
374// this callback handler is called every time a buffer finishes recording
375static void bqRecorderCallback(SLAndroidSimpleBufferQueueItf bq, void* context)
376{
377 OPENSL_STREAM* p = (OPENSL_STREAM*)context;
378 queue_element* e;
379
380 if (!p)
381 return;
382
383 e = p->next;
384
385 if (!e)
386 return;
387
388 if (!p->context || !p->receive)
389 WLog_WARN(TAG, "Missing receive callback=%p, context=%p", p->receive, p->context);
390 else
391 p->receive(p->context, e->data, e->size);
392
393 p->next = p->prep;
394 p->prep = e;
395 (*p->recorderBufferQueue)->Enqueue(p->recorderBufferQueue, e->data, e->size);
396}