@norskvideo/moq-watch 0.1.2 → 0.1.4
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.
- package/README.md +1 -2
- package/audio/buffer.d.ts +8 -0
- package/audio/buffer.d.ts.map +1 -1
- package/audio/decoder.d.ts +25 -15
- package/audio/decoder.d.ts.map +1 -1
- package/audio/emitter.d.ts +13 -10
- package/audio/emitter.d.ts.map +1 -1
- package/audio/handover.d.ts +16 -0
- package/audio/handover.d.ts.map +1 -0
- package/audio/index.d.ts +0 -2
- package/audio/index.d.ts.map +1 -1
- package/audio/render.d.ts +10 -1
- package/audio/render.d.ts.map +1 -1
- package/audio/ring-buffer.d.ts +7 -0
- package/audio/ring-buffer.d.ts.map +1 -1
- package/audio/shared-ring-buffer.d.ts +30 -2
- package/audio/shared-ring-buffer.d.ts.map +1 -1
- package/audio/source.d.ts +21 -17
- package/audio/source.d.ts.map +1 -1
- package/audio/subscription.d.ts +10 -0
- package/audio/subscription.d.ts.map +1 -0
- package/audio/terminal.d.ts +36 -0
- package/audio/terminal.d.ts.map +1 -0
- package/audio/unlock.d.ts +20 -0
- package/audio/unlock.d.ts.map +1 -0
- package/audio/warmup.d.ts +9 -0
- package/audio/warmup.d.ts.map +1 -0
- package/broadcast.d.ts +21 -61
- package/broadcast.d.ts.map +1 -1
- package/element.d.ts +45 -12
- package/element.d.ts.map +1 -1
- package/element.js +190 -95
- package/element.js.map +1 -1
- package/index.d.ts +9 -6
- package/index.d.ts.map +1 -1
- package/index.js +24 -5
- package/index.js.map +1 -0
- package/msf.d.ts.map +1 -1
- package/package.json +5 -6
- package/source-lWNGIbmd.js +1722 -0
- package/source-lWNGIbmd.js.map +1 -0
- package/support/element.d.ts.map +1 -1
- package/support/element.js.map +1 -1
- package/support/index.d.ts +3 -3
- package/support/index.d.ts.map +1 -1
- package/support/index.js +18 -17
- package/support/index.js.map +1 -1
- package/sync-DNQkgnlX.js +132 -0
- package/sync-DNQkgnlX.js.map +1 -0
- package/sync.d.ts +42 -22
- package/sync.d.ts.map +1 -1
- package/ui/components/buffer-control.d.ts +1 -1
- package/ui/components/buffer-control.d.ts.map +1 -1
- package/ui/components/fullscreen-button.d.ts +1 -2
- package/ui/components/fullscreen-button.d.ts.map +1 -1
- package/ui/components/play-pause.d.ts +1 -1
- package/ui/components/play-pause.d.ts.map +1 -1
- package/ui/element.d.ts.map +1 -1
- package/ui/element.js +269 -265
- package/ui/element.js.map +1 -1
- package/ui/fullscreen.d.ts +1 -2
- package/ui/fullscreen.d.ts.map +1 -1
- package/video/config.d.ts +17 -0
- package/video/config.d.ts.map +1 -0
- package/video/decoder.d.ts +42 -16
- package/video/decoder.d.ts.map +1 -1
- package/video/index.d.ts +0 -2
- package/video/index.d.ts.map +1 -1
- package/video/playhead.d.ts +31 -0
- package/video/playhead.d.ts.map +1 -0
- package/video/presentation.d.ts +16 -0
- package/video/presentation.d.ts.map +1 -0
- package/video/renderer.d.ts +14 -17
- package/video/renderer.d.ts.map +1 -1
- package/video/source.d.ts +23 -20
- package/video/source.d.ts.map +1 -1
- package/audio/backend.d.ts +0 -26
- package/audio/backend.d.ts.map +0 -1
- package/audio/mse.d.ts +0 -22
- package/audio/mse.d.ts.map +0 -1
- package/audio/ring-buffer.test.d.ts +0 -2
- package/audio/ring-buffer.test.d.ts.map +0 -1
- package/audio/shared-ring-buffer.test.d.ts +0 -2
- package/audio/shared-ring-buffer.test.d.ts.map +0 -1
- package/backend.d.ts +0 -65
- package/backend.d.ts.map +0 -1
- package/broadcast-BY0pAaOe.js +0 -1706
- package/broadcast-BY0pAaOe.js.map +0 -1
- package/buffered.d.ts +0 -19
- package/buffered.d.ts.map +0 -1
- package/mse.d.ts +0 -19
- package/mse.d.ts.map +0 -1
- package/sync-D67IxmxJ.js +0 -128
- package/sync-D67IxmxJ.js.map +0 -1
- package/sync.test.d.ts +0 -2
- package/sync.test.d.ts.map +0 -1
- package/video/backend.d.ts +0 -25
- package/video/backend.d.ts.map +0 -1
- package/video/mse.d.ts +0 -23
- package/video/mse.d.ts.map +0 -1
- package/video/source.test.d.ts +0 -2
- package/video/source.test.d.ts.map +0 -1
|
@@ -0,0 +1,1722 @@
|
|
|
1
|
+
import { n as e } from "./sync-DNQkgnlX.js";
|
|
2
|
+
import { Path as t, Time as n } from "@norskvideo/moq-net";
|
|
3
|
+
import { Effect as r, Signal as i, getter as a, readonlys as o } from "@norskvideo/moq-signals";
|
|
4
|
+
import * as s from "@norskvideo/moq-hang/catalog";
|
|
5
|
+
import { u53 as c } from "@norskvideo/moq-hang/catalog";
|
|
6
|
+
import * as l from "@norskvideo/moq-hang/container";
|
|
7
|
+
import * as u from "@norskvideo/moq-hang/util";
|
|
8
|
+
import * as d from "@norskvideo/moq-json";
|
|
9
|
+
import * as f from "@norskvideo/moq-msf";
|
|
10
|
+
//#region src/base64.ts
|
|
11
|
+
function p(e) {
|
|
12
|
+
let t = atob(e), n = new Uint8Array(t.length);
|
|
13
|
+
for (let e = 0; e < t.length; e++) n[e] = t.charCodeAt(e);
|
|
14
|
+
return n;
|
|
15
|
+
}
|
|
16
|
+
//#endregion
|
|
17
|
+
//#region src/audio/shared-ring-buffer.ts
|
|
18
|
+
var m = 0, h = 1, g = 2, _ = 3, v = 4294967295n;
|
|
19
|
+
function y(e, t) {
|
|
20
|
+
return BigInt(e >>> 0) << 32n | BigInt(t >>> 0);
|
|
21
|
+
}
|
|
22
|
+
function b(e) {
|
|
23
|
+
return Number(e >> 32n) | 0;
|
|
24
|
+
}
|
|
25
|
+
function x(e) {
|
|
26
|
+
return Number(e & v) | 0;
|
|
27
|
+
}
|
|
28
|
+
function ee(e) {
|
|
29
|
+
return e <= 1 ? 1 : 1 << 32 - Math.clz32(e - 1);
|
|
30
|
+
}
|
|
31
|
+
function S(e, t, n, r = !1) {
|
|
32
|
+
if (e <= 0) throw Error("invalid channels");
|
|
33
|
+
if (t <= 0 || t > 2 ** 30) throw Error("invalid capacity");
|
|
34
|
+
if (n <= 0) throw Error("invalid sample rate");
|
|
35
|
+
t = ee(t);
|
|
36
|
+
let i = new SharedArrayBuffer(e * t * Float32Array.BYTES_PER_ELEMENT), a = new SharedArrayBuffer(_ * Int32Array.BYTES_PER_ELEMENT), o = new SharedArrayBuffer(BigInt64Array.BYTES_PER_ELEMENT), s = new Int32Array(a);
|
|
37
|
+
return Atomics.store(s, g, 1), {
|
|
38
|
+
channels: e,
|
|
39
|
+
capacity: t,
|
|
40
|
+
rate: n,
|
|
41
|
+
samples: i,
|
|
42
|
+
control: a,
|
|
43
|
+
state: o,
|
|
44
|
+
buffered: r
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
function C(e, t) {
|
|
48
|
+
return (e - t | 0) > 0 ? e : t;
|
|
49
|
+
}
|
|
50
|
+
function w(e, t) {
|
|
51
|
+
return e & t - 1;
|
|
52
|
+
}
|
|
53
|
+
var te = class e {
|
|
54
|
+
channels;
|
|
55
|
+
capacity;
|
|
56
|
+
rate;
|
|
57
|
+
buffered;
|
|
58
|
+
init;
|
|
59
|
+
#e;
|
|
60
|
+
#t;
|
|
61
|
+
#n;
|
|
62
|
+
#r = !1;
|
|
63
|
+
#i = 0;
|
|
64
|
+
#a = 0;
|
|
65
|
+
#o = 0;
|
|
66
|
+
constructor(e, t) {
|
|
67
|
+
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 = new BigInt64Array(e.state), this.#n = [];
|
|
68
|
+
for (let t = 0; t < this.channels; t++) this.#n.push(new Float32Array(e.samples, t * this.capacity * Float32Array.BYTES_PER_ELEMENT, this.capacity));
|
|
69
|
+
t !== void 0 && this.#s(t);
|
|
70
|
+
}
|
|
71
|
+
#s(e) {
|
|
72
|
+
if (e.channels !== this.channels || e.rate !== this.rate) return;
|
|
73
|
+
let t = Atomics.load(e.#t, 0);
|
|
74
|
+
for (;;) {
|
|
75
|
+
let e = Atomics.load(this.#t, 0);
|
|
76
|
+
if (b(e) !== b(t) || (x(t) - x(e) | 0) <= 0) return;
|
|
77
|
+
let n = y(b(e), x(t));
|
|
78
|
+
if (Atomics.compareExchange(this.#t, 0, e, n) === e) return;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
#c(e) {
|
|
82
|
+
for (;;) {
|
|
83
|
+
let t = Atomics.load(this.#t, 0);
|
|
84
|
+
if ((e - x(t) | 0) <= 0) return;
|
|
85
|
+
let n = y(b(t), e);
|
|
86
|
+
if (Atomics.compareExchange(this.#t, 0, t, n) === t) return;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
insert(e, t) {
|
|
90
|
+
if (t.length !== this.channels) throw Error("wrong number of channels");
|
|
91
|
+
let r = Math.round(n.Second.fromMicro(e) * this.rate), i = t[0].length, a = 0;
|
|
92
|
+
if (!this.#r) {
|
|
93
|
+
this.#i = r;
|
|
94
|
+
let e = b(Atomics.load(this.#t, 0));
|
|
95
|
+
Atomics.store(this.#t, 0, y(e + 1 | 0, 0)), Atomics.store(this.#e, m, 0), this.#r = !0, this.#a = 0, this.#o = 0;
|
|
96
|
+
}
|
|
97
|
+
r = r - this.#i | 0;
|
|
98
|
+
let o = r + i | 0, s = x(Atomics.load(this.#t, 0)), c = s - r | 0;
|
|
99
|
+
if (c > 0) {
|
|
100
|
+
if (c >= i) return;
|
|
101
|
+
a = c, r = r + c | 0;
|
|
102
|
+
}
|
|
103
|
+
let l = i - a;
|
|
104
|
+
(o - s | 0) > this.capacity && this.#c(o - this.capacity | 0);
|
|
105
|
+
let u = Atomics.load(this.#e, m), d = r - u | 0;
|
|
106
|
+
if (d > 0) {
|
|
107
|
+
let e = Math.min(d, this.capacity);
|
|
108
|
+
for (let t = 0; t < this.channels; t++) {
|
|
109
|
+
let n = this.#n[t];
|
|
110
|
+
for (let t = 0; t < e; t++) n[w(u + t | 0, this.capacity)] = 0;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
for (let e = 0; e < this.channels; e++) {
|
|
114
|
+
let n = t[e], i = this.#n[e];
|
|
115
|
+
for (let e = 0; e < l; e++) i[w(r + e | 0, this.capacity)] = n[a + e];
|
|
116
|
+
}
|
|
117
|
+
Atomics.store(this.#e, m, C(Atomics.load(this.#e, m), o));
|
|
118
|
+
let f = x(Atomics.load(this.#t, 0)), p = Atomics.load(this.#e, m), _ = Atomics.load(this.#e, h);
|
|
119
|
+
(p - f | 0) >= _ && _ > 0 && Atomics.store(this.#e, g, 0);
|
|
120
|
+
}
|
|
121
|
+
read(e) {
|
|
122
|
+
let t = Atomics.load(this.#t, 0);
|
|
123
|
+
if (Atomics.load(this.#e, g) === 1) return 0;
|
|
124
|
+
let n = x(t), r = Atomics.load(this.#e, m), i = Atomics.load(this.#e, h), a = r - n | 0;
|
|
125
|
+
if (!this.buffered && i > 0 && a > i) {
|
|
126
|
+
let e = r - i | 0;
|
|
127
|
+
(e - n | 0) > 0 && (n = e);
|
|
128
|
+
}
|
|
129
|
+
let o = r - n | 0, s = Math.min(o, e[0].length);
|
|
130
|
+
if (s <= 0) return (n - x(t) | 0) > 0 && Atomics.compareExchange(this.#t, 0, t, y(b(t), n)), 0;
|
|
131
|
+
for (let t = 0; t < this.channels; t++) {
|
|
132
|
+
let r = this.#n[t], i = e[t];
|
|
133
|
+
for (let e = 0; e < s; e++) i[e] = r[w(n + e | 0, this.capacity)];
|
|
134
|
+
}
|
|
135
|
+
let c = y(b(t), n + s | 0);
|
|
136
|
+
if (Atomics.compareExchange(this.#t, 0, t, c) !== t) {
|
|
137
|
+
for (let t = 0; t < this.channels; t++) e[t].fill(0, 0, s);
|
|
138
|
+
return 0;
|
|
139
|
+
}
|
|
140
|
+
return s;
|
|
141
|
+
}
|
|
142
|
+
setLatency(e) {
|
|
143
|
+
Atomics.store(this.#e, h, e);
|
|
144
|
+
}
|
|
145
|
+
truncate(e) {
|
|
146
|
+
let t = Math.round(n.Second.fromMicro(e) * this.rate) - this.#i | 0;
|
|
147
|
+
for (;;) {
|
|
148
|
+
let e = Atomics.load(this.#e, m);
|
|
149
|
+
if ((e - t | 0) <= 0) return;
|
|
150
|
+
let n = C(t, x(Atomics.load(this.#t, 0)));
|
|
151
|
+
if ((e - n | 0) <= 0 || Atomics.compareExchange(this.#e, m, e, n) === e) return;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
reset() {
|
|
155
|
+
this.#r = !1, Atomics.store(this.#e, g, 1);
|
|
156
|
+
let e = Atomics.load(this.#e, m), t = Atomics.load(this.#t, 0);
|
|
157
|
+
Atomics.store(this.#t, 0, y(b(t), e));
|
|
158
|
+
}
|
|
159
|
+
resize(t) {
|
|
160
|
+
let n = S(this.channels, t, this.rate, this.buffered), r = new e(n);
|
|
161
|
+
r.#r = this.#r, r.#i = this.#i;
|
|
162
|
+
let i = Atomics.load(this.#t, 0), a = x(i), o = Atomics.load(this.#e, m), s = Atomics.load(this.#e, h), c = Atomics.load(this.#e, g), l = o - a | 0, u = Math.max(0, Math.min(l, r.capacity)), d = o - u | 0;
|
|
163
|
+
for (let e = 0; e < this.channels; e++) {
|
|
164
|
+
let t = this.#n[e], n = r.#n[e];
|
|
165
|
+
for (let e = 0; e < u; e++) {
|
|
166
|
+
let i = d + e | 0;
|
|
167
|
+
n[w(i, r.capacity)] = t[w(i, this.capacity)];
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return Atomics.store(r.#t, 0, y(b(i), d)), Atomics.store(r.#e, m, o), Atomics.store(r.#e, h, s), Atomics.store(r.#e, g, c), r.#a = this.#l(a) + (d - a | 0), r.#o = d, r;
|
|
171
|
+
}
|
|
172
|
+
#l(e) {
|
|
173
|
+
return this.#a += e - this.#o | 0, this.#o = e, this.#a;
|
|
174
|
+
}
|
|
175
|
+
#u() {
|
|
176
|
+
return this.#l(x(Atomics.load(this.#t, 0)));
|
|
177
|
+
}
|
|
178
|
+
get timestamp() {
|
|
179
|
+
return n.Micro.fromSecond((this.#i + this.#u()) / this.rate);
|
|
180
|
+
}
|
|
181
|
+
get stalled() {
|
|
182
|
+
return Atomics.load(this.#e, g) === 1;
|
|
183
|
+
}
|
|
184
|
+
get length() {
|
|
185
|
+
return Atomics.load(this.#e, m) - x(Atomics.load(this.#t, 0)) | 0;
|
|
186
|
+
}
|
|
187
|
+
}, T = class {
|
|
188
|
+
#e;
|
|
189
|
+
#t;
|
|
190
|
+
#n = [];
|
|
191
|
+
constructor(e, t) {
|
|
192
|
+
this.#e = e, this.#t = t;
|
|
193
|
+
}
|
|
194
|
+
setHeadroom(e) {
|
|
195
|
+
this.#t = e;
|
|
196
|
+
}
|
|
197
|
+
wait(e, t) {
|
|
198
|
+
return !this.#e || t >= (e - this.#t | 0) ? Promise.resolve() : new Promise((t) => this.#n.push({
|
|
199
|
+
timestamp: e,
|
|
200
|
+
resolve: t
|
|
201
|
+
}));
|
|
202
|
+
}
|
|
203
|
+
advance(e) {
|
|
204
|
+
this.#n.length !== 0 && (this.#n = this.#n.filter(({ timestamp: t, resolve: n }) => e < (t - this.#t | 0) || (n(), !1)));
|
|
205
|
+
}
|
|
206
|
+
flush() {
|
|
207
|
+
for (let { resolve: e } of this.#n) e();
|
|
208
|
+
this.#n = [];
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
function E(e, t) {
|
|
212
|
+
return n.Micro.fromSecond(e / t);
|
|
213
|
+
}
|
|
214
|
+
function D() {
|
|
215
|
+
return !(typeof SharedArrayBuffer > "u" || typeof crossOriginIsolated < "u" && !crossOriginIsolated);
|
|
216
|
+
}
|
|
217
|
+
function ne(e, t, n, r, i = !1) {
|
|
218
|
+
return D() ? (console.log("[audio] using SharedArrayBuffer audio buffer"), new re(e, t, n, r, i)) : (console.warn("[audio] SharedArrayBuffer unavailable, falling back to the higher latency postMessage audio buffer. Serve the page cross-origin isolated (Cross-Origin-Opener-Policy: same-origin, Cross-Origin-Embedder-Policy: require-corp) to avoid this."), new ie(e, t, n, r, i));
|
|
219
|
+
}
|
|
220
|
+
var re = class {
|
|
221
|
+
rate;
|
|
222
|
+
channels;
|
|
223
|
+
#e;
|
|
224
|
+
#t;
|
|
225
|
+
#n = new i(0);
|
|
226
|
+
timestamp = this.#n;
|
|
227
|
+
#r = new i(!0);
|
|
228
|
+
stalled = this.#r;
|
|
229
|
+
#i;
|
|
230
|
+
#a = new r();
|
|
231
|
+
constructor(e, t, n, r, i) {
|
|
232
|
+
this.#e = e, this.channels = t, this.rate = n;
|
|
233
|
+
let a = Math.max(n, r * 2);
|
|
234
|
+
this.#i = new T(i, E(r, n));
|
|
235
|
+
let o = S(t, a, n, i);
|
|
236
|
+
this.#t = new te(o), this.#t.setLatency(r);
|
|
237
|
+
let s = {
|
|
238
|
+
type: "init-shared",
|
|
239
|
+
...o
|
|
240
|
+
};
|
|
241
|
+
e.port.postMessage(s), this.#a.interval(() => {
|
|
242
|
+
let e = this.#t.stalled;
|
|
243
|
+
this.#n.set(this.#t.timestamp), this.#r.set(e), e ? this.#i.flush() : this.#i.advance(this.#t.timestamp);
|
|
244
|
+
}, 50);
|
|
245
|
+
}
|
|
246
|
+
insert(e, t) {
|
|
247
|
+
this.#t.insert(e, t);
|
|
248
|
+
}
|
|
249
|
+
setLatency(e) {
|
|
250
|
+
if (this.#i.setHeadroom(E(e, this.rate)), this.#t.capacity < e * 1.5) {
|
|
251
|
+
let t = Math.max(this.rate, e * 2);
|
|
252
|
+
this.#t = this.#t.resize(t), this.#t.setLatency(e);
|
|
253
|
+
let n = {
|
|
254
|
+
type: "init-shared",
|
|
255
|
+
...this.#t.init
|
|
256
|
+
};
|
|
257
|
+
this.#e.port.postMessage(n);
|
|
258
|
+
} else this.#t.setLatency(e);
|
|
259
|
+
}
|
|
260
|
+
truncate(e) {
|
|
261
|
+
this.#t.truncate(e);
|
|
262
|
+
}
|
|
263
|
+
reset() {
|
|
264
|
+
this.#t.reset(), this.#i.flush();
|
|
265
|
+
}
|
|
266
|
+
wait(e) {
|
|
267
|
+
return this.#t.stalled ? Promise.resolve() : this.#i.wait(e, this.#t.timestamp);
|
|
268
|
+
}
|
|
269
|
+
close() {
|
|
270
|
+
this.#i.flush(), this.#a.close();
|
|
271
|
+
}
|
|
272
|
+
}, ie = class {
|
|
273
|
+
rate;
|
|
274
|
+
channels;
|
|
275
|
+
#e;
|
|
276
|
+
#t = new i(0);
|
|
277
|
+
timestamp = this.#t;
|
|
278
|
+
#n = new i(!0);
|
|
279
|
+
stalled = this.#n;
|
|
280
|
+
#r;
|
|
281
|
+
#i = new r();
|
|
282
|
+
constructor(e, t, r, i, a) {
|
|
283
|
+
this.#e = e, this.channels = t, this.rate = r, this.#r = new T(a, E(i, r));
|
|
284
|
+
let o = {
|
|
285
|
+
type: "init-post",
|
|
286
|
+
channels: t,
|
|
287
|
+
rate: r,
|
|
288
|
+
latency: n.Milli.fromSecond(i / r),
|
|
289
|
+
buffered: a
|
|
290
|
+
};
|
|
291
|
+
e.port.postMessage(o), this.#i.event(e.port, "message", (e) => {
|
|
292
|
+
let t = e.data;
|
|
293
|
+
t?.type === "state" && (this.#t.set(t.timestamp), this.#n.set(t.stalled), t.stalled ? this.#r.flush() : this.#r.advance(t.timestamp));
|
|
294
|
+
}), e.port.start();
|
|
295
|
+
}
|
|
296
|
+
insert(e, t) {
|
|
297
|
+
let n = {
|
|
298
|
+
type: "data",
|
|
299
|
+
data: t,
|
|
300
|
+
timestamp: e
|
|
301
|
+
};
|
|
302
|
+
this.#e.port.postMessage(n, t.map((e) => e.buffer));
|
|
303
|
+
}
|
|
304
|
+
setLatency(e) {
|
|
305
|
+
this.#r.setHeadroom(E(e, this.rate));
|
|
306
|
+
let t = {
|
|
307
|
+
type: "latency",
|
|
308
|
+
latency: n.Milli.fromSecond(e / this.rate)
|
|
309
|
+
};
|
|
310
|
+
this.#e.port.postMessage(t);
|
|
311
|
+
}
|
|
312
|
+
truncate(e) {
|
|
313
|
+
let t = {
|
|
314
|
+
type: "truncate",
|
|
315
|
+
timestamp: e
|
|
316
|
+
};
|
|
317
|
+
this.#e.port.postMessage(t);
|
|
318
|
+
}
|
|
319
|
+
reset() {
|
|
320
|
+
this.#e.port.postMessage({ type: "reset" }), this.#r.flush();
|
|
321
|
+
}
|
|
322
|
+
wait(e) {
|
|
323
|
+
return this.#n.peek() ? Promise.resolve() : this.#r.wait(e, this.#t.peek());
|
|
324
|
+
}
|
|
325
|
+
close() {
|
|
326
|
+
this.#r.flush(), this.#i.close();
|
|
327
|
+
}
|
|
328
|
+
}, ae = class {
|
|
329
|
+
#e = !1;
|
|
330
|
+
#t = !1;
|
|
331
|
+
opened() {
|
|
332
|
+
this.#e && (this.#t = !0), this.#e = !0;
|
|
333
|
+
}
|
|
334
|
+
takeover() {
|
|
335
|
+
let e = this.#t;
|
|
336
|
+
return this.#t = !1, e;
|
|
337
|
+
}
|
|
338
|
+
}, oe = 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: play through everything buffered 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.#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 /**\n * Drop buffered samples at or after `timestamp`, keeping whatever is already due.\n *\n * A successor track overwrites the slots its own samples land on, but anything the previous\n * track wrote beyond them would otherwise still play once the successor runs out.\n */\n truncate(timestamp) {\n const target = Math.round(time_exports.Second.fromMicro(timestamp) * this.rate);\n if (target >= this.#writeIndex) return;\n this.#writeIndex = Math.max(target, this.#readIndex);\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 LATENCY = 1;\nvar STALLED = 2;\nvar CONTROL_SLOTS = 3;\nvar CURSOR_MASK = 0xffffffffn;\nfunction pack(epoch, read) {\n return BigInt(epoch >>> 0) << 32n | BigInt(read >>> 0);\n}\nfunction epochOf(state) {\n return Number(state >> 32n) | 0;\n}\nfunction readOf(state) {\n return Number(state & CURSOR_MASK) | 0;\n}\nfunction ceilPow2(n) {\n return n <= 1 ? 1 : 1 << 32 - Math.clz32(n - 1);\n}\nfunction allocSharedRingBuffer(channels, capacity, rate, buffered = false) {\n if (channels <= 0) throw new Error(\"invalid channels\");\n if (capacity <= 0 || capacity > 2 ** 30) throw new Error(\"invalid capacity\");\n if (rate <= 0) throw new Error(\"invalid sample rate\");\n capacity = ceilPow2(capacity);\n const samples = new SharedArrayBuffer(channels * capacity * Float32Array.BYTES_PER_ELEMENT);\n const control = new SharedArrayBuffer(CONTROL_SLOTS * Int32Array.BYTES_PER_ELEMENT);\n const state = new SharedArrayBuffer(BigInt64Array.BYTES_PER_ELEMENT);\n const ctrl = new Int32Array(control);\n Atomics.store(ctrl, STALLED, 1);\n return { channels, capacity, rate, samples, control, state, buffered };\n}\nfunction i32Max(a, b) {\n return (a - b | 0) > 0 ? a : b;\n}\nfunction slot(idx, capacity) {\n return idx & capacity - 1;\n}\nvar SharedRingBuffer = class _SharedRingBuffer {\n channels;\n capacity;\n rate;\n buffered;\n init;\n #control;\n #state;\n #samples;\n // Whether READ/WRITE have been anchored to the first inserted sample.\n #anchored = false;\n // Absolute sample index of that first sample. READ/WRITE are stored relative to it, so\n // `timestamp` adds it back to recover media time. Main-thread only: the worklet reads by\n // difference and never needs an absolute position.\n #anchor = 0;\n // Unwrapped READ, in anchor-relative samples, plus the raw i32 it was last derived from.\n // READ is Int32 and wraps every ~13.5h at 44.1kHz. That is harmless for the modular\n // comparisons the ring runs on, but reading the negative half as a magnitude would report\n // the playhead jumping back 2^32 samples, so accumulate deltas here instead. Main-thread\n // only, and only accurate while `timestamp` is observed more often than READ can advance\n // 2^31 samples, which the 50ms poll in `buffer.ts` satisfies by six orders of magnitude.\n #position = 0;\n #lastRead = 0;\n /**\n * Wrap the shared memory described by `init`.\n *\n * Pass `previous` in the worklet when this ring replaces one already being read. `resize`\n * snapshots the playhead on the main thread and hands the replacement over by message, so the\n * reader keeps draining the old ring in the meantime. Carrying its cursor across means those\n * samples are not played twice.\n */\n constructor(init, previous) {\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.#state = new BigInt64Array(init.state);\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 if (previous !== void 0) this.#handoff(previous);\n }\n /**\n * Carry `source`'s playhead across, if the replacement is still the timeline it belongs to.\n *\n * `resize` copies the epoch, so a destination that re-anchored since has a different one and\n * the cursor is dropped rather than applied to audio the reader has never played. The check\n * and the write are the same exchange, so a re-anchor landing mid-handoff makes it fail\n * instead of slipping through the gap that separate operations would leave.\n */\n #handoff(source) {\n if (source.channels !== this.channels || source.rate !== this.rate) return;\n const from = Atomics.load(source.#state, 0);\n for (; ; ) {\n const state = Atomics.load(this.#state, 0);\n if (epochOf(state) !== epochOf(from)) return;\n if ((readOf(from) - readOf(state) | 0) <= 0) return;\n const next = pack(epochOf(state), readOf(from));\n if (Atomics.compareExchange(this.#state, 0, state, next) === state) return;\n }\n }\n /**\n * Move the playhead forward to `candidate`, staying on whatever timeline is current.\n *\n * Retries while the word changes under it, and never steps backwards. Used by the writer's\n * overflow path; the reader publishes with its own exchange so it can tell a rebase apart\n * from losing a race.\n */\n #advance(candidate) {\n for (; ; ) {\n const state = Atomics.load(this.#state, 0);\n if ((candidate - readOf(state) | 0) <= 0) return;\n const next = pack(epochOf(state), candidate);\n if (Atomics.compareExchange(this.#state, 0, state, next) === state) return;\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.#anchored) {\n this.#anchor = start;\n const epoch = epochOf(Atomics.load(this.#state, 0));\n Atomics.store(this.#state, 0, pack(epoch + 1 | 0, 0));\n Atomics.store(this.#control, WRITE, 0);\n this.#anchored = true;\n this.#position = 0;\n this.#lastRead = 0;\n }\n start = start - this.#anchor | 0;\n const end = start + originalLength | 0;\n const read = readOf(Atomics.load(this.#state, 0));\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 this.#advance(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 = readOf(Atomics.load(this.#state, 0));\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 const state = Atomics.load(this.#state, 0);\n if (Atomics.load(this.#control, STALLED) === 1) return 0;\n let read = readOf(state);\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 if ((skipTo - read | 0) > 0) read = skipTo;\n }\n const available = write - read | 0;\n const count = Math.min(available, output[0].length);\n if (count <= 0) {\n if ((read - readOf(state) | 0) > 0) {\n Atomics.compareExchange(this.#state, 0, state, pack(epochOf(state), read));\n }\n return 0;\n }\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 const next = pack(epochOf(state), read + count | 0);\n if (Atomics.compareExchange(this.#state, 0, state, next) !== state) {\n for (let channel = 0; channel < this.channels; channel++) output[channel].fill(0, 0, count);\n return 0;\n }\n return count;\n }\n /** Update the target latency in samples. */\n setLatency(samples) {\n Atomics.store(this.#control, LATENCY, samples);\n }\n /**\n * Drop buffered samples at or after `timestamp`, keeping whatever is already due.\n * Main thread only.\n *\n * A successor track overwrites the slots its own samples land on, but anything the previous\n * track wrote beyond them would otherwise still play once the successor runs out.\n */\n truncate(timestamp) {\n const target = Math.round(time_exports.Second.fromMicro(timestamp) * this.rate) - this.#anchor | 0;\n for (; ; ) {\n const write = Atomics.load(this.#control, WRITE);\n if ((write - target | 0) <= 0) return;\n const clamped = i32Max(target, readOf(Atomics.load(this.#state, 0)));\n if ((write - clamped | 0) <= 0) return;\n if (Atomics.compareExchange(this.#control, WRITE, write, clamped) === write) return;\n }\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 const state = Atomics.load(this.#state, 0);\n Atomics.store(this.#state, 0, pack(epochOf(state), 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 dst.#anchor = this.#anchor;\n const state = Atomics.load(this.#state, 0);\n const read = readOf(state);\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.#state, 0, pack(epochOf(state), copyStart));\n Atomics.store(dst.#control, WRITE, write);\n Atomics.store(dst.#control, LATENCY, latency);\n Atomics.store(dst.#control, STALLED, stalled);\n dst.#position = this.#foldRead(read) + (copyStart - read | 0);\n dst.#lastRead = copyStart;\n return dst;\n }\n /**\n * Fold an observed READ into `#position`, so the returned offset keeps counting up across\n * the i32 wrap. Idempotent: folding the same value twice adds a zero delta.\n */\n #foldRead(read) {\n this.#position += read - this.#lastRead | 0;\n this.#lastRead = read;\n return this.#position;\n }\n /** `#foldRead` against the current READ. */\n #unwrapRead() {\n return this.#foldRead(readOf(Atomics.load(this.#state, 0)));\n }\n /**\n * Current playback timestamp derived from READ position.\n *\n * Main thread only, and stateful: it advances the unwrapped read position, so it has to be\n * polled rather than sampled once. See `#position`.\n */\n get timestamp() {\n return time_exports.Micro.fromSecond((this.#anchor + this.#unwrapRead()) / 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) - readOf(Atomics.load(this.#state, 0)) | 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 const previous = this.#backend instanceof SharedRingBuffer ? this.#backend : void 0;\n this.#backend = new SharedRingBuffer(msg, previous);\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 === \"truncate\") {\n if (this.#backend instanceof AudioRingBuffer) this.#backend.truncate(msg.timestamp);\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" }), se = URL.createObjectURL(oe);
|
|
339
|
+
//#endregion
|
|
340
|
+
//#region src/audio/subscription.ts
|
|
341
|
+
function ce(e, { broadcast: t, track: n, maxLatency: r }) {
|
|
342
|
+
let i = s.PRIORITY.audio, a = Math.ceil(r.peek()), o = t.track(n).subscribe({
|
|
343
|
+
priority: i,
|
|
344
|
+
latencyMax: a
|
|
345
|
+
});
|
|
346
|
+
return e.cleanup(() => o.close()), e.run((e) => {
|
|
347
|
+
let t = Math.ceil(e.get(r));
|
|
348
|
+
t !== a && (a = t, o.update({
|
|
349
|
+
priority: i,
|
|
350
|
+
latencyMax: a
|
|
351
|
+
}));
|
|
352
|
+
}), o;
|
|
353
|
+
}
|
|
354
|
+
//#endregion
|
|
355
|
+
//#region src/audio/terminal.ts
|
|
356
|
+
var le = class {
|
|
357
|
+
#e = 0;
|
|
358
|
+
#t;
|
|
359
|
+
#n;
|
|
360
|
+
#r = 0;
|
|
361
|
+
#i;
|
|
362
|
+
get end() {
|
|
363
|
+
return this.#t;
|
|
364
|
+
}
|
|
365
|
+
clear(e = 0) {
|
|
366
|
+
this.#e = 0, this.#t = void 0, this.#r = e, this.#a();
|
|
367
|
+
}
|
|
368
|
+
update(e) {
|
|
369
|
+
let t = e.discontinuity !== this.#e;
|
|
370
|
+
return t && (this.#e = e.discontinuity, this.#t = void 0, this.#a()), e.frame && this.#n === void 0 && (this.#n = e.frame.timestamp), e.end !== void 0 && (this.#t = e.end), t;
|
|
371
|
+
}
|
|
372
|
+
span(e) {
|
|
373
|
+
let t = this.#n ?? e.timestamp;
|
|
374
|
+
this.#n = t;
|
|
375
|
+
let n = Math.floor(this.#r * e.sampleRate / 48e3), r = this.#i ?? n, i = Math.min(r, e.numberOfFrames);
|
|
376
|
+
this.#i = r - i;
|
|
377
|
+
let a = Math.round(n * 1e6 / e.sampleRate), o = Math.max(t, e.timestamp - a), s = e.numberOfFrames - i;
|
|
378
|
+
if (this.#t !== void 0) {
|
|
379
|
+
if (this.#t <= o) s = 0;
|
|
380
|
+
else {
|
|
381
|
+
let t = this.#t - o, n = Math.round(t * e.sampleRate / 1e6);
|
|
382
|
+
s = Math.min(s, n);
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
return {
|
|
386
|
+
timestamp: o,
|
|
387
|
+
frameOffset: i,
|
|
388
|
+
frames: s
|
|
389
|
+
};
|
|
390
|
+
}
|
|
391
|
+
#a() {
|
|
392
|
+
this.#n = void 0, this.#i = void 0;
|
|
393
|
+
}
|
|
394
|
+
};
|
|
395
|
+
//#endregion
|
|
396
|
+
//#region src/audio/unlock.ts
|
|
397
|
+
function ue(e, t) {
|
|
398
|
+
let n = new i(t.state === "running");
|
|
399
|
+
e.event(t, "statechange", () => n.set(t.state === "running")), e.run((e) => {
|
|
400
|
+
if (e.get(n)) return;
|
|
401
|
+
let r = () => {
|
|
402
|
+
t.resume().catch(() => {});
|
|
403
|
+
};
|
|
404
|
+
r(), e.event(document, "pointerdown", r), e.event(document, "keydown", r);
|
|
405
|
+
});
|
|
406
|
+
}
|
|
407
|
+
//#endregion
|
|
408
|
+
//#region src/audio/warmup.ts
|
|
409
|
+
var de = class {
|
|
410
|
+
#e;
|
|
411
|
+
constructor(e) {
|
|
412
|
+
this.#e = e;
|
|
413
|
+
}
|
|
414
|
+
drop() {
|
|
415
|
+
return this.#e !== 0 && (this.#e--, !0);
|
|
416
|
+
}
|
|
417
|
+
}, fe = 150, pe = 3, me = class {
|
|
418
|
+
in;
|
|
419
|
+
source;
|
|
420
|
+
sync;
|
|
421
|
+
#e = {
|
|
422
|
+
context: new i(void 0),
|
|
423
|
+
root: new i(void 0),
|
|
424
|
+
sampleRate: new i(void 0),
|
|
425
|
+
stats: new i(void 0),
|
|
426
|
+
timestamp: new i(void 0),
|
|
427
|
+
stalled: new i(!0),
|
|
428
|
+
buffered: new i([])
|
|
429
|
+
};
|
|
430
|
+
out = o(this.#e);
|
|
431
|
+
#t = new i([]);
|
|
432
|
+
#n;
|
|
433
|
+
#r = new i(void 0);
|
|
434
|
+
#i = new le();
|
|
435
|
+
#a;
|
|
436
|
+
#o = new ae();
|
|
437
|
+
#s = new r();
|
|
438
|
+
constructor(e, t, n) {
|
|
439
|
+
this.in = { enabled: a(n?.enabled ?? !1) }, this.source = e, this.sync = t, this.#s.run(this.#c.bind(this)), this.#s.run(this.#l.bind(this)), this.#s.run(this.#u.bind(this)), this.#s.run(this.#d.bind(this)), this.#s.run(this.#f.bind(this));
|
|
440
|
+
}
|
|
441
|
+
#c(e) {
|
|
442
|
+
let t = e.get(this.source.out.config);
|
|
443
|
+
if (!t) return;
|
|
444
|
+
let r = e.get(this.#r) ?? t.sampleRate, i = t.numberOfChannels;
|
|
445
|
+
e.set(this.#e.sampleRate, r);
|
|
446
|
+
let a = new AudioContext({
|
|
447
|
+
latencyHint: "interactive",
|
|
448
|
+
sampleRate: r
|
|
449
|
+
});
|
|
450
|
+
e.set(this.#e.context, a), e.cleanup(() => a.close()), e.spawn(async () => {
|
|
451
|
+
if (!await Promise.race([a.audioWorklet.addModule(se).then(() => !0), e.cancel])) return;
|
|
452
|
+
let t = new AudioWorkletNode(a, "render", {
|
|
453
|
+
channelCount: i,
|
|
454
|
+
channelCountMode: "explicit",
|
|
455
|
+
outputChannelCount: [i]
|
|
456
|
+
});
|
|
457
|
+
e.cleanup(() => t.disconnect());
|
|
458
|
+
let o = this.sync.out.buffer.peek(), s = Math.ceil(r * n.Second.fromMilli(o)), c = this.sync.out.buffered.peek(), l = ne(t, i, r, s, c);
|
|
459
|
+
this.#n = l, e.cleanup(() => {
|
|
460
|
+
l.close(), this.#n = void 0;
|
|
461
|
+
}), e.run((e) => {
|
|
462
|
+
let t = n.Milli.fromMicro(e.get(l.timestamp));
|
|
463
|
+
this.#e.timestamp.set(t), this.#v(t);
|
|
464
|
+
}), e.run((e) => {
|
|
465
|
+
this.#e.stalled.set(e.get(l.stalled));
|
|
466
|
+
}), e.set(this.#e.root, t);
|
|
467
|
+
});
|
|
468
|
+
}
|
|
469
|
+
#l(e) {
|
|
470
|
+
if (!e.get(this.in.enabled)) return;
|
|
471
|
+
let t = e.get(this.#e.context);
|
|
472
|
+
t && ue(e, t);
|
|
473
|
+
}
|
|
474
|
+
#u(e) {
|
|
475
|
+
if (!e.get(this.#e.root)) return;
|
|
476
|
+
let t = this.#n;
|
|
477
|
+
if (!t) return;
|
|
478
|
+
let r = e.get(this.sync.out.buffer), i = Math.ceil(t.rate * n.Second.fromMilli(r));
|
|
479
|
+
t.setLatency(i);
|
|
480
|
+
}
|
|
481
|
+
#d(t) {
|
|
482
|
+
let n = e(t.get(this.sync.in.latency)).min;
|
|
483
|
+
if (this.#a === void 0) {
|
|
484
|
+
this.#a = n;
|
|
485
|
+
return;
|
|
486
|
+
}
|
|
487
|
+
let r = this.#a;
|
|
488
|
+
t.timer(() => {
|
|
489
|
+
let e = (e) => e === "real-time" ? 0 : e;
|
|
490
|
+
e(n) > e(r) && this.reset(), this.#a = n;
|
|
491
|
+
}, fe);
|
|
492
|
+
}
|
|
493
|
+
#f(e) {
|
|
494
|
+
if (!e.get(this.in.enabled)) return;
|
|
495
|
+
let t = e.get(this.source.in.broadcast);
|
|
496
|
+
if (!t) return;
|
|
497
|
+
let n = e.get(this.source.out.track);
|
|
498
|
+
if (!n) return;
|
|
499
|
+
let r = e.get(this.source.out.config);
|
|
500
|
+
if (!r) return;
|
|
501
|
+
let i = t.relativeBroadcast(e, r.broadcast);
|
|
502
|
+
if (!i) return;
|
|
503
|
+
this.#o.opened();
|
|
504
|
+
let a = ce(e, {
|
|
505
|
+
broadcast: i,
|
|
506
|
+
track: n,
|
|
507
|
+
maxLatency: this.sync.out.maxBuffer
|
|
508
|
+
});
|
|
509
|
+
r.container.kind === "cmaf" ? this.#m(e, a, r) : this.#p(e, a, r);
|
|
510
|
+
}
|
|
511
|
+
#p(e, t, r) {
|
|
512
|
+
let i = r.codec === "opus" && r.description ? u.Opus.preSkip(u.Hex.toBytes(r.description)) : 0;
|
|
513
|
+
this.#i.clear(i);
|
|
514
|
+
let a = r.container.kind === "loc" ? new l.Loc.Format() : new l.Legacy.Format(), o = new l.Consumer(t, {
|
|
515
|
+
format: a,
|
|
516
|
+
latency: this.sync.out.maxBuffer
|
|
517
|
+
});
|
|
518
|
+
e.cleanup(() => o.close()), e.run((e) => {
|
|
519
|
+
let t = e.get(o.buffered), n = e.get(this.#t);
|
|
520
|
+
this.#e.buffered.update(() => l.mergeBufferedRanges(t, n));
|
|
521
|
+
}), e.spawn(async () => {
|
|
522
|
+
if (!await u.Libav.polyfill()) return;
|
|
523
|
+
let t = new de(pe), i = new AudioDecoder({
|
|
524
|
+
output: (e) => {
|
|
525
|
+
let n = this.#i.span(e);
|
|
526
|
+
if (t.drop()) {
|
|
527
|
+
e.close();
|
|
528
|
+
return;
|
|
529
|
+
}
|
|
530
|
+
this.#h(e, n);
|
|
531
|
+
},
|
|
532
|
+
error: (e) => console.error("audio decoder error", e)
|
|
533
|
+
});
|
|
534
|
+
e.cleanup(() => {
|
|
535
|
+
i.state !== "closed" && i.close();
|
|
536
|
+
});
|
|
537
|
+
let a = r.codec === "opus" ? void 0 : r.description ? u.Hex.toBytes(r.description) : void 0, s = {
|
|
538
|
+
...r,
|
|
539
|
+
description: a
|
|
540
|
+
};
|
|
541
|
+
for (i.configure(s);;) {
|
|
542
|
+
let e = await o.next();
|
|
543
|
+
if (!e) break;
|
|
544
|
+
if (this.#y(e) && (i.reset(), i.configure(s)), e.end !== void 0) continue;
|
|
545
|
+
let { frame: t } = e;
|
|
546
|
+
if (!t) continue;
|
|
547
|
+
let r = n.Milli.fromMicro(t.timestamp);
|
|
548
|
+
this.sync.received(r, "audio"), this.#e.stats.update((e) => ({ bytesReceived: (e?.bytesReceived ?? 0) + t.payload.byteLength })), await this.#n?.wait(t.timestamp);
|
|
549
|
+
let a = new EncodedAudioChunk({
|
|
550
|
+
type: t.keyframe ? "key" : "delta",
|
|
551
|
+
data: t.payload,
|
|
552
|
+
timestamp: t.timestamp
|
|
553
|
+
});
|
|
554
|
+
if (i.state === "closed") break;
|
|
555
|
+
i.decode(a);
|
|
556
|
+
}
|
|
557
|
+
});
|
|
558
|
+
}
|
|
559
|
+
#m(e, t, r) {
|
|
560
|
+
if (r.container.kind !== "cmaf") return;
|
|
561
|
+
let i = p(r.container.init), a = l.Cmaf.decodeInitSegment(i), o = r.description ? u.Hex.toBytes(r.description) : a.description, s = r.codec === "opus" && o ? u.Opus.preSkip(o) : 0;
|
|
562
|
+
this.#i.clear(s);
|
|
563
|
+
let c = r.codec === "opus" ? void 0 : r.description ? u.Hex.toBytes(r.description) : a.description, d = new l.Consumer(t, {
|
|
564
|
+
format: new l.Cmaf.Format(a),
|
|
565
|
+
latency: this.sync.out.maxBuffer
|
|
566
|
+
});
|
|
567
|
+
e.cleanup(() => d.close()), e.run((e) => {
|
|
568
|
+
let t = e.get(d.buffered), n = e.get(this.#t);
|
|
569
|
+
this.#e.buffered.update(() => l.mergeBufferedRanges(t, n));
|
|
570
|
+
}), e.spawn(async () => {
|
|
571
|
+
if (!await u.Libav.polyfill()) return;
|
|
572
|
+
let t = new AudioDecoder({
|
|
573
|
+
output: (e) => this.#h(e),
|
|
574
|
+
error: (e) => console.error("audio decoder error", e)
|
|
575
|
+
});
|
|
576
|
+
e.cleanup(() => {
|
|
577
|
+
t.state !== "closed" && t.close();
|
|
578
|
+
});
|
|
579
|
+
let i = {
|
|
580
|
+
codec: r.codec,
|
|
581
|
+
sampleRate: r.sampleRate,
|
|
582
|
+
numberOfChannels: r.numberOfChannels,
|
|
583
|
+
description: c
|
|
584
|
+
};
|
|
585
|
+
for (t.configure(i);;) {
|
|
586
|
+
let e = await d.next();
|
|
587
|
+
if (!e) break;
|
|
588
|
+
this.#y(e) && (t.reset(), t.configure(i));
|
|
589
|
+
let { frame: r } = e;
|
|
590
|
+
if (!r) continue;
|
|
591
|
+
let a = n.Milli.fromMicro(r.timestamp);
|
|
592
|
+
if (this.sync.received(a, "audio"), this.#e.stats.update((e) => ({ bytesReceived: (e?.bytesReceived ?? 0) + r.payload.byteLength })), await this.#n?.wait(r.timestamp), t.state === "closed") break;
|
|
593
|
+
t.decode(new EncodedAudioChunk({
|
|
594
|
+
type: r.keyframe ? "key" : "delta",
|
|
595
|
+
data: r.payload,
|
|
596
|
+
timestamp: r.timestamp
|
|
597
|
+
}));
|
|
598
|
+
}
|
|
599
|
+
});
|
|
600
|
+
}
|
|
601
|
+
#h(e, t = this.#i.span(e)) {
|
|
602
|
+
let { timestamp: r, frameOffset: i, frames: a } = t, o = n.Milli.fromMicro(r);
|
|
603
|
+
if (a === 0) {
|
|
604
|
+
e.close();
|
|
605
|
+
return;
|
|
606
|
+
}
|
|
607
|
+
let s = this.#n;
|
|
608
|
+
if (!s) {
|
|
609
|
+
e.close();
|
|
610
|
+
return;
|
|
611
|
+
}
|
|
612
|
+
if (e.sampleRate !== s.rate) {
|
|
613
|
+
this.#r.set(e.sampleRate), e.close();
|
|
614
|
+
return;
|
|
615
|
+
}
|
|
616
|
+
let c = a / e.sampleRate * 1e6, l = n.Milli.fromMicro(c), u = n.Milli.add(o, l);
|
|
617
|
+
this.#o.takeover() && (s.truncate(r), this.#_(o)), this.#g(o, u);
|
|
618
|
+
let d = Math.min(e.numberOfChannels, s.channels), f = [];
|
|
619
|
+
for (let t = 0; t < d; t++) {
|
|
620
|
+
let n = new Float32Array(a);
|
|
621
|
+
e.copyTo(n, {
|
|
622
|
+
format: "f32-planar",
|
|
623
|
+
planeIndex: t,
|
|
624
|
+
frameOffset: i,
|
|
625
|
+
frameCount: a
|
|
626
|
+
}), f.push(n);
|
|
627
|
+
}
|
|
628
|
+
s.insert(r, f), e.close();
|
|
629
|
+
}
|
|
630
|
+
#g(e, t) {
|
|
631
|
+
e > t || this.#t.mutate((r) => {
|
|
632
|
+
for (let i of r) if (e <= i.end + 1 && t >= i.start) {
|
|
633
|
+
i.start = n.Milli.min(i.start, e), i.end = n.Milli.max(i.end, t);
|
|
634
|
+
return;
|
|
635
|
+
}
|
|
636
|
+
r.push({
|
|
637
|
+
start: e,
|
|
638
|
+
end: t
|
|
639
|
+
}), r.sort((e, t) => e.start - t.start);
|
|
640
|
+
});
|
|
641
|
+
}
|
|
642
|
+
#_(e) {
|
|
643
|
+
this.#t.mutate((t) => {
|
|
644
|
+
for (; t.length > 0 && t[t.length - 1].start >= e;) t.pop();
|
|
645
|
+
let n = t[t.length - 1];
|
|
646
|
+
n && n.end > e && (n.end = e);
|
|
647
|
+
});
|
|
648
|
+
}
|
|
649
|
+
#v(e) {
|
|
650
|
+
this.#t.mutate((t) => {
|
|
651
|
+
for (; t.length > 0;) {
|
|
652
|
+
if (t[0].end >= e) {
|
|
653
|
+
t[0].start = n.Milli.max(t[0].start, e);
|
|
654
|
+
break;
|
|
655
|
+
}
|
|
656
|
+
t.shift();
|
|
657
|
+
}
|
|
658
|
+
});
|
|
659
|
+
}
|
|
660
|
+
reset() {
|
|
661
|
+
this.#n?.reset();
|
|
662
|
+
}
|
|
663
|
+
#y(e) {
|
|
664
|
+
return this.#i.update(e) ? (this.#n?.reset(), this.sync.reset(), !0) : !1;
|
|
665
|
+
}
|
|
666
|
+
close() {
|
|
667
|
+
this.#s.close();
|
|
668
|
+
}
|
|
669
|
+
static supported = he;
|
|
670
|
+
};
|
|
671
|
+
async function he(e) {
|
|
672
|
+
if (!s.containerSupported(e.container)) {
|
|
673
|
+
let t = e.container.kind === "unknown" ? e.container.raw.kind : e.container.kind;
|
|
674
|
+
return console.warn(`audio: ignoring rendition with unknown container: ${t}`), !1;
|
|
675
|
+
}
|
|
676
|
+
e.codec === "opus" && !u.Opus.supportsRate(e.sampleRate) && console.warn(`audio: opus advertised at ${e.sampleRate}Hz, which some browsers cannot decode`);
|
|
677
|
+
let t;
|
|
678
|
+
if (e.codec !== "opus") {
|
|
679
|
+
if (e.description) t = u.Hex.toBytes(e.description);
|
|
680
|
+
else if (e.container.kind === "cmaf") try {
|
|
681
|
+
t = l.Cmaf.decodeInitSegment(p(e.container.init)).description;
|
|
682
|
+
} catch (t) {
|
|
683
|
+
return console.warn(`audio: malformed CMAF init segment for codec ${e.codec}`, t), !1;
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
return (await AudioDecoder.isConfigSupported({
|
|
687
|
+
...e,
|
|
688
|
+
description: t
|
|
689
|
+
})).supported ?? !1;
|
|
690
|
+
}
|
|
691
|
+
//#endregion
|
|
692
|
+
//#region src/audio/emitter.ts
|
|
693
|
+
var O = .001, k = .2, A = class {
|
|
694
|
+
source;
|
|
695
|
+
in;
|
|
696
|
+
#e = { enabled: new i(!1) };
|
|
697
|
+
out = o(this.#e);
|
|
698
|
+
#t = new r();
|
|
699
|
+
#n = new i(void 0);
|
|
700
|
+
constructor(e, t) {
|
|
701
|
+
this.source = e, this.in = {
|
|
702
|
+
volume: a(t?.volume ?? .5),
|
|
703
|
+
muted: a(t?.muted ?? !1),
|
|
704
|
+
paused: a(t?.paused ?? !1)
|
|
705
|
+
}, this.#t.run((e) => {
|
|
706
|
+
let t = !e.get(this.in.paused);
|
|
707
|
+
this.#e.enabled.set(t);
|
|
708
|
+
}), this.#t.run((e) => {
|
|
709
|
+
let t = e.get(this.source.out.root);
|
|
710
|
+
if (!t) return;
|
|
711
|
+
let n = new GainNode(t.context, { gain: e.get(this.in.volume) });
|
|
712
|
+
t.connect(n), e.set(this.#n, n), e.run((e) => {
|
|
713
|
+
e.get(this.#e.enabled) && (n.connect(t.context.destination), e.cleanup(() => n.disconnect()));
|
|
714
|
+
});
|
|
715
|
+
}), this.#t.run((e) => {
|
|
716
|
+
let t = e.get(this.source.out.root);
|
|
717
|
+
if (!t || e.get(this.in.muted)) return;
|
|
718
|
+
let n = t.context;
|
|
719
|
+
n.state === "suspended" && n.resume();
|
|
720
|
+
}), this.#t.run((e) => {
|
|
721
|
+
let t = e.get(this.#n);
|
|
722
|
+
if (!t) return;
|
|
723
|
+
e.cleanup(() => t.gain.cancelScheduledValues(t.context.currentTime));
|
|
724
|
+
let n = e.get(this.in.volume);
|
|
725
|
+
n < O ? (t.gain.exponentialRampToValueAtTime(O, t.context.currentTime + k), t.gain.setValueAtTime(0, t.context.currentTime + k + .01)) : t.gain.exponentialRampToValueAtTime(n, t.context.currentTime + k);
|
|
726
|
+
});
|
|
727
|
+
}
|
|
728
|
+
close() {
|
|
729
|
+
this.#t.close();
|
|
730
|
+
}
|
|
731
|
+
}, j = 128, M = class {
|
|
732
|
+
in;
|
|
733
|
+
#e = {
|
|
734
|
+
catalog: new i(void 0),
|
|
735
|
+
available: new i({}),
|
|
736
|
+
track: new i(void 0),
|
|
737
|
+
config: new i(void 0),
|
|
738
|
+
jitter: new i(void 0)
|
|
739
|
+
};
|
|
740
|
+
out = o(this.#e);
|
|
741
|
+
#t = new r();
|
|
742
|
+
constructor(e) {
|
|
743
|
+
this.in = {
|
|
744
|
+
broadcast: a(e?.broadcast),
|
|
745
|
+
target: a(e?.target),
|
|
746
|
+
supported: a(e?.supported)
|
|
747
|
+
}, this.#t.run(this.#n.bind(this)), this.#t.run(this.#r.bind(this)), this.#t.run(this.#i.bind(this));
|
|
748
|
+
}
|
|
749
|
+
#n(e) {
|
|
750
|
+
let t = e.get(this.in.broadcast);
|
|
751
|
+
if (!t) return;
|
|
752
|
+
let n = e.get(t.out.catalog)?.audio;
|
|
753
|
+
n && e.set(this.#e.catalog, n);
|
|
754
|
+
}
|
|
755
|
+
#r(e) {
|
|
756
|
+
let t = e.get(this.#e.catalog)?.renditions ?? {}, n = e.get(this.in.supported);
|
|
757
|
+
n && e.spawn(async () => {
|
|
758
|
+
let r = {}, i = e.cancel.then(() => void 0);
|
|
759
|
+
for (let [a, o] of Object.entries(t)) {
|
|
760
|
+
let t = await Promise.race([n(o), i]);
|
|
761
|
+
if (e.abort.aborted) return;
|
|
762
|
+
t && (r[a] = o);
|
|
763
|
+
}
|
|
764
|
+
Object.keys(r).length === 0 && Object.keys(t).length > 0 && console.warn("no supported audio renditions found:", t), this.#e.available.set(r);
|
|
765
|
+
});
|
|
766
|
+
}
|
|
767
|
+
#i(e) {
|
|
768
|
+
let t = e.get(this.#e.available);
|
|
769
|
+
if (Object.keys(t).length === 0) return;
|
|
770
|
+
let r = e.get(this.in.target), i;
|
|
771
|
+
if (r?.name && r.name in t) i = {
|
|
772
|
+
track: r.name,
|
|
773
|
+
config: t[r.name]
|
|
774
|
+
};
|
|
775
|
+
else if (i = this.#a(t), !i) return;
|
|
776
|
+
e.set(this.#e.track, i.track), e.set(this.#e.config, i.config);
|
|
777
|
+
let a = (i.config.jitter ?? N(i.config) ?? 0) + Math.ceil(j / i.config.sampleRate * 1e3);
|
|
778
|
+
e.set(this.#e.jitter, n.Milli(a));
|
|
779
|
+
}
|
|
780
|
+
#a(e) {
|
|
781
|
+
let t = Object.entries(e);
|
|
782
|
+
if (t.length !== 0) {
|
|
783
|
+
for (let [e, n] of t) if (n.container.kind === "legacy") return {
|
|
784
|
+
track: e,
|
|
785
|
+
config: n
|
|
786
|
+
};
|
|
787
|
+
for (let [e, n] of t) if (n.container.kind === "loc") return {
|
|
788
|
+
track: e,
|
|
789
|
+
config: n
|
|
790
|
+
};
|
|
791
|
+
for (let [e, n] of t) if (n.container.kind === "cmaf") return {
|
|
792
|
+
track: e,
|
|
793
|
+
config: n
|
|
794
|
+
};
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
close() {
|
|
798
|
+
this.#t.close();
|
|
799
|
+
}
|
|
800
|
+
};
|
|
801
|
+
function N(e) {
|
|
802
|
+
if (e.codec.startsWith("opus")) return 20;
|
|
803
|
+
if (e.codec.startsWith("mp4a")) return Math.ceil(1024 / e.sampleRate * 1e3);
|
|
804
|
+
if (e.codec === "mp3") {
|
|
805
|
+
let t = e.sampleRate >= 32e3 ? 1152 : 576;
|
|
806
|
+
return Math.ceil(t / e.sampleRate * 1e3);
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
//#endregion
|
|
810
|
+
//#region src/msf.ts
|
|
811
|
+
var P = 48e3, F = 2;
|
|
812
|
+
function I(e) {
|
|
813
|
+
let t = "";
|
|
814
|
+
for (let n = 0; n < e.length; n++) t += e[n].toString(16).padStart(2, "0");
|
|
815
|
+
return t;
|
|
816
|
+
}
|
|
817
|
+
function L(e) {
|
|
818
|
+
let t;
|
|
819
|
+
try {
|
|
820
|
+
t = e.initData ? p(e.initData) : void 0;
|
|
821
|
+
} catch {
|
|
822
|
+
t = void 0;
|
|
823
|
+
}
|
|
824
|
+
let n = t ? I(t) : void 0;
|
|
825
|
+
switch (e.packaging) {
|
|
826
|
+
case "cmaf": return !e.initData || !t ? void 0 : {
|
|
827
|
+
container: {
|
|
828
|
+
kind: "cmaf",
|
|
829
|
+
init: e.initData
|
|
830
|
+
},
|
|
831
|
+
description: void 0
|
|
832
|
+
};
|
|
833
|
+
case "loc": return {
|
|
834
|
+
container: { kind: "loc" },
|
|
835
|
+
description: n
|
|
836
|
+
};
|
|
837
|
+
case "legacy": return {
|
|
838
|
+
container: { kind: "legacy" },
|
|
839
|
+
description: n
|
|
840
|
+
};
|
|
841
|
+
default: return;
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
function R(e) {
|
|
845
|
+
if (!e.codec) return;
|
|
846
|
+
let t = L(e);
|
|
847
|
+
if (!t) return;
|
|
848
|
+
let { container: n, description: r } = t;
|
|
849
|
+
return {
|
|
850
|
+
codec: e.codec,
|
|
851
|
+
container: n,
|
|
852
|
+
description: r,
|
|
853
|
+
codedWidth: e.width == null ? void 0 : c(e.width),
|
|
854
|
+
codedHeight: e.height == null ? void 0 : c(e.height),
|
|
855
|
+
framerate: e.framerate,
|
|
856
|
+
bitrate: e.bitrate == null ? void 0 : c(e.bitrate),
|
|
857
|
+
stalled: e.stalled,
|
|
858
|
+
jitter: e.jitter == null ? void 0 : c(e.jitter)
|
|
859
|
+
};
|
|
860
|
+
}
|
|
861
|
+
function ge(e) {
|
|
862
|
+
if (!e.codec) return;
|
|
863
|
+
let t = (() => {
|
|
864
|
+
if (!e.channelConfig) return F;
|
|
865
|
+
let t = Number.parseInt(e.channelConfig, 10);
|
|
866
|
+
return Number.isFinite(t) ? t : F;
|
|
867
|
+
})(), n = L(e);
|
|
868
|
+
if (!n) return;
|
|
869
|
+
let { container: r, description: i } = n;
|
|
870
|
+
return {
|
|
871
|
+
codec: e.codec,
|
|
872
|
+
container: r,
|
|
873
|
+
description: i,
|
|
874
|
+
sampleRate: c(e.samplerate ?? P),
|
|
875
|
+
numberOfChannels: c(t),
|
|
876
|
+
bitrate: e.bitrate == null ? void 0 : c(e.bitrate),
|
|
877
|
+
jitter: e.jitter == null ? void 0 : c(e.jitter)
|
|
878
|
+
};
|
|
879
|
+
}
|
|
880
|
+
function _e(e) {
|
|
881
|
+
let t = {}, n = {};
|
|
882
|
+
for (let r of e.tracks) if (r.role === "video") {
|
|
883
|
+
let e = R(r);
|
|
884
|
+
e && (t[r.name] = e);
|
|
885
|
+
} else if (r.role === "audio") {
|
|
886
|
+
let e = ge(r);
|
|
887
|
+
e && (n[r.name] = e);
|
|
888
|
+
}
|
|
889
|
+
let r = {};
|
|
890
|
+
return Object.keys(t).length > 0 && (r.video = { renditions: t }), Object.keys(n).length > 0 && (r.audio = { renditions: n }), r;
|
|
891
|
+
}
|
|
892
|
+
//#endregion
|
|
893
|
+
//#region src/broadcast.ts
|
|
894
|
+
var z = /* @__PURE__ */ new WeakSet();
|
|
895
|
+
function B(e) {
|
|
896
|
+
return !e.discovery && (z.has(e) || (z.add(e), console.warn("relay does not support broadcast discovery; subscribing to siblings blind.")), !0);
|
|
897
|
+
}
|
|
898
|
+
function V(e, t) {
|
|
899
|
+
return Object.fromEntries(Object.entries(e).filter(([, e]) => t(e.broadcast)));
|
|
900
|
+
}
|
|
901
|
+
function ve(e, t) {
|
|
902
|
+
return {
|
|
903
|
+
...e,
|
|
904
|
+
video: e.video ? {
|
|
905
|
+
...e.video,
|
|
906
|
+
renditions: V(e.video.renditions, t)
|
|
907
|
+
} : void 0,
|
|
908
|
+
audio: e.audio ? {
|
|
909
|
+
...e.audio,
|
|
910
|
+
renditions: V(e.audio.renditions, t)
|
|
911
|
+
} : void 0
|
|
912
|
+
};
|
|
913
|
+
}
|
|
914
|
+
var H = [
|
|
915
|
+
...s.FORMATS,
|
|
916
|
+
"hangz",
|
|
917
|
+
"manual"
|
|
918
|
+
];
|
|
919
|
+
function ye(e) {
|
|
920
|
+
if (e !== null) return H.find((t) => t === e);
|
|
921
|
+
}
|
|
922
|
+
var be = class {
|
|
923
|
+
in;
|
|
924
|
+
#e = {
|
|
925
|
+
status: new i("offline"),
|
|
926
|
+
active: new i(void 0),
|
|
927
|
+
catalog: new i(void 0)
|
|
928
|
+
};
|
|
929
|
+
out = o(this.#e);
|
|
930
|
+
#t = new i(void 0);
|
|
931
|
+
#n = new i(!1);
|
|
932
|
+
#r = new i(void 0);
|
|
933
|
+
#i = new r();
|
|
934
|
+
constructor(e) {
|
|
935
|
+
this.in = {
|
|
936
|
+
connection: a(e?.connection),
|
|
937
|
+
name: a(e?.name ?? t.empty()),
|
|
938
|
+
enabled: a(e?.enabled ?? !1),
|
|
939
|
+
reload: a(e?.reload ?? !0),
|
|
940
|
+
catalogFormat: a(e?.catalogFormat),
|
|
941
|
+
catalog: a(e?.catalog)
|
|
942
|
+
}, this.#i.run(this.#a.bind(this)), this.#i.run(this.#c.bind(this)), this.#i.run(this.#l.bind(this)), this.#i.run(this.#o.bind(this));
|
|
943
|
+
}
|
|
944
|
+
#a(e) {
|
|
945
|
+
if (this.#t.set(void 0), !e.get(this.#n) || !e.get(this.in.reload)) return;
|
|
946
|
+
let n = e.get(this.in.connection);
|
|
947
|
+
if (!n || B(n)) return;
|
|
948
|
+
let r = n.announced(t.empty());
|
|
949
|
+
e.cleanup(() => r.close()), this.#t.set(/* @__PURE__ */ new Set()), e.spawn(async () => {
|
|
950
|
+
for (;;) {
|
|
951
|
+
let t = await Promise.race([e.cancel, r.next()]);
|
|
952
|
+
if (!t) break;
|
|
953
|
+
this.#t.mutate((e) => {
|
|
954
|
+
e && (t.active ? e.add(t.path) : e.delete(t.path));
|
|
955
|
+
});
|
|
956
|
+
}
|
|
957
|
+
});
|
|
958
|
+
}
|
|
959
|
+
#o(e) {
|
|
960
|
+
let t = e.get(this.#r);
|
|
961
|
+
e.set(this.#e.catalog, t ? ve(t, (t) => this.#u(e, t) !== void 0) : void 0);
|
|
962
|
+
}
|
|
963
|
+
#s(e, t) {
|
|
964
|
+
if (!e.get(this.in.reload)) return !0;
|
|
965
|
+
let n = e.get(this.in.connection);
|
|
966
|
+
if (!n || B(n)) return !0;
|
|
967
|
+
this.#n.set(!0);
|
|
968
|
+
let r = e.get(this.#t);
|
|
969
|
+
return r ? r.has(t) : !1;
|
|
970
|
+
}
|
|
971
|
+
#c(e) {
|
|
972
|
+
if (!e.get(this.in.enabled)) return;
|
|
973
|
+
let t = e.get(this.in.connection);
|
|
974
|
+
if (!t) return;
|
|
975
|
+
let n = e.get(this.in.name);
|
|
976
|
+
if (!e.get(this.in.reload)) {
|
|
977
|
+
let r = t.consume(n);
|
|
978
|
+
e.cleanup(() => r.close()), e.set(this.#e.active, r, void 0);
|
|
979
|
+
return;
|
|
980
|
+
}
|
|
981
|
+
let r = t.announcedBroadcast(n);
|
|
982
|
+
e.cleanup(() => r.close()), e.run((e) => {
|
|
983
|
+
e.set(this.#e.active, e.get(r.active), void 0);
|
|
984
|
+
});
|
|
985
|
+
}
|
|
986
|
+
#l(e) {
|
|
987
|
+
if (!e.get(this.in.enabled)) return;
|
|
988
|
+
let t = e.get(this.in.catalogFormat), n = e.get(this.in.name), r = t ?? s.detectFormat(n) ?? s.DEFAULT_FORMAT;
|
|
989
|
+
if (r === "manual") {
|
|
990
|
+
let t = e.get(this.in.catalog);
|
|
991
|
+
this.#r.set(t, !0), e.cleanup(() => this.#r.set(void 0, !0)), this.#e.status.set(t ? "live" : "loading");
|
|
992
|
+
return;
|
|
993
|
+
}
|
|
994
|
+
let i = e.get(this.out.active);
|
|
995
|
+
if (!i) return;
|
|
996
|
+
this.#e.status.set("loading");
|
|
997
|
+
let a = r === "hang" ? s.TRACK : r === "hangz" ? s.TRACK_COMPRESSED : "catalog", o = i.track(a).subscribe({ priority: s.PRIORITY.catalog });
|
|
998
|
+
e.cleanup(() => o.close());
|
|
999
|
+
let c;
|
|
1000
|
+
if (r === "hang" || r === "hangz") {
|
|
1001
|
+
let e = new d.Snapshot.Consumer(o, {
|
|
1002
|
+
schema: s.RootSchema,
|
|
1003
|
+
compression: r === "hangz"
|
|
1004
|
+
});
|
|
1005
|
+
c = () => e.next();
|
|
1006
|
+
} else c = async () => {
|
|
1007
|
+
let e = await f.fetch(o);
|
|
1008
|
+
return e ? _e(e) : void 0;
|
|
1009
|
+
};
|
|
1010
|
+
e.spawn(async () => {
|
|
1011
|
+
try {
|
|
1012
|
+
for (;;) {
|
|
1013
|
+
let t = await Promise.race([e.cancel, c()]);
|
|
1014
|
+
if (!t) break;
|
|
1015
|
+
console.debug("received catalog", r, this.in.name.peek(), t), this.#r.set(t, !0), this.#e.status.set("live");
|
|
1016
|
+
}
|
|
1017
|
+
} catch (e) {
|
|
1018
|
+
console.warn("error fetching catalog", this.in.name.peek(), e);
|
|
1019
|
+
} finally {
|
|
1020
|
+
this.#r.set(void 0), this.#e.status.set("offline");
|
|
1021
|
+
}
|
|
1022
|
+
});
|
|
1023
|
+
}
|
|
1024
|
+
#u(e, n) {
|
|
1025
|
+
if (!n) return { local: !0 };
|
|
1026
|
+
let r = e.get(this.in.name), i = t.tryResolve(r, n);
|
|
1027
|
+
if (i !== void 0) {
|
|
1028
|
+
if (i === r) return { local: !0 };
|
|
1029
|
+
if (this.#s(e, i)) return {
|
|
1030
|
+
local: !1,
|
|
1031
|
+
path: i
|
|
1032
|
+
};
|
|
1033
|
+
}
|
|
1034
|
+
}
|
|
1035
|
+
relativeBroadcast(e, t) {
|
|
1036
|
+
let n = this.#u(e, t);
|
|
1037
|
+
if (!n) return;
|
|
1038
|
+
if (n.local) return e.get(this.out.active);
|
|
1039
|
+
if (!e.get(this.in.enabled)) return;
|
|
1040
|
+
let r = e.get(this.in.connection);
|
|
1041
|
+
if (!r) return;
|
|
1042
|
+
let i = r.consume(n.path);
|
|
1043
|
+
return e.cleanup(() => i.close()), i;
|
|
1044
|
+
}
|
|
1045
|
+
close() {
|
|
1046
|
+
this.#i.close();
|
|
1047
|
+
}
|
|
1048
|
+
}, U = Symbol("supportCacheKey");
|
|
1049
|
+
function W(e) {
|
|
1050
|
+
return {
|
|
1051
|
+
broadcast: e.broadcast,
|
|
1052
|
+
decoder: {
|
|
1053
|
+
codec: e.codec,
|
|
1054
|
+
container: e.container,
|
|
1055
|
+
description: e.description,
|
|
1056
|
+
displayAspectWidth: e.displayAspectWidth,
|
|
1057
|
+
displayAspectHeight: e.displayAspectHeight,
|
|
1058
|
+
optimizeForLatency: e.optimizeForLatency ?? !0
|
|
1059
|
+
}
|
|
1060
|
+
};
|
|
1061
|
+
}
|
|
1062
|
+
function xe(e) {
|
|
1063
|
+
return JSON.stringify(W(e).decoder);
|
|
1064
|
+
}
|
|
1065
|
+
//#endregion
|
|
1066
|
+
//#region src/video/playhead.ts
|
|
1067
|
+
var Se = n.Milli(100);
|
|
1068
|
+
function G(e) {
|
|
1069
|
+
if (e.jitter !== void 0) return n.Milli(e.jitter);
|
|
1070
|
+
if (e.framerate) return n.Milli(Math.ceil(1e3 / e.framerate));
|
|
1071
|
+
}
|
|
1072
|
+
function Ce(e) {
|
|
1073
|
+
return e.active === void 0 || n.Milli.add(e.playhead, Se) >= e.active;
|
|
1074
|
+
}
|
|
1075
|
+
//#endregion
|
|
1076
|
+
//#region src/video/presentation.ts
|
|
1077
|
+
function K(e = 0) {
|
|
1078
|
+
let t = (e % 360 + 360) % 360;
|
|
1079
|
+
return Math.round(t / 90) % 4 * 90;
|
|
1080
|
+
}
|
|
1081
|
+
function q(e, t = 0) {
|
|
1082
|
+
let n = K(t);
|
|
1083
|
+
return n === 90 || n === 270 ? {
|
|
1084
|
+
width: e.height,
|
|
1085
|
+
height: e.width
|
|
1086
|
+
} : {
|
|
1087
|
+
width: e.width,
|
|
1088
|
+
height: e.height
|
|
1089
|
+
};
|
|
1090
|
+
}
|
|
1091
|
+
function J(e) {
|
|
1092
|
+
return Object.is(e, -0) ? 0 : e;
|
|
1093
|
+
}
|
|
1094
|
+
function we(e, t) {
|
|
1095
|
+
let [n, r, i, a, o, s] = e;
|
|
1096
|
+
return [
|
|
1097
|
+
J(-n),
|
|
1098
|
+
J(r),
|
|
1099
|
+
J(-i),
|
|
1100
|
+
J(a),
|
|
1101
|
+
J(t - o),
|
|
1102
|
+
J(s)
|
|
1103
|
+
];
|
|
1104
|
+
}
|
|
1105
|
+
function Te(e, t) {
|
|
1106
|
+
let n = K(t?.rotation), r = q(e, n), i;
|
|
1107
|
+
switch (n) {
|
|
1108
|
+
case 90:
|
|
1109
|
+
i = [
|
|
1110
|
+
0,
|
|
1111
|
+
1,
|
|
1112
|
+
-1,
|
|
1113
|
+
0,
|
|
1114
|
+
e.width,
|
|
1115
|
+
0
|
|
1116
|
+
];
|
|
1117
|
+
break;
|
|
1118
|
+
case 180:
|
|
1119
|
+
i = [
|
|
1120
|
+
-1,
|
|
1121
|
+
0,
|
|
1122
|
+
0,
|
|
1123
|
+
-1,
|
|
1124
|
+
e.width,
|
|
1125
|
+
e.height
|
|
1126
|
+
];
|
|
1127
|
+
break;
|
|
1128
|
+
case 270:
|
|
1129
|
+
i = [
|
|
1130
|
+
0,
|
|
1131
|
+
-1,
|
|
1132
|
+
1,
|
|
1133
|
+
0,
|
|
1134
|
+
0,
|
|
1135
|
+
e.height
|
|
1136
|
+
];
|
|
1137
|
+
break;
|
|
1138
|
+
default: i = [
|
|
1139
|
+
1,
|
|
1140
|
+
0,
|
|
1141
|
+
0,
|
|
1142
|
+
1,
|
|
1143
|
+
0,
|
|
1144
|
+
0
|
|
1145
|
+
];
|
|
1146
|
+
}
|
|
1147
|
+
return t?.flip && (i = we(i, e.width)), {
|
|
1148
|
+
matrix: i,
|
|
1149
|
+
source: r
|
|
1150
|
+
};
|
|
1151
|
+
}
|
|
1152
|
+
//#endregion
|
|
1153
|
+
//#region src/video/decoder.ts
|
|
1154
|
+
var Ee = n.Milli(500), De = class {
|
|
1155
|
+
in;
|
|
1156
|
+
source;
|
|
1157
|
+
sync;
|
|
1158
|
+
#e = {
|
|
1159
|
+
frame: new i(void 0),
|
|
1160
|
+
timestamp: new i(void 0),
|
|
1161
|
+
display: new i(void 0),
|
|
1162
|
+
stalled: new i(!1),
|
|
1163
|
+
stats: new i(void 0),
|
|
1164
|
+
buffered: new i([])
|
|
1165
|
+
};
|
|
1166
|
+
out = o(this.#e);
|
|
1167
|
+
#t = new i(void 0);
|
|
1168
|
+
#n;
|
|
1169
|
+
#r = new r();
|
|
1170
|
+
#i() {
|
|
1171
|
+
this.#e.frame.update((e) => {
|
|
1172
|
+
e?.close();
|
|
1173
|
+
}), this.#e.timestamp.set(void 0);
|
|
1174
|
+
}
|
|
1175
|
+
constructor(e, t, n) {
|
|
1176
|
+
this.in = {
|
|
1177
|
+
enabled: a(n?.enabled ?? !1),
|
|
1178
|
+
paced: a(n?.paced ?? !0)
|
|
1179
|
+
}, this.source = e, this.sync = t, this.#n = this.#r.computed((e) => {
|
|
1180
|
+
let t = e.get(this.source.out.config);
|
|
1181
|
+
return t ? W(t) : void 0;
|
|
1182
|
+
}), this.#r.run(this.#a.bind(this)), this.#r.run(this.#o.bind(this)), this.#r.run(this.#s.bind(this)), this.#r.run(this.#c.bind(this));
|
|
1183
|
+
}
|
|
1184
|
+
#a(e) {
|
|
1185
|
+
let t = e.getAll([
|
|
1186
|
+
this.in.enabled,
|
|
1187
|
+
this.source.in.broadcast,
|
|
1188
|
+
this.source.out.track,
|
|
1189
|
+
this.#n
|
|
1190
|
+
]);
|
|
1191
|
+
if (!t) {
|
|
1192
|
+
this.#t.set(void 0);
|
|
1193
|
+
return;
|
|
1194
|
+
}
|
|
1195
|
+
let [n, r, i, a] = t, o = r.relativeBroadcast(e, a.broadcast);
|
|
1196
|
+
if (!o) {
|
|
1197
|
+
this.#t.set(void 0), this.#i(), this.#e.buffered.set([]);
|
|
1198
|
+
return;
|
|
1199
|
+
}
|
|
1200
|
+
let s = new Y({
|
|
1201
|
+
sync: this.sync,
|
|
1202
|
+
paced: this.in.paced,
|
|
1203
|
+
broadcast: o,
|
|
1204
|
+
track: i,
|
|
1205
|
+
config: a.decoder,
|
|
1206
|
+
stats: this.#e.stats
|
|
1207
|
+
});
|
|
1208
|
+
e.cleanup(() => s?.close()), e.run((e) => {
|
|
1209
|
+
if (!s) return;
|
|
1210
|
+
let t = e.get(this.#t);
|
|
1211
|
+
if (t) {
|
|
1212
|
+
let n = e.get(s.timestamp);
|
|
1213
|
+
if (n === void 0 || !Ce({
|
|
1214
|
+
playhead: n,
|
|
1215
|
+
active: e.get(t.timestamp)
|
|
1216
|
+
})) return;
|
|
1217
|
+
}
|
|
1218
|
+
this.#t.set(s), s = void 0, e.close();
|
|
1219
|
+
});
|
|
1220
|
+
}
|
|
1221
|
+
#o(e) {
|
|
1222
|
+
let t = e.get(this.#t);
|
|
1223
|
+
if (!t) {
|
|
1224
|
+
this.#e.buffered.set([]);
|
|
1225
|
+
return;
|
|
1226
|
+
}
|
|
1227
|
+
e.cleanup(() => t.close()), e.run((e) => {
|
|
1228
|
+
let n = e.get(t.frame);
|
|
1229
|
+
this.#e.frame.update((e) => (e?.close(), n?.clone()));
|
|
1230
|
+
}), e.proxy(this.#e.timestamp, t.timestamp), e.proxy(this.#e.buffered, t.buffered);
|
|
1231
|
+
}
|
|
1232
|
+
#s(e) {
|
|
1233
|
+
let t = e.get(this.source.out.catalog);
|
|
1234
|
+
if (!t) return;
|
|
1235
|
+
let n = t.display;
|
|
1236
|
+
if (n) {
|
|
1237
|
+
e.set(this.#e.display, {
|
|
1238
|
+
width: n.width,
|
|
1239
|
+
height: n.height
|
|
1240
|
+
});
|
|
1241
|
+
return;
|
|
1242
|
+
}
|
|
1243
|
+
let r = e.get(this.#e.frame);
|
|
1244
|
+
r && e.set(this.#e.display, q({
|
|
1245
|
+
width: r.displayWidth,
|
|
1246
|
+
height: r.displayHeight
|
|
1247
|
+
}, t.rotation));
|
|
1248
|
+
}
|
|
1249
|
+
#c(e) {
|
|
1250
|
+
if (e.get(this.in.enabled)) {
|
|
1251
|
+
if (!e.get(this.#e.frame)) {
|
|
1252
|
+
this.#e.stalled.set(!0);
|
|
1253
|
+
return;
|
|
1254
|
+
}
|
|
1255
|
+
this.#e.stalled.set(!1), e.timer(() => {
|
|
1256
|
+
this.#e.stalled.set(!0);
|
|
1257
|
+
}, Ee);
|
|
1258
|
+
}
|
|
1259
|
+
}
|
|
1260
|
+
close() {
|
|
1261
|
+
this.#i(), this.#r.close();
|
|
1262
|
+
}
|
|
1263
|
+
static supported = X;
|
|
1264
|
+
}, Y = class {
|
|
1265
|
+
sync;
|
|
1266
|
+
paced;
|
|
1267
|
+
broadcast;
|
|
1268
|
+
track;
|
|
1269
|
+
config;
|
|
1270
|
+
stats;
|
|
1271
|
+
timestamp = new i(void 0);
|
|
1272
|
+
frame = new i(void 0);
|
|
1273
|
+
buffered = new i([]);
|
|
1274
|
+
#e = new i([]);
|
|
1275
|
+
#t = new i(n.Milli.zero);
|
|
1276
|
+
#n = 0;
|
|
1277
|
+
#r = new r();
|
|
1278
|
+
constructor(e) {
|
|
1279
|
+
this.sync = e.sync, this.paced = e.paced, this.broadcast = e.broadcast, this.track = e.track, this.config = e.config, this.stats = e.stats, this.#r.run((e) => {
|
|
1280
|
+
let t = e.get(this.paced);
|
|
1281
|
+
this.#t.set(t ? e.get(this.sync.out.buffer) : n.Milli.zero);
|
|
1282
|
+
}), this.#r.run(this.#i.bind(this));
|
|
1283
|
+
}
|
|
1284
|
+
#i(e) {
|
|
1285
|
+
let t = this.broadcast.track(this.track).subscribe({ priority: s.PRIORITY.video });
|
|
1286
|
+
e.cleanup(() => t.close());
|
|
1287
|
+
let r = new VideoDecoder({
|
|
1288
|
+
output: async (t) => {
|
|
1289
|
+
try {
|
|
1290
|
+
let r = this.#n, i = n.Milli.fromMicro(t.timestamp);
|
|
1291
|
+
if (i < (this.timestamp.peek() ?? 0) || this.paced.peek() && (this.sync.out.reference.peek() === void 0 || (this.frame.peek() === void 0 && this.frame.set(t.clone()), !await this.#c(i, e)) || r !== this.#n || i < (this.timestamp.peek() ?? 0))) return;
|
|
1292
|
+
this.timestamp.set(i), this.#u(i), this.frame.update((e) => (e?.close(), t.clone()));
|
|
1293
|
+
} finally {
|
|
1294
|
+
t.close();
|
|
1295
|
+
}
|
|
1296
|
+
},
|
|
1297
|
+
error: (t) => {
|
|
1298
|
+
console.error(t), e.close();
|
|
1299
|
+
}
|
|
1300
|
+
});
|
|
1301
|
+
e.cleanup(() => {
|
|
1302
|
+
r.state !== "closed" && r.close();
|
|
1303
|
+
}), this.config.container.kind === "cmaf" ? this.#o(e, t, r) : this.#a(e, t, r);
|
|
1304
|
+
}
|
|
1305
|
+
#a(e, t, r) {
|
|
1306
|
+
let i = this.config.container.kind === "loc" ? new l.Loc.Format() : new l.Legacy.Format(), a = new l.Consumer(t, {
|
|
1307
|
+
format: i,
|
|
1308
|
+
latency: this.#t
|
|
1309
|
+
});
|
|
1310
|
+
e.cleanup(() => a.close()), e.run((e) => {
|
|
1311
|
+
let t = e.get(a.buffered), n = e.get(this.#e);
|
|
1312
|
+
this.buffered.update(() => l.mergeBufferedRanges(t, n));
|
|
1313
|
+
}), r.configure({
|
|
1314
|
+
codec: this.config.codec,
|
|
1315
|
+
description: this.config.description ? u.Hex.toBytes(this.config.description) : void 0,
|
|
1316
|
+
displayAspectWidth: this.config.displayAspectWidth,
|
|
1317
|
+
displayAspectHeight: this.config.displayAspectHeight,
|
|
1318
|
+
optimizeForLatency: this.config.optimizeForLatency,
|
|
1319
|
+
flip: !1
|
|
1320
|
+
});
|
|
1321
|
+
let o;
|
|
1322
|
+
e.spawn(async () => {
|
|
1323
|
+
for (;;) {
|
|
1324
|
+
let e = await a.next();
|
|
1325
|
+
if (!e) break;
|
|
1326
|
+
this.#s(e.discontinuity) && (o = void 0);
|
|
1327
|
+
let { frame: t } = e;
|
|
1328
|
+
if (!t) continue;
|
|
1329
|
+
let i = n.Milli.fromMicro(t.timestamp);
|
|
1330
|
+
this.sync.received(i, "video");
|
|
1331
|
+
let s = new EncodedVideoChunk({
|
|
1332
|
+
type: t.keyframe ? "key" : "delta",
|
|
1333
|
+
data: t.payload,
|
|
1334
|
+
timestamp: t.timestamp
|
|
1335
|
+
});
|
|
1336
|
+
this.stats.update((e) => ({
|
|
1337
|
+
frameCount: (e?.frameCount ?? 0) + 1,
|
|
1338
|
+
bytesReceived: (e?.bytesReceived ?? 0) + t.payload.byteLength
|
|
1339
|
+
})), o !== void 0 && e.continuous && this.#l(n.Milli.fromMicro(o), n.Milli.fromMicro(t.timestamp)), o = t.timestamp, r.decode(s);
|
|
1340
|
+
}
|
|
1341
|
+
});
|
|
1342
|
+
}
|
|
1343
|
+
#o(e, t, r) {
|
|
1344
|
+
let i = this.config.container;
|
|
1345
|
+
if (i.kind !== "cmaf") return;
|
|
1346
|
+
let a = p(i.init), o = l.Cmaf.decodeInitSegment(a), s = this.config.description ? u.Hex.toBytes(this.config.description) : o.description, c = new l.Consumer(t, {
|
|
1347
|
+
format: new l.Cmaf.Format(o),
|
|
1348
|
+
latency: this.#t
|
|
1349
|
+
});
|
|
1350
|
+
e.cleanup(() => c.close()), e.run((e) => {
|
|
1351
|
+
let t = e.get(c.buffered), n = e.get(this.#e);
|
|
1352
|
+
this.buffered.update(() => l.mergeBufferedRanges(t, n));
|
|
1353
|
+
}), r.configure({
|
|
1354
|
+
codec: this.config.codec,
|
|
1355
|
+
description: s,
|
|
1356
|
+
displayAspectWidth: this.config.displayAspectWidth,
|
|
1357
|
+
displayAspectHeight: this.config.displayAspectHeight,
|
|
1358
|
+
optimizeForLatency: this.config.optimizeForLatency,
|
|
1359
|
+
flip: !1
|
|
1360
|
+
});
|
|
1361
|
+
let d;
|
|
1362
|
+
e.spawn(async () => {
|
|
1363
|
+
for (;;) {
|
|
1364
|
+
let e = await c.next();
|
|
1365
|
+
if (!e) break;
|
|
1366
|
+
this.#s(e.discontinuity) && (d = void 0);
|
|
1367
|
+
let { frame: t } = e;
|
|
1368
|
+
if (!t) continue;
|
|
1369
|
+
let i = n.Milli.fromMicro(t.timestamp);
|
|
1370
|
+
if (this.sync.received(i, "video"), this.stats.update((e) => ({
|
|
1371
|
+
frameCount: (e?.frameCount ?? 0) + 1,
|
|
1372
|
+
bytesReceived: (e?.bytesReceived ?? 0) + t.payload.byteLength
|
|
1373
|
+
})), d !== void 0 && e.continuous && this.#l(n.Milli.fromMicro(d), n.Milli.fromMicro(t.timestamp)), d = t.timestamp, r.state === "closed") break;
|
|
1374
|
+
r.decode(new EncodedVideoChunk({
|
|
1375
|
+
type: t.keyframe ? "key" : "delta",
|
|
1376
|
+
data: t.payload,
|
|
1377
|
+
timestamp: t.timestamp
|
|
1378
|
+
}));
|
|
1379
|
+
}
|
|
1380
|
+
});
|
|
1381
|
+
}
|
|
1382
|
+
#s(e) {
|
|
1383
|
+
return e !== this.#n && (this.#n = e, this.timestamp.set(void 0), this.#e.set([]), this.sync.reset(), !0);
|
|
1384
|
+
}
|
|
1385
|
+
async #c(e, t) {
|
|
1386
|
+
let n;
|
|
1387
|
+
try {
|
|
1388
|
+
let r = new Promise((e) => {
|
|
1389
|
+
n = this.paced.changed(() => e(!this.paced.peek()));
|
|
1390
|
+
}), i = this.sync.wait(e).then(() => !0);
|
|
1391
|
+
return await Promise.race([
|
|
1392
|
+
i,
|
|
1393
|
+
r,
|
|
1394
|
+
t.cancel
|
|
1395
|
+
]) ?? !1;
|
|
1396
|
+
} finally {
|
|
1397
|
+
n?.();
|
|
1398
|
+
}
|
|
1399
|
+
}
|
|
1400
|
+
#l(e, t) {
|
|
1401
|
+
e > t || this.#e.mutate((r) => {
|
|
1402
|
+
for (let i of r) if (i.start <= t && i.end >= e) {
|
|
1403
|
+
i.start = n.Milli.min(i.start, e), i.end = n.Milli.max(i.end, t);
|
|
1404
|
+
return;
|
|
1405
|
+
}
|
|
1406
|
+
r.push({
|
|
1407
|
+
start: e,
|
|
1408
|
+
end: t
|
|
1409
|
+
}), r.sort((e, t) => e.start - t.start);
|
|
1410
|
+
});
|
|
1411
|
+
}
|
|
1412
|
+
#u(e) {
|
|
1413
|
+
this.#e.mutate((t) => {
|
|
1414
|
+
for (; t.length > 0;) {
|
|
1415
|
+
if (t[0].end >= e) {
|
|
1416
|
+
t[0].start = n.Milli.max(t[0].start, e);
|
|
1417
|
+
break;
|
|
1418
|
+
}
|
|
1419
|
+
t.shift();
|
|
1420
|
+
}
|
|
1421
|
+
});
|
|
1422
|
+
}
|
|
1423
|
+
close() {
|
|
1424
|
+
this.#r.close(), this.frame.update((e) => {
|
|
1425
|
+
e?.close();
|
|
1426
|
+
});
|
|
1427
|
+
}
|
|
1428
|
+
};
|
|
1429
|
+
async function X(e) {
|
|
1430
|
+
if (!s.containerSupported(e.container)) {
|
|
1431
|
+
let t = e.container.kind === "unknown" ? e.container.raw.kind : e.container.kind;
|
|
1432
|
+
return console.warn(`video: ignoring rendition with unknown container: ${t}`), !1;
|
|
1433
|
+
}
|
|
1434
|
+
let t;
|
|
1435
|
+
if (e.description) t = u.Hex.toBytes(e.description);
|
|
1436
|
+
else if (e.container.kind === "cmaf") try {
|
|
1437
|
+
t = l.Cmaf.decodeInitSegment(p(e.container.init)).description;
|
|
1438
|
+
} catch (t) {
|
|
1439
|
+
return console.warn(`video: malformed CMAF init segment for codec ${e.codec}`, t), !1;
|
|
1440
|
+
}
|
|
1441
|
+
let { supported: n } = await VideoDecoder.isConfigSupported({
|
|
1442
|
+
codec: e.codec,
|
|
1443
|
+
description: t,
|
|
1444
|
+
displayAspectWidth: e.displayAspectWidth,
|
|
1445
|
+
displayAspectHeight: e.displayAspectHeight,
|
|
1446
|
+
optimizeForLatency: e.optimizeForLatency ?? !0
|
|
1447
|
+
});
|
|
1448
|
+
if (n) return !0;
|
|
1449
|
+
if (e.codec.startsWith("avc3.")) {
|
|
1450
|
+
let n = `avc1.${e.codec.slice(5)}`;
|
|
1451
|
+
if ((await VideoDecoder.isConfigSupported({
|
|
1452
|
+
codec: n,
|
|
1453
|
+
description: t,
|
|
1454
|
+
displayAspectWidth: e.displayAspectWidth,
|
|
1455
|
+
displayAspectHeight: e.displayAspectHeight,
|
|
1456
|
+
optimizeForLatency: e.optimizeForLatency ?? !0
|
|
1457
|
+
})).supported) return e.codec = n, !0;
|
|
1458
|
+
}
|
|
1459
|
+
return !1;
|
|
1460
|
+
}
|
|
1461
|
+
Object.assign(X, { [U]: xe });
|
|
1462
|
+
//#endregion
|
|
1463
|
+
//#region src/video/renderer.ts
|
|
1464
|
+
var Z = .01, Oe = class {
|
|
1465
|
+
decoder;
|
|
1466
|
+
in;
|
|
1467
|
+
#e = {
|
|
1468
|
+
frame: new i(void 0),
|
|
1469
|
+
timestamp: new i(void 0),
|
|
1470
|
+
visible: new i(!1)
|
|
1471
|
+
};
|
|
1472
|
+
out = o(this.#e);
|
|
1473
|
+
#t = new i(void 0);
|
|
1474
|
+
#n = new r();
|
|
1475
|
+
constructor(e, t) {
|
|
1476
|
+
this.decoder = e, this.in = {
|
|
1477
|
+
canvas: a(t?.canvas),
|
|
1478
|
+
visible: a(t?.visible ?? "20%")
|
|
1479
|
+
}, this.#n.run((e) => {
|
|
1480
|
+
let t = e.get(this.in.canvas);
|
|
1481
|
+
this.#t.set(t?.getContext("2d") ?? void 0);
|
|
1482
|
+
}), this.#n.run(this.#i.bind(this)), this.#n.run(this.#a.bind(this)), this.#n.run(this.#r.bind(this));
|
|
1483
|
+
}
|
|
1484
|
+
#r(e) {
|
|
1485
|
+
let t = e.getAll([this.in.canvas, this.decoder.out.display]);
|
|
1486
|
+
if (!t) return;
|
|
1487
|
+
let [n, r] = t;
|
|
1488
|
+
(n.width !== r.width || n.height !== r.height) && (n.width = r.width, n.height = r.height);
|
|
1489
|
+
}
|
|
1490
|
+
#i(e) {
|
|
1491
|
+
let t = e.get(this.in.visible);
|
|
1492
|
+
if (t === "never") {
|
|
1493
|
+
this.#e.visible.set(!1);
|
|
1494
|
+
return;
|
|
1495
|
+
}
|
|
1496
|
+
if (t === "always") {
|
|
1497
|
+
this.#e.visible.set(!0), e.cleanup(() => this.#e.visible.set(!1));
|
|
1498
|
+
return;
|
|
1499
|
+
}
|
|
1500
|
+
let n = e.get(this.in.canvas);
|
|
1501
|
+
if (!n) {
|
|
1502
|
+
this.#e.visible.set(!1);
|
|
1503
|
+
return;
|
|
1504
|
+
}
|
|
1505
|
+
let r = !1, i = () => {
|
|
1506
|
+
this.#e.visible.set(r && !document.hidden);
|
|
1507
|
+
}, a = (e) => {
|
|
1508
|
+
for (let t of e) r = t.isIntersecting, i();
|
|
1509
|
+
}, o;
|
|
1510
|
+
try {
|
|
1511
|
+
o = new IntersectionObserver(a, {
|
|
1512
|
+
threshold: Z,
|
|
1513
|
+
rootMargin: t
|
|
1514
|
+
});
|
|
1515
|
+
} catch {
|
|
1516
|
+
console.warn(`moq-watch: invalid visible margin "${t}", using "0px"`), o = new IntersectionObserver(a, { threshold: Z });
|
|
1517
|
+
}
|
|
1518
|
+
i(), e.event(document, "visibilitychange", i), o.observe(n), e.cleanup(() => o.disconnect()), e.cleanup(() => this.#e.visible.set(!1));
|
|
1519
|
+
}
|
|
1520
|
+
#a(e) {
|
|
1521
|
+
let t = e.get(this.#t);
|
|
1522
|
+
if (!t) return;
|
|
1523
|
+
let r = e.get(this.decoder.out.frame), i = e.get(this.decoder.source.out.catalog), a = requestAnimationFrame(() => {
|
|
1524
|
+
this.#o(t, r, i), r ? (this.#e.frame.update((e) => (e?.close(), r.clone())), this.#e.timestamp.set(n.Milli.fromMicro(r.timestamp))) : (this.#e.frame.update((e) => {
|
|
1525
|
+
e?.close();
|
|
1526
|
+
}), this.#e.timestamp.set(void 0)), a = void 0;
|
|
1527
|
+
});
|
|
1528
|
+
e.cleanup(() => {
|
|
1529
|
+
a !== void 0 && cancelAnimationFrame(a);
|
|
1530
|
+
});
|
|
1531
|
+
}
|
|
1532
|
+
#o(e, t, n) {
|
|
1533
|
+
if (!t) {
|
|
1534
|
+
e.fillStyle = "#000", e.fillRect(0, 0, e.canvas.width, e.canvas.height);
|
|
1535
|
+
return;
|
|
1536
|
+
}
|
|
1537
|
+
if (e.save(), e.fillStyle = "#000", e.fillRect(0, 0, e.canvas.width, e.canvas.height), !n?.rotation) n?.flip && (e.scale(-1, 1), e.translate(-e.canvas.width, 0)), e.drawImage(t, 0, 0, e.canvas.width, e.canvas.height);
|
|
1538
|
+
else {
|
|
1539
|
+
let r = Te(e.canvas, n);
|
|
1540
|
+
e.setTransform(...r.matrix), e.drawImage(t, 0, 0, r.source.width, r.source.height);
|
|
1541
|
+
}
|
|
1542
|
+
e.restore();
|
|
1543
|
+
}
|
|
1544
|
+
close() {
|
|
1545
|
+
this.#e.frame.update((e) => {
|
|
1546
|
+
e?.close();
|
|
1547
|
+
}), this.#e.timestamp.set(void 0), this.#n.close();
|
|
1548
|
+
}
|
|
1549
|
+
};
|
|
1550
|
+
//#endregion
|
|
1551
|
+
//#region src/video/source.ts
|
|
1552
|
+
function ke(e) {
|
|
1553
|
+
return (t) => {
|
|
1554
|
+
let n = [], r = [];
|
|
1555
|
+
for (let [i, a] of t) if (a.codedWidth && a.codedHeight) {
|
|
1556
|
+
let t = a.codedWidth * a.codedHeight;
|
|
1557
|
+
t <= e ? n.push({
|
|
1558
|
+
name: i,
|
|
1559
|
+
size: t
|
|
1560
|
+
}) : r.push({
|
|
1561
|
+
name: i,
|
|
1562
|
+
size: t
|
|
1563
|
+
});
|
|
1564
|
+
}
|
|
1565
|
+
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);
|
|
1566
|
+
};
|
|
1567
|
+
}
|
|
1568
|
+
function Q(e, t) {
|
|
1569
|
+
return (n) => {
|
|
1570
|
+
let r = [], i = [];
|
|
1571
|
+
for (let [a, o] of n) {
|
|
1572
|
+
if (!o.codedWidth || !o.codedHeight) continue;
|
|
1573
|
+
let n = o.codedWidth * o.codedHeight, s = e == null || o.codedWidth <= e, c = t == null || o.codedHeight <= t;
|
|
1574
|
+
s && c ? r.push({
|
|
1575
|
+
name: a,
|
|
1576
|
+
size: n
|
|
1577
|
+
}) : i.push({
|
|
1578
|
+
name: a,
|
|
1579
|
+
size: n
|
|
1580
|
+
});
|
|
1581
|
+
}
|
|
1582
|
+
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);
|
|
1583
|
+
};
|
|
1584
|
+
}
|
|
1585
|
+
function $(e) {
|
|
1586
|
+
return (t) => {
|
|
1587
|
+
let n = [], r = [];
|
|
1588
|
+
for (let [i, a] of t) a.bitrate != null && a.bitrate <= e ? n.push({
|
|
1589
|
+
name: i,
|
|
1590
|
+
bitrate: a.bitrate
|
|
1591
|
+
}) : a.bitrate != null && r.push({
|
|
1592
|
+
name: i,
|
|
1593
|
+
bitrate: a.bitrate
|
|
1594
|
+
});
|
|
1595
|
+
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);
|
|
1596
|
+
};
|
|
1597
|
+
}
|
|
1598
|
+
function Ae(e) {
|
|
1599
|
+
let t = e[0];
|
|
1600
|
+
for (let n of e) {
|
|
1601
|
+
let [, e] = n, [, r] = t, i = (e.codedWidth ?? 0) * (e.codedHeight ?? 0), a = (r.codedWidth ?? 0) * (r.codedHeight ?? 0);
|
|
1602
|
+
if (i !== a) {
|
|
1603
|
+
i > a && (t = n);
|
|
1604
|
+
continue;
|
|
1605
|
+
}
|
|
1606
|
+
(e.bitrate ?? 0) > (r.bitrate ?? 0) && (t = n);
|
|
1607
|
+
}
|
|
1608
|
+
return t[0];
|
|
1609
|
+
}
|
|
1610
|
+
function je(e) {
|
|
1611
|
+
let t = Object.entries(e).filter(([, e]) => !e.stalled);
|
|
1612
|
+
if (t.length > 0) return Object.fromEntries(t);
|
|
1613
|
+
let n = Object.entries(e);
|
|
1614
|
+
if (n.length === 0) return {};
|
|
1615
|
+
let r = $(0)(n), i = r.length === 1 ? r[0] : Q(0, 0)(n)[0];
|
|
1616
|
+
return { [i]: e[i] };
|
|
1617
|
+
}
|
|
1618
|
+
var Me = class {
|
|
1619
|
+
in;
|
|
1620
|
+
#e = {
|
|
1621
|
+
catalog: new i(void 0),
|
|
1622
|
+
available: new i({}),
|
|
1623
|
+
error: new i(void 0),
|
|
1624
|
+
track: new i(void 0),
|
|
1625
|
+
config: new i(void 0),
|
|
1626
|
+
jitter: new i(void 0)
|
|
1627
|
+
};
|
|
1628
|
+
out = o(this.#e);
|
|
1629
|
+
#t = new r();
|
|
1630
|
+
#n = /* @__PURE__ */ new WeakMap();
|
|
1631
|
+
constructor(e) {
|
|
1632
|
+
this.in = {
|
|
1633
|
+
broadcast: a(e?.broadcast),
|
|
1634
|
+
target: a(e?.target),
|
|
1635
|
+
supported: a(e?.supported)
|
|
1636
|
+
}, this.#t.run(this.#r.bind(this)), this.#t.run(this.#i.bind(this)), this.#t.run(this.#a.bind(this));
|
|
1637
|
+
}
|
|
1638
|
+
#r(e) {
|
|
1639
|
+
let t = e.get(this.in.broadcast);
|
|
1640
|
+
if (!t) return;
|
|
1641
|
+
let n = e.get(t.out.catalog)?.video;
|
|
1642
|
+
n && e.set(this.#e.catalog, n);
|
|
1643
|
+
}
|
|
1644
|
+
#i(e) {
|
|
1645
|
+
let t = e.get(this.in.supported);
|
|
1646
|
+
if (!t) {
|
|
1647
|
+
this.#e.error.set(void 0);
|
|
1648
|
+
return;
|
|
1649
|
+
}
|
|
1650
|
+
let n = e.get(this.#e.catalog)?.renditions ?? {};
|
|
1651
|
+
this.#e.error.set(void 0);
|
|
1652
|
+
let r = this.#n.get(t);
|
|
1653
|
+
r || (r = /* @__PURE__ */ new Map(), this.#n.set(t, r));
|
|
1654
|
+
let i = new Set(Object.keys(n));
|
|
1655
|
+
for (let e of r.keys()) i.has(e) || r.delete(e);
|
|
1656
|
+
e.spawn(async () => {
|
|
1657
|
+
let i = {}, a = e.cancel.then(() => void 0);
|
|
1658
|
+
for (let [o, s] of Object.entries(n)) {
|
|
1659
|
+
let n = t[U], c = n ? n(s) : JSON.stringify(s), l = r.get(o), u = !1;
|
|
1660
|
+
if (l?.key === c) u = l.supported;
|
|
1661
|
+
else {
|
|
1662
|
+
let e = !1;
|
|
1663
|
+
try {
|
|
1664
|
+
u = await Promise.race([t(s), a]);
|
|
1665
|
+
} catch (t) {
|
|
1666
|
+
e = !0, console.warn(`[Source] video rendition ${o} (${s.codec}) support probe failed; treating as unsupported`, t);
|
|
1667
|
+
}
|
|
1668
|
+
!e && u !== void 0 && r.set(o, {
|
|
1669
|
+
key: n ? n(s) : JSON.stringify(s),
|
|
1670
|
+
supported: u
|
|
1671
|
+
});
|
|
1672
|
+
}
|
|
1673
|
+
if (e.abort.aborted) return;
|
|
1674
|
+
u && (i[o] = s);
|
|
1675
|
+
}
|
|
1676
|
+
let o = Object.keys(i).length === 0 && Object.keys(n).length > 0 ? "unsupported" : void 0;
|
|
1677
|
+
o === "unsupported" && console.warn("[Source] No supported video renditions found:", n), this.#e.error.set(o), this.#e.available.set(i);
|
|
1678
|
+
});
|
|
1679
|
+
}
|
|
1680
|
+
#a(e) {
|
|
1681
|
+
let t = je(e.get(this.#e.available));
|
|
1682
|
+
if (Object.keys(t).length === 0) return;
|
|
1683
|
+
let n = e.get(this.in.target);
|
|
1684
|
+
if (n?.name && n.name in t) {
|
|
1685
|
+
let r = t[n.name];
|
|
1686
|
+
e.set(this.#e.track, n.name), e.set(this.#e.config, r), e.set(this.#e.jitter, G(r));
|
|
1687
|
+
return;
|
|
1688
|
+
}
|
|
1689
|
+
let r = n;
|
|
1690
|
+
if (!n?.bitrate) {
|
|
1691
|
+
let t = e.get(this.in.broadcast), i = t ? e.get(t.in.connection) : void 0, a = i && e.get(i.probe).estimatedRecvRate;
|
|
1692
|
+
if (a != null) {
|
|
1693
|
+
let e = Math.round(a * .8);
|
|
1694
|
+
r = {
|
|
1695
|
+
...n,
|
|
1696
|
+
bitrate: e
|
|
1697
|
+
};
|
|
1698
|
+
}
|
|
1699
|
+
}
|
|
1700
|
+
let i = this.#o(t, r);
|
|
1701
|
+
if (!i) return;
|
|
1702
|
+
let a = t[i];
|
|
1703
|
+
e.set(this.#e.track, i), e.set(this.#e.config, a), e.set(this.#e.jitter, G(a));
|
|
1704
|
+
}
|
|
1705
|
+
#o(e, t) {
|
|
1706
|
+
let n = Object.entries(e);
|
|
1707
|
+
if (n.length === 0) return;
|
|
1708
|
+
if (n.length === 1) return n[0][0];
|
|
1709
|
+
let r = [];
|
|
1710
|
+
if (t?.pixels != null && r.push(ke(t.pixels)), (t?.width != null || t?.height != null) && r.push(Q(t.width, t.height)), t?.bitrate != null && r.push($(t.bitrate)), r.length === 0) return Ae(n);
|
|
1711
|
+
let i = r.map((e) => e(n)), a = i.map((e) => new Set(e));
|
|
1712
|
+
for (let e of i[0]) if (a.every((t) => t.has(e))) return e;
|
|
1713
|
+
console.warn("conflicting rendition filters, no rendition satisfies all criteria");
|
|
1714
|
+
}
|
|
1715
|
+
close() {
|
|
1716
|
+
this.#t.close();
|
|
1717
|
+
}
|
|
1718
|
+
};
|
|
1719
|
+
//#endregion
|
|
1720
|
+
export { H as a, A as c, be as i, me as l, Oe as n, ye as o, De as r, M as s, Me as t };
|
|
1721
|
+
|
|
1722
|
+
//# sourceMappingURL=source-lWNGIbmd.js.map
|