Mercurial > mplayer.hg
comparison libao2/ao_alsa1x.c @ 6589:1595ca898d3b
cleanup and bufferhandling fix by Joy Ping <joy at pingfm.org>. Bufferhandling fix based on idea by Marius David <marius at rohost.com>
author | alex |
---|---|
date | Fri, 28 Jun 2002 16:48:10 +0000 |
parents | 156144ee6810 |
children | 769246a4eb41 |
comparison
equal
deleted
inserted
replaced
6588:12826366a806 | 6589:1595ca898d3b |
---|---|
1 /* | 1 /* |
2 ao_alsa9 - ALSA-0.9.x output plugin for MPlayer | 2 ao_alsa9 - ALSA-0.9.x output plugin for MPlayer |
3 | 3 |
4 (C) Alex Beregszaszi <alex@naxine.org> | 4 (C) Alex Beregszaszi <alex@naxine.org> |
5 | 5 |
6 modified for better alsa-0.9.0beta8a-support by Joy Winter <joy@pingfm.org> | 6 modified for better alsa-0.9.0beta12(rc1)-support by Joy Winter <joy@pingfm.org> |
7 additional AC3 passthrough support by Andy Lo A Foe <andy@alsaplayer.org> | 7 additional AC3 passthrough support by Andy Lo A Foe <andy@alsaplayer.org> |
8 | |
9 This driver is still at alpha stage. | |
10 If you want stable sound-support use the OSS emulation instead. | |
11 | 8 |
12 Any bugreports regarding to this driver are welcome either to the mplayer-user-mailinglist or directly to the authors. | 9 Any bugreports regarding to this driver are welcome either to the mplayer-user-mailinglist or directly to the authors. |
13 */ | 10 */ |
14 | 11 |
15 #include <errno.h> | 12 #include <errno.h> |
13 #include <sys/time.h> | |
14 #include <stdlib.h> | |
15 //#include <unistd.h> | |
16 //#include <string.h> | |
16 | 17 |
17 #include "../config.h" | 18 #include "../config.h" |
18 | 19 |
19 #if HAVE_SYS_ASOUNDLIB_H | 20 #if HAVE_SYS_ASOUNDLIB_H |
20 #include <sys/asoundlib.h> | 21 #include <sys/asoundlib.h> |
44 static snd_pcm_t *alsa_handler; | 45 static snd_pcm_t *alsa_handler; |
45 static snd_pcm_format_t alsa_format; | 46 static snd_pcm_format_t alsa_format; |
46 static snd_pcm_hw_params_t *alsa_hwparams; | 47 static snd_pcm_hw_params_t *alsa_hwparams; |
47 static snd_pcm_sw_params_t *alsa_swparams; | 48 static snd_pcm_sw_params_t *alsa_swparams; |
48 static char *alsa_device; | 49 static char *alsa_device; |
50 | |
51 static int alsa_fragsize = OUTBURST; /* possible 4096, original 8192, OUTBURST is set statically to 512 in config.h but now its not used cause chunksize is allocated dynamically. */ | |
52 static int alsa_fragcount = 8; | |
53 | |
54 static int chunk_size = -1; | |
55 static int buffer_size = 0; | |
56 static int start_delay = 0; | |
57 static int stop_delay = 0; | |
58 static size_t bits_per_sample, bits_per_frame; | |
59 static size_t chunk_bytes; | |
60 | |
49 #define ALSA_DEVICE_SIZE 48 | 61 #define ALSA_DEVICE_SIZE 48 |
50 | 62 |
51 static int alsa_fragsize = 8192; /* possible 4096, original 8192 */ | 63 #define BUFFERTIME /* last undef */ |
52 static int alsa_fragcount = 8; | 64 #undef SET_PERIOD /* only function now is to set chunksize staticaly, last defined */ |
53 | 65 #define SW_PARAMS /* last undef */ |
54 static int chunk_size = -1; | 66 |
55 static int start_delay = 1; | |
56 | 67 |
57 snd_pcm_t * | 68 snd_pcm_t * |
58 spdif_init(int acard, int adevice) | 69 spdif_init(int acard, int adevice) |
59 { | 70 { |
60 //char *pcm_name = "hw:0,2"; /* first card second device */ | 71 //char *pcm_name = "hw:0,2"; /* first card second device */ |
176 static int control(int cmd, int arg) | 187 static int control(int cmd, int arg) |
177 { | 188 { |
178 return(CONTROL_UNKNOWN); | 189 return(CONTROL_UNKNOWN); |
179 } | 190 } |
180 | 191 |
181 #undef start /* orig. undef */ | |
182 #define buffsize | |
183 #define buffertime /* orig. undef? */ | |
184 #define set_period | |
185 #define sw_params /* orig. undef */ | |
186 #undef set_start_mode /* orig. undef */ | |
187 | 192 |
188 /* | 193 /* |
189 open & setup audio device | 194 open & setup audio device |
190 return: 1=success 0=fail | 195 return: 1=success 0=fail |
191 */ | 196 */ |
196 snd_pcm_info_t *alsa_info; | 201 snd_pcm_info_t *alsa_info; |
197 | 202 |
198 size_t xfer_align; //new | 203 size_t xfer_align; //new |
199 snd_pcm_uframes_t start_threshold, stop_threshold; //new | 204 snd_pcm_uframes_t start_threshold, stop_threshold; //new |
200 | 205 |
201 printf("alsa-init: this driver is still at alpha-stage. if you want stable sound support use the OSS emulation instead.\n"); | 206 printf("alsa-init: testing and bugreports are welcome.\n"); |
202 printf("alsa-init: requested format: %d Hz, %d channels, %s\n", rate_hz, | 207 printf("alsa-init: requested format: %d Hz, %d channels, %s\n", rate_hz, |
203 channels, audio_out_format_name(format)); | 208 channels, audio_out_format_name(format)); |
204 | 209 |
205 alsa_handler = NULL; | 210 alsa_handler = NULL; |
206 | 211 |
263 return(0); | 268 return(0); |
264 default: | 269 default: |
265 break; | 270 break; |
266 } | 271 } |
267 | 272 |
268 if ((err = snd_pcm_info_malloc(&alsa_info)) < 0) | 273 if (ao_subdevice != NULL) // ?? makes no sense |
269 { | |
270 printf("alsa-init: memory allocation error: %s\n", snd_strerror(err)); | |
271 return(0); | |
272 } | |
273 | |
274 if (ao_subdevice != NULL) | |
275 alsa_device = ao_subdevice; | 274 alsa_device = ao_subdevice; |
276 | 275 |
277 if (alsa_device == NULL) | 276 if (alsa_device == NULL) |
278 { | 277 { |
279 if ((alsa_device = malloc(ALSA_DEVICE_SIZE)) == NULL) | 278 int tmp_device, tmp_subdevice, err; |
280 { | 279 |
280 if ((err = snd_pcm_info_malloc(&alsa_info)) < 0) | |
281 { | |
282 printf("alsa-init: memory allocation error: %s\n", snd_strerror(err)); | |
283 return(0); | |
284 } | |
285 | |
286 if ((alsa_device = alloca(ALSA_DEVICE_SIZE)) == NULL) | |
287 { | |
281 printf("alsa-init: memory allocation error: %s\n", strerror(errno)); | 288 printf("alsa-init: memory allocation error: %s\n", strerror(errno)); |
282 return(0); | 289 return(0); |
283 } | 290 } |
284 | 291 |
285 snprintf(alsa_device, ALSA_DEVICE_SIZE, "hw:%d,%d", | 292 if ((tmp_device = snd_pcm_info_get_device(alsa_info)) < 0) |
286 snd_pcm_info_get_device(alsa_info), | 293 { |
287 snd_pcm_info_get_subdevice(alsa_info)); | 294 printf("alsa-init: cant get device\n"); |
295 return(0); | |
296 } | |
297 | |
298 if ((tmp_subdevice = snd_pcm_info_get_subdevice(alsa_info)) < 0) | |
299 { | |
300 printf("alsa-init: cant get subdevice\n"); | |
301 return(0); | |
302 } | |
303 | |
304 if (verbose) | |
305 printf("alsa-init: got device=%i, subdevice=%i\n", tmp_device, tmp_subdevice); | |
306 | |
307 if ((err = snprintf(alsa_device, ALSA_DEVICE_SIZE, "hw:%1d,%1d", tmp_device, tmp_subdevice)) <= 0) | |
308 { | |
309 printf("alsa-init: cant wrote device-id\n"); | |
310 } | |
288 | 311 |
289 snd_pcm_info_free(alsa_info); | 312 snd_pcm_info_free(alsa_info); |
290 } | 313 } |
291 | 314 |
292 printf("alsa-init: %d soundcard%s found, using: %s\n", cards+1, | 315 printf("alsa-init: %d soundcard%s found, using: %s\n", cards+1, |
293 (cards >= 0) ? "" : "s", alsa_device); | 316 (cards >= 0) ? "" : "s", alsa_device); |
294 | 317 |
295 if (format == AFMT_AC3) { | 318 if (format == AFMT_AC3) { |
296 // Try to initialize the SPDIF interface | 319 // Try to initialize the SPDIF interface |
297 alsa_handler = spdif_init(0, 2); | 320 alsa_handler = spdif_init(0, 2); |
298 } | 321 } |
299 | 322 |
300 if (!alsa_handler) { | 323 if (!alsa_handler) { |
301 if ((err = snd_pcm_open(&alsa_handler, alsa_device, SND_PCM_STREAM_PLAYBACK, | 324 if ((err = snd_pcm_open(&alsa_handler,alsa_device,SND_PCM_STREAM_PLAYBACK,0)) < 0) |
302 0)) < 0) | |
303 { | 325 { |
304 printf("alsa-init: playback open error: %s\n", snd_strerror(err)); | 326 printf("alsa-init: playback open error: %s\n", snd_strerror(err)); |
305 return(0); | 327 return(0); |
306 } | 328 } |
307 } | 329 } |
308 | 330 |
309 snd_pcm_hw_params_malloc(&alsa_hwparams); | 331 snd_pcm_hw_params_alloca(&alsa_hwparams); |
310 snd_pcm_sw_params_alloca(&alsa_swparams); | 332 snd_pcm_sw_params_alloca(&alsa_swparams); |
333 | |
334 // setting hw-parameters | |
311 if ((err = snd_pcm_hw_params_any(alsa_handler, alsa_hwparams)) < 0) | 335 if ((err = snd_pcm_hw_params_any(alsa_handler, alsa_hwparams)) < 0) |
312 { | 336 { |
313 printf("alsa-init: unable to get initial parameters: %s\n", | 337 printf("alsa-init: unable to get initial parameters: %s\n", |
314 snd_strerror(err)); | 338 snd_strerror(err)); |
315 return(0); | 339 return(0); |
338 snd_strerror(err)); | 362 snd_strerror(err)); |
339 return(0); | 363 return(0); |
340 } | 364 } |
341 | 365 |
342 if ((err = snd_pcm_hw_params_set_rate_near(alsa_handler, alsa_hwparams, ao_data.samplerate, 0)) < 0) | 366 if ((err = snd_pcm_hw_params_set_rate_near(alsa_handler, alsa_hwparams, ao_data.samplerate, 0)) < 0) |
343 /* was originally only snd_pcm_hw_params_set_rate jp*/ | |
344 { | 367 { |
345 printf("alsa-init: unable to set samplerate-2: %s\n", | 368 printf("alsa-init: unable to set samplerate-2: %s\n", |
346 snd_strerror(err)); | 369 snd_strerror(err)); |
347 //snd_pcm_hw_params_dump(alsa_hwparams, errlog); jp | 370 //snd_pcm_hw_params_dump(alsa_hwparams, errlog); jp |
348 return(0); | 371 return(0); |
349 } | 372 } |
350 | 373 |
351 #ifdef set_period | 374 |
352 { | 375 #ifdef SET_PERIOD |
353 if ((err = snd_pcm_hw_params_set_period_size(alsa_handler, alsa_hwparams, alsa_fragsize / 4, 0)) < 0) | 376 { |
377 if ((err = snd_pcm_hw_params_set_period_size(alsa_handler, alsa_hwparams, alsa_fragsize, 0)) < 0) | |
354 { | 378 { |
355 printf("alsa-init: unable to set periodsize: %s\n", | 379 printf("alsa-init: unable to set periodsize: %s\n", snd_strerror(err)); |
356 snd_strerror(err)); | |
357 return(0); | 380 return(0); |
358 } | 381 } |
359 if ((err = snd_pcm_hw_params_set_periods(alsa_handler, alsa_hwparams, alsa_fragcount, 0)) < 0) | |
360 { | |
361 printf("alsa-init: unable to set periods: %s\n", | |
362 snd_strerror(err)); | |
363 return(0); | |
364 } | |
365 } | 382 } |
366 #endif | 383 #endif |
367 #ifdef buffsize | 384 |
368 if ((err = snd_pcm_hw_params_get_buffer_size(alsa_hwparams)) < 0) | 385 #ifdef BUFFERTIME |
369 { | |
370 printf("alsa-init: unable to get buffer size: %s\n", | |
371 snd_strerror(err)); | |
372 return(0); | |
373 } else | |
374 { | |
375 ao_data.buffersize = err; | |
376 if (verbose) | |
377 printf("alsa-init: got buffersize %i\n", ao_data.buffersize); | |
378 } | |
379 #endif | |
380 | |
381 #ifdef buffertime | |
382 { | 386 { |
383 int alsa_buffer_time = 500000; /* original 60 */ | 387 int alsa_buffer_time = 500000; /* original 60 */ |
384 | 388 |
385 if ((err = snd_pcm_hw_params_set_buffer_time_near(alsa_handler, alsa_hwparams, alsa_buffer_time, 0)) < 0) | 389 if ((err = snd_pcm_hw_params_set_buffer_time_near(alsa_handler, alsa_hwparams, alsa_buffer_time, 0)) < 0) |
386 { | 390 { |
395 { | 399 { |
396 printf("alsa-init: unable to set period time: %s\n", | 400 printf("alsa-init: unable to set period time: %s\n", |
397 snd_strerror(err)); | 401 snd_strerror(err)); |
398 return(0); | 402 return(0); |
399 } | 403 } |
400 printf("alsa-init: buffer_time: %d, period_time :%d\n", | 404 if (verbose) |
401 alsa_buffer_time, err); | 405 printf("alsa-init: buffer_time: %d, period_time :%d\n",alsa_buffer_time, err); |
402 } | 406 } |
403 #endif | 407 #endif |
404 | 408 |
409 /* get chunk-size */ | |
410 if ((err = snd_pcm_hw_params_get_period_size(alsa_hwparams, 0)) < 0) | |
411 { | |
412 printf("alsa-init: unable to get chunk-size in hw-params: %s\n", snd_strerror(err)); | |
413 return(0); | |
414 } else | |
415 { | |
416 chunk_size = err; | |
417 if (verbose) {printf("alsa-init: got chunksize %i\n", chunk_size);} | |
418 } | |
419 | |
420 /* get buffer size */ | |
421 if ((err = snd_pcm_hw_params_get_buffer_size(alsa_hwparams)) < 0) | |
422 { | |
423 printf("alsa-init: unable to get buffersize in hw-params: %s\n", snd_strerror(err)); | |
424 return(0); | |
425 } else | |
426 { | |
427 ao_data.buffersize = err; | |
428 if (verbose) {printf("alsa-init: got buffersize %i\n", ao_data.buffersize);} | |
429 } | |
430 | |
431 if (MAX_OUTBURST > ao_data.buffersize) { //warning if MAX_OUTBURST is bigger than buffersize | |
432 printf("alsa-init: WARNING! MAX_OUTBURST exceeds your available buffersize.\nalsa-init: MAX_OUTBURST=%i, buffersize=%i\n",MAX_OUTBURST,ao_data.buffersize);} | |
433 | |
434 if (chunk_size == ao_data.buffersize) | |
435 { | |
436 printf("alsa-init: Can't use period equal to buffer size (%u == %lu)", chunk_size, (long)buffer_size); | |
437 return(0); | |
438 } | |
439 | |
440 /* finally install hardware parameters */ | |
405 if ((err = snd_pcm_hw_params(alsa_handler, alsa_hwparams)) < 0) | 441 if ((err = snd_pcm_hw_params(alsa_handler, alsa_hwparams)) < 0) |
406 { | 442 { |
407 printf("alsa-init: unable to set parameters: %s\n", | 443 printf("alsa-init: unable to set hw-parameters: %s\n", |
408 snd_strerror(err)); | 444 snd_strerror(err)); |
409 return(0); | 445 return(0); |
410 } | 446 } |
411 | 447 // end setting hw-params |
412 #ifdef sw_params | 448 |
413 { | 449 #ifdef SW_PARAMS |
414 chunk_size = snd_pcm_hw_params_get_period_size(alsa_hwparams, 0); | 450 { |
415 start_threshold = (double) ao_data.samplerate * start_delay / 1000000; | 451 size_t n; |
416 xfer_align = snd_pcm_sw_params_get_xfer_align(alsa_swparams); | 452 xfer_align = snd_pcm_sw_params_get_xfer_align(alsa_swparams); |
453 if (xfer_align == 0) | |
454 xfer_align = 4; | |
455 n = (ao_data.buffersize / xfer_align) * xfer_align; | |
456 | |
457 if (start_delay <= 0) { | |
458 start_threshold = n + (double) ao_data.samplerate * start_delay / 1000000; | |
459 } else { | |
460 start_threshold = (double) ao_data.samplerate * start_delay / 1000000; | |
461 } | |
462 if (start_threshold < 1) | |
463 start_threshold = 1; | |
464 if (start_threshold > n) | |
465 start_threshold = n; | |
466 | |
467 if (stop_delay <= 0) { | |
468 stop_threshold = ao_data.buffersize + (double) ao_data.samplerate * stop_delay / 1000000; | |
469 } else { | |
470 stop_threshold = (double) ao_data.samplerate * stop_delay / 1000000; | |
471 } | |
472 | |
473 if (verbose) { | |
474 printf("alsa-init: start_threshold=%lu, stop_threshold=%lu\n",start_threshold,stop_threshold); | |
475 printf("alsa-init: n=%i\n", n); | |
476 } | |
417 | 477 |
418 if ((err = snd_pcm_sw_params_current(alsa_handler, alsa_swparams)) < 0) | 478 if ((err = snd_pcm_sw_params_current(alsa_handler, alsa_swparams)) < 0) |
419 { | 479 { |
420 printf("alsa-init: unable to get parameters: %s\n", | 480 printf("alsa-init: unable to get parameters: %s\n",snd_strerror(err)); |
421 snd_strerror(err)); | 481 return(0); |
422 return(0); | 482 } |
423 } | 483 |
484 //set min available frames to consider pcm ready (4) | |
485 if ((err = snd_pcm_sw_params_set_avail_min(alsa_handler, alsa_swparams, 4)) < 0) | |
486 { | |
487 printf("alsa-init: unable to set avail_min %s\n",snd_strerror(err)); | |
488 return(0); | |
489 } | |
424 | 490 |
425 if ((err = snd_pcm_sw_params_set_avail_min(alsa_handler, alsa_swparams, chunk_size)) < 0) | 491 if ((err = snd_pcm_sw_params_set_start_threshold(alsa_handler, alsa_swparams, start_threshold)) < 0) |
426 { | 492 { |
427 printf("alsa-init: unable to set avail_min %s\n",snd_strerror(err)); | 493 printf("alsa-init: unable to set start_threshold %s\n",snd_strerror(err)); |
428 return(0); | 494 return(0); |
429 } | 495 } |
430 | 496 |
431 | 497 if ((err = snd_pcm_sw_params_set_stop_threshold(alsa_handler, alsa_swparams, stop_threshold)) < 0) |
432 | 498 { |
433 if ((err = snd_pcm_sw_params_set_start_threshold(alsa_handler, alsa_swparams, start_threshold)) < 0) | 499 printf("alsa-init: unable to set stop_threshold %s\n",snd_strerror(err)); |
434 { | 500 return(0); |
435 printf("alsa-init: unable to set start_threshold %s\n",snd_strerror(err)); | 501 } |
436 return(0); | 502 |
437 } | 503 //transfers stream aligned to 4 in nonblocking-mode it would be 1 |
438 } | 504 if ((err = snd_pcm_sw_params_set_xfer_align(alsa_handler, alsa_swparams, 4)) < 0) |
439 // if ((err = snd_pcm_sw_params_set_xfer_align(alsa_handler, alsa_swparams, xfer_align)) < 0) | 505 { |
440 //{ | 506 printf("alsa-init: unable to set xfer_align: %s\n",snd_strerror(err)); |
441 // printf("alsa-init: unable to set xfer_align: %s\n", | 507 return(0); |
442 // snd_strerror(err)); | 508 } |
443 // return(0); | |
444 //} | |
445 | |
446 #ifdef set_start_mode | |
447 if ((err = snd_pcm_sw_params_set_start_mode(alsa_handler, alsa_swparams, | |
448 SND_PCM_START_DATA)) < 0) | |
449 { | |
450 printf("alsa-init: unable to set start mode: %s\n", | |
451 snd_strerror(err)); | |
452 return(0); | |
453 } | |
454 #endif | |
455 | 509 |
456 if ((err = snd_pcm_sw_params(alsa_handler, alsa_swparams)) < 0) | 510 if ((err = snd_pcm_sw_params(alsa_handler, alsa_swparams)) < 0) |
457 { | 511 { |
458 printf("alsa-init: unable to set parameters: %s\n", | 512 printf("alsa-init: unable to install sw-params\n"); |
459 snd_strerror(err)); | 513 return(0); |
460 return(0); | 514 } |
461 } | 515 |
462 | 516 bits_per_sample = snd_pcm_format_physical_width(alsa_format); |
463 // snd_pcm_sw_params_default(alsa_handler, alsa_swparams); | 517 bits_per_frame = bits_per_sample * channels; |
464 #endif | 518 chunk_bytes = chunk_size * bits_per_frame / 8; |
519 | |
520 if (verbose) { | |
521 printf("alsa-init: bits per sample (bps)=%i, bits per frame (bpf)=%i, chunk_bytes=%i\n",bits_per_sample,bits_per_frame,chunk_bytes);} | |
522 } | |
523 | |
524 #endif //end swparams | |
525 | |
465 if ((err = snd_pcm_prepare(alsa_handler)) < 0) | 526 if ((err = snd_pcm_prepare(alsa_handler)) < 0) |
466 { | 527 { |
467 printf("alsa-init: pcm prepare error: %s\n", snd_strerror(err)); | 528 printf("alsa-init: pcm prepare error: %s\n", snd_strerror(err)); |
468 return(0); | 529 return(0); |
469 } | 530 } |
470 | 531 |
471 #ifdef start | 532 printf("alsa9: %d Hz/%d channels/%d bpf/%d bytes buffer/%s\n", |
472 if ((err = snd_pcm_start(alsa_handler)) < 0) | |
473 { | |
474 printf("alsa-init: pcm start error: %s\n", snd_strerror(err)); | |
475 if (err != -EPIPE) | |
476 return(0); | |
477 if ((err = snd_pcm_start(alsa_handler)) < 0) | |
478 { | |
479 printf("alsa-init: pcm start error: %s\n", snd_strerror(err)); | |
480 return(0); | |
481 } | |
482 } | |
483 #endif | |
484 printf("AUDIO: %d Hz/%d channels/%d bpf/%d bytes buffer/%s\n", | |
485 ao_data.samplerate, ao_data.channels, ao_data.bps, ao_data.buffersize, | 533 ao_data.samplerate, ao_data.channels, ao_data.bps, ao_data.buffersize, |
486 snd_pcm_format_description(alsa_format)); | 534 snd_pcm_format_description(alsa_format)); |
487 return(1); | 535 return(1); |
488 } | 536 } // end init |
537 | |
489 | 538 |
490 /* close audio device */ | 539 /* close audio device */ |
491 static void uninit() | 540 static void uninit() |
492 { | 541 { |
493 int err; | 542 int err; |
494 | 543 |
495 if (alsa_device != NULL) | 544 //if (alsa_device != NULL) |
496 free(alsa_device); | 545 //free(alsa_device); |
497 | 546 |
498 snd_pcm_hw_params_free(alsa_hwparams); | 547 //snd_pcm_hw_params_free(alsa_hwparams); |
499 | 548 |
500 if ((err = snd_pcm_drain(alsa_handler)) < 0) | 549 if ((err = snd_pcm_drain(alsa_handler)) < 0) |
501 { | 550 { |
502 printf("alsa-uninit: pcm drain error: %s\n", snd_strerror(err)); | 551 printf("alsa-uninit: pcm drain error: %s\n", snd_strerror(err)); |
503 return; | 552 return; |
504 } | 553 } |
505 | 554 |
506 #ifdef start | |
507 if ((err = snd_pcm_reset(alsa_handler)) < 0) | |
508 { | |
509 printf("alsa-uninit: pcm reset error: %s\n", snd_strerror(err)); | |
510 return; | |
511 } | |
512 #endif | |
513 | |
514 if ((err = snd_pcm_close(alsa_handler)) < 0) | 555 if ((err = snd_pcm_close(alsa_handler)) < 0) |
515 { | 556 { |
516 printf("alsa-uninit: pcm close error: %s\n", snd_strerror(err)); | 557 printf("alsa-uninit: pcm close error: %s\n", snd_strerror(err)); |
517 return; | 558 return; |
518 } | 559 } |
560 else { | |
561 alsa_handler = NULL; | |
562 alsa_device = NULL; | |
563 printf("alsa-uninit: pcm closed\n"); | |
564 } | |
519 } | 565 } |
520 | 566 |
521 static void audio_pause() | 567 static void audio_pause() |
522 { | 568 { |
523 int err; | 569 int err; |
544 if ((err = snd_pcm_prepare(alsa_handler)) < 0) | 590 if ((err = snd_pcm_prepare(alsa_handler)) < 0) |
545 { | 591 { |
546 printf("alsa-resume: pcm prepare error: %s\n", snd_strerror(err)); | 592 printf("alsa-resume: pcm prepare error: %s\n", snd_strerror(err)); |
547 return; | 593 return; |
548 } | 594 } |
549 | |
550 #ifdef start | |
551 if ((err = snd_pcm_start(alsa_handler)) < 0) | |
552 { | |
553 printf("alsa-resume: pcm start error: %s\n", snd_strerror(err)); | |
554 return; | |
555 } | |
556 #endif | |
557 } | 595 } |
558 | 596 |
559 /* stop playing and empty buffers (for seeking/pause) */ | 597 /* stop playing and empty buffers (for seeking/pause) */ |
560 static void reset() | 598 static void reset() |
561 { | 599 { |
565 { | 603 { |
566 printf("alsa-reset: pcm drain error: %s\n", snd_strerror(err)); | 604 printf("alsa-reset: pcm drain error: %s\n", snd_strerror(err)); |
567 return; | 605 return; |
568 } | 606 } |
569 | 607 |
570 #ifdef start | |
571 if ((err = snd_pcm_reset(alsa_handler)) < 0) | |
572 { | |
573 printf("alsa-reset: pcm reset error: %s\n", snd_strerror(err)); | |
574 return; | |
575 } | |
576 #endif | |
577 | |
578 if ((err = snd_pcm_prepare(alsa_handler)) < 0) | 608 if ((err = snd_pcm_prepare(alsa_handler)) < 0) |
579 { | 609 { |
580 printf("alsa-reset: pcm prepare error: %s\n", snd_strerror(err)); | 610 printf("alsa-reset: pcm prepare error: %s\n", snd_strerror(err)); |
581 return; | 611 return; |
582 } | 612 } |
583 | 613 |
584 #ifdef start | 614 } |
585 if ((err = snd_pcm_start(alsa_handler)) < 0) | 615 |
586 { | 616 #ifndef timersub |
587 printf("alsa-reset: pcm start error: %s\n", snd_strerror(err)); | 617 #define timersub(a, b, result) \ |
588 return; | 618 do { \ |
589 } | 619 (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \ |
620 (result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \ | |
621 if ((result)->tv_usec < 0) { \ | |
622 --(result)->tv_sec; \ | |
623 (result)->tv_usec += 1000000; \ | |
624 } \ | |
625 } while (0) | |
590 #endif | 626 #endif |
591 } | |
592 | 627 |
593 /* | 628 /* |
594 plays 'len' bytes of 'data' | 629 plays 'len' bytes of 'data' |
595 returns: number of bytes played | 630 returns: number of bytes played |
631 modified last at 26.06.02 by jp | |
596 */ | 632 */ |
597 | 633 |
598 static int play(void* data, int len, int flags) | 634 static int play(void* data, int len, int flags) |
599 { | 635 { |
600 int got_len; | 636 |
601 | 637 snd_pcm_status_t *status; |
602 got_len = snd_pcm_writei(alsa_handler, data, len / 4); | 638 |
603 | 639 int num_frames=len/ao_data.bps; |
604 //if ((got_len = snd_pcm_writei(alsa_handler, data, (len/ao_data.bps))) != (len/ao_data.bps)) { | 640 signed short *output_samples=data; |
605 //SHOULD BE FIXED | 641 snd_pcm_sframes_t res = 0; |
606 if (got_len == -EPIPE) /* underrun? */ | 642 |
607 { | 643 if (!alsa_handler) { |
608 printf("alsa-play: alsa underrun, resetting stream\n"); | 644 printf("alsa-play: device configuration error"); |
609 if ((got_len = snd_pcm_prepare(alsa_handler)) < 0) | 645 return 0; |
610 { | 646 } |
611 printf("alsa-play: playback prepare error: %s\n", snd_strerror(got_len)); | 647 |
612 return(0); | 648 do { |
613 } | 649 if (res == -EPIPE) { /* underrun */ |
614 if ((got_len = snd_pcm_writei(alsa_handler, data, (len/ao_data.bps))) != (len/ao_data.bps)) | 650 snd_pcm_status_alloca(&status); |
615 { | 651 if ((res = snd_pcm_status(alsa_handler, status))<0) { |
616 printf("alsa-play: write error after reset: %s - giving up\n", | 652 printf("alsa-play: buffer underrun. can't determine length"); |
617 snd_strerror(got_len)); | 653 } else { |
618 return(0); | 654 if (snd_pcm_status_get_state(status) == SND_PCM_STATE_XRUN) { |
619 } | 655 struct timeval now, diff, tstamp; |
620 return(len); /* 2nd write was ok */ | 656 gettimeofday(&now, 0); |
621 } | 657 snd_pcm_status_get_trigger_tstamp(status, &tstamp); |
622 return(len); | 658 timersub(&now, &tstamp, &diff); |
623 //} | 659 printf("alsa-play: xrun of at least %.3f msecs. resetting stream", |
624 } | 660 diff.tv_sec * 1000 + diff.tv_usec / 1000.0); |
661 } else | |
662 printf("alsa-play: xrun. can't determine length"); | |
663 } | |
664 res = snd_pcm_prepare(alsa_handler); | |
665 } | |
666 else if (res == -ESTRPIPE) { /* suspend */ | |
667 printf("alsa-play: pcm in suspend mode. trying to resume"); | |
668 while ((res = snd_pcm_resume(alsa_handler)) == -EAGAIN) | |
669 sleep(1); | |
670 if (res < 0) | |
671 res = snd_pcm_prepare(alsa_handler); | |
672 } | |
673 | |
674 if (res >= 0) | |
675 res = snd_pcm_writei(alsa_handler, (void *)output_samples, num_frames); | |
676 | |
677 if (res > 0) { | |
678 output_samples += ao_data.channels * res; | |
679 num_frames -= res; | |
680 } | |
681 | |
682 } while (res == -EPIPE || num_frames > 0); | |
683 | |
684 if (res < 0) { | |
685 printf("alsa-play: write error %s", snd_strerror(res)); | |
686 return 0; | |
687 } | |
688 return res < 0 ? (int)res : len; | |
689 } | |
690 | |
625 | 691 |
626 /* how many byes are free in the buffer */ | 692 /* how many byes are free in the buffer */ |
627 static int get_space() | 693 static int get_space() |
628 { | 694 { |
629 snd_pcm_status_t *status; | 695 snd_pcm_status_t *status; |
653 } | 719 } |
654 | 720 |
655 snd_pcm_status_free(status); | 721 snd_pcm_status_free(status); |
656 | 722 |
657 if (ret < 0) | 723 if (ret < 0) |
658 ret = 0; | 724 ret = 0; |
725 //printf("alsa-space: free space = %i",ret); | |
659 return(ret); | 726 return(ret); |
660 } | 727 } |
661 | 728 |
662 /* delay in seconds between first and last sample in buffer */ | 729 /* delay in seconds between first and last sample in buffer */ |
663 static float get_delay() | 730 static float get_delay() |
689 } | 756 } |
690 | 757 |
691 snd_pcm_status_free(status); | 758 snd_pcm_status_free(status); |
692 | 759 |
693 if (ret < 0) | 760 if (ret < 0) |
694 ret = 0; | 761 ret = 0; |
695 return(ret); | 762 return(ret); |
696 } | 763 } |