Go Live: request window-scoped audio (windowAudio: window, Chrome 141+); keep the picker window-only

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
2026-10-31 01:44:45 -05:00
parent f3388f52bc
commit b634413773
4 changed files with 9 additions and 8 deletions

View File

@@ -22,6 +22,6 @@ Toolbar → **Go Live**: closes all viewer windows, fetches the logged-in user's
`/me/stream-key` (dumpd, identity from Authentik's header), opens Chrome's window picker (windows only,
audio requested), and publishes over WebRTC/WHIP to `<user>/HelmetCam-<date>` at ≤12 Mbps, H.264, up to
1440p60. Recording, the "is live" post, the sweep and Jellyfin follow exactly as for an OBS stream.
Window audio: Chrome on Windows. Linux/Mac: pick a tab or the whole screen for sound.
Window audio: Chrome/Edge 141+ (`windowAudio: "window"`); older browsers share the window without sound.
Requires the Authentik username to equal the MediaMTX streamer name (configure.py keeps them in sync via
`/etc/vanguard/streamers.json`).

View File

@@ -66,8 +66,8 @@ export default function GoLive({ onExit }) {
<input value={title} onChange={e => setTitle(e.target.value)} disabled={phase === 'capturing'} />
<div className="hint">
Click <b>Start</b>, then pick the <b>WarDogs</b> window in Chrome's dialog and tick <b>Share audio</b>.
Window audio works in Chrome on Windows; on Linux/Mac pick a tab or the whole screen for sound.
Capped at {MAX_KBPS / 1000} Mbps, up to 1440p60, H.264.
Window audio needs <b>Chrome or Edge 141 or newer</b> (chrome://version). Older browsers capture the window
without sound. Capped at {MAX_KBPS / 1000} Mbps, up to 1440p60, H.264.
</div>
{err && <div className="err">{err}</div>}
<button className="primary" disabled={!key || phase === 'capturing'} onClick={start}>{phase === 'capturing' ? 'Waiting for the window picker…' : 'Start'}</button>

View File

@@ -10,14 +10,15 @@ export function defaultTitle(now = new Date()) {
export const cleanTitle = t => t.trim().replace(/\s+/g, '-').replace(/[^A-Za-z0-9_.-]/g, '')
export async function captureWindow() {
// Window-only picker with audio. Chrome on Windows captures that window's audio; elsewhere the user
// should pick a tab or the whole screen to get sound.
// Window-only picker with that window's own audio. Chrome/Edge 141+ honour windowAudio: "window"
// (only the shared window's sound); older Chrome offers no audio for a window at all.
const constraints = {
video: { displaySurface: 'window', frameRate: { ideal: 60, max: 60 }, width: { max: 2560 }, height: { max: 1440 } },
audio: { echoCancellation: false, noiseSuppression: false, autoGainControl: false, sampleRate: 48000, channelCount: 2 },
systemAudio: 'include',
windowAudio: 'window', // capture the picked window's audio (Chrome 141+)
systemAudio: 'exclude',
selfBrowserSurface: 'exclude',
monitorTypeSurfaces: 'exclude', // hide "Entire screen" so people pick the game window
monitorTypeSurfaces: 'exclude', // hide "Entire screen": this is a single-window helmet cam
surfaceSwitching: 'include',
preferCurrentTab: false,
}