web+publisher: align moq watch client and disable passthrough by default
This commit is contained in:
parent
5bce56ee79
commit
c2db3c6727
5 changed files with 88 additions and 23 deletions
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
This is a static web watcher site.
|
||||
|
||||
It embeds the upstream `@kixelated/hang` WebTransport player component (`<hang-watch>`).
|
||||
It embeds the upstream `@moq/watch` WebTransport player component (`<moq-watch>`).
|
||||
|
||||
## Dev
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,12 @@
|
|||
// every.channel web watcher
|
||||
//
|
||||
// This uses the upstream hang web component (WebTransport + WebCodecs).
|
||||
// This uses the upstream moq watch web component (WebTransport + WebCodecs).
|
||||
// It is intentionally dependency-light: no framework, no bundler.
|
||||
|
||||
const DEFAULT_RELAY_URL = "https://cdn.moq.dev/anon";
|
||||
const HANG_WATCH_MODULE_URL = "https://esm.sh/@kixelated/hang@0.7.0/watch/element.js";
|
||||
let hangWatchModulePromise = null;
|
||||
const MOQ_WATCH_MODULE_URL = "https://esm.sh/@moq/watch@0.1.1/element";
|
||||
let moqWatchModulePromise = null;
|
||||
let disposePlayerSignals = null;
|
||||
|
||||
function $(id) {
|
||||
const el = document.getElementById(id);
|
||||
|
|
@ -47,14 +48,69 @@ function setShareLink(text) {
|
|||
el.textContent = text || "";
|
||||
}
|
||||
|
||||
function clearPlayerSignals() {
|
||||
if (typeof disposePlayerSignals === "function") {
|
||||
disposePlayerSignals();
|
||||
}
|
||||
disposePlayerSignals = null;
|
||||
}
|
||||
|
||||
function bindPlayerSignals(watch, name) {
|
||||
const cleanup = [];
|
||||
|
||||
const maybeWatch = (signal, onValue) => {
|
||||
if (!signal || typeof signal.watch !== "function") return;
|
||||
const dispose = signal.watch(onValue);
|
||||
if (typeof dispose === "function") cleanup.push(dispose);
|
||||
};
|
||||
|
||||
let sawLoading = false;
|
||||
maybeWatch(watch?.broadcast?.status, (status) => {
|
||||
if (status === "loading") {
|
||||
sawLoading = true;
|
||||
setHint(`Connecting to relay and subscribing: ${name}`, "ok");
|
||||
return;
|
||||
}
|
||||
if (status === "live") {
|
||||
setHint(`Live: subscribed to ${name}`, "ok");
|
||||
return;
|
||||
}
|
||||
if (status === "offline" && sawLoading) {
|
||||
setHint(`Stream offline or ended: ${name}`, "warn");
|
||||
}
|
||||
});
|
||||
|
||||
maybeWatch(watch?.broadcast?.catalog, (catalog) => {
|
||||
if (!catalog) return;
|
||||
const hasVideo = Boolean(catalog.video && catalog.video.renditions);
|
||||
const hasAudio = Boolean(catalog.audio && catalog.audio.renditions);
|
||||
if (hasVideo || hasAudio) {
|
||||
setHint(`Live: subscribed to ${name}`, "ok");
|
||||
}
|
||||
});
|
||||
|
||||
if (cleanup.length) {
|
||||
disposePlayerSignals = () => {
|
||||
for (const fn of cleanup) {
|
||||
try {
|
||||
fn();
|
||||
} catch (_) {
|
||||
// Best-effort cleanup only.
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function mountPlayer(relayUrl, name) {
|
||||
clearPlayerSignals();
|
||||
|
||||
const mount = $("playerMount");
|
||||
mount.textContent = "";
|
||||
|
||||
const watch = document.createElement("hang-watch");
|
||||
const watch = document.createElement("moq-watch");
|
||||
watch.setAttribute("url", relayUrl);
|
||||
watch.setAttribute("name", name);
|
||||
watch.setAttribute("controls", "");
|
||||
watch.setAttribute("path", name);
|
||||
|
||||
// A canvas enables video rendering. Without it, only audio is played.
|
||||
const canvas = document.createElement("canvas");
|
||||
|
|
@ -62,16 +118,17 @@ function mountPlayer(relayUrl, name) {
|
|||
watch.appendChild(canvas);
|
||||
|
||||
mount.appendChild(watch);
|
||||
bindPlayerSignals(watch, name);
|
||||
}
|
||||
|
||||
async function ensureHangWatchElement() {
|
||||
if (window.customElements && window.customElements.get("hang-watch")) return;
|
||||
if (!hangWatchModulePromise) {
|
||||
hangWatchModulePromise = import(HANG_WATCH_MODULE_URL);
|
||||
async function ensureMoqWatchElement() {
|
||||
if (window.customElements && window.customElements.get("moq-watch")) return;
|
||||
if (!moqWatchModulePromise) {
|
||||
moqWatchModulePromise = import(MOQ_WATCH_MODULE_URL);
|
||||
}
|
||||
await hangWatchModulePromise;
|
||||
if (!(window.customElements && window.customElements.get("hang-watch"))) {
|
||||
throw new Error("hang-watch custom element is unavailable");
|
||||
await moqWatchModulePromise;
|
||||
if (!(window.customElements && window.customElements.get("moq-watch"))) {
|
||||
throw new Error("moq-watch custom element is unavailable");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -162,10 +219,10 @@ function main() {
|
|||
}
|
||||
|
||||
try {
|
||||
await ensureHangWatchElement();
|
||||
await ensureMoqWatchElement();
|
||||
} catch (e) {
|
||||
setHint(
|
||||
`Failed to load web player dependency: ${String(e)}. Disable script blockers for esm.sh and retry.`,
|
||||
`Failed to load MoQ web player dependency: ${String(e)}. Disable script blockers for esm.sh and retry.`,
|
||||
"warn",
|
||||
);
|
||||
return;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue