comparison src/audio/alsa/SDL_alsa_audio.c @ 4333:55717a755897 SDL-1.2

Switched from setting the period size and count to setting the buffer size directly, based on feedback from the ALSA development list: http://mailman.alsa-project.org/pipermail/alsa-devel/2009-October/022267.html This has the nice side effect of reducing latency on my SBLive! card.
author Sam Lantinga <slouken@libsdl.org>
date Tue, 13 Oct 2009 09:56:15 +0000
parents 67e799ffcadf
children afadcd7d2319
comparison
equal deleted inserted replaced
4332:67e799ffcadf 4333:55717a755897
43 /* The tag name used by ALSA audio */ 43 /* The tag name used by ALSA audio */
44 #define DRIVER_NAME "alsa" 44 #define DRIVER_NAME "alsa"
45 45
46 /* The default ALSA audio driver */ 46 /* The default ALSA audio driver */
47 #define DEFAULT_DEVICE "default" 47 #define DEFAULT_DEVICE "default"
48
49 /* Whether we should set the buffer size or the period size */
50 /*#define SET_PERIOD_SIZE*/
51 /*#define DEBUG_PERIOD_SIZE*/
48 52
49 /* Audio driver functions */ 53 /* Audio driver functions */
50 static int ALSA_OpenAudio(_THIS, SDL_AudioSpec *spec); 54 static int ALSA_OpenAudio(_THIS, SDL_AudioSpec *spec);
51 static void ALSA_WaitAudio(_THIS); 55 static void ALSA_WaitAudio(_THIS);
52 static void ALSA_PlayAudio(_THIS); 56 static void ALSA_PlayAudio(_THIS);
76 static int (*SDL_NAME(snd_pcm_hw_params_set_rate_near))(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir); 80 static int (*SDL_NAME(snd_pcm_hw_params_set_rate_near))(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir);
77 static int (*SDL_NAME(snd_pcm_hw_params_set_period_size_near))(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val, int *dir); 81 static int (*SDL_NAME(snd_pcm_hw_params_set_period_size_near))(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val, int *dir);
78 static int (*SDL_NAME(snd_pcm_hw_params_get_period_size))(const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *frames, int *dir); 82 static int (*SDL_NAME(snd_pcm_hw_params_get_period_size))(const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *frames, int *dir);
79 static int (*SDL_NAME(snd_pcm_hw_params_set_periods_near))(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir); 83 static int (*SDL_NAME(snd_pcm_hw_params_set_periods_near))(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir);
80 static int (*SDL_NAME(snd_pcm_hw_params_get_periods))(const snd_pcm_hw_params_t *params, unsigned int *val, int *dir); 84 static int (*SDL_NAME(snd_pcm_hw_params_get_periods))(const snd_pcm_hw_params_t *params, unsigned int *val, int *dir);
85 static int (*SDL_NAME(snd_pcm_hw_params_set_buffer_size_near))(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val);
81 static int (*SDL_NAME(snd_pcm_hw_params_get_buffer_size))(const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val); 86 static int (*SDL_NAME(snd_pcm_hw_params_get_buffer_size))(const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val);
82 static int (*SDL_NAME(snd_pcm_hw_params))(snd_pcm_t *pcm, snd_pcm_hw_params_t *params); 87 static int (*SDL_NAME(snd_pcm_hw_params))(snd_pcm_t *pcm, snd_pcm_hw_params_t *params);
83 /* 88 /*
84 */ 89 */
85 static int (*SDL_NAME(snd_pcm_sw_params_current))(snd_pcm_t *pcm, snd_pcm_sw_params_t *swparams); 90 static int (*SDL_NAME(snd_pcm_sw_params_current))(snd_pcm_t *pcm, snd_pcm_sw_params_t *swparams);
86 static int (*SDL_NAME(snd_pcm_sw_params_set_start_threshold))(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val); 91 static int (*SDL_NAME(snd_pcm_sw_params_set_start_threshold))(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val);
87 static int (*SDL_NAME(snd_pcm_sw_params_set_avail_min))(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val);
88 static int (*SDL_NAME(snd_pcm_sw_params))(snd_pcm_t *pcm, snd_pcm_sw_params_t *params); 92 static int (*SDL_NAME(snd_pcm_sw_params))(snd_pcm_t *pcm, snd_pcm_sw_params_t *params);
89 static int (*SDL_NAME(snd_pcm_nonblock))(snd_pcm_t *pcm, int nonblock); 93 static int (*SDL_NAME(snd_pcm_nonblock))(snd_pcm_t *pcm, int nonblock);
90 #define snd_pcm_hw_params_sizeof SDL_NAME(snd_pcm_hw_params_sizeof) 94 #define snd_pcm_hw_params_sizeof SDL_NAME(snd_pcm_hw_params_sizeof)
91 #define snd_pcm_sw_params_sizeof SDL_NAME(snd_pcm_sw_params_sizeof) 95 #define snd_pcm_sw_params_sizeof SDL_NAME(snd_pcm_sw_params_sizeof)
92 96
112 { "snd_pcm_hw_params_set_rate_near", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_set_rate_near) }, 116 { "snd_pcm_hw_params_set_rate_near", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_set_rate_near) },
113 { "snd_pcm_hw_params_set_period_size_near", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_set_period_size_near) }, 117 { "snd_pcm_hw_params_set_period_size_near", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_set_period_size_near) },
114 { "snd_pcm_hw_params_get_period_size", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_get_period_size) }, 118 { "snd_pcm_hw_params_get_period_size", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_get_period_size) },
115 { "snd_pcm_hw_params_set_periods_near", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_set_periods_near) }, 119 { "snd_pcm_hw_params_set_periods_near", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_set_periods_near) },
116 { "snd_pcm_hw_params_get_periods", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_get_periods) }, 120 { "snd_pcm_hw_params_get_periods", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_get_periods) },
121 { "snd_pcm_hw_params_set_buffer_size_near", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_set_buffer_size_near) },
117 { "snd_pcm_hw_params_get_buffer_size", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_get_buffer_size) }, 122 { "snd_pcm_hw_params_get_buffer_size", (void**)(char*)&SDL_NAME(snd_pcm_hw_params_get_buffer_size) },
118 { "snd_pcm_hw_params", (void**)(char*)&SDL_NAME(snd_pcm_hw_params) }, 123 { "snd_pcm_hw_params", (void**)(char*)&SDL_NAME(snd_pcm_hw_params) },
119 { "snd_pcm_sw_params_current", (void**)(char*)&SDL_NAME(snd_pcm_sw_params_current) }, 124 { "snd_pcm_sw_params_current", (void**)(char*)&SDL_NAME(snd_pcm_sw_params_current) },
120 { "snd_pcm_sw_params_set_start_threshold", (void**)(char*)&SDL_NAME(snd_pcm_sw_params_set_start_threshold) }, 125 { "snd_pcm_sw_params_set_start_threshold", (void**)(char*)&SDL_NAME(snd_pcm_sw_params_set_start_threshold) },
121 { "snd_pcm_sw_params_set_avail_min", (void**)(char*)&SDL_NAME(snd_pcm_sw_params_set_avail_min) },
122 { "snd_pcm_sw_params", (void**)(char*)&SDL_NAME(snd_pcm_sw_params) }, 126 { "snd_pcm_sw_params", (void**)(char*)&SDL_NAME(snd_pcm_sw_params) },
123 { "snd_pcm_nonblock", (void**)(char*)&SDL_NAME(snd_pcm_nonblock) }, 127 { "snd_pcm_nonblock", (void**)(char*)&SDL_NAME(snd_pcm_nonblock) },
124 }; 128 };
125 129
126 static void UnloadALSALibrary(void) { 130 static void UnloadALSALibrary(void) {
366 snd_pcm_hw_params_t *hwparams; 370 snd_pcm_hw_params_t *hwparams;
367 snd_pcm_sw_params_t *swparams; 371 snd_pcm_sw_params_t *swparams;
368 snd_pcm_format_t format; 372 snd_pcm_format_t format;
369 snd_pcm_uframes_t frames; 373 snd_pcm_uframes_t frames;
370 unsigned int rate; 374 unsigned int rate;
375 #ifdef SET_PERIOD_SIZE
371 unsigned int periods; 376 unsigned int periods;
372 unsigned int channels; 377 #endif
378 unsigned int channels;
373 Uint16 test_format; 379 Uint16 test_format;
374 380
375 /* Open the audio device */ 381 /* Open the audio device */
376 /* Name of device should depend on # channels in spec */ 382 /* Name of device should depend on # channels in spec */
377 status = SDL_NAME(snd_pcm_open)(&pcm_handle, get_audio_device(spec->channels), SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK); 383 status = SDL_NAME(snd_pcm_open)(&pcm_handle, get_audio_device(spec->channels), SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
462 return(-1); 468 return(-1);
463 } 469 }
464 spec->freq = rate; 470 spec->freq = rate;
465 471
466 /* Set the buffer size, in samples */ 472 /* Set the buffer size, in samples */
473 #ifdef SET_PERIOD_SIZE
467 frames = spec->samples; 474 frames = spec->samples;
468 status = SDL_NAME(snd_pcm_hw_params_set_period_size_near)(pcm_handle, hwparams, &frames, NULL); 475 status = SDL_NAME(snd_pcm_hw_params_set_period_size_near)(pcm_handle, hwparams, &frames, NULL);
469 if ( status < 0 ) { 476 if ( status < 0 ) {
470 SDL_SetError("Couldn't set audio frequency: %s", SDL_NAME(snd_strerror)(status)); 477 SDL_SetError("Couldn't set period size: %s", SDL_NAME(snd_strerror)(status));
471 ALSA_CloseAudio(this); 478 ALSA_CloseAudio(this);
472 return(-1); 479 return(-1);
473 } 480 }
474 481
475 spec->samples = frames; 482 spec->samples = frames;
476 483
477 periods = 2; 484 periods = 2;
478 SDL_NAME(snd_pcm_hw_params_set_periods_near)(pcm_handle, hwparams, &periods, NULL); 485 status = SDL_NAME(snd_pcm_hw_params_set_periods_near)(pcm_handle, hwparams, &periods, NULL);
486 if ( status < 0 ) {
487 SDL_SetError("Couldn't set period count: %s", SDL_NAME(snd_strerror)(status));
488 ALSA_CloseAudio(this);
489 return(-1);
490 }
491 #else
492 frames = spec->samples * 2;
493 status = SDL_NAME(snd_pcm_hw_params_set_buffer_size_near)(pcm_handle, hwparams, &frames);
494 #endif
479 495
480 /* "set" the hardware with the desired parameters */ 496 /* "set" the hardware with the desired parameters */
481 status = SDL_NAME(snd_pcm_hw_params)(pcm_handle, hwparams); 497 status = SDL_NAME(snd_pcm_hw_params)(pcm_handle, hwparams);
482 if ( status < 0 ) { 498 if ( status < 0 ) {
483 SDL_SetError("Couldn't set hardware audio parameters: %s", SDL_NAME(snd_strerror)(status)); 499 SDL_SetError("Couldn't set hardware audio parameters: %s", SDL_NAME(snd_strerror)(status));
484 ALSA_CloseAudio(this); 500 ALSA_CloseAudio(this);
485 return(-1); 501 return(-1);
486 } 502 }
487 503
488 /* This is useful for debugging... */ 504 /* This is useful for debugging... */
489 #if 0 505 #ifdef DEBUG_PERIOD_SIZE
490 { snd_pcm_uframes_t bufsize; snd_pcm_sframes_t persize; unsigned int periods; int dir; 506 { snd_pcm_uframes_t bufsize; snd_pcm_sframes_t persize; unsigned int periods; int dir;
491 SDL_NAME(snd_pcm_hw_params_get_buffer_size)(hwparams, &bufsize); 507 SDL_NAME(snd_pcm_hw_params_get_buffer_size)(hwparams, &bufsize);
492 SDL_NAME(snd_pcm_hw_params_get_period_size)(hwparams, &persize, &dir); 508 SDL_NAME(snd_pcm_hw_params_get_period_size)(hwparams, &persize, &dir);
493 SDL_NAME(snd_pcm_hw_params_get_periods)(hwparams, &periods, &dir); 509 SDL_NAME(snd_pcm_hw_params_get_periods)(hwparams, &periods, &dir);
494 510
508 if ( status < 0 ) { 524 if ( status < 0 ) {
509 SDL_SetError("Couldn't set start threshold: %s", SDL_NAME(snd_strerror)(status)); 525 SDL_SetError("Couldn't set start threshold: %s", SDL_NAME(snd_strerror)(status));
510 ALSA_CloseAudio(this); 526 ALSA_CloseAudio(this);
511 return(-1); 527 return(-1);
512 } 528 }
513 status = SDL_NAME(snd_pcm_sw_params_set_avail_min)(pcm_handle, swparams, frames);
514 if ( status < 0 ) {
515 SDL_SetError("Couldn't set avail min: %s", SDL_NAME(snd_strerror)(status));
516 ALSA_CloseAudio(this);
517 return(-1);
518 }
519 status = SDL_NAME(snd_pcm_sw_params)(pcm_handle, swparams); 529 status = SDL_NAME(snd_pcm_sw_params)(pcm_handle, swparams);
520 if ( status < 0 ) { 530 if ( status < 0 ) {
521 SDL_SetError("Couldn't set software audio parameters: %s", SDL_NAME(snd_strerror)(status)); 531 SDL_SetError("Couldn't set software audio parameters: %s", SDL_NAME(snd_strerror)(status));
522 ALSA_CloseAudio(this); 532 ALSA_CloseAudio(this);
523 return(-1); 533 return(-1);