mirror of
https://github.com/got-feedBack/feedBack-desktop.git
synced 2026-09-11 06:54:11 +00:00
fix(audio): close Windows ASIO before reconfiguration
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
'use strict';
|
||||
|
||||
// Source-level lifecycle contract for the hardware-dependent half of the ASIO
|
||||
// repair. The pure format decision table is covered by rate_match_test.cpp;
|
||||
// these assertions pin the ordering that cannot be exercised without loading
|
||||
// a real Windows ASIO driver in CI.
|
||||
|
||||
const test = require('node:test');
|
||||
const assert = require('node:assert/strict');
|
||||
const fs = require('node:fs');
|
||||
const path = require('node:path');
|
||||
|
||||
const source = fs.readFileSync(
|
||||
path.join(__dirname, '..', 'src', 'audio', 'engine', 'DeviceSetup.cpp'),
|
||||
'utf8').replace(/\r\n/g, '\n');
|
||||
|
||||
const start = source.indexOf('juce::String DeviceSetup::applyDuplex');
|
||||
const end = source.indexOf('DeviceConfigResult DeviceSetup::applySplit', start);
|
||||
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"\);/);
|
||||
|
||||
const guardedClose = applyDuplex.indexOf(
|
||||
'if (closeBeforeReconfigure && inMgr.getCurrentAudioDevice() != nullptr)');
|
||||
const close = applyDuplex.indexOf('inMgr.closeAudioDevice();', guardedClose);
|
||||
const probe = applyDuplex.indexOf('type->createDevice(outputName, inputName)');
|
||||
assert.ok(guardedClose >= 0 && close > guardedClose && probe > close,
|
||||
'the live ASIO device must be closed before a temporary probe is created');
|
||||
});
|
||||
|
||||
test('duplex setup never converts requested-device failure into default-device success', () => {
|
||||
assert.doesNotMatch(applyDuplex, /initialiseWithDefaultDevices/);
|
||||
assert.match(applyDuplex, /return failClosed\("device setup failed: " \+ result\);/);
|
||||
});
|
||||
|
||||
test('duplex success is gated on actual rate, buffer, and active channel masks', () => {
|
||||
assert.match(applyDuplex, /getCurrentSampleRate\(\)/);
|
||||
assert.match(applyDuplex, /getCurrentBufferSizeSamples\(\)/);
|
||||
assert.match(applyDuplex, /getActiveInputChannels\(\)/);
|
||||
assert.match(applyDuplex, /getActiveOutputChannels\(\)/);
|
||||
assert.match(applyDuplex, /validateOpenedDeviceFormat\(/);
|
||||
});
|
||||
|
||||
test('duplex failures clear observable format state and release monitor resources', () => {
|
||||
const cleanupStart = applyDuplex.indexOf('auto failClosed =');
|
||||
const cleanupEnd = applyDuplex.indexOf('// Channel masks must match too', cleanupStart);
|
||||
const cleanup = applyDuplex.slice(cleanupStart, cleanupEnd);
|
||||
|
||||
assert.match(cleanup, /inMgr\.closeAudioDevice\(\)/);
|
||||
assert.match(cleanup, /currentSampleRate\.store\(0\.0/);
|
||||
assert.match(cleanup, /inputBlockSize\.store\(0/);
|
||||
assert.match(cleanup, /outputBlockSize\.store\(0/);
|
||||
assert.match(cleanup, /monitorChain\.releaseMonitorChain\(\)/);
|
||||
});
|
||||
@@ -10,6 +10,8 @@
|
||||
|
||||
using slopsmith::ratesMatch;
|
||||
using slopsmith::nominalRateCandidate;
|
||||
using slopsmith::DeviceFormatMismatch;
|
||||
using slopsmith::validateOpenedDeviceFormat;
|
||||
|
||||
int main()
|
||||
{
|
||||
@@ -41,6 +43,20 @@ int main()
|
||||
// Non-matching pair → no candidate at all.
|
||||
assert(!nominalRateCandidate(44100.0, 48000.0, c));
|
||||
|
||||
// A device setup is successful only when the driver accepted every
|
||||
// requested format field. This pins the Helix regression where JUCE
|
||||
// returned success for a 512 request while the driver remained at 256.
|
||||
assert(validateOpenedDeviceFormat(48000.0, 512, 48000.0, 512, true, true)
|
||||
== DeviceFormatMismatch::none);
|
||||
assert(validateOpenedDeviceFormat(48000.0, 512, 44100.0, 512, true, true)
|
||||
== DeviceFormatMismatch::sampleRate);
|
||||
assert(validateOpenedDeviceFormat(48000.0, 512, 48000.0, 256, true, true)
|
||||
== DeviceFormatMismatch::bufferSize);
|
||||
assert(validateOpenedDeviceFormat(48000.0, 512, 48000.0, 512, false, true)
|
||||
== DeviceFormatMismatch::inputChannels);
|
||||
assert(validateOpenedDeviceFormat(48000.0, 512, 48000.0, 512, true, false)
|
||||
== DeviceFormatMismatch::outputChannels);
|
||||
|
||||
std::puts("rate_match: all cases passed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user