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 }