From 0bcce066058940fdf028ae259bc5da2df5fe8970 Mon Sep 17 00:00:00 2001 From: ChrisBeWithYou Date: Tue, 7 Jul 2026 23:59:12 -0500 Subject: [PATCH] fix(audio): probe same-endpoint duplex the same way apply routes it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Startup auto-apply (renderer init) fail-closes on probeDeviceOptionsDual's `compatible` verdict, but the probe still measured a COMBINED duplex device for any same-backend pair while setAudioDevices now opens split for different endpoints. That mismatch made the startup probe describe a config that isn't the one applied — surfacing as "no audio until I press Apply" for a USB cable + separate speakers. Gate the probe's duplex path on the same sameEndpointIntent (same type AND same device) the apply path uses, so a two-device pair is probed via the split path it will actually run on. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01JEoFeTPSnz4NpwwCG52hnu --- src/audio/AudioEngine.cpp | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/audio/AudioEngine.cpp b/src/audio/AudioEngine.cpp index a164ede..79fb9f5 100644 --- a/src/audio/AudioEngine.cpp +++ b/src/audio/AudioEngine.cpp @@ -254,12 +254,17 @@ AudioEngine::DeviceOptions AudioEngine::probeDeviceOptionsDual(const juce::Strin const juce::String probeOutputName = options.output.isEmpty() && outputs.size() > 0 ? outputs[0] : options.output; - // Same backend type can usually be opened by one AudioDeviceManager even - // when the capture/render endpoint names differ (common for USB guitar - // cables: cable input + normal speakers). Probe that low-latency path - // first; split mode is only needed for different backend types or when - // the backend refuses a combined input/output device. - bool isDuplex = options.inputType == options.outputType; + // Probe the SAME way setAudioDevices() will actually apply, or the + // startup auto-apply mis-fires: init() fail-closes on this probe's + // `compatible` verdict, so if the probe measures a combined duplex device + // but apply then opens split (or vice-versa), the verdict describes a + // config that won't be the one used — the classic symptom being "no audio + // until I press Apply". Duplex is only attempted for the SAME physical + // endpoint (a true single-clock device); two different endpoints of the + // same backend (USB cable in + separate speakers out) are two clocks and + // go split. Mirror setAudioDevices()'s sameEndpointIntent exactly. + bool isDuplex = (options.inputType == options.outputType) + && (options.input == options.output); if (isDuplex) {