git: f01b594b7fa5 - main - snd_uaudio: recognize hardware sidetone as a monitor

From: Kyle Evans <kevans_at_FreeBSD.org>
Date: Wed, 26 Aug 2026 14:32:14 UTC
The branch main has been updated by kevans:

URL: https://cgit.FreeBSD.org/src/commit/?id=f01b594b7fa5cac4328f7137fb9cb0eef7ffd040

commit f01b594b7fa5cac4328f7137fb9cb0eef7ffd040
Author:     Kyle Evans <kevans@FreeBSD.org>
AuthorDate: 2026-08-26 14:31:57 +0000
Commit:     Kyle Evans <kevans@FreeBSD.org>
CommitDate: 2026-08-26 14:31:57 +0000

    snd_uaudio: recognize hardware sidetone as a monitor
    
    The Logitech H390, for instance, has the following interface layout:
    
    ~~
    7 INPUT              34 INPUT            10 INPUT
      Mic (0x201)          Mic (0x201)         USB Stream (0x101)
       |                    |                     |
       v                    v                     |
     19 FEATURE           35 FEATURE              |
       |                    |                     |
       v                    v                     |
     25 EXTENSION           +------> 36 MIXER <---+
       |                              |
       v                              v
     13 OUTPUT                     22 FEATURE
     USB Stream (0x101)               |
                                      v
                                   16 OUTPUT
                                   Speaker (0x301)
    ~~
    
    The 7->13 path on the left is a typical microphone-in configuration,
    while the right side is a little more complicated. The 34 -> 35 -> 36
    leg is describing a hardware sidetone control, while the other is a
    standard audio-out configuration.
    
    During feature unit evaluation, we need to pick up the scenario of node
    35 above, which is directly wiring the microphone to the speaker.  Right
    now we'll likely tie it to the pcm/vol levels and this unit will emit
    a very prompt feedback screech, but it's really shaped more like a
    MONITOR control.
    
    This avoids mishandling feature unit 22 because that's evaluated in one
    of the other cases: one of the inputs is the USB stream, so it's
    wired up as a PCM.
    
    One note on this headset: the presence of mixer 36 currently breaks the
    `vol` control, leaving only `pcm` to control the volume.  Given that it
    has both Mic and USB input, I suspect we get a 1:1 cluster configuration
    for the Mic input but something more complicated for the USB input that
    we end up ignoring.  Thus, "vol" might technically control the monitor
    volume but isn't wired up to the USB input cluster.  I have not had a
    chance to confirm this, yet.
    
    PR:             291424
    Reviewed by:    christos
    Differential Revision:  https://reviews.freebsd.org/D58779
---
 sys/dev/sound/usb/uaudio.c | 22 ++++++++++++++++++++--
 1 file changed, 20 insertions(+), 2 deletions(-)

diff --git a/sys/dev/sound/usb/uaudio.c b/sys/dev/sound/usb/uaudio.c
index f12fc1ede541..2e0f670ddc28 100644
--- a/sys/dev/sound/usb/uaudio.c
+++ b/sys/dev/sound/usb/uaudio.c
@@ -4688,7 +4688,16 @@ uaudio_mixer_determine_class(const struct uaudio_terminal_node *iot)
 
 	switch (match) {
 	case 0:	/* not connected to USB */
-		if (terminal_type_output != 0) {
+		/*
+		 * Some devices have a hardware sidetone that will show up here
+		 * as connecting the microphone to the speaker.  If we look at
+		 * the output first, then we are more likely to get a PCM type
+		 * and accidentally tie it to playback when we really should
+		 * treat it as a monitor control.
+		 */
+		if (terminal_type_input != 0 && terminal_type_output != 0) {
+			return (SOUND_MIXER_MONITOR);
+		} else if (terminal_type_output != 0) {
 			return (uaudio_mixer_get_feature_by_tt(
 			    terminal_type_output, SOUND_MIXER_MONITOR));
 		} else {
@@ -4747,7 +4756,16 @@ uaudio20_mixer_determine_class(const struct uaudio_terminal_node *iot)
 
 	switch (match) {
 	case 0:	/* not connected to USB */
-		if (terminal_type_output != 0) {
+		/*
+		 * Some devices have a hardware sidetone that will show up here
+		 * as connecting the microphone to the speaker.  If we look at
+		 * the output first, then we are more likely to get a PCM type
+		 * and accidentally tie it to playback when we really should
+		 * treat it as a monitor control.
+		 */
+		if (terminal_type_input != 0 && terminal_type_output != 0) {
+			return (SOUND_MIXER_MONITOR);
+		} else if (terminal_type_output != 0) {
 			return (uaudio_mixer_get_feature_by_tt(
 			    terminal_type_output, SOUND_MIXER_MONITOR));
 		} else {