[alsa-devel] [PATCH 2/3] route: Select slave chmap based on ttable information

Takashi Iwai tiwai at suse.de
Fri Feb 21 16:49:21 CET 2014


At Fri, 21 Feb 2014 16:24:21 +0100,
David Henningsson wrote:
> 
> It means we need to initialize this order:
> 
>  1) Read the ttable to figure out which channels are present
>  2) Open slave pcm and find a matching chmap
>  3) Determine size of ttable (this can now depend on the chmap)
>  4) Read ttable coefficients
>  5) At prepare time, select the matching chmap
> 
> Signed-off-by: David Henningsson <david.henningsson at canonical.com>
> ---
>  src/pcm/pcm_route.c | 300 ++++++++++++++++++++++++++++++++++++++++++++--------
>  1 file changed, 257 insertions(+), 43 deletions(-)
> 
> diff --git a/src/pcm/pcm_route.c b/src/pcm/pcm_route.c
> index ffc283f..355da1e 100644
> --- a/src/pcm/pcm_route.c
> +++ b/src/pcm/pcm_route.c
> @@ -103,6 +103,7 @@ typedef struct {
>  	snd_pcm_format_t sformat;
>  	int schannels;
>  	snd_pcm_route_params_t params;
> +	snd_pcm_chmap_t *chmap;
>  } snd_pcm_route_t;
>  
>  #endif /* DOC_HIDDEN */
> @@ -518,6 +519,7 @@ static int snd_pcm_route_close(snd_pcm_t *pcm)
>  		}
>  		free(params->dsts);
>  	}
> +	free(route->chmap);
>  	return snd_pcm_generic_close(pcm);
>  }
>  
> @@ -789,21 +791,168 @@ static void snd_pcm_route_dump(snd_pcm_t *pcm, snd_output_t *out)
>  	snd_pcm_dump(route->plug.gen.slave, out);
>  }
>  
> -static int safe_chmapchannel(const char *id, long *channel)
> +static int safe_chmapchannel(const char *id, snd_pcm_chmap_t *chmap,
> +			     long *channel, int channel_size)

A brief description of the function would be helpful, as the code
becomes no longer trivial by this patch.


>  {
> -	int err;
>  	int ch;
> -	err = safe_strtol(id, channel);
> -	if (err >= 0)
> -		return err;
> +	if (safe_strtol(id, channel) >= 0)
> +		return 1;
>  
>  	ch = (int) snd_pcm_chmap_from_string(id);
>  	if (ch == -1)
>  		return -EINVAL;
>  
> -	/* For now, assume standard channel mapping */
> -	*channel = ch - SND_CHMAP_FL;
> +	if (chmap) {
> +		int i, r = 0;
> +		/* Start with highest channel to simplify implementation of
> +		   determine ttable size */
> +		for (i = chmap->channels - 1; i >= 0; i--) {
> +			if ((int) chmap->pos[i] != ch)
> +				continue;
> +			if (r >= channel_size)
> +				continue;
> +			channel[r++] = i;
> +		}
> +		return r;
> +	}
> +	else {
> +		/* Assume ALSA standard channel mapping */
> +		*channel = ch - SND_CHMAP_FL;
> +		return 1;
> +	}
> +}
> +
> +#define MAX_CHMAP_CHANNELS 256
> +
> +static int determine_chmap(snd_config_t *tt, snd_pcm_chmap_t **tt_chmap)
> +{
> +	snd_config_iterator_t i, inext;
> +	snd_pcm_chmap_t *chmap;
> +
> +	assert(tt && tt_chmap);
> +	chmap = malloc(sizeof(snd_pcm_chmap_t) +
> +		       MAX_CHMAP_CHANNELS * sizeof(unsigned int));
> +
> +	chmap->channels = 0;
> +	snd_config_for_each(i, inext, tt) {
> +		const char *id;
> +		snd_config_iterator_t j, jnext;
> +		snd_config_t *in = snd_config_iterator_entry(i);
> +
> +		if (!snd_config_get_id(in, &id) < 0)
> +			continue;
> +		if (snd_config_get_type(in) != SND_CONFIG_TYPE_COMPOUND)
> +			goto err;
> +		snd_config_for_each(j, jnext, in) {
> +			int ch, k, found;
> +			long schannel;
> +			snd_config_t *jnode = snd_config_iterator_entry(j);
> +			if (snd_config_get_id(jnode, &id) < 0)
> +				continue;
> +			if (safe_strtol(id, &schannel) >= 0)
> +				continue;
> +			ch = (int) snd_pcm_chmap_from_string(id);
> +			if (ch == -1)
> +				goto err;
> +
> +			found = 0;
> +			for (k = 0; k < (int) chmap->channels; k++)
> +				if (ch == (int) chmap->pos[k]) {
> +					found = 1;
> +					break;
> +				}
> +			if (found)
> +				continue;
> +
> +			if (chmap->channels >= MAX_CHMAP_CHANNELS) {
> +				SNDERR("Too many channels in ttable chmap");
> +				goto err;
> +			}
> +			chmap->pos[chmap->channels++] = ch;
> +		}
> +	}
> +
> +
> +	*tt_chmap = chmap;
>  	return 0;
> +
> +err:
> +	*tt_chmap = NULL;
> +	free(chmap);
> +	return -EINVAL;
> +}
> +
> +static int find_matching_chmap(snd_pcm_t *spcm, snd_pcm_chmap_t *tt_chmap,
> +			       snd_pcm_chmap_t **found_chmap, int *schannels)
> +{
> +	snd_pcm_chmap_query_t** chmaps = snd_pcm_query_chmaps(spcm);
> +	int i;
> +
> +	*found_chmap = NULL;
> +
> +	if (chmaps == NULL)
> +		return 0; /* chmap API not supported for this slave */
> +
> +	for (i = 0; chmaps[i]; i++) {
> +		unsigned int j, k;
> +		int match = 1;
> +		snd_pcm_chmap_t *c = &chmaps[i]->map;
> +		if (*schannels >= 0 && (int) c->channels != *schannels)
> +			continue;
> +
> +		for (j = 0; j < tt_chmap->channels; j++) {
> +			int found = 0;
> +			unsigned int ch = tt_chmap->pos[j];
> +			for (k = 0; k < c->channels; k++)
> +				if (c->pos[k] == ch) {
> +					found = 1;
> +					break;
> +				}
> +			if (!found) {
> +				match = 0;
> +				break;
> +			}
> +		}
> +
> +		if (match) {
> +			int size = sizeof(snd_pcm_chmap_t) + c->channels * sizeof(unsigned int);
> +			*found_chmap = malloc(size);

NULL check is missing here.


> +			memcpy(*found_chmap, c, size);
> +			*schannels = c->channels;
> +			break;
> +		}
> +	}
> +
> +	snd_pcm_free_chmaps(chmaps);
> +
> +	if (*found_chmap == NULL) {
> +		SNDERR("Found no matching channel map");
> +		return -EINVAL;
> +	}
> +	return 0;
> +}
> +
> +static int route_chmap_init(snd_pcm_t *pcm)
> +{
> +	int set_map = 0;
> +	snd_pcm_chmap_t *current;
> +	snd_pcm_route_t *route = pcm->private_data;
> +	if (!route->chmap)
> +		return 0;
> +	if (snd_pcm_state(pcm) != SND_PCM_STATE_PREPARED)
> +		return 0;
> +
> +	current = snd_pcm_get_chmap(route->plug.gen.slave);
> +	if (!current)
> +		return -ENOSYS;
> +	if (current->channels != route->chmap->channels)
> +		set_map = 1;
> +	else set_map = memcmp(current->pos, route->chmap->pos, current->channels);

Please fix the indentation.


Takashi


More information about the Alsa-devel mailing list