Recommendation from Lennart Poettering: SDL-1.2
authorSam Lantinga <slouken@libsdl.org>
Mon, 19 Oct 2009 02:23:21 +0000
branchSDL-1.2
changeset 4357a10dac5858fe
parent 4356 ab2dfac9d5c1
child 4358 df306a61a61d
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.
src/audio/alsa/SDL_alsa_audio.c
     1.1 --- a/src/audio/alsa/SDL_alsa_audio.c	Sun Oct 18 23:18:28 2009 +0000
     1.2 +++ b/src/audio/alsa/SDL_alsa_audio.c	Mon Oct 19 02:23:21 2009 +0000
     1.3 @@ -65,6 +65,7 @@
     1.4  static const char *(*SDL_NAME(snd_strerror))(int errnum);
     1.5  static size_t (*SDL_NAME(snd_pcm_hw_params_sizeof))(void);
     1.6  static size_t (*SDL_NAME(snd_pcm_sw_params_sizeof))(void);
     1.7 +static void (*SDL_NAME(snd_pcm_hw_params_copy))(snd_pcm_hw_params_t *dst, const snd_pcm_hw_params_t *src);
     1.8  static int (*SDL_NAME(snd_pcm_hw_params_any))(snd_pcm_t *pcm, snd_pcm_hw_params_t *params);
     1.9  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);
    1.10  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);
    1.11 @@ -101,6 +102,7 @@
    1.12  	{ "snd_strerror",	(void**)(char*)&SDL_NAME(snd_strerror)		},
    1.13  	{ "snd_pcm_hw_params_sizeof",		(void**)(char*)&SDL_NAME(snd_pcm_hw_params_sizeof)		},
    1.14  	{ "snd_pcm_sw_params_sizeof",		(void**)(char*)&SDL_NAME(snd_pcm_sw_params_sizeof)		},
    1.15 +	{ "snd_pcm_hw_params_copy",		(void**)(char*)&SDL_NAME(snd_pcm_hw_params_copy)		},
    1.16  	{ "snd_pcm_hw_params_any",		(void**)(char*)&SDL_NAME(snd_pcm_hw_params_any)		},
    1.17  	{ "snd_pcm_hw_params_set_access",	(void**)(char*)&SDL_NAME(snd_pcm_hw_params_set_access)		},
    1.18  	{ "snd_pcm_hw_params_set_format",	(void**)(char*)&SDL_NAME(snd_pcm_hw_params_set_format)		},
    1.19 @@ -365,16 +367,116 @@
    1.20  	}
    1.21  }
    1.22  
    1.23 +static int ALSA_finalize_hardware(_THIS, SDL_AudioSpec *spec, snd_pcm_hw_params_t *hwparams, int override)
    1.24 +{
    1.25 +	int status;
    1.26 +	snd_pcm_uframes_t bufsize;
    1.27 +
    1.28 +	/* "set" the hardware with the desired parameters */
    1.29 +	status = SDL_NAME(snd_pcm_hw_params)(pcm_handle, hwparams);
    1.30 +	if ( status < 0 ) {
    1.31 +		return(-1);
    1.32 +	}
    1.33 +
    1.34 +	/* Get samples for the actual buffer size */
    1.35 +	status = SDL_NAME(snd_pcm_hw_params_get_buffer_size)(hwparams, &bufsize);
    1.36 +	if ( status < 0 ) {
    1.37 +		return(-1);
    1.38 +	}
    1.39 +	if ( !override && bufsize != spec->samples * 2 ) {
    1.40 +		return(-1);
    1.41 +	}
    1.42 +
    1.43 +	/* FIXME: Is this safe to do? */
    1.44 +	spec->samples = bufsize / 2;
    1.45 +
    1.46 +	/* This is useful for debugging */
    1.47 +	if ( getenv("SDL_AUDIO_ALSA_DEBUG") ) {
    1.48 +		snd_pcm_sframes_t persize = 0;
    1.49 +		unsigned int periods = 0;
    1.50 +
    1.51 +		SDL_NAME(snd_pcm_hw_params_get_period_size)(hwparams, &persize, NULL);
    1.52 +		SDL_NAME(snd_pcm_hw_params_get_periods)(hwparams, &periods, NULL);
    1.53 +
    1.54 +		fprintf(stderr, "ALSA: period size = %ld, periods = %u, buffer size = %lu\n", persize, periods, bufsize);
    1.55 +	}
    1.56 +	return(0);
    1.57 +}
    1.58 +
    1.59 +static int ALSA_set_period_size(_THIS, SDL_AudioSpec *spec, snd_pcm_hw_params_t *params)
    1.60 +{
    1.61 +	const char *env;
    1.62 +	int status;
    1.63 +	int override = 0;
    1.64 +	snd_pcm_hw_params_t *hwparams;
    1.65 +	snd_pcm_uframes_t frames;
    1.66 +	unsigned int periods;
    1.67 +
    1.68 +	/* Copy the hardware parameters for this setup */
    1.69 +	snd_pcm_hw_params_alloca(&hwparams);
    1.70 +	SDL_NAME(snd_pcm_hw_params_copy)(hwparams, params);
    1.71 +
    1.72 +	env = getenv("SDL_AUDIO_ALSA_SET_PERIOD_SIZE");
    1.73 +	if ( env ) {
    1.74 +		override = SDL_strol(env);
    1.75 +		if ( override == 0 ) {
    1.76 +			return(-1);
    1.77 +		}
    1.78 +	}
    1.79 +
    1.80 +	frames = spec->samples;
    1.81 +	status = SDL_NAME(snd_pcm_hw_params_set_period_size_near)(pcm_handle, hwparams, &frames, NULL);
    1.82 +	if ( status < 0 ) {
    1.83 +		return(-1);
    1.84 +	}
    1.85 +
    1.86 +	periods = 2;
    1.87 +	status = SDL_NAME(snd_pcm_hw_params_set_periods_near)(pcm_handle, hwparams, &periods, NULL);
    1.88 +	if ( status < 0 ) {
    1.89 +		return(-1);
    1.90 +	}
    1.91 +
    1.92 +	return ALSA_finalize_hardware(this, spec, hwparams, override);
    1.93 +}
    1.94 +
    1.95 +static int ALSA_set_buffer_size(_THIS, SDL_AudioSpec *spec, snd_pcm_hw_params_t *params)
    1.96 +{
    1.97 +	const char *env;
    1.98 +	int status;
    1.99 +	int override = 0;
   1.100 +	snd_pcm_hw_params_t *hwparams;
   1.101 +	snd_pcm_uframes_t frames;
   1.102 +
   1.103 +	/* Copy the hardware parameters for this setup */
   1.104 +	snd_pcm_hw_params_alloca(&hwparams);
   1.105 +	SDL_NAME(snd_pcm_hw_params_copy)(hwparams, params);
   1.106 +
   1.107 +	env = getenv("SDL_AUDIO_ALSA_SET_BUFFER_SIZE");
   1.108 +	if ( env ) {
   1.109 +		override = SDL_strol(env);
   1.110 +		if ( override == 0 ) {
   1.111 +			return(-1);
   1.112 +		}
   1.113 +	}
   1.114 +
   1.115 +	frames = spec->samples * 2;
   1.116 +	status = SDL_NAME(snd_pcm_hw_params_set_buffer_size_near)(pcm_handle, hwparams, &frames);
   1.117 +	if ( status < 0 ) {
   1.118 +		return(-1);
   1.119 +	}
   1.120 +
   1.121 +	return ALSA_finalize_hardware(this, spec, hwparams, override);
   1.122 +}
   1.123 +
   1.124  static int ALSA_OpenAudio(_THIS, SDL_AudioSpec *spec)
   1.125  {
   1.126  	int                  status;
   1.127  	snd_pcm_hw_params_t *hwparams;
   1.128  	snd_pcm_sw_params_t *swparams;
   1.129  	snd_pcm_format_t     format;
   1.130 -	snd_pcm_uframes_t    frames;
   1.131  	unsigned int         rate;
   1.132 -	unsigned int         periods;
   1.133  	unsigned int 	     channels;
   1.134 +	snd_pcm_uframes_t    bufsize;
   1.135  	Uint16               test_format;
   1.136  
   1.137  	/* Open the audio device */
   1.138 @@ -469,53 +571,14 @@
   1.139  	spec->freq = rate;
   1.140  
   1.141  	/* Set the buffer size, in samples */
   1.142 -	if (getenv("SDL_AUDIO_ALSA_SET_PERIOD_SIZE")) {
   1.143 -		frames = spec->samples;
   1.144 -		status = SDL_NAME(snd_pcm_hw_params_set_period_size_near)(pcm_handle, hwparams, &frames, NULL);
   1.145 -		if ( status < 0 ) {
   1.146 -			SDL_SetError("Couldn't set period size: %s", SDL_NAME(snd_strerror)(status));
   1.147 -			ALSA_CloseAudio(this);
   1.148 -			return(-1);
   1.149 -		}
   1.150 -
   1.151 -		spec->samples = frames;
   1.152 -
   1.153 -		periods = 2;
   1.154 -		status = SDL_NAME(snd_pcm_hw_params_set_periods_near)(pcm_handle, hwparams, &periods, NULL);
   1.155 -		if ( status < 0 ) {
   1.156 -			SDL_SetError("Couldn't set period count: %s", SDL_NAME(snd_strerror)(status));
   1.157 +	if ( ALSA_set_period_size(this, spec, hwparams) < 0 &&
   1.158 +	     ALSA_set_buffer_size(this, spec, hwparams) < 0 ) {
   1.159 +		/* Failed to set buffer size, try to just use the defaults */
   1.160 +		if ( ALSA_finalize_hardware(this, spec, hwparams, 1) < 0 ) {
   1.161 +			SDL_SetError("Couldn't set hardware audio parameters: %s", SDL_NAME(snd_strerror)(status));
   1.162  			ALSA_CloseAudio(this);
   1.163  			return(-1);
   1.164  		}
   1.165 -	} else {
   1.166 -		frames = spec->samples * 2;
   1.167 -		status = SDL_NAME(snd_pcm_hw_params_set_buffer_size_near)(pcm_handle, hwparams, &frames);
   1.168 -		if ( status < 0 ) {
   1.169 -			SDL_SetError("Couldn't set buffer size: %s", SDL_NAME(snd_strerror)(status));
   1.170 -			ALSA_CloseAudio(this);
   1.171 -			return(-1);
   1.172 -		}
   1.173 -	}
   1.174 -
   1.175 -	/* "set" the hardware with the desired parameters */
   1.176 -	status = SDL_NAME(snd_pcm_hw_params)(pcm_handle, hwparams);
   1.177 -	if ( status < 0 ) {
   1.178 -		SDL_SetError("Couldn't set hardware audio parameters: %s", SDL_NAME(snd_strerror)(status));
   1.179 -		ALSA_CloseAudio(this);
   1.180 -		return(-1);
   1.181 -	}
   1.182 -
   1.183 -	/* This is useful for debugging */
   1.184 -	if (getenv("SDL_AUDIO_ALSA_DEBUG_PERIOD_SIZE")) {
   1.185 -		snd_pcm_uframes_t bufsize;
   1.186 -		snd_pcm_sframes_t persize;
   1.187 -		unsigned int periods; int dir;
   1.188 -
   1.189 -		SDL_NAME(snd_pcm_hw_params_get_buffer_size)(hwparams, &bufsize);
   1.190 -		SDL_NAME(snd_pcm_hw_params_get_period_size)(hwparams, &persize, &dir);
   1.191 -		SDL_NAME(snd_pcm_hw_params_get_periods)(hwparams, &periods, &dir);
   1.192 -
   1.193 -		fprintf(stderr, "ALSA: period size = %ld, periods = %u, buffer size = %lu\n", persize, periods, bufsize);
   1.194  	}
   1.195  
   1.196  	/* Set the software parameters */