1 /*         ______   ___    ___
2  *        /\  _  \ /\_ \  /\_ \
3  *        \ \ \L\ \\//\ \ \//\ \      __     __   _ __   ___
4  *         \ \  __ \ \ \ \  \ \ \   /'__`\ /'_ `\/\`'__\/ __`\
5  *          \ \ \/\ \ \_\ \_ \_\ \_/\  __//\ \L\ \ \ \//\ \L\ \
6  *           \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
7  *            \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
8  *                                           /\____/
9  *                                           \_/__/
10  *
11  *      ALSA 0.9 sound driver.
12  *
13  *      By Thomas Fjellstrom.
14  *
15  *      Extensively modified by Elias Pschernig.
16  *
17  *      See readme.txt for copyright information.
18  */
19 
20 
21 #include "allegro.h"
22 
23 #if (ALLEGRO_ALSA_VERSION == 9) && (defined ALLEGRO_WITH_ALSADIGI) && ((!defined ALLEGRO_WITH_MODULES) || (defined ALLEGRO_MODULE))
24 
25 #include "allegro/internal/aintern.h"
26 #ifdef ALLEGRO_QNX
27 #include "allegro/platform/aintqnx.h"
28 #else
29 #include "allegro/platform/aintunix.h"
30 #endif
31 
32 #ifndef SCAN_DEPEND
33    #include <string.h>
34    #define ALSA_PCM_NEW_HW_PARAMS_API 1
35    #include <alsa/asoundlib.h>
36    #include <math.h>
37 #endif
38 
39 
40 #ifndef SND_PCM_FORMAT_S16_NE
41    #ifdef ALLEGRO_BIG_ENDIAN
42       #define SND_PCM_FORMAT_S16_NE SND_PCM_FORMAT_S16_BE
43    #else
44       #define SND_PCM_FORMAT_S16_NE SND_PCM_FORMAT_S16_LE
45    #endif
46 #endif
47 #ifndef SND_PCM_FORMAT_U16_NE
48    #ifdef ALLEGRO_BIG_ENDIAN
49       #define SND_PCM_FORMAT_U16_NE SND_PCM_FORMAT_U16_BE
50    #else
51       #define SND_PCM_FORMAT_U16_NE SND_PCM_FORMAT_U16_LE
52    #endif
53 #endif
54 
55 #define ALSA9_CHECK(a) do { \
56    int err = (a); \
57    if (err<0) { \
58       uszprintf(allegro_error, ALLEGRO_ERROR_SIZE, "ALSA: %s : %s", #a, get_config_text(snd_strerror(err))); \
59       goto Error; \
60    } \
61 } while(0)
62 
63 
64 #define PREFIX_I                "al-alsa9 INFO: "
65 #define PREFIX_W                "al-alsa9 WARNING: "
66 #define PREFIX_E                "al-alsa9 ERROR: "
67 
68 static char const *alsa_device = "default";
69 static char const *alsa_mixer_device = "default";
70 static snd_pcm_hw_params_t *hwparams = NULL;
71 static snd_pcm_sw_params_t *swparams = NULL;
72 static snd_output_t *snd_output = NULL;
73 static snd_pcm_uframes_t alsa_bufsize;
74 static snd_mixer_t *alsa_mixer = NULL;
75 static snd_mixer_elem_t *alsa_mixer_elem = NULL;
76 static long alsa_mixer_elem_min, alsa_mixer_elem_max;
77 static double alsa_mixer_allegro_ratio = 0.0;
78 
79 #define ALSA_DEFAULT_BUFFER_MS  100
80 #define ALSA_DEFAULT_NUMFRAGS   5
81 
82 static snd_pcm_t *pcm_handle;
83 static unsigned char *alsa_bufdata;
84 static int alsa_bits, alsa_signed, alsa_stereo;
85 static unsigned int alsa_rate;
86 static unsigned int alsa_fragments;
87 static int alsa_sample_size;
88 
89 static struct pollfd *ufds = NULL;
90 static int pdc = 0;
91 static int poll_next;
92 
93 static char alsa_desc[256] = EMPTY_STRING;
94 
95 static int alsa_detect(int input);
96 static int alsa_init(int input, int voices);
97 static void alsa_exit(int input);
98 static int alsa_set_mixer_volume(int volume);
99 static int alsa_get_mixer_volume(void);
100 static int alsa_buffer_size(void);
101 
102 
103 
104 DIGI_DRIVER digi_alsa =
105 {
106    DIGI_ALSA,
107    empty_string,
108    empty_string,
109    "ALSA",
110    0,
111    0,
112    MIXER_MAX_SFX,
113    MIXER_DEF_SFX,
114 
115    alsa_detect,
116    alsa_init,
117    alsa_exit,
118    alsa_set_mixer_volume,
119    alsa_get_mixer_volume,
120 
121    NULL,
122    NULL,
123    alsa_buffer_size,
124    _mixer_init_voice,
125    _mixer_release_voice,
126    _mixer_start_voice,
127    _mixer_stop_voice,
128    _mixer_loop_voice,
129 
130    _mixer_get_position,
131    _mixer_set_position,
132 
133    _mixer_get_volume,
134    _mixer_set_volume,
135    _mixer_ramp_volume,
136    _mixer_stop_volume_ramp,
137 
138    _mixer_get_frequency,
139    _mixer_set_frequency,
140    _mixer_sweep_frequency,
141    _mixer_stop_frequency_sweep,
142 
143    _mixer_get_pan,
144    _mixer_set_pan,
145    _mixer_sweep_pan,
146    _mixer_stop_pan_sweep,
147 
148    _mixer_set_echo,
149    _mixer_set_tremolo,
150    _mixer_set_vibrato,
151    0, 0,
152    0,
153    0,
154    0,
155    0,
156    0,
157    0
158 };
159 
160 
161 
162 /* alsa_buffer_size:
163  *  Returns the current DMA buffer size, for use by the audiostream code.
164  */
alsa_buffer_size(void)165 static int alsa_buffer_size(void)
166 {
167    return alsa_bufsize;
168 }
169 
170 /* xrun_recovery:
171  *  Underrun and suspend recovery
172  */
xrun_recovery(snd_pcm_t * handle,int err)173 static int xrun_recovery(snd_pcm_t *handle, int err)
174 {
175    if (err == -EPIPE) {  /* under-run */
176       err = snd_pcm_prepare(pcm_handle);
177       if (err < 0)
178 	 fprintf(stderr, "Can't recovery from underrun, prepare failed: %s\n", snd_strerror(err));
179       return 0;
180    }
181    /* TODO: Can't wait here like that - we are inside an 'interrupt' after all. */
182 #if 0
183    else if (err == -ESTRPIPE) {
184       while ((err = snd_pcm_resume(pcm_handle)) == -EAGAIN)
185 	 sleep(1);  /* wait until the suspend flag is released */
186 
187       if (err < 0) {
188 	 err = snd_pcm_prepare(pcm_handle);
189 	 if (err < 0)
190 	    fprintf(stderr, "Can't recovery from suspend, prepare failed: %s\n", snd_strerror(err));
191       }
192       return 0;
193    }
194 #endif
195 
196    return err;
197 }
198 
199 
200 
201 /* alsa_mix
202  *  Mix and send some samples to ALSA.
203  */
alsa_mix(void)204 static void alsa_mix(void)
205 {
206    int ret, samples = alsa_bufsize;
207    unsigned char *ptr = alsa_bufdata;
208 
209    while (samples > 0) {
210       ret = snd_pcm_writei(pcm_handle, ptr, samples);
211       if (ret == -EAGAIN)
212 	 continue;
213 
214       if (ret < 0) {
215 	 if (xrun_recovery(pcm_handle, ret) < 0)
216 	    fprintf(stderr, "Write error: %s\n", snd_strerror(ret));
217 	 poll_next = 0;
218 	 break;  /* skip one period */
219       }
220       if (snd_pcm_state(pcm_handle) == SND_PCM_STATE_RUNNING)
221 	 poll_next = 1;
222       samples -= ret;
223       ptr += ret * alsa_sample_size;
224    }
225 
226    _mix_some_samples((uintptr_t)alsa_bufdata, 0, alsa_signed);
227 }
228 
229 
230 
231 /* alsa_update:
232  *  Updates main buffer in case ALSA is ready.
233  */
alsa_update(int threaded)234 static void alsa_update(int threaded)
235 {
236    unsigned short revents;
237 
238    if (poll_next) {
239       poll(ufds, pdc, 0);
240       snd_pcm_poll_descriptors_revents(pcm_handle, ufds, pdc, &revents);
241       if (revents & POLLERR) {
242 	 if (snd_pcm_state(pcm_handle) == SND_PCM_STATE_XRUN ||
243 	    snd_pcm_state(pcm_handle) == SND_PCM_STATE_SUSPENDED) {
244 	    int err = snd_pcm_state(pcm_handle) == SND_PCM_STATE_XRUN ? -EPIPE : -ESTRPIPE;
245 	    if (xrun_recovery(pcm_handle, err) < 0) {
246 	       fprintf(stderr, "Write error: %s\n", snd_strerror(err));
247 	    }
248 	    poll_next = 0;
249          }
250 	 else {
251 	    fprintf(stderr, "Wait for poll failed\n");
252 	 }
253          return;
254       }
255       if (!(revents & POLLOUT))
256 	 return;
257    }
258    alsa_mix();
259 }
260 
261 
262 
263 /* alsa_detect:
264  *  Detects driver presence.
265  */
alsa_detect(int input)266 static int alsa_detect(int input)
267 {
268    int ret = FALSE;
269    char tmp1[128], tmp2[128];
270 
271    alsa_device = get_config_string(uconvert_ascii("sound", tmp1),
272 				   uconvert_ascii("alsa_device", tmp2),
273 				   alsa_device);
274 
275    ret = snd_pcm_open(&pcm_handle, alsa_device, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
276    if (ret < 0) {
277       ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Can not open card/pcm device"));
278       return FALSE;
279    }
280 
281    snd_pcm_close(pcm_handle);
282    pcm_handle = NULL;
283    return TRUE;
284 }
285 
286 
287 
288 /* alsa_init:
289  *  ALSA init routine.
290  */
alsa_init(int input,int voices)291 static int alsa_init(int input, int voices)
292 {
293    int ret = 0;
294    char tmp1[128], tmp2[128];
295    int format = 0;
296    unsigned int numfrags = 0;
297    snd_pcm_uframes_t fragsize;
298 
299    if (input) {
300       ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Input is not supported"));
301       return -1;
302    }
303 
304    ALSA9_CHECK(snd_output_stdio_attach(&snd_output, stdout, 0));
305 
306    alsa_device = get_config_string(uconvert_ascii("sound", tmp1),
307 				   uconvert_ascii("alsa_device", tmp2),
308 				   alsa_device);
309 
310    alsa_mixer_device = get_config_string(uconvert_ascii("sound", tmp1),
311 				   uconvert_ascii("alsa_mixer_device", tmp2),
312 				   alsa_mixer_device);
313 
314    fragsize = get_config_int(uconvert_ascii("sound", tmp1),
315 			     uconvert_ascii("alsa_fragsize", tmp2), 0);
316 
317    numfrags = get_config_int(uconvert_ascii("sound", tmp1),
318 			     uconvert_ascii("alsa_numfrags", tmp2),
319 			     ALSA_DEFAULT_NUMFRAGS);
320 
321    ret = snd_pcm_open(&pcm_handle, alsa_device, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
322    if (ret < 0) {
323       ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Can not open card/pcm device"));
324       return -1;
325    }
326 
327    snd_mixer_open(&alsa_mixer, 0);
328 
329    if (alsa_mixer
330        && snd_mixer_attach(alsa_mixer, alsa_mixer_device) >= 0
331        && snd_mixer_selem_register (alsa_mixer, NULL, NULL) >= 0
332        && snd_mixer_load(alsa_mixer) >= 0) {
333       const char *alsa_mixer_elem_name = get_config_string(uconvert_ascii("sound", tmp1),
334 							   uconvert_ascii("alsa_mixer_elem", tmp2),
335 							   "PCM");
336 
337       alsa_mixer_elem = snd_mixer_first_elem(alsa_mixer);
338 
339       while (alsa_mixer_elem) {
340 	 const char *name = snd_mixer_selem_get_name(alsa_mixer_elem);
341 
342 	 if (strcasecmp(name, alsa_mixer_elem_name) == 0) {
343 	    snd_mixer_selem_get_playback_volume_range(alsa_mixer_elem, &alsa_mixer_elem_min, &alsa_mixer_elem_max);
344 	    alsa_mixer_allegro_ratio = (double) (alsa_mixer_elem_max - alsa_mixer_elem_min) / (double) 255;
345 	    break;
346 	 }
347 
348 	 alsa_mixer_elem = snd_mixer_elem_next(alsa_mixer_elem);
349       }
350    }
351 
352    /* Set format variables. */
353    alsa_bits = (_sound_bits == 8) ? 8 : 16;
354    alsa_stereo = (_sound_stereo) ? 1 : 0;
355    alsa_rate = (_sound_freq > 0) ? _sound_freq : 44100;
356 
357    snd_pcm_hw_params_malloc(&hwparams);
358    ALSA9_CHECK(snd_pcm_hw_params_any(pcm_handle, hwparams));
359 
360    if (alsa_bits == 8) {
361       if (snd_pcm_hw_params_test_format(pcm_handle, hwparams, SND_PCM_FORMAT_U8) == 0) {
362          format = SND_PCM_FORMAT_U8;
363          alsa_signed = 0;
364       }
365       else if (snd_pcm_hw_params_test_format(pcm_handle, hwparams, SND_PCM_FORMAT_S8) == 0) {
366          format = SND_PCM_FORMAT_S8;
367          alsa_signed = 1;
368       }
369       else {
370          ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Unsupported sample format"));
371          goto Error;
372       }
373    }
374    else if (alsa_bits == 16) {
375       if (sizeof(short) != 2) {
376          ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Unsupported sample format"));
377          goto Error;
378       }
379 
380       if (snd_pcm_hw_params_test_format(pcm_handle, hwparams, SND_PCM_FORMAT_U16_NE) == 0) {
381          format = SND_PCM_FORMAT_U16_NE;
382          alsa_signed = 0;
383       }
384       else if (snd_pcm_hw_params_test_format(pcm_handle, hwparams, SND_PCM_FORMAT_S16_NE) == 0) {
385          format = SND_PCM_FORMAT_S16_NE;
386          alsa_signed = 1;
387       }
388       else {
389          ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Unsupported sample format"));
390          goto Error;
391       }
392    }
393 
394    alsa_sample_size = (alsa_bits / 8) * (alsa_stereo ? 2 : 1);
395 
396    if (fragsize == 0) {
397       unsigned int size = alsa_rate * ALSA_DEFAULT_BUFFER_MS / 1000 / numfrags;
398       fragsize = 1;
399       while (fragsize < size)
400 	 fragsize <<= 1;
401    }
402 
403    ALSA9_CHECK(snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED));
404    ALSA9_CHECK(snd_pcm_hw_params_set_format(pcm_handle, hwparams, format));
405    ALSA9_CHECK(snd_pcm_hw_params_set_channels(pcm_handle, hwparams, alsa_stereo + 1));
406 
407    ALSA9_CHECK(snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &alsa_rate, NULL));
408    ALSA9_CHECK(snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams, &fragsize, NULL));
409    ALSA9_CHECK(snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, &numfrags, NULL));
410 
411    ALSA9_CHECK(snd_pcm_hw_params(pcm_handle, hwparams));
412 
413    ALSA9_CHECK(snd_pcm_hw_params_get_period_size(hwparams, &alsa_bufsize, NULL));
414    ALSA9_CHECK(snd_pcm_hw_params_get_periods(hwparams, &alsa_fragments, NULL));
415 
416    TRACE (PREFIX_I "alsa_bufsize = %ld, alsa_fragments = %d\n", alsa_bufsize, alsa_fragments);
417 
418    snd_pcm_sw_params_malloc(&swparams);
419    ALSA9_CHECK(snd_pcm_sw_params_current(pcm_handle, swparams));
420    ALSA9_CHECK(snd_pcm_sw_params_set_start_threshold(pcm_handle, swparams, alsa_bufsize));
421    ALSA9_CHECK(snd_pcm_sw_params_set_avail_min(pcm_handle, swparams, fragsize));
422    ALSA9_CHECK(snd_pcm_sw_params(pcm_handle, swparams));
423 
424    /* Allocate mixing buffer. */
425    alsa_bufdata = _AL_MALLOC_ATOMIC(alsa_bufsize * alsa_sample_size);
426    if (!alsa_bufdata) {
427       ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Can not allocate audio buffer"));
428       goto Error;
429    }
430 
431    /* Initialise mixer. */
432    digi_alsa.voices = voices;
433 
434    if (_mixer_init(alsa_bufsize * (alsa_stereo ? 2 : 1), alsa_rate,
435 		   alsa_stereo, ((alsa_bits == 16) ? 1 : 0),
436 		   &digi_alsa.voices) != 0) {
437       ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Can not init software mixer"));
438       goto Error;
439    }
440 
441    snd_pcm_prepare(pcm_handle);
442    pdc = snd_pcm_poll_descriptors_count (pcm_handle);
443    if (pdc <= 0) {
444       ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Invalid poll descriptors count"));
445       goto Error;
446    }
447 
448    ufds = _AL_MALLOC(sizeof(struct pollfd) * pdc);
449    if (ufds == NULL) {
450       ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Not enough memory for poll descriptors"));
451       goto Error;
452    }
453    ALSA9_CHECK(snd_pcm_poll_descriptors(pcm_handle, ufds, pdc));
454 
455    poll_next = 0;
456 
457    _mix_some_samples((uintptr_t) alsa_bufdata, 0, alsa_signed);
458 
459    /* Add audio interrupt. */
460    _unix_bg_man->register_func(alsa_update);
461 
462    uszprintf(alsa_desc, sizeof(alsa_desc),
463 	     get_config_text
464 	     ("Alsa 0.9, Device '%s': %d bits, %s, %d bps, %s"),
465 	     alsa_device, alsa_bits,
466 	     uconvert_ascii((alsa_signed ? "signed" : "unsigned"), tmp1),
467 	     alsa_rate, uconvert_ascii((alsa_stereo ? "stereo" : "mono"), tmp2));
468 
469    digi_driver->desc = alsa_desc;
470    return 0;
471 
472  Error:
473    if (pcm_handle) {
474       snd_pcm_close(pcm_handle);
475       pcm_handle = NULL;
476    }
477 
478    return -1;
479 }
480 
481 
482 
483 /* alsa_exit:
484  *  Shuts down ALSA driver.
485  */
alsa_exit(int input)486 static void alsa_exit(int input)
487 {
488    if (input)
489       return;
490 
491    _unix_bg_man->unregister_func(alsa_update);
492 
493    _AL_FREE(alsa_bufdata);
494    alsa_bufdata = NULL;
495 
496    _mixer_exit();
497 
498    if (alsa_mixer)
499       snd_mixer_close(alsa_mixer);
500 
501    snd_pcm_close(pcm_handle);
502 
503    snd_pcm_hw_params_free(hwparams);
504    snd_pcm_sw_params_free(swparams);
505 }
506 
507 
508 
509 /* alsa_set_mixer_volume:
510  *  Set mixer volume (0-255)
511  */
alsa_set_mixer_volume(int volume)512 static int alsa_set_mixer_volume(int volume)
513 {
514    if (alsa_mixer && alsa_mixer_elem) {
515       snd_mixer_selem_set_playback_volume(alsa_mixer_elem, 0, volume * alsa_mixer_allegro_ratio);
516       snd_mixer_selem_set_playback_volume(alsa_mixer_elem, 1, volume * alsa_mixer_allegro_ratio);
517    }
518    return 0;
519 }
520 
521 
522 
523 /* alsa_get_mixer_volume:
524  *  Return mixer volume (0-255)
525  */
alsa_get_mixer_volume(void)526 static int alsa_get_mixer_volume(void)
527 {
528    if (alsa_mixer && alsa_mixer_elem) {
529       long vol1, vol2;
530 
531       snd_mixer_handle_events(alsa_mixer);
532 
533       if (snd_mixer_selem_get_playback_volume(alsa_mixer_elem, 0, &vol1) < 0)
534 	 return -1;
535       if (snd_mixer_selem_get_playback_volume(alsa_mixer_elem, 1, &vol2) < 0)
536          return -1;
537 
538       vol1 /= alsa_mixer_allegro_ratio;
539       vol2 /= alsa_mixer_allegro_ratio;
540 
541       return (vol1 + vol2) / 2;
542    }
543 
544    return -1;
545 }
546 
547 
548 
549 #ifdef ALLEGRO_MODULE
550 
551 /* _module_init:
552  *  Called when loaded as a dynamically linked module.
553  */
_module_init(int system_driver)554 void _module_init(int system_driver)
555 {
556    _unix_register_digi_driver(DIGI_ALSA, &digi_alsa, TRUE, TRUE);
557 }
558 
559 #endif
560 
561 #endif
562