summaryrefslogtreecommitdiffstats
path: root/libao2
diff options
context:
space:
mode:
authorpontscho <pontscho@b3059339-0415-0410-9bf9-f77b7e298cf2>2001-06-04 17:42:09 +0000
committerpontscho <pontscho@b3059339-0415-0410-9bf9-f77b7e298cf2>2001-06-04 17:42:09 +0000
commit70faf50935741eccc31853b09bec99692cfe0527 (patch)
tree85d7e7fe564c2543d190777d4669442651cf6448 /libao2
parent43243ae9e389fa3e802ac498bf10a2443dd0fe25 (diff)
downloadmpv-70faf50935741eccc31853b09bec99692cfe0527.tar.bz2
mpv-70faf50935741eccc31853b09bec99692cfe0527.tar.xz
initial alsa support by al3x
git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@997 b3059339-0415-0410-9bf9-f77b7e298cf2
Diffstat (limited to 'libao2')
-rw-r--r--libao2/ao_alsa5.c321
1 files changed, 321 insertions, 0 deletions
diff --git a/libao2/ao_alsa5.c b/libao2/ao_alsa5.c
new file mode 100644
index 0000000000..2039dacd26
--- /dev/null
+++ b/libao2/ao_alsa5.c
@@ -0,0 +1,321 @@
+/*
+ ao_alsa5 - ALSA 5.x output plugin for MPlayer
+
+ (C) Alex Beregszaszi <alex@naxine.org>
+
+ Thanks to Arpi for helping me ;)
+*/
+
+#include <errno.h>
+#include <sys/soundcard.h> /* AFMT_* */
+#include <sys/asoundlib.h>
+
+#include "../config.h"
+
+#include "audio_out.h"
+#include "audio_out_internal.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);
+ }
+
+ 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(&params, 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, &params)) < 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()
+{
+ reset();
+ snd_pcm_close(alsa_handler);
+}
+
+/* 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;
+ }
+}
+
+/*
+ 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);
+ 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(0);
+ else
+ return(ch_stat.count);
+}