window.BackOneAddons = window.BackOneAddons || {}; window.BackOneAddons.video = function videoAddon() { let picker = null; let selectedPeer = null; let inCall = false; let micEnabled = true; let camEnabled = true; let root = null; function updateConnectionBar() { const bar = root?.querySelector('#video-conn-bar'); if (!bar || !window.BackOneCommLayout) return; bar.innerHTML = BackOneCommLayout.connectionBarHtml( selectedPeer, BackOneNetworkSession.getActiveNetwork() ); } function updateHeadStatus() { const statusEl = root?.querySelector('#video-head-status'); const breadcrumb = root?.querySelector('#video-breadcrumb-peer'); if (!statusEl) return; if (inCall && selectedPeer) { statusEl.innerHTML = `Connected · ${selectedPeer.latency != null ? selectedPeer.latency + 'ms' : '—'}`; if (breadcrumb) breadcrumb.textContent = selectedPeer.peerId; } else if (selectedPeer) { statusEl.textContent = 'Ready'; if (breadcrumb) breadcrumb.textContent = selectedPeer.peerId; } else { statusEl.textContent = ''; if (breadcrumb) breadcrumb.textContent = '—'; } } function updateCallButtons() { const callBtn = root?.querySelector('#video-call'); if (callBtn) callBtn.disabled = !selectedPeer || !BackOneNetworkSession.getNetworkId() || inCall; const selectedLabel = root?.querySelector('#video-selected-label'); if (selectedLabel) { selectedLabel.innerHTML = selectedPeer ? `Selected: ${selectedPeer.peerId.slice(0, 10)}…` : 'Selected: —'; } updateHeadStatus(); updateConnectionBar(); } function updateCallLayout() { const layout = root?.querySelector('.comm-layout'); if (layout) layout.classList.toggle('video-in-call', inCall); } function showPlaceholder(show) { const stage = root?.querySelector('.video-stage'); const remote = root?.querySelector('#video-remote'); const phLabel = root?.querySelector('#video-ph-label'); if (stage) stage.classList.toggle('has-remote', !show); if (remote) remote.classList.toggle('active', !show); if (phLabel && show) { phLabel.textContent = inCall ? 'Waiting for remote peer…' : (selectedPeer ? 'Ready to call' : 'Select a peer to start a video call'); } updateCallLayout(); } function bindStreams() { const local = root?.querySelector('#video-local'); const remote = root?.querySelector('#video-remote'); const localStream = BackOneWebRtcSession.getLocalStream(); const remoteStream = BackOneWebRtcSession.getRemoteStream(); if (local && localStream) local.srcObject = localStream; if (remote && remoteStream && remoteStream.getTracks().length) { remote.srcObject = remoteStream; showPlaceholder(false); root?.querySelector('#video-breadcrumb-state')?.textContent = 'Connected to'; } } async function hangUp() { await BackOneWebRtcSession.hangUp(); const local = root?.querySelector('#video-local'); const remote = root?.querySelector('#video-remote'); if (local) local.srcObject = null; if (remote) remote.srcObject = null; inCall = false; micEnabled = true; camEnabled = true; const breadcrumbState = root?.querySelector('#video-breadcrumb-state'); if (breadcrumbState) breadcrumbState.textContent = 'Select peer'; showPlaceholder(true); updateCallButtons(); window.BackOneRingingPopup?.dismiss(); } return { mount(container) { root = container; container.innerHTML = `
Video Call P2P > Select peer —
👤
—
Select a peer to start a video call
You
Remote
`; const callBtn = container.querySelector('#video-call'); picker = BackOnePeerPicker(container.querySelector('#video-picker'), { layout: 'sidebar', showActionButton: false, onSelect(peer) { selectedPeer = peer; const phPeer = root.querySelector('#video-ph-peer'); if (phPeer) phPeer.textContent = peer.peerId; if (!inCall) showPlaceholder(true); updateCallButtons(); }, onNetworkChange() { if (!inCall) selectedPeer = null; updateCallButtons(); } }); BackOneNetworkSession.subscribe(() => updateCallButtons()); BackOneWebRtcSession.subscribe((event) => { if (event === 'call-started') { inCall = true; updateCallButtons(); bindStreams(); } if (event === 'remote-track' || event === 'call-accepted') bindStreams(); if (event === 'call-ended') { inCall = false; showPlaceholder(true); updateCallButtons(); } }); callBtn.onclick = async () => { const peer = selectedPeer || picker.getSelectedPeer(); if (!peer || !BackOneNetworkSession.getNetworkId()) return; try { inCall = true; root.querySelector('#video-breadcrumb-state').textContent = 'Connecting to'; updateCallLayout(); updateCallButtons(); await BackOneWebRtcSession.startOutgoingCall(peer, 'video'); bindStreams(); } catch (err) { await hangUp(); alert(err.message || 'Call failed'); } }; container.querySelector('#video-hangup').onclick = () => hangUp(); container.querySelector('#video-hangup-stage').onclick = () => hangUp(); container.querySelector('#video-mic').onclick = () => { const localStream = BackOneWebRtcSession.getLocalStream(); if (!localStream) return; micEnabled = !micEnabled; localStream.getAudioTracks().forEach(t => { t.enabled = micEnabled; }); container.querySelector('#video-mic').textContent = micEnabled ? 'Mic' : 'Mic off'; }; container.querySelector('#video-cam').onclick = () => { const localStream = BackOneWebRtcSession.getLocalStream(); if (!localStream) return; camEnabled = !camEnabled; localStream.getVideoTracks().forEach(t => { t.enabled = camEnabled; }); container.querySelector('#video-cam').textContent = camEnabled ? 'Camera' : 'Camera off'; }; container.querySelector('#video-fs').onclick = () => { const stage = container.querySelector('.comm-stage'); if (stage.requestFullscreen) stage.requestFullscreen(); }; const active = BackOneWebRtcSession.getActiveCall(); inCall = !!active && active.callType === 'video'; showPlaceholder(true); if (inCall) bindStreams(); updateCallButtons(); } }; };