[alsa-devel] [PATCH 0/3] ALSA: usb channel map fixes
Ok, so I actually tested my patch, and it turned out things were slightly more complex than expected - the original patch is still needed, but in addition, we also need to build the channel map after the format parse, because the format of the descriptor is not always the same as the format of the input terminal. These two fixes made the mono chmap show up on my logitech USB headset, on both output and input side.
I also tested my patches with another USB device. This device is UAC2, and when looking at lsusb I found that in UAC2 the streaming descriptor has a channel config too. Given what I found on the headset, it seems reasonable to use this channel config instead of the input terminal's channel config, although in my case it made no practical difference.
David Henningsson (3): ALSA: usb: supply channel maps even when wChannelConfig is unspecified ALSA: usb - For class 2 devices, use channel map from altsettings ALSA: usb - Don't trust the channel config if the channel count changed
sound/usb/stream.c | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-)
If wChannelconfig is given for some formats but not others, userspace might not be able to set the channel map.
This is RFC because I'm not sure what the best behaviour is - to guess the channel map from the given number of channels (it's quite likely that one channel is MONO and two channels is FL FR), or just to supply UNKNOWN for all channels.
But the complete lack of channel map for a format leads userspace to believe that the format is not available at all. Or am I misunderstanding how this should be used?
Signed-off-by: David Henningsson david.henningsson@canonical.com --- sound/usb/stream.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-)
diff --git a/sound/usb/stream.c b/sound/usb/stream.c index c4339f9..b43b6ee 100644 --- a/sound/usb/stream.c +++ b/sound/usb/stream.c @@ -281,8 +281,6 @@ static struct snd_pcm_chmap_elem *convert_chmap(int channels, unsigned int bits, const unsigned int *maps; int c;
- if (!bits) - return NULL; if (channels > ARRAY_SIZE(chmap->map)) return NULL;
@@ -293,9 +291,19 @@ static struct snd_pcm_chmap_elem *convert_chmap(int channels, unsigned int bits, maps = protocol == UAC_VERSION_2 ? uac2_maps : uac1_maps; chmap->channels = channels; c = 0; - for (; bits && *maps; maps++, bits >>= 1) { - if (bits & 1) - chmap->map[c++] = *maps; + + if (bits) { + for (; bits && *maps; maps++, bits >>= 1) + if (bits & 1) + chmap->map[c++] = *maps; + } else { + /* If we're missing wChannelConfig, then guess something + to make sure the channel map is not skipped entirely */ + if (channels == 1) + chmap->map[c++] = SNDRV_CHMAP_MONO; + else + for (; c < channels && *maps; maps++) + chmap->map[c++] = *maps; }
for (; c < channels; c++)
The channel config from the streaming descriptor is probably a better indicator of the channel map than the input terminal. Use the input terminal's channel map as fallback only.
Signed-off-by: David Henningsson david.henningsson@canonical.com --- sound/usb/stream.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/sound/usb/stream.c b/sound/usb/stream.c index b43b6ee..badd1d6d 100644 --- a/sound/usb/stream.c +++ b/sound/usb/stream.c @@ -587,6 +587,7 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no)
num_channels = as->bNrChannels; format = le32_to_cpu(as->bmFormats); + chconfig = le32_to_cpu(as->bmChannelConfig);
/* lookup the terminal associated to this interface * to extract the clock */ @@ -594,7 +595,8 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no) as->bTerminalLink); if (input_term) { clock = input_term->bCSourceID; - chconfig = le32_to_cpu(input_term->bmChannelConfig); + if (!chconfig && (num_channels == input_term->bNrChannels)) + chconfig = le32_to_cpu(input_term->bmChannelConfig); break; }
In case the channel count of the input terminal is not the same as the channel count of the streaming descriptor, the channel config of the input terminal can not be trusted. Instead fall back to a default (guessed) channel map.
This was found on a Logitech USB Headset.
Signed-off-by: David Henningsson david.henningsson@canonical.com --- sound/usb/stream.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/sound/usb/stream.c b/sound/usb/stream.c index badd1d6d..d737d0e 100644 --- a/sound/usb/stream.c +++ b/sound/usb/stream.c @@ -662,7 +662,6 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no) * (fp->maxpacksize & 0x7ff); fp->attributes = parse_uac_endpoint_attributes(chip, alts, protocol, iface_no); fp->clock = clock; - fp->chmap = convert_chmap(num_channels, chconfig, protocol);
/* some quirks for attributes here */
@@ -698,12 +697,16 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no) /* ok, let's parse further... */ if (snd_usb_parse_audio_format(chip, fp, format, fmt, stream) < 0) { kfree(fp->rate_table); - kfree(fp->chmap); kfree(fp); fp = NULL; continue; }
+ /* Create chmap */ + if (fp->channels != num_channels) + chconfig = 0; + fp->chmap = convert_chmap(fp->channels, chconfig, protocol); + snd_printdd(KERN_INFO "%d:%u:%d: add audio endpoint %#x\n", dev->devnum, iface_no, altno, fp->endpoint); err = snd_usb_add_audio_stream(chip, stream, fp); if (err < 0) {
At Tue, 5 Nov 2013 04:41:05 +0100, David Henningsson wrote:
Ok, so I actually tested my patch, and it turned out things were slightly more complex than expected - the original patch is still needed, but in addition, we also need to build the channel map after the format parse, because the format of the descriptor is not always the same as the format of the input terminal. These two fixes made the mono chmap show up on my logitech USB headset, on both output and input side.
I also tested my patches with another USB device. This device is UAC2, and when looking at lsusb I found that in UAC2 the streaming descriptor has a channel config too. Given what I found on the headset, it seems reasonable to use this channel config instead of the input terminal's channel config, although in my case it made no practical difference.
David Henningsson (3): ALSA: usb: supply channel maps even when wChannelConfig is unspecified ALSA: usb - For class 2 devices, use channel map from altsettings ALSA: usb - Don't trust the channel config if the channel count changed
Thanks, applied all patches now.
Takashi
sound/usb/stream.c | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-)
-- 1.7.9.5
participants (2)
-
David Henningsson
-
Takashi Iwai