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