video_out.h: Cosmetics
[mplayer/kovensky.git] / libao2 / ao_alsa.c
blob92e827ea7e578a7a054791df23065fdb1b0369cb
1 /*
2 * ALSA 0.9.x-1.x audio output driver
4 * Copyright (C) 2004 Alex Beregszaszi
6 * modified for real ALSA 0.9.0 support by Zsolt Barat <joy@streamminister.de>
7 * additional AC-3 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 * This file is part of MPlayer.
14 * MPlayer is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
19 * MPlayer is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public License along
25 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
26 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
29 #include <errno.h>
30 #include <sys/time.h>
31 #include <stdlib.h>
32 #include <stdarg.h>
33 #include <ctype.h>
34 #include <math.h>
35 #include <string.h>
36 #include <alloca.h>
38 #include "config.h"
39 #include "subopt-helper.h"
40 #include "mixer.h"
41 #include "mp_msg.h"
42 #include "help_mp.h"
44 #define ALSA_PCM_NEW_HW_PARAMS_API
45 #define ALSA_PCM_NEW_SW_PARAMS_API
47 #ifdef HAVE_SYS_ASOUNDLIB_H
48 #include <sys/asoundlib.h>
49 #elif defined(HAVE_ALSA_ASOUNDLIB_H)
50 #include <alsa/asoundlib.h>
51 #else
52 #error "asoundlib.h is not in sys/ or alsa/ - please bugreport"
53 #endif
56 #include "audio_out.h"
57 #include "audio_out_internal.h"
58 #include "libaf/af_format.h"
60 static const ao_info_t info =
62 "ALSA-0.9.x-1.x audio output",
63 "alsa",
64 "Alex Beregszaszi, Zsolt Barat <joy@streamminister.de>",
65 "under developement"
68 LIBAO_EXTERN(alsa)
70 static snd_pcm_t *alsa_handler;
71 static snd_pcm_format_t alsa_format;
72 static snd_pcm_hw_params_t *alsa_hwparams;
73 static snd_pcm_sw_params_t *alsa_swparams;
75 /* 16 sets buffersize to 16 * chunksize is as default 1024
76 * which seems to be good avarge for most situations
77 * so buffersize is 16384 frames by default */
78 static int alsa_fragcount = 16;
79 static snd_pcm_uframes_t chunk_size = 1024;
81 static size_t bytes_per_sample;
83 static int ao_noblock = 0;
85 static int open_mode;
86 static int alsa_can_pause = 0;
87 static snd_pcm_sframes_t prepause_frames;
89 #define ALSA_DEVICE_SIZE 256
91 #undef BUFFERTIME
92 #define SET_CHUNKSIZE
94 static void alsa_error_handler(const char *file, int line, const char *function,
95 int err, const char *format, ...)
97 char tmp[0xc00];
98 va_list va;
100 va_start(va, format);
101 vsnprintf(tmp, sizeof tmp, format, va);
102 va_end(va);
103 tmp[sizeof tmp - 1] = '\0';
105 if (err)
106 mp_msg(MSGT_AO, MSGL_ERR, "[AO_ALSA] alsa-lib: %s:%i:(%s) %s: %s\n",
107 file, line, function, tmp, snd_strerror(err));
108 else
109 mp_msg(MSGT_AO, MSGL_ERR, "[AO_ALSA] alsa-lib: %s:%i:(%s) %s\n",
110 file, line, function, tmp);
113 /* to set/get/query special features/parameters */
114 static int control(int cmd, void *arg)
116 switch(cmd) {
117 case AOCONTROL_QUERY_FORMAT:
118 return CONTROL_TRUE;
119 case AOCONTROL_GET_VOLUME:
120 case AOCONTROL_SET_VOLUME:
122 ao_control_vol_t *vol = (ao_control_vol_t *)arg;
124 int err;
125 snd_mixer_t *handle;
126 snd_mixer_elem_t *elem;
127 snd_mixer_selem_id_t *sid;
129 static char *mix_name = "PCM";
130 static char *card = "default";
131 static int mix_index = 0;
133 long pmin, pmax;
134 long get_vol, set_vol;
135 float f_multi;
137 if(ao_data.format == AF_FORMAT_AC3)
138 return CONTROL_TRUE;
140 if(mixer_channel) {
141 char *test_mix_index;
143 mix_name = strdup(mixer_channel);
144 if ((test_mix_index = strchr(mix_name, ','))){
145 *test_mix_index = 0;
146 test_mix_index++;
147 mix_index = strtol(test_mix_index, &test_mix_index, 0);
149 if (*test_mix_index){
150 mp_tmsg(MSGT_AO,MSGL_ERR,
151 "[AO_ALSA] Invalid mixer index. Defaulting to 0.\n");
152 mix_index = 0 ;
156 if(mixer_device) card = mixer_device;
158 //allocate simple id
159 snd_mixer_selem_id_alloca(&sid);
161 //sets simple-mixer index and name
162 snd_mixer_selem_id_set_index(sid, mix_index);
163 snd_mixer_selem_id_set_name(sid, mix_name);
165 if (mixer_channel) {
166 free(mix_name);
167 mix_name = NULL;
170 if ((err = snd_mixer_open(&handle, 0)) < 0) {
171 mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Mixer open error: %s\n", snd_strerror(err));
172 return CONTROL_ERROR;
175 if ((err = snd_mixer_attach(handle, card)) < 0) {
176 mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Mixer attach %s error: %s\n",
177 card, snd_strerror(err));
178 snd_mixer_close(handle);
179 return CONTROL_ERROR;
182 if ((err = snd_mixer_selem_register(handle, NULL, NULL)) < 0) {
183 mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Mixer register error: %s\n", snd_strerror(err));
184 snd_mixer_close(handle);
185 return CONTROL_ERROR;
187 err = snd_mixer_load(handle);
188 if (err < 0) {
189 mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Mixer load error: %s\n", snd_strerror(err));
190 snd_mixer_close(handle);
191 return CONTROL_ERROR;
194 elem = snd_mixer_find_selem(handle, sid);
195 if (!elem) {
196 mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Unable to find simple control '%s',%i.\n",
197 snd_mixer_selem_id_get_name(sid), snd_mixer_selem_id_get_index(sid));
198 snd_mixer_close(handle);
199 return CONTROL_ERROR;
202 snd_mixer_selem_get_playback_volume_range(elem,&pmin,&pmax);
203 f_multi = (100 / (float)(pmax - pmin));
205 if (cmd == AOCONTROL_SET_VOLUME) {
207 set_vol = vol->left / f_multi + pmin + 0.5;
209 //setting channels
210 if ((err = snd_mixer_selem_set_playback_volume(elem, SND_MIXER_SCHN_FRONT_LEFT, set_vol)) < 0) {
211 mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Error setting left channel, %s\n",
212 snd_strerror(err));
213 snd_mixer_close(handle);
214 return CONTROL_ERROR;
216 mp_msg(MSGT_AO,MSGL_DBG2,"left=%li, ", set_vol);
218 set_vol = vol->right / f_multi + pmin + 0.5;
220 if ((err = snd_mixer_selem_set_playback_volume(elem, SND_MIXER_SCHN_FRONT_RIGHT, set_vol)) < 0) {
221 mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Error setting right channel, %s\n",
222 snd_strerror(err));
223 snd_mixer_close(handle);
224 return CONTROL_ERROR;
226 mp_msg(MSGT_AO,MSGL_DBG2,"right=%li, pmin=%li, pmax=%li, mult=%f\n",
227 set_vol, pmin, pmax, f_multi);
229 if (snd_mixer_selem_has_playback_switch(elem)) {
230 int lmute = (vol->left == 0.0);
231 int rmute = (vol->right == 0.0);
232 if (snd_mixer_selem_has_playback_switch_joined(elem)) {
233 lmute = rmute = lmute && rmute;
234 } else {
235 snd_mixer_selem_set_playback_switch(elem, SND_MIXER_SCHN_FRONT_RIGHT, !rmute);
237 snd_mixer_selem_set_playback_switch(elem, SND_MIXER_SCHN_FRONT_LEFT, !lmute);
240 else {
241 snd_mixer_selem_get_playback_volume(elem, SND_MIXER_SCHN_FRONT_LEFT, &get_vol);
242 vol->left = (get_vol - pmin) * f_multi;
243 snd_mixer_selem_get_playback_volume(elem, SND_MIXER_SCHN_FRONT_RIGHT, &get_vol);
244 vol->right = (get_vol - pmin) * f_multi;
246 mp_msg(MSGT_AO,MSGL_DBG2,"left=%f, right=%f\n",vol->left,vol->right);
248 snd_mixer_close(handle);
249 return CONTROL_OK;
252 } //end switch
253 return CONTROL_UNKNOWN;
256 static void parse_device (char *dest, const char *src, int len)
258 char *tmp;
259 memmove(dest, src, len);
260 dest[len] = 0;
261 while ((tmp = strrchr(dest, '.')))
262 tmp[0] = ',';
263 while ((tmp = strrchr(dest, '=')))
264 tmp[0] = ':';
267 static void print_help (void)
269 mp_tmsg (MSGT_AO, MSGL_FATAL,
270 "\n[AO_ALSA] -ao alsa commandline help:\n"\
271 "[AO_ALSA] Example: mplayer -ao alsa:device=hw=0.3\n"\
272 "[AO_ALSA] Sets first card fourth hardware device.\n\n"\
273 "[AO_ALSA] Options:\n"\
274 "[AO_ALSA] noblock\n"\
275 "[AO_ALSA] Opens device in non-blocking mode.\n"\
276 "[AO_ALSA] device=<device-name>\n"\
277 "[AO_ALSA] Sets device (change , to . and : to =)\n");
280 static int str_maxlen(strarg_t *str) {
281 if (str->len > ALSA_DEVICE_SIZE)
282 return 0;
283 return 1;
286 static int try_open_device(const char *device, int open_mode, int try_ac3)
288 int err, len;
289 char *ac3_device, *args;
291 if (try_ac3) {
292 /* to set the non-audio bit, use AES0=6 */
293 len = strlen(device);
294 ac3_device = malloc(len + 7 + 1);
295 if (!ac3_device)
296 return -ENOMEM;
297 strcpy(ac3_device, device);
298 args = strchr(ac3_device, ':');
299 if (!args) {
300 /* no existing parameters: add it behind device name */
301 strcat(ac3_device, ":AES0=6");
302 } else {
304 ++args;
305 while (isspace(*args));
306 if (*args == '\0') {
307 /* ":" but no parameters */
308 strcat(ac3_device, "AES0=6");
309 } else if (*args != '{') {
310 /* a simple list of parameters: add it at the end of the list */
311 strcat(ac3_device, ",AES0=6");
312 } else {
313 /* parameters in config syntax: add it inside the { } block */
315 --len;
316 while (len > 0 && isspace(ac3_device[len]));
317 if (ac3_device[len] == '}')
318 strcpy(ac3_device + len, " AES0=6}");
321 err = snd_pcm_open(&alsa_handler, ac3_device, SND_PCM_STREAM_PLAYBACK,
322 open_mode);
323 free(ac3_device);
325 if (!try_ac3 || err < 0)
326 err = snd_pcm_open(&alsa_handler, device, SND_PCM_STREAM_PLAYBACK,
327 open_mode);
328 return err;
332 open & setup audio device
333 return: 1=success 0=fail
335 static int init(int rate_hz, int channels, int format, int flags)
337 int err;
338 int block;
339 strarg_t device;
340 snd_pcm_uframes_t bufsize;
341 snd_pcm_uframes_t boundary;
342 opt_t subopts[] = {
343 {"block", OPT_ARG_BOOL, &block, NULL},
344 {"device", OPT_ARG_STR, &device, (opt_test_f)str_maxlen},
345 {NULL}
348 char alsa_device[ALSA_DEVICE_SIZE + 1];
349 // make sure alsa_device is null-terminated even when using strncpy etc.
350 memset(alsa_device, 0, ALSA_DEVICE_SIZE + 1);
352 mp_msg(MSGT_AO,MSGL_V,"alsa-init: requested format: %d Hz, %d channels, %x\n", rate_hz,
353 channels, format);
354 alsa_handler = NULL;
355 #if SND_LIB_VERSION >= 0x010005
356 mp_msg(MSGT_AO,MSGL_V,"alsa-init: using ALSA %s\n", snd_asoundlib_version());
357 #else
358 mp_msg(MSGT_AO,MSGL_V,"alsa-init: compiled for ALSA-%s\n", SND_LIB_VERSION_STR);
359 #endif
361 prepause_frames = 0;
363 snd_lib_error_set_handler(alsa_error_handler);
365 ao_data.samplerate = rate_hz;
366 ao_data.format = format;
367 ao_data.channels = channels;
369 switch (format)
371 case AF_FORMAT_S8:
372 alsa_format = SND_PCM_FORMAT_S8;
373 break;
374 case AF_FORMAT_U8:
375 alsa_format = SND_PCM_FORMAT_U8;
376 break;
377 case AF_FORMAT_U16_LE:
378 alsa_format = SND_PCM_FORMAT_U16_LE;
379 break;
380 case AF_FORMAT_U16_BE:
381 alsa_format = SND_PCM_FORMAT_U16_BE;
382 break;
383 #if !HAVE_BIGENDIAN
384 case AF_FORMAT_AC3:
385 #endif
386 case AF_FORMAT_S16_LE:
387 alsa_format = SND_PCM_FORMAT_S16_LE;
388 break;
389 #if HAVE_BIGENDIAN
390 case AF_FORMAT_AC3:
391 #endif
392 case AF_FORMAT_S16_BE:
393 alsa_format = SND_PCM_FORMAT_S16_BE;
394 break;
395 case AF_FORMAT_U32_LE:
396 alsa_format = SND_PCM_FORMAT_U32_LE;
397 break;
398 case AF_FORMAT_U32_BE:
399 alsa_format = SND_PCM_FORMAT_U32_BE;
400 break;
401 case AF_FORMAT_S32_LE:
402 alsa_format = SND_PCM_FORMAT_S32_LE;
403 break;
404 case AF_FORMAT_S32_BE:
405 alsa_format = SND_PCM_FORMAT_S32_BE;
406 break;
407 case AF_FORMAT_U24_LE:
408 alsa_format = SND_PCM_FORMAT_U24_3LE;
409 break;
410 case AF_FORMAT_U24_BE:
411 alsa_format = SND_PCM_FORMAT_U24_3BE;
412 break;
413 case AF_FORMAT_S24_LE:
414 alsa_format = SND_PCM_FORMAT_S24_3LE;
415 break;
416 case AF_FORMAT_S24_BE:
417 alsa_format = SND_PCM_FORMAT_S24_3BE;
418 break;
419 case AF_FORMAT_FLOAT_LE:
420 alsa_format = SND_PCM_FORMAT_FLOAT_LE;
421 break;
422 case AF_FORMAT_FLOAT_BE:
423 alsa_format = SND_PCM_FORMAT_FLOAT_BE;
424 break;
425 case AF_FORMAT_MU_LAW:
426 alsa_format = SND_PCM_FORMAT_MU_LAW;
427 break;
428 case AF_FORMAT_A_LAW:
429 alsa_format = SND_PCM_FORMAT_A_LAW;
430 break;
432 default:
433 alsa_format = SND_PCM_FORMAT_MPEG; //? default should be -1
434 break;
437 //subdevice parsing
438 // set defaults
439 block = 1;
440 /* switch for spdif
441 * sets opening sequence for SPDIF
442 * sets also the playback and other switches 'on the fly'
443 * while opening the abstract alias for the spdif subdevice
444 * 'iec958'
446 if (format == AF_FORMAT_AC3) {
447 device.str = "iec958";
448 mp_msg(MSGT_AO,MSGL_V,"alsa-spdif-init: playing AC3, %i channels\n", channels);
450 else
451 /* in any case for multichannel playback we should select
452 * appropriate device
454 switch (channels) {
455 case 1:
456 case 2:
457 device.str = "default";
458 mp_msg(MSGT_AO,MSGL_V,"alsa-init: setup for 1/2 channel(s)\n");
459 break;
460 case 4:
461 if (alsa_format == SND_PCM_FORMAT_FLOAT_LE)
462 // hack - use the converter plugin
463 device.str = "plug:surround40";
464 else
465 device.str = "surround40";
466 mp_msg(MSGT_AO,MSGL_V,"alsa-init: device set to surround40\n");
467 break;
468 case 6:
469 if (alsa_format == SND_PCM_FORMAT_FLOAT_LE)
470 device.str = "plug:surround51";
471 else
472 device.str = "surround51";
473 mp_msg(MSGT_AO,MSGL_V,"alsa-init: device set to surround51\n");
474 break;
475 default:
476 device.str = "default";
477 mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] %d channels are not supported.\n",channels);
479 device.len = strlen(device.str);
480 if (subopt_parse(ao_subdevice, subopts) != 0) {
481 print_help();
482 return 0;
484 ao_noblock = !block;
485 parse_device(alsa_device, device.str, device.len);
487 mp_msg(MSGT_AO,MSGL_V,"alsa-init: using device %s\n", alsa_device);
489 //setting modes for block or nonblock-mode
490 if (ao_noblock) {
491 open_mode = SND_PCM_NONBLOCK;
493 else {
494 open_mode = 0;
497 //sets buff/chunksize if its set manually
498 if (ao_data.buffersize) {
499 switch (ao_data.buffersize)
501 case 1:
502 alsa_fragcount = 16;
503 chunk_size = 512;
504 mp_msg(MSGT_AO,MSGL_V,"alsa-init: buffersize set manually to 8192\n");
505 mp_msg(MSGT_AO,MSGL_V,"alsa-init: chunksize set manually to 512\n");
506 break;
507 case 2:
508 alsa_fragcount = 8;
509 chunk_size = 1024;
510 mp_msg(MSGT_AO,MSGL_V,"alsa-init: buffersize set manually to 8192\n");
511 mp_msg(MSGT_AO,MSGL_V,"alsa-init: chunksize set manually to 1024\n");
512 break;
513 case 3:
514 alsa_fragcount = 32;
515 chunk_size = 512;
516 mp_msg(MSGT_AO,MSGL_V,"alsa-init: buffersize set manually to 16384\n");
517 mp_msg(MSGT_AO,MSGL_V,"alsa-init: chunksize set manually to 512\n");
518 break;
519 case 4:
520 alsa_fragcount = 16;
521 chunk_size = 1024;
522 mp_msg(MSGT_AO,MSGL_V,"alsa-init: buffersize set manually to 16384\n");
523 mp_msg(MSGT_AO,MSGL_V,"alsa-init: chunksize set manually to 1024\n");
524 break;
525 default:
526 alsa_fragcount = 16;
527 chunk_size = 1024;
528 break;
532 if (!alsa_handler) {
533 //modes = 0, SND_PCM_NONBLOCK, SND_PCM_ASYNC
534 if ((err = try_open_device(alsa_device, open_mode, format == AF_FORMAT_AC3)) < 0)
536 if (err != -EBUSY && ao_noblock) {
537 mp_tmsg(MSGT_AO,MSGL_INFO,"[AO_ALSA] Open in nonblock-mode failed, trying to open in block-mode.\n");
538 if ((err = try_open_device(alsa_device, 0, format == AF_FORMAT_AC3)) < 0) {
539 mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Playback open error: %s\n", snd_strerror(err));
540 return 0;
542 } else {
543 mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Playback open error: %s\n", snd_strerror(err));
544 return 0;
548 if ((err = snd_pcm_nonblock(alsa_handler, 0)) < 0) {
549 mp_tmsg(MSGT_AO,MSGL_ERR,"[AL_ALSA] Error setting block-mode %s.\n", snd_strerror(err));
550 } else {
551 mp_msg(MSGT_AO,MSGL_V,"alsa-init: pcm opened in blocking mode\n");
554 snd_pcm_hw_params_alloca(&alsa_hwparams);
555 snd_pcm_sw_params_alloca(&alsa_swparams);
557 // setting hw-parameters
558 if ((err = snd_pcm_hw_params_any(alsa_handler, alsa_hwparams)) < 0)
560 mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Unable to get initial parameters: %s\n",
561 snd_strerror(err));
562 return 0;
565 err = snd_pcm_hw_params_set_access(alsa_handler, alsa_hwparams,
566 SND_PCM_ACCESS_RW_INTERLEAVED);
567 if (err < 0) {
568 mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Unable to set access type: %s\n",
569 snd_strerror(err));
570 return 0;
573 /* workaround for nonsupported formats
574 sets default format to S16_LE if the given formats aren't supported */
575 if ((err = snd_pcm_hw_params_test_format(alsa_handler, alsa_hwparams,
576 alsa_format)) < 0)
578 mp_tmsg(MSGT_AO,MSGL_INFO,
579 "[AO_ALSA] Format %s is not supported by hardware, trying default.\n", af_fmt2str_short(format));
580 alsa_format = SND_PCM_FORMAT_S16_LE;
581 ao_data.format = AF_FORMAT_S16_LE;
584 if ((err = snd_pcm_hw_params_set_format(alsa_handler, alsa_hwparams,
585 alsa_format)) < 0)
587 mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Unable to set format: %s\n",
588 snd_strerror(err));
589 return 0;
592 if ((err = snd_pcm_hw_params_set_channels_near(alsa_handler, alsa_hwparams,
593 &ao_data.channels)) < 0)
595 mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Unable to set channels: %s\n",
596 snd_strerror(err));
597 return 0;
600 /* workaround for buggy rate plugin (should be fixed in ALSA 1.0.11)
601 prefer our own resampler */
602 #if SND_LIB_VERSION >= 0x010009
603 if ((err = snd_pcm_hw_params_set_rate_resample(alsa_handler, alsa_hwparams,
604 0)) < 0)
606 mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Unable to disable resampling: %s\n",
607 snd_strerror(err));
608 return 0;
610 #endif
612 if ((err = snd_pcm_hw_params_set_rate_near(alsa_handler, alsa_hwparams,
613 &ao_data.samplerate, NULL)) < 0)
615 mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Unable to set samplerate-2: %s\n",
616 snd_strerror(err));
617 return 0;
620 bytes_per_sample = snd_pcm_format_physical_width(alsa_format) / 8;
621 bytes_per_sample *= ao_data.channels;
622 ao_data.bps = ao_data.samplerate * bytes_per_sample;
624 #ifdef BUFFERTIME
626 int alsa_buffer_time = 500000; /* original 60 */
627 int alsa_period_time;
628 alsa_period_time = alsa_buffer_time/4;
629 if ((err = snd_pcm_hw_params_set_buffer_time_near(alsa_handler, alsa_hwparams,
630 &alsa_buffer_time, NULL)) < 0)
632 mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Unable to set buffer time near: %s\n",
633 snd_strerror(err));
634 return 0;
635 } else
636 alsa_buffer_time = err;
638 if ((err = snd_pcm_hw_params_set_period_time_near(alsa_handler, alsa_hwparams,
639 &alsa_period_time, NULL)) < 0)
640 /* original: alsa_buffer_time/ao_data.bps */
642 mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Unable to set period time: %s\n",
643 snd_strerror(err));
644 return 0;
646 mp_tmsg(MSGT_AO,MSGL_INFO,"[AO_ALSA] buffer_time: %d, period_time :%d\n",
647 alsa_buffer_time, err);
649 #endif//end SET_BUFFERTIME
651 #ifdef SET_CHUNKSIZE
653 //set chunksize
654 if ((err = snd_pcm_hw_params_set_period_size_near(alsa_handler, alsa_hwparams,
655 &chunk_size, NULL)) < 0)
657 mp_tmsg(MSGT_AO,MSGL_ERR,"[AO ALSA] Unable to set period size(%ld): %s\n",
658 chunk_size, snd_strerror(err));
659 return 0;
661 else {
662 mp_msg(MSGT_AO,MSGL_V,"alsa-init: chunksize set to %li\n", chunk_size);
664 if ((err = snd_pcm_hw_params_set_periods_near(alsa_handler, alsa_hwparams,
665 &alsa_fragcount, NULL)) < 0) {
666 mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Unable to set periods: %s\n",
667 snd_strerror(err));
668 return 0;
670 else {
671 mp_msg(MSGT_AO,MSGL_V,"alsa-init: fragcount=%i\n", alsa_fragcount);
674 #endif//end SET_CHUNKSIZE
676 /* finally install hardware parameters */
677 if ((err = snd_pcm_hw_params(alsa_handler, alsa_hwparams)) < 0)
679 mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Unable to set hw-parameters: %s\n",
680 snd_strerror(err));
681 return 0;
683 // end setting hw-params
686 // gets buffersize for control
687 if ((err = snd_pcm_hw_params_get_buffer_size(alsa_hwparams, &bufsize)) < 0)
689 mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Unable to get buffersize: %s\n", snd_strerror(err));
690 return 0;
692 else {
693 ao_data.buffersize = bufsize * bytes_per_sample;
694 mp_msg(MSGT_AO,MSGL_V,"alsa-init: got buffersize=%i\n", ao_data.buffersize);
697 if ((err = snd_pcm_hw_params_get_period_size(alsa_hwparams, &chunk_size, NULL)) < 0) {
698 mp_tmsg(MSGT_AO,MSGL_ERR,"[AO ALSA] Unable to get period size: %s\n", snd_strerror(err));
699 return 0;
700 } else {
701 mp_msg(MSGT_AO,MSGL_V,"alsa-init: got period size %li\n", chunk_size);
703 ao_data.outburst = chunk_size * bytes_per_sample;
705 /* setting software parameters */
706 if ((err = snd_pcm_sw_params_current(alsa_handler, alsa_swparams)) < 0) {
707 mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Unable to get sw-parameters: %s\n",
708 snd_strerror(err));
709 return 0;
711 #if SND_LIB_VERSION >= 0x000901
712 if ((err = snd_pcm_sw_params_get_boundary(alsa_swparams, &boundary)) < 0) {
713 mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Unable to get boundary: %s\n",
714 snd_strerror(err));
715 return 0;
717 #else
718 boundary = 0x7fffffff;
719 #endif
720 /* start playing when one period has been written */
721 if ((err = snd_pcm_sw_params_set_start_threshold(alsa_handler, alsa_swparams, chunk_size)) < 0) {
722 mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Unable to set start threshold: %s\n",
723 snd_strerror(err));
724 return 0;
726 /* disable underrun reporting */
727 if ((err = snd_pcm_sw_params_set_stop_threshold(alsa_handler, alsa_swparams, boundary)) < 0) {
728 mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Unable to set stop threshold: %s\n",
729 snd_strerror(err));
730 return 0;
732 #if SND_LIB_VERSION >= 0x000901
733 /* play silence when there is an underrun */
734 if ((err = snd_pcm_sw_params_set_silence_size(alsa_handler, alsa_swparams, boundary)) < 0) {
735 mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Unable to set silence size: %s\n",
736 snd_strerror(err));
737 return 0;
739 #endif
740 if ((err = snd_pcm_sw_params(alsa_handler, alsa_swparams)) < 0) {
741 mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Unable to get sw-parameters: %s\n",
742 snd_strerror(err));
743 return 0;
745 /* end setting sw-params */
747 mp_msg(MSGT_AO,MSGL_V,"alsa: %d Hz/%d channels/%d bpf/%d bytes buffer/%s\n",
748 ao_data.samplerate, ao_data.channels, (int)bytes_per_sample, ao_data.buffersize,
749 snd_pcm_format_description(alsa_format));
751 } // end switch alsa_handler (spdif)
752 alsa_can_pause = snd_pcm_hw_params_can_pause(alsa_hwparams);
753 return 1;
754 } // end init
757 /* close audio device */
758 static void uninit(int immed)
761 if (alsa_handler) {
762 int err;
764 if (!immed)
765 snd_pcm_drain(alsa_handler);
767 if ((err = snd_pcm_close(alsa_handler)) < 0)
769 mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] pcm close error: %s\n", snd_strerror(err));
770 return;
772 else {
773 alsa_handler = NULL;
774 mp_msg(MSGT_AO,MSGL_V,"alsa-uninit: pcm closed\n");
777 else {
778 mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] No handler defined!\n");
782 static void audio_pause(void)
784 int err;
786 if (alsa_can_pause) {
787 if ((err = snd_pcm_pause(alsa_handler, 1)) < 0)
789 mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] pcm pause error: %s\n", snd_strerror(err));
790 return;
792 mp_msg(MSGT_AO,MSGL_V,"alsa-pause: pause supported by hardware\n");
793 } else {
794 if (snd_pcm_delay(alsa_handler, &prepause_frames) < 0
795 || prepause_frames < 0)
796 prepause_frames = 0;
798 if ((err = snd_pcm_drop(alsa_handler)) < 0)
800 mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] pcm drop error: %s\n", snd_strerror(err));
801 return;
806 static void audio_resume(void)
808 int err;
810 if (snd_pcm_state(alsa_handler) == SND_PCM_STATE_SUSPENDED) {
811 mp_tmsg(MSGT_AO,MSGL_INFO,"[AO_ALSA] Pcm in suspend mode, trying to resume.\n");
812 while ((err = snd_pcm_resume(alsa_handler)) == -EAGAIN) sleep(1);
814 if (alsa_can_pause) {
815 if ((err = snd_pcm_pause(alsa_handler, 0)) < 0)
817 mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] pcm resume error: %s\n", snd_strerror(err));
818 return;
820 mp_msg(MSGT_AO,MSGL_V,"alsa-resume: resume supported by hardware\n");
821 } else {
822 if ((err = snd_pcm_prepare(alsa_handler)) < 0)
824 mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] pcm prepare error: %s\n", snd_strerror(err));
825 return;
827 if (prepause_frames) {
828 void *silence = calloc(prepause_frames, bytes_per_sample);
829 play(silence, prepause_frames * bytes_per_sample, 0);
830 free(silence);
835 /* stop playing and empty buffers (for seeking/pause) */
836 static void reset(void)
838 int err;
840 prepause_frames = 0;
841 if ((err = snd_pcm_drop(alsa_handler)) < 0)
843 mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] pcm prepare error: %s\n", snd_strerror(err));
844 return;
846 if ((err = snd_pcm_prepare(alsa_handler)) < 0)
848 mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] pcm prepare error: %s\n", snd_strerror(err));
849 return;
851 return;
855 plays 'len' bytes of 'data'
856 returns: number of bytes played
857 modified last at 29.06.02 by jp
858 thanxs for marius <marius@rospot.com> for giving us the light ;)
861 static int play(void* data, int len, int flags)
863 int num_frames = len / bytes_per_sample;
864 snd_pcm_sframes_t res = 0;
866 //mp_msg(MSGT_AO,MSGL_ERR,"alsa-play: frames=%i, len=%i\n",num_frames,len);
868 if (!alsa_handler) {
869 mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Device configuration error.");
870 return 0;
873 if (num_frames == 0)
874 return 0;
876 do {
877 res = snd_pcm_writei(alsa_handler, data, num_frames);
879 if (res == -EINTR) {
880 /* nothing to do */
881 res = 0;
883 else if (res == -ESTRPIPE) { /* suspend */
884 mp_tmsg(MSGT_AO,MSGL_INFO,"[AO_ALSA] Pcm in suspend mode, trying to resume.\n");
885 while ((res = snd_pcm_resume(alsa_handler)) == -EAGAIN)
886 sleep(1);
888 if (res < 0) {
889 mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Write error: %s\n", snd_strerror(res));
890 mp_tmsg(MSGT_AO,MSGL_INFO,"[AO_ALSA] Trying to reset soundcard.\n");
891 if ((res = snd_pcm_prepare(alsa_handler)) < 0) {
892 mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] pcm prepare error: %s\n", snd_strerror(res));
893 return 0;
894 break;
897 } while (res == 0);
899 return res < 0 ? res : res * bytes_per_sample;
902 /* how many byes are free in the buffer */
903 static int get_space(void)
905 snd_pcm_status_t *status;
906 int ret;
908 snd_pcm_status_alloca(&status);
910 if ((ret = snd_pcm_status(alsa_handler, status)) < 0)
912 mp_tmsg(MSGT_AO,MSGL_ERR,"[AO_ALSA] Cannot get pcm status: %s\n", snd_strerror(ret));
913 return 0;
916 unsigned space = snd_pcm_status_get_avail(status) * bytes_per_sample;
917 if (space > ao_data.buffersize) // Buffer underrun?
918 space = ao_data.buffersize;
919 return space;
922 /* delay in seconds between first and last sample in buffer */
923 static float get_delay(void)
925 if (alsa_handler) {
926 snd_pcm_sframes_t delay;
928 if (snd_pcm_delay(alsa_handler, &delay) < 0)
929 return 0;
931 if (delay < 0) {
932 /* underrun - move the application pointer forward to catch up */
933 #if SND_LIB_VERSION >= 0x000901 /* snd_pcm_forward() exists since 0.9.0rc8 */
934 snd_pcm_forward(alsa_handler, -delay);
935 #endif
936 delay = 0;
938 return (float)delay / (float)ao_data.samplerate;
939 } else {
940 return 0;