2 ao_alsa5 - ALSA-0.5.x output plugin for MPlayer
6 Thanks to Arpi for helping me ;)
10 #include <sys/asoundlib.h>
14 #include "audio_out.h"
15 #include "audio_out_internal.h"
16 #include "libaf/af_format.h"
21 static ao_info_t info
=
23 "ALSA-0.5.x audio output",
31 static snd_pcm_t
*alsa_handler
;
32 static snd_pcm_format_t alsa_format
;
33 static int alsa_rate
= SND_PCM_RATE_CONTINUOUS
;
35 /* to set/get/query special features/parameters */
36 static int control(int cmd
, void *arg
)
38 return CONTROL_UNKNOWN
;
42 open & setup audio device
43 return: 1=success 0=fail
45 static int init(int rate_hz
, int channels
, int format
, int flags
)
49 snd_pcm_channel_params_t params
;
50 snd_pcm_channel_setup_t setup
;
52 snd_pcm_channel_info_t chninfo
;
54 mp_msg(MSGT_AO
, MSGL_INFO
, MSGTR_AO_ALSA5_InitInfo
, rate_hz
,
55 channels
, af_fmt2str_short(format
));
59 mp_msg(MSGT_AO
, MSGL_V
, "alsa-init: compiled for ALSA-%s (%d)\n", SND_LIB_VERSION_STR
,
62 if ((cards
= snd_cards()) < 0)
64 mp_msg(MSGT_AO
, MSGL_ERR
, MSGTR_AO_ALSA5_SoundCardNotFound
);
68 ao_data
.format
= format
;
69 ao_data
.channels
= channels
;
70 ao_data
.samplerate
= rate_hz
;
71 ao_data
.bps
= ao_data
.samplerate
*ao_data
.channels
;
72 ao_data
.outburst
= OUTBURST
;
73 ao_data
.buffersize
= 16384;
75 memset(&alsa_format
, 0, sizeof(alsa_format
));
79 alsa_format
.format
= SND_PCM_SFMT_S8
;
82 alsa_format
.format
= SND_PCM_SFMT_U8
;
84 case AF_FORMAT_U16_LE
:
85 alsa_format
.format
= SND_PCM_SFMT_U16_LE
;
87 case AF_FORMAT_U16_BE
:
88 alsa_format
.format
= SND_PCM_SFMT_U16_BE
;
90 #ifndef WORDS_BIGENDIAN
93 case AF_FORMAT_S16_LE
:
94 alsa_format
.format
= SND_PCM_SFMT_S16_LE
;
96 #ifdef WORDS_BIGENDIAN
99 case AF_FORMAT_S16_BE
:
100 alsa_format
.format
= SND_PCM_SFMT_S16_BE
;
103 alsa_format
.format
= SND_PCM_SFMT_MPEG
;
107 switch(alsa_format
.format
)
109 case SND_PCM_SFMT_S16_LE
:
110 case SND_PCM_SFMT_U16_LE
:
114 mp_msg(MSGT_AO
, MSGL_ERR
, MSGTR_AO_ALSA5_InvalidFormatReq
,af_fmt2str_short(format
));
123 alsa_rate
= SND_PCM_RATE_8000
;
126 alsa_rate
= SND_PCM_RATE_11025
;
129 alsa_rate
= SND_PCM_RATE_16000
;
132 alsa_rate
= SND_PCM_RATE_22050
;
135 alsa_rate
= SND_PCM_RATE_32000
;
138 alsa_rate
= SND_PCM_RATE_44100
;
141 alsa_rate
= SND_PCM_RATE_48000
;
144 alsa_rate
= SND_PCM_RATE_88200
;
147 alsa_rate
= SND_PCM_RATE_96000
;
150 alsa_rate
= SND_PCM_RATE_176400
;
153 alsa_rate
= SND_PCM_RATE_192000
;
156 alsa_rate
= SND_PCM_RATE_CONTINUOUS
;
160 alsa_format
.rate
= ao_data
.samplerate
;
161 alsa_format
.voices
= ao_data
.channels
;
162 alsa_format
.interleave
= 1;
164 if ((err
= snd_pcm_open(&alsa_handler
, 0, 0, SND_PCM_OPEN_PLAYBACK
)) < 0)
166 mp_msg(MSGT_AO
, MSGL_ERR
, MSGTR_AO_ALSA5_PlayBackError
, snd_strerror(err
));
170 if ((err
= snd_pcm_info(alsa_handler
, &info
)) < 0)
172 mp_msg(MSGT_AO
, MSGL_ERR
, MSGTR_AO_ALSA5_PcmInfoError
, snd_strerror(err
));
176 mp_msg(MSGT_AO
, MSGL_INFO
, MSGTR_AO_ALSA5_SoundcardsFound
,
179 if (info
.flags
& SND_PCM_INFO_PLAYBACK
)
181 memset(&chninfo
, 0, sizeof(chninfo
));
182 chninfo
.channel
= SND_PCM_CHANNEL_PLAYBACK
;
183 if ((err
= snd_pcm_channel_info(alsa_handler
, &chninfo
)) < 0)
185 mp_msg(MSGT_AO
, MSGL_ERR
, MSGTR_AO_ALSA5_PcmChanInfoError
, snd_strerror(err
));
190 if (chninfo
.buffer_size
)
191 ao_data
.buffersize
= chninfo
.buffer_size
;
194 mp_msg(MSGT_AO
, MSGL_V
, "alsa-init: setting preferred buffer size from driver: %d bytes\n",
198 memset(¶ms
, 0, sizeof(params
));
199 params
.channel
= SND_PCM_CHANNEL_PLAYBACK
;
200 params
.mode
= SND_PCM_MODE_STREAM
;
201 params
.format
= alsa_format
;
202 params
.start_mode
= SND_PCM_START_DATA
;
203 params
.stop_mode
= SND_PCM_STOP_ROLLOVER
;
204 params
.buf
.stream
.queue_size
= ao_data
.buffersize
;
205 params
.buf
.stream
.fill
= SND_PCM_FILL_NONE
;
207 if ((err
= snd_pcm_channel_params(alsa_handler
, ¶ms
)) < 0)
209 mp_msg(MSGT_AO
, MSGL_ERR
, MSGTR_AO_ALSA5_CantSetParms
, snd_strerror(err
));
213 memset(&setup
, 0, sizeof(setup
));
214 setup
.channel
= SND_PCM_CHANNEL_PLAYBACK
;
215 setup
.mode
= SND_PCM_MODE_STREAM
;
216 setup
.format
= alsa_format
;
217 setup
.buf
.stream
.queue_size
= ao_data
.buffersize
;
218 setup
.msbits_per_sample
= ao_data
.bps
;
220 if ((err
= snd_pcm_channel_setup(alsa_handler
, &setup
)) < 0)
222 mp_msg(MSGT_AO
, MSGL_ERR
, MSGTR_AO_ALSA5_CantSetChan
, snd_strerror(err
));
226 if ((err
= snd_pcm_channel_prepare(alsa_handler
, SND_PCM_CHANNEL_PLAYBACK
)) < 0)
228 mp_msg(MSGT_AO
, MSGL_ERR
, MSGTR_AO_ALSA5_ChanPrepareError
, snd_strerror(err
));
232 mp_msg(MSGT_AO
, MSGL_INFO
, "AUDIO: %d Hz/%d channels/%d bps/%d bytes buffer/%s\n",
233 ao_data
.samplerate
, ao_data
.channels
, ao_data
.bps
, ao_data
.buffersize
,
234 snd_pcm_get_format_name(alsa_format
.format
));
238 /* close audio device */
239 static void uninit(int immed
)
243 if ((err
= snd_pcm_playback_drain(alsa_handler
)) < 0)
245 mp_msg(MSGT_AO
, MSGL_ERR
, MSGTR_AO_ALSA5_DrainError
, snd_strerror(err
));
249 if ((err
= snd_pcm_channel_flush(alsa_handler
, SND_PCM_CHANNEL_PLAYBACK
)) < 0)
251 mp_msg(MSGT_AO
, MSGL_ERR
, MSGTR_AO_ALSA5_FlushError
, snd_strerror(err
));
255 if ((err
= snd_pcm_close(alsa_handler
)) < 0)
257 mp_msg(MSGT_AO
, MSGL_ERR
, MSGTR_AO_ALSA5_PcmCloseError
, snd_strerror(err
));
262 /* stop playing and empty buffers (for seeking/pause) */
263 static void reset(void)
267 if ((err
= snd_pcm_playback_drain(alsa_handler
)) < 0)
269 mp_msg(MSGT_AO
, MSGL_ERR
, MSGTR_AO_ALSA5_ResetDrainError
, snd_strerror(err
));
273 if ((err
= snd_pcm_channel_flush(alsa_handler
, SND_PCM_CHANNEL_PLAYBACK
)) < 0)
275 mp_msg(MSGT_AO
, MSGL_ERR
, MSGTR_AO_ALSA5_ResetFlushError
, snd_strerror(err
));
279 if ((err
= snd_pcm_channel_prepare(alsa_handler
, SND_PCM_CHANNEL_PLAYBACK
)) < 0)
281 mp_msg(MSGT_AO
, MSGL_ERR
, MSGTR_AO_ALSA5_ResetChanPrepareError
, snd_strerror(err
));
286 /* stop playing, keep buffers (for pause) */
287 static void audio_pause(void)
291 if ((err
= snd_pcm_playback_drain(alsa_handler
)) < 0)
293 mp_msg(MSGT_AO
, MSGL_ERR
, MSGTR_AO_ALSA5_PauseDrainError
, snd_strerror(err
));
297 if ((err
= snd_pcm_channel_flush(alsa_handler
, SND_PCM_CHANNEL_PLAYBACK
)) < 0)
299 mp_msg(MSGT_AO
, MSGL_ERR
, MSGTR_AO_ALSA5_PauseFlushError
, snd_strerror(err
));
304 /* resume playing, after audio_pause() */
305 static void audio_resume(void)
308 if ((err
= snd_pcm_channel_prepare(alsa_handler
, SND_PCM_CHANNEL_PLAYBACK
)) < 0)
310 mp_msg(MSGT_AO
, MSGL_ERR
, MSGTR_AO_ALSA5_ResumePrepareError
, snd_strerror(err
));
316 plays 'len' bytes of 'data'
317 returns: number of bytes played
319 static int play(void* data
, int len
, int flags
)
326 if ((got_len
= snd_pcm_write(alsa_handler
, data
, len
)) < 0)
328 if (got_len
== -EPIPE
) /* underrun? */
330 mp_msg(MSGT_AO
, MSGL_ERR
, MSGTR_AO_ALSA5_Underrun
);
331 if ((got_len
= snd_pcm_channel_prepare(alsa_handler
, SND_PCM_CHANNEL_PLAYBACK
)) < 0)
333 mp_msg(MSGT_AO
, MSGL_ERR
, MSGTR_AO_ALSA5_PlaybackPrepareError
, snd_strerror(got_len
));
336 if ((got_len
= snd_pcm_write(alsa_handler
, data
, len
)) < 0)
338 mp_msg(MSGT_AO
, MSGL_ERR
, MSGTR_AO_ALSA5_WriteErrorAfterReset
,
339 snd_strerror(got_len
));
342 return got_len
; /* 2nd write was ok */
344 mp_msg(MSGT_AO
, MSGL_ERR
, MSGTR_AO_ALSA5_OutPutError
, snd_strerror(got_len
));
350 /* how many byes are free in the buffer */
351 static int get_space(void)
353 snd_pcm_channel_status_t ch_stat
;
355 ch_stat
.channel
= SND_PCM_CHANNEL_PLAYBACK
;
357 if (snd_pcm_channel_status(alsa_handler
, &ch_stat
) < 0)
358 return 0; /* error occurred */
363 /* delay in seconds between first and last sample in buffer */
364 static float get_delay(void)
366 snd_pcm_channel_status_t ch_stat
;
368 ch_stat
.channel
= SND_PCM_CHANNEL_PLAYBACK
;
370 if (snd_pcm_channel_status(alsa_handler
, &ch_stat
) < 0)
371 return (float)ao_data
.buffersize
/(float)ao_data
.bps
; /* error occurred */
373 return (float)ch_stat
.count
/(float)ao_data
.bps
;