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, nullptr, 0, nullptr, nullptr);
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, nullptr };
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 != nullptr)
247 {
248 (*p->bqPlayerObject)->Destroy(p->bqPlayerObject);
249 p->bqPlayerObject = nullptr;
250 p->bqPlayerVolume = nullptr;
251 p->bqPlayerPlay = nullptr;
252 p->bqPlayerBufferQueue = nullptr;
253 p->bqPlayerEffectSend = nullptr;
254 }
255
256 // destroy output mix object, and invalidate all associated interfaces
257 if (p->outputMixObject != nullptr)
258 {
259 (*p->outputMixObject)->Destroy(p->outputMixObject);
260 p->outputMixObject = nullptr;
261 }
262
263 // destroy engine object, and invalidate all associated interfaces
264 if (p->engineObject != nullptr)
265 {
266 (*p->engineObject)->Destroy(p->engineObject);
267 p->engineObject = nullptr;
268 p->engineEngine = nullptr;
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 nullptr;
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 nullptr;
289 }
290
291 if (openSLPlayOpen(p) != SL_RESULT_SUCCESS)
292 {
293 android_CloseAudioDevice(p);
294 return nullptr;
295 }
296
297 p->queue = Queue_New(TRUE, -1, -1);
298
299 if (!p->queue)
300 {
301 android_CloseAudioDevice(p);
302 return nullptr;
303 }
304
305 return p;
306}
307
308// close the android audio device
309void android_CloseAudioDevice(OPENSL_STREAM* p)
310{
311 if (p == nullptr)
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 WINPR_ASSERT(p);
336 WINPR_ASSERT(buffer);
337 WINPR_ASSERT(size > 0);
338
339 HANDLE ev = Queue_Event(p->queue);
340 /* Assure, that the queue is not full. */
341 if (p->queuesize <= Queue_Count(p->queue) && WaitForSingleObject(ev, INFINITE) == WAIT_FAILED)
342 {
343 DEBUG_SND("WaitForSingleObject failed!");
344 return -1;
345 }
346
347 void* data = calloc(size, sizeof(short));
348
349 if (!data)
350 {
351 DEBUG_SND("unable to allocate a buffer");
352 return -1;
353 }
354
355 memcpy(data, buffer, size * sizeof(short));
356 if (!Queue_Enqueue(p->queue, data))
357 {
358 free(data);
359 return -1;
360 }
361 (*p->bqPlayerBufferQueue)->Enqueue(p->bqPlayerBufferQueue, data, sizeof(short) * size);
362 return size;
363}
364
365int android_GetOutputMute(OPENSL_STREAM* p)
366{
367 SLboolean mute;
368 WINPR_ASSERT(p);
369 WINPR_ASSERT(p->bqPlayerVolume);
370 SLresult rc = (*p->bqPlayerVolume)->GetMute(p->bqPlayerVolume, &mute);
371
372 if (SL_RESULT_SUCCESS != rc)
373 return SL_BOOLEAN_FALSE;
374
375 return mute;
376}
377
378BOOL android_SetOutputMute(OPENSL_STREAM* p, BOOL _mute)
379{
380 SLboolean mute = _mute;
381 WINPR_ASSERT(p);
382 WINPR_ASSERT(p->bqPlayerVolume);
383 SLresult rc = (*p->bqPlayerVolume)->SetMute(p->bqPlayerVolume, mute);
384
385 if (SL_RESULT_SUCCESS != rc)
386 return FALSE;
387
388 return TRUE;
389}
390
391int android_GetOutputVolume(OPENSL_STREAM* p)
392{
393 SLmillibel level;
394 WINPR_ASSERT(p);
395 WINPR_ASSERT(p->bqPlayerVolume);
396 SLresult rc = (*p->bqPlayerVolume)->GetVolumeLevel(p->bqPlayerVolume, &level);
397
398 if (SL_RESULT_SUCCESS != rc)
399 return 0;
400
401 return level;
402}
403
404int android_GetOutputVolumeMax(OPENSL_STREAM* p)
405{
406 SLmillibel level;
407 WINPR_ASSERT(p);
408 WINPR_ASSERT(p->bqPlayerVolume);
409 SLresult rc = (*p->bqPlayerVolume)->GetMaxVolumeLevel(p->bqPlayerVolume, &level);
410
411 if (SL_RESULT_SUCCESS != rc)
412 return 0;
413
414 return level;
415}
416
417BOOL android_SetOutputVolume(OPENSL_STREAM* p, int level)
418{
419 SLresult rc = (*p->bqPlayerVolume)->SetVolumeLevel(p->bqPlayerVolume, level);
420
421 if (SL_RESULT_SUCCESS != rc)
422 return FALSE;
423
424 return TRUE;
425}