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, NULL, 0, NULL, NULL);
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 = NULL;
100 result = SL_RESULT_SUCCESS;
101 }
102
103engine_end:
104 WINPR_ASSERT(SL_RESULT_SUCCESS == result);
105 return result;
106}
107
108// Open the OpenSL ES device for input
109static SLresult openSLRecOpen(OPENSL_STREAM* p)
110{
111 SLresult result;
112 SLuint32 sr = p->sr;
113 SLuint32 channels = p->inchannels;
114 WINPR_ASSERT(!p->recorderObject);
115
116 if (channels)
117 {
118 switch (sr)
119 {
120 case 8000:
121 sr = SL_SAMPLINGRATE_8;
122 break;
123
124 case 11025:
125 sr = SL_SAMPLINGRATE_11_025;
126 break;
127
128 case 16000:
129 sr = SL_SAMPLINGRATE_16;
130 break;
131
132 case 22050:
133 sr = SL_SAMPLINGRATE_22_05;
134 break;
135
136 case 24000:
137 sr = SL_SAMPLINGRATE_24;
138 break;
139
140 case 32000:
141 sr = SL_SAMPLINGRATE_32;
142 break;
143
144 case 44100:
145 sr = SL_SAMPLINGRATE_44_1;
146 break;
147
148 case 48000:
149 sr = SL_SAMPLINGRATE_48;
150 break;
151
152 case 64000:
153 sr = SL_SAMPLINGRATE_64;
154 break;
155
156 case 88200:
157 sr = SL_SAMPLINGRATE_88_2;
158 break;
159
160 case 96000:
161 sr = SL_SAMPLINGRATE_96;
162 break;
163
164 case 192000:
165 sr = SL_SAMPLINGRATE_192;
166 break;
167
168 default:
169 return -1;
170 }
171
172 // configure audio source
173 SLDataLocator_IODevice loc_dev = { SL_DATALOCATOR_IODEVICE, SL_IODEVICE_AUDIOINPUT,
174 SL_DEFAULTDEVICEID_AUDIOINPUT, NULL };
175 SLDataSource audioSrc = { &loc_dev, NULL };
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;
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 WINPR_ASSERT(0);
205
206 SLDataSink audioSnk = { &loc_bq, &format_pcm };
207 // create audio recorder
208 // (requires the RECORD_AUDIO permission)
209 const SLInterfaceID id[] = { SL_IID_ANDROIDSIMPLEBUFFERQUEUE };
210 const SLboolean req[] = { SL_BOOLEAN_TRUE };
211 result = (*p->engineEngine)
212 ->CreateAudioRecorder(p->engineEngine, &(p->recorderObject), &audioSrc,
213 &audioSnk, 1, id, req);
214 WINPR_ASSERT(!result);
215
216 if (SL_RESULT_SUCCESS != result)
217 goto end_recopen;
218
219 // realize the audio recorder
220 result = (*p->recorderObject)->Realize(p->recorderObject, SL_BOOLEAN_FALSE);
221 WINPR_ASSERT(!result);
222
223 if (SL_RESULT_SUCCESS != result)
224 goto end_recopen;
225
226 // get the record interface
227 result = (*p->recorderObject)
228 ->GetInterface(p->recorderObject, SL_IID_RECORD, &(p->recorderRecord));
229 WINPR_ASSERT(!result);
230
231 if (SL_RESULT_SUCCESS != result)
232 goto end_recopen;
233
234 // get the buffer queue interface
235 result = (*p->recorderObject)
236 ->GetInterface(p->recorderObject, SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
237 &(p->recorderBufferQueue));
238 WINPR_ASSERT(!result);
239
240 if (SL_RESULT_SUCCESS != result)
241 goto end_recopen;
242
243 // register callback on the buffer queue
244 result = (*p->recorderBufferQueue)
245 ->RegisterCallback(p->recorderBufferQueue, bqRecorderCallback, p);
246 WINPR_ASSERT(!result);
247
248 if (SL_RESULT_SUCCESS != result)
249 goto end_recopen;
250
251 end_recopen:
252 return result;
253 }
254 else
255 return SL_RESULT_SUCCESS;
256}
257
258// close the OpenSL IO and destroy the audio engine
259static void openSLDestroyEngine(OPENSL_STREAM* p)
260{
261 // destroy audio recorder object, and invalidate all associated interfaces
262 if (p->recorderObject != NULL)
263 {
264 (*p->recorderObject)->Destroy(p->recorderObject);
265 p->recorderObject = NULL;
266 p->recorderRecord = NULL;
267 p->recorderBufferQueue = NULL;
268 }
269
270 // destroy engine object, and invalidate all associated interfaces
271 if (p->engineObject != NULL)
272 {
273 (*p->engineObject)->Destroy(p->engineObject);
274 p->engineObject = NULL;
275 p->engineEngine = NULL;
276 }
277}
278
279static queue_element* opensles_queue_element_new(size_t size)
280{
281 queue_element* q = calloc(1, sizeof(queue_element));
282
283 if (!q)
284 goto fail;
285
286 q->size = size;
287 q->data = malloc(size);
288
289 if (!q->data)
290 goto fail;
291
292 return q;
293fail:
294 free(q);
295 return NULL;
296}
297
298static void opensles_queue_element_free(void* obj)
299{
300 queue_element* e = (queue_element*)obj;
301
302 if (e)
303 free(e->data);
304
305 free(e);
306}
307
308// open the android audio device for input
309OPENSL_STREAM* android_OpenRecDevice(void* context, opensl_receive_t receive, int sr,
310 int inchannels, int bufferframes, int bits_per_sample)
311{
312 OPENSL_STREAM* p;
313
314 if (!context || !receive)
315 return NULL;
316
317 p = (OPENSL_STREAM*)calloc(1, sizeof(OPENSL_STREAM));
318
319 if (!p)
320 return NULL;
321
322 p->context = context;
323 p->receive = receive;
324 p->inchannels = inchannels;
325 p->sr = sr;
326 p->buffersize = bufferframes;
327 p->bits_per_sample = bits_per_sample;
328
329 if ((p->bits_per_sample != 8) && (p->bits_per_sample != 16))
330 goto fail;
331
332 if (openSLCreateEngine(p) != SL_RESULT_SUCCESS)
333 goto fail;
334
335 if (openSLRecOpen(p) != SL_RESULT_SUCCESS)
336 goto fail;
337
338 /* Create receive buffers, prepare them and start recording */
339 p->prep = opensles_queue_element_new(p->buffersize * p->bits_per_sample / 8);
340 p->next = opensles_queue_element_new(p->buffersize * p->bits_per_sample / 8);
341
342 if (!p->prep || !p->next)
343 goto fail;
344
345 (*p->recorderBufferQueue)->Enqueue(p->recorderBufferQueue, p->next->data, p->next->size);
346 (*p->recorderBufferQueue)->Enqueue(p->recorderBufferQueue, p->prep->data, p->prep->size);
347 (*p->recorderRecord)->SetRecordState(p->recorderRecord, SL_RECORDSTATE_RECORDING);
348 return p;
349fail:
350 android_CloseRecDevice(p);
351 return NULL;
352}
353
354// close the android audio device
355void android_CloseRecDevice(OPENSL_STREAM* p)
356{
357 if (p == NULL)
358 return;
359
360 opensles_queue_element_free(p->next);
361 opensles_queue_element_free(p->prep);
362 openSLDestroyEngine(p);
363 free(p);
364}
365
366// this callback handler is called every time a buffer finishes recording
367static void bqRecorderCallback(SLAndroidSimpleBufferQueueItf bq, void* context)
368{
369 OPENSL_STREAM* p = (OPENSL_STREAM*)context;
370 queue_element* e;
371
372 if (!p)
373 return;
374
375 e = p->next;
376
377 if (!e)
378 return;
379
380 if (!p->context || !p->receive)
381 WLog_WARN(TAG, "Missing receive callback=%p, context=%p", p->receive, p->context);
382 else
383 p->receive(p->context, e->data, e->size);
384
385 p->next = p->prep;
386 p->prep = e;
387 (*p->recorderBufferQueue)->Enqueue(p->recorderBufferQueue, e->data, e->size);
388}