FreeRDP
Loading...
Searching...
No Matches
rdpsnd/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 "rdpsnd_main.h"
33#include "opensl_io.h"
34#define CONV16BIT 32768
35#define CONVMYFLT (1. / 32768.)
36
37static void bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void* context);
38
39// creates the OpenSL ES audio engine
40static SLresult openSLCreateEngine(OPENSL_STREAM* p)
41{
42 SLresult result;
43 // create engine
44 result = slCreateEngine(&(p->engineObject), 0, NULL, 0, NULL, NULL);
45 DEBUG_SND("engineObject=%p", (void*)p->engineObject);
46
47 if (result != SL_RESULT_SUCCESS)
48 goto engine_end;
49
50 // realize the engine
51 result = (*p->engineObject)->Realize(p->engineObject, SL_BOOLEAN_FALSE);
52 DEBUG_SND("Realize=%" PRIu32 "", result);
53
54 if (result != SL_RESULT_SUCCESS)
55 goto engine_end;
56
57 // get the engine interface, which is needed in order to create other objects
58 result = (*p->engineObject)->GetInterface(p->engineObject, SL_IID_ENGINE, &(p->engineEngine));
59 DEBUG_SND("engineEngine=%p", (void*)p->engineEngine);
60
61 if (result != SL_RESULT_SUCCESS)
62 goto engine_end;
63
64engine_end:
65 return result;
66}
67
68// opens the OpenSL ES device for output
69static SLresult openSLPlayOpen(OPENSL_STREAM* p)
70{
71 SLresult result;
72 SLuint32 sr = p->sr;
73 SLuint32 channels = p->outchannels;
74 WINPR_ASSERT(p->engineObject);
75 WINPR_ASSERT(p->engineEngine);
76
77 if (channels)
78 {
79 // configure audio source
80 SLDataLocator_AndroidSimpleBufferQueue loc_bufq = { SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE,
81 p->queuesize };
82
83 switch (sr)
84 {
85 case 8000:
86 sr = SL_SAMPLINGRATE_8;
87 break;
88
89 case 11025:
90 sr = SL_SAMPLINGRATE_11_025;
91 break;
92
93 case 16000:
94 sr = SL_SAMPLINGRATE_16;
95 break;
96
97 case 22050:
98 sr = SL_SAMPLINGRATE_22_05;
99 break;
100
101 case 24000:
102 sr = SL_SAMPLINGRATE_24;
103 break;
104
105 case 32000:
106 sr = SL_SAMPLINGRATE_32;
107 break;
108
109 case 44100:
110 sr = SL_SAMPLINGRATE_44_1;
111 break;
112
113 case 48000:
114 sr = SL_SAMPLINGRATE_48;
115 break;
116
117 case 64000:
118 sr = SL_SAMPLINGRATE_64;
119 break;
120
121 case 88200:
122 sr = SL_SAMPLINGRATE_88_2;
123 break;
124
125 case 96000:
126 sr = SL_SAMPLINGRATE_96;
127 break;
128
129 case 192000:
130 sr = SL_SAMPLINGRATE_192;
131 break;
132
133 default:
134 return -1;
135 }
136
137 const SLInterfaceID ids[] = { SL_IID_VOLUME };
138 const SLboolean req[] = { SL_BOOLEAN_FALSE };
139 result = (*p->engineEngine)
140 ->CreateOutputMix(p->engineEngine, &(p->outputMixObject), 1, ids, req);
141 DEBUG_SND("engineEngine=%p", (void*)p->engineEngine);
142 WINPR_ASSERT(!result);
143
144 if (result != SL_RESULT_SUCCESS)
145 goto end_openaudio;
146
147 // realize the output mix
148 result = (*p->outputMixObject)->Realize(p->outputMixObject, SL_BOOLEAN_FALSE);
149 DEBUG_SND("Realize=%" PRIu32 "", result);
150 WINPR_ASSERT(!result);
151
152 if (result != SL_RESULT_SUCCESS)
153 goto end_openaudio;
154
155 int speakers;
156
157 if (channels > 1)
158 speakers = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
159 else
160 speakers = SL_SPEAKER_FRONT_CENTER;
161
162 SLDataFormat_PCM format_pcm = { SL_DATAFORMAT_PCM,
163 channels,
164 sr,
165 SL_PCMSAMPLEFORMAT_FIXED_16,
166 SL_PCMSAMPLEFORMAT_FIXED_16,
167 speakers,
168 SL_BYTEORDER_LITTLEENDIAN };
169 SLDataSource audioSrc = { &loc_bufq, &format_pcm };
170 // configure audio sink
171 SLDataLocator_OutputMix loc_outmix = { SL_DATALOCATOR_OUTPUTMIX, p->outputMixObject };
172 SLDataSink audioSnk = { &loc_outmix, NULL };
173 // create audio player
174 const SLInterfaceID ids1[] = { SL_IID_ANDROIDSIMPLEBUFFERQUEUE, SL_IID_VOLUME };
175 const SLboolean req1[] = { SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE };
176 result = (*p->engineEngine)
177 ->CreateAudioPlayer(p->engineEngine, &(p->bqPlayerObject), &audioSrc,
178 &audioSnk, 2, ids1, req1);
179 DEBUG_SND("bqPlayerObject=%p", (void*)p->bqPlayerObject);
180 WINPR_ASSERT(!result);
181
182 if (result != SL_RESULT_SUCCESS)
183 goto end_openaudio;
184
185 // realize the player
186 result = (*p->bqPlayerObject)->Realize(p->bqPlayerObject, SL_BOOLEAN_FALSE);
187 DEBUG_SND("Realize=%" PRIu32 "", result);
188 WINPR_ASSERT(!result);
189
190 if (result != SL_RESULT_SUCCESS)
191 goto end_openaudio;
192
193 // get the play interface
194 result =
195 (*p->bqPlayerObject)->GetInterface(p->bqPlayerObject, SL_IID_PLAY, &(p->bqPlayerPlay));
196 DEBUG_SND("bqPlayerPlay=%p", (void*)p->bqPlayerPlay);
197 WINPR_ASSERT(!result);
198
199 if (result != SL_RESULT_SUCCESS)
200 goto end_openaudio;
201
202 // get the volume interface
203 result = (*p->bqPlayerObject)
204 ->GetInterface(p->bqPlayerObject, SL_IID_VOLUME, &(p->bqPlayerVolume));
205 DEBUG_SND("bqPlayerVolume=%p", (void*)p->bqPlayerVolume);
206 WINPR_ASSERT(!result);
207
208 if (result != SL_RESULT_SUCCESS)
209 goto end_openaudio;
210
211 // get the buffer queue interface
212 result = (*p->bqPlayerObject)
213 ->GetInterface(p->bqPlayerObject, SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
214 &(p->bqPlayerBufferQueue));
215 DEBUG_SND("bqPlayerBufferQueue=%p", (void*)p->bqPlayerBufferQueue);
216 WINPR_ASSERT(!result);
217
218 if (result != SL_RESULT_SUCCESS)
219 goto end_openaudio;
220
221 // register callback on the buffer queue
222 result = (*p->bqPlayerBufferQueue)
223 ->RegisterCallback(p->bqPlayerBufferQueue, bqPlayerCallback, p);
224 DEBUG_SND("bqPlayerCallback=%p", (void*)p->bqPlayerCallback);
225 WINPR_ASSERT(!result);
226
227 if (result != SL_RESULT_SUCCESS)
228 goto end_openaudio;
229
230 // set the player's state to playing
231 result = (*p->bqPlayerPlay)->SetPlayState(p->bqPlayerPlay, SL_PLAYSTATE_PLAYING);
232 DEBUG_SND("SetPlayState=%" PRIu32 "", result);
233 WINPR_ASSERT(!result);
234 end_openaudio:
235 WINPR_ASSERT(!result);
236 return result;
237 }
238
239 return SL_RESULT_SUCCESS;
240}
241
242// close the OpenSL IO and destroy the audio engine
243static void openSLDestroyEngine(OPENSL_STREAM* p)
244{
245 // destroy buffer queue audio player object, and invalidate all associated interfaces
246 if (p->bqPlayerObject != NULL)
247 {
248 (*p->bqPlayerObject)->Destroy(p->bqPlayerObject);
249 p->bqPlayerObject = NULL;
250 p->bqPlayerVolume = NULL;
251 p->bqPlayerPlay = NULL;
252 p->bqPlayerBufferQueue = NULL;
253 p->bqPlayerEffectSend = NULL;
254 }
255
256 // destroy output mix object, and invalidate all associated interfaces
257 if (p->outputMixObject != NULL)
258 {
259 (*p->outputMixObject)->Destroy(p->outputMixObject);
260 p->outputMixObject = NULL;
261 }
262
263 // destroy engine object, and invalidate all associated interfaces
264 if (p->engineObject != NULL)
265 {
266 (*p->engineObject)->Destroy(p->engineObject);
267 p->engineObject = NULL;
268 p->engineEngine = NULL;
269 }
270}
271
272// open the android audio device for and/or output
273OPENSL_STREAM* android_OpenAudioDevice(int sr, int outchannels, int bufferframes)
274{
275 OPENSL_STREAM* p;
276 p = (OPENSL_STREAM*)calloc(1, sizeof(OPENSL_STREAM));
277
278 if (!p)
279 return NULL;
280
281 p->queuesize = bufferframes;
282 p->outchannels = outchannels;
283 p->sr = sr;
284
285 if (openSLCreateEngine(p) != SL_RESULT_SUCCESS)
286 {
287 android_CloseAudioDevice(p);
288 return NULL;
289 }
290
291 if (openSLPlayOpen(p) != SL_RESULT_SUCCESS)
292 {
293 android_CloseAudioDevice(p);
294 return NULL;
295 }
296
297 p->queue = Queue_New(TRUE, -1, -1);
298
299 if (!p->queue)
300 {
301 android_CloseAudioDevice(p);
302 return NULL;
303 }
304
305 return p;
306}
307
308// close the android audio device
309void android_CloseAudioDevice(OPENSL_STREAM* p)
310{
311 if (p == NULL)
312 return;
313
314 openSLDestroyEngine(p);
315
316 if (p->queue)
317 Queue_Free(p->queue);
318
319 free(p);
320}
321
322// this callback handler is called every time a buffer finishes playing
323static void bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void* context)
324{
325 OPENSL_STREAM* p = (OPENSL_STREAM*)context;
326 WINPR_ASSERT(p);
327 WINPR_ASSERT(p->queue);
328 void* data = Queue_Dequeue(p->queue);
329 free(data);
330}
331
332// puts a buffer of size samples to the device
333int android_AudioOut(OPENSL_STREAM* p, const short* buffer, int size)
334{
335 HANDLE ev;
336 WINPR_ASSERT(p);
337 WINPR_ASSERT(buffer);
338 WINPR_ASSERT(size > 0);
339
340 ev = Queue_Event(p->queue);
341 /* Assure, that the queue is not full. */
342 if (p->queuesize <= Queue_Count(p->queue) && WaitForSingleObject(ev, INFINITE) == WAIT_FAILED)
343 {
344 DEBUG_SND("WaitForSingleObject failed!");
345 return -1;
346 }
347
348 void* data = calloc(size, sizeof(short));
349
350 if (!data)
351 {
352 DEBUG_SND("unable to allocate a buffer");
353 return -1;
354 }
355
356 memcpy(data, buffer, size * sizeof(short));
357 Queue_Enqueue(p->queue, data);
358 (*p->bqPlayerBufferQueue)->Enqueue(p->bqPlayerBufferQueue, data, sizeof(short) * size);
359 return size;
360}
361
362int android_GetOutputMute(OPENSL_STREAM* p)
363{
364 SLboolean mute;
365 WINPR_ASSERT(p);
366 WINPR_ASSERT(p->bqPlayerVolume);
367 SLresult rc = (*p->bqPlayerVolume)->GetMute(p->bqPlayerVolume, &mute);
368
369 if (SL_RESULT_SUCCESS != rc)
370 return SL_BOOLEAN_FALSE;
371
372 return mute;
373}
374
375BOOL android_SetOutputMute(OPENSL_STREAM* p, BOOL _mute)
376{
377 SLboolean mute = _mute;
378 WINPR_ASSERT(p);
379 WINPR_ASSERT(p->bqPlayerVolume);
380 SLresult rc = (*p->bqPlayerVolume)->SetMute(p->bqPlayerVolume, mute);
381
382 if (SL_RESULT_SUCCESS != rc)
383 return FALSE;
384
385 return TRUE;
386}
387
388int android_GetOutputVolume(OPENSL_STREAM* p)
389{
390 SLmillibel level;
391 WINPR_ASSERT(p);
392 WINPR_ASSERT(p->bqPlayerVolume);
393 SLresult rc = (*p->bqPlayerVolume)->GetVolumeLevel(p->bqPlayerVolume, &level);
394
395 if (SL_RESULT_SUCCESS != rc)
396 return 0;
397
398 return level;
399}
400
401int android_GetOutputVolumeMax(OPENSL_STREAM* p)
402{
403 SLmillibel level;
404 WINPR_ASSERT(p);
405 WINPR_ASSERT(p->bqPlayerVolume);
406 SLresult rc = (*p->bqPlayerVolume)->GetMaxVolumeLevel(p->bqPlayerVolume, &level);
407
408 if (SL_RESULT_SUCCESS != rc)
409 return 0;
410
411 return level;
412}
413
414BOOL android_SetOutputVolume(OPENSL_STREAM* p, int level)
415{
416 SLresult rc = (*p->bqPlayerVolume)->SetVolumeLevel(p->bqPlayerVolume, level);
417
418 if (SL_RESULT_SUCCESS != rc)
419 return FALSE;
420
421 return TRUE;
422}