Add a comment that explains why this header has no multiple inclusion guards.
[mplayer/greg.git] / libao2 / ao_alsa.c
blob53a9768730aef04474e592c8348b712fee1bffca
1 /*
2 ao_alsa9/1.x - ALSA-0.9.x-1.x output plugin for MPlayer
4 (C) Alex Beregszaszi
6 modified for real alsa-0.9.0-support by Zsolt Barat <joy@streamminister.de>
7 additional AC3 passthrough support by Andy Lo A Foe <andy@alsaplayer.org>
8 08/22/2002 iec958-init rewritten and merged with common init, zsolt
9 04/13/2004 merged with ao_alsa1.x, fixes provided by Jindrich Makovicka
10 04/25/2004 printfs converted to mp_msg, Zsolt.
12 Any bugreports regarding to this driver are welcome.
15 #include <errno.h>
16 #include <sys/time.h>
17 #include <stdlib.h>
18 #include <stdarg.h>
19 #include <ctype.h>
20 #include <math.h>
21 #include <string.h>
23 #include "config.h"
24 #include "subopt-helper.h"
25 #include "mixer.h"
26 #include "mp_msg.h"
27 #include "help_mp.h"
29 #define ALSA_PCM_NEW_HW_PARAMS_API
30 #define ALSA_PCM_NEW_SW_PARAMS_API
32 #if HAVE_SYS_ASOUNDLIB_H
33 #include <sys/asoundlib.h>
34 #elif HAVE_ALSA_ASOUNDLIB_H
35 #include <alsa/asoundlib.h>
36 #else
37 #error "asoundlib.h is not in sys/ or alsa/ - please bugreport"
38 #endif
41 #include "audio_out.h"
42 #include "audio_out_internal.h"
43 #include "libaf/af_format.h"
45 static ao_info_t info =
47 "ALSA-0.9.x-1.x audio output",
48 "alsa",
49 "Alex Beregszaszi, Zsolt Barat <joy@streamminister.de>",
50 "under developement"
53 LIBAO_EXTERN(alsa)
55 static snd_pcm_t *alsa_handler;
56 static snd_pcm_format_t alsa_format;
57 static snd_pcm_hw_params_t *alsa_hwparams;
58 static snd_pcm_sw_params_t *alsa_swparams;
60 /* 16 sets buffersize to 16 * chunksize is as default 1024
61 * which seems to be good avarge for most situations
62 * so buffersize is 16384 frames by default */
63 static int alsa_fragcount = 16;
64 static snd_pcm_uframes_t chunk_size = 1024;
66 static size_t bytes_per_sample;
68 static int ao_noblock = 0;
70 static int open_mode;
71 static int alsa_can_pause = 0;
73 #define ALSA_DEVICE_SIZE 256
75 #undef BUFFERTIME
76 #define SET_CHUNKSIZE
78 static void alsa_error_handler(const char *file, int line, const char *function,
79 int err, const char *format, ...)
81 char tmp[0xc00];
82 va_list va;
84 va_start(va, format);
85 vsnprintf(tmp, sizeof tmp, format, va);
86 va_end(va);
87 tmp[sizeof tmp - 1] = '\0';
89 if (err)
90 mp_msg(MSGT_AO, MSGL_ERR, "[AO_ALSA] alsa-lib: %s:%i:(%s) %s: %s\n",
91 file, line, function, tmp, snd_strerror(err));
92 else
93 mp_msg(MSGT_AO, MSGL_ERR, "[AO_ALSA] alsa-lib: %s:%i:(%s) %s\n",
94 file, line, function, tmp);
97 /* to set/get/query special features/parameters */
98 static int control(int cmd, void *arg)
100 switch(cmd) {
101 case AOCONTROL_QUERY_FORMAT:
102 return CONTROL_TRUE;
103 case AOCONTROL_GET_VOLUME:
104 case AOCONTROL_SET_VOLUME:
106 ao_control_vol_t *vol = (ao_control_vol_t *)arg;
108 int err;
109 snd_mixer_t *handle;
110 snd_mixer_elem_t *elem;
111 snd_mixer_selem_id_t *sid;
113 static char *mix_name = "PCM";
114 static char *card = "default";
115 static int mix_index = 0;
117 long pmin, pmax;
118 long get_vol, set_vol;
119 float f_multi;
121 if(mixer_channel) {
122 char *test_mix_index;
124 mix_name = strdup(mixer_channel);
125 if ((test_mix_index = strchr(mix_name, ','))){
126 *test_mix_index = 0;
127 test_mix_index++;
128 mix_index = strtol(test_mix_index, &test_mix_index, 0);
130 if (*test_mix_index){
131 mp_msg(MSGT_AO,MSGL_ERR,
132 MSGTR_AO_ALSA_InvalidMixerIndexDefaultingToZero);
133 mix_index = 0 ;
137 if(mixer_device) card = mixer_device;
139 if(ao_data.format == AF_FORMAT_AC3)
140 return CONTROL_TRUE;
142 //allocate simple id
143 snd_mixer_selem_id_alloca(&sid);
145 //sets simple-mixer index and name
146 snd_mixer_selem_id_set_index(sid, mix_index);
147 snd_mixer_selem_id_set_name(sid, mix_name);
149 if (mixer_channel) {
150 free(mix_name);
151 mix_name = NULL;
154 if ((err = snd_mixer_open(&handle, 0)) < 0) {
155 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_MixerOpenError, snd_strerror(err));
156 return CONTROL_ERROR;
159 if ((err = snd_mixer_attach(handle, card)) < 0) {
160 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_MixerAttachError,
161 card, snd_strerror(err));
162 snd_mixer_close(handle);
163 return CONTROL_ERROR;
166 if ((err = snd_mixer_selem_register(handle, NULL, NULL)) < 0) {
167 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_MixerRegisterError, snd_strerror(err));
168 snd_mixer_close(handle);
169 return CONTROL_ERROR;
171 err = snd_mixer_load(handle);
172 if (err < 0) {
173 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_MixerLoadError, snd_strerror(err));
174 snd_mixer_close(handle);
175 return CONTROL_ERROR;
178 elem = snd_mixer_find_selem(handle, sid);
179 if (!elem) {
180 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToFindSimpleControl,
181 snd_mixer_selem_id_get_name(sid), snd_mixer_selem_id_get_index(sid));
182 snd_mixer_close(handle);
183 return CONTROL_ERROR;
186 snd_mixer_selem_get_playback_volume_range(elem,&pmin,&pmax);
187 f_multi = (100 / (float)(pmax - pmin));
189 if (cmd == AOCONTROL_SET_VOLUME) {
191 set_vol = vol->left / f_multi + pmin + 0.5;
193 //setting channels
194 if ((err = snd_mixer_selem_set_playback_volume(elem, 0, set_vol)) < 0) {
195 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_ErrorSettingLeftChannel,
196 snd_strerror(err));
197 return CONTROL_ERROR;
199 mp_msg(MSGT_AO,MSGL_DBG2,"left=%li, ", set_vol);
201 set_vol = vol->right / f_multi + pmin + 0.5;
203 if ((err = snd_mixer_selem_set_playback_volume(elem, 1, set_vol)) < 0) {
204 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_ErrorSettingRightChannel,
205 snd_strerror(err));
206 return CONTROL_ERROR;
208 mp_msg(MSGT_AO,MSGL_DBG2,"right=%li, pmin=%li, pmax=%li, mult=%f\n",
209 set_vol, pmin, pmax, f_multi);
211 if (snd_mixer_selem_has_playback_switch(elem)) {
212 int lmute = (vol->left == 0.0);
213 int rmute = (vol->right == 0.0);
214 if (snd_mixer_selem_has_playback_switch_joined(elem)) {
215 lmute = rmute = lmute && rmute;
216 } else {
217 snd_mixer_selem_set_playback_switch(elem, SND_MIXER_SCHN_FRONT_RIGHT, !rmute);
219 snd_mixer_selem_set_playback_switch(elem, SND_MIXER_SCHN_FRONT_LEFT, !lmute);
222 else {
223 snd_mixer_selem_get_playback_volume(elem, 0, &get_vol);
224 vol->left = (get_vol - pmin) * f_multi;
225 snd_mixer_selem_get_playback_volume(elem, 1, &get_vol);
226 vol->right = (get_vol - pmin) * f_multi;
228 mp_msg(MSGT_AO,MSGL_DBG2,"left=%f, right=%f\n",vol->left,vol->right);
230 snd_mixer_close(handle);
231 return CONTROL_OK;
234 } //end switch
235 return(CONTROL_UNKNOWN);
238 static void parse_device (char *dest, const char *src, int len)
240 char *tmp;
241 memmove(dest, src, len);
242 dest[len] = 0;
243 while ((tmp = strrchr(dest, '.')))
244 tmp[0] = ',';
245 while ((tmp = strrchr(dest, '=')))
246 tmp[0] = ':';
249 static void print_help (void)
251 mp_msg (MSGT_AO, MSGL_FATAL,
252 MSGTR_AO_ALSA_CommandlineHelp);
255 static int str_maxlen(strarg_t *str) {
256 if (str->len > ALSA_DEVICE_SIZE)
257 return 0;
258 return 1;
261 static int try_open_device(const char *device, int open_mode, int try_ac3)
263 int err, len;
264 char *ac3_device, *args;
266 if (try_ac3) {
267 /* to set the non-audio bit, use AES0=6 */
268 len = strlen(device);
269 ac3_device = malloc(len + 7 + 1);
270 if (!ac3_device)
271 return -ENOMEM;
272 strcpy(ac3_device, device);
273 args = strchr(ac3_device, ':');
274 if (!args) {
275 /* no existing parameters: add it behind device name */
276 strcat(ac3_device, ":AES0=6");
277 } else {
279 ++args;
280 while (isspace(*args));
281 if (*args == '\0') {
282 /* ":" but no parameters */
283 strcat(ac3_device, "AES0=6");
284 } else if (*args != '{') {
285 /* a simple list of parameters: add it at the end of the list */
286 strcat(ac3_device, ",AES0=6");
287 } else {
288 /* parameters in config syntax: add it inside the { } block */
290 --len;
291 while (len > 0 && isspace(ac3_device[len]));
292 if (ac3_device[len] == '}')
293 strcpy(ac3_device + len, " AES0=6}");
296 err = snd_pcm_open(&alsa_handler, ac3_device, SND_PCM_STREAM_PLAYBACK,
297 open_mode);
298 free(ac3_device);
300 if (!try_ac3 || err < 0)
301 err = snd_pcm_open(&alsa_handler, device, SND_PCM_STREAM_PLAYBACK,
302 open_mode);
303 return err;
307 open & setup audio device
308 return: 1=success 0=fail
310 static int init(int rate_hz, int channels, int format, int flags)
312 int err;
313 int block;
314 strarg_t device;
315 snd_pcm_uframes_t bufsize;
316 snd_pcm_uframes_t boundary;
317 opt_t subopts[] = {
318 {"block", OPT_ARG_BOOL, &block, NULL},
319 {"device", OPT_ARG_STR, &device, (opt_test_f)str_maxlen},
320 {NULL}
323 char alsa_device[ALSA_DEVICE_SIZE + 1];
324 // make sure alsa_device is null-terminated even when using strncpy etc.
325 memset(alsa_device, 0, ALSA_DEVICE_SIZE + 1);
327 mp_msg(MSGT_AO,MSGL_V,"alsa-init: requested format: %d Hz, %d channels, %x\n", rate_hz,
328 channels, format);
329 alsa_handler = NULL;
330 #if SND_LIB_VERSION >= 0x010005
331 mp_msg(MSGT_AO,MSGL_V,"alsa-init: using ALSA %s\n", snd_asoundlib_version());
332 #else
333 mp_msg(MSGT_AO,MSGL_V,"alsa-init: compiled for ALSA-%s\n", SND_LIB_VERSION_STR);
334 #endif
336 snd_lib_error_set_handler(alsa_error_handler);
338 ao_data.samplerate = rate_hz;
339 ao_data.format = format;
340 ao_data.channels = channels;
342 switch (format)
344 case AF_FORMAT_S8:
345 alsa_format = SND_PCM_FORMAT_S8;
346 break;
347 case AF_FORMAT_U8:
348 alsa_format = SND_PCM_FORMAT_U8;
349 break;
350 case AF_FORMAT_U16_LE:
351 alsa_format = SND_PCM_FORMAT_U16_LE;
352 break;
353 case AF_FORMAT_U16_BE:
354 alsa_format = SND_PCM_FORMAT_U16_BE;
355 break;
356 #ifndef WORDS_BIGENDIAN
357 case AF_FORMAT_AC3:
358 #endif
359 case AF_FORMAT_S16_LE:
360 alsa_format = SND_PCM_FORMAT_S16_LE;
361 break;
362 #ifdef WORDS_BIGENDIAN
363 case AF_FORMAT_AC3:
364 #endif
365 case AF_FORMAT_S16_BE:
366 alsa_format = SND_PCM_FORMAT_S16_BE;
367 break;
368 case AF_FORMAT_U32_LE:
369 alsa_format = SND_PCM_FORMAT_U32_LE;
370 break;
371 case AF_FORMAT_U32_BE:
372 alsa_format = SND_PCM_FORMAT_U32_BE;
373 break;
374 case AF_FORMAT_S32_LE:
375 alsa_format = SND_PCM_FORMAT_S32_LE;
376 break;
377 case AF_FORMAT_S32_BE:
378 alsa_format = SND_PCM_FORMAT_S32_BE;
379 break;
380 case AF_FORMAT_FLOAT_LE:
381 alsa_format = SND_PCM_FORMAT_FLOAT_LE;
382 break;
383 case AF_FORMAT_FLOAT_BE:
384 alsa_format = SND_PCM_FORMAT_FLOAT_BE;
385 break;
386 case AF_FORMAT_MU_LAW:
387 alsa_format = SND_PCM_FORMAT_MU_LAW;
388 break;
389 case AF_FORMAT_A_LAW:
390 alsa_format = SND_PCM_FORMAT_A_LAW;
391 break;
393 default:
394 alsa_format = SND_PCM_FORMAT_MPEG; //? default should be -1
395 break;
398 //subdevice parsing
399 // set defaults
400 block = 1;
401 /* switch for spdif
402 * sets opening sequence for SPDIF
403 * sets also the playback and other switches 'on the fly'
404 * while opening the abstract alias for the spdif subdevice
405 * 'iec958'
407 if (format == AF_FORMAT_AC3) {
408 device.str = "iec958";
409 mp_msg(MSGT_AO,MSGL_V,"alsa-spdif-init: playing AC3, %i channels\n", channels);
411 else
412 /* in any case for multichannel playback we should select
413 * appropriate device
415 switch (channels) {
416 case 1:
417 case 2:
418 device.str = "default";
419 mp_msg(MSGT_AO,MSGL_V,"alsa-init: setup for 1/2 channel(s)\n");
420 break;
421 case 4:
422 if (alsa_format == SND_PCM_FORMAT_FLOAT_LE)
423 // hack - use the converter plugin
424 device.str = "plug:surround40";
425 else
426 device.str = "surround40";
427 mp_msg(MSGT_AO,MSGL_V,"alsa-init: device set to surround40\n");
428 break;
429 case 6:
430 if (alsa_format == SND_PCM_FORMAT_FLOAT_LE)
431 device.str = "plug:surround51";
432 else
433 device.str = "surround51";
434 mp_msg(MSGT_AO,MSGL_V,"alsa-init: device set to surround51\n");
435 break;
436 default:
437 device.str = "default";
438 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_ChannelsNotSupported,channels);
440 device.len = strlen(device.str);
441 if (subopt_parse(ao_subdevice, subopts) != 0) {
442 print_help();
443 return 0;
445 ao_noblock = !block;
446 parse_device(alsa_device, device.str, device.len);
448 mp_msg(MSGT_AO,MSGL_V,"alsa-init: using device %s\n", alsa_device);
450 //setting modes for block or nonblock-mode
451 if (ao_noblock) {
452 open_mode = SND_PCM_NONBLOCK;
454 else {
455 open_mode = 0;
458 //sets buff/chunksize if its set manually
459 if (ao_data.buffersize) {
460 switch (ao_data.buffersize)
462 case 1:
463 alsa_fragcount = 16;
464 chunk_size = 512;
465 mp_msg(MSGT_AO,MSGL_V,"alsa-init: buffersize set manually to 8192\n");
466 mp_msg(MSGT_AO,MSGL_V,"alsa-init: chunksize set manually to 512\n");
467 break;
468 case 2:
469 alsa_fragcount = 8;
470 chunk_size = 1024;
471 mp_msg(MSGT_AO,MSGL_V,"alsa-init: buffersize set manually to 8192\n");
472 mp_msg(MSGT_AO,MSGL_V,"alsa-init: chunksize set manually to 1024\n");
473 break;
474 case 3:
475 alsa_fragcount = 32;
476 chunk_size = 512;
477 mp_msg(MSGT_AO,MSGL_V,"alsa-init: buffersize set manually to 16384\n");
478 mp_msg(MSGT_AO,MSGL_V,"alsa-init: chunksize set manually to 512\n");
479 break;
480 case 4:
481 alsa_fragcount = 16;
482 chunk_size = 1024;
483 mp_msg(MSGT_AO,MSGL_V,"alsa-init: buffersize set manually to 16384\n");
484 mp_msg(MSGT_AO,MSGL_V,"alsa-init: chunksize set manually to 1024\n");
485 break;
486 default:
487 alsa_fragcount = 16;
488 chunk_size = 1024;
489 break;
493 if (!alsa_handler) {
494 //modes = 0, SND_PCM_NONBLOCK, SND_PCM_ASYNC
495 if ((err = try_open_device(alsa_device, open_mode, format == AF_FORMAT_AC3)) < 0)
497 if (err != -EBUSY && ao_noblock) {
498 mp_msg(MSGT_AO,MSGL_INFO,MSGTR_AO_ALSA_OpenInNonblockModeFailed);
499 if ((err = try_open_device(alsa_device, 0, format == AF_FORMAT_AC3)) < 0) {
500 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_PlaybackOpenError, snd_strerror(err));
501 return(0);
503 } else {
504 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_PlaybackOpenError, snd_strerror(err));
505 return(0);
509 if ((err = snd_pcm_nonblock(alsa_handler, 0)) < 0) {
510 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_ErrorSetBlockMode, snd_strerror(err));
511 } else {
512 mp_msg(MSGT_AO,MSGL_V,"alsa-init: pcm opened in blocking mode\n");
515 snd_pcm_hw_params_alloca(&alsa_hwparams);
516 snd_pcm_sw_params_alloca(&alsa_swparams);
518 // setting hw-parameters
519 if ((err = snd_pcm_hw_params_any(alsa_handler, alsa_hwparams)) < 0)
521 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToGetInitialParameters,
522 snd_strerror(err));
523 return(0);
526 err = snd_pcm_hw_params_set_access(alsa_handler, alsa_hwparams,
527 SND_PCM_ACCESS_RW_INTERLEAVED);
528 if (err < 0) {
529 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToSetAccessType,
530 snd_strerror(err));
531 return (0);
534 /* workaround for nonsupported formats
535 sets default format to S16_LE if the given formats aren't supported */
536 if ((err = snd_pcm_hw_params_test_format(alsa_handler, alsa_hwparams,
537 alsa_format)) < 0)
539 mp_msg(MSGT_AO,MSGL_INFO,
540 MSGTR_AO_ALSA_FormatNotSupportedByHardware, af_fmt2str_short(format));
541 alsa_format = SND_PCM_FORMAT_S16_LE;
542 ao_data.format = AF_FORMAT_S16_LE;
545 if ((err = snd_pcm_hw_params_set_format(alsa_handler, alsa_hwparams,
546 alsa_format)) < 0)
548 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToSetFormat,
549 snd_strerror(err));
550 return(0);
553 if ((err = snd_pcm_hw_params_set_channels_near(alsa_handler, alsa_hwparams,
554 &ao_data.channels)) < 0)
556 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToSetChannels,
557 snd_strerror(err));
558 return(0);
561 /* workaround for buggy rate plugin (should be fixed in ALSA 1.0.11)
562 prefer our own resampler */
563 #if SND_LIB_VERSION >= 0x010009
564 if ((err = snd_pcm_hw_params_set_rate_resample(alsa_handler, alsa_hwparams,
565 0)) < 0)
567 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToDisableResampling,
568 snd_strerror(err));
569 return(0);
571 #endif
573 if ((err = snd_pcm_hw_params_set_rate_near(alsa_handler, alsa_hwparams,
574 &ao_data.samplerate, NULL)) < 0)
576 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToSetSamplerate2,
577 snd_strerror(err));
578 return(0);
581 bytes_per_sample = snd_pcm_format_physical_width(alsa_format) / 8;
582 bytes_per_sample *= ao_data.channels;
583 ao_data.bps = ao_data.samplerate * bytes_per_sample;
585 #ifdef BUFFERTIME
587 int alsa_buffer_time = 500000; /* original 60 */
588 int alsa_period_time;
589 alsa_period_time = alsa_buffer_time/4;
590 if ((err = snd_pcm_hw_params_set_buffer_time_near(alsa_handler, alsa_hwparams,
591 &alsa_buffer_time, NULL)) < 0)
593 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToSetBufferTimeNear,
594 snd_strerror(err));
595 return(0);
596 } else
597 alsa_buffer_time = err;
599 if ((err = snd_pcm_hw_params_set_period_time_near(alsa_handler, alsa_hwparams,
600 &alsa_period_time, NULL)) < 0)
601 /* original: alsa_buffer_time/ao_data.bps */
603 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToSetPeriodTime,
604 snd_strerror(err));
605 return 0;
607 mp_msg(MSGT_AO,MSGL_INFO,MSGTR_AO_ALSA_BufferTimePeriodTime,
608 alsa_buffer_time, err);
610 #endif//end SET_BUFFERTIME
612 #ifdef SET_CHUNKSIZE
614 //set chunksize
615 if ((err = snd_pcm_hw_params_set_period_size_near(alsa_handler, alsa_hwparams,
616 &chunk_size, NULL)) < 0)
618 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToSetPeriodSize,
619 chunk_size, snd_strerror(err));
620 return 0;
622 else {
623 mp_msg(MSGT_AO,MSGL_V,"alsa-init: chunksize set to %li\n", chunk_size);
625 if ((err = snd_pcm_hw_params_set_periods_near(alsa_handler, alsa_hwparams,
626 &alsa_fragcount, NULL)) < 0) {
627 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToSetPeriods,
628 snd_strerror(err));
629 return 0;
631 else {
632 mp_msg(MSGT_AO,MSGL_V,"alsa-init: fragcount=%i\n", alsa_fragcount);
635 #endif//end SET_CHUNKSIZE
637 /* finally install hardware parameters */
638 if ((err = snd_pcm_hw_params(alsa_handler, alsa_hwparams)) < 0)
640 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToSetHwParameters,
641 snd_strerror(err));
642 return 0;
644 // end setting hw-params
647 // gets buffersize for control
648 if ((err = snd_pcm_hw_params_get_buffer_size(alsa_hwparams, &bufsize)) < 0)
650 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToGetBufferSize, snd_strerror(err));
651 return 0;
653 else {
654 ao_data.buffersize = bufsize * bytes_per_sample;
655 mp_msg(MSGT_AO,MSGL_V,"alsa-init: got buffersize=%i\n", ao_data.buffersize);
658 if ((err = snd_pcm_hw_params_get_period_size(alsa_hwparams, &chunk_size, NULL)) < 0) {
659 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToGetPeriodSize, snd_strerror(err));
660 return 0;
661 } else {
662 mp_msg(MSGT_AO,MSGL_V,"alsa-init: got period size %li\n", chunk_size);
664 ao_data.outburst = chunk_size * bytes_per_sample;
666 /* setting software parameters */
667 if ((err = snd_pcm_sw_params_current(alsa_handler, alsa_swparams)) < 0) {
668 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToGetSwParameters,
669 snd_strerror(err));
670 return 0;
672 #if SND_LIB_VERSION >= 0x000901
673 if ((err = snd_pcm_sw_params_get_boundary(alsa_swparams, &boundary)) < 0) {
674 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToGetBoundary,
675 snd_strerror(err));
676 return 0;
678 #else
679 boundary = 0x7fffffff;
680 #endif
681 /* start playing when one period has been written */
682 if ((err = snd_pcm_sw_params_set_start_threshold(alsa_handler, alsa_swparams, chunk_size)) < 0) {
683 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToSetStartThreshold,
684 snd_strerror(err));
685 return 0;
687 /* disable underrun reporting */
688 if ((err = snd_pcm_sw_params_set_stop_threshold(alsa_handler, alsa_swparams, boundary)) < 0) {
689 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToSetStopThreshold,
690 snd_strerror(err));
691 return 0;
693 #if SND_LIB_VERSION >= 0x000901
694 /* play silence when there is an underrun */
695 if ((err = snd_pcm_sw_params_set_silence_size(alsa_handler, alsa_swparams, boundary)) < 0) {
696 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToSetSilenceSize,
697 snd_strerror(err));
698 return 0;
700 #endif
701 if ((err = snd_pcm_sw_params(alsa_handler, alsa_swparams)) < 0) {
702 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToGetSwParameters,
703 snd_strerror(err));
704 return 0;
706 /* end setting sw-params */
708 mp_msg(MSGT_AO,MSGL_V,"alsa: %d Hz/%d channels/%d bpf/%d bytes buffer/%s\n",
709 ao_data.samplerate, ao_data.channels, bytes_per_sample, ao_data.buffersize,
710 snd_pcm_format_description(alsa_format));
712 } // end switch alsa_handler (spdif)
713 alsa_can_pause = snd_pcm_hw_params_can_pause(alsa_hwparams);
714 return(1);
715 } // end init
718 /* close audio device */
719 static void uninit(int immed)
722 if (alsa_handler) {
723 int err;
725 if (!immed)
726 snd_pcm_drain(alsa_handler);
728 if ((err = snd_pcm_close(alsa_handler)) < 0)
730 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_PcmCloseError, snd_strerror(err));
731 return;
733 else {
734 alsa_handler = NULL;
735 mp_msg(MSGT_AO,MSGL_V,"alsa-uninit: pcm closed\n");
738 else {
739 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_NoHandlerDefined);
743 static void audio_pause(void)
745 int err;
747 if (alsa_can_pause) {
748 if ((err = snd_pcm_pause(alsa_handler, 1)) < 0)
750 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_PcmPauseError, snd_strerror(err));
751 return;
753 mp_msg(MSGT_AO,MSGL_V,"alsa-pause: pause supported by hardware\n");
754 } else {
755 if ((err = snd_pcm_drop(alsa_handler)) < 0)
757 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_PcmDropError, snd_strerror(err));
758 return;
763 static void audio_resume(void)
765 int err;
767 if (alsa_can_pause) {
768 if ((err = snd_pcm_pause(alsa_handler, 0)) < 0)
770 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_PcmResumeError, snd_strerror(err));
771 return;
773 mp_msg(MSGT_AO,MSGL_V,"alsa-resume: resume supported by hardware\n");
774 } else {
775 if ((err = snd_pcm_prepare(alsa_handler)) < 0)
777 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_PcmPrepareError, snd_strerror(err));
778 return;
783 /* stop playing and empty buffers (for seeking/pause) */
784 static void reset(void)
786 int err;
788 if ((err = snd_pcm_drop(alsa_handler)) < 0)
790 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_PcmPrepareError, snd_strerror(err));
791 return;
793 if ((err = snd_pcm_prepare(alsa_handler)) < 0)
795 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_PcmPrepareError, snd_strerror(err));
796 return;
798 return;
802 plays 'len' bytes of 'data'
803 returns: number of bytes played
804 modified last at 29.06.02 by jp
805 thanxs for marius <marius@rospot.com> for giving us the light ;)
808 static int play(void* data, int len, int flags)
810 int num_frames = len / bytes_per_sample;
811 snd_pcm_sframes_t res = 0;
813 //mp_msg(MSGT_AO,MSGL_ERR,"alsa-play: frames=%i, len=%i\n",num_frames,len);
815 if (!alsa_handler) {
816 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_DeviceConfigurationError);
817 return 0;
820 if (num_frames == 0)
821 return 0;
823 do {
824 res = snd_pcm_writei(alsa_handler, data, num_frames);
826 if (res == -EINTR) {
827 /* nothing to do */
828 res = 0;
830 else if (res == -ESTRPIPE) { /* suspend */
831 mp_msg(MSGT_AO,MSGL_INFO,MSGTR_AO_ALSA_PcmInSuspendModeTryingResume);
832 while ((res = snd_pcm_resume(alsa_handler)) == -EAGAIN)
833 sleep(1);
835 if (res < 0) {
836 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_WriteError, snd_strerror(res));
837 mp_msg(MSGT_AO,MSGL_INFO,MSGTR_AO_ALSA_TryingToResetSoundcard);
838 if ((res = snd_pcm_prepare(alsa_handler)) < 0) {
839 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_PcmPrepareError, snd_strerror(res));
840 return(0);
841 break;
844 } while (res == 0);
846 return res < 0 ? res : res * bytes_per_sample;
849 /* how many byes are free in the buffer */
850 static int get_space(void)
852 snd_pcm_status_t *status;
853 int ret;
855 snd_pcm_status_alloca(&status);
857 if ((ret = snd_pcm_status(alsa_handler, status)) < 0)
859 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_CannotGetPcmStatus, snd_strerror(ret));
860 return(0);
863 ret = snd_pcm_status_get_avail(status) * bytes_per_sample;
864 if (ret > ao_data.buffersize) // Buffer underrun?
865 ret = ao_data.buffersize;
866 return(ret);
869 /* delay in seconds between first and last sample in buffer */
870 static float get_delay(void)
872 if (alsa_handler) {
873 snd_pcm_sframes_t delay;
875 if (snd_pcm_delay(alsa_handler, &delay) < 0)
876 return 0;
878 if (delay < 0) {
879 /* underrun - move the application pointer forward to catch up */
880 #if SND_LIB_VERSION >= 0x000901 /* snd_pcm_forward() exists since 0.9.0rc8 */
881 snd_pcm_forward(alsa_handler, -delay);
882 #endif
883 delay = 0;
885 return (float)delay / (float)ao_data.samplerate;
886 } else {
887 return(0);