Apply patch for oCERT #2008-013 / CVE-2008-3827
[mplayer/glamo.git] / libao2 / ao_alsa5.c
blob7bec0371e66bed53588e911105cea287331c7f9e
1 /*
2 ao_alsa5 - ALSA-0.5.x output plugin for MPlayer
4 (C) Alex Beregszaszi
6 Thanks to Arpi for helping me ;)
7 */
9 #include <errno.h>
10 #include <sys/asoundlib.h>
12 #include "config.h"
14 #include "audio_out.h"
15 #include "audio_out_internal.h"
16 #include "libaf/af_format.h"
18 #include "mp_msg.h"
19 #include "help_mp.h"
21 static ao_info_t info =
23 "ALSA-0.5.x audio output",
24 "alsa5",
25 "Alex Beregszaszi",
29 LIBAO_EXTERN(alsa5)
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)
47 int err;
48 int cards = -1;
49 snd_pcm_channel_params_t params;
50 snd_pcm_channel_setup_t setup;
51 snd_pcm_info_t info;
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));
57 alsa_handler = NULL;
59 mp_msg(MSGT_AO, MSGL_V, "alsa-init: compiled for ALSA-%s (%d)\n", SND_LIB_VERSION_STR,
60 SND_LIB_VERSION);
62 if ((cards = snd_cards()) < 0)
64 mp_msg(MSGT_AO, MSGL_ERR, MSGTR_AO_ALSA5_SoundCardNotFound);
65 return 0;
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));
76 switch (format)
78 case AF_FORMAT_S8:
79 alsa_format.format = SND_PCM_SFMT_S8;
80 break;
81 case AF_FORMAT_U8:
82 alsa_format.format = SND_PCM_SFMT_U8;
83 break;
84 case AF_FORMAT_U16_LE:
85 alsa_format.format = SND_PCM_SFMT_U16_LE;
86 break;
87 case AF_FORMAT_U16_BE:
88 alsa_format.format = SND_PCM_SFMT_U16_BE;
89 break;
90 #ifndef WORDS_BIGENDIAN
91 case AF_FORMAT_AC3:
92 #endif
93 case AF_FORMAT_S16_LE:
94 alsa_format.format = SND_PCM_SFMT_S16_LE;
95 break;
96 #ifdef WORDS_BIGENDIAN
97 case AF_FORMAT_AC3:
98 #endif
99 case AF_FORMAT_S16_BE:
100 alsa_format.format = SND_PCM_SFMT_S16_BE;
101 break;
102 default:
103 alsa_format.format = SND_PCM_SFMT_MPEG;
104 break;
107 switch(alsa_format.format)
109 case SND_PCM_SFMT_S16_LE:
110 case SND_PCM_SFMT_U16_LE:
111 ao_data.bps *= 2;
112 break;
113 case -1:
114 mp_msg(MSGT_AO, MSGL_ERR, MSGTR_AO_ALSA5_InvalidFormatReq,af_fmt2str_short(format));
115 return 0;
116 default:
117 break;
120 switch(rate_hz)
122 case 8000:
123 alsa_rate = SND_PCM_RATE_8000;
124 break;
125 case 11025:
126 alsa_rate = SND_PCM_RATE_11025;
127 break;
128 case 16000:
129 alsa_rate = SND_PCM_RATE_16000;
130 break;
131 case 22050:
132 alsa_rate = SND_PCM_RATE_22050;
133 break;
134 case 32000:
135 alsa_rate = SND_PCM_RATE_32000;
136 break;
137 case 44100:
138 alsa_rate = SND_PCM_RATE_44100;
139 break;
140 case 48000:
141 alsa_rate = SND_PCM_RATE_48000;
142 break;
143 case 88200:
144 alsa_rate = SND_PCM_RATE_88200;
145 break;
146 case 96000:
147 alsa_rate = SND_PCM_RATE_96000;
148 break;
149 case 176400:
150 alsa_rate = SND_PCM_RATE_176400;
151 break;
152 case 192000:
153 alsa_rate = SND_PCM_RATE_192000;
154 break;
155 default:
156 alsa_rate = SND_PCM_RATE_CONTINUOUS;
157 break;
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));
167 return 0;
170 if ((err = snd_pcm_info(alsa_handler, &info)) < 0)
172 mp_msg(MSGT_AO, MSGL_ERR, MSGTR_AO_ALSA5_PcmInfoError, snd_strerror(err));
173 return 0;
176 mp_msg(MSGT_AO, MSGL_INFO, MSGTR_AO_ALSA5_SoundcardsFound,
177 cards, info.name);
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));
186 return 0;
189 #ifndef __QNX__
190 if (chninfo.buffer_size)
191 ao_data.buffersize = chninfo.buffer_size;
192 #endif
194 mp_msg(MSGT_AO, MSGL_V, "alsa-init: setting preferred buffer size from driver: %d bytes\n",
195 ao_data.buffersize);
198 memset(&params, 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, &params)) < 0)
209 mp_msg(MSGT_AO, MSGL_ERR, MSGTR_AO_ALSA5_CantSetParms, snd_strerror(err));
210 return 0;
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));
223 return 0;
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));
229 return 0;
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));
235 return 1;
238 /* close audio device */
239 static void uninit(int immed)
241 int err;
243 if ((err = snd_pcm_playback_drain(alsa_handler)) < 0)
245 mp_msg(MSGT_AO, MSGL_ERR, MSGTR_AO_ALSA5_DrainError, snd_strerror(err));
246 return;
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));
252 return;
255 if ((err = snd_pcm_close(alsa_handler)) < 0)
257 mp_msg(MSGT_AO, MSGL_ERR, MSGTR_AO_ALSA5_PcmCloseError, snd_strerror(err));
258 return;
262 /* stop playing and empty buffers (for seeking/pause) */
263 static void reset(void)
265 int err;
267 if ((err = snd_pcm_playback_drain(alsa_handler)) < 0)
269 mp_msg(MSGT_AO, MSGL_ERR, MSGTR_AO_ALSA5_ResetDrainError, snd_strerror(err));
270 return;
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));
276 return;
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));
282 return;
286 /* stop playing, keep buffers (for pause) */
287 static void audio_pause(void)
289 int err;
291 if ((err = snd_pcm_playback_drain(alsa_handler)) < 0)
293 mp_msg(MSGT_AO, MSGL_ERR, MSGTR_AO_ALSA5_PauseDrainError, snd_strerror(err));
294 return;
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));
300 return;
304 /* resume playing, after audio_pause() */
305 static void audio_resume(void)
307 int err;
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));
311 return;
316 plays 'len' bytes of 'data'
317 returns: number of bytes played
319 static int play(void* data, int len, int flags)
321 int got_len;
323 if (!len)
324 return 0;
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));
334 return 0;
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));
340 return 0;
342 return got_len; /* 2nd write was ok */
344 mp_msg(MSGT_AO, MSGL_ERR, MSGTR_AO_ALSA5_OutPutError, snd_strerror(got_len));
345 return 0;
347 return 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 */
359 else
360 return ch_stat.free;
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 */
372 else
373 return (float)ch_stat.count/(float)ao_data.bps;