Mercurial > mplayer.hg
annotate libao2/ao_alsa9.c @ 1116:faa68f4c03be
unstable gcc-3.0 warning surpressing
author | nickols_k |
---|---|
date | Tue, 12 Jun 2001 15:55:59 +0000 |
parents | a16b569f2702 |
children | d2dd25dd11bc |
rev | line source |
---|---|
1050 | 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/asoundlib.h> | |
9 | |
10 #include "../config.h" | |
11 | |
12 #include "audio_out.h" | |
13 #include "audio_out_internal.h" | |
1058 | 14 #include "afmt.h" |
1050 | 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 | |
1115
a16b569f2702
-Wall style cleanups, TEST IT, it can be working by others
al3x
parents:
1058
diff
changeset
|
58 #define start |
1050 | 59 /* |
60 open & setup audio device | |
61 return: 1=success 0=fail | |
62 */ | |
63 static int init(int rate_hz, int channels, int format, int flags) | |
64 { | |
65 int err; | |
66 int cards = -1; | |
67 snd_pcm_info_t *alsa_info; | |
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 switch (format) | |
92 { | |
93 case AFMT_S8: | |
94 alsa_format = SND_PCM_FORMAT_S8; | |
95 break; | |
96 case AFMT_U8: | |
97 alsa_format = SND_PCM_FORMAT_U8; | |
98 break; | |
99 case AFMT_U16_LE: | |
100 alsa_format = SND_PCM_FORMAT_U16_LE; | |
101 break; | |
102 case AFMT_U16_BE: | |
103 alsa_format = SND_PCM_FORMAT_U16_BE; | |
104 break; | |
105 case AFMT_S16_LE: | |
106 alsa_format = SND_PCM_FORMAT_S16_LE; | |
107 break; | |
108 case AFMT_S16_BE: | |
109 alsa_format = SND_PCM_FORMAT_S16_BE; | |
110 break; | |
111 default: | |
112 alsa_format = SND_PCM_FORMAT_MPEG; | |
113 break; | |
114 } | |
115 | |
116 switch(alsa_format) | |
117 { | |
118 case SND_PCM_FORMAT_S16_LE: | |
119 case SND_PCM_FORMAT_U16_LE: | |
120 ao_bps *= 2; | |
121 break; | |
122 case -1: | |
123 printf("alsa-init: invalid format (%s) requested - output disabled\n", | |
124 audio_out_format_name(format)); | |
125 return(0); | |
1115
a16b569f2702
-Wall style cleanups, TEST IT, it can be working by others
al3x
parents:
1058
diff
changeset
|
126 default: |
a16b569f2702
-Wall style cleanups, TEST IT, it can be working by others
al3x
parents:
1058
diff
changeset
|
127 break; |
1050 | 128 } |
129 | |
130 if ((err = snd_pcm_info_malloc(&alsa_info)) < 0) | |
131 { | |
132 printf("alsa-init: memory allocation error: %s\n", snd_strerror(err)); | |
133 return(0); | |
134 } | |
135 | |
136 if ((alsa_device = malloc(ALSA_DEVICE_SIZE)) == NULL) | |
137 { | |
138 printf("alsa-init: memory allocation error: %s\n", strerror(errno)); | |
139 return(0); | |
140 } | |
141 | |
142 snprintf(alsa_device, ALSA_DEVICE_SIZE, "hw:%d,%d", | |
143 snd_pcm_info_get_device(alsa_info), | |
144 snd_pcm_info_get_subdevice(alsa_info)); | |
145 | |
146 snd_pcm_info_free(alsa_info); | |
147 | |
148 printf("alsa-init: %d soundcard%s found, using: %s\n", cards+1, | |
149 (cards >= 0) ? "" : "s", alsa_device); | |
150 | |
151 if ((err = snd_pcm_open(&alsa_handler, alsa_device, SND_PCM_STREAM_PLAYBACK, | |
152 0)) < 0) | |
153 { | |
154 printf("alsa-init: playback open error: %s\n", snd_strerror(err)); | |
155 return(0); | |
156 } | |
157 | |
158 snd_pcm_hw_params_malloc(&alsa_hwparams); | |
159 snd_pcm_sw_params_malloc(&alsa_swparams); | |
160 | |
161 if ((err = snd_pcm_hw_params_any(alsa_handler, alsa_hwparams)) < 0) | |
162 { | |
163 printf("alsa-init: unable to get initial parameters: %s\n", | |
164 snd_strerror(err)); | |
165 return(0); | |
166 } | |
167 | |
168 if ((err = snd_pcm_hw_params_set_access(alsa_handler, alsa_hwparams, | |
169 SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) | |
170 { | |
171 printf("alsa-init: unable to set access type: %s\n", | |
172 snd_strerror(err)); | |
173 return(0); | |
174 } | |
175 | |
176 if ((err = snd_pcm_hw_params_set_format(alsa_handler, alsa_hwparams, | |
177 alsa_format)) < 0) | |
178 { | |
179 printf("alsa-init: unable to set format: %s\n", | |
180 snd_strerror(err)); | |
181 return(0); | |
182 } | |
183 | |
184 if ((err = snd_pcm_hw_params_set_channels(alsa_handler, alsa_hwparams, | |
185 ao_channels)) < 0) | |
186 { | |
187 printf("alsa-init: unable to set channels: %s\n", | |
188 snd_strerror(err)); | |
189 return(0); | |
190 } | |
191 | |
192 if ((err = snd_pcm_hw_params_set_rate(alsa_handler, alsa_hwparams, | |
193 ao_samplerate, 0)) < 0) | |
194 { | |
195 printf("alsa-init: unable to set channels: %s\n", | |
196 snd_strerror(err)); | |
197 return(0); | |
198 } | |
199 | |
1115
a16b569f2702
-Wall style cleanups, TEST IT, it can be working by others
al3x
parents:
1058
diff
changeset
|
200 { |
a16b569f2702
-Wall style cleanups, TEST IT, it can be working by others
al3x
parents:
1058
diff
changeset
|
201 int fragment_size = 4096; |
a16b569f2702
-Wall style cleanups, TEST IT, it can be working by others
al3x
parents:
1058
diff
changeset
|
202 int fragment_count = 8; |
a16b569f2702
-Wall style cleanups, TEST IT, it can be working by others
al3x
parents:
1058
diff
changeset
|
203 snd_pcm_hw_params_set_period_size(alsa_handler, alsa_hwparams, fragment_size / 4, 0); |
a16b569f2702
-Wall style cleanups, TEST IT, it can be working by others
al3x
parents:
1058
diff
changeset
|
204 snd_pcm_hw_params_set_periods(alsa_handler, alsa_hwparams, fragment_count, 0); |
a16b569f2702
-Wall style cleanups, TEST IT, it can be working by others
al3x
parents:
1058
diff
changeset
|
205 } |
a16b569f2702
-Wall style cleanups, TEST IT, it can be working by others
al3x
parents:
1058
diff
changeset
|
206 |
1050 | 207 #ifdef buffersize |
208 if ((err = snd_pcm_hw_params_get_buffer_size(alsa_hwparams)) < 0) | |
209 { | |
210 printf("alsa-init: unable to get buffer size: %s\n", | |
211 snd_strerror(err)); | |
212 return(0); | |
213 } else | |
214 ao_buffersize = err; | |
215 #endif | |
216 | |
217 #ifdef buffertime | |
218 { | |
219 int alsa_buffer_time = 60; | |
220 | |
221 if ((err = snd_pcm_hw_params_set_buffer_time_near(alsa_handler, alsa_hwparams, | |
222 alsa_buffer_time, 0)) < 0) | |
223 { | |
224 printf("alsa-init: unable to set buffer time near: %s\n", | |
225 snd_strerror(err)); | |
226 return(0); | |
227 } else | |
228 alsa_buffer_time = err; | |
229 | |
230 if ((err = snd_pcm_hw_params_set_period_time_near(alsa_handler, alsa_hwparams, | |
231 alsa_buffer_time/ao_bps, 0)) < 0) | |
232 { | |
233 printf("alsa-init: unable to set period time: %s\n", | |
234 snd_strerror(err)); | |
235 return(0); | |
236 } | |
237 } | |
238 #endif | |
239 | |
240 if ((err = snd_pcm_hw_params(alsa_handler, alsa_hwparams)) < 0) | |
241 { | |
242 printf("alsa-init: unable to set parameters: %s\n", | |
243 snd_strerror(err)); | |
244 return(0); | |
245 } | |
246 | |
247 if ((err = snd_pcm_sw_params_current(alsa_handler, alsa_swparams)) < 0) | |
248 { | |
249 printf("alsa-init: unable to get parameters: %s\n", | |
250 snd_strerror(err)); | |
251 return(0); | |
252 } | |
253 | |
254 if ((err = snd_pcm_sw_params_set_start_mode(alsa_handler, alsa_swparams, | |
255 SND_PCM_START_DATA)) < 0) | |
256 { | |
257 printf("alsa-init: unable to set start mode: %s\n", | |
258 snd_strerror(err)); | |
259 return(0); | |
260 } | |
261 | |
262 if ((err = snd_pcm_sw_params(alsa_handler, alsa_swparams)) < 0) | |
263 { | |
264 printf("alsa-init: unable to set parameters: %s\n", | |
265 snd_strerror(err)); | |
266 return(0); | |
267 } | |
268 | |
269 snd_pcm_sw_params_default(alsa_handler, alsa_swparams); | |
270 | |
271 if ((err = snd_pcm_prepare(alsa_handler)) < 0) | |
272 { | |
273 printf("alsa-init: pcm prepare error: %s\n", snd_strerror(err)); | |
274 return(0); | |
275 } | |
276 | |
1115
a16b569f2702
-Wall style cleanups, TEST IT, it can be working by others
al3x
parents:
1058
diff
changeset
|
277 #ifdef start |
1050 | 278 if ((err = snd_pcm_start(alsa_handler)) < 0) |
279 { | |
280 printf("alsa-init: pcm start error: %s\n", snd_strerror(err)); | |
281 if (err != -EPIPE) | |
282 return(0); | |
283 if ((err = snd_pcm_start(alsa_handler)) < 0) | |
284 { | |
285 printf("alsa-init: pcm start error: %s\n", snd_strerror(err)); | |
286 return(0); | |
287 } | |
288 } | |
1115
a16b569f2702
-Wall style cleanups, TEST IT, it can be working by others
al3x
parents:
1058
diff
changeset
|
289 #endif |
1050 | 290 printf("AUDIO: %d Hz/%d channels/%d bps/%d bytes buffer/%s\n", |
291 ao_samplerate, ao_channels+1, ao_bps, ao_buffersize, | |
292 snd_pcm_format_description(alsa_format)); | |
293 return(1); | |
294 } | |
295 | |
296 /* close audio device */ | |
297 static void uninit() | |
298 { | |
299 int err; | |
300 | |
301 if (alsa_device != NULL) | |
302 free(alsa_device); | |
303 | |
304 snd_pcm_hw_params_free(alsa_hwparams); | |
305 snd_pcm_sw_params_free(alsa_swparams); | |
306 | |
307 if ((err = snd_pcm_drain(alsa_handler)) < 0) | |
308 { | |
309 printf("alsa-uninit: pcm drain error: %s\n", snd_strerror(err)); | |
310 return; | |
311 } | |
312 | |
313 if ((err = snd_pcm_reset(alsa_handler)) < 0) | |
314 { | |
315 printf("alsa-uninit: pcm reset error: %s\n", snd_strerror(err)); | |
316 return; | |
317 } | |
318 | |
319 if ((err = snd_pcm_close(alsa_handler)) < 0) | |
320 { | |
321 printf("alsa-uninit: pcm close error: %s\n", snd_strerror(err)); | |
322 return; | |
323 } | |
324 } | |
325 | |
326 static void audio_pause() | |
327 { | |
328 int err; | |
329 | |
330 if ((err = snd_pcm_drain(alsa_handler)) < 0) | |
331 { | |
332 printf("alsa-pause: pcm drain error: %s\n", snd_strerror(err)); | |
333 return; | |
334 } | |
335 | |
336 if ((err = snd_pcm_reset(alsa_handler)) < 0) | |
337 { | |
338 printf("alsa-pause: pcm reset error: %s\n", snd_strerror(err)); | |
339 return; | |
340 } | |
341 } | |
342 | |
343 static void audio_resume() | |
344 { | |
345 int err; | |
346 | |
347 if ((err = snd_pcm_prepare(alsa_handler)) < 0) | |
348 { | |
349 printf("alsa-resume: pcm prepare error: %s\n", snd_strerror(err)); | |
350 return; | |
351 } | |
352 | |
353 if ((err = snd_pcm_start(alsa_handler)) < 0) | |
354 { | |
355 printf("alsa-resume: pcm start error: %s\n", snd_strerror(err)); | |
356 return; | |
357 } | |
358 } | |
359 | |
360 /* stop playing and empty buffers (for seeking/pause) */ | |
361 static void reset() | |
362 { | |
363 int err; | |
364 | |
365 if ((err = snd_pcm_drain(alsa_handler)) < 0) | |
366 { | |
367 printf("alsa-reset: pcm drain error: %s\n", snd_strerror(err)); | |
368 return; | |
369 } | |
370 | |
371 if ((err = snd_pcm_reset(alsa_handler)) < 0) | |
372 { | |
373 printf("alsa-reset: pcm reset error: %s\n", snd_strerror(err)); | |
374 return; | |
375 } | |
376 | |
377 if ((err = snd_pcm_prepare(alsa_handler)) < 0) | |
378 { | |
379 printf("alsa-reset: pcm prepare error: %s\n", snd_strerror(err)); | |
380 return; | |
381 } | |
382 | |
383 if ((err = snd_pcm_start(alsa_handler)) < 0) | |
384 { | |
385 printf("alsa-reset: pcm start error: %s\n", snd_strerror(err)); | |
386 return; | |
387 } | |
388 } | |
389 | |
390 /* | |
391 plays 'len' bytes of 'data' | |
392 returns: number of bytes played | |
393 */ | |
394 static int play(void* data, int len, int flags) | |
395 { | |
1115
a16b569f2702
-Wall style cleanups, TEST IT, it can be working by others
al3x
parents:
1058
diff
changeset
|
396 int got_len; |
a16b569f2702
-Wall style cleanups, TEST IT, it can be working by others
al3x
parents:
1058
diff
changeset
|
397 |
a16b569f2702
-Wall style cleanups, TEST IT, it can be working by others
al3x
parents:
1058
diff
changeset
|
398 if ((got_len = snd_pcm_writei(alsa_handler, data, len/4)) != len/4) |
1050 | 399 { |
1115
a16b569f2702
-Wall style cleanups, TEST IT, it can be working by others
al3x
parents:
1058
diff
changeset
|
400 if (got_len == -EPIPE) /* underrun? */ |
1050 | 401 { |
402 printf("alsa-play: alsa underrun, resetting stream\n"); | |
403 if ((len = snd_pcm_prepare(alsa_handler)) < 0) | |
404 { | |
405 printf("alsa-play: playback prepare error: %s\n", snd_strerror(len)); | |
406 return(0); | |
407 } | |
408 if ((len = snd_pcm_writei(alsa_handler, data, len)) != len) | |
409 { | |
410 printf("alsa-play: write error after reset: %s - giving up\n", | |
411 snd_strerror(len)); | |
412 return(0); | |
413 } | |
414 return(len); /* 2nd write was ok */ | |
415 } | |
416 printf("alsa-play: output error: %s\n", snd_strerror(len)); | |
417 } | |
418 return(len); | |
419 } | |
420 | |
421 /* how many byes are free in the buffer */ | |
422 static int get_space() | |
423 { | |
424 snd_pcm_status_t *status; | |
425 int ret; | |
426 | |
427 if ((ret = snd_pcm_status_malloc(&status)) < 0) | |
428 { | |
429 printf("alsa-space: memory allocation error: %s\n", snd_strerror(ret)); | |
430 return(0); | |
431 } | |
432 | |
433 if ((ret = snd_pcm_status(alsa_handler, status)) < 0) | |
434 { | |
435 printf("alsa-space: cannot get pcm status: %s\n", snd_strerror(ret)); | |
436 return(0); | |
437 } | |
438 | |
439 switch(snd_pcm_status_get_state(status)) | |
440 { | |
441 case SND_PCM_STATE_OPEN: | |
442 case SND_PCM_STATE_PREPARED: | |
443 case SND_PCM_STATE_RUNNING: | |
444 ret = snd_pcm_status_get_avail(status) * ao_bps; | |
445 break; | |
446 default: | |
447 ret = 0; | |
448 } | |
449 | |
450 snd_pcm_status_free(status); | |
451 return(ret); | |
452 } | |
453 | |
454 /* how many unplayed bytes are in the buffer */ | |
455 static int get_delay() | |
456 { | |
457 snd_pcm_status_t *status; | |
458 int ret; | |
459 | |
460 if ((ret = snd_pcm_status_malloc(&status)) < 0) | |
461 { | |
462 printf("alsa-delay: memory allocation error: %s\n", snd_strerror(ret)); | |
463 return(0); | |
464 } | |
465 | |
466 if ((ret = snd_pcm_status(alsa_handler, status)) < 0) | |
467 { | |
468 printf("alsa-delay: cannot get pcm status: %s\n", snd_strerror(ret)); | |
469 return(0); | |
470 } | |
471 | |
472 switch(snd_pcm_status_get_state(status)) | |
473 { | |
474 case SND_PCM_STATE_OPEN: | |
475 case SND_PCM_STATE_PREPARED: | |
476 case SND_PCM_STATE_RUNNING: | |
477 ret = snd_pcm_status_get_delay(status) * ao_bps; | |
478 break; | |
479 default: | |
480 ret = 0; | |
481 } | |
482 | |
483 snd_pcm_status_free(status); | |
484 return(ret); | |
485 } |