pcm: add chmap option to route plugin

Add a config definition "chmap" to override the channel maps in the same
way as in the hw and null plugins.

Signed-off-by: Jonas Holmberg <jonashg@axis.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
Jonas Holmberg 2020-03-31 17:09:25 +02:00 committed by Takashi Iwai
parent bca39e99d0
commit 3b46b03f09

View file

@ -104,6 +104,7 @@ typedef struct {
int schannels; int schannels;
snd_pcm_route_params_t params; snd_pcm_route_params_t params;
snd_pcm_chmap_t *chmap; snd_pcm_chmap_t *chmap;
snd_pcm_chmap_query_t **chmap_override;
} snd_pcm_route_t; } snd_pcm_route_t;
#endif /* DOC_HIDDEN */ #endif /* DOC_HIDDEN */
@ -441,6 +442,7 @@ static int snd_pcm_route_close(snd_pcm_t *pcm)
free(params->dsts); free(params->dsts);
} }
free(route->chmap); free(route->chmap);
snd_pcm_free_chmaps(route->chmap_override);
return snd_pcm_generic_close(pcm); return snd_pcm_generic_close(pcm);
} }
@ -634,6 +636,9 @@ static snd_pcm_chmap_t *snd_pcm_route_get_chmap(snd_pcm_t *pcm)
snd_pcm_chmap_t *map, *slave_map; snd_pcm_chmap_t *map, *slave_map;
unsigned int src, dst, nsrcs; unsigned int src, dst, nsrcs;
if (route->chmap_override)
return _snd_pcm_choose_fixed_chmap(pcm, route->chmap_override);
slave_map = snd_pcm_generic_get_chmap(pcm); slave_map = snd_pcm_generic_get_chmap(pcm);
if (!slave_map) if (!slave_map)
return NULL; return NULL;
@ -660,8 +665,14 @@ static snd_pcm_chmap_t *snd_pcm_route_get_chmap(snd_pcm_t *pcm)
static snd_pcm_chmap_query_t **snd_pcm_route_query_chmaps(snd_pcm_t *pcm) static snd_pcm_chmap_query_t **snd_pcm_route_query_chmaps(snd_pcm_t *pcm)
{ {
snd_pcm_route_t *route = pcm->private_data;
snd_pcm_chmap_query_t **maps; snd_pcm_chmap_query_t **maps;
snd_pcm_chmap_t *map = snd_pcm_route_get_chmap(pcm); snd_pcm_chmap_t *map;
if (route->chmap_override)
return _snd_pcm_copy_chmap_query(route->chmap_override);
map = snd_pcm_route_get_chmap(pcm);
if (!map) if (!map)
return NULL; return NULL;
maps = _snd_pcm_make_single_query_chmaps(map); maps = _snd_pcm_make_single_query_chmaps(map);
@ -818,10 +829,10 @@ err:
return -EINVAL; return -EINVAL;
} }
static int find_matching_chmap(snd_pcm_t *spcm, snd_pcm_chmap_t *tt_chmap, static int find_matching_chmap(snd_pcm_chmap_query_t **chmaps,
snd_pcm_chmap_t *tt_chmap,
snd_pcm_chmap_t **found_chmap, int *schannels) snd_pcm_chmap_t **found_chmap, int *schannels)
{ {
snd_pcm_chmap_query_t** chmaps = snd_pcm_query_chmaps(spcm);
int i; int i;
*found_chmap = NULL; *found_chmap = NULL;
@ -854,7 +865,6 @@ static int find_matching_chmap(snd_pcm_t *spcm, snd_pcm_chmap_t *tt_chmap,
int size = sizeof(snd_pcm_chmap_t) + c->channels * sizeof(unsigned int); int size = sizeof(snd_pcm_chmap_t) + c->channels * sizeof(unsigned int);
*found_chmap = malloc(size); *found_chmap = malloc(size);
if (!*found_chmap) { if (!*found_chmap) {
snd_pcm_free_chmaps(chmaps);
return -ENOMEM; return -ENOMEM;
} }
memcpy(*found_chmap, c, size); memcpy(*found_chmap, c, size);
@ -863,8 +873,6 @@ static int find_matching_chmap(snd_pcm_t *spcm, snd_pcm_chmap_t *tt_chmap,
} }
} }
snd_pcm_free_chmaps(chmaps);
if (*found_chmap == NULL) { if (*found_chmap == NULL) {
SNDERR("Found no matching channel map"); SNDERR("Found no matching channel map");
return -EINVAL; return -EINVAL;
@ -1252,6 +1260,7 @@ pcm.name {
SCHANNEL REAL # route value (0.0 - 1.0) SCHANNEL REAL # route value (0.0 - 1.0)
} }
} }
[chmap MAP] # Override channel maps; MAP is a string array
} }
\endcode \endcode
@ -1292,6 +1301,7 @@ int _snd_pcm_route_open(snd_pcm_t **pcmp, const char *name,
snd_pcm_route_ttable_entry_t *ttable = NULL; snd_pcm_route_ttable_entry_t *ttable = NULL;
unsigned int csize, ssize; unsigned int csize, ssize;
unsigned int cused, sused; unsigned int cused, sused;
snd_pcm_chmap_query_t **chmaps = NULL;
snd_config_for_each(i, next, conf) { snd_config_for_each(i, next, conf) {
snd_config_t *n = snd_config_iterator_entry(i); snd_config_t *n = snd_config_iterator_entry(i);
const char *id; const char *id;
@ -1306,31 +1316,45 @@ int _snd_pcm_route_open(snd_pcm_t **pcmp, const char *name,
if (strcmp(id, "ttable") == 0) { if (strcmp(id, "ttable") == 0) {
if (snd_config_get_type(n) != SND_CONFIG_TYPE_COMPOUND) { if (snd_config_get_type(n) != SND_CONFIG_TYPE_COMPOUND) {
SNDERR("Invalid type for %s", id); SNDERR("Invalid type for %s", id);
snd_pcm_free_chmaps(chmaps);
return -EINVAL; return -EINVAL;
} }
tt = n; tt = n;
continue; continue;
} }
if (strcmp(id, "chmap") == 0) {
chmaps = _snd_pcm_parse_config_chmaps(n);
if (!chmaps) {
SNDERR("Invalid channel map for %s", id);
return -EINVAL;
}
continue;
}
SNDERR("Unknown field %s", id); SNDERR("Unknown field %s", id);
return -EINVAL; return -EINVAL;
} }
if (!slave) { if (!slave) {
SNDERR("slave is not defined"); SNDERR("slave is not defined");
snd_pcm_free_chmaps(chmaps);
return -EINVAL; return -EINVAL;
} }
if (!tt) { if (!tt) {
SNDERR("ttable is not defined"); SNDERR("ttable is not defined");
snd_pcm_free_chmaps(chmaps);
return -EINVAL; return -EINVAL;
} }
err = snd_pcm_slave_conf(root, slave, &sconf, 2, err = snd_pcm_slave_conf(root, slave, &sconf, 2,
SND_PCM_HW_PARAM_FORMAT, 0, &sformat, SND_PCM_HW_PARAM_FORMAT, 0, &sformat,
SND_PCM_HW_PARAM_CHANNELS, 0, &schannels); SND_PCM_HW_PARAM_CHANNELS, 0, &schannels);
if (err < 0) if (err < 0) {
snd_pcm_free_chmaps(chmaps);
return err; return err;
}
if (sformat != SND_PCM_FORMAT_UNKNOWN && if (sformat != SND_PCM_FORMAT_UNKNOWN &&
snd_pcm_format_linear(sformat) != 1) { snd_pcm_format_linear(sformat) != 1) {
snd_config_delete(sconf); snd_config_delete(sconf);
SNDERR("slave format is not linear"); SNDERR("slave format is not linear");
snd_pcm_free_chmaps(chmaps);
return -EINVAL; return -EINVAL;
} }
@ -1345,13 +1369,19 @@ int _snd_pcm_route_open(snd_pcm_t **pcmp, const char *name,
if (err < 0) { if (err < 0) {
free(tt_chmap); free(tt_chmap);
free(ttable); free(ttable);
snd_pcm_free_chmaps(chmaps);
return err; return err;
} }
if (tt_chmap) { if (tt_chmap) {
err = find_matching_chmap(spcm, tt_chmap, &chmap, &schannels); if (!chmaps)
chmaps = snd_pcm_query_chmaps(spcm);
if (chmaps)
err = find_matching_chmap(chmaps, tt_chmap, &chmap,
&schannels);
free(tt_chmap); free(tt_chmap);
if (err < 0) { if (chmaps && err < 0) {
snd_pcm_free_chmaps(chmaps);
snd_pcm_close(spcm); snd_pcm_close(spcm);
return err; return err;
} }
@ -1360,12 +1390,14 @@ int _snd_pcm_route_open(snd_pcm_t **pcmp, const char *name,
err = _snd_pcm_route_determine_ttable(tt, &csize, &ssize, chmap); err = _snd_pcm_route_determine_ttable(tt, &csize, &ssize, chmap);
if (err < 0) { if (err < 0) {
free(chmap); free(chmap);
snd_pcm_free_chmaps(chmaps);
snd_pcm_close(spcm); snd_pcm_close(spcm);
return err; return err;
} }
ttable = malloc(csize * ssize * sizeof(snd_pcm_route_ttable_entry_t)); ttable = malloc(csize * ssize * sizeof(snd_pcm_route_ttable_entry_t));
if (ttable == NULL) { if (ttable == NULL) {
free(chmap); free(chmap);
snd_pcm_free_chmaps(chmaps);
snd_pcm_close(spcm); snd_pcm_close(spcm);
return -ENOMEM; return -ENOMEM;
} }
@ -1374,6 +1406,7 @@ int _snd_pcm_route_open(snd_pcm_t **pcmp, const char *name,
if (err < 0) { if (err < 0) {
free(chmap); free(chmap);
free(ttable); free(ttable);
snd_pcm_free_chmaps(chmaps);
snd_pcm_close(spcm); snd_pcm_close(spcm);
return err; return err;
} }
@ -1385,9 +1418,13 @@ int _snd_pcm_route_open(snd_pcm_t **pcmp, const char *name,
free(ttable); free(ttable);
if (err < 0) { if (err < 0) {
free(chmap); free(chmap);
snd_pcm_free_chmaps(chmaps);
snd_pcm_close(spcm); snd_pcm_close(spcm);
} else { } else {
((snd_pcm_route_t*) (*pcmp)->private_data)->chmap = chmap; snd_pcm_route_t *route = (*pcmp)->private_data;
route->chmap = chmap;
route->chmap_override = chmaps;
} }
return err; return err;