Mercurial > mplayer.hg
view libao2/ao_alsa5.c @ 2982:32638add0dc8
mode selection (subdev) fix by Matan Ziv-Av matan@svgalib.org
author | arpi |
---|---|
date | Sun, 18 Nov 2001 19:47:58 +0000 |
parents | a3c3e1de6f02 |
children | 08947e067d80 |
line wrap: on
line source
/* ao_alsa5 - ALSA-0.5.x output plugin for MPlayer (C) Alex Beregszaszi <alex@naxine.org> Thanks to Arpi for helping me ;) */ #include <errno.h> #include <sys/asoundlib.h> #include "../config.h" #include "audio_out.h" #include "audio_out_internal.h" #include "afmt.h" extern int verbose; static ao_info_t info = { "ALSA-0.5.x audio output", "alsa5", "Alex Beregszaszi <alex@naxine.org>", "" }; LIBAO_EXTERN(alsa5) /* global variables: ao_samplerate ao_channels ao_format ao_bps ao_outburst ao_buffersize */ static snd_pcm_t *alsa_handler; static snd_pcm_format_t alsa_format; static int alsa_rate = SND_PCM_RATE_CONTINUOUS; /* to set/get/query special features/parameters */ static int control(int cmd, int arg) { return(CONTROL_UNKNOWN); } /* open & setup audio device return: 1=success 0=fail */ static int init(int rate_hz, int channels, int format, int flags) { int err; int cards = -1; snd_pcm_channel_params_t params; snd_pcm_channel_setup_t setup; snd_pcm_info_t info; snd_pcm_channel_info_t chninfo; printf("alsa-init: requested format: %d Hz, %d channels, %s\n", rate_hz, channels, audio_out_format_name(format)); alsa_handler = NULL; if (verbose) printf("alsa-init: compiled for ALSA-%s (%d)\n", SND_LIB_VERSION_STR, SND_LIB_VERSION); if ((cards = snd_cards()) < 0) { printf("alsa-init: no soundcards found\n"); return(0); } ao_format = format; ao_channels = channels - 1; ao_samplerate = rate_hz; ao_bps = ao_samplerate*(ao_channels+1); ao_outburst = OUTBURST; ao_buffersize = 16384; memset(&alsa_format, 0, sizeof(alsa_format)); switch (format) { case AFMT_S8: alsa_format.format = SND_PCM_SFMT_S8; break; case AFMT_U8: alsa_format.format = SND_PCM_SFMT_U8; break; case AFMT_U16_LE: alsa_format.format = SND_PCM_SFMT_U16_LE; break; case AFMT_U16_BE: alsa_format.format = SND_PCM_SFMT_U16_BE; break; case AFMT_S16_LE: alsa_format.format = SND_PCM_SFMT_S16_LE; break; case AFMT_S16_BE: alsa_format.format = SND_PCM_SFMT_S16_BE; break; default: alsa_format.format = SND_PCM_SFMT_MPEG; break; } switch(alsa_format.format) { case SND_PCM_SFMT_S16_LE: case SND_PCM_SFMT_U16_LE: ao_bps *= 2; break; case -1: printf("alsa-init: invalid format (%s) requested - output disabled\n", audio_out_format_name(format)); return(0); default: break; } switch(rate_hz) { case 8000: alsa_rate = SND_PCM_RATE_8000; break; case 11025: alsa_rate = SND_PCM_RATE_11025; break; case 16000: alsa_rate = SND_PCM_RATE_16000; break; case 22050: alsa_rate = SND_PCM_RATE_22050; break; case 32000: alsa_rate = SND_PCM_RATE_32000; break; case 44100: alsa_rate = SND_PCM_RATE_44100; break; case 48000: alsa_rate = SND_PCM_RATE_48000; break; case 88200: alsa_rate = SND_PCM_RATE_88200; break; case 96000: alsa_rate = SND_PCM_RATE_96000; break; case 176400: alsa_rate = SND_PCM_RATE_176400; break; case 192000: alsa_rate = SND_PCM_RATE_192000; break; default: alsa_rate = SND_PCM_RATE_CONTINUOUS; break; } alsa_format.rate = ao_samplerate; alsa_format.voices = ao_channels*2; alsa_format.interleave = 1; if ((err = snd_pcm_open(&alsa_handler, 0, 0, SND_PCM_OPEN_PLAYBACK)) < 0) { printf("alsa-init: playback open error: %s\n", snd_strerror(err)); return(0); } if ((err = snd_pcm_info(alsa_handler, &info)) < 0) { printf("alsa-init: pcm info error: %s\n", snd_strerror(err)); return(0); } printf("alsa-init: %d soundcard%s found, using: %s\n", cards, (cards == 1) ? "" : "s", info.name); if (info.flags & SND_PCM_INFO_PLAYBACK) { bzero(&chninfo, sizeof(chninfo)); chninfo.channel = SND_PCM_CHANNEL_PLAYBACK; if ((err = snd_pcm_channel_info(alsa_handler, &chninfo)) < 0) { printf("alsa-init: pcm channel info error: %s\n", snd_strerror(err)); return(0); } if (chninfo.buffer_size) ao_buffersize = chninfo.buffer_size; if (verbose) printf("alsa-init: setting preferred buffer size from driver: %d bytes\n", ao_buffersize); } memset(¶ms, 0, sizeof(params)); params.channel = SND_PCM_CHANNEL_PLAYBACK; params.mode = SND_PCM_MODE_STREAM; params.format = alsa_format; params.start_mode = SND_PCM_START_DATA; params.stop_mode = SND_PCM_STOP_ROLLOVER; params.buf.stream.queue_size = ao_buffersize; params.buf.stream.fill = SND_PCM_FILL_NONE; if ((err = snd_pcm_channel_params(alsa_handler, ¶ms)) < 0) { printf("alsa-init: error setting parameters: %s\n", snd_strerror(err)); return(0); } memset(&setup, 0, sizeof(setup)); setup.channel = SND_PCM_CHANNEL_PLAYBACK; setup.mode = SND_PCM_MODE_STREAM; setup.format = alsa_format; setup.buf.stream.queue_size = ao_buffersize; setup.msbits_per_sample = ao_bps; if ((err = snd_pcm_channel_setup(alsa_handler, &setup)) < 0) { printf("alsa-init: error setting up channel: %s\n", snd_strerror(err)); return(0); } if ((err = snd_pcm_channel_prepare(alsa_handler, SND_PCM_CHANNEL_PLAYBACK)) < 0) { printf("alsa-init: channel prepare error: %s\n", snd_strerror(err)); return(0); } printf("AUDIO: %d Hz/%d channels/%d bps/%d bytes buffer/%s\n", ao_samplerate, ao_channels+1, ao_bps, ao_buffersize, snd_pcm_get_format_name(alsa_format.format)); return(1); } /* close audio device */ static void uninit() { int err; if ((err = snd_pcm_playback_drain(alsa_handler)) < 0) { printf("alsa-uninit: playback drain error: %s\n", snd_strerror(err)); return; } if ((err = snd_pcm_channel_flush(alsa_handler, SND_PCM_CHANNEL_PLAYBACK)) < 0) { printf("alsa-uninit: playback flush error: %s\n", snd_strerror(err)); return; } if ((err = snd_pcm_close(alsa_handler)) < 0) { printf("alsa-uninit: pcm close error: %s\n", snd_strerror(err)); return; } } /* stop playing and empty buffers (for seeking/pause) */ static void reset() { int err; if ((err = snd_pcm_playback_drain(alsa_handler)) < 0) { printf("alsa-reset: playback drain error: %s\n", snd_strerror(err)); return; } if ((err = snd_pcm_channel_flush(alsa_handler, SND_PCM_CHANNEL_PLAYBACK)) < 0) { printf("alsa-reset: playback flush error: %s\n", snd_strerror(err)); return; } if ((err = snd_pcm_channel_prepare(alsa_handler, SND_PCM_CHANNEL_PLAYBACK)) < 0) { printf("alsa-reset: channel prepare error: %s\n", snd_strerror(err)); return; } } /* stop playing, keep buffers (for pause) */ static void audio_pause() { int err; if ((err = snd_pcm_playback_drain(alsa_handler)) < 0) { printf("alsa-pause: playback drain error: %s\n", snd_strerror(err)); return; } if ((err = snd_pcm_channel_flush(alsa_handler, SND_PCM_CHANNEL_PLAYBACK)) < 0) { printf("alsa-pause: playback flush error: %s\n", snd_strerror(err)); return; } } /* resume playing, after audio_pause() */ static void audio_resume() { int err; if ((err = snd_pcm_channel_prepare(alsa_handler, SND_PCM_CHANNEL_PLAYBACK)) < 0) { printf("alsa-resume: channel prepare error: %s\n", snd_strerror(err)); return; } } /* plays 'len' bytes of 'data' returns: number of bytes played */ static int play(void* data, int len, int flags) { if ((len = snd_pcm_write(alsa_handler, data, len)) != len) { if (len == -EPIPE) /* underrun? */ { printf("alsa-play: alsa underrun, resetting stream\n"); if ((len = snd_pcm_channel_prepare(alsa_handler, SND_PCM_CHANNEL_PLAYBACK)) < 0) { printf("alsa-play: playback prepare error: %s\n", snd_strerror(len)); return(0); } if ((len = snd_pcm_write(alsa_handler, data, len)) != len) { printf("alsa-play: write error after reset: %s - giving up\n", snd_strerror(len)); return(0); } return(len); /* 2nd write was ok */ } printf("alsa-play: output error: %s\n", snd_strerror(len)); } return(len); } /* how many byes are free in the buffer */ static int get_space() { snd_pcm_channel_status_t ch_stat; ch_stat.channel = SND_PCM_CHANNEL_PLAYBACK; if (snd_pcm_channel_status(alsa_handler, &ch_stat) < 0) return(0); /* error occured */ else return(ch_stat.free); } /* how many unplayed bytes are in the buffer */ static int get_delay() { snd_pcm_channel_status_t ch_stat; ch_stat.channel = SND_PCM_CHANNEL_PLAYBACK; if (snd_pcm_channel_status(alsa_handler, &ch_stat) < 0) return(ao_buffersize); /* error occured */ else return(ch_stat.count); }