Mercurial > mplayer.hg
comparison libao2/ao_alsa9.c @ 1050:87eb4325baf6
first release, meg nem akar menni :(
author | al3x |
---|---|
date | Thu, 07 Jun 2001 15:43:47 +0000 |
parents | |
children | cab5ba9ffc6c |
comparison
equal
deleted
inserted
replaced
1049:ce338825e215 | 1050:87eb4325baf6 |
---|---|
1 /* | |
2 ao_alsa9 - ALSA-0.9.x output plugin for MPlayer | |
3 | |
4 (C) Alex Beregszaszi <alex@naxine.org> | |
5 */ | |
6 | |
7 #include <errno.h> | |
8 #include <sys/soundcard.h> /* AFMT_* */ | |
9 #include <sys/asoundlib.h> | |
10 | |
11 #include "../config.h" | |
12 | |
13 #include "audio_out.h" | |
14 #include "audio_out_internal.h" | |
15 | |
16 extern int verbose; | |
17 | |
18 static ao_info_t info = | |
19 { | |
20 "ALSA-0.9.x audio output", | |
21 "alsa9", | |
22 "Alex Beregszaszi <alex@naxine.org>", | |
23 "under developement" | |
24 }; | |
25 | |
26 LIBAO_EXTERN(alsa9) | |
27 | |
28 /* global variables: | |
29 ao_samplerate | |
30 ao_channels | |
31 ao_format | |
32 ao_bps | |
33 ao_outburst | |
34 ao_buffersize | |
35 */ | |
36 | |
37 static snd_pcm_t *alsa_handler; | |
38 static snd_pcm_format_t alsa_format; | |
39 static snd_pcm_hw_params_t *alsa_hwparams; | |
40 static snd_pcm_sw_params_t *alsa_swparams; | |
41 static char *alsa_device; | |
42 #define ALSA_DEVICE_SIZE 48 | |
43 | |
44 /* to set/get/query special features/parameters */ | |
45 static int control(int cmd, int arg) | |
46 { | |
47 switch(cmd) | |
48 { | |
49 case AOCONTROL_GET_DEVICE: | |
50 return(char *)alsa_device; /* egy kicsit brutalis, dehat :) */ | |
51 case AOCONTROL_SET_DEVICE: | |
52 strncpy(alsa_device, (char *)arg, ALSA_DEVICE_SIZE); | |
53 break; | |
54 } | |
55 return(CONTROL_UNKNOWN); | |
56 } | |
57 | |
58 /* | |
59 open & setup audio device | |
60 return: 1=success 0=fail | |
61 */ | |
62 static int init(int rate_hz, int channels, int format, int flags) | |
63 { | |
64 int err; | |
65 int cards = -1; | |
66 snd_pcm_info_t *alsa_info; | |
67 int chunck_size; | |
68 | |
69 printf("alsa-init: requested format: %d Hz, %d channels, %s\n", rate_hz, | |
70 channels, audio_out_format_name(format)); | |
71 | |
72 alsa_handler = NULL; | |
73 | |
74 if (verbose) | |
75 printf("alsa-init: compiled for ALSA-%s (%d)\n", SND_LIB_VERSION_STR, | |
76 SND_LIB_VERSION); | |
77 | |
78 if ((err = snd_card_next(&cards)) < 0 || cards < 0) | |
79 { | |
80 printf("alsa-init: no soundcards found: %s\n", snd_strerror(err)); | |
81 return(0); | |
82 } | |
83 | |
84 ao_format = format; | |
85 ao_channels = channels - 1; | |
86 ao_samplerate = rate_hz; | |
87 ao_bps = ao_samplerate*(ao_channels+1); | |
88 ao_outburst = OUTBURST; | |
89 ao_buffersize = 16384; | |
90 | |
91 memset(&alsa_format, 0, sizeof(alsa_format)); | |
92 switch (format) | |
93 { | |
94 case AFMT_S8: | |
95 alsa_format = SND_PCM_FORMAT_S8; | |
96 break; | |
97 case AFMT_U8: | |
98 alsa_format = SND_PCM_FORMAT_U8; | |
99 break; | |
100 case AFMT_U16_LE: | |
101 alsa_format = SND_PCM_FORMAT_U16_LE; | |
102 break; | |
103 case AFMT_U16_BE: | |
104 alsa_format = SND_PCM_FORMAT_U16_BE; | |
105 break; | |
106 case AFMT_S16_LE: | |
107 alsa_format = SND_PCM_FORMAT_S16_LE; | |
108 break; | |
109 case AFMT_S16_BE: | |
110 alsa_format = SND_PCM_FORMAT_S16_BE; | |
111 break; | |
112 default: | |
113 alsa_format = SND_PCM_FORMAT_MPEG; | |
114 break; | |
115 } | |
116 | |
117 switch(alsa_format) | |
118 { | |
119 case SND_PCM_FORMAT_S16_LE: | |
120 case SND_PCM_FORMAT_U16_LE: | |
121 ao_bps *= 2; | |
122 break; | |
123 case -1: | |
124 printf("alsa-init: invalid format (%s) requested - output disabled\n", | |
125 audio_out_format_name(format)); | |
126 return(0); | |
127 } | |
128 | |
129 if ((err = snd_pcm_info_malloc(&alsa_info)) < 0) | |
130 { | |
131 printf("alsa-init: memory allocation error: %s\n", snd_strerror(err)); | |
132 return(0); | |
133 } | |
134 | |
135 if ((alsa_device = malloc(ALSA_DEVICE_SIZE)) == NULL) | |
136 { | |
137 printf("alsa-init: memory allocation error: %s\n", strerror(errno)); | |
138 return(0); | |
139 } | |
140 | |
141 snprintf(alsa_device, ALSA_DEVICE_SIZE, "hw:%d,%d", | |
142 snd_pcm_info_get_device(alsa_info), | |
143 snd_pcm_info_get_subdevice(alsa_info)); | |
144 | |
145 snd_pcm_info_free(alsa_info); | |
146 | |
147 printf("alsa-init: %d soundcard%s found, using: %s\n", cards+1, | |
148 (cards >= 0) ? "" : "s", alsa_device); | |
149 | |
150 if ((err = snd_pcm_open(&alsa_handler, alsa_device, SND_PCM_STREAM_PLAYBACK, | |
151 0)) < 0) | |
152 { | |
153 printf("alsa-init: playback open error: %s\n", snd_strerror(err)); | |
154 return(0); | |
155 } | |
156 | |
157 snd_pcm_hw_params_malloc(&alsa_hwparams); | |
158 snd_pcm_sw_params_malloc(&alsa_swparams); | |
159 | |
160 if ((err = snd_pcm_hw_params_any(alsa_handler, alsa_hwparams)) < 0) | |
161 { | |
162 printf("alsa-init: unable to get initial parameters: %s\n", | |
163 snd_strerror(err)); | |
164 return(0); | |
165 } | |
166 | |
167 if ((err = snd_pcm_hw_params_set_access(alsa_handler, alsa_hwparams, | |
168 SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) | |
169 { | |
170 printf("alsa-init: unable to set access type: %s\n", | |
171 snd_strerror(err)); | |
172 return(0); | |
173 } | |
174 | |
175 if ((err = snd_pcm_hw_params_set_format(alsa_handler, alsa_hwparams, | |
176 alsa_format)) < 0) | |
177 { | |
178 printf("alsa-init: unable to set format: %s\n", | |
179 snd_strerror(err)); | |
180 return(0); | |
181 } | |
182 | |
183 if ((err = snd_pcm_hw_params_set_channels(alsa_handler, alsa_hwparams, | |
184 ao_channels)) < 0) | |
185 { | |
186 printf("alsa-init: unable to set channels: %s\n", | |
187 snd_strerror(err)); | |
188 return(0); | |
189 } | |
190 | |
191 if ((err = snd_pcm_hw_params_set_rate(alsa_handler, alsa_hwparams, | |
192 ao_samplerate, 0)) < 0) | |
193 { | |
194 printf("alsa-init: unable to set channels: %s\n", | |
195 snd_strerror(err)); | |
196 return(0); | |
197 } | |
198 | |
199 #ifdef buffersize | |
200 if ((err = snd_pcm_hw_params_get_buffer_size(alsa_hwparams)) < 0) | |
201 { | |
202 printf("alsa-init: unable to get buffer size: %s\n", | |
203 snd_strerror(err)); | |
204 return(0); | |
205 } else | |
206 ao_buffersize = err; | |
207 #endif | |
208 | |
209 #ifdef buffertime | |
210 { | |
211 int alsa_buffer_time = 60; | |
212 | |
213 if ((err = snd_pcm_hw_params_set_buffer_time_near(alsa_handler, alsa_hwparams, | |
214 alsa_buffer_time, 0)) < 0) | |
215 { | |
216 printf("alsa-init: unable to set buffer time near: %s\n", | |
217 snd_strerror(err)); | |
218 return(0); | |
219 } else | |
220 alsa_buffer_time = err; | |
221 | |
222 if ((err = snd_pcm_hw_params_set_period_time_near(alsa_handler, alsa_hwparams, | |
223 alsa_buffer_time/ao_bps, 0)) < 0) | |
224 { | |
225 printf("alsa-init: unable to set period time: %s\n", | |
226 snd_strerror(err)); | |
227 return(0); | |
228 } | |
229 } | |
230 #endif | |
231 | |
232 if ((err = snd_pcm_hw_params(alsa_handler, alsa_hwparams)) < 0) | |
233 { | |
234 printf("alsa-init: unable to set parameters: %s\n", | |
235 snd_strerror(err)); | |
236 return(0); | |
237 } | |
238 | |
239 if ((err = snd_pcm_sw_params_current(alsa_handler, alsa_swparams)) < 0) | |
240 { | |
241 printf("alsa-init: unable to get parameters: %s\n", | |
242 snd_strerror(err)); | |
243 return(0); | |
244 } | |
245 | |
246 if ((err = snd_pcm_sw_params_set_start_mode(alsa_handler, alsa_swparams, | |
247 SND_PCM_START_DATA)) < 0) | |
248 { | |
249 printf("alsa-init: unable to set start mode: %s\n", | |
250 snd_strerror(err)); | |
251 return(0); | |
252 } | |
253 | |
254 if ((err = snd_pcm_sw_params(alsa_handler, alsa_swparams)) < 0) | |
255 { | |
256 printf("alsa-init: unable to set parameters: %s\n", | |
257 snd_strerror(err)); | |
258 return(0); | |
259 } | |
260 | |
261 snd_pcm_sw_params_default(alsa_handler, alsa_swparams); | |
262 | |
263 if ((err = snd_pcm_prepare(alsa_handler)) < 0) | |
264 { | |
265 printf("alsa-init: pcm prepare error: %s\n", snd_strerror(err)); | |
266 return(0); | |
267 } | |
268 | |
269 if ((err = snd_pcm_start(alsa_handler)) < 0) | |
270 { | |
271 printf("alsa-init: pcm start error: %s\n", snd_strerror(err)); | |
272 if (err != -EPIPE) | |
273 return(0); | |
274 if ((err = snd_pcm_start(alsa_handler)) < 0) | |
275 { | |
276 printf("alsa-init: pcm start error: %s\n", snd_strerror(err)); | |
277 return(0); | |
278 } | |
279 } | |
280 | |
281 printf("AUDIO: %d Hz/%d channels/%d bps/%d bytes buffer/%s\n", | |
282 ao_samplerate, ao_channels+1, ao_bps, ao_buffersize, | |
283 snd_pcm_format_description(alsa_format)); | |
284 return(1); | |
285 } | |
286 | |
287 /* close audio device */ | |
288 static void uninit() | |
289 { | |
290 int err; | |
291 | |
292 if (alsa_device != NULL) | |
293 free(alsa_device); | |
294 | |
295 snd_pcm_hw_params_free(alsa_hwparams); | |
296 snd_pcm_sw_params_free(alsa_swparams); | |
297 | |
298 if ((err = snd_pcm_drain(alsa_handler)) < 0) | |
299 { | |
300 printf("alsa-uninit: pcm drain error: %s\n", snd_strerror(err)); | |
301 return; | |
302 } | |
303 | |
304 if ((err = snd_pcm_reset(alsa_handler)) < 0) | |
305 { | |
306 printf("alsa-uninit: pcm reset error: %s\n", snd_strerror(err)); | |
307 return; | |
308 } | |
309 | |
310 if ((err = snd_pcm_close(alsa_handler)) < 0) | |
311 { | |
312 printf("alsa-uninit: pcm close error: %s\n", snd_strerror(err)); | |
313 return; | |
314 } | |
315 } | |
316 | |
317 static void audio_pause() | |
318 { | |
319 int err; | |
320 | |
321 if ((err = snd_pcm_drain(alsa_handler)) < 0) | |
322 { | |
323 printf("alsa-pause: pcm drain error: %s\n", snd_strerror(err)); | |
324 return; | |
325 } | |
326 | |
327 if ((err = snd_pcm_reset(alsa_handler)) < 0) | |
328 { | |
329 printf("alsa-pause: pcm reset error: %s\n", snd_strerror(err)); | |
330 return; | |
331 } | |
332 } | |
333 | |
334 static void audio_resume() | |
335 { | |
336 int err; | |
337 | |
338 if ((err = snd_pcm_prepare(alsa_handler)) < 0) | |
339 { | |
340 printf("alsa-resume: pcm prepare error: %s\n", snd_strerror(err)); | |
341 return; | |
342 } | |
343 | |
344 if ((err = snd_pcm_start(alsa_handler)) < 0) | |
345 { | |
346 printf("alsa-resume: pcm start error: %s\n", snd_strerror(err)); | |
347 return; | |
348 } | |
349 } | |
350 | |
351 /* stop playing and empty buffers (for seeking/pause) */ | |
352 static void reset() | |
353 { | |
354 int err; | |
355 | |
356 if ((err = snd_pcm_drain(alsa_handler)) < 0) | |
357 { | |
358 printf("alsa-reset: pcm drain error: %s\n", snd_strerror(err)); | |
359 return; | |
360 } | |
361 | |
362 if ((err = snd_pcm_reset(alsa_handler)) < 0) | |
363 { | |
364 printf("alsa-reset: pcm reset error: %s\n", snd_strerror(err)); | |
365 return; | |
366 } | |
367 | |
368 if ((err = snd_pcm_prepare(alsa_handler)) < 0) | |
369 { | |
370 printf("alsa-reset: pcm prepare error: %s\n", snd_strerror(err)); | |
371 return; | |
372 } | |
373 | |
374 if ((err = snd_pcm_start(alsa_handler)) < 0) | |
375 { | |
376 printf("alsa-reset: pcm start error: %s\n", snd_strerror(err)); | |
377 return; | |
378 } | |
379 } | |
380 | |
381 /* | |
382 plays 'len' bytes of 'data' | |
383 returns: number of bytes played | |
384 */ | |
385 static int play(void* data, int len, int flags) | |
386 { | |
387 if ((len = snd_pcm_writei(alsa_handler, data, len)) != len) | |
388 { | |
389 if (len == -EPIPE) /* underrun? */ | |
390 { | |
391 printf("alsa-play: alsa underrun, resetting stream\n"); | |
392 if ((len = snd_pcm_prepare(alsa_handler)) < 0) | |
393 { | |
394 printf("alsa-play: playback prepare error: %s\n", snd_strerror(len)); | |
395 return(0); | |
396 } | |
397 if ((len = snd_pcm_writei(alsa_handler, data, len)) != len) | |
398 { | |
399 printf("alsa-play: write error after reset: %s - giving up\n", | |
400 snd_strerror(len)); | |
401 return(0); | |
402 } | |
403 return(len); /* 2nd write was ok */ | |
404 } | |
405 printf("alsa-play: output error: %s\n", snd_strerror(len)); | |
406 } | |
407 return(len); | |
408 } | |
409 | |
410 /* how many byes are free in the buffer */ | |
411 static int get_space() | |
412 { | |
413 snd_pcm_status_t *status; | |
414 int ret; | |
415 | |
416 if ((ret = snd_pcm_status_malloc(&status)) < 0) | |
417 { | |
418 printf("alsa-space: memory allocation error: %s\n", snd_strerror(ret)); | |
419 return(0); | |
420 } | |
421 | |
422 if ((ret = snd_pcm_status(alsa_handler, status)) < 0) | |
423 { | |
424 printf("alsa-space: cannot get pcm status: %s\n", snd_strerror(ret)); | |
425 return(0); | |
426 } | |
427 | |
428 switch(snd_pcm_status_get_state(status)) | |
429 { | |
430 case SND_PCM_STATE_OPEN: | |
431 case SND_PCM_STATE_PREPARED: | |
432 case SND_PCM_STATE_RUNNING: | |
433 ret = snd_pcm_status_get_avail(status) * ao_bps; | |
434 break; | |
435 default: | |
436 ret = 0; | |
437 } | |
438 | |
439 snd_pcm_status_free(status); | |
440 return(ret); | |
441 } | |
442 | |
443 /* how many unplayed bytes are in the buffer */ | |
444 static int get_delay() | |
445 { | |
446 snd_pcm_status_t *status; | |
447 int ret; | |
448 | |
449 if ((ret = snd_pcm_status_malloc(&status)) < 0) | |
450 { | |
451 printf("alsa-delay: memory allocation error: %s\n", snd_strerror(ret)); | |
452 return(0); | |
453 } | |
454 | |
455 if ((ret = snd_pcm_status(alsa_handler, status)) < 0) | |
456 { | |
457 printf("alsa-delay: cannot get pcm status: %s\n", snd_strerror(ret)); | |
458 return(0); | |
459 } | |
460 | |
461 switch(snd_pcm_status_get_state(status)) | |
462 { | |
463 case SND_PCM_STATE_OPEN: | |
464 case SND_PCM_STATE_PREPARED: | |
465 case SND_PCM_STATE_RUNNING: | |
466 ret = snd_pcm_status_get_delay(status) * ao_bps; | |
467 break; | |
468 default: | |
469 ret = 0; | |
470 } | |
471 | |
472 snd_pcm_status_free(status); | |
473 return(ret); | |
474 } |