1 /* FluidSynth - A Software Synthesizer
2 *
3 * Copyright (C) 2003 Peter Hanappe and others.
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public License
7 * as published by the Free Software Foundation; either version 2 of
8 * the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the Free
17 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 * 02110-1301, USA
19 */
20
21 /* fluid_opensles.c
22 *
23 * Audio driver for OpenSLES.
24 *
25 */
26
27 #include "fluid_adriver.h"
28
29 #if OPENSLES_SUPPORT
30
31 #include <SLES/OpenSLES.h>
32 #include <SLES/OpenSLES_Android.h>
33
34 static const int NUM_CHANNELS = 2;
35
36 /** fluid_opensles_audio_driver_t
37 *
38 * This structure should not be accessed directly. Use audio port
39 * functions instead.
40 */
41 typedef struct
42 {
43 fluid_audio_driver_t driver;
44 SLObjectItf engine;
45 SLObjectItf output_mix_object;
46 SLObjectItf audio_player;
47 SLPlayItf audio_player_interface;
48 SLAndroidSimpleBufferQueueItf player_buffer_queue_interface;
49
50 void *synth;
51 int period_frames;
52
53 int is_sample_format_float;
54
55 /* used only by callback mode */
56 short *sles_buffer_short;
57 float *sles_buffer_float;
58
59 int cont;
60
61 double sample_rate;
62 } fluid_opensles_audio_driver_t;
63
64
65 static void opensles_callback(SLAndroidSimpleBufferQueueItf caller, void *pContext);
66 static void process_fluid_buffer(fluid_opensles_audio_driver_t *dev);
67
fluid_opensles_audio_driver_settings(fluid_settings_t * settings)68 void fluid_opensles_audio_driver_settings(fluid_settings_t *settings)
69 {
70 }
71
72
73 /*
74 * new_fluid_opensles_audio_driver
75 */
76 fluid_audio_driver_t *
new_fluid_opensles_audio_driver(fluid_settings_t * settings,fluid_synth_t * synth)77 new_fluid_opensles_audio_driver(fluid_settings_t *settings, fluid_synth_t *synth)
78 {
79 SLresult result;
80 fluid_opensles_audio_driver_t *dev;
81 double sample_rate;
82 int period_size;
83 int realtime_prio = 0;
84 int is_sample_format_float;
85 SLEngineItf engine_interface;
86
87 dev = FLUID_NEW(fluid_opensles_audio_driver_t);
88
89 if(dev == NULL)
90 {
91 FLUID_LOG(FLUID_ERR, "Out of memory");
92 return NULL;
93 }
94
95 FLUID_MEMSET(dev, 0, sizeof(*dev));
96
97 fluid_settings_getint(settings, "audio.period-size", &period_size);
98 fluid_settings_getnum(settings, "synth.sample-rate", &sample_rate);
99 fluid_settings_getint(settings, "audio.realtime-prio", &realtime_prio);
100 is_sample_format_float = fluid_settings_str_equal(settings, "audio.sample-format", "float");
101
102 dev->synth = synth;
103 dev->is_sample_format_float = is_sample_format_float;
104 dev->period_frames = period_size;
105 dev->sample_rate = sample_rate;
106 dev->cont = 1;
107
108 result = slCreateEngine(&(dev->engine), 0, NULL, 0, NULL, NULL);
109
110 if(!dev->engine)
111 {
112 FLUID_LOG(FLUID_ERR, "Failed to create the OpenSL ES engine, error code 0x%lx", (unsigned long)result);
113 goto error_recovery;
114 }
115
116 result = (*dev->engine)->Realize(dev->engine, SL_BOOLEAN_FALSE);
117
118 if(result != SL_RESULT_SUCCESS)
119 {
120 FLUID_LOG(FLUID_ERR, "Failed to realize the OpenSL ES engine, error code 0x%lx", (unsigned long)result);
121 goto error_recovery;
122 }
123
124 result = (*dev->engine)->GetInterface(dev->engine, SL_IID_ENGINE, &engine_interface);
125
126 if(result != SL_RESULT_SUCCESS)
127 {
128 FLUID_LOG(FLUID_ERR, "Failed to retrieve the OpenSL ES engine interface, error code 0x%lx", (unsigned long)result);
129 goto error_recovery;
130 }
131
132 result = (*engine_interface)->CreateOutputMix(engine_interface, &dev->output_mix_object, 0, 0, 0);
133
134 if(result != SL_RESULT_SUCCESS)
135 {
136 FLUID_LOG(FLUID_ERR, "Failed to create the OpenSL ES output mix object, error code 0x%lx", (unsigned long)result);
137 goto error_recovery;
138 }
139
140 result = (*dev->output_mix_object)->Realize(dev->output_mix_object, SL_BOOLEAN_FALSE);
141
142 if(result != SL_RESULT_SUCCESS)
143 {
144 FLUID_LOG(FLUID_ERR, "Failed to realize the OpenSL ES output mix object, error code 0x%lx", (unsigned long)result);
145 goto error_recovery;
146 }
147
148 {
149 SLDataLocator_AndroidSimpleBufferQueue loc_buffer_queue =
150 {
151 SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE,
152 2 /* number of buffers */
153 };
154 SLAndroidDataFormat_PCM_EX format_pcm =
155 {
156 SL_ANDROID_DATAFORMAT_PCM_EX,
157 NUM_CHANNELS,
158 ((SLuint32) sample_rate) * 1000,
159 is_sample_format_float ? SL_PCMSAMPLEFORMAT_FIXED_32 : SL_PCMSAMPLEFORMAT_FIXED_16,
160 is_sample_format_float ? SL_PCMSAMPLEFORMAT_FIXED_32 : SL_PCMSAMPLEFORMAT_FIXED_16,
161 SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT,
162 SL_BYTEORDER_LITTLEENDIAN,
163 is_sample_format_float ? SL_ANDROID_PCM_REPRESENTATION_FLOAT : SL_ANDROID_PCM_REPRESENTATION_SIGNED_INT
164 };
165 SLDataSource audio_src =
166 {
167 &loc_buffer_queue,
168 &format_pcm
169 };
170
171 SLDataLocator_OutputMix loc_outmix =
172 {
173 SL_DATALOCATOR_OUTPUTMIX,
174 dev->output_mix_object
175 };
176 SLDataSink audio_sink = {&loc_outmix, NULL};
177
178 const SLInterfaceID ids1[] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE};
179 const SLboolean req1[] = {SL_BOOLEAN_TRUE};
180 result = (*engine_interface)->CreateAudioPlayer(engine_interface,
181 &(dev->audio_player), &audio_src, &audio_sink, 1, ids1, req1);
182 }
183
184 if(result != SL_RESULT_SUCCESS)
185 {
186 FLUID_LOG(FLUID_ERR, "Failed to create the OpenSL ES audio player object, error code 0x%lx", (unsigned long)result);
187 goto error_recovery;
188 }
189
190 result = (*dev->audio_player)->Realize(dev->audio_player, SL_BOOLEAN_FALSE);
191
192 if(result != SL_RESULT_SUCCESS)
193 {
194 FLUID_LOG(FLUID_ERR, "Failed to realize the OpenSL ES audio player object, error code 0x%lx", (unsigned long)result);
195 goto error_recovery;
196 }
197
198 result = (*dev->audio_player)->GetInterface(dev->audio_player,
199 SL_IID_PLAY, &(dev->audio_player_interface));
200
201 if(result != SL_RESULT_SUCCESS)
202 {
203 FLUID_LOG(FLUID_ERR, "Failed to retrieve the OpenSL ES audio player interface, error code 0x%lx", (unsigned long)result);
204 goto error_recovery;
205 }
206
207 result = (*dev->audio_player)->GetInterface(dev->audio_player,
208 SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &(dev->player_buffer_queue_interface));
209
210 if(result != SL_RESULT_SUCCESS)
211 {
212 FLUID_LOG(FLUID_ERR, "Failed to retrieve the OpenSL ES buffer queue interface, error code 0x%lx", (unsigned long)result);
213 goto error_recovery;
214 }
215
216 if(dev->is_sample_format_float)
217 {
218 dev->sles_buffer_float = FLUID_ARRAY(float, dev->period_frames * NUM_CHANNELS);
219 }
220 else
221 {
222 dev->sles_buffer_short = FLUID_ARRAY(short, dev->period_frames * NUM_CHANNELS);
223 }
224
225 if(dev->sles_buffer_float == NULL && dev->sles_buffer_short == NULL)
226 {
227 FLUID_LOG(FLUID_ERR, "Out of memory.");
228 goto error_recovery;
229 }
230
231 result = (*dev->player_buffer_queue_interface)->RegisterCallback(dev->player_buffer_queue_interface, opensles_callback, dev);
232
233 if(result != SL_RESULT_SUCCESS)
234 {
235 FLUID_LOG(FLUID_ERR, "Failed to register the opensles_callback, error code 0x%lx", (unsigned long)result);
236 goto error_recovery;
237 }
238
239 if(dev->is_sample_format_float)
240 {
241 result = (*dev->player_buffer_queue_interface)->Enqueue(dev->player_buffer_queue_interface, dev->sles_buffer_float, dev->period_frames * NUM_CHANNELS * sizeof(float));
242 }
243 else
244 {
245 result = (*dev->player_buffer_queue_interface)->Enqueue(dev->player_buffer_queue_interface, dev->sles_buffer_short, dev->period_frames * NUM_CHANNELS * sizeof(short));
246 }
247
248 if(result != SL_RESULT_SUCCESS)
249 {
250 FLUID_LOG(FLUID_ERR, "Failed to add a buffer to the queue, error code 0x%lx", (unsigned long)result);
251 goto error_recovery;
252 }
253
254 result = (*dev->audio_player_interface)->SetCallbackEventsMask(dev->audio_player_interface, SL_PLAYEVENT_HEADATEND);
255
256 if(result != SL_RESULT_SUCCESS)
257 {
258 FLUID_LOG(FLUID_ERR, "Failed to set OpenSL ES audio player callback events, error code 0x%lx", (unsigned long)result);
259 goto error_recovery;
260 }
261
262 result = (*dev->audio_player_interface)->SetPlayState(dev->audio_player_interface, SL_PLAYSTATE_PLAYING);
263
264 if(result != SL_RESULT_SUCCESS)
265 {
266 FLUID_LOG(FLUID_ERR, "Failed to set OpenSL ES audio player play state to playing, error code 0x%lx", (unsigned long)result);
267 goto error_recovery;
268 }
269
270 FLUID_LOG(FLUID_INFO, "Using OpenSLES driver.");
271
272 return (fluid_audio_driver_t *) dev;
273
274 error_recovery:
275
276 delete_fluid_opensles_audio_driver((fluid_audio_driver_t *) dev);
277 return NULL;
278 }
279
delete_fluid_opensles_audio_driver(fluid_audio_driver_t * p)280 void delete_fluid_opensles_audio_driver(fluid_audio_driver_t *p)
281 {
282 fluid_opensles_audio_driver_t *dev = (fluid_opensles_audio_driver_t *) p;
283
284 fluid_return_if_fail(dev != NULL);
285
286 dev->cont = 0;
287
288 if(dev->audio_player)
289 {
290 (*dev->audio_player)->Destroy(dev->audio_player);
291 }
292
293 if(dev->output_mix_object)
294 {
295 (*dev->output_mix_object)->Destroy(dev->output_mix_object);
296 }
297
298 if(dev->engine)
299 {
300 (*dev->engine)->Destroy(dev->engine);
301 }
302
303 if(dev->sles_buffer_float)
304 {
305 FLUID_FREE(dev->sles_buffer_float);
306 }
307
308 if(dev->sles_buffer_short)
309 {
310 FLUID_FREE(dev->sles_buffer_short);
311 }
312
313 FLUID_FREE(dev);
314 }
315
opensles_callback(SLAndroidSimpleBufferQueueItf caller,void * pContext)316 void opensles_callback(SLAndroidSimpleBufferQueueItf caller, void *pContext)
317 {
318 fluid_opensles_audio_driver_t *dev = (fluid_opensles_audio_driver_t *) pContext;
319 SLresult result;
320
321 process_fluid_buffer(dev);
322
323 if(dev->is_sample_format_float)
324 {
325 result = (*caller)->Enqueue(
326 dev->player_buffer_queue_interface, dev->sles_buffer_float, dev->period_frames * sizeof(float) * NUM_CHANNELS);
327 }
328 else
329 {
330 result = (*caller)->Enqueue(
331 dev->player_buffer_queue_interface, dev->sles_buffer_short, dev->period_frames * sizeof(short) * NUM_CHANNELS);
332 }
333
334 /*
335 if (result != SL_RESULT_SUCCESS)
336 {
337 // Do not simply break at just one single insufficient buffer. Go on.
338 }
339 */
340 }
341
process_fluid_buffer(fluid_opensles_audio_driver_t * dev)342 void process_fluid_buffer(fluid_opensles_audio_driver_t *dev)
343 {
344 short *out_short = dev->sles_buffer_short;
345 float *out_float = dev->sles_buffer_float;
346 int period_frames = dev->period_frames;
347
348 if(dev->is_sample_format_float)
349 {
350 fluid_synth_write_float(dev->synth, period_frames, out_float, 0, 2, out_float, 1, 2);
351 }
352 else
353 {
354 fluid_synth_write_s16(dev->synth, period_frames, out_short, 0, 2, out_short, 1, 2);
355 }
356 }
357
358 #endif
359