constant qscale was broken due to libavcodec changes, fix taken from ve_lavc.c
[mplayer/greg.git] / libao2 / ao_alsa9.c
blobce43b7e843f7b7f02bf92d6f57ea6b62bb1c1972
1 /*
2 ao_alsa9 - ALSA-0.9.x output plugin for MPlayer
4 (C) Alex Beregszaszi
6 modified for real alsa-0.9.0-support by Joy Winter <joy@pingfm.org>
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, joy
10 Any bugreports regarding to this driver are welcome.
13 #include <errno.h>
14 #include <sys/time.h>
15 #include <stdlib.h>
16 #include <math.h>
17 #include <string.h>
18 #include <sys/poll.h>
20 #include "../config.h"
22 #if HAVE_SYS_ASOUNDLIB_H
23 #include <sys/asoundlib.h>
24 #elif HAVE_ALSA_ASOUNDLIB_H
25 #include <alsa/asoundlib.h>
26 #else
27 #error "asoundlib.h is not in sys/ or alsa/ - please bugreport"
28 #endif
30 #include "audio_out.h"
31 #include "audio_out_internal.h"
32 #include "afmt.h"
34 extern int verbose;
36 static ao_info_t info =
38 "ALSA-0.9.x audio output",
39 "alsa9",
40 "Alex Beregszaszi, Joy Winter <joy@pingfm.org>",
41 "under developement"
44 LIBAO_EXTERN(alsa9)
47 static snd_pcm_t *alsa_handler;
48 static snd_pcm_format_t alsa_format;
49 static snd_pcm_hw_params_t *alsa_hwparams;
50 static snd_pcm_sw_params_t *alsa_swparams;
51 static char *alsa_device;
53 /* possible 4096, original 8192
54 * was only needed for calculating chunksize? */
55 static int alsa_fragsize = 4096;
56 /* 16 sets buffersize to 16 * chunksize is as default 1024
57 * which seems to be good avarge for most situations
58 * so buffersize is 16384 frames by default */
59 static int alsa_fragcount = 16;
60 static int chunk_size = 1024; //is alsa_fragsize / 4
62 #define MIN_CHUNK_SIZE 1024
64 static size_t bits_per_sample, bytes_per_sample, bits_per_frame;
65 static size_t chunk_bytes;
67 int ao_mmap = 0;
68 int ao_noblock = 0;
69 int first = 1;
71 static int open_mode;
72 static int set_block_mode;
73 static int alsa_can_pause = 0;
75 #define ALSA_DEVICE_SIZE 48
77 #undef BUFFERTIME
78 #define SET_CHUNKSIZE
79 #undef USE_POLL
82 /* to set/get/query special features/parameters */
83 static int control(int cmd, void *arg)
85 switch(cmd) {
86 case AOCONTROL_QUERY_FORMAT:
87 return CONTROL_TRUE;
88 #ifndef WORDS_BIGENDIAN
89 case AOCONTROL_GET_VOLUME:
90 case AOCONTROL_SET_VOLUME:
92 ao_control_vol_t *vol = (ao_control_vol_t *)arg;
94 int err;
95 snd_mixer_t *handle;
96 snd_mixer_elem_t *elem;
97 snd_mixer_selem_id_t *sid;
99 const char *mix_name = "PCM";
100 char *card = "default";
102 long pmin, pmax;
103 long get_vol, set_vol;
104 float calc_vol, diff, f_multi;
106 if(ao_data.format == AFMT_AC3)
107 return CONTROL_TRUE;
109 //allocate simple id
110 snd_mixer_selem_id_alloca(&sid);
112 //sets simple-mixer index and name
113 snd_mixer_selem_id_set_index(sid, 0);
114 snd_mixer_selem_id_set_name(sid, mix_name);
116 if ((err = snd_mixer_open(&handle, 0)) < 0) {
117 printf("alsa-control: mixer open error: %s\n", snd_strerror(err));
118 return CONTROL_ERROR;
121 if ((err = snd_mixer_attach(handle, card)) < 0) {
122 printf("alsa-control: mixer attach %s error: %s", card, snd_strerror(err));
123 snd_mixer_close(handle);
124 return CONTROL_ERROR;
127 if ((err = snd_mixer_selem_register(handle, NULL, NULL)) < 0) {
128 printf("alsa-control: mixer register error: %s", snd_strerror(err));
129 snd_mixer_close(handle);
130 return CONTROL_ERROR;
132 err = snd_mixer_load(handle);
133 if (err < 0) {
134 printf("alsa-control: mixer load error: %s", snd_strerror(err));
135 snd_mixer_close(handle);
136 return CONTROL_ERROR;
139 elem = snd_mixer_find_selem(handle, sid);
140 if (!elem) {
141 printf("alsa-control: unable to find simple control '%s',%i\n", snd_mixer_selem_id_get_name(sid), snd_mixer_selem_id_get_index(sid));
142 snd_mixer_close(handle);
143 return CONTROL_ERROR;
146 snd_mixer_selem_get_playback_volume_range(elem,&pmin,&pmax);
147 f_multi = (100 / (float)pmax);
149 if (cmd == AOCONTROL_SET_VOLUME) {
151 diff = (vol->left+vol->right) / 2;
152 set_vol = rint(diff / f_multi);
154 if (set_vol < 0)
155 set_vol = 0;
156 else if (set_vol > pmax)
157 set_vol = pmax;
159 //setting channels
160 if ((err = snd_mixer_selem_set_playback_volume(elem, 0, set_vol)) < 0) {
161 printf("alsa-control: error setting left channel, %s",snd_strerror(err));
162 return CONTROL_ERROR;
164 if ((err = snd_mixer_selem_set_playback_volume(elem, 1, set_vol)) < 0) {
165 printf("alsa-control: error setting right channel, %s",snd_strerror(err));
166 return CONTROL_ERROR;
169 //printf("diff=%f, set_vol=%i, pmax=%i, mult=%f\n", diff, set_vol, pmax, f_multi);
171 else {
172 snd_mixer_selem_get_playback_volume(elem, 0, &get_vol);
173 calc_vol = get_vol;
174 calc_vol = rintf(calc_vol * f_multi);
176 vol->left = vol->right = (int)calc_vol;
178 //printf("get_vol = %i, calc=%i\n",get_vol, calc_vol);
180 snd_mixer_close(handle);
181 return CONTROL_OK;
183 #endif
185 } //end switch
186 return(CONTROL_UNKNOWN);
191 open & setup audio device
192 return: 1=success 0=fail
194 static int init(int rate_hz, int channels, int format, int flags)
196 int err;
197 int cards = -1;
198 int period_val;
199 snd_pcm_info_t *alsa_info;
200 char *str_block_mode;
201 int device_set = 0;
203 printf("alsa-init: requested format: %d Hz, %d channels, %s\n", rate_hz,
204 channels, audio_out_format_name(format));
206 alsa_handler = NULL;
208 if (verbose>0)
209 printf("alsa-init: compiled for ALSA-%s\n", SND_LIB_VERSION_STR);
211 if ((err = snd_card_next(&cards)) < 0 || cards < 0)
213 printf("alsa-init: no soundcards found: %s\n", snd_strerror(err));
214 return(0);
217 ao_data.samplerate = rate_hz;
218 ao_data.bps = channels * rate_hz;
219 ao_data.format = format;
220 ao_data.channels = channels;
221 ao_data.outburst = OUTBURST;
222 //ao_data.buffersize = MAX_OUTBURST; // was 16384
224 switch (format)
226 case AFMT_S8:
227 alsa_format = SND_PCM_FORMAT_S8;
228 break;
229 case AFMT_U8:
230 alsa_format = SND_PCM_FORMAT_U8;
231 break;
232 case AFMT_U16_LE:
233 alsa_format = SND_PCM_FORMAT_U16_LE;
234 break;
235 case AFMT_U16_BE:
236 alsa_format = SND_PCM_FORMAT_U16_BE;
237 break;
238 #ifndef WORDS_BIGENDIAN
239 case AFMT_AC3:
240 #endif
241 case AFMT_S16_LE:
242 alsa_format = SND_PCM_FORMAT_S16_LE;
243 break;
244 #ifdef WORDS_BIGENDIAN
245 case AFMT_AC3:
246 #endif
247 case AFMT_S16_BE:
248 alsa_format = SND_PCM_FORMAT_S16_BE;
249 break;
250 case AFMT_S32_LE:
251 alsa_format = SND_PCM_FORMAT_S32_LE;
252 break;
253 case AFMT_S32_BE:
254 alsa_format = SND_PCM_FORMAT_S32_BE;
255 break;
257 default:
258 alsa_format = SND_PCM_FORMAT_MPEG;
259 break;
262 switch(alsa_format)
264 case SND_PCM_FORMAT_S16_LE:
265 case SND_PCM_FORMAT_U16_LE:
266 ao_data.bps *= 2;
267 break;
268 case SND_PCM_FORMAT_S32_LE:
269 case SND_PCM_FORMAT_S32_BE:
270 ao_data.bps *= 4;
271 break;
272 case -1:
273 printf("alsa-init: invalid format (%s) requested - output disabled\n",
274 audio_out_format_name(format));
275 return(0);
276 default:
277 break;
280 if (ao_subdevice) {
281 //start parsing ao_subdevice, ugly and not thread safe!
282 //maybe there's a better way?
283 int i2 = 1;
284 int i3 = 0;
285 char *sub_str;
287 char *token_str[3];
288 char* test_str = strdup(ao_subdevice);
291 if ((strcspn(ao_subdevice, ":")) > 0) {
293 sub_str = strtok(test_str, ":");
294 *(token_str) = sub_str;
296 while (((sub_str = strtok(NULL, ":")) != NULL) && (i2 <= 3)) {
297 *(token_str+i2) = sub_str;
298 i2 += 1;
301 for (i3=0; i3 <= i2-1; i3++) {
302 if (strcmp(*(token_str + i3), "mmap") == 0) {
303 ao_mmap = 1;
305 else if (strcmp(*(token_str+i3), "noblock") == 0) {
306 ao_noblock = 1;
308 else if (strcmp(*(token_str+i3), "hw") == 0) {
309 if ((i3 < i2-1) && (strcmp(*(token_str+i3+1), "noblock") != 0) && (strcmp(*(token_str+i3+1), "mmap") != 0)) {
310 char *tmp;
312 alsa_device = alloca(ALSA_DEVICE_SIZE);
313 snprintf(alsa_device, ALSA_DEVICE_SIZE, "hw:%s", *(token_str+(i3+1)));
314 if ((tmp = strrchr(alsa_device, '.')) && isdigit(*(tmp+1)))
315 *tmp = ',';
316 device_set = 1;
318 else {
319 alsa_device = *(token_str+i3);
320 device_set = 1;
323 else if (device_set == 0 && (!ao_mmap || !ao_noblock)) {
324 alsa_device = *(token_str+i3);
325 device_set = 1;
329 } else { //end parsing ao_subdevice
330 /* in any case for multichannel playback we should select
331 * appropriate device
333 char devstr[128];
335 switch (channels) {
336 case 4:
337 strcpy(devstr, "surround40");
338 alsa_device = devstr;
339 break;
340 case 6:
341 strcpy(devstr, "surround51");
342 alsa_device = devstr;
343 break;
344 default:
349 /* switch for spdif
350 * sets opening sequence for SPDIF
351 * sets also the playback and other switches 'on the fly'
352 * while opening the abstract alias for the spdif subdevice
353 * 'iec958'
355 if (format == AFMT_AC3) {
356 char devstr[128];
357 unsigned char s[4];
358 int err, c;
360 switch (channels) {
361 case 1:
362 case 2:
364 s[0] = IEC958_AES0_NONAUDIO |
365 IEC958_AES0_CON_EMPHASIS_NONE;
366 s[1] = IEC958_AES1_CON_ORIGINAL |
367 IEC958_AES1_CON_PCM_CODER;
368 s[2] = 0;
369 s[3] = IEC958_AES3_CON_FS_48000;
371 sprintf(devstr, "iec958:AES0=0x%x,AES1=0x%x,AES2=0x%x,AES3=0x%x",
372 s[0], s[1], s[2], s[3]);
374 if (verbose>0)
375 printf("alsa-spdif-init: playing AC3, %i channels\n", channels);
376 break;
377 case 4:
378 strcpy(devstr, "surround40");
379 break;
381 case 6:
382 strcpy(devstr, "surround51");
383 break;
385 default:
386 fprintf(stderr, "%d channels are not supported\n", channels);
387 return(0);
390 alsa_device = devstr;
393 if (alsa_device == NULL)
395 int tmp_device, tmp_subdevice, err;
397 if ((err = snd_pcm_info_malloc(&alsa_info)) < 0)
399 printf("alsa-init: memory allocation error: %s\n", snd_strerror(err));
400 return(0);
403 if ((alsa_device = alloca(ALSA_DEVICE_SIZE)) == NULL)
405 printf("alsa-init: memory allocation error: %s\n", strerror(errno));
406 return(0);
409 if ((tmp_device = snd_pcm_info_get_device(alsa_info)) < 0)
411 printf("alsa-init: can't get device\n");
412 return(0);
415 if ((tmp_subdevice = snd_pcm_info_get_subdevice(alsa_info)) < 0)
417 printf("alsa-init: can't get subdevice\n");
418 return(0);
421 if (verbose>0)
422 printf("alsa-init: got device=%i, subdevice=%i\n", tmp_device, tmp_subdevice);
424 if ((err = snprintf(alsa_device, ALSA_DEVICE_SIZE, "hw:%1d,%1d", tmp_device, tmp_subdevice)) <= 0)
426 printf("alsa-init: can't write device-id\n");
429 snd_pcm_info_free(alsa_info);
430 printf("alsa-init: %d soundcard%s found, using: %s\n", cards+1,
431 (cards >= 0) ? "" : "s", alsa_device);
432 } else if (strcmp(alsa_device, "help") == 0) {
433 printf("alsa-help: available options are:\n");
434 printf(" mmap: sets mmap-mode\n");
435 printf(" noblock: sets noblock-mode\n");
436 printf(" device-name: sets device name (change comma to point)\n");
437 printf(" example -ao alsa9:mmap:noblock:hw:0.3 sets noblock-mode,\n");
438 printf(" mmap-mode and the device-name as first card fourth device\n");
439 return(0);
440 } else {
441 printf("alsa-init: soundcard set to %s\n", alsa_device);
444 //setting modes for block or nonblock-mode
445 if (ao_noblock) {
446 open_mode = SND_PCM_NONBLOCK;
447 set_block_mode = 1;
448 str_block_mode = "nonblock-mode";
450 else {
451 open_mode = 0;
452 set_block_mode = 0;
453 str_block_mode = "block-mode";
456 //sets buff/chunksize if its set manually
457 if (ao_data.buffersize) {
458 switch (ao_data.buffersize)
460 case 1:
461 alsa_fragcount = 16;
462 chunk_size = 512;
463 if (verbose>0) {
464 printf("alsa-init: buffersize set manually to 8192\n");
465 printf("alsa-init: chunksize set manually to 512\n");
467 break;
468 case 2:
469 alsa_fragcount = 8;
470 chunk_size = 1024;
471 if (verbose>0) {
472 printf("alsa-init: buffersize set manually to 8192\n");
473 printf("alsa-init: chunksize set manually to 1024\n");
475 break;
476 case 3:
477 alsa_fragcount = 32;
478 chunk_size = 512;
479 if (verbose>0) {
480 printf("alsa-init: buffersize set manually to 16384\n");
481 printf("alsa-init: chunksize set manually to 512\n");
483 break;
484 case 4:
485 alsa_fragcount = 16;
486 chunk_size = 1024;
487 if (verbose>0) {
488 printf("alsa-init: buffersize set manually to 16384\n");
489 printf("alsa-init: chunksize set manually to 1024\n");
491 break;
492 default:
493 alsa_fragcount = 16;
494 if (ao_mmap)
495 chunk_size = 512;
496 else
497 chunk_size = 1024;
498 break;
502 if (!alsa_handler) {
503 //modes = 0, SND_PCM_NONBLOCK, SND_PCM_ASYNC
504 if ((err = snd_pcm_open(&alsa_handler, alsa_device, SND_PCM_STREAM_PLAYBACK, open_mode)) < 0)
506 if (err != -EBUSY && ao_noblock) {
507 printf("alsa-init: open in nonblock-mode failed, trying to open in block-mode\n");
508 if ((err = snd_pcm_open(&alsa_handler, alsa_device, SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
509 printf("alsa-init: playback open error: %s\n", snd_strerror(err));
510 return(0);
511 } else {
512 set_block_mode = 0;
513 str_block_mode = "block-mode";
515 } else {
516 printf("alsa-init: playback open error: %s\n", snd_strerror(err));
517 return(0);
521 if ((err = snd_pcm_nonblock(alsa_handler, set_block_mode)) < 0) {
522 printf("alsa-init: error set block-mode %s\n", snd_strerror(err));
524 else if (verbose>0) {
525 printf("alsa-init: pcm opend in %s\n", str_block_mode);
528 snd_pcm_hw_params_alloca(&alsa_hwparams);
529 snd_pcm_sw_params_alloca(&alsa_swparams);
531 // setting hw-parameters
532 if ((err = snd_pcm_hw_params_any(alsa_handler, alsa_hwparams)) < 0)
534 printf("alsa-init: unable to get initial parameters: %s\n",
535 snd_strerror(err));
536 return(0);
539 if (ao_mmap) {
540 snd_pcm_access_mask_t *mask = alloca(snd_pcm_access_mask_sizeof());
541 snd_pcm_access_mask_none(mask);
542 snd_pcm_access_mask_set(mask, SND_PCM_ACCESS_MMAP_INTERLEAVED);
543 snd_pcm_access_mask_set(mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED);
544 snd_pcm_access_mask_set(mask, SND_PCM_ACCESS_MMAP_COMPLEX);
545 err = snd_pcm_hw_params_set_access_mask(alsa_handler, alsa_hwparams, mask);
546 printf("alsa-init: mmap set\n");
547 } else {
548 err = snd_pcm_hw_params_set_access(alsa_handler, alsa_hwparams,SND_PCM_ACCESS_RW_INTERLEAVED);
550 if (err < 0) {
551 printf("alsa-init: unable to set access type: %s\n", snd_strerror(err));
552 return (0);
555 /* workaround for nonsupported formats
556 sets default format to S16_LE if the given formats aren't supported */
557 if ((err = snd_pcm_hw_params_test_format(alsa_handler, alsa_hwparams,
558 alsa_format)) < 0)
560 printf("alsa-init: format %s are not supported by hardware, trying default\n",
561 audio_out_format_name(format));
562 alsa_format = SND_PCM_FORMAT_S16_LE;
563 ao_data.format = AFMT_S16_LE;
564 ao_data.bps = channels * rate_hz * 2;
567 bytes_per_sample = ao_data.bps / ao_data.samplerate; //it should be here
570 if ((err = snd_pcm_hw_params_set_format(alsa_handler, alsa_hwparams,
571 alsa_format)) < 0)
573 printf("alsa-init: unable to set format: %s\n",
574 snd_strerror(err));
575 return(0);
578 if ((err = snd_pcm_hw_params_set_channels(alsa_handler, alsa_hwparams,
579 ao_data.channels)) < 0)
581 printf("alsa-init: unable to set channels: %s\n",
582 snd_strerror(err));
583 return(0);
586 if ((err = snd_pcm_hw_params_set_rate_near(alsa_handler, alsa_hwparams, ao_data.samplerate, 0)) < 0)
588 printf("alsa-init: unable to set samplerate-2: %s\n",
589 snd_strerror(err));
590 return(0);
593 #ifdef BUFFERTIME
595 int alsa_buffer_time = 500000; /* original 60 */
597 if ((err = snd_pcm_hw_params_set_buffer_time_near(alsa_handler, alsa_hwparams, alsa_buffer_time, 0)) < 0)
599 printf("alsa-init: unable to set buffer time near: %s\n",
600 snd_strerror(err));
601 return(0);
602 } else
603 alsa_buffer_time = err;
605 if ((err = snd_pcm_hw_params_set_period_time_near(alsa_handler, alsa_hwparams, alsa_buffer_time/4, 0)) < 0)
606 /* original: alsa_buffer_time/ao_data.bps */
608 printf("alsa-init: unable to set period time: %s\n",
609 snd_strerror(err));
610 return(0);
612 if (verbose>0)
613 printf("alsa-init: buffer_time: %d, period_time :%d\n",alsa_buffer_time, err);
615 #endif
617 #ifdef SET_CHUNKSIZE
619 //set chunksize
620 if ((err = snd_pcm_hw_params_set_period_size(alsa_handler, alsa_hwparams, chunk_size, 0)) < 0)
622 printf("alsa-init: unable to set periodsize: %s\n", snd_strerror(err));
623 return(0);
625 else if (verbose>0) {
626 printf("alsa-init: chunksize set to %i\n", chunk_size);
629 //set period_count
630 if ((period_val = snd_pcm_hw_params_get_periods_max(alsa_hwparams, 0)) < alsa_fragcount) {
631 alsa_fragcount = period_val;
634 if (verbose>0)
635 printf("alsa-init: current val=%i, fragcount=%i\n", period_val, alsa_fragcount);
637 if ((err = snd_pcm_hw_params_set_periods(alsa_handler, alsa_hwparams, alsa_fragcount, 0)) < 0) {
638 printf("alsa-init: unable to set periods: %s\n", snd_strerror(err));
641 #endif
643 /* finally install hardware parameters */
644 if ((err = snd_pcm_hw_params(alsa_handler, alsa_hwparams)) < 0)
646 printf("alsa-init: unable to set hw-parameters: %s\n",
647 snd_strerror(err));
648 return(0);
650 // end setting hw-params
653 // gets buffersize for control
654 if ((err = snd_pcm_hw_params_get_buffer_size(alsa_hwparams)) < 0)
656 printf("alsa-init: unable to get buffersize: %s\n", snd_strerror(err));
657 return(0);
659 else {
660 ao_data.buffersize = err * bytes_per_sample;
661 if (verbose>0)
662 printf("alsa-init: got buffersize=%i\n", ao_data.buffersize);
665 // setting sw-params (only avail-min) if noblocking mode was choosed
666 if (ao_noblock)
669 if ((err = snd_pcm_sw_params_current(alsa_handler, alsa_swparams)) < 0)
671 printf("alsa-init: unable to get parameters: %s\n",snd_strerror(err));
672 return(0);
675 //set min available frames to consider pcm ready (4)
676 //increased for nonblock-mode should be set dynamically later
677 if ((err = snd_pcm_sw_params_set_avail_min(alsa_handler, alsa_swparams, 4)) < 0)
679 printf("alsa-init: unable to set avail_min %s\n",snd_strerror(err));
680 return(0);
683 if ((err = snd_pcm_sw_params(alsa_handler, alsa_swparams)) < 0)
685 printf("alsa-init: unable to install sw-params\n");
686 return(0);
689 bits_per_sample = snd_pcm_format_physical_width(alsa_format);
690 bits_per_frame = bits_per_sample * channels;
691 chunk_bytes = chunk_size * bits_per_frame / 8;
693 if (verbose>0) {
694 printf("alsa-init: bits per sample (bps)=%i, bits per frame (bpf)=%i, chunk_bytes=%i\n",bits_per_sample,bits_per_frame,chunk_bytes);}
696 }//end swparams
698 if ((err = snd_pcm_prepare(alsa_handler)) < 0)
700 printf("alsa-init: pcm prepare error: %s\n", snd_strerror(err));
701 return(0);
704 printf("alsa9: %d Hz/%d channels/%d bpf/%d bytes buffer/%s\n",
705 ao_data.samplerate, ao_data.channels, bytes_per_sample, ao_data.buffersize,
706 snd_pcm_format_description(alsa_format));
708 } // end switch alsa_handler (spdif)
709 alsa_can_pause = snd_pcm_hw_params_can_pause(alsa_hwparams);
710 return(1);
711 } // end init
714 /* close audio device */
715 static void uninit()
718 if (alsa_handler) {
719 int err;
721 if (!ao_noblock) {
722 if ((err = snd_pcm_drop(alsa_handler)) < 0)
724 printf("alsa-uninit: pcm drop error: %s\n", snd_strerror(err));
725 return;
729 if ((err = snd_pcm_close(alsa_handler)) < 0)
731 printf("alsa-uninit: pcm close error: %s\n", snd_strerror(err));
732 return;
734 else {
735 alsa_handler = NULL;
736 alsa_device = NULL;
737 printf("alsa-uninit: pcm closed\n");
740 else {
741 printf("alsa-uninit: no handler defined!\n");
745 static void audio_pause()
747 int err;
749 if (alsa_can_pause) {
750 if ((err = snd_pcm_pause(alsa_handler, 1)) < 0)
752 printf("alsa-pause: pcm pause error: %s\n", snd_strerror(err));
753 return;
755 if (verbose)
756 printf("alsa-pause: pause supported by hardware\n");
757 } else {
758 if ((err = snd_pcm_drop(alsa_handler)) < 0)
760 printf("alsa-pause: pcm drop error: %s\n", snd_strerror(err));
761 return;
766 static void audio_resume()
768 int err;
770 if (alsa_can_pause) {
771 if ((err = snd_pcm_pause(alsa_handler, 0)) < 0)
773 printf("alsa-resume: pcm resume error: %s\n", snd_strerror(err));
774 return;
776 if (verbose)
777 printf("alsa-resume: resume supported by hardware\n");
778 } else {
779 if ((err = snd_pcm_prepare(alsa_handler)) < 0)
781 printf("alsa-resume: pcm prepare error: %s\n", snd_strerror(err));
782 return;
787 /* stop playing and empty buffers (for seeking/pause) */
788 static void reset()
790 int err;
792 if ((err = snd_pcm_drop(alsa_handler)) < 0)
794 printf("alsa-reset: pcm drop error: %s\n", snd_strerror(err));
795 return;
797 if ((err = snd_pcm_prepare(alsa_handler)) < 0)
799 printf("alsa-reset: pcm prepare error: %s\n", snd_strerror(err));
800 return;
802 return;
805 #ifdef USE_POLL
806 static int wait_for_poll(snd_pcm_t *handle, struct pollfd *ufds, unsigned int count)
808 unsigned short revents;
810 while (1) {
811 poll(ufds, count, -1);
812 snd_pcm_poll_descriptors_revents(handle, ufds, count, &revents);
813 if (revents & POLLERR)
814 return -EIO;
815 if (revents & POLLOUT)
816 return 0;
819 #endif
821 #ifndef timersub
822 #define timersub(a, b, result) \
823 do { \
824 (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \
825 (result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \
826 if ((result)->tv_usec < 0) { \
827 --(result)->tv_sec; \
828 (result)->tv_usec += 1000000; \
830 } while (0)
831 #endif
833 /* I/O error handler */
834 static int xrun(u_char *str_mode)
836 int err;
837 snd_pcm_status_t *status;
839 snd_pcm_status_alloca(&status);
841 if ((err = snd_pcm_status(alsa_handler, status))<0) {
842 printf("status error: %s", snd_strerror(err));
843 return(0);
846 if (snd_pcm_status_get_state(status) == SND_PCM_STATE_XRUN) {
847 struct timeval now, diff, tstamp;
848 gettimeofday(&now, 0);
849 snd_pcm_status_get_trigger_tstamp(status, &tstamp);
850 timersub(&now, &tstamp, &diff);
851 printf("alsa-%s: xrun of at least %.3f msecs. resetting stream\n",
852 str_mode,
853 diff.tv_sec * 1000 + diff.tv_usec / 1000.0);
856 if ((err = snd_pcm_prepare(alsa_handler))<0) {
857 printf("xrun: prepare error: %s", snd_strerror(err));
858 return(0);
861 return(1); /* ok, data should be accepted again */
864 static int play_normal(void* data, int len);
865 static int play_mmap(void* data, int len);
867 static int play(void* data, int len, int flags)
869 int result;
870 if (ao_mmap)
871 result = play_mmap(data, len);
872 else
873 result = play_normal(data, len);
875 return result;
879 plays 'len' bytes of 'data'
880 returns: number of bytes played
881 modified last at 29.06.02 by jp
882 thanxs for marius <marius@rospot.com> for giving us the light ;)
885 static int play_normal(void* data, int len)
888 //bytes_per_sample is always 4 for 2 chn S16_LE
889 int num_frames = len / bytes_per_sample;
890 char *output_samples = (char *)data;
891 snd_pcm_sframes_t res = 0;
893 //fprintf(stderr,"alsa-play: frames=%i, len=%i\n",num_frames,len);
895 if (!alsa_handler) {
896 printf("alsa-play: device configuration error");
897 return 0;
900 while (num_frames > 0) {
902 res = snd_pcm_writei(alsa_handler, (void *)output_samples, num_frames);
904 if (res == -EAGAIN) {
905 snd_pcm_wait(alsa_handler, 1000);
907 else if (res == -EPIPE) { /* underrun */
908 if (xrun("play") <= 0) {
909 printf("alsa-play: xrun reset error");
910 return(0);
913 else if (res == -ESTRPIPE) { /* suspend */
914 printf("alsa-play: pcm in suspend mode. trying to resume\n");
915 while ((res = snd_pcm_resume(alsa_handler)) == -EAGAIN)
916 sleep(1);
918 else if (res < 0) {
919 printf("alsa-play: unknown status, trying to reset soundcard\n");
920 if ((res = snd_pcm_prepare(alsa_handler)) < 0) {
921 printf("alsa-play: snd prepare error");
922 return(0);
923 break;
927 if (res > 0) {
929 /* output_samples += ao_data.channels * res; */
930 output_samples += res * bytes_per_sample;
932 num_frames -= res;
935 } //end while
937 if (res < 0) {
938 printf("alsa-play: write error %s", snd_strerror(res));
939 return 0;
941 return res < 0 ? (int)res : len - len % bytes_per_sample;
944 /* mmap-mode mainly based on descriptions by Joshua Haberman <joshua@haberman.com>
945 * 'An overview of the ALSA API' http://people.debian.org/~joshua/x66.html
946 * and some help by Paul Davis <pbd@op.net> */
948 static int play_mmap(void* data, int len)
950 snd_pcm_sframes_t commitres, frames_available;
951 snd_pcm_uframes_t frames_transmit, size, offset;
952 const snd_pcm_channel_area_t *area;
953 void *outbuffer;
954 int err, result;
956 #ifdef USE_POLL //seems not really be needed
957 struct pollfd *ufds;
958 int count;
960 count = snd_pcm_poll_descriptors_count (alsa_handler);
961 ufds = malloc(sizeof(struct pollfd) * count);
962 snd_pcm_poll_descriptors(alsa_handler, ufds, count);
964 //first wait_for_poll
965 if (err = (wait_for_poll(alsa_handler, ufds, count) < 0)) {
966 if (snd_pcm_state(alsa_handler) == SND_PCM_STATE_XRUN ||
967 snd_pcm_state(alsa_handler) == SND_PCM_STATE_SUSPENDED) {
968 xrun("play");
971 #endif
973 outbuffer = alloca(ao_data.buffersize);
975 //don't trust get_space() ;)
976 frames_available = snd_pcm_avail_update(alsa_handler) * bytes_per_sample;
977 if (frames_available < 0)
978 xrun("play");
980 if (frames_available < 4) {
981 if (first) {
982 first = 0;
983 snd_pcm_start(alsa_handler);
985 else { //FIXME should break and return 0?
986 snd_pcm_wait(alsa_handler, -1);
987 first = 1;
991 /* len is simply the available bufferspace got by get_space()
992 * but real avail_buffer in frames is ab/bytes_per_sample */
993 size = len / bytes_per_sample;
995 //if (verbose)
996 //printf("len: %i size %i, f_avail %i, bps %i ...\n", len, size, frames_available, bytes_per_sample);
998 frames_transmit = size;
1000 /* prepare areas and set sw-pointers
1001 * frames_transmit returns the real available buffer-size
1002 * sometimes != frames_available cause of ringbuffer 'emulation' */
1003 snd_pcm_mmap_begin(alsa_handler, &area, &offset, &frames_transmit);
1005 /* this is specific to interleaved streams (or non-interleaved
1006 * streams with only one channel) */
1007 outbuffer = ((char *) area->addr + (area->first + area->step * offset) / 8); //8
1009 //write data
1010 memcpy(outbuffer, data, (frames_transmit * bytes_per_sample));
1012 commitres = snd_pcm_mmap_commit(alsa_handler, offset, frames_transmit);
1014 if (commitres < 0 || commitres != frames_transmit) {
1015 if (snd_pcm_state(alsa_handler) == SND_PCM_STATE_XRUN ||
1016 snd_pcm_state(alsa_handler) == SND_PCM_STATE_SUSPENDED) {
1017 xrun("play");
1021 //if (verbose)
1022 //printf("mmap ft: %i, cres: %i\n", frames_transmit, commitres);
1024 /* err = snd_pcm_area_copy(&area, offset, &data, offset, len, alsa_format); */
1025 /* if (err < 0) { */
1026 /* printf("area-copy-error\n"); */
1027 /* return 0; */
1028 /* } */
1031 //calculate written frames!
1032 result = commitres * bytes_per_sample;
1035 /* if (verbose) { */
1036 /* if (len == result) */
1037 /* printf("result: %i, frames written: %i ...\n", result, frames_transmit); */
1038 /* else */
1039 /* printf("result: %i, frames written: %i, result != len ...\n", result, frames_transmit); */
1040 /* } */
1042 //mplayer doesn't like -result
1043 if (result < 0)
1044 result = 0;
1046 #ifdef USE_POLL
1047 free(ufds);
1048 #endif
1050 return result;
1053 /* how many byes are free in the buffer */
1054 static int get_space()
1056 snd_pcm_status_t *status;
1057 int ret;
1058 char *str_status;
1060 //snd_pcm_sframes_t avail_frames = 0;
1062 if ((ret = snd_pcm_status_malloc(&status)) < 0)
1064 printf("alsa-space: memory allocation error: %s\n", snd_strerror(ret));
1065 return(0);
1068 if ((ret = snd_pcm_status(alsa_handler, status)) < 0)
1070 printf("alsa-space: cannot get pcm status: %s\n", snd_strerror(ret));
1071 return(0);
1074 switch(snd_pcm_status_get_state(status))
1076 case SND_PCM_STATE_OPEN:
1077 str_status = "open";
1078 case SND_PCM_STATE_PREPARED:
1079 if (str_status != "open") {
1080 str_status = "prepared";
1081 first = 1;
1082 ret = snd_pcm_status_get_avail(status) * bytes_per_sample;
1083 if (ret == 0) //ugly workaround for hang in mmap-mode
1084 ret = 10;
1085 break;
1087 case SND_PCM_STATE_RUNNING:
1088 ret = snd_pcm_status_get_avail(status) * bytes_per_sample;
1089 //avail_frames = snd_pcm_avail_update(alsa_handler) * bytes_per_sample;
1090 if (str_status != "open" && str_status != "prepared")
1091 str_status = "running";
1092 break;
1093 case SND_PCM_STATE_PAUSED:
1094 if (verbose>0) printf("alsa-space: paused");
1095 str_status = "paused";
1096 ret = 0;
1097 break;
1098 case SND_PCM_STATE_XRUN:
1099 xrun("space");
1100 str_status = "xrun";
1101 first = 1;
1102 ret = 0;
1103 break;
1104 default:
1105 str_status = "undefined";
1106 ret = snd_pcm_status_get_avail(status) * bytes_per_sample;
1107 if (ret <= 0) {
1108 xrun("space");
1112 if (verbose>0 && str_status != "running")
1113 printf("alsa-space: free space = %i, status=%i, %s --\n", ret, status, str_status);
1114 snd_pcm_status_free(status);
1116 if (ret < 0) {
1117 printf("negative value!!\n");
1118 ret = 0;
1121 // workaround for too small value returned
1122 if (ret < MIN_CHUNK_SIZE)
1123 ret = 0;
1125 return(ret);
1128 /* delay in seconds between first and last sample in buffer */
1129 static float get_delay()
1132 if (alsa_handler) {
1134 snd_pcm_status_t *status;
1135 float ret;
1137 if ((ret = snd_pcm_status_malloc(&status)) < 0)
1139 printf("alsa-delay: memory allocation error: %s\n", snd_strerror(ret));
1140 return(0);
1143 if ((ret = snd_pcm_status(alsa_handler, status)) < 0)
1145 printf("alsa-delay: cannot get pcm status: %s\n", snd_strerror(ret));
1146 return(0);
1149 switch(snd_pcm_status_get_state(status))
1151 case SND_PCM_STATE_OPEN:
1152 case SND_PCM_STATE_PREPARED:
1153 case SND_PCM_STATE_RUNNING:
1154 ret = (float)snd_pcm_status_get_delay(status)/(float)ao_data.samplerate;
1155 break;
1156 default:
1157 ret = 0;
1160 snd_pcm_status_free(status);
1162 if (ret < 0)
1163 ret = 0;
1164 return(ret);
1166 } else {
1167 return(0);