Mercurial > sdl-ios-xcode
comparison src/audio/alsa/SDL_alsa_audio.c @ 4357:a10dac5858fe SDL-1.2
Recommendation from Lennart Poettering:
In ALSA_OpenAudio(): instead of setting period_size+n_periods OR
buffer_size I'd recommend copying the hwparams stuff before you do
this, then first try period_size+n_periods, and then apply it with
snd_pcm_hw_params() and check if that works. If it didn't you should
take the copy of hwparams and try setting buffer_size and apply that
via snd_pcm_hw_params() and check if that worked. And if that failed
too, then take the copy and don't apply neither period nor buffer
settings and see if that works.
author | Sam Lantinga <slouken@libsdl.org> |
---|---|
date | Mon, 19 Oct 2009 02:23:21 +0000 |
parents | 471dac4b41dd |
children | df306a61a61d |
comparison
equal
deleted
inserted
replaced
4356:ab2dfac9d5c1 | 4357:a10dac5858fe |
---|---|
63 static int (*SDL_NAME(snd_pcm_prepare))(snd_pcm_t *pcm); | 63 static int (*SDL_NAME(snd_pcm_prepare))(snd_pcm_t *pcm); |
64 static int (*SDL_NAME(snd_pcm_drain))(snd_pcm_t *pcm); | 64 static int (*SDL_NAME(snd_pcm_drain))(snd_pcm_t *pcm); |
65 static const char *(*SDL_NAME(snd_strerror))(int errnum); | 65 static const char *(*SDL_NAME(snd_strerror))(int errnum); |
66 static size_t (*SDL_NAME(snd_pcm_hw_params_sizeof))(void); | 66 static size_t (*SDL_NAME(snd_pcm_hw_params_sizeof))(void); |
67 static size_t (*SDL_NAME(snd_pcm_sw_params_sizeof))(void); | 67 static size_t (*SDL_NAME(snd_pcm_sw_params_sizeof))(void); |
68 static void (*SDL_NAME(snd_pcm_hw_params_copy))(snd_pcm_hw_params_t *dst, const snd_pcm_hw_params_t *src); | |
68 static int (*SDL_NAME(snd_pcm_hw_params_any))(snd_pcm_t *pcm, snd_pcm_hw_params_t *params); | 69 static int (*SDL_NAME(snd_pcm_hw_params_any))(snd_pcm_t *pcm, snd_pcm_hw_params_t *params); |
69 static int (*SDL_NAME(snd_pcm_hw_params_set_access))(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_access_t access); | 70 static int (*SDL_NAME(snd_pcm_hw_params_set_access))(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_access_t access); |
70 static int (*SDL_NAME(snd_pcm_hw_params_set_format))(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_format_t val); | 71 static int (*SDL_NAME(snd_pcm_hw_params_set_format))(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_format_t val); |
71 static int (*SDL_NAME(snd_pcm_hw_params_set_channels))(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val); | 72 static int (*SDL_NAME(snd_pcm_hw_params_set_channels))(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val); |
72 static int (*SDL_NAME(snd_pcm_hw_params_get_channels))(const snd_pcm_hw_params_t *params, unsigned int *val); | 73 static int (*SDL_NAME(snd_pcm_hw_params_get_channels))(const snd_pcm_hw_params_t *params, unsigned int *val); |
99 { "snd_pcm_prepare", (void**)(char*)&SDL_NAME(snd_pcm_prepare) }, | 100 { "snd_pcm_prepare", (void**)(char*)&SDL_NAME(snd_pcm_prepare) }, |
100 { "snd_pcm_drain", (void**)(char*)&SDL_NAME(snd_pcm_drain) }, | 101 { "snd_pcm_drain", (void**)(char*)&SDL_NAME(snd_pcm_drain) }, |
101 { "snd_strerror", (void**)(char*)&SDL_NAME(snd_strerror) }, | 102 { "snd_strerror", (void**)(char*)&SDL_NAME(snd_strerror) }, |
102 { "snd_pcm_hw_params_sizeof", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_sizeof) }, | 103 { "snd_pcm_hw_params_sizeof", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_sizeof) }, |
103 { "snd_pcm_sw_params_sizeof", (void**)(char*)&SDL_NAME(snd_pcm_sw_params_sizeof) }, | 104 { "snd_pcm_sw_params_sizeof", (void**)(char*)&SDL_NAME(snd_pcm_sw_params_sizeof) }, |
105 { "snd_pcm_hw_params_copy", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_copy) }, | |
104 { "snd_pcm_hw_params_any", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_any) }, | 106 { "snd_pcm_hw_params_any", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_any) }, |
105 { "snd_pcm_hw_params_set_access", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_set_access) }, | 107 { "snd_pcm_hw_params_set_access", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_set_access) }, |
106 { "snd_pcm_hw_params_set_format", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_set_format) }, | 108 { "snd_pcm_hw_params_set_format", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_set_format) }, |
107 { "snd_pcm_hw_params_set_channels", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_set_channels) }, | 109 { "snd_pcm_hw_params_set_channels", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_set_channels) }, |
108 { "snd_pcm_hw_params_get_channels", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_get_channels) }, | 110 { "snd_pcm_hw_params_get_channels", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_get_channels) }, |
363 SDL_NAME(snd_pcm_close)(pcm_handle); | 365 SDL_NAME(snd_pcm_close)(pcm_handle); |
364 pcm_handle = NULL; | 366 pcm_handle = NULL; |
365 } | 367 } |
366 } | 368 } |
367 | 369 |
370 static int ALSA_finalize_hardware(_THIS, SDL_AudioSpec *spec, snd_pcm_hw_params_t *hwparams, int override) | |
371 { | |
372 int status; | |
373 snd_pcm_uframes_t bufsize; | |
374 | |
375 /* "set" the hardware with the desired parameters */ | |
376 status = SDL_NAME(snd_pcm_hw_params)(pcm_handle, hwparams); | |
377 if ( status < 0 ) { | |
378 return(-1); | |
379 } | |
380 | |
381 /* Get samples for the actual buffer size */ | |
382 status = SDL_NAME(snd_pcm_hw_params_get_buffer_size)(hwparams, &bufsize); | |
383 if ( status < 0 ) { | |
384 return(-1); | |
385 } | |
386 if ( !override && bufsize != spec->samples * 2 ) { | |
387 return(-1); | |
388 } | |
389 | |
390 /* FIXME: Is this safe to do? */ | |
391 spec->samples = bufsize / 2; | |
392 | |
393 /* This is useful for debugging */ | |
394 if ( getenv("SDL_AUDIO_ALSA_DEBUG") ) { | |
395 snd_pcm_sframes_t persize = 0; | |
396 unsigned int periods = 0; | |
397 | |
398 SDL_NAME(snd_pcm_hw_params_get_period_size)(hwparams, &persize, NULL); | |
399 SDL_NAME(snd_pcm_hw_params_get_periods)(hwparams, &periods, NULL); | |
400 | |
401 fprintf(stderr, "ALSA: period size = %ld, periods = %u, buffer size = %lu\n", persize, periods, bufsize); | |
402 } | |
403 return(0); | |
404 } | |
405 | |
406 static int ALSA_set_period_size(_THIS, SDL_AudioSpec *spec, snd_pcm_hw_params_t *params) | |
407 { | |
408 const char *env; | |
409 int status; | |
410 int override = 0; | |
411 snd_pcm_hw_params_t *hwparams; | |
412 snd_pcm_uframes_t frames; | |
413 unsigned int periods; | |
414 | |
415 /* Copy the hardware parameters for this setup */ | |
416 snd_pcm_hw_params_alloca(&hwparams); | |
417 SDL_NAME(snd_pcm_hw_params_copy)(hwparams, params); | |
418 | |
419 env = getenv("SDL_AUDIO_ALSA_SET_PERIOD_SIZE"); | |
420 if ( env ) { | |
421 override = SDL_strol(env); | |
422 if ( override == 0 ) { | |
423 return(-1); | |
424 } | |
425 } | |
426 | |
427 frames = spec->samples; | |
428 status = SDL_NAME(snd_pcm_hw_params_set_period_size_near)(pcm_handle, hwparams, &frames, NULL); | |
429 if ( status < 0 ) { | |
430 return(-1); | |
431 } | |
432 | |
433 periods = 2; | |
434 status = SDL_NAME(snd_pcm_hw_params_set_periods_near)(pcm_handle, hwparams, &periods, NULL); | |
435 if ( status < 0 ) { | |
436 return(-1); | |
437 } | |
438 | |
439 return ALSA_finalize_hardware(this, spec, hwparams, override); | |
440 } | |
441 | |
442 static int ALSA_set_buffer_size(_THIS, SDL_AudioSpec *spec, snd_pcm_hw_params_t *params) | |
443 { | |
444 const char *env; | |
445 int status; | |
446 int override = 0; | |
447 snd_pcm_hw_params_t *hwparams; | |
448 snd_pcm_uframes_t frames; | |
449 | |
450 /* Copy the hardware parameters for this setup */ | |
451 snd_pcm_hw_params_alloca(&hwparams); | |
452 SDL_NAME(snd_pcm_hw_params_copy)(hwparams, params); | |
453 | |
454 env = getenv("SDL_AUDIO_ALSA_SET_BUFFER_SIZE"); | |
455 if ( env ) { | |
456 override = SDL_strol(env); | |
457 if ( override == 0 ) { | |
458 return(-1); | |
459 } | |
460 } | |
461 | |
462 frames = spec->samples * 2; | |
463 status = SDL_NAME(snd_pcm_hw_params_set_buffer_size_near)(pcm_handle, hwparams, &frames); | |
464 if ( status < 0 ) { | |
465 return(-1); | |
466 } | |
467 | |
468 return ALSA_finalize_hardware(this, spec, hwparams, override); | |
469 } | |
470 | |
368 static int ALSA_OpenAudio(_THIS, SDL_AudioSpec *spec) | 471 static int ALSA_OpenAudio(_THIS, SDL_AudioSpec *spec) |
369 { | 472 { |
370 int status; | 473 int status; |
371 snd_pcm_hw_params_t *hwparams; | 474 snd_pcm_hw_params_t *hwparams; |
372 snd_pcm_sw_params_t *swparams; | 475 snd_pcm_sw_params_t *swparams; |
373 snd_pcm_format_t format; | 476 snd_pcm_format_t format; |
374 snd_pcm_uframes_t frames; | |
375 unsigned int rate; | 477 unsigned int rate; |
376 unsigned int periods; | |
377 unsigned int channels; | 478 unsigned int channels; |
479 snd_pcm_uframes_t bufsize; | |
378 Uint16 test_format; | 480 Uint16 test_format; |
379 | 481 |
380 /* Open the audio device */ | 482 /* Open the audio device */ |
381 /* Name of device should depend on # channels in spec */ | 483 /* Name of device should depend on # channels in spec */ |
382 status = SDL_NAME(snd_pcm_open)(&pcm_handle, get_audio_device(spec->channels), SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK); | 484 status = SDL_NAME(snd_pcm_open)(&pcm_handle, get_audio_device(spec->channels), SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK); |
467 return(-1); | 569 return(-1); |
468 } | 570 } |
469 spec->freq = rate; | 571 spec->freq = rate; |
470 | 572 |
471 /* Set the buffer size, in samples */ | 573 /* Set the buffer size, in samples */ |
472 if (getenv("SDL_AUDIO_ALSA_SET_PERIOD_SIZE")) { | 574 if ( ALSA_set_period_size(this, spec, hwparams) < 0 && |
473 frames = spec->samples; | 575 ALSA_set_buffer_size(this, spec, hwparams) < 0 ) { |
474 status = SDL_NAME(snd_pcm_hw_params_set_period_size_near)(pcm_handle, hwparams, &frames, NULL); | 576 /* Failed to set buffer size, try to just use the defaults */ |
475 if ( status < 0 ) { | 577 if ( ALSA_finalize_hardware(this, spec, hwparams, 1) < 0 ) { |
476 SDL_SetError("Couldn't set period size: %s", SDL_NAME(snd_strerror)(status)); | 578 SDL_SetError("Couldn't set hardware audio parameters: %s", SDL_NAME(snd_strerror)(status)); |
477 ALSA_CloseAudio(this); | 579 ALSA_CloseAudio(this); |
478 return(-1); | 580 return(-1); |
479 } | 581 } |
480 | |
481 spec->samples = frames; | |
482 | |
483 periods = 2; | |
484 status = SDL_NAME(snd_pcm_hw_params_set_periods_near)(pcm_handle, hwparams, &periods, NULL); | |
485 if ( status < 0 ) { | |
486 SDL_SetError("Couldn't set period count: %s", SDL_NAME(snd_strerror)(status)); | |
487 ALSA_CloseAudio(this); | |
488 return(-1); | |
489 } | |
490 } else { | |
491 frames = spec->samples * 2; | |
492 status = SDL_NAME(snd_pcm_hw_params_set_buffer_size_near)(pcm_handle, hwparams, &frames); | |
493 if ( status < 0 ) { | |
494 SDL_SetError("Couldn't set buffer size: %s", SDL_NAME(snd_strerror)(status)); | |
495 ALSA_CloseAudio(this); | |
496 return(-1); | |
497 } | |
498 } | |
499 | |
500 /* "set" the hardware with the desired parameters */ | |
501 status = SDL_NAME(snd_pcm_hw_params)(pcm_handle, hwparams); | |
502 if ( status < 0 ) { | |
503 SDL_SetError("Couldn't set hardware audio parameters: %s", SDL_NAME(snd_strerror)(status)); | |
504 ALSA_CloseAudio(this); | |
505 return(-1); | |
506 } | |
507 | |
508 /* This is useful for debugging */ | |
509 if (getenv("SDL_AUDIO_ALSA_DEBUG_PERIOD_SIZE")) { | |
510 snd_pcm_uframes_t bufsize; | |
511 snd_pcm_sframes_t persize; | |
512 unsigned int periods; int dir; | |
513 | |
514 SDL_NAME(snd_pcm_hw_params_get_buffer_size)(hwparams, &bufsize); | |
515 SDL_NAME(snd_pcm_hw_params_get_period_size)(hwparams, &persize, &dir); | |
516 SDL_NAME(snd_pcm_hw_params_get_periods)(hwparams, &periods, &dir); | |
517 | |
518 fprintf(stderr, "ALSA: period size = %ld, periods = %u, buffer size = %lu\n", persize, periods, bufsize); | |
519 } | 582 } |
520 | 583 |
521 /* Set the software parameters */ | 584 /* Set the software parameters */ |
522 snd_pcm_sw_params_alloca(&swparams); | 585 snd_pcm_sw_params_alloca(&swparams); |
523 status = SDL_NAME(snd_pcm_sw_params_current)(pcm_handle, swparams); | 586 status = SDL_NAME(snd_pcm_sw_params_current)(pcm_handle, swparams); |