Skip to content

HDMI playback volume jumps and hissing during Teams mute/unmute #9

Description

@Rayn0r

Hi,

I’m using macOS 26.6.2 and installed SoundBridge v1.1.2 today. I noticed the following issue while using Microsoft Teams.

During a Teams call, I also have music playing in the background through the speakers of my Lenovo display. Every time I mute or unmute my microphone in Teams, the playback volume through the display speakers suddenly increases significantly.

The behavior is especially noticeable at very low volume levels. For example, if the SoundBridge volume slider is at the lowest position where music is still audible:

  • Muting or unmuting in Teams makes the display speakers suddenly much louder.
  • Pressing Volume Down then mutes the output completely.
  • Pressing Volume Up instead makes it only slightly louder than the intended low level.
  • Every mute/unmute action is accompanied by a short but harsh hissing sound.

The same behavior can be reproduced in iTerm by triggering the terminal bell:

printf '\a'

Pressing Tab in iTerm, when it produces the terminal bell, causes the same volume jump and hissing. This suggests that the issue is related to short-lived CoreAudio activity rather than being specific to Teams microphone muting.

Setup:

  • macOS 26.6.2
  • SoundBridge v1.1.2
  • Microsoft Teams
  • Music playing through the Lenovo display speakers
  • Yealink BH76 Plus headset connected via its USB dongle
  • Headset used for the Teams call

Steps to reproduce:

  1. Start playing music through the display speakers.

  2. Join a Teams call using the Yealink headset.

  3. Set the SoundBridge playback volume to a very low level where music is still audible.

  4. Mute or unmute the microphone in Teams.

  5. Observe that the display speakers suddenly become much louder.

  6. Listen for the short, harsh hissing sound.

  7. Press Volume Down. The output becomes muted.

  8. Alternatively, press Volume Up. The output becomes only slightly louder than the intended low level.

  9. In iTerm, run:

    printf '\a'
    
  10. Press Tab in iTerm to trigger the terminal bell.

  11. Observe the same volume jump and hissing.

Likely cause:

The host renderer applies the SoundBridge proxy volume and mute state as software gain. ProxyDeviceManager also writes the same volume and mute state to the physical output device.

This creates two separate volume and mute paths:

  1. Software gain in the host renderer.
  2. Physical-device volume and mute changes through CoreAudio.

During short-lived CoreAudio activity, these paths can apply different transitions. This can cause the effective output volume to change independently of the SoundBridge slider and can produce an audible transient.

The following patch removes the duplicate physical-device volume and mute writes. The proxy state is still read and persisted, while playback volume and mute are handled by the renderer as software gain.

Complete patch:

diff --git a/packages/driver/install.sh b/packages/driver/install.sh
index 569b92f..d7bd09b 100755
--- a/packages/driver/install.sh
+++ b/packages/driver/install.sh
@@ -3,7 +3,8 @@
 
 set -e
 
-DRIVER_PATH="./build/SoundBridgeDriver.driver"
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+DRIVER_PATH="$SCRIPT_DIR/build/SoundBridgeDriver.driver"
 INSTALL_PATH="/Library/Audio/Plug-Ins/HAL/SoundBridgeDriver.driver"
 
 echo "SoundBridge HAL Driver Installer"
diff --git a/packages/host/README.md b/packages/host/README.md
index 5aa6d06..87af89b 100644
--- a/packages/host/README.md
+++ b/packages/host/README.md
@@ -12,7 +12,7 @@ It discovers physical output devices, creates shared memory endpoints for the HA
 - Writes the driver control file (`/tmp/soundbridge-devices.txt`)
 - Starts heartbeat updates for driver/host health signaling
 - Starts a CoreAudio HAL output unit and renders `ring buffer -> DSP -> hardware`
-- Auto-switches system output to the matching proxy device and forwards proxy volume/mute to the physical device
+- Auto-switches system output to the matching proxy device; proxy volume/mute is applied by the renderer as software gain
 - Monitors device list/default output changes and sleep/wake recovery hooks
 
 ## Architecture
diff --git a/packages/host/Sources/SoundBridgeHost/Devices/ProxyDeviceManager.swift b/packages/host/Sources/SoundBridgeHost/Devices/ProxyDeviceManager.swift
index 12ec32d..c6d771f 100644
--- a/packages/host/Sources/SoundBridgeHost/Devices/ProxyDeviceManager.swift
+++ b/packages/host/Sources/SoundBridgeHost/Devices/ProxyDeviceManager.swift
@@ -642,9 +642,7 @@ class ProxyDeviceManager {
 
     private func forwardProxyMuteToPhysical(proxyDeviceID: AudioDeviceID, physicalDeviceID: AudioDeviceID) {
         guard let muted = getDeviceMute(proxyDeviceID) else { return }
-        _ = setDeviceMute(physicalDeviceID, muted: muted)
 
-        // Persist mute state for the physical device
         if let physicalUID = activeProxyUID {
             let volume = getDeviceVolume(proxyDeviceID) ?? VolumePersistence.defaultVolume
             volumePersistence.save(uid: physicalUID, volume: volume, muted: muted)
@@ -766,9 +764,7 @@ class ProxyDeviceManager {
         }
 
         lastForwardedProxyVolume = proxyVolume
-        _ = setDeviceVolume(physicalDeviceID, volume: proxyVolume)
 
-        // Persist volume state for the physical device
         if let physicalUID = activeProxyUID {
             let muted = getDeviceMute(proxyDeviceID) ?? false
             volumePersistence.save(uid: physicalUID, volume: proxyVolume, muted: muted)

Testing performed:

  1. Built the DSP library, HAL driver, host, and menu bar app.

  2. Created a universal application bundle.

  3. Installed the rebuilt driver.

  4. Restarted CoreAudio.

  5. Played music through the Lenovo display speakers.

  6. Tested Teams microphone mute and unmute.

  7. Tested the iTerm terminal bell using:

    printf '\a'
    
  8. Tested the Tab key in iTerm.

  9. Tested the behavior at a very low SoundBridge volume level.

  10. Tested the behavior for several hours.

Result:

After applying the patch, the volume jumps and hissing during Teams mute/unmute and iTerm terminal-bell events no longer occurred in testing.

Build commands:

cd /Users/andreweidemann/repos/SoundBridge
git submodule update --init --recursive
make build

Install the rebuilt driver:

cd /Users/andreweidemann/repos/SoundBridge
./packages/driver/install.sh
sudo killall coreaudiod
open dist/SoundBridge.app

The resulting application bundle is:

/Users/andreweidemann/repos/SoundBridge/dist/SoundBridge.app

The application and driver were built as universal binaries for:

arm64
x86_64

Important:

The driver must be rebuilt and installed before testing. Opening the application bundle alone does not replace the driver installed in:

/Library/Audio/Plug-Ins/HAL/SoundBridgeDriver.driver

Thanks.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions