mirror of
https://github.com/got-feedBack/feedBack-desktop.git
synced 2026-09-11 01:44:11 +00:00
fix(audio): route device probing through the message thread; document timeout desync
Review follow-up (PR #113, finding 1): ProbeDeviceOptions constructs and destroys short-lived ASIO device objects (DeviceSetup::probeDual / rateSupportedBy createDevice) on the Node thread - the same create/destroy-off-the-message-thread pattern as the lifecycle ops, and a probe ASIOAudioIODevice owns the same reset-timer machinery. Wrap it in runDeviceLifecycleOp for consistency. Finding 2 (timeout desync - op reported failed may still complete late) is documented as a known limitation on the helper. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
aa0bb9d173
commit
895d0af969
@@ -80,6 +80,14 @@ inline bool dispatchOnMessageThread(Func&& func)
|
||||
// closure must own everything it touches — capture by value (engine
|
||||
// snapshot, args) and write results through a shared_ptr, never through
|
||||
// references to the caller's stack.
|
||||
//
|
||||
// KNOWN LIMITATION (timeout desync): when the 15 s wait expires the binding
|
||||
// reports failure to JS, but the closure may still complete afterwards —
|
||||
// e.g. addSource returns -1 yet the source gets created, holding its input
|
||||
// device until the next reconfigure. Memory-safe by the capture rule above,
|
||||
// just not logically reconciled; only reachable with the message thread
|
||||
// jammed > 15 s. Callers that care can re-query engine state (listSources,
|
||||
// getCurrentDevice) after a reported failure.
|
||||
template <typename Func>
|
||||
inline bool runDeviceLifecycleOp(Func&& func)
|
||||
{
|
||||
|
||||
@@ -126,9 +126,24 @@ Napi::Value ProbeDeviceOptions(const Napi::CallbackInfo& info)
|
||||
return obj;
|
||||
}
|
||||
|
||||
auto options = liveEngine->probeDeviceOptionsDual(
|
||||
juce::String(inputType), juce::String(inputName),
|
||||
juce::String(outputType), juce::String(outputName));
|
||||
// Probing constructs + destroys short-lived ASIO device objects
|
||||
// (DeviceSetup::probeDual / rateSupportedBy createDevice) — same
|
||||
// create/destroy-off-the-message-thread pattern as the lifecycle ops, so
|
||||
// it takes the same hop (PR #113 review finding 1). Query-only (never
|
||||
// open()), but a probe ASIOAudioIODevice owns the same reset-timer
|
||||
// machinery as the live one.
|
||||
auto optionsPtr = std::make_shared<AudioEngine::DeviceOptions>();
|
||||
if (!runDeviceLifecycleOp([liveEngine, inputType, inputName, outputType, outputName, optionsPtr] {
|
||||
*optionsPtr = liveEngine->probeDeviceOptionsDual(
|
||||
juce::String(inputType), juce::String(inputName),
|
||||
juce::String(outputType), juce::String(outputName));
|
||||
}))
|
||||
{
|
||||
obj.Set("error", "device probe did not complete (message thread unavailable or timed out)");
|
||||
obj.Set("compatible", false);
|
||||
return obj;
|
||||
}
|
||||
const auto& options = *optionsPtr;
|
||||
obj.Set("type", options.inputType.toStdString()); // legacy alias
|
||||
obj.Set("inputType", options.inputType.toStdString());
|
||||
obj.Set("outputType", options.outputType.toStdString());
|
||||
|
||||
Reference in New Issue
Block a user