[alsa-devel] [PATCH - oss plugin update 2/2] oss: Add user variables to set period and buffer config

Takashi Iwai tiwai at suse.de
Mon Jun 24 10:00:06 CEST 2013


At Sun, 23 Jun 2013 01:25:19 +0100,
alex.d.wiggins at gmail.com wrote:
> 
> From: Alex Wiggins <alex.d.wiggins at gmail.com>
> 
> Added 4 user variables to control the OSS period and buffer config:
> 
>  - period_size_allowany (boolean):
>    if not set then queries OSS for period size
>    (by using SNDCTL_DSP_GETBLKSIZE),
>    if set to true then allows any power of 2 period size;
> 

I'd suggest to put an underscore between "allow" and "any".
Or, instead of adding a flag...

>  - period_size (integer):
>    sets the OSS period size (SND_PCM_IOPLUG_HW_PERIOD_BYTES);

... handle allowany when period_size < 0, for example.


Takashi


>  - periods (integer):
>    sets the number of OSS periods (SND_PCM_IOPLUG_HW_PERIODS);
> 
>  - buffer_size (integer):
>    sets the OSS buffer size (SND_PCM_IOPLUG_HW_BUFFER_BYTES).
> 
> Note that ALSA performs sanity checks to prevent conflicts.
> 
> Signed-off-by: Alex Wiggins <alex.d.wiggins at gmail.com>
> 
> diff --git a/oss/pcm_oss.c b/oss/pcm_oss.c
> index 6d8dea4..7131e54 100644
> --- a/oss/pcm_oss.c
> +++ b/oss/pcm_oss.c
> @@ -60,6 +60,13 @@ typedef struct snd_pcm_oss {
>  	unsigned int period_shift;
>  	unsigned int periods;
>  	unsigned int frame_bytes;
> +	/* user variables set using ALSA config files */
> +	/* included here as this snd_pcm_oss_t struct
> +	   is stored in io->private_data */
> +	int user_period_size_allowany;
> +	long int user_period_size;
> +	long int user_periods;
> +	long int user_buffer_size;
>  } snd_pcm_oss_t;
>  
>  static snd_pcm_sframes_t oss_write(snd_pcm_ioplug_t *io,
> @@ -406,6 +413,7 @@ static int oss_hw_constraint(snd_pcm_oss_t *oss)
>  	unsigned int nchannels;
>  	unsigned int channel[6];
>  	/* period and buffer bytes must be power of two */
> +	/* minimum: 2^8 = 256; maximum: 2^23 = 8388608 */
>  	static const unsigned int bytes_list[] = {
>  		1U<<8, 1U<<9, 1U<<10, 1U<<11, 1U<<12, 1U<<13, 1U<<14, 1U<<15,
>  		1U<<16, 1U<<17, 1U<<18, 1U<<19, 1U<<20, 1U<<21, 1U<<22, 1U<<23
> @@ -498,20 +506,96 @@ static int oss_hw_constraint(snd_pcm_oss_t *oss)
>  	if (err < 0)
>  		return err;
>  
> -	/* period size (in power of two) */
> -	err = snd_pcm_ioplug_set_param_list(io, SND_PCM_IOPLUG_HW_PERIOD_BYTES,
> -					    ARRAY_SIZE(bytes_list), bytes_list);
> -	if (err < 0)
> -		return err;
> -	/* periods */
> -	err = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_PERIODS, 2, 1024);
> -	if (err < 0)
> -		return err;
> -	/* buffer size (in power of two) */
> -	err = snd_pcm_ioplug_set_param_list(io, SND_PCM_IOPLUG_HW_BUFFER_BYTES,
> -					    ARRAY_SIZE(bytes_list), bytes_list);
> -	if (err < 0)
> -		return err;
> +	/* period and buffer sizes: default behaviour below is to
> +	   query period size from OSS */
> +
> +	/* consider user set paramaters
> +	   (period_size_allowany; period_size; periods; buffer_size) */
> +	/* note: ALSA performs sanity checks
> +		 to prevent conflicting parameters */
> +
> +	/* period_size_allowany and period_size */
> +	if (oss->user_period_size_allowany) {
> +		/* period_size_allowany flag set:
> +		   allow any power of 2 period size */
> +		err = snd_pcm_ioplug_set_param_list(io,
> +			SND_PCM_IOPLUG_HW_PERIOD_BYTES,
> +			ARRAY_SIZE(bytes_list), bytes_list);
> +		if (err < 0)
> +			return err;
> +	} else {
> +		if (oss->user_period_size > 0) {
> +			/* period_size set to positive value:
> +			   use user set period size */
> +			const unsigned int user_period_size
> +			  = oss->user_period_size;
> +			err = snd_pcm_ioplug_set_param_list(io,
> +				SND_PCM_IOPLUG_HW_PERIOD_BYTES, 1,
> +				&user_period_size);
> +		} else {
> +			/* query OSS for period size (called fragment size) */
> +			unsigned int fragsize;
> +			if (ioctl(oss->fd, SNDCTL_DSP_GETBLKSIZE, &fragsize)
> +				< 0)
> +				fprintf(stderr,
> +"*** alsa-plugins-oss: error querying SNDCTL_DSP_GETBLKSIZE.\n");
> +
> +			/* note: second query of SNDCTL_DSP_GETBLKSIZE
> +				 can give different result
> +				 (i.e. 4096 instead of 2048) */
> +			/* in oss_audio_core.c getblksize function,
> +			   4096 is the default return value:
> +			   so second time probably not reliable */
> +
> +			/* period size (in power of two) */
> +			unsigned int x = fragsize;
> +			/* check if fragsize is a power of two */
> +			if ((x != 0) && ((x & (~x + 1)) == x))
> +				err = snd_pcm_ioplug_set_param_list(io,
> +					SND_PCM_IOPLUG_HW_PERIOD_BYTES,
> +					1, &fragsize);
> +			else
> +				err = snd_pcm_ioplug_set_param_list(io,
> +					SND_PCM_IOPLUG_HW_PERIOD_BYTES,
> +					ARRAY_SIZE(bytes_list), bytes_list);
> +			if (err < 0)
> +				return err;
> +		}
> +	}
> +
> +	/* periods (number of periods per buffer) */
> +	if (oss->user_periods > 0) {
> +		/* force number of periods to user set periods */
> +		const unsigned int user_periods = oss->user_periods;
> +		err = snd_pcm_ioplug_set_param_list(io,
> +			SND_PCM_IOPLUG_HW_PERIODS, 1, &user_periods);
> +		if (err < 0)
> +			return err;
> +	} else {
> +		/* allow any number of periods between 2 and 1024 inclusive
> +		  (ALSA can choose) */
> +		err = snd_pcm_ioplug_set_param_minmax(io,
> +			SND_PCM_IOPLUG_HW_PERIODS, 2, 1024);
> +		if (err < 0)
> +			return err;
> +	}
> +
> +	/* buffer_size */
> +	if (oss->user_buffer_size > 0) {
> +		/* force buffer size to user set buffer_size */
> +		const unsigned int user_buffer_size = oss->user_buffer_size;
> +		err = snd_pcm_ioplug_set_param_list(io,
> +			SND_PCM_IOPLUG_HW_BUFFER_BYTES, 1, &user_buffer_size);
> +		if (err < 0)
> +			return err;
> +	} else {
> +		/* buffer size (in power of two) */
> +		err = snd_pcm_ioplug_set_param_list(io,
> +			SND_PCM_IOPLUG_HW_BUFFER_BYTES,
> +			ARRAY_SIZE(bytes_list), bytes_list);
> +		if (err < 0)
> +			return err;
> +	}
>  
>  	return 0;
>  }
> @@ -556,6 +640,11 @@ SND_PCM_PLUGIN_DEFINE_FUNC(oss)
>  	const char *device = "/dev/dsp";
>  	int err;
>  	snd_pcm_oss_t *oss;
> +	/* default values for user variables*/
> +	int user_period_size_allowany = 0;
> +	long int user_period_size = 0;
> +	long int user_periods = 0;
> +	long int user_buffer_size = 0;
>  	
>  	snd_config_for_each(i, next, conf) {
>  		snd_config_t *n = snd_config_iterator_entry(i);
> @@ -571,6 +660,39 @@ SND_PCM_PLUGIN_DEFINE_FUNC(oss)
>  			}
>  			continue;
>  		}
> +
> +		/* user variables */
> +		if (strcmp(id, "period_size_allowany") == 0) {
> +			if (snd_config_get_bool(n) < 0) {
> +				SNDERR("Invalid type for %s", id);
> +				return -EINVAL;
> +			} else
> +				user_period_size_allowany =
> +					snd_config_get_bool(n);
> +			continue;
> +		}
> +		if (strcmp(id, "period_size") == 0) {
> +			if (snd_config_get_integer(n, &user_period_size) < 0) {
> +				SNDERR("Invalid type for %s", id);
> +				return -EINVAL;
> +			}
> +			continue;
> +		}
> +		if (strcmp(id, "periods") == 0) {
> +			if (snd_config_get_integer(n, &user_periods) < 0) {
> +				SNDERR("Invalid type for %s", id);
> +				return -EINVAL;
> +			}
> +			continue;
> +		}
> +		if (strcmp(id, "buffer_size") == 0) {
> +			if (snd_config_get_integer(n, &user_buffer_size) < 0) {
> +				SNDERR("Invalid type for %s", id);
> +				return -EINVAL;
> +			}
> +			continue;
> +		}
> +
>  		SNDERR("Unknown field %s", id);
>  		return -EINVAL;
>  	}
> @@ -595,6 +717,12 @@ SND_PCM_PLUGIN_DEFINE_FUNC(oss)
>  		goto error;
>  	}
>  
> +	/* save user variables from ALSA config files */
> +	oss->user_period_size_allowany = user_period_size_allowany;
> +	oss->user_period_size = user_period_size;
> +	oss->user_periods = user_periods;
> +	oss->user_buffer_size = user_buffer_size;
> +
>  	oss->io.version = SND_PCM_IOPLUG_VERSION;
>  	oss->io.name = "ALSA <-> OSS PCM I/O Plugin";
>  	oss->io.poll_fd = oss->fd;
> -- 
> 1.8.3.1
> 


More information about the Alsa-devel mailing list