demux: take chapter/attachment name strings without 0-termination
[mplayer/glamo.git] / libao2 / ao_alsa5.c
blob8843efb68a6eb40f6446be1c3a76088e7a3de572
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"
33 #include "help_mp.h"
35 static const ao_info_t info =
37 "ALSA-0.5.x audio output",
38 "alsa5",
39 "Alex Beregszaszi",
43 LIBAO_EXTERN(alsa5)
45 static snd_pcm_t *alsa_handler;
46 static snd_pcm_format_t alsa_format;
47 static int alsa_rate = SND_PCM_RATE_CONTINUOUS;
49 /* to set/get/query special features/parameters */
50 static int control(int cmd, void *arg)
52 return CONTROL_UNKNOWN;
56 open & setup audio device
57 return: 1=success 0=fail
59 static int init(int rate_hz, int channels, int format, int flags)
61 int err;
62 int cards = -1;
63 snd_pcm_channel_params_t params;
64 snd_pcm_channel_setup_t setup;
65 snd_pcm_info_t info;
66 snd_pcm_channel_info_t chninfo;
68 mp_tmsg(MSGT_AO, MSGL_INFO, "[AO ALSA5] alsa-init: requested format: %d Hz, %d channels, %s\n", rate_hz,
69 channels, af_fmt2str_short(format));
71 alsa_handler = NULL;
73 mp_msg(MSGT_AO, MSGL_V, "alsa-init: compiled for ALSA-%s (%d)\n", SND_LIB_VERSION_STR,
74 SND_LIB_VERSION);
76 if ((cards = snd_cards()) < 0)
78 mp_tmsg(MSGT_AO, MSGL_ERR, "[AO ALSA5] alsa-init: no soundcards found.\n");
79 return 0;
82 ao_data.format = format;
83 ao_data.channels = channels;
84 ao_data.samplerate = rate_hz;
85 ao_data.bps = ao_data.samplerate*ao_data.channels;
86 ao_data.outburst = OUTBURST;
87 ao_data.buffersize = 16384;
89 memset(&alsa_format, 0, sizeof(alsa_format));
90 switch (format)
92 case AF_FORMAT_S8:
93 alsa_format.format = SND_PCM_SFMT_S8;
94 break;
95 case AF_FORMAT_U8:
96 alsa_format.format = SND_PCM_SFMT_U8;
97 break;
98 case AF_FORMAT_U16_LE:
99 alsa_format.format = SND_PCM_SFMT_U16_LE;
100 break;
101 case AF_FORMAT_U16_BE:
102 alsa_format.format = SND_PCM_SFMT_U16_BE;
103 break;
104 #if !HAVE_BIGENDIAN
105 case AF_FORMAT_AC3:
106 #endif
107 case AF_FORMAT_S16_LE:
108 alsa_format.format = SND_PCM_SFMT_S16_LE;
109 break;
110 #if HAVE_BIGENDIAN
111 case AF_FORMAT_AC3:
112 #endif
113 case AF_FORMAT_S16_BE:
114 alsa_format.format = SND_PCM_SFMT_S16_BE;
115 break;
116 default:
117 alsa_format.format = SND_PCM_SFMT_MPEG;
118 break;
121 switch(alsa_format.format)
123 case SND_PCM_SFMT_S16_LE:
124 case SND_PCM_SFMT_U16_LE:
125 ao_data.bps *= 2;
126 break;
127 case -1:
128 mp_tmsg(MSGT_AO, MSGL_ERR, "[AO ALSA5] alsa-init: invalid format (%s) requested - output disabled.\n",af_fmt2str_short(format));
129 return 0;
130 default:
131 break;
134 switch(rate_hz)
136 case 8000:
137 alsa_rate = SND_PCM_RATE_8000;
138 break;
139 case 11025:
140 alsa_rate = SND_PCM_RATE_11025;
141 break;
142 case 16000:
143 alsa_rate = SND_PCM_RATE_16000;
144 break;
145 case 22050:
146 alsa_rate = SND_PCM_RATE_22050;
147 break;
148 case 32000:
149 alsa_rate = SND_PCM_RATE_32000;
150 break;
151 case 44100:
152 alsa_rate = SND_PCM_RATE_44100;
153 break;
154 case 48000:
155 alsa_rate = SND_PCM_RATE_48000;
156 break;
157 case 88200:
158 alsa_rate = SND_PCM_RATE_88200;
159 break;
160 case 96000:
161 alsa_rate = SND_PCM_RATE_96000;
162 break;
163 case 176400:
164 alsa_rate = SND_PCM_RATE_176400;
165 break;
166 case 192000:
167 alsa_rate = SND_PCM_RATE_192000;
168 break;
169 default:
170 alsa_rate = SND_PCM_RATE_CONTINUOUS;
171 break;
174 alsa_format.rate = ao_data.samplerate;
175 alsa_format.voices = ao_data.channels;
176 alsa_format.interleave = 1;
178 if ((err = snd_pcm_open(&alsa_handler, 0, 0, SND_PCM_OPEN_PLAYBACK)) < 0)
180 mp_tmsg(MSGT_AO, MSGL_ERR, "[AO ALSA5] alsa-init: playback open error: %s\n", snd_strerror(err));
181 return 0;
184 if ((err = snd_pcm_info(alsa_handler, &info)) < 0)
186 mp_tmsg(MSGT_AO, MSGL_ERR, "[AO ALSA5] alsa-init: PCM info error: %s\n", snd_strerror(err));
187 return 0;
190 mp_tmsg(MSGT_AO, MSGL_INFO, "[AO ALSA5] alsa-init: %d soundcard(s) found, using: %s\n",
191 cards, info.name);
193 if (info.flags & SND_PCM_INFO_PLAYBACK)
195 memset(&chninfo, 0, sizeof(chninfo));
196 chninfo.channel = SND_PCM_CHANNEL_PLAYBACK;
197 if ((err = snd_pcm_channel_info(alsa_handler, &chninfo)) < 0)
199 mp_tmsg(MSGT_AO, MSGL_ERR, "[AO ALSA5] alsa-init: PCM channel info error: %s\n", snd_strerror(err));
200 return 0;
203 #ifndef __QNX__
204 if (chninfo.buffer_size)
205 ao_data.buffersize = chninfo.buffer_size;
206 #endif
208 mp_msg(MSGT_AO, MSGL_V, "alsa-init: setting preferred buffer size from driver: %d bytes\n",
209 ao_data.buffersize);
212 memset(&params, 0, sizeof(params));
213 params.channel = SND_PCM_CHANNEL_PLAYBACK;
214 params.mode = SND_PCM_MODE_STREAM;
215 params.format = alsa_format;
216 params.start_mode = SND_PCM_START_DATA;
217 params.stop_mode = SND_PCM_STOP_ROLLOVER;
218 params.buf.stream.queue_size = ao_data.buffersize;
219 params.buf.stream.fill = SND_PCM_FILL_NONE;
221 if ((err = snd_pcm_channel_params(alsa_handler, &params)) < 0)
223 mp_tmsg(MSGT_AO, MSGL_ERR, "[AO ALSA5] alsa-init: error setting parameters: %s\n", snd_strerror(err));
224 return 0;
227 memset(&setup, 0, sizeof(setup));
228 setup.channel = SND_PCM_CHANNEL_PLAYBACK;
229 setup.mode = SND_PCM_MODE_STREAM;
230 setup.format = alsa_format;
231 setup.buf.stream.queue_size = ao_data.buffersize;
232 setup.msbits_per_sample = ao_data.bps;
234 if ((err = snd_pcm_channel_setup(alsa_handler, &setup)) < 0)
236 mp_tmsg(MSGT_AO, MSGL_ERR, "[AO ALSA5] alsa-init: error setting up channel: %s\n", snd_strerror(err));
237 return 0;
240 if ((err = snd_pcm_channel_prepare(alsa_handler, SND_PCM_CHANNEL_PLAYBACK)) < 0)
242 mp_tmsg(MSGT_AO, MSGL_ERR, "[AO ALSA5] alsa-init: channel prepare error: %s\n", snd_strerror(err));
243 return 0;
246 mp_msg(MSGT_AO, MSGL_INFO, "AUDIO: %d Hz/%d channels/%d bps/%d bytes buffer/%s\n",
247 ao_data.samplerate, ao_data.channels, ao_data.bps, ao_data.buffersize,
248 snd_pcm_get_format_name(alsa_format.format));
249 return 1;
252 /* close audio device */
253 static void uninit(int immed)
255 int err;
257 if ((err = snd_pcm_playback_drain(alsa_handler)) < 0)
259 mp_tmsg(MSGT_AO, MSGL_ERR, "[AO ALSA5] alsa-uninit: playback drain error: %s\n", snd_strerror(err));
260 return;
263 if ((err = snd_pcm_channel_flush(alsa_handler, SND_PCM_CHANNEL_PLAYBACK)) < 0)
265 mp_tmsg(MSGT_AO, MSGL_ERR, "[AO ALSA5] alsa-uninit: playback flush error: %s\n", snd_strerror(err));
266 return;
269 if ((err = snd_pcm_close(alsa_handler)) < 0)
271 mp_tmsg(MSGT_AO, MSGL_ERR, "[AO ALSA5] alsa-uninit: PCM close error: %s\n", snd_strerror(err));
272 return;
276 /* stop playing and empty buffers (for seeking/pause) */
277 static void reset(void)
279 int err;
281 if ((err = snd_pcm_playback_drain(alsa_handler)) < 0)
283 mp_tmsg(MSGT_AO, MSGL_ERR, "[AO ALSA5] alsa-reset: playback drain error: %s\n", snd_strerror(err));
284 return;
287 if ((err = snd_pcm_channel_flush(alsa_handler, SND_PCM_CHANNEL_PLAYBACK)) < 0)
289 mp_tmsg(MSGT_AO, MSGL_ERR, "[AO ALSA5] alsa-reset: playback flush error: %s\n", snd_strerror(err));
290 return;
293 if ((err = snd_pcm_channel_prepare(alsa_handler, SND_PCM_CHANNEL_PLAYBACK)) < 0)
295 mp_tmsg(MSGT_AO, MSGL_ERR, "[AO ALSA5] alsa-reset: channel prepare error: %s\n", snd_strerror(err));
296 return;
300 /* stop playing, keep buffers (for pause) */
301 static void audio_pause(void)
303 int err;
305 if ((err = snd_pcm_playback_drain(alsa_handler)) < 0)
307 mp_tmsg(MSGT_AO, MSGL_ERR, "[AO ALSA5] alsa-pause: playback drain error: %s\n", snd_strerror(err));
308 return;
311 if ((err = snd_pcm_channel_flush(alsa_handler, SND_PCM_CHANNEL_PLAYBACK)) < 0)
313 mp_tmsg(MSGT_AO, MSGL_ERR, "[AO ALSA5] alsa-pause: playback flush error: %s\n", snd_strerror(err));
314 return;
318 /* resume playing, after audio_pause() */
319 static void audio_resume(void)
321 int err;
322 if ((err = snd_pcm_channel_prepare(alsa_handler, SND_PCM_CHANNEL_PLAYBACK)) < 0)
324 mp_tmsg(MSGT_AO, MSGL_ERR, "[AO ALSA5] alsa-resume: channel prepare error: %s\n", snd_strerror(err));
325 return;
330 plays 'len' bytes of 'data'
331 returns: number of bytes played
333 static int play(void* data, int len, int flags)
335 int got_len;
337 if (!len)
338 return 0;
340 if ((got_len = snd_pcm_write(alsa_handler, data, len)) < 0)
342 if (got_len == -EPIPE) /* underrun? */
344 mp_tmsg(MSGT_AO, MSGL_ERR, "[AO ALSA5] alsa-play: alsa underrun, resetting stream.\n");
345 if ((got_len = snd_pcm_channel_prepare(alsa_handler, SND_PCM_CHANNEL_PLAYBACK)) < 0)
347 mp_tmsg(MSGT_AO, MSGL_ERR, "[AO ALSA5] alsa-play: playback prepare error: %s\n", snd_strerror(got_len));
348 return 0;
350 if ((got_len = snd_pcm_write(alsa_handler, data, len)) < 0)
352 mp_tmsg(MSGT_AO, MSGL_ERR, "[AO ALSA5] alsa-play: write error after reset: %s - giving up.\n",
353 snd_strerror(got_len));
354 return 0;
356 return got_len; /* 2nd write was ok */
358 mp_tmsg(MSGT_AO, MSGL_ERR, "[AO ALSA5] alsa-play: output error: %s\n", snd_strerror(got_len));
359 return 0;
361 return got_len;
364 /* how many byes are free in the buffer */
365 static int get_space(void)
367 snd_pcm_channel_status_t ch_stat;
369 ch_stat.channel = SND_PCM_CHANNEL_PLAYBACK;
371 if (snd_pcm_channel_status(alsa_handler, &ch_stat) < 0)
372 return 0; /* error occurred */
373 else
374 return ch_stat.free;
377 /* delay in seconds between first and last sample in buffer */
378 static float get_delay(void)
380 snd_pcm_channel_status_t ch_stat;
382 ch_stat.channel = SND_PCM_CHANNEL_PLAYBACK;
384 if (snd_pcm_channel_status(alsa_handler, &ch_stat) < 0)
385 return (float)ao_data.buffersize/(float)ao_data.bps; /* error occurred */
386 else
387 return (float)ch_stat.count/(float)ao_data.bps;