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
;
104 case AF_FORMAT_AC3_LE
:
105 case AF_FORMAT_S16_LE
:
106 alsa_format
.format
= SND_PCM_SFMT_S16_LE
;
108 case AF_FORMAT_AC3_BE
:
109 case AF_FORMAT_S16_BE
:
110 alsa_format
.format
= SND_PCM_SFMT_S16_BE
;
113 alsa_format
.format
= SND_PCM_SFMT_MPEG
;
117 switch(alsa_format
.format
)
119 case SND_PCM_SFMT_S16_LE
:
120 case SND_PCM_SFMT_U16_LE
:
124 mp_tmsg(MSGT_AO
, MSGL_ERR
, "[AO ALSA5] alsa-init: invalid format (%s) requested - output disabled.\n",af_fmt2str_short(format
));
133 alsa_rate
= SND_PCM_RATE_8000
;
136 alsa_rate
= SND_PCM_RATE_11025
;
139 alsa_rate
= SND_PCM_RATE_16000
;
142 alsa_rate
= SND_PCM_RATE_22050
;
145 alsa_rate
= SND_PCM_RATE_32000
;
148 alsa_rate
= SND_PCM_RATE_44100
;
151 alsa_rate
= SND_PCM_RATE_48000
;
154 alsa_rate
= SND_PCM_RATE_88200
;
157 alsa_rate
= SND_PCM_RATE_96000
;
160 alsa_rate
= SND_PCM_RATE_176400
;
163 alsa_rate
= SND_PCM_RATE_192000
;
166 alsa_rate
= SND_PCM_RATE_CONTINUOUS
;
170 alsa_format
.rate
= ao_data
.samplerate
;
171 alsa_format
.voices
= ao_data
.channels
;
172 alsa_format
.interleave
= 1;
174 if ((err
= snd_pcm_open(&alsa_handler
, 0, 0, SND_PCM_OPEN_PLAYBACK
)) < 0)
176 mp_tmsg(MSGT_AO
, MSGL_ERR
, "[AO ALSA5] alsa-init: playback open error: %s\n", snd_strerror(err
));
180 if ((err
= snd_pcm_info(alsa_handler
, &info
)) < 0)
182 mp_tmsg(MSGT_AO
, MSGL_ERR
, "[AO ALSA5] alsa-init: PCM info error: %s\n", snd_strerror(err
));
186 mp_tmsg(MSGT_AO
, MSGL_INFO
, "[AO ALSA5] alsa-init: %d soundcard(s) found, using: %s\n",
189 if (info
.flags
& SND_PCM_INFO_PLAYBACK
)
191 memset(&chninfo
, 0, sizeof(chninfo
));
192 chninfo
.channel
= SND_PCM_CHANNEL_PLAYBACK
;
193 if ((err
= snd_pcm_channel_info(alsa_handler
, &chninfo
)) < 0)
195 mp_tmsg(MSGT_AO
, MSGL_ERR
, "[AO ALSA5] alsa-init: PCM channel info error: %s\n", snd_strerror(err
));
200 if (chninfo
.buffer_size
)
201 ao_data
.buffersize
= chninfo
.buffer_size
;
204 mp_msg(MSGT_AO
, MSGL_V
, "alsa-init: setting preferred buffer size from driver: %d bytes\n",
208 memset(¶ms
, 0, sizeof(params
));
209 params
.channel
= SND_PCM_CHANNEL_PLAYBACK
;
210 params
.mode
= SND_PCM_MODE_STREAM
;
211 params
.format
= alsa_format
;
212 params
.start_mode
= SND_PCM_START_DATA
;
213 params
.stop_mode
= SND_PCM_STOP_ROLLOVER
;
214 params
.buf
.stream
.queue_size
= ao_data
.buffersize
;
215 params
.buf
.stream
.fill
= SND_PCM_FILL_NONE
;
217 if ((err
= snd_pcm_channel_params(alsa_handler
, ¶ms
)) < 0)
219 mp_tmsg(MSGT_AO
, MSGL_ERR
, "[AO ALSA5] alsa-init: error setting parameters: %s\n", snd_strerror(err
));
223 memset(&setup
, 0, sizeof(setup
));
224 setup
.channel
= SND_PCM_CHANNEL_PLAYBACK
;
225 setup
.mode
= SND_PCM_MODE_STREAM
;
226 setup
.format
= alsa_format
;
227 setup
.buf
.stream
.queue_size
= ao_data
.buffersize
;
228 setup
.msbits_per_sample
= ao_data
.bps
;
230 if ((err
= snd_pcm_channel_setup(alsa_handler
, &setup
)) < 0)
232 mp_tmsg(MSGT_AO
, MSGL_ERR
, "[AO ALSA5] alsa-init: error setting up channel: %s\n", snd_strerror(err
));
236 if ((err
= snd_pcm_channel_prepare(alsa_handler
, SND_PCM_CHANNEL_PLAYBACK
)) < 0)
238 mp_tmsg(MSGT_AO
, MSGL_ERR
, "[AO ALSA5] alsa-init: channel prepare error: %s\n", snd_strerror(err
));
242 mp_msg(MSGT_AO
, MSGL_INFO
, "AUDIO: %d Hz/%d channels/%d bps/%d bytes buffer/%s\n",
243 ao_data
.samplerate
, ao_data
.channels
, ao_data
.bps
, ao_data
.buffersize
,
244 snd_pcm_get_format_name(alsa_format
.format
));
248 /* close audio device */
249 static void uninit(int immed
)
253 if ((err
= snd_pcm_playback_drain(alsa_handler
)) < 0)
255 mp_tmsg(MSGT_AO
, MSGL_ERR
, "[AO ALSA5] alsa-uninit: playback drain error: %s\n", snd_strerror(err
));
259 if ((err
= snd_pcm_channel_flush(alsa_handler
, SND_PCM_CHANNEL_PLAYBACK
)) < 0)
261 mp_tmsg(MSGT_AO
, MSGL_ERR
, "[AO ALSA5] alsa-uninit: playback flush error: %s\n", snd_strerror(err
));
265 if ((err
= snd_pcm_close(alsa_handler
)) < 0)
267 mp_tmsg(MSGT_AO
, MSGL_ERR
, "[AO ALSA5] alsa-uninit: PCM close error: %s\n", snd_strerror(err
));
272 /* stop playing and empty buffers (for seeking/pause) */
273 static void reset(void)
277 if ((err
= snd_pcm_playback_drain(alsa_handler
)) < 0)
279 mp_tmsg(MSGT_AO
, MSGL_ERR
, "[AO ALSA5] alsa-reset: playback drain error: %s\n", snd_strerror(err
));
283 if ((err
= snd_pcm_channel_flush(alsa_handler
, SND_PCM_CHANNEL_PLAYBACK
)) < 0)
285 mp_tmsg(MSGT_AO
, MSGL_ERR
, "[AO ALSA5] alsa-reset: playback flush error: %s\n", snd_strerror(err
));
289 if ((err
= snd_pcm_channel_prepare(alsa_handler
, SND_PCM_CHANNEL_PLAYBACK
)) < 0)
291 mp_tmsg(MSGT_AO
, MSGL_ERR
, "[AO ALSA5] alsa-reset: channel prepare error: %s\n", snd_strerror(err
));
296 /* stop playing, keep buffers (for pause) */
297 static void audio_pause(void)
301 if ((err
= snd_pcm_playback_drain(alsa_handler
)) < 0)
303 mp_tmsg(MSGT_AO
, MSGL_ERR
, "[AO ALSA5] alsa-pause: playback drain error: %s\n", snd_strerror(err
));
307 if ((err
= snd_pcm_channel_flush(alsa_handler
, SND_PCM_CHANNEL_PLAYBACK
)) < 0)
309 mp_tmsg(MSGT_AO
, MSGL_ERR
, "[AO ALSA5] alsa-pause: playback flush error: %s\n", snd_strerror(err
));
314 /* resume playing, after audio_pause() */
315 static void audio_resume(void)
318 if ((err
= snd_pcm_channel_prepare(alsa_handler
, SND_PCM_CHANNEL_PLAYBACK
)) < 0)
320 mp_tmsg(MSGT_AO
, MSGL_ERR
, "[AO ALSA5] alsa-resume: channel prepare error: %s\n", snd_strerror(err
));
326 plays 'len' bytes of 'data'
327 returns: number of bytes played
329 static int play(void* data
, int len
, int flags
)
336 if ((got_len
= snd_pcm_write(alsa_handler
, data
, len
)) < 0)
338 if (got_len
== -EPIPE
) /* underrun? */
340 mp_tmsg(MSGT_AO
, MSGL_ERR
, "[AO ALSA5] alsa-play: alsa underrun, resetting stream.\n");
341 if ((got_len
= snd_pcm_channel_prepare(alsa_handler
, SND_PCM_CHANNEL_PLAYBACK
)) < 0)
343 mp_tmsg(MSGT_AO
, MSGL_ERR
, "[AO ALSA5] alsa-play: playback prepare error: %s\n", snd_strerror(got_len
));
346 if ((got_len
= snd_pcm_write(alsa_handler
, data
, len
)) < 0)
348 mp_tmsg(MSGT_AO
, MSGL_ERR
, "[AO ALSA5] alsa-play: write error after reset: %s - giving up.\n",
349 snd_strerror(got_len
));
352 return got_len
; /* 2nd write was ok */
354 mp_tmsg(MSGT_AO
, MSGL_ERR
, "[AO ALSA5] alsa-play: output error: %s\n", snd_strerror(got_len
));
360 /* how many byes are free in the buffer */
361 static int get_space(void)
363 snd_pcm_channel_status_t ch_stat
;
365 ch_stat
.channel
= SND_PCM_CHANNEL_PLAYBACK
;
367 if (snd_pcm_channel_status(alsa_handler
, &ch_stat
) < 0)
368 return 0; /* error occurred */
373 /* delay in seconds between first and last sample in buffer */
374 static float get_delay(void)
376 snd_pcm_channel_status_t ch_stat
;
378 ch_stat
.channel
= SND_PCM_CHANNEL_PLAYBACK
;
380 if (snd_pcm_channel_status(alsa_handler
, &ch_stat
) < 0)
381 return (float)ao_data
.buffersize
/(float)ao_data
.bps
; /* error occurred */
383 return (float)ch_stat
.count
/(float)ao_data
.bps
;