* [PATCH 0/3] alsa-lib - improve surround 2.1 support
@ 2014-02-21 15:24 David Henningsson
2014-02-21 15:24 ` [PATCH 1/3] route: Allow chmap syntax for slave channels in ttable David Henningsson
` (3 more replies)
0 siblings, 4 replies; 7+ messages in thread
From: David Henningsson @ 2014-02-21 15:24 UTC (permalink / raw)
To: tiwai, alsa-devel; +Cc: David Henningsson
So, in order to support 2.1 surround on both 4-channels (e g FL FR LFE LFE,
on internal subwoofer) and 6-channels (e g FL FR RL RR C LFE, on desktops
with 5.1 out), I needed to make the route plugin more chmap aware.
This also included allowing a new syntax for the ttable, which I think is
quite nice. The new syntax also falls back to ALSAs standard chmap in case
the hardware does not support it.
David Henningsson (3):
route: Allow chmap syntax for slave channels in ttable
route: Select slave chmap based on ttable information
conf: Allow 2.1 surround to use different number of channels
src/conf/pcm/surround21.conf | 7 +-
src/pcm/pcm_route.c | 304 ++++++++++++++++++++++++++++++++++++++-----
2 files changed, 271 insertions(+), 40 deletions(-)
--
1.9.0
^ permalink raw reply [flat|nested] 7+ messages in thread* [PATCH 1/3] route: Allow chmap syntax for slave channels in ttable 2014-02-21 15:24 [PATCH 0/3] alsa-lib - improve surround 2.1 support David Henningsson @ 2014-02-21 15:24 ` David Henningsson 2014-02-21 15:42 ` Takashi Iwai 2014-02-21 15:24 ` [PATCH 2/3] route: Select slave chmap based on ttable information David Henningsson ` (2 subsequent siblings) 3 siblings, 1 reply; 7+ messages in thread From: David Henningsson @ 2014-02-21 15:24 UTC (permalink / raw) To: tiwai, alsa-devel; +Cc: David Henningsson Instead of writing e g "0" and "1", one can now write "FL" and "FR" instead. E g: ttable.0.FL 1 ttable.1.FR 1 ttable.2.LFE 1 Signed-off-by: David Henningsson <david.henningsson@canonical.com> --- src/pcm/pcm_route.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/src/pcm/pcm_route.c b/src/pcm/pcm_route.c index 2beedf6..ffc283f 100644 --- a/src/pcm/pcm_route.c +++ b/src/pcm/pcm_route.c @@ -789,6 +789,24 @@ 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) +{ + int err; + int ch; + err = safe_strtol(id, channel); + if (err >= 0) + return err; + + ch = (int) snd_pcm_chmap_from_string(id); + if (ch == -1) + return -EINVAL; + + /* For now, assume standard channel mapping */ + *channel = ch - SND_CHMAP_FL; + return 0; +} + + static const snd_pcm_ops_t snd_pcm_route_ops = { .close = snd_pcm_route_close, .info = snd_pcm_generic_info, @@ -983,7 +1001,7 @@ int snd_pcm_route_determine_ttable(snd_config_t *tt, const char *id; if (snd_config_get_id(jnode, &id) < 0) continue; - err = safe_strtol(id, &schannel); + err = safe_chmapchannel(id, &schannel); if (err < 0) { SNDERR("Invalid slave channel: %s", id); return -EINVAL; @@ -1046,7 +1064,7 @@ int snd_pcm_route_load_ttable(snd_config_t *tt, snd_pcm_route_ttable_entry_t *tt const char *id; if (snd_config_get_id(jnode, &id) < 0) continue; - err = safe_strtol(id, &schannel); + err = safe_chmapchannel(id, &schannel); if (err < 0 || schannel < 0 || (unsigned int) schannel > tt_ssize || (schannels > 0 && schannel >= schannels)) { -- 1.9.0 ^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH 1/3] route: Allow chmap syntax for slave channels in ttable 2014-02-21 15:24 ` [PATCH 1/3] route: Allow chmap syntax for slave channels in ttable David Henningsson @ 2014-02-21 15:42 ` Takashi Iwai 0 siblings, 0 replies; 7+ messages in thread From: Takashi Iwai @ 2014-02-21 15:42 UTC (permalink / raw) To: David Henningsson; +Cc: alsa-devel At Fri, 21 Feb 2014 16:24:20 +0100, David Henningsson wrote: > > Instead of writing e g "0" and "1", one can now write "FL" and "FR" instead. > > E g: > ttable.0.FL 1 > ttable.1.FR 1 > ttable.2.LFE 1 > > Signed-off-by: David Henningsson <david.henningsson@canonical.com> > --- > src/pcm/pcm_route.c | 22 ++++++++++++++++++++-- > 1 file changed, 20 insertions(+), 2 deletions(-) > > diff --git a/src/pcm/pcm_route.c b/src/pcm/pcm_route.c > index 2beedf6..ffc283f 100644 > --- a/src/pcm/pcm_route.c > +++ b/src/pcm/pcm_route.c > @@ -789,6 +789,24 @@ 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) You need no safe_ prefix for this function. safe_strtol() is just because strtol() already exists in an unsafe way. Besides that, I find it also OK to just return the channel (>= 0) or a negative error. But it's no big matter in which form is. Takashi > +{ > + int err; > + int ch; > + err = safe_strtol(id, channel); > + if (err >= 0) > + return err; > + > + ch = (int) snd_pcm_chmap_from_string(id); > + if (ch == -1) > + return -EINVAL; > + > + /* For now, assume standard channel mapping */ > + *channel = ch - SND_CHMAP_FL; > + return 0; > +} > + > + > static const snd_pcm_ops_t snd_pcm_route_ops = { > .close = snd_pcm_route_close, > .info = snd_pcm_generic_info, > @@ -983,7 +1001,7 @@ int snd_pcm_route_determine_ttable(snd_config_t *tt, > const char *id; > if (snd_config_get_id(jnode, &id) < 0) > continue; > - err = safe_strtol(id, &schannel); > + err = safe_chmapchannel(id, &schannel); > if (err < 0) { > SNDERR("Invalid slave channel: %s", id); > return -EINVAL; > @@ -1046,7 +1064,7 @@ int snd_pcm_route_load_ttable(snd_config_t *tt, snd_pcm_route_ttable_entry_t *tt > const char *id; > if (snd_config_get_id(jnode, &id) < 0) > continue; > - err = safe_strtol(id, &schannel); > + err = safe_chmapchannel(id, &schannel); > if (err < 0 || > schannel < 0 || (unsigned int) schannel > tt_ssize || > (schannels > 0 && schannel >= schannels)) { > -- > 1.9.0 > ^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH 2/3] route: Select slave chmap based on ttable information 2014-02-21 15:24 [PATCH 0/3] alsa-lib - improve surround 2.1 support David Henningsson 2014-02-21 15:24 ` [PATCH 1/3] route: Allow chmap syntax for slave channels in ttable David Henningsson @ 2014-02-21 15:24 ` David Henningsson 2014-02-21 15:49 ` Takashi Iwai 2014-02-21 15:24 ` [PATCH 3/3] conf: Allow 2.1 surround to use different number of channels David Henningsson 2014-02-21 15:50 ` [PATCH 0/3] alsa-lib - improve surround 2.1 support Takashi Iwai 3 siblings, 1 reply; 7+ messages in thread From: David Henningsson @ 2014-02-21 15:24 UTC (permalink / raw) To: tiwai, alsa-devel; +Cc: David Henningsson 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@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) { - 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); + 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); + free(current); + if (!set_map) + return 0; + + return snd_pcm_set_chmap(route->plug.gen.slave, route->chmap); } @@ -939,6 +1088,7 @@ int snd_pcm_route_open(snd_pcm_t **pcmp, const char *name, route->plug.undo_write = snd_pcm_plugin_undo_write_generic; route->plug.gen.slave = slave; route->plug.gen.close_slave = close_slave; + route->plug.init = route_chmap_init; err = snd_pcm_new(&pcm, SND_PCM_TYPE_ROUTE, name, slave->stream, slave->mode); if (err < 0) { @@ -963,16 +1113,10 @@ int snd_pcm_route_open(snd_pcm_t **pcmp, const char *name, return 0; } -/** - * \brief Determine route matrix sizes - * \param tt Configuration root describing route matrix - * \param tt_csize Returned client size in elements - * \param tt_ssize Returned slave size in elements - * \retval zero on success otherwise a negative error code - */ -int snd_pcm_route_determine_ttable(snd_config_t *tt, - unsigned int *tt_csize, - unsigned int *tt_ssize) +static int _snd_pcm_route_determine_ttable(snd_config_t *tt, + unsigned int *tt_csize, + unsigned int *tt_ssize, + snd_pcm_chmap_t *chmap) { snd_config_iterator_t i, inext; long csize = 0, ssize = 0; @@ -1001,7 +1145,7 @@ int snd_pcm_route_determine_ttable(snd_config_t *tt, const char *id; if (snd_config_get_id(jnode, &id) < 0) continue; - err = safe_chmapchannel(id, &schannel); + err = safe_chmapchannel(id, chmap, &schannel, 1); if (err < 0) { SNDERR("Invalid slave channel: %s", id); return -EINVAL; @@ -1020,6 +1164,20 @@ int snd_pcm_route_determine_ttable(snd_config_t *tt, } /** + * \brief Determine route matrix sizes + * \param tt Configuration root describing route matrix + * \param tt_csize Returned client size in elements + * \param tt_ssize Returned slave size in elements + * \retval zero on success otherwise a negative error code + */ +int snd_pcm_route_determine_ttable(snd_config_t *tt, + unsigned int *tt_csize, + unsigned int *tt_ssize) +{ + return _snd_pcm_route_determine_ttable(tt, tt_csize, tt_ssize, NULL); +} + +/** * \brief Load route matrix * \param tt Configuration root describing route matrix * \param ttable Returned route matrix @@ -1030,10 +1188,10 @@ int snd_pcm_route_determine_ttable(snd_config_t *tt, * \param schannels Slave channels * \retval zero on success otherwise a negative error code */ -int snd_pcm_route_load_ttable(snd_config_t *tt, snd_pcm_route_ttable_entry_t *ttable, - unsigned int tt_csize, unsigned int tt_ssize, - unsigned int *tt_cused, unsigned int *tt_sused, - int schannels) +static int _snd_pcm_route_load_ttable(snd_config_t *tt, snd_pcm_route_ttable_entry_t *ttable, + unsigned int tt_csize, unsigned int tt_ssize, + unsigned int *tt_cused, unsigned int *tt_sused, + int schannels, snd_pcm_chmap_t *chmap) { int cused = -1; int sused = -1; @@ -1060,17 +1218,18 @@ int snd_pcm_route_load_ttable(snd_config_t *tt, snd_pcm_route_ttable_entry_t *tt snd_config_for_each(j, jnext, in) { snd_config_t *jnode = snd_config_iterator_entry(j); double value; - long schannel; + int ss; + long *scha = alloca(tt_ssize * sizeof(long)); const char *id; if (snd_config_get_id(jnode, &id) < 0) continue; - err = safe_chmapchannel(id, &schannel); - if (err < 0 || - schannel < 0 || (unsigned int) schannel > tt_ssize || - (schannels > 0 && schannel >= schannels)) { + + ss = safe_chmapchannel(id, chmap, scha, tt_ssize); + if (ss < 0) { SNDERR("Invalid slave channel: %s", id); return -EINVAL; } + err = snd_config_get_real(jnode, &value); if (err < 0) { long v; @@ -1081,9 +1240,18 @@ int snd_pcm_route_load_ttable(snd_config_t *tt, snd_pcm_route_ttable_entry_t *tt } value = v; } - ttable[cchannel * tt_ssize + schannel] = value; - if (schannel > sused) - sused = schannel; + + for (k = 0; (int) k < ss; k++) { + long schannel = scha[k]; + if (schannel < 0 || (unsigned int) schannel > tt_ssize || + (schannels > 0 && schannel >= schannels)) { + SNDERR("Invalid slave channel: %s", id); + return -EINVAL; + } + ttable[cchannel * tt_ssize + schannel] = value; + if (schannel > sused) + sused = schannel; + } } if (cchannel > cused) cused = cchannel; @@ -1093,6 +1261,26 @@ int snd_pcm_route_load_ttable(snd_config_t *tt, snd_pcm_route_ttable_entry_t *tt return 0; } +/** + * \brief Load route matrix + * \param tt Configuration root describing route matrix + * \param ttable Returned route matrix + * \param tt_csize Client size in elements + * \param tt_ssize Slave size in elements + * \param tt_cused Used client elements + * \param tt_sused Used slave elements + * \param schannels Slave channels + * \retval zero on success otherwise a negative error code + */ +int snd_pcm_route_load_ttable(snd_config_t *tt, snd_pcm_route_ttable_entry_t *ttable, + unsigned int tt_csize, unsigned int tt_ssize, + unsigned int *tt_cused, unsigned int *tt_sused, + int schannels) +{ + return _snd_pcm_route_load_ttable(tt, ttable, tt_csize, tt_ssize, + tt_cused, tt_sused, schannels, NULL); +} + /*! \page pcm_plugins \section pcm_plugins_route Plugin: Route & Volume @@ -1100,6 +1288,9 @@ int snd_pcm_route_load_ttable(snd_config_t *tt, snd_pcm_route_ttable_entry_t *tt This plugin converts channels and applies volume during the conversion. The format and rate must match for both of them. +SCHANNEL can be a channel name instead of a number (e g FL, LFE). +If so, a matching channel map will be selected for the slave. + \code pcm.name { type route # Route & Volume conversion PCM @@ -1150,6 +1341,7 @@ int _snd_pcm_route_open(snd_pcm_t **pcmp, const char *name, int err; snd_pcm_t *spcm; snd_config_t *slave = NULL, *sconf; + snd_pcm_chmap_t *tt_chmap, *chmap; snd_pcm_format_t sformat = SND_PCM_FORMAT_UNKNOWN; int schannels = -1; snd_config_t *tt = NULL; @@ -1198,37 +1390,59 @@ int _snd_pcm_route_open(snd_pcm_t **pcmp, const char *name, return -EINVAL; } - err = snd_pcm_route_determine_ttable(tt, &csize, &ssize); + err = determine_chmap(tt, &tt_chmap); if (err < 0) { - snd_config_delete(sconf); + free(ttable); return err; } - ttable = malloc(csize * ssize * sizeof(snd_pcm_route_ttable_entry_t)); - if (ttable == NULL) { - snd_config_delete(sconf); - return -ENOMEM; - } - err = snd_pcm_route_load_ttable(tt, ttable, csize, ssize, - &cused, &sused, schannels); + + err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf); + snd_config_delete(sconf); if (err < 0) { + free(tt_chmap); free(ttable); - snd_config_delete(sconf); return err; } - err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf); - snd_config_delete(sconf); + if (tt_chmap) { + err = find_matching_chmap(spcm, tt_chmap, &chmap, &schannels); + free(tt_chmap); + if (err < 0) + return err; + } + + err = _snd_pcm_route_determine_ttable(tt, &csize, &ssize, chmap); if (err < 0) { + free(chmap); + snd_pcm_close(spcm); + return err; + } + ttable = malloc(csize * ssize * sizeof(snd_pcm_route_ttable_entry_t)); + if (ttable == NULL) { + free(chmap); + snd_pcm_close(spcm); + return -ENOMEM; + } + err = _snd_pcm_route_load_ttable(tt, ttable, csize, ssize, + &cused, &sused, schannels, chmap); + if (err < 0) { + free(chmap); free(ttable); + snd_pcm_close(spcm); return err; } + err = snd_pcm_route_open(pcmp, name, sformat, schannels, ttable, ssize, cused, sused, spcm, 1); free(ttable); - if (err < 0) + if (err < 0) { + free(chmap); snd_pcm_close(spcm); + } + ((snd_pcm_route_t*) (*pcmp)->private_data)->chmap = chmap; + return err; } #ifndef DOC_HIDDEN -- 1.9.0 ^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH 2/3] route: Select slave chmap based on ttable information 2014-02-21 15:24 ` [PATCH 2/3] route: Select slave chmap based on ttable information David Henningsson @ 2014-02-21 15:49 ` Takashi Iwai 0 siblings, 0 replies; 7+ messages in thread From: Takashi Iwai @ 2014-02-21 15:49 UTC (permalink / raw) To: David Henningsson; +Cc: alsa-devel 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@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 ^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH 3/3] conf: Allow 2.1 surround to use different number of channels 2014-02-21 15:24 [PATCH 0/3] alsa-lib - improve surround 2.1 support David Henningsson 2014-02-21 15:24 ` [PATCH 1/3] route: Allow chmap syntax for slave channels in ttable David Henningsson 2014-02-21 15:24 ` [PATCH 2/3] route: Select slave chmap based on ttable information David Henningsson @ 2014-02-21 15:24 ` David Henningsson 2014-02-21 15:50 ` [PATCH 0/3] alsa-lib - improve surround 2.1 support Takashi Iwai 3 siblings, 0 replies; 7+ messages in thread From: David Henningsson @ 2014-02-21 15:24 UTC (permalink / raw) To: tiwai, alsa-devel; +Cc: David Henningsson This way, cards that support LFE on four channels (e g laptop with internal subwoofer) can do that, and other cards on a six channel setup can use that as well. Well, note that there is still a reference to "pcm.surround51" left here. In practice, for HDA Intel sound cards this does not matter as both surround51 and surround40 reference the same definition. (And that's the only card I currently know of that actually does surround2.1 over four channels.) Signed-off-by: David Henningsson <david.henningsson@canonical.com> --- src/conf/pcm/surround21.conf | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/conf/pcm/surround21.conf b/src/conf/pcm/surround21.conf index be29020..7f4676b 100644 --- a/src/conf/pcm/surround21.conf +++ b/src/conf/pcm/surround21.conf @@ -51,10 +51,9 @@ pcm.!surround21 { ] } } - slave.channels 6 - ttable.0.0 1 - ttable.1.1 1 - ttable.2.5 1 + ttable.0.FL 1 + ttable.1.FR 1 + ttable.2.LFE 1 hint { description "2.1 Surround output to Front and Subwoofer speakers" device $DEV -- 1.9.0 ^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH 0/3] alsa-lib - improve surround 2.1 support 2014-02-21 15:24 [PATCH 0/3] alsa-lib - improve surround 2.1 support David Henningsson ` (2 preceding siblings ...) 2014-02-21 15:24 ` [PATCH 3/3] conf: Allow 2.1 surround to use different number of channels David Henningsson @ 2014-02-21 15:50 ` Takashi Iwai 3 siblings, 0 replies; 7+ messages in thread From: Takashi Iwai @ 2014-02-21 15:50 UTC (permalink / raw) To: David Henningsson; +Cc: alsa-devel At Fri, 21 Feb 2014 16:24:19 +0100, David Henningsson wrote: > > So, in order to support 2.1 surround on both 4-channels (e g FL FR LFE LFE, > on internal subwoofer) and 6-channels (e g FL FR RL RR C LFE, on desktops > with 5.1 out), I needed to make the route plugin more chmap aware. > > This also included allowing a new syntax for the ttable, which I think is > quite nice. The new syntax also falls back to ALSAs standard chmap in case > the hardware does not support it. The idea looks great, a nice improvement. Spotted a few trivial things I posted individually, but in general it's in a good shape. thanks, Takashi > > David Henningsson (3): > route: Allow chmap syntax for slave channels in ttable > route: Select slave chmap based on ttable information > conf: Allow 2.1 surround to use different number of channels > > src/conf/pcm/surround21.conf | 7 +- > src/pcm/pcm_route.c | 304 ++++++++++++++++++++++++++++++++++++++----- > 2 files changed, 271 insertions(+), 40 deletions(-) > > -- > 1.9.0 > ^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2014-02-21 15:51 UTC | newest] Thread overview: 7+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2014-02-21 15:24 [PATCH 0/3] alsa-lib - improve surround 2.1 support David Henningsson 2014-02-21 15:24 ` [PATCH 1/3] route: Allow chmap syntax for slave channels in ttable David Henningsson 2014-02-21 15:42 ` Takashi Iwai 2014-02-21 15:24 ` [PATCH 2/3] route: Select slave chmap based on ttable information David Henningsson 2014-02-21 15:49 ` Takashi Iwai 2014-02-21 15:24 ` [PATCH 3/3] conf: Allow 2.1 surround to use different number of channels David Henningsson 2014-02-21 15:50 ` [PATCH 0/3] alsa-lib - improve surround 2.1 support Takashi Iwai
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox