Skip to content

Tolerate USB port changes and retry missing output devices - #71

Open
mcg1969 wants to merge 1 commit into
briankendall:masterfrom
mcg1969:robust-device-matching
Open

mcg1969 wants to merge 1 commit into
briankendall:masterfrom
mcg1969:robust-device-matching

Conversation

@mcg1969

@mcg1969 mcg1969 commented May 23, 2026

Copy link
Copy Markdown
Contributor

Disclosure: Claude (Anthropic's AI coding assistant) was used in the development of this PR. The author has reviewed and tested the change.

Summary

My audio device is the digital audio output from my CalDigit Thunderbolt dock. I was finding that sometimes, when I plug my dock back in, Proxy Audio Device wasn't finding the device anymore. I expected #61 / #70 to fix that, but it didn't... And I was finding the symptom was not consistent. Sometimes it found the device, sometimes it didn't.

It turns out that the randomness was generated by me. When I plug in the dock I'm doing it by feel, and I was alternating randomly between the two USB-C ports on the left/blind side of my MBP. If I plugged it into the other port compared to the one I used to set the ProxyAudioDevice settings, that's when it lost track of the device.

This PR makes the driver more robust about retaining its target output device when the device is briefly unavailable or its UID has changed because of a USB port swap.

The problem

The driver remembers its target output device by UID, but for USB audio devices that don't expose a serial number (common in Thunderbolt docks), macOS synthesizes the UID by embedding the USB location ID:

AppleUSBAudioEngine:<vendor>:<product>:<location-id>:<stream>

Plugging the same device into a different physical port on the Mac changes the location ID, which changes the UID. The driver would fail to find the device and stay silent until the user manually re-selected it from the Settings app.

This was also a contributing factor to the issue described in PR #61: when the dock came back on a different port, the proxy audio device remained "selected" but was effectively pointing at nothing. (With the new "hide when unavailable" preference from #70 turned on, the symptom shifted from "no audio" to "Proxy Audio is missing from the system audio list".)

The fix

Two complementary changes, both in the driver:

1. Tolerant USB UID matching in findTargetOutputAudioDevice. When the exact UID match fails, a second pass looks for a device whose UID matches in every component except the location ID. Only AppleUSBAudioEngine UIDs of exactly the expected 5-component shape are eligible, so devices from the same vendor with different products won't be confused. The stored UID is intentionally not overwritten on a port-swap match — returning to the original port still just works.

2. Periodic retry when the target device can't be found. When setupTargetOutputDevice finds no match, it now schedules a retry every 5 seconds via the existing audio-output dispatch queue. The device-list listener already covers most reconnections, but sleep/wake and transient Bluetooth dropouts don't always fire it. A generation counter ensures any in-flight retry from a previous failed setup is canceled when a new setup runs.

Test plan

Tested locally on macOS 26.4 (Apple Silicon) with a CalDigit Thunderbolt 3 Dock with no USB serial number. Even though I only ever swapped between two physical USB-C ports, the dock's location ID came back as three distinct values across the testing session — further evidence that the UID can't be relied on as a stable handle for the same device:

AppleUSBAudioEngine:CalDigit, Inc.:CalDigit Thunderbolt 3 Audio:20200000:1
AppleUSBAudioEngine:CalDigit, Inc.:CalDigit Thunderbolt 3 Audio:21200000:1
AppleUSBAudioEngine:CalDigit, Inc.:CalDigit Thunderbolt 3 Audio:22200000:1
  • Build cleanly with xcodebuild -configuration Release.
  • Driver loads after install + killall coreaudiod.
  • Proxy Audio Device remains present and audible after dock is moved to a different USB-C port (audio handed off seamlessly without user intervention).
  • After dock is fully unplugged, audio falls back to another device. When dock is plugged back in, Proxy Audio reconnects automatically within a few seconds (retry path).
  • Stored UID is preserved across port-swap matches — returning to the original port works without re-selection.

Notes

  • Behavior is unchanged for devices whose UIDs are stable across reconnections (devices with serial numbers, non-USB devices, etc.).
  • No change to the settings app.
  • No change to user-facing preferences.

🤖 Generated with Claude Code

The driver remembered its target output device by UID. For USB audio
devices without a serial number (common in Thunderbolt docks), macOS
embeds the USB location ID into the synthesized UID, which means
plugging into a different port produces a different UID. The driver
would fail to find the device and stay silent until the user manually
re-selected it.

Two changes:

* findTargetOutputAudioDevice now does a tolerant fallback pass. If no
  exact UID match is found, it looks for a UID that matches in every
  field except the USB location ID (the format is
  AppleUSBAudioEngine:<vendor>:<product>:<location>:<stream>). The
  stored UID is intentionally not overwritten, so returning to the
  original port still just works.

* When setupTargetOutputDevice can't find the device at all, it now
  schedules a retry every 5 seconds. The device-list listener already
  covers most reconnections, but sleep/wake and transient Bluetooth
  dropouts don't always fire it. A generation counter ensures any
  in-flight retry from a previous failed setup is canceled when a new
  setup runs.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@mcg1969
mcg1969 marked this pull request as ready for review May 23, 2026 20:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant