diff --git a/src/audio/engine/DeviceSetup.cpp b/src/audio/engine/DeviceSetup.cpp index 72d5663..71912ed 100644 --- a/src/audio/engine/DeviceSetup.cpp +++ b/src/audio/engine/DeviceSetup.cpp @@ -266,6 +266,7 @@ juce::String DeviceSetup::applyDuplex(const juce::String& inputName, state.currentSampleRate.store(0.0, std::memory_order_relaxed); state.inputBlockSize.store(0, std::memory_order_relaxed); state.outputBlockSize.store(0, std::memory_order_relaxed); + state.duplexMode.store(false, std::memory_order_relaxed); try { monitorChain.releaseMonitorChain(); } catch (...) { fprintf(stderr, "[AudioEngine] Duplex failure cleanup: monitor release threw\n"); @@ -409,20 +410,18 @@ juce::String DeviceSetup::applyDuplex(const juce::String& inputName, // the requested contract. Rebuild those masks from the opened device's // advertised channels so a failed pre-open probe cannot silently // collapse an 8-input ASIO interface to the old two-channel fallback. - juce::BigInteger expectedInputs = setup.inputChannels; - if (!setup.useDefaultInputChannels) - { - expectedInputs.clear(); + juce::BigInteger expectedInputs; + if (setup.useDefaultInputChannels) + expectedInputs = setup.inputChannels; + else expectedInputs.setRange( 0, configuredDevice->getInputChannelNames().size(), true); - } - juce::BigInteger expectedOutputs = setup.outputChannels; - if (!setup.useDefaultOutputChannels) - { - expectedOutputs.clear(); + juce::BigInteger expectedOutputs; + if (setup.useDefaultOutputChannels) + expectedOutputs = setup.outputChannels; + else expectedOutputs.setRange( 0, juce::jmin(configuredDevice->getOutputChannelNames().size(), 2), true); - } const auto actualInputs = configuredDevice->getActiveInputChannels(); const auto actualOutputs = configuredDevice->getActiveOutputChannels(); diff --git a/tests/device-setup-lifecycle.test.js b/tests/device-setup-lifecycle.test.js index 410b054..8e54d4f 100644 --- a/tests/device-setup-lifecycle.test.js +++ b/tests/device-setup-lifecycle.test.js @@ -16,10 +16,12 @@ const source = fs.readFileSync( const start = source.indexOf('juce::String DeviceSetup::applyDuplex'); const end = source.indexOf('DeviceConfigResult DeviceSetup::applySplit', start); +// Fail with a clear message before any slicing if the function markers move — +// a bad slice would otherwise make every assertion below fail confusingly. +assert.ok(start >= 0 && end > start, 'could not locate applyDuplex in DeviceSetup.cpp'); const applyDuplex = source.slice(start, end); test('duplex setup closes Windows ASIO before constructing its channel probe', () => { - assert.ok(start >= 0 && end > start, 'could not locate applyDuplex'); assert.match( applyDuplex, /#elif JUCE_WINDOWS\s+closeBeforeReconfigure = \(currentTypeName == "ASIO"\);/);