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