diff --git a/lib/contribute/broadcast.ts b/lib/contribute/broadcast.ts index ec42635..f3e2c20 100644 --- a/lib/contribute/broadcast.ts +++ b/lib/contribute/broadcast.ts @@ -7,6 +7,7 @@ import { Catalog, Mp4Track, VideoTrack, Track as CatalogTrack, AudioTrack } from import { isAudioTrackSettings, isVideoTrackSettings } from "../common/settings" export interface BroadcastConfig { + namespace: string connection: Connection media: MediaStream @@ -31,7 +32,7 @@ export class Broadcast { constructor(config: BroadcastConfig) { this.connection = config.connection this.config = config - this.catalog = new Catalog() + this.catalog = new Catalog(config.namespace) for (const media of this.config.media.getTracks()) { const track = new Track(media, config) diff --git a/lib/media/catalog/index.ts b/lib/media/catalog/index.ts index edfa169..3351d2e 100644 --- a/lib/media/catalog/index.ts +++ b/lib/media/catalog/index.ts @@ -3,34 +3,35 @@ import { asError } from "../../common/error" // JSON encoded catalog export class Catalog { + namespace: string tracks = new Array() + constructor(namespace: string) { + this.namespace = namespace + } + encode(): Uint8Array { const encoder = new TextEncoder() const str = JSON.stringify(this) return encoder.encode(str) } - static decode(raw: Uint8Array): Catalog { + decode(raw: Uint8Array) { const decoder = new TextDecoder() const str = decoder.decode(raw) try { - const catalog = new Catalog() - catalog.tracks = JSON.parse(str).tracks - - if (!isCatalog(catalog)) { + this.tracks = JSON.parse(str).tracks + if (!isCatalog(this)) { throw new Error("invalid catalog") } - - return catalog } catch (e) { throw new Error("invalid catalog") } } - static async fetch(connection: Connection): Promise { - const subscribe = await connection.subscribe("", ".catalog") + async fetch(connection: Connection) { + const subscribe = await connection.subscribe(this.namespace, ".catalog") try { const segment = await subscribe.data() if (!segment) throw new Error("no catalog data") @@ -41,7 +42,7 @@ export class Catalog { await segment.close() await subscribe.close() // we done - return Catalog.decode(chunk.payload) + this.decode(chunk.payload) } catch (e) { const err = asError(e) diff --git a/lib/playback/index.ts b/lib/playback/index.ts index bf40eae..ca23816 100644 --- a/lib/playback/index.ts +++ b/lib/playback/index.ts @@ -15,6 +15,7 @@ export type Timeline = Message.Timeline export interface PlayerConfig { url: string + namespace: string fingerprint?: string // URL to fetch TLS certificate fingerprint element: HTMLCanvasElement | HTMLVideoElement } @@ -53,7 +54,8 @@ export class Player { const client = new Client({ url: config.url, fingerprint: config.fingerprint, role: "subscriber" }) const connection = await client.connect() - const catalog = await Catalog.fetch(connection) + const catalog = new Catalog(config.namespace) + await catalog.fetch(connection) let backend @@ -94,7 +96,7 @@ export class Player { } async #runInit(name: string) { - const sub = await this.#connection.subscribe("", name) + const sub = await this.#connection.subscribe(this.#catalog.namespace, name) try { const init = await Promise.race([sub.data(), this.#running]) if (!init) throw new Error("no init data") @@ -114,7 +116,7 @@ export class Player { throw new Error(`unknown track kind: ${track.kind}`) } - const sub = await this.#connection.subscribe("", track.data_track) + const sub = await this.#connection.subscribe(this.#catalog.namespace, track.data_track) try { for (;;) { const segment = await Promise.race([sub.data(), this.#running]) diff --git a/web/src/components/publish.tsx b/web/src/components/publish.tsx index dedcaf4..0b8dafb 100644 --- a/web/src/components/publish.tsx +++ b/web/src/components/publish.tsx @@ -97,14 +97,14 @@ export default function Publish() { return tracks[0].getSettings() as VideoTrackSettings }) - const id = crypto.randomUUID() - let watchUrl = `/watch/${id}` + const name = crypto.randomUUID() + let watchUrl = `/watch/${name}` if (server != import.meta.env.PUBLIC_RELAY_HOST) { watchUrl = `${watchUrl}?server=${server}` } createEffect(() => { - const url = `https://${server}/${id}` + const url = `https://${server}` // Special case localhost to fetch the TLS fingerprint from the server. // TODO remove this when WebTransport correctly supports self-signed certificates @@ -145,6 +145,7 @@ export default function Publish() { media: d, audio: a, video: v, + namespace: name, }) } diff --git a/web/src/components/watch.tsx b/web/src/components/watch.tsx index 40839f7..4b91bdc 100644 --- a/web/src/components/watch.tsx +++ b/web/src/components/watch.tsx @@ -34,14 +34,15 @@ export default function Watch(props: { name: string }) { const [usePlayer, setPlayer] = createSignal() createEffect(() => { - const url = `https://${server}/${props.name}` + const namespace = props.name + const url = `https://${server}` // Special case localhost to fetch the TLS fingerprint from the server. // TODO remove this when WebTransport correctly supports self-signed certificates const fingerprint = server.startsWith("localhost") ? `https://${server}/fingerprint` : undefined const element = useElement() - Player.create({ url, fingerprint, element }).then(setPlayer).catch(setError) + Player.create({ url, fingerprint, element, namespace }).then(setPlayer).catch(setError) }) createEffect(() => { diff --git a/web/src/pages/watch/[name].astro b/web/src/pages/watch/[name].astro index 7dead2c..c59078d 100644 --- a/web/src/pages/watch/[name].astro +++ b/web/src/pages/watch/[name].astro @@ -6,7 +6,6 @@ if (!name) return Astro.redirect("/404") import Issues from "@/components/issues.astro" import Watch from "@/components/watch.tsx" -import Clock from "@/components/clock.tsx" import Layout from "@/layouts/global.astro" --- @@ -16,6 +15,5 @@ import Layout from "@/layouts/global.astro"

Watching a PUBLIC broadcast. Pls report any abuse.

- {name == "bbb" && }