From 6fb7b61c1c6b5f058ad7fc57f2f53b9151c6b595 Mon Sep 17 00:00:00 2001 From: Stan Grams Date: Sun, 22 Mar 2026 06:15:47 +0100 Subject: [PATCH] [feat](trx-frontend-http): auto-subscribe new sessions to primary channel When a new tab connects and receives the initial channels event, automatically subscribe to channel 0 (primary) so the session joins the same tuned channel as other users on that rig. Uses a lightweight auto-join that skips scheduler control takeover since audio isn't started yet at this point. Co-Authored-By: Claude Opus 4.6 Signed-off-by: Stan Grams --- .../assets/web/plugins/vchan.js | 35 +++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/src/trx-client/trx-frontend/trx-frontend-http/assets/web/plugins/vchan.js b/src/trx-client/trx-frontend/trx-frontend-http/assets/web/plugins/vchan.js index 06f6033..a6facf5 100644 --- a/src/trx-client/trx-frontend/trx-frontend-http/assets/web/plugins/vchan.js +++ b/src/trx-client/trx-frontend/trx-frontend-http/assets/web/plugins/vchan.js @@ -130,9 +130,15 @@ function vchanHandleChannels(data) { const d = JSON.parse(data); vchanRigId = d.rig_id || null; vchanChannels = d.channels || []; - // If the active channel was evicted, fall back to channel 0 and reconnect audio. const ids = new Set(vchanChannels.map(c => c.id)); - if (vchanActiveId && !ids.has(vchanActiveId)) { + if (!vchanActiveId && vchanChannels.length > 0 && vchanSessionId) { + // First channels event for this session — auto-subscribe to channel 0 + // so we join the same tuned channel as other users on this rig. + // Use a direct subscribe (no scheduler control takeover) to avoid + // side-effects on initial connect. + vchanAutoJoinPrimary(vchanChannels[0].id); + } else if (vchanActiveId && !ids.has(vchanActiveId)) { + // Active channel was evicted — fall back to channel 0 and reconnect audio. vchanActiveId = vchanChannels.length > 0 ? vchanChannels[0].id : null; vchanReconnectAudio(); } @@ -243,6 +249,31 @@ async function vchanDelete(channelId) { } } +// Lightweight auto-join for initial connect: registers the session on +// channel 0 without taking scheduler control or reconnecting audio +// (audio isn't started yet at this point). +async function vchanAutoJoinPrimary(channelId) { + if (!vchanSessionId || !vchanRigId) return; + try { + const resp = await fetch( + `/channels/${encodeURIComponent(vchanRigId)}/${encodeURIComponent(channelId)}/subscribe`, + { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ session_id: vchanSessionId }), + } + ); + if (!resp.ok) { + console.warn("vchan: auto-join primary failed", resp.status); + return; + } + vchanActiveId = channelId; + vchanRender(); + } catch (e) { + console.error("vchan: auto-join error", e); + } +} + async function vchanSubscribe(channelId) { if (!vchanSessionId || !vchanRigId) return; try {