@moq/watch 0.3.1 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/README.md +1 -2
  2. package/audio/decoder.d.ts +25 -15
  3. package/audio/decoder.d.ts.map +1 -1
  4. package/audio/emitter.d.ts +13 -10
  5. package/audio/emitter.d.ts.map +1 -1
  6. package/audio/index.d.ts +0 -2
  7. package/audio/index.d.ts.map +1 -1
  8. package/audio/source.d.ts +21 -17
  9. package/audio/source.d.ts.map +1 -1
  10. package/audio/unlock.d.ts +20 -0
  11. package/audio/unlock.d.ts.map +1 -0
  12. package/audio/unlock.test.d.ts +2 -0
  13. package/audio/unlock.test.d.ts.map +1 -0
  14. package/broadcast.d.ts +27 -57
  15. package/broadcast.d.ts.map +1 -1
  16. package/element.d.ts +42 -12
  17. package/element.d.ts.map +1 -1
  18. package/element.js +146 -90
  19. package/element.js.map +1 -1
  20. package/index.d.ts +9 -6
  21. package/index.d.ts.map +1 -1
  22. package/index.js +24 -5
  23. package/index.js.map +1 -0
  24. package/package.json +5 -6
  25. package/source-CWtgjSC_.js +1359 -0
  26. package/source-CWtgjSC_.js.map +1 -0
  27. package/support/element.d.ts.map +1 -1
  28. package/support/element.js.map +1 -1
  29. package/support/index.d.ts +3 -3
  30. package/support/index.d.ts.map +1 -1
  31. package/support/index.js +18 -17
  32. package/support/index.js.map +1 -1
  33. package/sync-zdwVEj9u.js +129 -0
  34. package/sync-zdwVEj9u.js.map +1 -0
  35. package/sync.d.ts +19 -18
  36. package/sync.d.ts.map +1 -1
  37. package/ui/components/buffer-control.d.ts +1 -1
  38. package/ui/components/buffer-control.d.ts.map +1 -1
  39. package/ui/components/fullscreen-button.d.ts +1 -2
  40. package/ui/components/fullscreen-button.d.ts.map +1 -1
  41. package/ui/components/play-pause.d.ts +1 -1
  42. package/ui/components/play-pause.d.ts.map +1 -1
  43. package/ui/element.d.ts.map +1 -1
  44. package/ui/element.js +269 -265
  45. package/ui/element.js.map +1 -1
  46. package/ui/fullscreen.d.ts +1 -2
  47. package/ui/fullscreen.d.ts.map +1 -1
  48. package/video/decoder.d.ts +32 -16
  49. package/video/decoder.d.ts.map +1 -1
  50. package/video/index.d.ts +0 -2
  51. package/video/index.d.ts.map +1 -1
  52. package/video/renderer.d.ts +14 -17
  53. package/video/renderer.d.ts.map +1 -1
  54. package/video/source.d.ts +23 -20
  55. package/video/source.d.ts.map +1 -1
  56. package/audio/backend.d.ts +0 -26
  57. package/audio/backend.d.ts.map +0 -1
  58. package/audio/mse.d.ts +0 -22
  59. package/audio/mse.d.ts.map +0 -1
  60. package/backend.d.ts +0 -65
  61. package/backend.d.ts.map +0 -1
  62. package/broadcast-C2qofUBv.js +0 -1701
  63. package/broadcast-C2qofUBv.js.map +0 -1
  64. package/buffered.d.ts +0 -19
  65. package/buffered.d.ts.map +0 -1
  66. package/mse.d.ts +0 -19
  67. package/mse.d.ts.map +0 -1
  68. package/sync-D67IxmxJ.js +0 -128
  69. package/sync-D67IxmxJ.js.map +0 -1
  70. package/video/backend.d.ts +0 -25
  71. package/video/backend.d.ts.map +0 -1
  72. package/video/mse.d.ts +0 -23
  73. package/video/mse.d.ts.map +0 -1
@@ -0,0 +1,1359 @@
1
+ import { Path as e, Time as t } from "@moq/net";
2
+ import { Effect as n, Signal as r, getter as i, readonlys as a } from "@moq/signals";
3
+ import * as o from "@moq/hang/catalog";
4
+ import { u53 as s } from "@moq/hang/catalog";
5
+ import * as c from "@moq/hang/container";
6
+ import * as l from "@moq/hang/util";
7
+ import * as u from "@moq/json";
8
+ import * as d from "@moq/msf";
9
+ //#region src/base64.ts
10
+ function f(e) {
11
+ let t = atob(e), n = new Uint8Array(t.length);
12
+ for (let e = 0; e < t.length; e++) n[e] = t.charCodeAt(e);
13
+ return n;
14
+ }
15
+ //#endregion
16
+ //#region src/audio/shared-ring-buffer.ts
17
+ var p = 0, m = 1, h = 2, g = 3, _ = 4;
18
+ function v(e, t, n, r = !1) {
19
+ if (e <= 0) throw Error("invalid channels");
20
+ if (t <= 0) throw Error("invalid capacity");
21
+ if (n <= 0) throw Error("invalid sample rate");
22
+ let i = new SharedArrayBuffer(e * t * Float32Array.BYTES_PER_ELEMENT), a = new SharedArrayBuffer(_ * Int32Array.BYTES_PER_ELEMENT), o = new Int32Array(a);
23
+ return Atomics.store(o, g, 1), {
24
+ channels: e,
25
+ capacity: t,
26
+ rate: n,
27
+ samples: i,
28
+ control: a,
29
+ buffered: r
30
+ };
31
+ }
32
+ function y(e, t) {
33
+ return (e - t | 0) > 0 ? e : t;
34
+ }
35
+ function b(e, t) {
36
+ return (e % t + t) % t;
37
+ }
38
+ function x(e, t, n) {
39
+ for (;;) {
40
+ let r = Atomics.load(e, t);
41
+ if ((n - r | 0) <= 0) return r;
42
+ if (Atomics.compareExchange(e, t, r, n) === r) return n;
43
+ }
44
+ }
45
+ var S = class e {
46
+ channels;
47
+ capacity;
48
+ rate;
49
+ buffered;
50
+ init;
51
+ #e;
52
+ #t;
53
+ #n = !1;
54
+ constructor(e) {
55
+ this.channels = e.channels, this.capacity = e.capacity, this.rate = e.rate, this.buffered = e.buffered, this.init = e, this.#e = new Int32Array(e.control), this.#t = [];
56
+ for (let t = 0; t < this.channels; t++) this.#t.push(new Float32Array(e.samples, t * this.capacity * Float32Array.BYTES_PER_ELEMENT, this.capacity));
57
+ }
58
+ insert(e, n) {
59
+ if (n.length !== this.channels) throw Error("wrong number of channels");
60
+ let r = Math.round(t.Second.fromMicro(e) * this.rate), i = n[0].length, a = 0;
61
+ this.buffered && !this.#n && (Atomics.store(this.#e, m, r | 0), Atomics.store(this.#e, p, r | 0), this.#n = !0);
62
+ let o = r + i | 0, s = Atomics.load(this.#e, m), c = s - r | 0;
63
+ if (c > 0) {
64
+ if (c >= i) return;
65
+ a = c, r = r + c | 0;
66
+ }
67
+ let l = i - a;
68
+ (o - s | 0) > this.capacity && x(this.#e, m, o - this.capacity | 0);
69
+ let u = Atomics.load(this.#e, p), d = r - u | 0;
70
+ if (d > 0) {
71
+ let e = Math.min(d, this.capacity);
72
+ for (let t = 0; t < this.channels; t++) {
73
+ let n = this.#t[t];
74
+ for (let t = 0; t < e; t++) n[b(u + t | 0, this.capacity)] = 0;
75
+ }
76
+ }
77
+ for (let e = 0; e < this.channels; e++) {
78
+ let t = n[e], i = this.#t[e];
79
+ for (let e = 0; e < l; e++) i[b(r + e | 0, this.capacity)] = t[a + e];
80
+ }
81
+ Atomics.store(this.#e, p, y(Atomics.load(this.#e, p), o));
82
+ let f = Atomics.load(this.#e, m), _ = Atomics.load(this.#e, p), v = Atomics.load(this.#e, h);
83
+ (_ - f | 0) >= v && v > 0 && Atomics.store(this.#e, g, 0);
84
+ }
85
+ read(e) {
86
+ if (Atomics.load(this.#e, g) === 1) return 0;
87
+ let t = Atomics.load(this.#e, m), n = Atomics.load(this.#e, p), r = Atomics.load(this.#e, h), i = n - t | 0;
88
+ if (!this.buffered && r > 0 && i > r) {
89
+ let e = n - r | 0;
90
+ t = x(this.#e, m, e);
91
+ }
92
+ let a = n - t | 0, o = Math.min(a, e[0].length);
93
+ if (o <= 0) return 0;
94
+ for (let n = 0; n < this.channels; n++) {
95
+ let r = this.#t[n], i = e[n];
96
+ for (let e = 0; e < o; e++) i[e] = r[b(t + e | 0, this.capacity)];
97
+ }
98
+ return x(this.#e, m, t + o | 0), o;
99
+ }
100
+ setLatency(e) {
101
+ Atomics.store(this.#e, h, e);
102
+ }
103
+ reset() {
104
+ this.#n = !1, Atomics.store(this.#e, g, 1);
105
+ let e = Atomics.load(this.#e, p);
106
+ Atomics.store(this.#e, m, e);
107
+ }
108
+ resize(t) {
109
+ let n = v(this.channels, t, this.rate, this.buffered), r = new e(n);
110
+ r.#n = this.#n;
111
+ let i = Atomics.load(this.#e, m), a = Atomics.load(this.#e, p), o = Atomics.load(this.#e, h), s = Atomics.load(this.#e, g), c = a - i | 0, l = Math.max(0, Math.min(c, r.capacity)), u = a - l | 0;
112
+ for (let e = 0; e < this.channels; e++) {
113
+ let t = this.#t[e], n = r.#t[e];
114
+ for (let e = 0; e < l; e++) {
115
+ let i = u + e | 0;
116
+ n[b(i, r.capacity)] = t[b(i, this.capacity)];
117
+ }
118
+ }
119
+ return Atomics.store(r.#e, m, u), Atomics.store(r.#e, p, a), Atomics.store(r.#e, h, o), Atomics.store(r.#e, g, s), r;
120
+ }
121
+ get timestamp() {
122
+ let e = Atomics.load(this.#e, m);
123
+ return t.Micro.fromSecond(e / this.rate);
124
+ }
125
+ get stalled() {
126
+ return Atomics.load(this.#e, g) === 1;
127
+ }
128
+ get length() {
129
+ return Atomics.load(this.#e, p) - Atomics.load(this.#e, m) | 0;
130
+ }
131
+ }, C = class {
132
+ #e;
133
+ #t;
134
+ #n = [];
135
+ constructor(e, t) {
136
+ this.#e = e, this.#t = t;
137
+ }
138
+ setHeadroom(e) {
139
+ this.#t = e;
140
+ }
141
+ wait(e, t) {
142
+ return !this.#e || t >= (e - this.#t | 0) ? Promise.resolve() : new Promise((t) => this.#n.push({
143
+ timestamp: e,
144
+ resolve: t
145
+ }));
146
+ }
147
+ advance(e) {
148
+ this.#n.length !== 0 && (this.#n = this.#n.filter(({ timestamp: t, resolve: n }) => e < (t - this.#t | 0) ? !0 : (n(), !1)));
149
+ }
150
+ flush() {
151
+ for (let { resolve: e } of this.#n) e();
152
+ this.#n = [];
153
+ }
154
+ };
155
+ function w(e, n) {
156
+ return t.Micro.fromSecond(e / n);
157
+ }
158
+ function T() {
159
+ return !(typeof SharedArrayBuffer > "u" || typeof crossOriginIsolated < "u" && !crossOriginIsolated);
160
+ }
161
+ function E(e, t, n, r, i = !1) {
162
+ return T() ? (console.log("[audio] using SharedArrayBuffer audio buffer"), new D(e, t, n, r, i)) : (console.log("[audio] using postMessage audio buffer (SharedArrayBuffer unavailable)"), new O(e, t, n, r, i));
163
+ }
164
+ var D = class {
165
+ rate;
166
+ channels;
167
+ #e;
168
+ #t;
169
+ #n = new r(0);
170
+ timestamp = this.#n;
171
+ #r = new r(!0);
172
+ stalled = this.#r;
173
+ #i;
174
+ #a = new n();
175
+ constructor(e, t, n, r, i) {
176
+ this.#e = e, this.channels = t, this.rate = n;
177
+ let a = Math.max(n, r * 2);
178
+ this.#i = new C(i, w(r, n));
179
+ let o = v(t, a, n, i);
180
+ this.#t = new S(o), this.#t.setLatency(r);
181
+ let s = {
182
+ type: "init-shared",
183
+ ...o
184
+ };
185
+ e.port.postMessage(s), this.#a.interval(() => {
186
+ let e = this.#t.stalled;
187
+ this.#n.set(this.#t.timestamp), this.#r.set(e), e ? this.#i.flush() : this.#i.advance(this.#t.timestamp);
188
+ }, 50);
189
+ }
190
+ insert(e, t) {
191
+ this.#t.insert(e, t);
192
+ }
193
+ setLatency(e) {
194
+ if (this.#i.setHeadroom(w(e, this.rate)), this.#t.capacity < e * 1.5) {
195
+ let t = Math.max(this.rate, e * 2);
196
+ this.#t = this.#t.resize(t), this.#t.setLatency(e);
197
+ let n = {
198
+ type: "init-shared",
199
+ ...this.#t.init
200
+ };
201
+ this.#e.port.postMessage(n);
202
+ } else this.#t.setLatency(e);
203
+ }
204
+ reset() {
205
+ this.#t.reset(), this.#i.flush();
206
+ }
207
+ wait(e) {
208
+ return this.#t.stalled ? Promise.resolve() : this.#i.wait(e, this.#t.timestamp);
209
+ }
210
+ close() {
211
+ this.#i.flush(), this.#a.close();
212
+ }
213
+ }, O = class {
214
+ rate;
215
+ channels;
216
+ #e;
217
+ #t = new r(0);
218
+ timestamp = this.#t;
219
+ #n = new r(!0);
220
+ stalled = this.#n;
221
+ #r;
222
+ #i = new n();
223
+ constructor(e, n, r, i, a) {
224
+ this.#e = e, this.channels = n, this.rate = r, this.#r = new C(a, w(i, r));
225
+ let o = {
226
+ type: "init-post",
227
+ channels: n,
228
+ rate: r,
229
+ latency: t.Milli.fromSecond(i / r),
230
+ buffered: a
231
+ };
232
+ e.port.postMessage(o), this.#i.event(e.port, "message", (e) => {
233
+ let t = e.data;
234
+ t?.type === "state" && (this.#t.set(t.timestamp), this.#n.set(t.stalled), t.stalled ? this.#r.flush() : this.#r.advance(t.timestamp));
235
+ }), e.port.start();
236
+ }
237
+ insert(e, t) {
238
+ let n = {
239
+ type: "data",
240
+ data: t,
241
+ timestamp: e
242
+ };
243
+ this.#e.port.postMessage(n, t.map((e) => e.buffer));
244
+ }
245
+ setLatency(e) {
246
+ this.#r.setHeadroom(w(e, this.rate));
247
+ let n = {
248
+ type: "latency",
249
+ latency: t.Milli.fromSecond(e / this.rate)
250
+ };
251
+ this.#e.port.postMessage(n);
252
+ }
253
+ reset() {
254
+ this.#e.port.postMessage({ type: "reset" }), this.#r.flush();
255
+ }
256
+ wait(e) {
257
+ return this.#n.peek() ? Promise.resolve() : this.#r.wait(e, this.#t.peek());
258
+ }
259
+ close() {
260
+ this.#r.flush(), this.#i.close();
261
+ }
262
+ }, k = new Blob(["var __defProp = Object.defineProperty;\nvar __export = (target, all) => {\n for (var name in all)\n __defProp(target, name, { get: all[name], enumerable: true });\n};\n\n// ../net/src/time.ts\nvar time_exports = {};\n__export(time_exports, {\n Micro: () => Micro,\n Milli: () => Milli,\n Nano: () => Nano,\n Second: () => Second,\n Timescale: () => Timescale,\n Timestamp: () => Timestamp\n});\nvar Nano = Object.assign((value) => value, {\n zero: 0,\n fromMicro: (us) => us * 1e3,\n fromMilli: (ms) => ms * 1e6,\n fromSecond: (s) => s * 1e9,\n toMicro: (ns) => ns / 1e3,\n toMilli: (ns) => ns / 1e6,\n toSecond: (ns) => ns / 1e9,\n now: () => performance.now() * 1e6,\n add: (a, b) => a + b,\n sub: (a, b) => a - b,\n mul: (a, b) => a * b,\n div: (a, b) => a / b,\n max: (a, b) => Math.max(a, b),\n min: (a, b) => Math.min(a, b)\n});\nvar Micro = Object.assign((value) => value, {\n zero: 0,\n fromNano: (ns) => ns / 1e3,\n fromMilli: (ms) => ms * 1e3,\n fromSecond: (s) => s * 1e6,\n toNano: (us) => us * 1e3,\n toMilli: (us) => us / 1e3,\n toSecond: (us) => us / 1e6,\n now: () => performance.now() * 1e3,\n add: (a, b) => a + b,\n sub: (a, b) => a - b,\n mul: (a, b) => a * b,\n div: (a, b) => a / b,\n max: (a, b) => Math.max(a, b),\n min: (a, b) => Math.min(a, b)\n});\nvar Milli = Object.assign((value) => value, {\n zero: 0,\n fromNano: (ns) => ns / 1e6,\n fromMicro: (us) => us / 1e3,\n fromSecond: (s) => s * 1e3,\n toNano: (ms) => ms * 1e6,\n toMicro: (ms) => ms * 1e3,\n toSecond: (ms) => ms / 1e3,\n now: () => performance.now(),\n add: (a, b) => a + b,\n sub: (a, b) => a - b,\n mul: (a, b) => a * b,\n div: (a, b) => a / b,\n max: (a, b) => Math.max(a, b),\n min: (a, b) => Math.min(a, b)\n});\nvar Timescale = Object.assign(\n (unitsPerSecond) => {\n if (!Number.isInteger(unitsPerSecond) || unitsPerSecond <= 0) {\n throw new Error(`invalid timescale: ${unitsPerSecond}`);\n }\n return unitsPerSecond;\n },\n {\n /** One unit per second. */\n SECOND: 1,\n /** 1,000 units per second. */\n MILLI: 1e3,\n /** 1,000,000 units per second. */\n MICRO: 1e6,\n /** 1,000,000,000 units per second. */\n NANO: 1e9\n }\n);\nvar Timestamp = class _Timestamp {\n /** The raw value, in `scale` units. */\n value;\n /** Units per second the {@link value} is measured in. */\n scale;\n /** Build a timestamp of `value` units at `scale`. */\n constructor(value, scale) {\n if (!Number.isFinite(value) || value < 0) {\n throw new Error(`invalid timestamp: ${value}`);\n }\n this.value = value;\n this.scale = scale;\n }\n /** Monotonic now (`performance.now()`, milliseconds since page load), not wall-clock time. */\n static now() {\n return new _Timestamp(performance.now(), Timescale.MILLI);\n }\n /** A timestamp of `ms` milliseconds. */\n static fromMillis(ms) {\n return new _Timestamp(ms, Timescale.MILLI);\n }\n /** A timestamp of `us` microseconds. */\n static fromMicros(us) {\n return new _Timestamp(us, Timescale.MICRO);\n }\n /** This timestamp's value re-expressed at `scale` (a raw number, not a new Timestamp). */\n as(scale) {\n return scale === this.scale ? this.value : this.value * scale / this.scale;\n }\n /** The value in milliseconds. */\n asMillis() {\n return this.as(Timescale.MILLI);\n }\n /** The value in microseconds. */\n asMicros() {\n return this.as(Timescale.MICRO);\n }\n};\nvar Second = Object.assign((value) => value, {\n zero: 0,\n fromNano: (ns) => ns / 1e9,\n fromMicro: (us) => us / 1e6,\n fromMilli: (ms) => ms / 1e3,\n toNano: (s) => s * 1e9,\n toMicro: (s) => s * 1e6,\n toMilli: (s) => s * 1e3,\n now: () => performance.now() / 1e3,\n add: (a, b) => a + b,\n sub: (a, b) => a - b,\n mul: (a, b) => a * b,\n div: (a, b) => a / b,\n max: (a, b) => Math.max(a, b),\n min: (a, b) => Math.min(a, b)\n});\n\n// src/audio/ring-buffer.ts\nvar AudioRingBuffer = class {\n #buffer;\n #writeIndex = 0;\n #readIndex = 0;\n rate;\n channels;\n #stalled = true;\n // Buffered mode: anchor to the first sample, play through without skipping ahead.\n #buffered;\n // Un-stall threshold in samples (how much to buffer before playback starts).\n #latencySamples;\n // Whether the read/write indices have been anchored to the first inserted sample.\n #anchored = false;\n constructor(props) {\n if (props.channels <= 0) throw new Error(\"invalid channels\");\n if (props.rate <= 0) throw new Error(\"invalid sample rate\");\n if (props.latency <= 0) throw new Error(\"invalid latency\");\n this.#latencySamples = Math.ceil(props.rate * time_exports.Second.fromMilli(props.latency));\n if (this.#latencySamples === 0) throw new Error(\"empty buffer\");\n this.rate = props.rate;\n this.channels = props.channels;\n this.#buffered = props.buffered ?? false;\n const capacity = this.#capacityFor(this.#latencySamples);\n this.#buffer = [];\n for (let i = 0; i < this.channels; i++) {\n this.#buffer[i] = new Float32Array(capacity);\n }\n }\n #capacityFor(latencySamples) {\n return this.#buffered ? latencySamples * 2 : latencySamples;\n }\n get stalled() {\n return this.#stalled;\n }\n get timestamp() {\n return time_exports.Micro.fromSecond(this.#readIndex / this.rate);\n }\n get length() {\n return this.#writeIndex - this.#readIndex;\n }\n get capacity() {\n return this.#buffer[0]?.length;\n }\n resize(latency) {\n this.#latencySamples = Math.ceil(this.rate * time_exports.Second.fromMilli(latency));\n const newCapacity = this.#capacityFor(this.#latencySamples);\n if (newCapacity === this.capacity) return;\n if (newCapacity === 0) throw new Error(\"empty buffer\");\n const newBuffer = [];\n for (let i = 0; i < this.channels; i++) {\n newBuffer[i] = new Float32Array(newCapacity);\n }\n const samplesToKeep = Math.min(this.length, newCapacity);\n if (samplesToKeep > 0) {\n const copyStart = this.#writeIndex - samplesToKeep;\n for (let channel = 0; channel < this.channels; channel++) {\n const src = this.#buffer[channel];\n const dst = newBuffer[channel];\n for (let i = 0; i < samplesToKeep; i++) {\n const srcPos = (copyStart + i) % src.length;\n const dstPos = (copyStart + i) % dst.length;\n dst[dstPos] = src[srcPos];\n }\n }\n }\n this.#buffer = newBuffer;\n this.#readIndex = this.#writeIndex - samplesToKeep;\n if (samplesToKeep === 0) this.#stalled = true;\n }\n write(timestamp, data) {\n if (data.length !== this.channels) throw new Error(\"wrong number of channels\");\n let start = Math.round(time_exports.Second.fromMicro(timestamp) * this.rate);\n let samples = data[0].length;\n if (this.#buffered && !this.#anchored) {\n this.#readIndex = start;\n this.#writeIndex = start;\n this.#anchored = true;\n }\n let offset = this.#readIndex - start;\n if (offset > samples) {\n return;\n } else if (offset > 0) {\n samples -= offset;\n start += offset;\n } else {\n offset = 0;\n }\n const end = start + samples;\n const overflow = end - this.#readIndex - this.#buffer[0].length;\n if (overflow >= 0) {\n this.#stalled = false;\n this.#readIndex += overflow;\n }\n if (start > this.#writeIndex) {\n const gapSize = Math.min(start - this.#writeIndex, this.#buffer[0].length);\n if (gapSize === 1) {\n console.warn(\"floating point inaccuracy detected\");\n }\n for (let channel = 0; channel < this.channels; channel++) {\n const dst = this.#buffer[channel];\n for (let i = 0; i < gapSize; i++) {\n const writePos = (this.#writeIndex + i) % dst.length;\n dst[writePos] = 0;\n }\n }\n }\n for (let channel = 0; channel < this.channels; channel++) {\n let src = data[channel];\n src = src.subarray(src.length - samples);\n const dst = this.#buffer[channel];\n if (src.length !== samples) throw new Error(\"mismatching number of samples\");\n for (let i = 0; i < samples; i++) {\n const writePos = (start + i) % dst.length;\n dst[writePos] = src[i];\n }\n }\n if (end > this.#writeIndex) {\n this.#writeIndex = end;\n }\n if (this.#buffered && this.length >= this.#latencySamples) {\n this.#stalled = false;\n }\n }\n // Flush all buffered samples and re-stall, ready to anchor the next utterance.\n reset() {\n this.#readIndex = 0;\n this.#writeIndex = 0;\n this.#stalled = true;\n this.#anchored = false;\n }\n read(output) {\n if (output.length !== this.channels) throw new Error(\"wrong number of channels\");\n if (this.#stalled) return 0;\n const samples = Math.min(this.#writeIndex - this.#readIndex, output[0].length);\n if (samples === 0) return 0;\n for (let channel = 0; channel < this.channels; channel++) {\n const dst = output[channel];\n const src = this.#buffer[channel];\n if (dst.length !== output[0].length) throw new Error(\"mismatching number of samples\");\n for (let i = 0; i < samples; i++) {\n const readPos = (this.#readIndex + i) % src.length;\n dst[i] = src[readPos];\n }\n }\n this.#readIndex += samples;\n return samples;\n }\n};\n\n// src/audio/shared-ring-buffer.ts\nvar WRITE = 0;\nvar READ = 1;\nvar LATENCY = 2;\nvar STALLED = 3;\nvar CONTROL_SLOTS = 4;\nfunction allocSharedRingBuffer(channels, capacity, rate, buffered = false) {\n if (channels <= 0) throw new Error(\"invalid channels\");\n if (capacity <= 0) throw new Error(\"invalid capacity\");\n if (rate <= 0) throw new Error(\"invalid sample rate\");\n const samples = new SharedArrayBuffer(channels * capacity * Float32Array.BYTES_PER_ELEMENT);\n const control = new SharedArrayBuffer(CONTROL_SLOTS * Int32Array.BYTES_PER_ELEMENT);\n const ctrl = new Int32Array(control);\n Atomics.store(ctrl, STALLED, 1);\n return { channels, capacity, rate, samples, control, buffered };\n}\nfunction i32Max(a, b) {\n return (a - b | 0) > 0 ? a : b;\n}\nfunction slot(idx, capacity) {\n return (idx % capacity + capacity) % capacity;\n}\nfunction casAdvance(arr, idx, candidate) {\n for (; ; ) {\n const current = Atomics.load(arr, idx);\n if ((candidate - current | 0) <= 0) return current;\n const witnessed = Atomics.compareExchange(arr, idx, current, candidate);\n if (witnessed === current) return candidate;\n }\n}\nvar SharedRingBuffer = class _SharedRingBuffer {\n channels;\n capacity;\n rate;\n buffered;\n init;\n #control;\n #samples;\n // Whether READ/WRITE have been anchored to the first inserted sample (buffered mode).\n #anchored = false;\n constructor(init) {\n this.channels = init.channels;\n this.capacity = init.capacity;\n this.rate = init.rate;\n this.buffered = init.buffered;\n this.init = init;\n this.#control = new Int32Array(init.control);\n this.#samples = [];\n for (let i = 0; i < this.channels; i++) {\n this.#samples.push(\n new Float32Array(init.samples, i * this.capacity * Float32Array.BYTES_PER_ELEMENT, this.capacity)\n );\n }\n }\n /**\n * Insert audio samples at the given timestamp.\n * Main thread only. Handles out-of-order writes, gap filling, and overflow.\n */\n insert(timestamp, data) {\n if (data.length !== this.channels) throw new Error(\"wrong number of channels\");\n let start = Math.round(time_exports.Second.fromMicro(timestamp) * this.rate);\n const originalLength = data[0].length;\n let offset = 0;\n if (this.buffered && !this.#anchored) {\n Atomics.store(this.#control, READ, start | 0);\n Atomics.store(this.#control, WRITE, start | 0);\n this.#anchored = true;\n }\n const end = start + originalLength | 0;\n const read = Atomics.load(this.#control, READ);\n const behind = read - start | 0;\n if (behind > 0) {\n if (behind >= originalLength) {\n return;\n }\n offset = behind;\n start = start + behind | 0;\n }\n const samples = originalLength - offset;\n if ((end - read | 0) > this.capacity) {\n casAdvance(this.#control, READ, end - this.capacity | 0);\n }\n const write = Atomics.load(this.#control, WRITE);\n const gap = start - write | 0;\n if (gap > 0) {\n const gapSize = Math.min(gap, this.capacity);\n for (let channel = 0; channel < this.channels; channel++) {\n const dst = this.#samples[channel];\n for (let i = 0; i < gapSize; i++) {\n dst[slot(write + i | 0, this.capacity)] = 0;\n }\n }\n }\n for (let channel = 0; channel < this.channels; channel++) {\n const src = data[channel];\n const dst = this.#samples[channel];\n for (let i = 0; i < samples; i++) {\n dst[slot(start + i | 0, this.capacity)] = src[offset + i];\n }\n }\n Atomics.store(this.#control, WRITE, i32Max(Atomics.load(this.#control, WRITE), end));\n const currentRead = Atomics.load(this.#control, READ);\n const currentWrite = Atomics.load(this.#control, WRITE);\n const latency = Atomics.load(this.#control, LATENCY);\n if ((currentWrite - currentRead | 0) >= latency && latency > 0) {\n Atomics.store(this.#control, STALLED, 0);\n }\n }\n /**\n * Read audio samples into the output buffers.\n * AudioWorklet only. Returns the number of samples read.\n */\n read(output) {\n if (Atomics.load(this.#control, STALLED) === 1) return 0;\n let read = Atomics.load(this.#control, READ);\n const write = Atomics.load(this.#control, WRITE);\n const latency = Atomics.load(this.#control, LATENCY);\n const buffered = write - read | 0;\n if (!this.buffered && latency > 0 && buffered > latency) {\n const skipTo = write - latency | 0;\n read = casAdvance(this.#control, READ, skipTo);\n }\n const available = write - read | 0;\n const count = Math.min(available, output[0].length);\n if (count <= 0) return 0;\n for (let channel = 0; channel < this.channels; channel++) {\n const src = this.#samples[channel];\n const dst = output[channel];\n for (let i = 0; i < count; i++) {\n dst[i] = src[slot(read + i | 0, this.capacity)];\n }\n }\n casAdvance(this.#control, READ, read + count | 0);\n return count;\n }\n /** Update the target latency in samples. */\n setLatency(samples) {\n Atomics.store(this.#control, LATENCY, samples);\n }\n /**\n * Flush buffered samples and re-stall, ready to anchor the next utterance (buffered mode).\n * Main thread only. The worklet reader sees STALLED and stops until the next insert.\n */\n reset() {\n this.#anchored = false;\n Atomics.store(this.#control, STALLED, 1);\n const write = Atomics.load(this.#control, WRITE);\n Atomics.store(this.#control, READ, write);\n }\n /**\n * Allocate a new ring with `newCapacity` samples and copy the unread window\n * [READ, WRITE) plus control state into it. Used when growing capacity so\n * we don't drop buffered audio. If `newCapacity` is smaller than the unread\n * span, the oldest samples are truncated.\n *\n * Main thread only. `resize()` reads from the source `SharedRingBuffer` and\n * writes into a freshly allocated buffer from `allocSharedRingBuffer`, so it\n * relies on the same invariant as `insert()`: no concurrent main-thread\n * writers. The AudioWorklet reader is tolerated via the CAS discipline used\n * by READ/WRITE elsewhere.\n */\n resize(newCapacity) {\n const init = allocSharedRingBuffer(this.channels, newCapacity, this.rate, this.buffered);\n const dst = new _SharedRingBuffer(init);\n dst.#anchored = this.#anchored;\n const read = Atomics.load(this.#control, READ);\n const write = Atomics.load(this.#control, WRITE);\n const latency = Atomics.load(this.#control, LATENCY);\n const stalled = Atomics.load(this.#control, STALLED);\n const available = write - read | 0;\n const copyCount = Math.max(0, Math.min(available, dst.capacity));\n const copyStart = write - copyCount | 0;\n for (let channel = 0; channel < this.channels; channel++) {\n const src = this.#samples[channel];\n const out = dst.#samples[channel];\n for (let i = 0; i < copyCount; i++) {\n const idx = copyStart + i | 0;\n out[slot(idx, dst.capacity)] = src[slot(idx, this.capacity)];\n }\n }\n Atomics.store(dst.#control, READ, copyStart);\n Atomics.store(dst.#control, WRITE, write);\n Atomics.store(dst.#control, LATENCY, latency);\n Atomics.store(dst.#control, STALLED, stalled);\n return dst;\n }\n /** Current playback timestamp derived from READ position. */\n get timestamp() {\n const read = Atomics.load(this.#control, READ);\n return time_exports.Micro.fromSecond(read / this.rate);\n }\n /** Whether the buffer is stalled (waiting to fill). */\n get stalled() {\n return Atomics.load(this.#control, STALLED) === 1;\n }\n /**\n * Number of buffered samples (WRITE - READ).\n *\n * Non-atomic: WRITE and READ are loaded separately, so a concurrent\n * writer/reader can make the two loads inconsistent. Intended for\n * tests and diagnostics, not control-flow decisions.\n */\n get length() {\n return Atomics.load(this.#control, WRITE) - Atomics.load(this.#control, READ) | 0;\n }\n};\n\n// src/audio/render-worklet.ts\nvar Render = class extends AudioWorkletProcessor {\n // Set after init, depending on which path the main thread chose.\n #backend;\n #underflow = 0;\n #stateCounter = 0;\n constructor() {\n super();\n this.port.onmessage = (event) => {\n const msg = event.data;\n if (msg.type === \"init-shared\") {\n console.log(\"[audio-worklet] init-shared: using SharedArrayBuffer path\");\n this.#backend = new SharedRingBuffer(msg);\n this.#underflow = 0;\n } else if (msg.type === \"init-post\") {\n console.log(\"[audio-worklet] init-post: using postMessage path\");\n this.#backend = new AudioRingBuffer(msg);\n this.#underflow = 0;\n } else if (msg.type === \"data\") {\n if (this.#backend instanceof AudioRingBuffer) this.#backend.write(msg.timestamp, msg.data);\n } else if (msg.type === \"latency\") {\n if (this.#backend instanceof AudioRingBuffer) this.#backend.resize(msg.latency);\n } else if (msg.type === \"reset\") {\n if (this.#backend instanceof AudioRingBuffer) this.#backend.reset();\n }\n };\n }\n process(_inputs, outputs, _parameters) {\n const output = outputs[0];\n const backend = this.#backend;\n const samplesRead = backend?.read(output) ?? 0;\n if (samplesRead < output[0].length) {\n this.#underflow += output[0].length - samplesRead;\n } else if (this.#underflow > 0 && backend) {\n console.debug(`audio underflow: ${Math.round(1e3 * this.#underflow / backend.rate)}ms`);\n this.#underflow = 0;\n }\n if (backend instanceof AudioRingBuffer) {\n this.#stateCounter++;\n if (this.#stateCounter >= 5) {\n this.#stateCounter = 0;\n const state = {\n type: \"state\",\n timestamp: backend.timestamp,\n stalled: backend.stalled\n };\n this.port.postMessage(state);\n }\n }\n return true;\n }\n};\nregisterProcessor(\"render\", Render);\n"], { type: "application/javascript" }), ee = URL.createObjectURL(k);
263
+ //#endregion
264
+ //#region src/audio/unlock.ts
265
+ function te(e, t) {
266
+ let n = new r(t.state === "running");
267
+ e.event(t, "statechange", () => n.set(t.state === "running")), e.run((e) => {
268
+ if (e.get(n)) return;
269
+ let r = () => {
270
+ t.resume().catch(() => {});
271
+ };
272
+ r(), e.event(document, "pointerdown", r), e.event(document, "keydown", r);
273
+ });
274
+ }
275
+ //#endregion
276
+ //#region src/audio/decoder.ts
277
+ var A = class {
278
+ in;
279
+ source;
280
+ sync;
281
+ #e = {
282
+ context: new r(void 0),
283
+ root: new r(void 0),
284
+ sampleRate: new r(void 0),
285
+ stats: new r(void 0),
286
+ timestamp: new r(void 0),
287
+ stalled: new r(!0),
288
+ buffered: new r([])
289
+ };
290
+ out = a(this.#e);
291
+ #t = new r([]);
292
+ #n;
293
+ #r = new r(void 0);
294
+ #i = 0;
295
+ #a = new r(t.Milli.zero);
296
+ #o = new n();
297
+ constructor(e, t, n) {
298
+ this.in = { enabled: i(n?.enabled ?? !1) }, this.source = e, this.sync = t, this.#o.run((e) => {
299
+ this.#a.set(e.get(this.sync.out.maxBuffer));
300
+ }), this.#o.run(this.#s.bind(this)), this.#o.run(this.#c.bind(this)), this.#o.run(this.#l.bind(this)), this.#o.run(this.#u.bind(this));
301
+ }
302
+ #s(e) {
303
+ let n = e.get(this.source.out.config);
304
+ if (!n) return;
305
+ let r = e.get(this.#r) ?? n.sampleRate, i = n.numberOfChannels;
306
+ e.set(this.#e.sampleRate, r);
307
+ let a = new AudioContext({
308
+ latencyHint: "interactive",
309
+ sampleRate: r
310
+ });
311
+ e.set(this.#e.context, a), e.cleanup(() => a.close()), e.spawn(async () => {
312
+ if (!await Promise.race([a.audioWorklet.addModule(ee).then(() => !0), e.cancel])) return;
313
+ let n = new AudioWorkletNode(a, "render", {
314
+ channelCount: i,
315
+ channelCountMode: "explicit",
316
+ outputChannelCount: [i]
317
+ });
318
+ e.cleanup(() => n.disconnect());
319
+ let o = this.sync.out.buffer.peek(), s = Math.ceil(r * t.Second.fromMilli(o)), c = this.sync.out.buffered.peek(), l = E(n, i, r, s, c);
320
+ this.#n = l, e.cleanup(() => {
321
+ l.close(), this.#n = void 0;
322
+ }), e.run((e) => {
323
+ let n = t.Milli.fromMicro(e.get(l.timestamp));
324
+ this.#e.timestamp.set(n), this.#h(n);
325
+ }), e.run((e) => {
326
+ this.#e.stalled.set(e.get(l.stalled));
327
+ }), e.set(this.#e.root, n);
328
+ });
329
+ }
330
+ #c(e) {
331
+ if (!e.get(this.in.enabled)) return;
332
+ let t = e.get(this.#e.context);
333
+ t && te(e, t);
334
+ }
335
+ #l(e) {
336
+ if (!e.get(this.#e.root)) return;
337
+ let n = this.#n;
338
+ if (!n) return;
339
+ let r = e.get(this.sync.out.buffer), i = Math.ceil(n.rate * t.Second.fromMilli(r));
340
+ n.setLatency(i);
341
+ }
342
+ #u(e) {
343
+ if (!e.get(this.in.enabled)) return;
344
+ let t = e.get(this.source.in.broadcast);
345
+ if (!t) return;
346
+ let n = e.get(this.source.out.track);
347
+ if (!n) return;
348
+ let r = e.get(this.source.out.config);
349
+ if (!r) return;
350
+ let i = t.relativeBroadcast(e, r.broadcast);
351
+ if (!i) return;
352
+ let a = i.track(n).subscribe({ priority: o.PRIORITY.audio });
353
+ e.cleanup(() => a.close()), r.container.kind === "cmaf" ? this.#f(e, a, r) : this.#d(e, a, r);
354
+ }
355
+ #d(e, n, r) {
356
+ let i = r.container.kind === "loc" ? new c.Loc.Format() : new c.Legacy.Format(), a = new c.Consumer(n, {
357
+ format: i,
358
+ latency: this.#a
359
+ });
360
+ e.cleanup(() => a.close()), e.run((e) => {
361
+ let t = e.get(a.buffered), n = e.get(this.#t);
362
+ this.#e.buffered.update(() => c.mergeBufferedRanges(t, n));
363
+ }), e.spawn(async () => {
364
+ if (!await l.Libav.polyfill()) return;
365
+ let n = 0, i = new AudioDecoder({
366
+ output: (e) => {
367
+ if (n++, n <= 3) {
368
+ e.close();
369
+ return;
370
+ }
371
+ this.#p(e);
372
+ },
373
+ error: (e) => console.error("audio decoder error", e)
374
+ });
375
+ e.cleanup(() => {
376
+ i.state !== "closed" && i.close();
377
+ });
378
+ let o = r.codec === "opus" ? void 0 : r.description ? l.Hex.toBytes(r.description) : void 0;
379
+ for (i.configure({
380
+ ...r,
381
+ description: o
382
+ });;) {
383
+ let e = await a.next();
384
+ if (!e) break;
385
+ this.#g(e.discontinuity);
386
+ let { frame: n } = e;
387
+ if (!n) continue;
388
+ let r = t.Milli.fromMicro(n.timestamp);
389
+ this.sync.received(r, "audio"), this.#e.stats.update((e) => ({ bytesReceived: (e?.bytesReceived ?? 0) + n.payload.byteLength })), await this.#n?.wait(n.timestamp);
390
+ let o = new EncodedAudioChunk({
391
+ type: n.keyframe ? "key" : "delta",
392
+ data: n.payload,
393
+ timestamp: n.timestamp
394
+ });
395
+ if (i.state === "closed") break;
396
+ i.decode(o);
397
+ }
398
+ });
399
+ }
400
+ #f(e, n, r) {
401
+ if (r.container.kind !== "cmaf") return;
402
+ let i = f(r.container.init), a = c.Cmaf.decodeInitSegment(i), o = r.codec === "opus" ? void 0 : r.description ? l.Hex.toBytes(r.description) : a.description, s = new c.Consumer(n, {
403
+ format: new c.Cmaf.Format(a),
404
+ latency: this.#a
405
+ });
406
+ e.cleanup(() => s.close()), e.run((e) => {
407
+ let t = e.get(s.buffered), n = e.get(this.#t);
408
+ this.#e.buffered.update(() => c.mergeBufferedRanges(t, n));
409
+ }), e.spawn(async () => {
410
+ if (!await l.Libav.polyfill()) return;
411
+ let n = new AudioDecoder({
412
+ output: (e) => this.#p(e),
413
+ error: (e) => console.error("audio decoder error", e)
414
+ });
415
+ for (e.cleanup(() => {
416
+ n.state !== "closed" && n.close();
417
+ }), n.configure({
418
+ codec: r.codec,
419
+ sampleRate: r.sampleRate,
420
+ numberOfChannels: r.numberOfChannels,
421
+ description: o
422
+ });;) {
423
+ let e = await s.next();
424
+ if (!e) break;
425
+ this.#g(e.discontinuity);
426
+ let { frame: r } = e;
427
+ if (!r) continue;
428
+ let i = t.Milli.fromMicro(r.timestamp);
429
+ if (this.sync.received(i, "audio"), this.#e.stats.update((e) => ({ bytesReceived: (e?.bytesReceived ?? 0) + r.payload.byteLength })), await this.#n?.wait(r.timestamp), n.state === "closed") break;
430
+ n.decode(new EncodedAudioChunk({
431
+ type: r.keyframe ? "key" : "delta",
432
+ data: r.payload,
433
+ timestamp: r.timestamp
434
+ }));
435
+ }
436
+ });
437
+ }
438
+ #p(e) {
439
+ let n = e.timestamp, r = t.Milli.fromMicro(n), i = this.#n;
440
+ if (!i) {
441
+ e.close();
442
+ return;
443
+ }
444
+ if (e.sampleRate !== i.rate) {
445
+ this.#r.set(e.sampleRate), e.close();
446
+ return;
447
+ }
448
+ let a = e.numberOfFrames / e.sampleRate * 1e6, o = t.Milli.fromMicro(a), s = t.Milli.add(r, o);
449
+ this.#m(r, s);
450
+ let c = Math.min(e.numberOfChannels, i.channels), l = [];
451
+ for (let t = 0; t < c; t++) {
452
+ let n = new Float32Array(e.numberOfFrames);
453
+ e.copyTo(n, {
454
+ format: "f32-planar",
455
+ planeIndex: t
456
+ }), l.push(n);
457
+ }
458
+ i.insert(n, l), e.close();
459
+ }
460
+ #m(e, n) {
461
+ e > n || this.#t.mutate((r) => {
462
+ for (let i of r) if (e <= i.end + 1 && n >= i.start) {
463
+ i.start = t.Milli.min(i.start, e), i.end = t.Milli.max(i.end, n);
464
+ return;
465
+ }
466
+ r.push({
467
+ start: e,
468
+ end: n
469
+ }), r.sort((e, t) => e.start - t.start);
470
+ });
471
+ }
472
+ #h(e) {
473
+ this.#t.mutate((n) => {
474
+ for (; n.length > 0;) {
475
+ if (n[0].end >= e) {
476
+ n[0].start = t.Milli.max(n[0].start, e);
477
+ break;
478
+ }
479
+ n.shift();
480
+ }
481
+ });
482
+ }
483
+ reset() {
484
+ this.#n?.reset();
485
+ }
486
+ #g(e) {
487
+ e !== this.#i && (this.#i = e, this.#n?.reset(), this.sync.reset());
488
+ }
489
+ close() {
490
+ this.#o.close();
491
+ }
492
+ static supported = j;
493
+ };
494
+ async function j(e) {
495
+ if (!o.containerSupported(e.container)) {
496
+ let t = e.container.kind === "unknown" ? e.container.raw.kind : e.container.kind;
497
+ return console.warn(`audio: ignoring rendition with unknown container: ${t}`), !1;
498
+ }
499
+ e.codec === "opus" && !l.Opus.supportsRate(e.sampleRate) && console.warn(`audio: opus advertised at ${e.sampleRate}Hz, which some browsers cannot decode`);
500
+ let t;
501
+ if (e.codec !== "opus") {
502
+ if (e.description) t = l.Hex.toBytes(e.description);
503
+ else if (e.container.kind === "cmaf") try {
504
+ t = c.Cmaf.decodeInitSegment(f(e.container.init)).description;
505
+ } catch (t) {
506
+ return console.warn(`audio: malformed CMAF init segment for codec ${e.codec}`, t), !1;
507
+ }
508
+ }
509
+ return (await AudioDecoder.isConfigSupported({
510
+ ...e,
511
+ description: t
512
+ })).supported ?? !1;
513
+ }
514
+ //#endregion
515
+ //#region src/audio/emitter.ts
516
+ var M = .001, N = .2, P = class {
517
+ source;
518
+ in;
519
+ #e = { enabled: new r(!1) };
520
+ out = a(this.#e);
521
+ #t = new n();
522
+ #n = new r(void 0);
523
+ constructor(e, t) {
524
+ this.source = e, this.in = {
525
+ volume: i(t?.volume ?? .5),
526
+ muted: i(t?.muted ?? !1),
527
+ paused: i(t?.paused ?? !1)
528
+ }, this.#t.run((e) => {
529
+ let t = !e.get(this.in.paused) && !e.get(this.in.muted);
530
+ this.#e.enabled.set(t);
531
+ }), this.#t.run((e) => {
532
+ let t = e.get(this.source.out.root);
533
+ if (!t) return;
534
+ let n = new GainNode(t.context, { gain: e.get(this.in.volume) });
535
+ t.connect(n), e.set(this.#n, n), e.run((e) => {
536
+ e.get(this.#e.enabled) && (n.connect(t.context.destination), e.cleanup(() => n.disconnect()));
537
+ });
538
+ }), this.#t.run((e) => {
539
+ let t = e.get(this.#n);
540
+ if (!t) return;
541
+ e.cleanup(() => t.gain.cancelScheduledValues(t.context.currentTime));
542
+ let n = e.get(this.in.volume);
543
+ n < M ? (t.gain.exponentialRampToValueAtTime(M, t.context.currentTime + N), t.gain.setValueAtTime(0, t.context.currentTime + N + .01)) : t.gain.exponentialRampToValueAtTime(n, t.context.currentTime + N);
544
+ });
545
+ }
546
+ close() {
547
+ this.#t.close();
548
+ }
549
+ }, F = 128, I = class {
550
+ in;
551
+ #e = {
552
+ catalog: new r(void 0),
553
+ available: new r({}),
554
+ track: new r(void 0),
555
+ config: new r(void 0),
556
+ jitter: new r(void 0)
557
+ };
558
+ out = a(this.#e);
559
+ #t = new n();
560
+ constructor(e) {
561
+ this.in = {
562
+ broadcast: i(e?.broadcast),
563
+ target: i(e?.target),
564
+ supported: i(e?.supported)
565
+ }, this.#t.run(this.#n.bind(this)), this.#t.run(this.#r.bind(this)), this.#t.run(this.#i.bind(this));
566
+ }
567
+ #n(e) {
568
+ let t = e.get(this.in.broadcast);
569
+ if (!t) return;
570
+ let n = e.get(t.out.catalog)?.audio;
571
+ n && e.set(this.#e.catalog, n);
572
+ }
573
+ #r(e) {
574
+ let t = e.get(this.#e.catalog)?.renditions ?? {}, n = e.get(this.in.supported);
575
+ n && e.spawn(async () => {
576
+ let e = {};
577
+ for (let [r, i] of Object.entries(t)) await n(i) && (e[r] = i);
578
+ Object.keys(e).length === 0 && Object.keys(t).length > 0 && console.warn("no supported audio renditions found:", t), this.#e.available.set(e);
579
+ });
580
+ }
581
+ #i(e) {
582
+ let n = e.get(this.#e.available);
583
+ if (Object.keys(n).length === 0) return;
584
+ let r = e.get(this.in.target), i;
585
+ if (r?.name && r.name in n) i = {
586
+ track: r.name,
587
+ config: n[r.name]
588
+ };
589
+ else if (i = this.#a(n), !i) return;
590
+ e.set(this.#e.track, i.track), e.set(this.#e.config, i.config);
591
+ let a = (i.config.jitter ?? L(i.config) ?? 0) + Math.ceil(F / i.config.sampleRate * 1e3);
592
+ e.set(this.#e.jitter, t.Milli(a));
593
+ }
594
+ #a(e) {
595
+ let t = Object.entries(e);
596
+ if (t.length !== 0) {
597
+ for (let [e, n] of t) if (n.container.kind === "legacy") return {
598
+ track: e,
599
+ config: n
600
+ };
601
+ for (let [e, n] of t) if (n.container.kind === "loc") return {
602
+ track: e,
603
+ config: n
604
+ };
605
+ for (let [e, n] of t) if (n.container.kind === "cmaf") return {
606
+ track: e,
607
+ config: n
608
+ };
609
+ }
610
+ }
611
+ close() {
612
+ this.#t.close();
613
+ }
614
+ };
615
+ function L(e) {
616
+ if (e.codec.startsWith("opus")) return 20;
617
+ if (e.codec.startsWith("mp4a")) return Math.ceil(1024 / e.sampleRate * 1e3);
618
+ if (e.codec === "mp3") {
619
+ let t = e.sampleRate >= 32e3 ? 1152 : 576;
620
+ return Math.ceil(t / e.sampleRate * 1e3);
621
+ }
622
+ }
623
+ //#endregion
624
+ //#region src/msf.ts
625
+ var R = 48e3, z = 2;
626
+ function B(e) {
627
+ let t = "";
628
+ for (let n = 0; n < e.length; n++) t += e[n].toString(16).padStart(2, "0");
629
+ return t;
630
+ }
631
+ function V(e) {
632
+ let t;
633
+ try {
634
+ t = e.initData ? f(e.initData) : void 0;
635
+ } catch {
636
+ t = void 0;
637
+ }
638
+ return e.packaging === "cmaf" && e.initData && t ? {
639
+ container: {
640
+ kind: "cmaf",
641
+ init: e.initData
642
+ },
643
+ description: void 0
644
+ } : {
645
+ container: { kind: "legacy" },
646
+ description: t ? B(t) : void 0
647
+ };
648
+ }
649
+ function H(e) {
650
+ if (!e.codec) return;
651
+ let { container: t, description: n } = V(e);
652
+ return {
653
+ codec: e.codec,
654
+ container: t,
655
+ description: n,
656
+ codedWidth: e.width == null ? void 0 : s(e.width),
657
+ codedHeight: e.height == null ? void 0 : s(e.height),
658
+ framerate: e.framerate,
659
+ bitrate: e.bitrate == null ? void 0 : s(e.bitrate),
660
+ jitter: e.jitter == null ? void 0 : s(e.jitter)
661
+ };
662
+ }
663
+ function U(e) {
664
+ if (!e.codec) return;
665
+ let t = (() => {
666
+ if (!e.channelConfig) return z;
667
+ let t = Number.parseInt(e.channelConfig, 10);
668
+ return Number.isFinite(t) ? t : z;
669
+ })(), { container: n, description: r } = V(e);
670
+ return {
671
+ codec: e.codec,
672
+ container: n,
673
+ description: r,
674
+ sampleRate: s(e.samplerate ?? R),
675
+ numberOfChannels: s(t),
676
+ bitrate: e.bitrate == null ? void 0 : s(e.bitrate),
677
+ jitter: e.jitter == null ? void 0 : s(e.jitter)
678
+ };
679
+ }
680
+ function W(e) {
681
+ let t = {}, n = {};
682
+ for (let r of e.tracks) if (r.role === "video") {
683
+ let e = H(r);
684
+ e && (t[r.name] = e);
685
+ } else if (r.role === "audio") {
686
+ let e = U(r);
687
+ e && (n[r.name] = e);
688
+ }
689
+ let r = {};
690
+ return Object.keys(t).length > 0 && (r.video = { renditions: t }), Object.keys(n).length > 0 && (r.audio = { renditions: n }), r;
691
+ }
692
+ //#endregion
693
+ //#region src/broadcast.ts
694
+ var G = /* @__PURE__ */ new WeakSet();
695
+ function K(e) {
696
+ return e.discovery ? !1 : (G.has(e) || (G.add(e), console.warn("relay does not support broadcast discovery; ignoring reload signal.")), !0);
697
+ }
698
+ var q = [
699
+ ...o.FORMATS,
700
+ "hangz",
701
+ "manual"
702
+ ];
703
+ function J(e) {
704
+ if (e !== null) return q.find((t) => t === e);
705
+ }
706
+ var Y = class {
707
+ in;
708
+ #e = {
709
+ status: new r("offline"),
710
+ active: new r(void 0),
711
+ catalog: new r(void 0)
712
+ };
713
+ out = a(this.#e);
714
+ #t = new r(void 0);
715
+ #n = new r(!1);
716
+ #r = new n();
717
+ constructor(t) {
718
+ this.in = {
719
+ connection: i(t?.connection),
720
+ name: i(t?.name ?? e.empty()),
721
+ enabled: i(t?.enabled ?? !1),
722
+ reload: i(t?.reload ?? !0),
723
+ catalogFormat: i(t?.catalogFormat),
724
+ catalog: i(t?.catalog)
725
+ }, this.#r.run(this.#i.bind(this)), this.#r.run(this.#o.bind(this)), this.#r.run(this.#s.bind(this));
726
+ }
727
+ #i(t) {
728
+ if (this.#t.set(void 0), !t.get(this.#n) || !t.get(this.in.reload)) return;
729
+ let n = t.get(this.in.connection);
730
+ if (!n || K(n)) return;
731
+ let r = n.announced(e.empty());
732
+ t.cleanup(() => r.close()), this.#t.set(/* @__PURE__ */ new Set()), t.spawn(async () => {
733
+ for (;;) {
734
+ let e = await Promise.race([t.cancel, r.next()]);
735
+ if (!e) break;
736
+ this.#t.mutate((t) => {
737
+ t && (e.active ? t.add(e.path) : t.delete(e.path));
738
+ });
739
+ }
740
+ });
741
+ }
742
+ #a(e, t) {
743
+ if (!e.get(this.in.reload)) return !0;
744
+ let n = e.get(this.in.connection);
745
+ if (n && K(n)) return !0;
746
+ this.#n.set(!0);
747
+ let r = e.get(this.#t);
748
+ return r ? r.has(t) : !1;
749
+ }
750
+ #o(t) {
751
+ if (!t.get(this.in.enabled)) return;
752
+ let n = t.get(this.in.connection);
753
+ if (!n) return;
754
+ let r = t.get(this.in.name);
755
+ if (!t.get(this.in.reload) || K(n)) {
756
+ let e = n.consume(r);
757
+ t.cleanup(() => e.close()), t.set(this.#e.active, e, void 0);
758
+ return;
759
+ }
760
+ let i = n.announced(r);
761
+ t.cleanup(() => i.close());
762
+ let a;
763
+ t.cleanup(() => {
764
+ a?.close(), a = void 0, this.#e.active.set(void 0);
765
+ }), t.spawn(async () => {
766
+ for (;;) {
767
+ let o = await Promise.race([t.cancel, i.next()]);
768
+ if (!o) break;
769
+ if (o.path === e.empty()) if (o.active) {
770
+ if (a && a.closed.peek() === void 0) continue;
771
+ a?.close(), a = n.consume(r), this.#e.active.set(a);
772
+ } else a?.close(), a = void 0, this.#e.active.set(void 0);
773
+ }
774
+ });
775
+ }
776
+ #s(e) {
777
+ if (!e.get(this.in.enabled)) return;
778
+ let t = e.get(this.in.catalogFormat), n = e.get(this.in.name), r = t ?? o.detectFormat(n) ?? o.DEFAULT_FORMAT;
779
+ if (r === "manual") {
780
+ let t = e.get(this.in.catalog);
781
+ e.set(this.#e.catalog, t, void 0), this.#e.status.set(t ? "live" : "loading");
782
+ return;
783
+ }
784
+ let i = e.get(this.out.active);
785
+ if (!i) return;
786
+ this.#e.status.set("loading");
787
+ let a = r === "hang" ? o.TRACK : r === "hangz" ? o.TRACK_COMPRESSED : "catalog", s = i.track(a).subscribe({ priority: o.PRIORITY.catalog });
788
+ e.cleanup(() => s.close());
789
+ let c;
790
+ if (r === "hang" || r === "hangz") {
791
+ let e = new u.Snapshot.Consumer(s, {
792
+ schema: o.RootSchema,
793
+ compression: r === "hangz"
794
+ });
795
+ c = () => e.next();
796
+ } else c = async () => {
797
+ let e = await d.fetch(s);
798
+ return e ? W(e) : void 0;
799
+ };
800
+ e.spawn(async () => {
801
+ try {
802
+ for (;;) {
803
+ let t = await Promise.race([e.cancel, c()]);
804
+ if (!t) break;
805
+ console.debug("received catalog", r, this.in.name.peek(), t), this.#e.catalog.set(t), this.#e.status.set("live");
806
+ }
807
+ } catch (e) {
808
+ console.warn("error fetching catalog", this.in.name.peek(), e);
809
+ } finally {
810
+ this.#e.catalog.set(void 0), this.#e.status.set("offline");
811
+ }
812
+ });
813
+ }
814
+ relativeBroadcast(t, n) {
815
+ if (!n) return t.get(this.out.active);
816
+ let r = t.get(this.in.name), i = e.resolve(r, n);
817
+ if (i === r || i === e.empty()) return t.get(this.out.active);
818
+ if (!t.get(this.in.enabled)) return;
819
+ let a = t.get(this.in.connection);
820
+ if (!a || !this.#a(t, i)) return;
821
+ let o = a.consume(i);
822
+ return t.cleanup(() => o.close()), o;
823
+ }
824
+ close() {
825
+ this.#r.close();
826
+ }
827
+ }, X = t.Milli(500), Z = t.Milli(100), ne = class {
828
+ in;
829
+ source;
830
+ sync;
831
+ #e = {
832
+ frame: new r(void 0),
833
+ timestamp: new r(void 0),
834
+ display: new r(void 0),
835
+ stalled: new r(!1),
836
+ stats: new r(void 0),
837
+ buffered: new r([])
838
+ };
839
+ out = a(this.#e);
840
+ #t = new r(void 0);
841
+ #n = new n();
842
+ #r() {
843
+ this.#e.frame.update((e) => {
844
+ e?.close();
845
+ }), this.#e.timestamp.set(void 0);
846
+ }
847
+ constructor(e, t, n) {
848
+ this.in = { enabled: i(n?.enabled ?? !1) }, this.source = e, this.sync = t, this.#n.run(this.#i.bind(this)), this.#n.run(this.#a.bind(this)), this.#n.run(this.#o.bind(this)), this.#n.run(this.#s.bind(this));
849
+ }
850
+ #i(e) {
851
+ let t = e.getAll([
852
+ this.in.enabled,
853
+ this.source.in.broadcast,
854
+ this.source.out.track,
855
+ this.source.out.config
856
+ ]);
857
+ if (!t) {
858
+ this.#t.set(void 0);
859
+ return;
860
+ }
861
+ let [n, r, i, a] = t, o = r.relativeBroadcast(e, a.broadcast);
862
+ if (!o) {
863
+ this.#t.set(void 0), this.#r(), this.#e.buffered.set([]);
864
+ return;
865
+ }
866
+ let s = new re({
867
+ sync: this.sync,
868
+ broadcast: o,
869
+ track: i,
870
+ config: a,
871
+ stats: this.#e.stats
872
+ });
873
+ e.cleanup(() => s?.close()), e.run((e) => {
874
+ if (!s) return;
875
+ let t = e.get(this.#t);
876
+ if (t) {
877
+ let n = e.get(s.timestamp), r = e.get(t.timestamp);
878
+ if (!n || r && r > n + Z) return;
879
+ }
880
+ this.#t.set(s), s = void 0, e.close();
881
+ });
882
+ }
883
+ #a(e) {
884
+ let t = e.get(this.#t);
885
+ if (!t) {
886
+ this.#e.buffered.set([]);
887
+ return;
888
+ }
889
+ e.cleanup(() => t.close()), e.run((e) => {
890
+ let n = e.get(t.frame);
891
+ this.#e.frame.update((e) => (e?.close(), n?.clone()));
892
+ }), e.proxy(this.#e.timestamp, t.timestamp), e.proxy(this.#e.buffered, t.buffered);
893
+ }
894
+ #o(e) {
895
+ let t = e.get(this.source.out.catalog);
896
+ if (!t) return;
897
+ let n = t.display;
898
+ if (n) {
899
+ e.set(this.#e.display, {
900
+ width: n.width,
901
+ height: n.height
902
+ });
903
+ return;
904
+ }
905
+ let r = e.get(this.#e.frame);
906
+ r && e.set(this.#e.display, {
907
+ width: r.displayWidth,
908
+ height: r.displayHeight
909
+ });
910
+ }
911
+ #s(e) {
912
+ if (e.get(this.in.enabled)) {
913
+ if (!e.get(this.#e.frame)) {
914
+ this.#e.stalled.set(!0);
915
+ return;
916
+ }
917
+ this.#e.stalled.set(!1), e.timer(() => {
918
+ this.#e.stalled.set(!0);
919
+ }, X);
920
+ }
921
+ }
922
+ close() {
923
+ this.#r(), this.#n.close();
924
+ }
925
+ static supported = ie;
926
+ }, re = class {
927
+ sync;
928
+ broadcast;
929
+ track;
930
+ config;
931
+ stats;
932
+ timestamp = new r(void 0);
933
+ frame = new r(void 0);
934
+ buffered = new r([]);
935
+ #e = new r([]);
936
+ #t = 0;
937
+ #n = new n();
938
+ constructor(e) {
939
+ let { codedWidth: t, codedHeight: n, ...r } = e.config;
940
+ this.sync = e.sync, this.broadcast = e.broadcast, this.track = e.track, this.config = r, this.stats = e.stats, this.#n.run(this.#r.bind(this));
941
+ }
942
+ #r(e) {
943
+ let n = this.broadcast.track(this.track).subscribe({ priority: o.PRIORITY.video });
944
+ e.cleanup(() => n.close());
945
+ let r = new VideoDecoder({
946
+ output: async (n) => {
947
+ try {
948
+ let r = this.#t, i = t.Milli.fromMicro(n.timestamp);
949
+ if (i < (this.timestamp.peek() ?? 0)) return;
950
+ this.frame.peek() === void 0 && this.frame.set(n.clone());
951
+ let a = this.sync.wait(i).then(() => !0);
952
+ if (!await Promise.race([a, e.cancel]) || r !== this.#t || i < (this.timestamp.peek() ?? 0)) return;
953
+ this.timestamp.set(i), this.#c(i), this.frame.update((e) => (e?.close(), n.clone()));
954
+ } finally {
955
+ n.close();
956
+ }
957
+ },
958
+ error: (t) => {
959
+ console.error(t), e.close();
960
+ }
961
+ });
962
+ e.cleanup(() => {
963
+ r.state !== "closed" && r.close();
964
+ }), this.config.container.kind === "cmaf" ? this.#a(e, n, r) : this.#i(e, n, r);
965
+ }
966
+ #i(e, n, r) {
967
+ let i = this.config.container.kind === "loc" ? new c.Loc.Format() : new c.Legacy.Format(), a = new c.Consumer(n, {
968
+ format: i,
969
+ latency: this.sync.out.buffer
970
+ });
971
+ e.cleanup(() => a.close()), e.run((e) => {
972
+ let t = e.get(a.buffered), n = e.get(this.#e);
973
+ this.buffered.update(() => c.mergeBufferedRanges(t, n));
974
+ }), r.configure({
975
+ ...this.config,
976
+ description: this.config.description ? l.Hex.toBytes(this.config.description) : void 0,
977
+ optimizeForLatency: this.config.optimizeForLatency ?? !0,
978
+ flip: !1
979
+ });
980
+ let o;
981
+ e.spawn(async () => {
982
+ for (;;) {
983
+ let e = await a.next();
984
+ if (!e) break;
985
+ this.#o(e.discontinuity) && (o = void 0);
986
+ let { frame: n, group: i } = e;
987
+ if (!n) {
988
+ o && (o.final = !0);
989
+ continue;
990
+ }
991
+ let s = t.Milli.fromMicro(n.timestamp);
992
+ this.sync.received(s, "video");
993
+ let c = new EncodedVideoChunk({
994
+ type: n.keyframe ? "key" : "delta",
995
+ data: n.payload,
996
+ timestamp: n.timestamp
997
+ });
998
+ this.stats.update((e) => ({
999
+ frameCount: (e?.frameCount ?? 0) + 1,
1000
+ bytesReceived: (e?.bytesReceived ?? 0) + n.payload.byteLength
1001
+ }));
1002
+ let l = o;
1003
+ if (l && (l.group === i || l.final && l.group + 1 === i)) {
1004
+ let e = t.Milli.fromMicro(l.timestamp), r = t.Milli.fromMicro(n.timestamp);
1005
+ this.#s(e, r);
1006
+ }
1007
+ o = {
1008
+ timestamp: n.timestamp,
1009
+ group: i,
1010
+ final: !1
1011
+ }, r.decode(c);
1012
+ }
1013
+ });
1014
+ }
1015
+ #a(e, n, r) {
1016
+ let i = this.config.container;
1017
+ if (i.kind !== "cmaf") return;
1018
+ let a = f(i.init), o = c.Cmaf.decodeInitSegment(a), s = this.config.description ? l.Hex.toBytes(this.config.description) : o.description, u = new c.Consumer(n, {
1019
+ format: new c.Cmaf.Format(o),
1020
+ latency: this.sync.out.buffer
1021
+ });
1022
+ e.cleanup(() => u.close()), e.run((e) => {
1023
+ let t = e.get(u.buffered), n = e.get(this.#e);
1024
+ this.buffered.update(() => c.mergeBufferedRanges(t, n));
1025
+ }), r.configure({
1026
+ codec: this.config.codec,
1027
+ description: s,
1028
+ optimizeForLatency: this.config.optimizeForLatency ?? !0,
1029
+ flip: !1
1030
+ });
1031
+ let d;
1032
+ e.spawn(async () => {
1033
+ for (;;) {
1034
+ let e = await u.next();
1035
+ if (!e) break;
1036
+ this.#o(e.discontinuity) && (d = void 0);
1037
+ let { frame: n, group: i } = e;
1038
+ if (!n) {
1039
+ d && (d.final = !0);
1040
+ continue;
1041
+ }
1042
+ let a = t.Milli.fromMicro(n.timestamp);
1043
+ this.sync.received(a, "video"), this.stats.update((e) => ({
1044
+ frameCount: (e?.frameCount ?? 0) + 1,
1045
+ bytesReceived: (e?.bytesReceived ?? 0) + n.payload.byteLength
1046
+ }));
1047
+ let o = d;
1048
+ if (o && (o.group === i || o.final && o.group + 1 === i)) {
1049
+ let e = t.Milli.fromMicro(o.timestamp), r = t.Milli.fromMicro(n.timestamp);
1050
+ this.#s(e, r);
1051
+ }
1052
+ if (d = {
1053
+ timestamp: n.timestamp,
1054
+ group: i,
1055
+ final: !1
1056
+ }, r.state === "closed") break;
1057
+ r.decode(new EncodedVideoChunk({
1058
+ type: n.keyframe ? "key" : "delta",
1059
+ data: n.payload,
1060
+ timestamp: n.timestamp
1061
+ }));
1062
+ }
1063
+ });
1064
+ }
1065
+ #o(e) {
1066
+ return e === this.#t ? !1 : (this.#t = e, this.timestamp.set(void 0), this.#e.set([]), this.sync.reset(), !0);
1067
+ }
1068
+ #s(e, n) {
1069
+ e > n || this.#e.mutate((r) => {
1070
+ for (let i of r) if (i.start <= n && i.end >= e) {
1071
+ i.start = t.Milli.min(i.start, e), i.end = t.Milli.max(i.end, n);
1072
+ return;
1073
+ }
1074
+ r.push({
1075
+ start: e,
1076
+ end: n
1077
+ }), r.sort((e, t) => e.start - t.start);
1078
+ });
1079
+ }
1080
+ #c(e) {
1081
+ this.#e.mutate((n) => {
1082
+ for (; n.length > 0;) {
1083
+ if (n[0].end >= e) {
1084
+ n[0].start = t.Milli.max(n[0].start, e);
1085
+ break;
1086
+ }
1087
+ n.shift();
1088
+ }
1089
+ });
1090
+ }
1091
+ close() {
1092
+ this.#n.close(), this.frame.update((e) => {
1093
+ e?.close();
1094
+ });
1095
+ }
1096
+ };
1097
+ async function ie(e) {
1098
+ if (!o.containerSupported(e.container)) {
1099
+ let t = e.container.kind === "unknown" ? e.container.raw.kind : e.container.kind;
1100
+ return console.warn(`video: ignoring rendition with unknown container: ${t}`), !1;
1101
+ }
1102
+ let t;
1103
+ if (e.description) t = l.Hex.toBytes(e.description);
1104
+ else if (e.container.kind === "cmaf") try {
1105
+ t = c.Cmaf.decodeInitSegment(f(e.container.init)).description;
1106
+ } catch (t) {
1107
+ return console.warn(`video: malformed CMAF init segment for codec ${e.codec}`, t), !1;
1108
+ }
1109
+ let { supported: n } = await VideoDecoder.isConfigSupported({
1110
+ codec: e.codec,
1111
+ description: t,
1112
+ optimizeForLatency: e.optimizeForLatency ?? !0
1113
+ });
1114
+ if (n) return !0;
1115
+ if (e.codec.startsWith("avc3.")) {
1116
+ let n = `avc1.${e.codec.slice(5)}`;
1117
+ if ((await VideoDecoder.isConfigSupported({
1118
+ codec: n,
1119
+ description: t,
1120
+ optimizeForLatency: e.optimizeForLatency ?? !0
1121
+ })).supported) return e.codec = n, !0;
1122
+ }
1123
+ return !1;
1124
+ }
1125
+ //#endregion
1126
+ //#region src/video/renderer.ts
1127
+ var Q = .01, ae = class {
1128
+ decoder;
1129
+ in;
1130
+ #e = {
1131
+ frame: new r(void 0),
1132
+ timestamp: new r(void 0),
1133
+ visible: new r(!1)
1134
+ };
1135
+ out = a(this.#e);
1136
+ #t = new r(void 0);
1137
+ #n = new n();
1138
+ constructor(e, t) {
1139
+ this.decoder = e, this.in = {
1140
+ canvas: i(t?.canvas),
1141
+ visible: i(t?.visible ?? "20%")
1142
+ }, this.#n.run((e) => {
1143
+ let t = e.get(this.in.canvas);
1144
+ this.#t.set(t?.getContext("2d") ?? void 0);
1145
+ }), this.#n.run(this.#i.bind(this)), this.#n.run(this.#a.bind(this)), this.#n.run(this.#r.bind(this));
1146
+ }
1147
+ #r(e) {
1148
+ let t = e.getAll([this.in.canvas, this.decoder.out.display]);
1149
+ if (!t) return;
1150
+ let [n, r] = t;
1151
+ (n.width !== r.width || n.height !== r.height) && (n.width = r.width, n.height = r.height);
1152
+ }
1153
+ #i(e) {
1154
+ let t = e.get(this.in.visible);
1155
+ if (t === "never") {
1156
+ this.#e.visible.set(!1);
1157
+ return;
1158
+ }
1159
+ if (t === "always") {
1160
+ this.#e.visible.set(!0), e.cleanup(() => this.#e.visible.set(!1));
1161
+ return;
1162
+ }
1163
+ let n = e.get(this.in.canvas);
1164
+ if (!n) {
1165
+ this.#e.visible.set(!1);
1166
+ return;
1167
+ }
1168
+ let r = !1, i = () => {
1169
+ this.#e.visible.set(r && !document.hidden);
1170
+ }, a = (e) => {
1171
+ for (let t of e) r = t.isIntersecting, i();
1172
+ }, o;
1173
+ try {
1174
+ o = new IntersectionObserver(a, {
1175
+ threshold: Q,
1176
+ rootMargin: t
1177
+ });
1178
+ } catch {
1179
+ console.warn(`moq-watch: invalid visible margin "${t}", using "0px"`), o = new IntersectionObserver(a, { threshold: Q });
1180
+ }
1181
+ i(), e.event(document, "visibilitychange", i), o.observe(n), e.cleanup(() => o.disconnect()), e.cleanup(() => this.#e.visible.set(!1));
1182
+ }
1183
+ #a(e) {
1184
+ let n = e.get(this.#t);
1185
+ if (!n) return;
1186
+ let r = e.get(this.decoder.out.frame), i = requestAnimationFrame(() => {
1187
+ this.#o(n, r), r ? (this.#e.frame.update((e) => (e?.close(), r.clone())), this.#e.timestamp.set(t.Milli.fromMicro(r.timestamp))) : (this.#e.frame.update((e) => {
1188
+ e?.close();
1189
+ }), this.#e.timestamp.set(void 0)), i = void 0;
1190
+ });
1191
+ e.cleanup(() => {
1192
+ i && cancelAnimationFrame(i);
1193
+ });
1194
+ }
1195
+ #o(e, t) {
1196
+ if (!t) {
1197
+ e.fillStyle = "#000", e.fillRect(0, 0, e.canvas.width, e.canvas.height);
1198
+ return;
1199
+ }
1200
+ e.save(), e.fillStyle = "#000", e.fillRect(0, 0, e.canvas.width, e.canvas.height), this.decoder.source.out.catalog.peek()?.flip && (e.scale(-1, 1), e.translate(-e.canvas.width, 0)), e.drawImage(t, 0, 0, e.canvas.width, e.canvas.height), e.restore();
1201
+ }
1202
+ close() {
1203
+ this.#e.frame.update((e) => {
1204
+ e?.close();
1205
+ }), this.#e.timestamp.set(void 0), this.#n.close();
1206
+ }
1207
+ };
1208
+ //#endregion
1209
+ //#region src/video/source.ts
1210
+ function oe(e) {
1211
+ return (t) => {
1212
+ let n = [], r = [];
1213
+ for (let [i, a] of t) if (a.codedWidth && a.codedHeight) {
1214
+ let t = a.codedWidth * a.codedHeight;
1215
+ t <= e ? n.push({
1216
+ name: i,
1217
+ size: t
1218
+ }) : r.push({
1219
+ name: i,
1220
+ size: t
1221
+ });
1222
+ }
1223
+ return n.sort((e, t) => t.size - e.size), n.length > 0 ? n.map((e) => e.name) : r.length > 0 ? (r.sort((e, t) => e.size - t.size), [r[0].name]) : t.map(([e]) => e);
1224
+ };
1225
+ }
1226
+ function $(e, t) {
1227
+ return (n) => {
1228
+ let r = [], i = [];
1229
+ for (let [a, o] of n) {
1230
+ if (!o.codedWidth || !o.codedHeight) continue;
1231
+ let n = o.codedWidth * o.codedHeight, s = e == null || o.codedWidth <= e, c = t == null || o.codedHeight <= t;
1232
+ s && c ? r.push({
1233
+ name: a,
1234
+ size: n
1235
+ }) : i.push({
1236
+ name: a,
1237
+ size: n
1238
+ });
1239
+ }
1240
+ return r.sort((e, t) => t.size - e.size), r.length > 0 ? r.map((e) => e.name) : i.length > 0 ? (i.sort((e, t) => e.size - t.size), [i[0].name]) : n.map(([e]) => e);
1241
+ };
1242
+ }
1243
+ function se(e) {
1244
+ return (t) => {
1245
+ let n = [], r = [];
1246
+ for (let [i, a] of t) a.bitrate != null && a.bitrate <= e ? n.push({
1247
+ name: i,
1248
+ bitrate: a.bitrate
1249
+ }) : a.bitrate != null && r.push({
1250
+ name: i,
1251
+ bitrate: a.bitrate
1252
+ });
1253
+ return n.sort((e, t) => t.bitrate - e.bitrate), n.length > 0 ? n.map((e) => e.name) : r.length > 0 ? (r.sort((e, t) => e.bitrate - t.bitrate), [r[0].name]) : t.map(([e]) => e);
1254
+ };
1255
+ }
1256
+ function ce(e) {
1257
+ let t = e[0];
1258
+ for (let n of e) {
1259
+ let [, e] = n, [, r] = t, i = (e.codedWidth ?? 0) * (e.codedHeight ?? 0), a = (r.codedWidth ?? 0) * (r.codedHeight ?? 0);
1260
+ if (i !== a) {
1261
+ i > a && (t = n);
1262
+ continue;
1263
+ }
1264
+ (e.bitrate ?? 0) > (r.bitrate ?? 0) && (t = n);
1265
+ }
1266
+ return t[0];
1267
+ }
1268
+ var le = class {
1269
+ in;
1270
+ #e = {
1271
+ catalog: new r(void 0),
1272
+ available: new r({}),
1273
+ error: new r(void 0),
1274
+ track: new r(void 0),
1275
+ config: new r(void 0),
1276
+ jitter: new r(void 0)
1277
+ };
1278
+ out = a(this.#e);
1279
+ #t = new n();
1280
+ constructor(e) {
1281
+ this.in = {
1282
+ broadcast: i(e?.broadcast),
1283
+ target: i(e?.target),
1284
+ supported: i(e?.supported)
1285
+ }, this.#t.run(this.#n.bind(this)), this.#t.run(this.#r.bind(this)), this.#t.run(this.#i.bind(this));
1286
+ }
1287
+ #n(e) {
1288
+ let t = e.get(this.in.broadcast);
1289
+ if (!t) return;
1290
+ let n = e.get(t.out.catalog)?.video;
1291
+ n && e.set(this.#e.catalog, n);
1292
+ }
1293
+ #r(e) {
1294
+ let t = e.get(this.in.supported);
1295
+ if (!t) {
1296
+ this.#e.error.set(void 0);
1297
+ return;
1298
+ }
1299
+ let n = e.get(this.#e.catalog)?.renditions ?? {};
1300
+ this.#e.error.set(void 0), e.spawn(async () => {
1301
+ let e = {};
1302
+ for (let [r, i] of Object.entries(n)) {
1303
+ let n = !1;
1304
+ try {
1305
+ n = await t(i);
1306
+ } catch (e) {
1307
+ console.warn(`[Source] video rendition ${r} (${i.codec}) support probe failed; treating as unsupported`, e);
1308
+ }
1309
+ n && (e[r] = i);
1310
+ }
1311
+ let r = Object.keys(e).length === 0 && Object.keys(n).length > 0 ? "unsupported" : void 0;
1312
+ r === "unsupported" && console.warn("[Source] No supported video renditions found:", n), this.#e.error.set(r), this.#e.available.set(e);
1313
+ });
1314
+ }
1315
+ #i(e) {
1316
+ let n = e.get(this.#e.available);
1317
+ if (Object.keys(n).length === 0) return;
1318
+ let r = e.get(this.in.target);
1319
+ if (r?.name && r.name in n) {
1320
+ let i = n[r.name];
1321
+ e.set(this.#e.track, r.name), e.set(this.#e.config, i), e.set(this.#e.jitter, i.jitter === void 0 ? void 0 : t.Milli(i.jitter));
1322
+ return;
1323
+ }
1324
+ let i = r;
1325
+ if (!r?.bitrate) {
1326
+ let t = e.get(this.in.broadcast), n = t ? e.get(t.in.connection) : void 0, a = n && e.get(n.probe).estimatedRecvRate;
1327
+ if (a != null) {
1328
+ let e = Math.round(a * .8);
1329
+ i = {
1330
+ ...r,
1331
+ bitrate: e
1332
+ };
1333
+ }
1334
+ }
1335
+ let a = this.#a(n, i);
1336
+ if (!a) return;
1337
+ let o = n[a];
1338
+ e.set(this.#e.track, a), e.set(this.#e.config, o);
1339
+ let s = o.jitter ?? (o.framerate ? Math.ceil(1e3 / o.framerate) : void 0);
1340
+ e.set(this.#e.jitter, s === void 0 ? void 0 : t.Milli(s));
1341
+ }
1342
+ #a(e, t) {
1343
+ let n = Object.entries(e);
1344
+ if (n.length === 0) return;
1345
+ if (n.length === 1) return n[0][0];
1346
+ let r = [];
1347
+ if (t?.pixels != null && r.push(oe(t.pixels)), (t?.width != null || t?.height != null) && r.push($(t.width, t.height)), t?.bitrate != null && r.push(se(t.bitrate)), r.length === 0) return ce(n);
1348
+ let i = r.map((e) => e(n)), a = i.map((e) => new Set(e));
1349
+ for (let e of i[0]) if (a.every((t) => t.has(e))) return e;
1350
+ console.warn("conflicting rendition filters, no rendition satisfies all criteria");
1351
+ }
1352
+ close() {
1353
+ this.#t.close();
1354
+ }
1355
+ };
1356
+ //#endregion
1357
+ export { q as a, P as c, Y as i, A as l, ae as n, J as o, ne as r, I as s, le as t };
1358
+
1359
+ //# sourceMappingURL=source-CWtgjSC_.js.map