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.
24 #include <sys/asoundlib.h>
28 #include "audio_out.h"
29 #include "audio_out_internal.h"
30 #include "libaf/af_format.h"
35 static const ao_info_t info
=
37 "ALSA-0.5.x audio output",
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
)
63 snd_pcm_channel_params_t params
;
64 snd_pcm_channel_setup_t setup
;
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
));
73 mp_msg(MSGT_AO
, MSGL_V
, "alsa-init: compiled for ALSA-%s (%d)\n", SND_LIB_VERSION_STR
,
76 if ((cards
= snd_cards()) < 0)
78 mp_tmsg(MSGT_AO
, MSGL_ERR
, "[AO ALSA5] alsa-init: no soundcards found.\n");
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
));
93 alsa_format
.format
= SND_PCM_SFMT_S8
;
96 alsa_format
.format
= SND_PCM_SFMT_U8
;
98 case AF_FORMAT_U16_LE
:
99 alsa_format
.format
= SND_PCM_SFMT_U16_LE
;
101 case AF_FORMAT_U16_BE
:
102 alsa_format
.format
= SND_PCM_SFMT_U16_BE
;
107 case AF_FORMAT_S16_LE
:
108 alsa_format
.format
= SND_PCM_SFMT_S16_LE
;
113 case AF_FORMAT_S16_BE
:
114 alsa_format
.format
= SND_PCM_SFMT_S16_BE
;
117 alsa_format
.format
= SND_PCM_SFMT_MPEG
;
121 switch(alsa_format
.format
)
123 case SND_PCM_SFMT_S16_LE
:
124 case SND_PCM_SFMT_U16_LE
:
128 mp_tmsg(MSGT_AO
, MSGL_ERR
, "[AO ALSA5] alsa-init: invalid format (%s) requested - output disabled.\n",af_fmt2str_short(format
));
137 alsa_rate
= SND_PCM_RATE_8000
;
140 alsa_rate
= SND_PCM_RATE_11025
;
143 alsa_rate
= SND_PCM_RATE_16000
;
146 alsa_rate
= SND_PCM_RATE_22050
;
149 alsa_rate
= SND_PCM_RATE_32000
;
152 alsa_rate
= SND_PCM_RATE_44100
;
155 alsa_rate
= SND_PCM_RATE_48000
;
158 alsa_rate
= SND_PCM_RATE_88200
;
161 alsa_rate
= SND_PCM_RATE_96000
;
164 alsa_rate
= SND_PCM_RATE_176400
;
167 alsa_rate
= SND_PCM_RATE_192000
;
170 alsa_rate
= SND_PCM_RATE_CONTINUOUS
;
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
));
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
));
190 mp_tmsg(MSGT_AO
, MSGL_INFO
, "[AO ALSA5] alsa-init: %d soundcard(s) found, using: %s\n",
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
));
204 if (chninfo
.buffer_size
)
205 ao_data
.buffersize
= chninfo
.buffer_size
;
208 mp_msg(MSGT_AO
, MSGL_V
, "alsa-init: setting preferred buffer size from driver: %d bytes\n",
212 memset(¶ms
, 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
, ¶ms
)) < 0)
223 mp_tmsg(MSGT_AO
, MSGL_ERR
, "[AO ALSA5] alsa-init: error setting parameters: %s\n", snd_strerror(err
));
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
));
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
));
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
));
252 /* close audio device */
253 static void uninit(int immed
)
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
));
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
));
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
));
276 /* stop playing and empty buffers (for seeking/pause) */
277 static void reset(void)
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
));
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
));
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
));
300 /* stop playing, keep buffers (for pause) */
301 static void audio_pause(void)
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
));
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
));
318 /* resume playing, after audio_pause() */
319 static void audio_resume(void)
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
));
330 plays 'len' bytes of 'data'
331 returns: number of bytes played
333 static int play(void* data
, int len
, int flags
)
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
));
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
));
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
));
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 */
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 */
387 return (float)ch_stat
.count
/(float)ao_data
.bps
;