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"
34 static const ao_info_t info
=
36 "ALSA-0.5.x audio output",
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
)
62 snd_pcm_channel_params_t params
;
63 snd_pcm_channel_setup_t setup
;
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
));
72 mp_msg(MSGT_AO
, MSGL_V
, "alsa-init: compiled for ALSA-%s (%d)\n", SND_LIB_VERSION_STR
,
75 if ((cards
= snd_cards()) < 0)
77 mp_tmsg(MSGT_AO
, MSGL_ERR
, "[AO ALSA5] alsa-init: no soundcards found.\n");
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
));
92 alsa_format
.format
= SND_PCM_SFMT_S8
;
95 alsa_format
.format
= SND_PCM_SFMT_U8
;
97 case AF_FORMAT_U16_LE
:
98 alsa_format
.format
= SND_PCM_SFMT_U16_LE
;
100 case AF_FORMAT_U16_BE
:
101 alsa_format
.format
= SND_PCM_SFMT_U16_BE
;
103 case AF_FORMAT_AC3_LE
:
104 case AF_FORMAT_S16_LE
:
105 alsa_format
.format
= SND_PCM_SFMT_S16_LE
;
107 case AF_FORMAT_AC3_BE
:
108 case AF_FORMAT_S16_BE
:
109 alsa_format
.format
= SND_PCM_SFMT_S16_BE
;
112 alsa_format
.format
= SND_PCM_SFMT_MPEG
;
116 switch(alsa_format
.format
)
118 case SND_PCM_SFMT_S16_LE
:
119 case SND_PCM_SFMT_U16_LE
:
123 mp_tmsg(MSGT_AO
, MSGL_ERR
, "[AO ALSA5] alsa-init: invalid format (%s) requested - output disabled.\n",af_fmt2str_short(format
));
132 alsa_rate
= SND_PCM_RATE_8000
;
135 alsa_rate
= SND_PCM_RATE_11025
;
138 alsa_rate
= SND_PCM_RATE_16000
;
141 alsa_rate
= SND_PCM_RATE_22050
;
144 alsa_rate
= SND_PCM_RATE_32000
;
147 alsa_rate
= SND_PCM_RATE_44100
;
150 alsa_rate
= SND_PCM_RATE_48000
;
153 alsa_rate
= SND_PCM_RATE_88200
;
156 alsa_rate
= SND_PCM_RATE_96000
;
159 alsa_rate
= SND_PCM_RATE_176400
;
162 alsa_rate
= SND_PCM_RATE_192000
;
165 alsa_rate
= SND_PCM_RATE_CONTINUOUS
;
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
));
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
));
185 mp_tmsg(MSGT_AO
, MSGL_INFO
, "[AO ALSA5] alsa-init: %d soundcard(s) found, using: %s\n",
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
));
199 if (chninfo
.buffer_size
)
200 ao_data
.buffersize
= chninfo
.buffer_size
;
203 mp_msg(MSGT_AO
, MSGL_V
, "alsa-init: setting preferred buffer size from driver: %d bytes\n",
207 memset(¶ms
, 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
, ¶ms
)) < 0)
218 mp_tmsg(MSGT_AO
, MSGL_ERR
, "[AO ALSA5] alsa-init: error setting parameters: %s\n", snd_strerror(err
));
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
));
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
));
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
));
247 /* close audio device */
248 static void uninit(int immed
)
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
));
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
));
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
));
271 /* stop playing and empty buffers (for seeking/pause) */
272 static void reset(void)
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
));
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
));
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
));
295 /* stop playing, keep buffers (for pause) */
296 static void audio_pause(void)
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
));
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
));
313 /* resume playing, after audio_pause() */
314 static void audio_resume(void)
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
));
325 plays 'len' bytes of 'data'
326 returns: number of bytes played
328 static int play(void* data
, int len
, int flags
)
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
));
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
));
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
));
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 */
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 */
382 return (float)ch_stat
.count
/(float)ao_data
.bps
;