loader: Move local_wm extern variable declaration to loader.h
[mplayer.git] / libao2 / ao_alsa5.c
blobd6ab7eeb226e38cf54f4469f9a97103fe224dde3
1 /*
2 * ALSA 0.5.x audio output driver
4 * Copyright (C) 2001 Alex Beregszaszi
6 * Thanks to Arpi for helping me ;)
8 * MPlayer is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * MPlayer is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License along
19 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 #include <errno.h>
24 #include <sys/asoundlib.h>
26 #include "config.h"
28 #include "audio_out.h"
29 #include "audio_out_internal.h"
30 #include "libaf/af_format.h"
32 #include "mp_msg.h"
34 static const ao_info_t info =
36 "ALSA-0.5.x audio output",
37 "alsa5",
38 "Alex Beregszaszi",
42 LIBAO_EXTERN(alsa5)
44 static snd_pcm_t *alsa_handler;
45 static snd_pcm_format_t alsa_format;
46 static int alsa_rate = SND_PCM_RATE_CONTINUOUS;
48 /* to set/get/query special features/parameters */
49 static int control(int cmd, void *arg)
51 return CONTROL_UNKNOWN;
55 open & setup audio device
56 return: 1=success 0=fail
58 static int init(int rate_hz, int channels, int format, int flags)
60 int err;
61 int cards = -1;
62 snd_pcm_channel_params_t params;
63 snd_pcm_channel_setup_t setup;
64 snd_pcm_info_t info;
65 snd_pcm_channel_info_t chninfo;
67 mp_tmsg(MSGT_AO, MSGL_INFO, "[AO ALSA5] alsa-init: requested format: %d Hz, %d channels, %s\n", rate_hz,
68 channels, af_fmt2str_short(format));
70 alsa_handler = NULL;
72 mp_msg(MSGT_AO, MSGL_V, "alsa-init: compiled for ALSA-%s (%d)\n", SND_LIB_VERSION_STR,
73 SND_LIB_VERSION);
75 if ((cards = snd_cards()) < 0)
77 mp_tmsg(MSGT_AO, MSGL_ERR, "[AO ALSA5] alsa-init: no soundcards found.\n");
78 return 0;
81 ao_data.format = format;
82 ao_data.channels = channels;
83 ao_data.samplerate = rate_hz;
84 ao_data.bps = ao_data.samplerate*ao_data.channels;
85 ao_data.outburst = OUTBURST;
86 ao_data.buffersize = 16384;
88 memset(&alsa_format, 0, sizeof(alsa_format));
89 switch (format)
91 case AF_FORMAT_S8:
92 alsa_format.format = SND_PCM_SFMT_S8;
93 break;
94 case AF_FORMAT_U8:
95 alsa_format.format = SND_PCM_SFMT_U8;
96 break;
97 case AF_FORMAT_U16_LE:
98 alsa_format.format = SND_PCM_SFMT_U16_LE;
99 break;
100 case AF_FORMAT_U16_BE:
101 alsa_format.format = SND_PCM_SFMT_U16_BE;
102 break;
103 case AF_FORMAT_AC3_LE:
104 case AF_FORMAT_S16_LE:
105 alsa_format.format = SND_PCM_SFMT_S16_LE;
106 break;
107 case AF_FORMAT_AC3_BE:
108 case AF_FORMAT_S16_BE:
109 alsa_format.format = SND_PCM_SFMT_S16_BE;
110 break;
111 default:
112 alsa_format.format = SND_PCM_SFMT_MPEG;
113 break;
116 switch(alsa_format.format)
118 case SND_PCM_SFMT_S16_LE:
119 case SND_PCM_SFMT_U16_LE:
120 ao_data.bps *= 2;
121 break;
122 case -1:
123 mp_tmsg(MSGT_AO, MSGL_ERR, "[AO ALSA5] alsa-init: invalid format (%s) requested - output disabled.\n",af_fmt2str_short(format));
124 return 0;
125 default:
126 break;
129 switch(rate_hz)
131 case 8000:
132 alsa_rate = SND_PCM_RATE_8000;
133 break;
134 case 11025:
135 alsa_rate = SND_PCM_RATE_11025;
136 break;
137 case 16000:
138 alsa_rate = SND_PCM_RATE_16000;
139 break;
140 case 22050:
141 alsa_rate = SND_PCM_RATE_22050;
142 break;
143 case 32000:
144 alsa_rate = SND_PCM_RATE_32000;
145 break;
146 case 44100:
147 alsa_rate = SND_PCM_RATE_44100;
148 break;
149 case 48000:
150 alsa_rate = SND_PCM_RATE_48000;
151 break;
152 case 88200:
153 alsa_rate = SND_PCM_RATE_88200;
154 break;
155 case 96000:
156 alsa_rate = SND_PCM_RATE_96000;
157 break;
158 case 176400:
159 alsa_rate = SND_PCM_RATE_176400;
160 break;
161 case 192000:
162 alsa_rate = SND_PCM_RATE_192000;
163 break;
164 default:
165 alsa_rate = SND_PCM_RATE_CONTINUOUS;
166 break;
169 alsa_format.rate = ao_data.samplerate;
170 alsa_format.voices = ao_data.channels;
171 alsa_format.interleave = 1;
173 if ((err = snd_pcm_open(&alsa_handler, 0, 0, SND_PCM_OPEN_PLAYBACK)) < 0)
175 mp_tmsg(MSGT_AO, MSGL_ERR, "[AO ALSA5] alsa-init: playback open error: %s\n", snd_strerror(err));
176 return 0;
179 if ((err = snd_pcm_info(alsa_handler, &info)) < 0)
181 mp_tmsg(MSGT_AO, MSGL_ERR, "[AO ALSA5] alsa-init: PCM info error: %s\n", snd_strerror(err));
182 return 0;
185 mp_tmsg(MSGT_AO, MSGL_INFO, "[AO ALSA5] alsa-init: %d soundcard(s) found, using: %s\n",
186 cards, info.name);
188 if (info.flags & SND_PCM_INFO_PLAYBACK)
190 memset(&chninfo, 0, sizeof(chninfo));
191 chninfo.channel = SND_PCM_CHANNEL_PLAYBACK;
192 if ((err = snd_pcm_channel_info(alsa_handler, &chninfo)) < 0)
194 mp_tmsg(MSGT_AO, MSGL_ERR, "[AO ALSA5] alsa-init: PCM channel info error: %s\n", snd_strerror(err));
195 return 0;
198 #ifndef __QNX__
199 if (chninfo.buffer_size)
200 ao_data.buffersize = chninfo.buffer_size;
201 #endif
203 mp_msg(MSGT_AO, MSGL_V, "alsa-init: setting preferred buffer size from driver: %d bytes\n",
204 ao_data.buffersize);
207 memset(&params, 0, sizeof(params));
208 params.channel = SND_PCM_CHANNEL_PLAYBACK;
209 params.mode = SND_PCM_MODE_STREAM;
210 params.format = alsa_format;
211 params.start_mode = SND_PCM_START_DATA;
212 params.stop_mode = SND_PCM_STOP_ROLLOVER;
213 params.buf.stream.queue_size = ao_data.buffersize;
214 params.buf.stream.fill = SND_PCM_FILL_NONE;
216 if ((err = snd_pcm_channel_params(alsa_handler, &params)) < 0)
218 mp_tmsg(MSGT_AO, MSGL_ERR, "[AO ALSA5] alsa-init: error setting parameters: %s\n", snd_strerror(err));
219 return 0;
222 memset(&setup, 0, sizeof(setup));
223 setup.channel = SND_PCM_CHANNEL_PLAYBACK;
224 setup.mode = SND_PCM_MODE_STREAM;
225 setup.format = alsa_format;
226 setup.buf.stream.queue_size = ao_data.buffersize;
227 setup.msbits_per_sample = ao_data.bps;
229 if ((err = snd_pcm_channel_setup(alsa_handler, &setup)) < 0)
231 mp_tmsg(MSGT_AO, MSGL_ERR, "[AO ALSA5] alsa-init: error setting up channel: %s\n", snd_strerror(err));
232 return 0;
235 if ((err = snd_pcm_channel_prepare(alsa_handler, SND_PCM_CHANNEL_PLAYBACK)) < 0)
237 mp_tmsg(MSGT_AO, MSGL_ERR, "[AO ALSA5] alsa-init: channel prepare error: %s\n", snd_strerror(err));
238 return 0;
241 mp_msg(MSGT_AO, MSGL_INFO, "AUDIO: %d Hz/%d channels/%d bps/%d bytes buffer/%s\n",
242 ao_data.samplerate, ao_data.channels, ao_data.bps, ao_data.buffersize,
243 snd_pcm_get_format_name(alsa_format.format));
244 return 1;
247 /* close audio device */
248 static void uninit(int immed)
250 int err;
252 if ((err = snd_pcm_playback_drain(alsa_handler)) < 0)
254 mp_tmsg(MSGT_AO, MSGL_ERR, "[AO ALSA5] alsa-uninit: playback drain error: %s\n", snd_strerror(err));
255 return;
258 if ((err = snd_pcm_channel_flush(alsa_handler, SND_PCM_CHANNEL_PLAYBACK)) < 0)
260 mp_tmsg(MSGT_AO, MSGL_ERR, "[AO ALSA5] alsa-uninit: playback flush error: %s\n", snd_strerror(err));
261 return;
264 if ((err = snd_pcm_close(alsa_handler)) < 0)
266 mp_tmsg(MSGT_AO, MSGL_ERR, "[AO ALSA5] alsa-uninit: PCM close error: %s\n", snd_strerror(err));
267 return;
271 /* stop playing and empty buffers (for seeking/pause) */
272 static void reset(void)
274 int err;
276 if ((err = snd_pcm_playback_drain(alsa_handler)) < 0)
278 mp_tmsg(MSGT_AO, MSGL_ERR, "[AO ALSA5] alsa-reset: playback drain error: %s\n", snd_strerror(err));
279 return;
282 if ((err = snd_pcm_channel_flush(alsa_handler, SND_PCM_CHANNEL_PLAYBACK)) < 0)
284 mp_tmsg(MSGT_AO, MSGL_ERR, "[AO ALSA5] alsa-reset: playback flush error: %s\n", snd_strerror(err));
285 return;
288 if ((err = snd_pcm_channel_prepare(alsa_handler, SND_PCM_CHANNEL_PLAYBACK)) < 0)
290 mp_tmsg(MSGT_AO, MSGL_ERR, "[AO ALSA5] alsa-reset: channel prepare error: %s\n", snd_strerror(err));
291 return;
295 /* stop playing, keep buffers (for pause) */
296 static void audio_pause(void)
298 int err;
300 if ((err = snd_pcm_playback_drain(alsa_handler)) < 0)
302 mp_tmsg(MSGT_AO, MSGL_ERR, "[AO ALSA5] alsa-pause: playback drain error: %s\n", snd_strerror(err));
303 return;
306 if ((err = snd_pcm_channel_flush(alsa_handler, SND_PCM_CHANNEL_PLAYBACK)) < 0)
308 mp_tmsg(MSGT_AO, MSGL_ERR, "[AO ALSA5] alsa-pause: playback flush error: %s\n", snd_strerror(err));
309 return;
313 /* resume playing, after audio_pause() */
314 static void audio_resume(void)
316 int err;
317 if ((err = snd_pcm_channel_prepare(alsa_handler, SND_PCM_CHANNEL_PLAYBACK)) < 0)
319 mp_tmsg(MSGT_AO, MSGL_ERR, "[AO ALSA5] alsa-resume: channel prepare error: %s\n", snd_strerror(err));
320 return;
325 plays 'len' bytes of 'data'
326 returns: number of bytes played
328 static int play(void* data, int len, int flags)
330 int got_len;
332 if (!len)
333 return 0;
335 if ((got_len = snd_pcm_write(alsa_handler, data, len)) < 0)
337 if (got_len == -EPIPE) /* underrun? */
339 mp_tmsg(MSGT_AO, MSGL_ERR, "[AO ALSA5] alsa-play: alsa underrun, resetting stream.\n");
340 if ((got_len = snd_pcm_channel_prepare(alsa_handler, SND_PCM_CHANNEL_PLAYBACK)) < 0)
342 mp_tmsg(MSGT_AO, MSGL_ERR, "[AO ALSA5] alsa-play: playback prepare error: %s\n", snd_strerror(got_len));
343 return 0;
345 if ((got_len = snd_pcm_write(alsa_handler, data, len)) < 0)
347 mp_tmsg(MSGT_AO, MSGL_ERR, "[AO ALSA5] alsa-play: write error after reset: %s - giving up.\n",
348 snd_strerror(got_len));
349 return 0;
351 return got_len; /* 2nd write was ok */
353 mp_tmsg(MSGT_AO, MSGL_ERR, "[AO ALSA5] alsa-play: output error: %s\n", snd_strerror(got_len));
354 return 0;
356 return got_len;
359 /* how many byes are free in the buffer */
360 static int get_space(void)
362 snd_pcm_channel_status_t ch_stat;
364 ch_stat.channel = SND_PCM_CHANNEL_PLAYBACK;
366 if (snd_pcm_channel_status(alsa_handler, &ch_stat) < 0)
367 return 0; /* error occurred */
368 else
369 return ch_stat.free;
372 /* delay in seconds between first and last sample in buffer */
373 static float get_delay(void)
375 snd_pcm_channel_status_t ch_stat;
377 ch_stat.channel = SND_PCM_CHANNEL_PLAYBACK;
379 if (snd_pcm_channel_status(alsa_handler, &ch_stat) < 0)
380 return (float)ao_data.buffersize/(float)ao_data.bps; /* error occurred */
381 else
382 return (float)ch_stat.count/(float)ao_data.bps;