fix(audio): skip redundant device rebind when opening the selected input

audioInputOpenHandler unconditionally called setDevice, so opening the
selected input (tuner/note_detect on song start) restarted the engine
even when the requested device was already bound — an audible dropout
and the 'Audio paused unexpectedly' seen in tester logs. Now the
handler reads the engine's actual binding (isAudioRunning +
getCurrentDevice) and returns the bound identity without touching the
device when input name and type already match; any read failure falls
through to the normal rebind path.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
OmikronApex
2026-07-15 14:28:02 +02:00
co-authored by Claude Fable 5
parent 854a53e8f7
commit d791552261
+20
View File
@@ -360,6 +360,26 @@ window.__feedBackDesktopAudioHooks = window.__feedBackDesktopAudioHooks || {};
return { outcome: 'failed', status: 'failed', reason: 'No input device selected' };
}
// If the engine is already running with exactly the requested input,
// don't tear it down just to rebind the same device — a redundant
// setDevice stops and restarts the engine mid-session (audible dropout,
// "Audio paused unexpectedly" on song start). Compare against what the
// engine ACTUALLY has bound, not the Settings dropdowns, so a stale UI
// can't fake a match.
try {
const running = typeof api.isAudioRunning === 'function' ? await api.isAudioRunning() : false;
if (running && typeof api.getCurrentDevice === 'function') {
const cur = await api.getCurrentDevice();
const curType = cur && (cur.inputType || cur.type) ? String(cur.inputType || cur.type) : '';
const curInput = cur && cur.input ? String(cur.input) : '';
const wantType = typeInfo && typeInfo.name ? String(typeInfo.name) : '';
if (curInput && curInput.trim() === String(inputDevice).trim()
&& (!wantType || curType === wantType)) {
return { outcome: 'handled', status: 'open', payload: { boundType: curType || wantType, boundName: curInput, requestedName: inputDevice, alreadyBound: true } };
}
}
} catch (_) { /* engine state unreadable — fall through to the normal (re)bind path */ }
const snapshot = currentAudioDeviceSnapshot();
const result = await api.setDevice({
inputType: typeInfo && typeInfo.name ? typeInfo.name : snapshot.inputType,