fix(api,ui): chan double-spawn GUI embed master chain - register bridge ngay sau Popen + inflight guard + frontend busy ref (crash 0xc0000005 2 instance Ozone)

This commit is contained in:
2026-09-02 12:34:46 +07:00
parent f793ebce9b
commit 33c5cc290f
2 changed files with 59 additions and 23 deletions
+23 -3
View File
@@ -14228,6 +14228,7 @@ const MasteringModal = ({ isOpen, onClose, masteringSettings, setMasteringSettin
const [activeMasterVstPath, setActiveMasterVstPath] = React.useState(null);
const masterGuiOpenRef = React.useRef(null);
masterGuiOpenRef.current = masterGuiOpen;
const masterGuiBusyRef = React.useRef(false); // request openFxGui đang bay (chưa có verdict 20-70s)
const closeMasterGui = () => {
const g = masterGuiOpenRef.current;
if (g) {
@@ -14255,12 +14256,14 @@ const MasteringModal = ({ isOpen, onClose, masteringSettings, setMasteringSettin
}, [masterGuiOpen]);
// Reopen the saved GUI when the panel is opened after a project restore.
React.useEffect(() => {
if (!isOpen || !ozState || !ozState.gui_open_path || masterGuiOpen) return;
if (!isOpen || !ozState || !ozState.gui_open_path || masterGuiOpen || masterGuiBusyRef.current) return;
const s = (ozState.vstFxChain || []).find(x => x.path === ozState.gui_open_path);
if (!s || !window.SonicAPI || !window.SonicAPI.openFxGui) return;
masterGuiBusyRef.current = true;
window.SonicAPI.openFxGui({ path: s.path, name: ozState.gui_open_name || s.name || s.path, embed: true, shm: fxRt.sessionId || '', preset_b64: _capturedPresetByPath[s.path] || s.preset_b64 || '' }).then(r => {
masterGuiBusyRef.current = false;
if (r && r.embed_url) setMasterGuiOpen({ path: s.path, url: r.embed_url });
}).catch(() => {});
}).catch(() => { masterGuiBusyRef.current = false; });
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isOpen, ozState && ozState.gui_open_path]);
const setMasterVstChain = (next) => setOzState(prev => {
@@ -14284,7 +14287,24 @@ const MasteringModal = ({ isOpen, onClose, masteringSettings, setMasteringSettin
const toggleMasterVst = (idx) => setMasterVstChain(masterVstChain.map((s, i) => i === idx ? { ...s, bypass: !s.bypass } : s));
const removeMasterVst = (idx) => { const rem = masterVstChain[idx]; if (rem) delete _capturedPresetByPath[rem.path]; setMasterVstChain(masterVstChain.filter((_, i) => i !== idx)); };
const moveMasterVst = (idx, dir) => { const j = idx + dir; if (j < 0 || j >= masterVstChain.length) return; const next = [...masterVstChain]; const mv = next.splice(idx, 1)[0]; next.splice(j, 0, mv); setMasterVstChain(next); };
const openMasterVstGui = (s) => { if (!s || !s.path) { window.showToast && window.showToast('Chọn VST FX trước', 'warning'); return; } if (masterGuiOpen && masterGuiOpen.path === s.path) { setActiveMasterVstPath(s.path); return; } if (masterGuiOpen) closeMasterGui(); if (s.path) setActiveMasterVstPath(s.path); if (!window.SonicAPI || !window.SonicAPI.openFxGui) { window.showToast && window.showToast('Máy này không hỗ trợ mở GUI VST', 'warning'); return; } window.SonicAPI.openFxGui({ path: s.path, name: s.name || s.path, embed: true, shm: fxRt.sessionId || '', preset_b64: _capturedPresetByPath[s.path] || s.preset_b64 || '' }).then(r => { if (r && r.embed_url) { setMasterGuiOpen({ path: s.path, url: r.embed_url, name: s.name || s.path }); setOzState(prev => ({ ...(prev || {}), gui_open_path: s.path, gui_open_name: s.name || s.path })); } else if (r && r.already_running && r.embed_url) { setMasterGuiOpen({ path: s.path, url: r.embed_url, name: s.name || s.path }); setOzState(prev => ({ ...(prev || {}), gui_open_path: s.path, gui_open_name: s.name || s.path })); } else if (r && r.already_running) window.showToast && window.showToast('GUI của plugin này đang mở sẵn (cửa sổ ngoài)', 'info'); else window.showToast && window.showToast('Không mở được GUI embed', 'error'); }).catch(err => window.showToast && window.showToast('Lỗi mở GUI: ' + (err.message || err), 'error')); };
const openMasterVstGui = (s) => {
if (!s || !s.path) { window.showToast && window.showToast('Chọn VST FX trước', 'warning'); return; }
if (masterGuiOpen && masterGuiOpen.path === s.path) { setActiveMasterVstPath(s.path); return; }
// Request trước cho GUI embed còn đang bay (verdict 20-70s với Ozone-class):
// chặn click lặp — nếu không sẽ spawn bridge GUI thứ 2 → crash (0xc0000005).
if (masterGuiBusyRef.current) { window.showToast && window.showToast('GUI đang mở, chờ chút...', 'info'); return; }
if (masterGuiOpen) closeMasterGui();
if (s.path) setActiveMasterVstPath(s.path);
if (!window.SonicAPI || !window.SonicAPI.openFxGui) { window.showToast && window.showToast('Máy này không hỗ trợ mở GUI VST', 'warning'); return; }
masterGuiBusyRef.current = true;
window.SonicAPI.openFxGui({ path: s.path, name: s.name || s.path, embed: true, shm: fxRt.sessionId || '', preset_b64: _capturedPresetByPath[s.path] || s.preset_b64 || '' }).then(r => {
masterGuiBusyRef.current = false;
if (r && r.embed_url) { setMasterGuiOpen({ path: s.path, url: r.embed_url, name: s.name || s.path }); setOzState(prev => ({ ...(prev || {}), gui_open_path: s.path, gui_open_name: s.name || s.path })); }
else if (r && r.already_running && r.embed_url) { setMasterGuiOpen({ path: s.path, url: r.embed_url, name: s.name || s.path }); setOzState(prev => ({ ...(prev || {}), gui_open_path: s.path, gui_open_name: s.name || s.path })); }
else if (r && r.already_running) window.showToast && window.showToast('GUI của plugin này đang mở sẵn (cửa sổ ngoài)', 'info');
else window.showToast && window.showToast('Không mở được GUI embed', 'error');
}).catch(err => { masterGuiBusyRef.current = false; window.showToast && window.showToast('Lỗi mở GUI: ' + (err.message || err), 'error'); });
};
const addMasterVst = (path) => { const fx = (masterFxList || []).find(f => f.path === path); if (!fx) return; setMasterVstChain([...masterVstChain, { type: 'vst3', path: fx.path, name: fx.name || fx.id, preset_b64: '', bypass: false }]);
openMasterVstGui({ path: fx.path, name: fx.name || fx.id }); };
const changeMasterVstPlugin = (idx, path) => { const fx = (masterFxList || []).find(f => f.path === path); delete _capturedPresetByPath[path]; setMasterVstChain(masterVstChain.map((s, i) => i === idx ? { ...s, path, name: fx ? (fx.name || fx.id) : s.name, preset_b64: '' } : s)); };