@moq/watch 0.2.17 → 0.2.19
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 +4 -3
- package/audio/backend.d.ts +11 -1
- package/audio/backend.d.ts.map +1 -1
- package/audio/buffer.d.ts +10 -1
- package/audio/buffer.d.ts.map +1 -1
- package/audio/decoder.d.ts +8 -1
- package/audio/decoder.d.ts.map +1 -1
- package/audio/emitter.d.ts.map +1 -1
- package/audio/mse.d.ts +1 -1
- package/audio/mse.d.ts.map +1 -1
- package/audio/render.d.ts +6 -1
- package/audio/render.d.ts.map +1 -1
- package/audio/ring-buffer.d.ts +2 -0
- package/audio/ring-buffer.d.ts.map +1 -1
- package/audio/shared-ring-buffer.d.ts +8 -1
- package/audio/shared-ring-buffer.d.ts.map +1 -1
- package/audio/source.d.ts.map +1 -1
- package/backend.d.ts +22 -18
- package/backend.d.ts.map +1 -1
- package/{broadcast-80k1hgfM.js → broadcast-Duw8w3D_.js} +446 -439
- package/broadcast-Duw8w3D_.js.map +1 -0
- package/broadcast.d.ts +15 -3
- package/broadcast.d.ts.map +1 -1
- package/buffered.d.ts +19 -0
- package/buffered.d.ts.map +1 -0
- package/element.d.ts +22 -4
- package/element.d.ts.map +1 -1
- package/element.js +65 -36
- package/element.js.map +1 -1
- package/index.d.ts +1 -0
- package/index.d.ts.map +1 -1
- package/index.js +7 -6
- package/mse.d.ts.map +1 -1
- package/package.json +6 -6
- package/support/element.d.ts.map +1 -1
- package/support/element.js.map +1 -1
- package/support/index.js.map +1 -1
- package/sync-D67IxmxJ.js +128 -0
- package/sync-D67IxmxJ.js.map +1 -0
- package/sync.d.ts +27 -5
- package/sync.d.ts.map +1 -1
- package/sync.test.d.ts +2 -0
- package/sync.test.d.ts.map +1 -0
- package/ui/components/latency.d.ts.map +1 -1
- package/ui/element.d.ts.map +1 -1
- package/ui/element.js +215 -178
- package/ui/element.js.map +1 -1
- package/video/backend.d.ts +10 -1
- package/video/backend.d.ts.map +1 -1
- package/video/decoder.d.ts +1 -1
- package/video/decoder.d.ts.map +1 -1
- package/video/mse.d.ts +3 -3
- package/video/mse.d.ts.map +1 -1
- package/video/renderer.d.ts +1 -1
- package/video/renderer.d.ts.map +1 -1
- package/video/source.d.ts.map +1 -1
- package/broadcast-80k1hgfM.js.map +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { t as e } from "./sync-D67IxmxJ.js";
|
|
2
2
|
import * as t from "@moq/net";
|
|
3
3
|
import { Path as n, Time as r } from "@moq/net";
|
|
4
4
|
import { Effect as i, Signal as a } from "@moq/signals";
|
|
@@ -26,17 +26,18 @@ function p(e) {
|
|
|
26
26
|
//#endregion
|
|
27
27
|
//#region src/audio/shared-ring-buffer.ts
|
|
28
28
|
var m = 0, h = 1, g = 2, _ = 3, v = 4;
|
|
29
|
-
function y(e, t, n) {
|
|
29
|
+
function y(e, t, n, r = !1) {
|
|
30
30
|
if (e <= 0) throw Error("invalid channels");
|
|
31
31
|
if (t <= 0) throw Error("invalid capacity");
|
|
32
32
|
if (n <= 0) throw Error("invalid sample rate");
|
|
33
|
-
let
|
|
34
|
-
return Atomics.store(
|
|
33
|
+
let i = new SharedArrayBuffer(e * t * Float32Array.BYTES_PER_ELEMENT), a = new SharedArrayBuffer(v * Int32Array.BYTES_PER_ELEMENT), o = new Int32Array(a);
|
|
34
|
+
return Atomics.store(o, _, 1), {
|
|
35
35
|
channels: e,
|
|
36
36
|
capacity: t,
|
|
37
37
|
rate: n,
|
|
38
|
-
samples:
|
|
39
|
-
control:
|
|
38
|
+
samples: i,
|
|
39
|
+
control: a,
|
|
40
|
+
buffered: r
|
|
40
41
|
};
|
|
41
42
|
}
|
|
42
43
|
function b(e, t) {
|
|
@@ -56,16 +57,20 @@ var C = class e {
|
|
|
56
57
|
channels;
|
|
57
58
|
capacity;
|
|
58
59
|
rate;
|
|
60
|
+
buffered;
|
|
59
61
|
init;
|
|
60
62
|
#e;
|
|
61
63
|
#t;
|
|
64
|
+
#n = !1;
|
|
62
65
|
constructor(e) {
|
|
63
|
-
this.channels = e.channels, this.capacity = e.capacity, this.rate = e.rate, this.init = e, this.#e = new Int32Array(e.control), this.#t = [];
|
|
66
|
+
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 = [];
|
|
64
67
|
for (let t = 0; t < this.channels; t++) this.#t.push(new Float32Array(e.samples, t * this.capacity * Float32Array.BYTES_PER_ELEMENT, this.capacity));
|
|
65
68
|
}
|
|
66
69
|
insert(e, t) {
|
|
67
70
|
if (t.length !== this.channels) throw Error("wrong number of channels");
|
|
68
|
-
let n = Math.round(r.Second.fromMicro(e) * this.rate), i = t[0].length, a = 0
|
|
71
|
+
let n = Math.round(r.Second.fromMicro(e) * this.rate), i = t[0].length, a = 0;
|
|
72
|
+
this.buffered && !this.#n && (Atomics.store(this.#e, h, n | 0), Atomics.store(this.#e, m, n | 0), this.#n = !0);
|
|
73
|
+
let o = n + i | 0, s = Atomics.load(this.#e, h), c = s - n | 0;
|
|
69
74
|
if (c > 0) {
|
|
70
75
|
if (c >= i) return;
|
|
71
76
|
a = c, n = n + c | 0;
|
|
@@ -91,7 +96,7 @@ var C = class e {
|
|
|
91
96
|
read(e) {
|
|
92
97
|
if (Atomics.load(this.#e, _) === 1) return 0;
|
|
93
98
|
let t = Atomics.load(this.#e, h), n = Atomics.load(this.#e, m), r = Atomics.load(this.#e, g), i = n - t | 0;
|
|
94
|
-
if (r > 0 && i > r) {
|
|
99
|
+
if (!this.buffered && r > 0 && i > r) {
|
|
95
100
|
let e = n - r | 0;
|
|
96
101
|
t = S(this.#e, h, e);
|
|
97
102
|
}
|
|
@@ -106,8 +111,15 @@ var C = class e {
|
|
|
106
111
|
setLatency(e) {
|
|
107
112
|
Atomics.store(this.#e, g, e);
|
|
108
113
|
}
|
|
114
|
+
reset() {
|
|
115
|
+
this.#n = !1, Atomics.store(this.#e, _, 1);
|
|
116
|
+
let e = Atomics.load(this.#e, m);
|
|
117
|
+
Atomics.store(this.#e, h, e);
|
|
118
|
+
}
|
|
109
119
|
resize(t) {
|
|
110
|
-
let n = new e(y(this.channels, t, this.rate
|
|
120
|
+
let n = new e(y(this.channels, t, this.rate, this.buffered));
|
|
121
|
+
n.#n = this.#n;
|
|
122
|
+
let r = Atomics.load(this.#e, h), i = Atomics.load(this.#e, m), a = Atomics.load(this.#e, g), o = Atomics.load(this.#e, _), s = i - r | 0, c = Math.max(0, Math.min(s, n.capacity)), l = i - c | 0;
|
|
111
123
|
for (let e = 0; e < this.channels; e++) {
|
|
112
124
|
let t = this.#t[e], r = n.#t[e];
|
|
113
125
|
for (let e = 0; e < c; e++) {
|
|
@@ -127,14 +139,38 @@ var C = class e {
|
|
|
127
139
|
get length() {
|
|
128
140
|
return Atomics.load(this.#e, m) - Atomics.load(this.#e, h) | 0;
|
|
129
141
|
}
|
|
142
|
+
}, w = class {
|
|
143
|
+
#e;
|
|
144
|
+
#t;
|
|
145
|
+
#n = [];
|
|
146
|
+
constructor(e, t) {
|
|
147
|
+
this.#e = e, this.#t = t;
|
|
148
|
+
}
|
|
149
|
+
setHeadroom(e) {
|
|
150
|
+
this.#t = e;
|
|
151
|
+
}
|
|
152
|
+
wait(e, t) {
|
|
153
|
+
return !this.#e || t >= (e - this.#t | 0) ? Promise.resolve() : new Promise((t) => this.#n.push({
|
|
154
|
+
timestamp: e,
|
|
155
|
+
resolve: t
|
|
156
|
+
}));
|
|
157
|
+
}
|
|
158
|
+
advance(e) {
|
|
159
|
+
this.#n.length !== 0 && (this.#n = this.#n.filter(({ timestamp: t, resolve: n }) => e < (t - this.#t | 0) ? !0 : (n(), !1)));
|
|
160
|
+
}
|
|
161
|
+
flush() {
|
|
162
|
+
for (let { resolve: e } of this.#n) e();
|
|
163
|
+
this.#n = [];
|
|
164
|
+
}
|
|
130
165
|
};
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
166
|
+
function T(e, t) {
|
|
167
|
+
return r.Micro.fromSecond(e / t);
|
|
168
|
+
}
|
|
169
|
+
function E() {
|
|
134
170
|
return !(typeof SharedArrayBuffer > "u" || typeof crossOriginIsolated < "u" && !crossOriginIsolated);
|
|
135
171
|
}
|
|
136
|
-
function ee(e, t, n, r) {
|
|
137
|
-
return
|
|
172
|
+
function ee(e, t, n, r, i = !1) {
|
|
173
|
+
return E() ? (console.log("[audio] using SharedArrayBuffer audio buffer"), new te(e, t, n, r, i)) : (console.log("[audio] using postMessage audio buffer (SharedArrayBuffer unavailable)"), new ne(e, t, n, r, i));
|
|
138
174
|
}
|
|
139
175
|
var te = class {
|
|
140
176
|
rate;
|
|
@@ -145,24 +181,28 @@ var te = class {
|
|
|
145
181
|
timestamp = this.#n;
|
|
146
182
|
#r = new a(!0);
|
|
147
183
|
stalled = this.#r;
|
|
148
|
-
#i
|
|
149
|
-
|
|
184
|
+
#i;
|
|
185
|
+
#a = new i();
|
|
186
|
+
constructor(e, t, n, r, i) {
|
|
150
187
|
this.#e = e, this.channels = t, this.rate = n;
|
|
151
|
-
let
|
|
152
|
-
this.#
|
|
153
|
-
let
|
|
188
|
+
let a = Math.max(n, r * 2);
|
|
189
|
+
this.#i = new w(i, T(r, n));
|
|
190
|
+
let o = y(t, a, n, i);
|
|
191
|
+
this.#t = new C(o), this.#t.setLatency(r);
|
|
192
|
+
let s = {
|
|
154
193
|
type: "init-shared",
|
|
155
|
-
...
|
|
194
|
+
...o
|
|
156
195
|
};
|
|
157
|
-
e.port.postMessage(
|
|
158
|
-
|
|
196
|
+
e.port.postMessage(s), this.#a.interval(() => {
|
|
197
|
+
let e = this.#t.stalled;
|
|
198
|
+
this.#n.set(this.#t.timestamp), this.#r.set(e), e ? this.#i.flush() : this.#i.advance(this.#t.timestamp);
|
|
159
199
|
}, 50);
|
|
160
200
|
}
|
|
161
201
|
insert(e, t) {
|
|
162
202
|
this.#t.insert(e, t);
|
|
163
203
|
}
|
|
164
204
|
setLatency(e) {
|
|
165
|
-
if (this.#t.capacity < e * 1.5) {
|
|
205
|
+
if (this.#i.setHeadroom(T(e, this.rate)), this.#t.capacity < e * 1.5) {
|
|
166
206
|
let t = Math.max(this.rate, e * 2);
|
|
167
207
|
this.#t = this.#t.resize(t), this.#t.setLatency(e);
|
|
168
208
|
let n = {
|
|
@@ -172,8 +212,14 @@ var te = class {
|
|
|
172
212
|
this.#e.port.postMessage(n);
|
|
173
213
|
} else this.#t.setLatency(e);
|
|
174
214
|
}
|
|
215
|
+
reset() {
|
|
216
|
+
this.#t.reset(), this.#i.flush();
|
|
217
|
+
}
|
|
218
|
+
wait(e) {
|
|
219
|
+
return this.#t.stalled ? Promise.resolve() : this.#i.wait(e, this.#t.timestamp);
|
|
220
|
+
}
|
|
175
221
|
close() {
|
|
176
|
-
this.#i.close();
|
|
222
|
+
this.#i.flush(), this.#a.close();
|
|
177
223
|
}
|
|
178
224
|
}, ne = class {
|
|
179
225
|
rate;
|
|
@@ -183,18 +229,20 @@ var te = class {
|
|
|
183
229
|
timestamp = this.#t;
|
|
184
230
|
#n = new a(!0);
|
|
185
231
|
stalled = this.#n;
|
|
186
|
-
#r
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
232
|
+
#r;
|
|
233
|
+
#i = new i();
|
|
234
|
+
constructor(e, t, n, i, a) {
|
|
235
|
+
this.#e = e, this.channels = t, this.rate = n, this.#r = new w(a, T(i, n));
|
|
236
|
+
let o = {
|
|
190
237
|
type: "init-post",
|
|
191
238
|
channels: t,
|
|
192
239
|
rate: n,
|
|
193
|
-
latency: r.Milli.fromSecond(i / n)
|
|
240
|
+
latency: r.Milli.fromSecond(i / n),
|
|
241
|
+
buffered: a
|
|
194
242
|
};
|
|
195
|
-
e.port.postMessage(
|
|
243
|
+
e.port.postMessage(o), this.#i.event(e.port, "message", (e) => {
|
|
196
244
|
let t = e.data;
|
|
197
|
-
t?.type === "state" && (this.#t.set(t.timestamp), this.#n.set(t.stalled));
|
|
245
|
+
t?.type === "state" && (this.#t.set(t.timestamp), this.#n.set(t.stalled), t.stalled ? this.#r.flush() : this.#r.advance(t.timestamp));
|
|
198
246
|
}), e.port.start();
|
|
199
247
|
}
|
|
200
248
|
insert(e, t) {
|
|
@@ -206,16 +254,23 @@ var te = class {
|
|
|
206
254
|
this.#e.port.postMessage(n, t.map((e) => e.buffer));
|
|
207
255
|
}
|
|
208
256
|
setLatency(e) {
|
|
257
|
+
this.#r.setHeadroom(T(e, this.rate));
|
|
209
258
|
let t = {
|
|
210
259
|
type: "latency",
|
|
211
260
|
latency: r.Milli.fromSecond(e / this.rate)
|
|
212
261
|
};
|
|
213
262
|
this.#e.port.postMessage(t);
|
|
214
263
|
}
|
|
264
|
+
reset() {
|
|
265
|
+
this.#e.port.postMessage({ type: "reset" }), this.#r.flush();
|
|
266
|
+
}
|
|
267
|
+
wait(e) {
|
|
268
|
+
return this.#n.peek() ? Promise.resolve() : this.#r.wait(e, this.#t.peek());
|
|
269
|
+
}
|
|
215
270
|
close() {
|
|
216
|
-
this.#r.close();
|
|
271
|
+
this.#r.flush(), this.#i.close();
|
|
217
272
|
}
|
|
218
|
-
}, re = new Blob(["var __defProp = Object.defineProperty;\nvar __getOwnPropNames = Object.getOwnPropertyNames;\nvar __esm = (fn, res) => function __init() {\n return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;\n};\nvar __export = (target, all) => {\n for (var name in all)\n __defProp(target, name, { get: all[name], enumerable: true });\n};\n\n// ../net/src/path.ts\nvar init_path = __esm({\n \"../net/src/path.ts\"() {\n \"use strict\";\n }\n});\n\n// ../net/src/varint.ts\nvar MAX_U6, MAX_U14, MAX_U30, MAX_U53, MAX_U64, MAX_U62;\nvar init_varint = __esm({\n \"../net/src/varint.ts\"() {\n \"use strict\";\n MAX_U6 = 2 ** 6 - 1;\n MAX_U14 = 2 ** 14 - 1;\n MAX_U30 = 2 ** 30 - 1;\n MAX_U53 = Number.MAX_SAFE_INTEGER;\n MAX_U64 = (1n << 64n) - 1n;\n MAX_U62 = 2n ** 62n - 1n;\n }\n});\n\n// ../net/src/index.ts\ninit_path();\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});\nvar Nano = {\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 = {\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 = {\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 Second = {\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// ../net/src/index.ts\ninit_varint();\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 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 const samples = Math.ceil(props.rate * time_exports.Second.fromMilli(props.latency));\n if (samples === 0) throw new Error(\"empty buffer\");\n this.rate = props.rate;\n this.channels = props.channels;\n this.#buffer = [];\n for (let i = 0; i < this.channels; i++) {\n this.#buffer[i] = new Float32Array(samples);\n }\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 const newCapacity = Math.ceil(this.rate * time_exports.Second.fromMilli(latency));\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 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 }\n read(output) {\n if (output.length !== this.channels) throw new Error(\"wrong number of channels\");\n if (this.#stalled) return 0;\n const samples = Math.min(this.#writeIndex - this.#readIndex, output[0].length);\n if (samples === 0) return 0;\n for (let channel = 0; channel < this.channels; channel++) {\n const dst = output[channel];\n const src = this.#buffer[channel];\n if (dst.length !== output[0].length) throw new Error(\"mismatching number of samples\");\n for (let i = 0; i < samples; i++) {\n const readPos = (this.#readIndex + i) % src.length;\n dst[i] = src[readPos];\n }\n }\n this.#readIndex += samples;\n return samples;\n }\n};\n\n// src/audio/shared-ring-buffer.ts\nvar WRITE = 0;\nvar READ = 1;\nvar LATENCY = 2;\nvar STALLED = 3;\nvar CONTROL_SLOTS = 4;\nfunction allocSharedRingBuffer(channels, capacity, rate) {\n if (channels <= 0) throw new Error(\"invalid channels\");\n if (capacity <= 0) throw new Error(\"invalid capacity\");\n if (rate <= 0) throw new Error(\"invalid sample rate\");\n const samples = new SharedArrayBuffer(channels * capacity * Float32Array.BYTES_PER_ELEMENT);\n const control = new SharedArrayBuffer(CONTROL_SLOTS * Int32Array.BYTES_PER_ELEMENT);\n const ctrl = new Int32Array(control);\n Atomics.store(ctrl, STALLED, 1);\n return { channels, capacity, rate, samples, control };\n}\nfunction i32Max(a, b) {\n return (a - b | 0) > 0 ? a : b;\n}\nfunction slot(idx, capacity) {\n return (idx % capacity + capacity) % capacity;\n}\nfunction casAdvance(arr, idx, candidate) {\n for (; ; ) {\n const current = Atomics.load(arr, idx);\n if ((candidate - current | 0) <= 0) return current;\n const witnessed = Atomics.compareExchange(arr, idx, current, candidate);\n if (witnessed === current) return candidate;\n }\n}\nvar SharedRingBuffer = class _SharedRingBuffer {\n channels;\n capacity;\n rate;\n init;\n #control;\n #samples;\n constructor(init) {\n this.channels = init.channels;\n this.capacity = init.capacity;\n this.rate = init.rate;\n this.init = init;\n this.#control = new Int32Array(init.control);\n this.#samples = [];\n for (let i = 0; i < this.channels; i++) {\n this.#samples.push(\n new Float32Array(init.samples, i * this.capacity * Float32Array.BYTES_PER_ELEMENT, this.capacity)\n );\n }\n }\n /**\n * Insert audio samples at the given timestamp.\n * Main thread only. Handles out-of-order writes, gap filling, and overflow.\n */\n insert(timestamp, data) {\n if (data.length !== this.channels) throw new Error(\"wrong number of channels\");\n let start = Math.round(time_exports.Second.fromMicro(timestamp) * this.rate);\n const originalLength = data[0].length;\n let offset = 0;\n const end = start + originalLength | 0;\n const read = Atomics.load(this.#control, READ);\n const behind = read - start | 0;\n if (behind > 0) {\n if (behind >= originalLength) {\n return;\n }\n offset = behind;\n start = start + behind | 0;\n }\n const samples = originalLength - offset;\n if ((end - read | 0) > this.capacity) {\n casAdvance(this.#control, READ, end - this.capacity | 0);\n }\n const write = Atomics.load(this.#control, WRITE);\n const gap = start - write | 0;\n if (gap > 0) {\n const gapSize = Math.min(gap, this.capacity);\n for (let channel = 0; channel < this.channels; channel++) {\n const dst = this.#samples[channel];\n for (let i = 0; i < gapSize; i++) {\n dst[slot(write + i | 0, this.capacity)] = 0;\n }\n }\n }\n for (let channel = 0; channel < this.channels; channel++) {\n const src = data[channel];\n const dst = this.#samples[channel];\n for (let i = 0; i < samples; i++) {\n dst[slot(start + i | 0, this.capacity)] = src[offset + i];\n }\n }\n Atomics.store(this.#control, WRITE, i32Max(Atomics.load(this.#control, WRITE), end));\n const currentRead = Atomics.load(this.#control, READ);\n const currentWrite = Atomics.load(this.#control, WRITE);\n const latency = Atomics.load(this.#control, LATENCY);\n if ((currentWrite - currentRead | 0) >= latency && latency > 0) {\n Atomics.store(this.#control, STALLED, 0);\n }\n }\n /**\n * Read audio samples into the output buffers.\n * AudioWorklet only. Returns the number of samples read.\n */\n read(output) {\n if (Atomics.load(this.#control, STALLED) === 1) return 0;\n let read = Atomics.load(this.#control, READ);\n const write = Atomics.load(this.#control, WRITE);\n const latency = Atomics.load(this.#control, LATENCY);\n const buffered = write - read | 0;\n if (latency > 0 && buffered > latency) {\n const skipTo = write - latency | 0;\n read = casAdvance(this.#control, READ, skipTo);\n }\n const available = write - read | 0;\n const count = Math.min(available, output[0].length);\n if (count <= 0) return 0;\n for (let channel = 0; channel < this.channels; channel++) {\n const src = this.#samples[channel];\n const dst = output[channel];\n for (let i = 0; i < count; i++) {\n dst[i] = src[slot(read + i | 0, this.capacity)];\n }\n }\n casAdvance(this.#control, READ, read + count | 0);\n return count;\n }\n /** Update the target latency in samples. */\n setLatency(samples) {\n Atomics.store(this.#control, LATENCY, samples);\n }\n /**\n * 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);\n const dst = new _SharedRingBuffer(init);\n const read = Atomics.load(this.#control, READ);\n const write = Atomics.load(this.#control, WRITE);\n const latency = Atomics.load(this.#control, LATENCY);\n const stalled = Atomics.load(this.#control, STALLED);\n const available = write - read | 0;\n const copyCount = Math.max(0, Math.min(available, dst.capacity));\n const copyStart = write - copyCount | 0;\n for (let channel = 0; channel < this.channels; channel++) {\n const src = this.#samples[channel];\n const out = dst.#samples[channel];\n for (let i = 0; i < copyCount; i++) {\n const idx = copyStart + i | 0;\n out[slot(idx, dst.capacity)] = src[slot(idx, this.capacity)];\n }\n }\n Atomics.store(dst.#control, READ, copyStart);\n Atomics.store(dst.#control, WRITE, write);\n Atomics.store(dst.#control, LATENCY, latency);\n Atomics.store(dst.#control, STALLED, stalled);\n return dst;\n }\n /** Current playback timestamp derived from READ position. */\n get timestamp() {\n const read = Atomics.load(this.#control, READ);\n return time_exports.Micro.fromSecond(read / this.rate);\n }\n /** Whether the buffer is stalled (waiting to fill). */\n get stalled() {\n return Atomics.load(this.#control, STALLED) === 1;\n }\n /**\n * Number of buffered samples (WRITE - READ).\n *\n * Non-atomic: WRITE and READ are loaded separately, so a concurrent\n * writer/reader can make the two loads inconsistent. Intended for\n * tests and diagnostics, not control-flow decisions.\n */\n get length() {\n return Atomics.load(this.#control, WRITE) - Atomics.load(this.#control, READ) | 0;\n }\n};\n\n// src/audio/render-worklet.ts\nvar Render = class extends AudioWorkletProcessor {\n // Set after init, depending on which path the main thread chose.\n #backend;\n #underflow = 0;\n #stateCounter = 0;\n constructor() {\n super();\n this.port.onmessage = (event) => {\n const msg = event.data;\n if (msg.type === \"init-shared\") {\n console.log(\"[audio-worklet] init-shared: using SharedArrayBuffer path\");\n this.#backend = new SharedRingBuffer(msg);\n this.#underflow = 0;\n } else if (msg.type === \"init-post\") {\n console.log(\"[audio-worklet] init-post: using postMessage path\");\n this.#backend = new AudioRingBuffer(msg);\n this.#underflow = 0;\n } else if (msg.type === \"data\") {\n if (this.#backend instanceof AudioRingBuffer) this.#backend.write(msg.timestamp, msg.data);\n } else if (msg.type === \"latency\") {\n if (this.#backend instanceof AudioRingBuffer) this.#backend.resize(msg.latency);\n }\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" }), T = URL.createObjectURL(re), E = class {
|
|
273
|
+
}, re = 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});\nvar Nano = {\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 = {\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 = {\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 Second = {\n zero: 0,\n fromNano: (ns) => ns / 1e9,\n fromMicro: (us) => us / 1e6,\n fromMilli: (ms) => ms / 1e3,\n toNano: (s) => s * 1e9,\n toMicro: (s) => s * 1e6,\n toMilli: (s) => s * 1e3,\n now: () => performance.now() / 1e3,\n add: (a, b) => a + b,\n sub: (a, b) => a - b,\n mul: (a, b) => a * b,\n div: (a, b) => a / b,\n max: (a, b) => Math.max(a, b),\n min: (a, b) => Math.min(a, b)\n};\n\n// src/audio/ring-buffer.ts\nvar AudioRingBuffer = class {\n #buffer;\n #writeIndex = 0;\n #readIndex = 0;\n rate;\n channels;\n #stalled = true;\n // Buffered mode: anchor to the first sample, play through without skipping ahead.\n #buffered;\n // Un-stall threshold in samples (how much to buffer before playback starts).\n #latencySamples;\n // Whether the read/write indices have been anchored to the first inserted sample.\n #anchored = false;\n constructor(props) {\n if (props.channels <= 0) throw new Error(\"invalid channels\");\n if (props.rate <= 0) throw new Error(\"invalid sample rate\");\n if (props.latency <= 0) throw new Error(\"invalid latency\");\n this.#latencySamples = Math.ceil(props.rate * time_exports.Second.fromMilli(props.latency));\n if (this.#latencySamples === 0) throw new Error(\"empty buffer\");\n this.rate = props.rate;\n this.channels = props.channels;\n this.#buffered = props.buffered ?? false;\n const capacity = this.#capacityFor(this.#latencySamples);\n this.#buffer = [];\n for (let i = 0; i < this.channels; i++) {\n this.#buffer[i] = new Float32Array(capacity);\n }\n }\n #capacityFor(latencySamples) {\n return this.#buffered ? latencySamples * 2 : latencySamples;\n }\n get stalled() {\n return this.#stalled;\n }\n get timestamp() {\n return time_exports.Micro.fromSecond(this.#readIndex / this.rate);\n }\n get length() {\n return this.#writeIndex - this.#readIndex;\n }\n get capacity() {\n return this.#buffer[0]?.length;\n }\n resize(latency) {\n this.#latencySamples = Math.ceil(this.rate * time_exports.Second.fromMilli(latency));\n const newCapacity = this.#capacityFor(this.#latencySamples);\n if (newCapacity === this.capacity) return;\n if (newCapacity === 0) throw new Error(\"empty buffer\");\n const newBuffer = [];\n for (let i = 0; i < this.channels; i++) {\n newBuffer[i] = new Float32Array(newCapacity);\n }\n const samplesToKeep = Math.min(this.length, newCapacity);\n if (samplesToKeep > 0) {\n const copyStart = this.#writeIndex - samplesToKeep;\n for (let channel = 0; channel < this.channels; channel++) {\n const src = this.#buffer[channel];\n const dst = newBuffer[channel];\n for (let i = 0; i < samplesToKeep; i++) {\n const srcPos = (copyStart + i) % src.length;\n const dstPos = (copyStart + i) % dst.length;\n dst[dstPos] = src[srcPos];\n }\n }\n }\n this.#buffer = newBuffer;\n this.#readIndex = this.#writeIndex - samplesToKeep;\n if (samplesToKeep === 0) this.#stalled = true;\n }\n write(timestamp, data) {\n if (data.length !== this.channels) throw new Error(\"wrong number of channels\");\n let start = Math.round(time_exports.Second.fromMicro(timestamp) * this.rate);\n let samples = data[0].length;\n if (this.#buffered && !this.#anchored) {\n this.#readIndex = start;\n this.#writeIndex = start;\n this.#anchored = true;\n }\n let offset = this.#readIndex - start;\n if (offset > samples) {\n return;\n } else if (offset > 0) {\n samples -= offset;\n start += offset;\n } else {\n offset = 0;\n }\n const end = start + samples;\n const overflow = end - this.#readIndex - this.#buffer[0].length;\n if (overflow >= 0) {\n this.#stalled = false;\n this.#readIndex += overflow;\n }\n if (start > this.#writeIndex) {\n const gapSize = Math.min(start - this.#writeIndex, this.#buffer[0].length);\n if (gapSize === 1) {\n console.warn(\"floating point inaccuracy detected\");\n }\n for (let channel = 0; channel < this.channels; channel++) {\n const dst = this.#buffer[channel];\n for (let i = 0; i < gapSize; i++) {\n const writePos = (this.#writeIndex + i) % dst.length;\n dst[writePos] = 0;\n }\n }\n }\n for (let channel = 0; channel < this.channels; channel++) {\n let src = data[channel];\n src = src.subarray(src.length - samples);\n const dst = this.#buffer[channel];\n if (src.length !== samples) throw new Error(\"mismatching number of samples\");\n for (let i = 0; i < samples; i++) {\n const writePos = (start + i) % dst.length;\n dst[writePos] = src[i];\n }\n }\n if (end > this.#writeIndex) {\n this.#writeIndex = end;\n }\n if (this.#buffered && this.length >= this.#latencySamples) {\n this.#stalled = false;\n }\n }\n // Flush all buffered samples and re-stall, ready to anchor the next utterance.\n reset() {\n this.#readIndex = 0;\n this.#writeIndex = 0;\n this.#stalled = true;\n this.#anchored = false;\n }\n read(output) {\n if (output.length !== this.channels) throw new Error(\"wrong number of channels\");\n if (this.#stalled) return 0;\n const samples = Math.min(this.#writeIndex - this.#readIndex, output[0].length);\n if (samples === 0) return 0;\n for (let channel = 0; channel < this.channels; channel++) {\n const dst = output[channel];\n const src = this.#buffer[channel];\n if (dst.length !== output[0].length) throw new Error(\"mismatching number of samples\");\n for (let i = 0; i < samples; i++) {\n const readPos = (this.#readIndex + i) % src.length;\n dst[i] = src[readPos];\n }\n }\n this.#readIndex += samples;\n return samples;\n }\n};\n\n// src/audio/shared-ring-buffer.ts\nvar WRITE = 0;\nvar READ = 1;\nvar LATENCY = 2;\nvar STALLED = 3;\nvar CONTROL_SLOTS = 4;\nfunction allocSharedRingBuffer(channels, capacity, rate, buffered = false) {\n if (channels <= 0) throw new Error(\"invalid channels\");\n if (capacity <= 0) throw new Error(\"invalid capacity\");\n if (rate <= 0) throw new Error(\"invalid sample rate\");\n const samples = new SharedArrayBuffer(channels * capacity * Float32Array.BYTES_PER_ELEMENT);\n const control = new SharedArrayBuffer(CONTROL_SLOTS * Int32Array.BYTES_PER_ELEMENT);\n const ctrl = new Int32Array(control);\n Atomics.store(ctrl, STALLED, 1);\n return { channels, capacity, rate, samples, control, buffered };\n}\nfunction i32Max(a, b) {\n return (a - b | 0) > 0 ? a : b;\n}\nfunction slot(idx, capacity) {\n return (idx % capacity + capacity) % capacity;\n}\nfunction casAdvance(arr, idx, candidate) {\n for (; ; ) {\n const current = Atomics.load(arr, idx);\n if ((candidate - current | 0) <= 0) return current;\n const witnessed = Atomics.compareExchange(arr, idx, current, candidate);\n if (witnessed === current) return candidate;\n }\n}\nvar SharedRingBuffer = class _SharedRingBuffer {\n channels;\n capacity;\n rate;\n buffered;\n init;\n #control;\n #samples;\n // Whether READ/WRITE have been anchored to the first inserted sample (buffered mode).\n #anchored = false;\n constructor(init) {\n this.channels = init.channels;\n this.capacity = init.capacity;\n this.rate = init.rate;\n this.buffered = init.buffered;\n this.init = init;\n this.#control = new Int32Array(init.control);\n this.#samples = [];\n for (let i = 0; i < this.channels; i++) {\n this.#samples.push(\n new Float32Array(init.samples, i * this.capacity * Float32Array.BYTES_PER_ELEMENT, this.capacity)\n );\n }\n }\n /**\n * Insert audio samples at the given timestamp.\n * Main thread only. Handles out-of-order writes, gap filling, and overflow.\n */\n insert(timestamp, data) {\n if (data.length !== this.channels) throw new Error(\"wrong number of channels\");\n let start = Math.round(time_exports.Second.fromMicro(timestamp) * this.rate);\n const originalLength = data[0].length;\n let offset = 0;\n if (this.buffered && !this.#anchored) {\n Atomics.store(this.#control, READ, start | 0);\n Atomics.store(this.#control, WRITE, start | 0);\n this.#anchored = true;\n }\n const end = start + originalLength | 0;\n const read = Atomics.load(this.#control, READ);\n const behind = read - start | 0;\n if (behind > 0) {\n if (behind >= originalLength) {\n return;\n }\n offset = behind;\n start = start + behind | 0;\n }\n const samples = originalLength - offset;\n if ((end - read | 0) > this.capacity) {\n casAdvance(this.#control, READ, end - this.capacity | 0);\n }\n const write = Atomics.load(this.#control, WRITE);\n const gap = start - write | 0;\n if (gap > 0) {\n const gapSize = Math.min(gap, this.capacity);\n for (let channel = 0; channel < this.channels; channel++) {\n const dst = this.#samples[channel];\n for (let i = 0; i < gapSize; i++) {\n dst[slot(write + i | 0, this.capacity)] = 0;\n }\n }\n }\n for (let channel = 0; channel < this.channels; channel++) {\n const src = data[channel];\n const dst = this.#samples[channel];\n for (let i = 0; i < samples; i++) {\n dst[slot(start + i | 0, this.capacity)] = src[offset + i];\n }\n }\n Atomics.store(this.#control, WRITE, i32Max(Atomics.load(this.#control, WRITE), end));\n const currentRead = Atomics.load(this.#control, READ);\n const currentWrite = Atomics.load(this.#control, WRITE);\n const latency = Atomics.load(this.#control, LATENCY);\n if ((currentWrite - currentRead | 0) >= latency && latency > 0) {\n Atomics.store(this.#control, STALLED, 0);\n }\n }\n /**\n * Read audio samples into the output buffers.\n * AudioWorklet only. Returns the number of samples read.\n */\n read(output) {\n if (Atomics.load(this.#control, STALLED) === 1) return 0;\n let read = Atomics.load(this.#control, READ);\n const write = Atomics.load(this.#control, WRITE);\n const latency = Atomics.load(this.#control, LATENCY);\n const buffered = write - read | 0;\n if (!this.buffered && latency > 0 && buffered > latency) {\n const skipTo = write - latency | 0;\n read = casAdvance(this.#control, READ, skipTo);\n }\n const available = write - read | 0;\n const count = Math.min(available, output[0].length);\n if (count <= 0) return 0;\n for (let channel = 0; channel < this.channels; channel++) {\n const src = this.#samples[channel];\n const dst = output[channel];\n for (let i = 0; i < count; i++) {\n dst[i] = src[slot(read + i | 0, this.capacity)];\n }\n }\n casAdvance(this.#control, READ, read + count | 0);\n return count;\n }\n /** Update the target latency in samples. */\n setLatency(samples) {\n Atomics.store(this.#control, LATENCY, samples);\n }\n /**\n * Flush buffered samples and re-stall, ready to anchor the next utterance (buffered mode).\n * Main thread only. The worklet reader sees STALLED and stops until the next insert.\n */\n reset() {\n this.#anchored = false;\n Atomics.store(this.#control, STALLED, 1);\n const write = Atomics.load(this.#control, WRITE);\n Atomics.store(this.#control, READ, write);\n }\n /**\n * Allocate a new ring with `newCapacity` samples and copy the unread window\n * [READ, WRITE) plus control state into it. Used when growing capacity so\n * we don't drop buffered audio. If `newCapacity` is smaller than the unread\n * span, the oldest samples are truncated.\n *\n * Main thread only. `resize()` reads from the source `SharedRingBuffer` and\n * writes into a freshly allocated buffer from `allocSharedRingBuffer`, so it\n * relies on the same invariant as `insert()`: no concurrent main-thread\n * writers. The AudioWorklet reader is tolerated via the CAS discipline used\n * by READ/WRITE elsewhere.\n */\n resize(newCapacity) {\n const init = allocSharedRingBuffer(this.channels, newCapacity, this.rate, this.buffered);\n const dst = new _SharedRingBuffer(init);\n dst.#anchored = this.#anchored;\n const read = Atomics.load(this.#control, READ);\n const write = Atomics.load(this.#control, WRITE);\n const latency = Atomics.load(this.#control, LATENCY);\n const stalled = Atomics.load(this.#control, STALLED);\n const available = write - read | 0;\n const copyCount = Math.max(0, Math.min(available, dst.capacity));\n const copyStart = write - copyCount | 0;\n for (let channel = 0; channel < this.channels; channel++) {\n const src = this.#samples[channel];\n const out = dst.#samples[channel];\n for (let i = 0; i < copyCount; i++) {\n const idx = copyStart + i | 0;\n out[slot(idx, dst.capacity)] = src[slot(idx, this.capacity)];\n }\n }\n Atomics.store(dst.#control, READ, copyStart);\n Atomics.store(dst.#control, WRITE, write);\n Atomics.store(dst.#control, LATENCY, latency);\n Atomics.store(dst.#control, STALLED, stalled);\n return dst;\n }\n /** Current playback timestamp derived from READ position. */\n get timestamp() {\n const read = Atomics.load(this.#control, READ);\n return time_exports.Micro.fromSecond(read / this.rate);\n }\n /** Whether the buffer is stalled (waiting to fill). */\n get stalled() {\n return Atomics.load(this.#control, STALLED) === 1;\n }\n /**\n * Number of buffered samples (WRITE - READ).\n *\n * Non-atomic: WRITE and READ are loaded separately, so a concurrent\n * writer/reader can make the two loads inconsistent. Intended for\n * tests and diagnostics, not control-flow decisions.\n */\n get length() {\n return Atomics.load(this.#control, WRITE) - Atomics.load(this.#control, READ) | 0;\n }\n};\n\n// src/audio/render-worklet.ts\nvar Render = class extends AudioWorkletProcessor {\n // Set after init, depending on which path the main thread chose.\n #backend;\n #underflow = 0;\n #stateCounter = 0;\n constructor() {\n super();\n this.port.onmessage = (event) => {\n const msg = event.data;\n if (msg.type === \"init-shared\") {\n console.log(\"[audio-worklet] init-shared: using SharedArrayBuffer path\");\n this.#backend = new SharedRingBuffer(msg);\n this.#underflow = 0;\n } else if (msg.type === \"init-post\") {\n console.log(\"[audio-worklet] init-post: using postMessage path\");\n this.#backend = new AudioRingBuffer(msg);\n this.#underflow = 0;\n } else if (msg.type === \"data\") {\n if (this.#backend instanceof AudioRingBuffer) this.#backend.write(msg.timestamp, msg.data);\n } else if (msg.type === \"latency\") {\n if (this.#backend instanceof AudioRingBuffer) this.#backend.resize(msg.latency);\n } else if (msg.type === \"reset\") {\n if (this.#backend instanceof AudioRingBuffer) this.#backend.reset();\n }\n };\n }\n process(_inputs, outputs, _parameters) {\n const output = outputs[0];\n const backend = this.#backend;\n const samplesRead = backend?.read(output) ?? 0;\n if (samplesRead < output[0].length) {\n this.#underflow += output[0].length - samplesRead;\n } else if (this.#underflow > 0 && backend) {\n console.debug(`audio underflow: ${Math.round(1e3 * this.#underflow / backend.rate)}ms`);\n this.#underflow = 0;\n }\n if (backend instanceof AudioRingBuffer) {\n this.#stateCounter++;\n if (this.#stateCounter >= 5) {\n this.#stateCounter = 0;\n const state = {\n type: \"state\",\n timestamp: backend.timestamp,\n stalled: backend.stalled\n };\n this.port.postMessage(state);\n }\n }\n return true;\n }\n};\nregisterProcessor(\"render\", Render);\n"], { type: "application/javascript" }), D = URL.createObjectURL(re), O = class {
|
|
219
274
|
source;
|
|
220
275
|
enabled;
|
|
221
276
|
#e = new a(void 0);
|
|
@@ -234,11 +289,15 @@ var te = class {
|
|
|
234
289
|
#s = new a([]);
|
|
235
290
|
buffered = this.#s;
|
|
236
291
|
#c;
|
|
237
|
-
#l =
|
|
292
|
+
#l = 0;
|
|
293
|
+
#u = new i();
|
|
294
|
+
#d = new a(r.Milli.zero);
|
|
238
295
|
constructor(e, t) {
|
|
239
|
-
this.source = e, this.source.supported.set(
|
|
296
|
+
this.source = e, this.source.supported.set(k), this.enabled = a.from(t?.enabled ?? !1), this.#u.run((e) => {
|
|
297
|
+
this.#d.set(e.get(this.source.sync.maxBuffer));
|
|
298
|
+
}), this.#u.run(this.#f.bind(this)), this.#u.run(this.#p.bind(this)), this.#u.run(this.#m.bind(this)), this.#u.run(this.#h.bind(this));
|
|
240
299
|
}
|
|
241
|
-
#
|
|
300
|
+
#f(e) {
|
|
242
301
|
let t = e.get(this.source.config);
|
|
243
302
|
if (!t) return;
|
|
244
303
|
let n = t.sampleRate, i = t.numberOfChannels, a = new AudioContext({
|
|
@@ -246,38 +305,38 @@ var te = class {
|
|
|
246
305
|
sampleRate: n
|
|
247
306
|
});
|
|
248
307
|
e.set(this.#e, a), e.cleanup(() => a.close()), e.spawn(async () => {
|
|
249
|
-
if (await a.audioWorklet.addModule(
|
|
308
|
+
if (await a.audioWorklet.addModule(D), a.state === "closed") return;
|
|
250
309
|
let t = new AudioWorkletNode(a, "render", {
|
|
251
310
|
channelCount: i,
|
|
252
311
|
channelCountMode: "explicit",
|
|
253
312
|
outputChannelCount: [i]
|
|
254
313
|
});
|
|
255
314
|
e.cleanup(() => t.disconnect());
|
|
256
|
-
let o = this.source.sync.buffer.peek(), s = ee(t, i, n, Math.ceil(n * r.Second.fromMilli(o)));
|
|
315
|
+
let o = this.source.sync.buffer.peek(), s = ee(t, i, n, Math.ceil(n * r.Second.fromMilli(o)), this.source.sync.buffered.peek());
|
|
257
316
|
this.#c = s, e.cleanup(() => {
|
|
258
317
|
s.close(), this.#c = void 0;
|
|
259
318
|
}), e.run((e) => {
|
|
260
319
|
let t = r.Milli.fromMicro(e.get(s.timestamp));
|
|
261
|
-
this.#i.set(t), this.#
|
|
320
|
+
this.#i.set(t), this.#b(t);
|
|
262
321
|
}), e.run((e) => {
|
|
263
322
|
this.#a.set(e.get(s.stalled));
|
|
264
323
|
}), e.set(this.#t, t);
|
|
265
324
|
});
|
|
266
325
|
}
|
|
267
|
-
#
|
|
326
|
+
#p(e) {
|
|
268
327
|
let t = e.getAll([this.enabled, this.#e]);
|
|
269
328
|
if (!t) return;
|
|
270
329
|
let [n, r] = t;
|
|
271
330
|
r.resume();
|
|
272
331
|
}
|
|
273
|
-
#
|
|
332
|
+
#m(e) {
|
|
274
333
|
if (!e.get(this.#t)) return;
|
|
275
334
|
let t = this.#c;
|
|
276
335
|
if (!t) return;
|
|
277
336
|
let n = e.get(this.source.sync.buffer), i = Math.ceil(t.rate * r.Second.fromMilli(n));
|
|
278
337
|
t.setLatency(i);
|
|
279
338
|
}
|
|
280
|
-
#
|
|
339
|
+
#h(e) {
|
|
281
340
|
if (!e.get(this.enabled)) return;
|
|
282
341
|
let t = e.get(this.source.broadcast);
|
|
283
342
|
if (!t) return;
|
|
@@ -288,12 +347,12 @@ var te = class {
|
|
|
288
347
|
let i = e.get(t.active);
|
|
289
348
|
if (!i) return;
|
|
290
349
|
let a = i.subscribe(n, o.PRIORITY.audio);
|
|
291
|
-
e.cleanup(() => a.close()), r.container.kind === "cmaf" ? this.#
|
|
350
|
+
e.cleanup(() => a.close()), r.container.kind === "cmaf" ? this.#_(e, a, r) : this.#g(e, a, r);
|
|
292
351
|
}
|
|
293
|
-
#
|
|
352
|
+
#g(e, t, n) {
|
|
294
353
|
let i = n.container.kind === "loc" ? new c.Loc.Format() : new c.Legacy.Format(), a = new c.Consumer(t, {
|
|
295
354
|
format: i,
|
|
296
|
-
latency: this
|
|
355
|
+
latency: this.#d
|
|
297
356
|
});
|
|
298
357
|
e.cleanup(() => a.close()), e.run((e) => {
|
|
299
358
|
let t = e.get(a.buffered), n = e.get(this.#o);
|
|
@@ -306,7 +365,7 @@ var te = class {
|
|
|
306
365
|
e.close();
|
|
307
366
|
return;
|
|
308
367
|
}
|
|
309
|
-
this.#
|
|
368
|
+
this.#v(e);
|
|
310
369
|
},
|
|
311
370
|
error: (e) => console.error(e)
|
|
312
371
|
});
|
|
@@ -320,10 +379,11 @@ var te = class {
|
|
|
320
379
|
});;) {
|
|
321
380
|
let e = await a.next();
|
|
322
381
|
if (!e) break;
|
|
382
|
+
this.#x(e.discontinuity);
|
|
323
383
|
let { frame: t } = e;
|
|
324
384
|
if (!t) continue;
|
|
325
385
|
let n = r.Milli.fromMicro(t.timestamp);
|
|
326
|
-
this.source.sync.received(n, "audio"), this.#r.update((e) => ({ bytesReceived: (e?.bytesReceived ?? 0) + t.data.byteLength }));
|
|
386
|
+
this.source.sync.received(n, "audio"), this.#r.update((e) => ({ bytesReceived: (e?.bytesReceived ?? 0) + t.data.byteLength })), await this.#c?.wait(t.timestamp);
|
|
327
387
|
let o = new EncodedAudioChunk({
|
|
328
388
|
type: t.keyframe ? "key" : "delta",
|
|
329
389
|
data: t.data,
|
|
@@ -333,11 +393,11 @@ var te = class {
|
|
|
333
393
|
}
|
|
334
394
|
});
|
|
335
395
|
}
|
|
336
|
-
#
|
|
396
|
+
#_(e, t, n) {
|
|
337
397
|
if (n.container.kind !== "cmaf") return;
|
|
338
398
|
let i = p(n.container.init), a = c.Cmaf.decodeInitSegment(i), o = n.codec === "opus" ? void 0 : n.description ? l.Hex.toBytes(n.description) : a.description, s = new c.Consumer(t, {
|
|
339
399
|
format: new c.Cmaf.Format(a),
|
|
340
|
-
latency: this
|
|
400
|
+
latency: this.#d
|
|
341
401
|
});
|
|
342
402
|
e.cleanup(() => s.close()), e.run((e) => {
|
|
343
403
|
let t = e.get(s.buffered), n = e.get(this.#o);
|
|
@@ -345,7 +405,7 @@ var te = class {
|
|
|
345
405
|
}), e.spawn(async () => {
|
|
346
406
|
if (!await l.Libav.polyfill()) return;
|
|
347
407
|
let t = new AudioDecoder({
|
|
348
|
-
output: (e) => this.#
|
|
408
|
+
output: (e) => this.#v(e),
|
|
349
409
|
error: (e) => console.error(e)
|
|
350
410
|
});
|
|
351
411
|
for (e.cleanup(() => {
|
|
@@ -358,10 +418,11 @@ var te = class {
|
|
|
358
418
|
});;) {
|
|
359
419
|
let e = await s.next();
|
|
360
420
|
if (!e) break;
|
|
421
|
+
this.#x(e.discontinuity);
|
|
361
422
|
let { frame: n } = e;
|
|
362
423
|
if (!n) continue;
|
|
363
424
|
let i = r.Milli.fromMicro(n.timestamp);
|
|
364
|
-
if (this.source.sync.received(i, "audio"), this.#r.update((e) => ({ bytesReceived: (e?.bytesReceived ?? 0) + n.data.byteLength })), t.state === "closed") break;
|
|
425
|
+
if (this.source.sync.received(i, "audio"), this.#r.update((e) => ({ bytesReceived: (e?.bytesReceived ?? 0) + n.data.byteLength })), await this.#c?.wait(n.timestamp), t.state === "closed") break;
|
|
365
426
|
t.decode(new EncodedAudioChunk({
|
|
366
427
|
type: n.keyframe ? "key" : "delta",
|
|
367
428
|
data: n.data,
|
|
@@ -370,14 +431,14 @@ var te = class {
|
|
|
370
431
|
}
|
|
371
432
|
});
|
|
372
433
|
}
|
|
373
|
-
#
|
|
434
|
+
#v(e) {
|
|
374
435
|
let t = e.timestamp, n = r.Milli.fromMicro(t), i = this.#c;
|
|
375
436
|
if (!i) {
|
|
376
437
|
e.close();
|
|
377
438
|
return;
|
|
378
439
|
}
|
|
379
440
|
let a = e.numberOfFrames / e.sampleRate * 1e6, o = r.Milli.fromMicro(a), s = r.Milli.add(n, o);
|
|
380
|
-
this.#
|
|
441
|
+
this.#y(n, s);
|
|
381
442
|
let c = Math.min(e.numberOfChannels, i.channels), l = [];
|
|
382
443
|
for (let t = 0; t < c; t++) {
|
|
383
444
|
let n = new Float32Array(e.numberOfFrames);
|
|
@@ -388,7 +449,7 @@ var te = class {
|
|
|
388
449
|
}
|
|
389
450
|
i.insert(t, l), e.close();
|
|
390
451
|
}
|
|
391
|
-
#
|
|
452
|
+
#y(e, t) {
|
|
392
453
|
e > t || this.#o.mutate((n) => {
|
|
393
454
|
for (let i of n) if (e <= i.end + 1 && t >= i.start) {
|
|
394
455
|
i.start = r.Milli.min(i.start, e), i.end = r.Milli.max(i.end, t);
|
|
@@ -400,7 +461,7 @@ var te = class {
|
|
|
400
461
|
}), n.sort((e, t) => e.start - t.start);
|
|
401
462
|
});
|
|
402
463
|
}
|
|
403
|
-
#
|
|
464
|
+
#b(e) {
|
|
404
465
|
this.#o.mutate((t) => {
|
|
405
466
|
for (; t.length > 0;) {
|
|
406
467
|
if (t[0].end >= e) {
|
|
@@ -411,11 +472,17 @@ var te = class {
|
|
|
411
472
|
}
|
|
412
473
|
});
|
|
413
474
|
}
|
|
475
|
+
reset() {
|
|
476
|
+
this.#c?.reset();
|
|
477
|
+
}
|
|
478
|
+
#x(e) {
|
|
479
|
+
e !== this.#l && (this.#l = e, this.#c?.reset(), this.source.sync.reset());
|
|
480
|
+
}
|
|
414
481
|
close() {
|
|
415
|
-
this.#
|
|
482
|
+
this.#u.close();
|
|
416
483
|
}
|
|
417
484
|
};
|
|
418
|
-
async function
|
|
485
|
+
async function k(e) {
|
|
419
486
|
let t;
|
|
420
487
|
if (e.codec !== "opus") {
|
|
421
488
|
if (e.description) t = l.Hex.toBytes(e.description);
|
|
@@ -432,7 +499,7 @@ async function D(e) {
|
|
|
432
499
|
}
|
|
433
500
|
//#endregion
|
|
434
501
|
//#region src/audio/emitter.ts
|
|
435
|
-
var
|
|
502
|
+
var A = .001, j = .2, M = class {
|
|
436
503
|
source;
|
|
437
504
|
volume;
|
|
438
505
|
muted;
|
|
@@ -461,13 +528,215 @@ var O = .001, k = .2, A = class {
|
|
|
461
528
|
if (!t) return;
|
|
462
529
|
e.cleanup(() => t.gain.cancelScheduledValues(t.context.currentTime));
|
|
463
530
|
let n = e.get(this.volume);
|
|
464
|
-
n <
|
|
531
|
+
n < A ? (t.gain.exponentialRampToValueAtTime(A, t.context.currentTime + j), t.gain.setValueAtTime(0, t.context.currentTime + j + .01)) : t.gain.exponentialRampToValueAtTime(n, t.context.currentTime + j);
|
|
465
532
|
});
|
|
466
533
|
}
|
|
467
534
|
close() {
|
|
468
535
|
this.#e.close();
|
|
469
536
|
}
|
|
470
|
-
}
|
|
537
|
+
};
|
|
538
|
+
//#endregion
|
|
539
|
+
//#region src/buffered.ts
|
|
540
|
+
function N(e) {
|
|
541
|
+
let n = [];
|
|
542
|
+
for (let r = 0; r < e.length; r++) {
|
|
543
|
+
let i = t.Time.Milli.fromSecond(e.start(r)), a = t.Time.Milli.fromSecond(e.end(r));
|
|
544
|
+
n.push({
|
|
545
|
+
start: i,
|
|
546
|
+
end: a
|
|
547
|
+
});
|
|
548
|
+
}
|
|
549
|
+
return n;
|
|
550
|
+
}
|
|
551
|
+
//#endregion
|
|
552
|
+
//#region src/audio/mse.ts
|
|
553
|
+
var P = class {
|
|
554
|
+
muxer;
|
|
555
|
+
source;
|
|
556
|
+
volume;
|
|
557
|
+
muted;
|
|
558
|
+
#e = new a(void 0);
|
|
559
|
+
stats = this.#e;
|
|
560
|
+
#t = new a([]);
|
|
561
|
+
buffered = this.#t;
|
|
562
|
+
context = new a(void 0);
|
|
563
|
+
#n = new i();
|
|
564
|
+
constructor(e, t, n) {
|
|
565
|
+
this.muxer = e, this.source = t, this.source.supported.set(ie), this.volume = a.from(n?.volume ?? .5), this.muted = a.from(n?.muted ?? !1), this.#n.run(this.#r.bind(this)), this.#n.run(this.#s.bind(this));
|
|
566
|
+
}
|
|
567
|
+
#r(e) {
|
|
568
|
+
let t = e.get(this.muxer.element);
|
|
569
|
+
if (!t) return;
|
|
570
|
+
let n = e.get(this.muxer.mediaSource);
|
|
571
|
+
if (!n) return;
|
|
572
|
+
let r = e.get(this.source.broadcast);
|
|
573
|
+
if (!r) return;
|
|
574
|
+
let i = e.get(r.active);
|
|
575
|
+
if (!i) return;
|
|
576
|
+
let a = e.get(this.source.track);
|
|
577
|
+
if (!a) return;
|
|
578
|
+
let s = e.get(this.source.config);
|
|
579
|
+
if (!s) return;
|
|
580
|
+
let c = `audio/mp4; codecs="${s.codec}"`, l = n.addSourceBuffer(c);
|
|
581
|
+
e.cleanup(() => {
|
|
582
|
+
n.removeSourceBuffer(l), l.abort();
|
|
583
|
+
}), e.event(l, "error", (e) => {
|
|
584
|
+
console.error("[MSE] SourceBuffer error:", e);
|
|
585
|
+
}), e.event(l, "updateend", () => {
|
|
586
|
+
this.#t.set(N(l.buffered));
|
|
587
|
+
});
|
|
588
|
+
let u = i.subscribe(a, o.PRIORITY.audio);
|
|
589
|
+
e.cleanup(() => u.close()), s.container.kind === "cmaf" ? this.#a(e, u, s, l, t) : this.#o(e, u, s, l, t);
|
|
590
|
+
}
|
|
591
|
+
async #i(e, t) {
|
|
592
|
+
for (; e.updating;) await new Promise((t) => e.addEventListener("updateend", t, { once: !0 }));
|
|
593
|
+
for (e.appendBuffer(t); e.updating;) await new Promise((t) => e.addEventListener("updateend", t, { once: !0 }));
|
|
594
|
+
}
|
|
595
|
+
#a(e, n, r, i, a) {
|
|
596
|
+
if (r.container.kind !== "cmaf") throw Error("unreachable");
|
|
597
|
+
let o = p(r.container.init), s = c.Cmaf.decodeInitSegment(o);
|
|
598
|
+
e.spawn(async () => {
|
|
599
|
+
for (await this.#i(i, o);;) {
|
|
600
|
+
let e = await n.readFrame();
|
|
601
|
+
if (!e) return;
|
|
602
|
+
let r = c.Cmaf.decodeTimestamp(e, s);
|
|
603
|
+
this.source.sync.received(t.Time.Milli.fromMicro(r), "audio"), await this.#i(i, e), a.buffered.length > 0 && a.currentTime < a.buffered.start(0) && (a.currentTime = a.buffered.start(0));
|
|
604
|
+
}
|
|
605
|
+
});
|
|
606
|
+
}
|
|
607
|
+
#o(e, n, r, i, a) {
|
|
608
|
+
let o = r.container.kind === "loc" ? new c.Loc.Format() : new c.Legacy.Format(), s = new c.Consumer(n, {
|
|
609
|
+
format: o,
|
|
610
|
+
latency: this.source.sync.buffer
|
|
611
|
+
});
|
|
612
|
+
e.cleanup(() => s.close()), e.spawn(async () => {
|
|
613
|
+
let e = c.Cmaf.createAudioInitSegment(r);
|
|
614
|
+
await this.#i(i, e);
|
|
615
|
+
let n = 1, o, l;
|
|
616
|
+
for (;;) {
|
|
617
|
+
let e = await s.next();
|
|
618
|
+
if (!e) return;
|
|
619
|
+
if (!e.frame) continue;
|
|
620
|
+
l = e.frame;
|
|
621
|
+
let n = t.Time.Milli.fromMicro(l.timestamp);
|
|
622
|
+
this.source.sync.received(n, "audio");
|
|
623
|
+
break;
|
|
624
|
+
}
|
|
625
|
+
for (;;) {
|
|
626
|
+
let e = await s.next();
|
|
627
|
+
if (e && !e.frame) continue;
|
|
628
|
+
let r = e?.frame;
|
|
629
|
+
if (r) {
|
|
630
|
+
o = t.Time.Micro.sub(r.timestamp, l.timestamp);
|
|
631
|
+
let e = t.Time.Milli.fromMicro(r.timestamp);
|
|
632
|
+
this.source.sync.received(e, "audio");
|
|
633
|
+
}
|
|
634
|
+
let u = c.Cmaf.encodeDataSegment({
|
|
635
|
+
data: l.data,
|
|
636
|
+
timestamp: l.timestamp,
|
|
637
|
+
duration: o ?? 0,
|
|
638
|
+
keyframe: l.keyframe,
|
|
639
|
+
sequence: n++
|
|
640
|
+
});
|
|
641
|
+
if (await this.#i(i, u), a.buffered.length > 0 && a.currentTime < a.buffered.start(0) && (a.currentTime = a.buffered.start(0)), !r) return;
|
|
642
|
+
l = r;
|
|
643
|
+
}
|
|
644
|
+
});
|
|
645
|
+
}
|
|
646
|
+
#s(e) {
|
|
647
|
+
let t = e.get(this.muxer.element);
|
|
648
|
+
if (!t) return;
|
|
649
|
+
let n = e.get(this.volume), r = e.get(this.muted);
|
|
650
|
+
r && !t.muted ? t.muted = !0 : !r && t.muted && (t.muted = !1), n !== t.volume && (t.volume = n), e.event(t, "volumechange", () => {
|
|
651
|
+
this.volume.set(t.volume);
|
|
652
|
+
});
|
|
653
|
+
}
|
|
654
|
+
close() {
|
|
655
|
+
this.#n.close();
|
|
656
|
+
}
|
|
657
|
+
};
|
|
658
|
+
async function ie(e) {
|
|
659
|
+
return MediaSource.isTypeSupported(`audio/mp4; codecs="${e.codec}"`);
|
|
660
|
+
}
|
|
661
|
+
//#endregion
|
|
662
|
+
//#region src/audio/source.ts
|
|
663
|
+
var ae = 128, F = class {
|
|
664
|
+
broadcast;
|
|
665
|
+
target;
|
|
666
|
+
catalog;
|
|
667
|
+
#e = new a({});
|
|
668
|
+
available = this.#e;
|
|
669
|
+
#t = new a(void 0);
|
|
670
|
+
track = this.#t;
|
|
671
|
+
#n = new a(void 0);
|
|
672
|
+
config = this.#n;
|
|
673
|
+
supported;
|
|
674
|
+
sync;
|
|
675
|
+
#r = new i();
|
|
676
|
+
constructor(e, t) {
|
|
677
|
+
this.sync = e, this.broadcast = a.from(t?.broadcast), this.target = a.from(t?.target), this.supported = a.from(t?.supported), this.catalog = this.#r.computed((e) => {
|
|
678
|
+
let t = e.get(this.broadcast);
|
|
679
|
+
return t ? e.get(t.catalog)?.audio : void 0;
|
|
680
|
+
}), this.#r.run(this.#i.bind(this)), this.#r.run(this.#a.bind(this));
|
|
681
|
+
}
|
|
682
|
+
#i(e) {
|
|
683
|
+
let t = e.get(this.catalog)?.renditions ?? {}, n = e.get(this.supported);
|
|
684
|
+
n && e.spawn(async () => {
|
|
685
|
+
let e = {};
|
|
686
|
+
for (let [r, i] of Object.entries(t)) await n(i) && (e[r] = i);
|
|
687
|
+
Object.keys(e).length === 0 && Object.keys(t).length > 0 && console.warn("no supported audio renditions found:", t), this.#e.set(e);
|
|
688
|
+
});
|
|
689
|
+
}
|
|
690
|
+
#a(e) {
|
|
691
|
+
let t = e.get(this.#e);
|
|
692
|
+
if (Object.keys(t).length === 0) return;
|
|
693
|
+
let n = e.get(this.target), r;
|
|
694
|
+
if (n?.name && n.name in t) r = {
|
|
695
|
+
track: n.name,
|
|
696
|
+
config: t[n.name]
|
|
697
|
+
};
|
|
698
|
+
else if (r = this.#o(t), !r) return;
|
|
699
|
+
e.set(this.#t, r.track), e.set(this.#n, r.config);
|
|
700
|
+
let i = (r.config.jitter ?? I(r.config) ?? 0) + Math.ceil(ae / r.config.sampleRate * 1e3);
|
|
701
|
+
e.set(this.sync.audio, i);
|
|
702
|
+
}
|
|
703
|
+
#o(e) {
|
|
704
|
+
let t = Object.entries(e);
|
|
705
|
+
if (t.length !== 0) {
|
|
706
|
+
for (let [e, n] of t) if (n.container.kind === "legacy") return {
|
|
707
|
+
track: e,
|
|
708
|
+
config: n
|
|
709
|
+
};
|
|
710
|
+
for (let [e, n] of t) if (n.container.kind === "loc") return {
|
|
711
|
+
track: e,
|
|
712
|
+
config: n
|
|
713
|
+
};
|
|
714
|
+
for (let [e, n] of t) if (n.container.kind === "cmaf") return {
|
|
715
|
+
track: e,
|
|
716
|
+
config: n
|
|
717
|
+
};
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
close() {
|
|
721
|
+
this.#r.close();
|
|
722
|
+
}
|
|
723
|
+
};
|
|
724
|
+
function I(e) {
|
|
725
|
+
if (e.codec.startsWith("opus")) return 20;
|
|
726
|
+
if (e.codec.startsWith("mp4a")) return Math.ceil(1024 / e.sampleRate * 1e3);
|
|
727
|
+
if (e.codec === "mp3") {
|
|
728
|
+
let t = e.sampleRate >= 32e3 ? 1152 : 576;
|
|
729
|
+
return Math.ceil(t / e.sampleRate * 1e3);
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
//#endregion
|
|
733
|
+
//#region src/audio/index.ts
|
|
734
|
+
var L = /* @__PURE__ */ f({
|
|
735
|
+
Decoder: () => O,
|
|
736
|
+
Emitter: () => M,
|
|
737
|
+
Mse: () => P,
|
|
738
|
+
Source: () => F
|
|
739
|
+
}), R = /* @__PURE__ */ f({ Muxer: () => z }), z = class {
|
|
471
740
|
element;
|
|
472
741
|
paused;
|
|
473
742
|
#e;
|
|
@@ -502,11 +771,8 @@ var O = .001, k = .2, A = class {
|
|
|
502
771
|
let t = e.get(this.element);
|
|
503
772
|
if (!t) return;
|
|
504
773
|
let n = e.get(this.mediaSource);
|
|
505
|
-
n && e.interval(
|
|
506
|
-
for (let e of n.sourceBuffers)
|
|
507
|
-
for (; e.updating;) await new Promise((t) => e.addEventListener("updateend", t, { once: !0 }));
|
|
508
|
-
t.currentTime > 10 && e.remove(0, t.currentTime - 10);
|
|
509
|
-
}
|
|
774
|
+
n && e.interval(() => {
|
|
775
|
+
for (let e of n.sourceBuffers) e.updating || t.currentTime > 10 && e.remove(0, t.currentTime - 10);
|
|
510
776
|
}, 1e3);
|
|
511
777
|
}
|
|
512
778
|
#o(e) {
|
|
@@ -528,91 +794,7 @@ var O = .001, k = .2, A = class {
|
|
|
528
794
|
close() {
|
|
529
795
|
this.#n.close();
|
|
530
796
|
}
|
|
531
|
-
},
|
|
532
|
-
#e = new a(void 0);
|
|
533
|
-
reference = this.#e;
|
|
534
|
-
latency;
|
|
535
|
-
jitter;
|
|
536
|
-
audio;
|
|
537
|
-
video;
|
|
538
|
-
#t = new a(r.Milli.zero);
|
|
539
|
-
buffer = this.#t;
|
|
540
|
-
#n;
|
|
541
|
-
timestamp = new a(void 0);
|
|
542
|
-
#r = /* @__PURE__ */ new Map();
|
|
543
|
-
#i;
|
|
544
|
-
#a;
|
|
545
|
-
signals = new i();
|
|
546
|
-
constructor(e) {
|
|
547
|
-
this.latency = a.from(e?.latency ?? "real-time"), this.jitter = new a(M), this.#i = e?.connection, this.audio = a.from(e?.audio), this.video = a.from(e?.video), this.#n = Promise.withResolvers(), this.signals.run(this.#o.bind(this)), this.signals.run(this.#s.bind(this));
|
|
548
|
-
}
|
|
549
|
-
#o(e) {
|
|
550
|
-
let t = e.get(this.latency);
|
|
551
|
-
if (typeof t == "number") {
|
|
552
|
-
this.#a = void 0, this.jitter.set(t);
|
|
553
|
-
return;
|
|
554
|
-
}
|
|
555
|
-
let n = (this.#i ? e.get(this.#i) : void 0)?.rtt, r = n ? e.get(n) : void 0;
|
|
556
|
-
if (r !== void 0) {
|
|
557
|
-
this.#a = this.#a === void 0 ? r : Math.min(this.#a, r);
|
|
558
|
-
let e = Math.max(ae, this.#a * 1.25);
|
|
559
|
-
this.jitter.set(e);
|
|
560
|
-
return;
|
|
561
|
-
}
|
|
562
|
-
this.#a = void 0, this.jitter.set(M);
|
|
563
|
-
}
|
|
564
|
-
#s(e) {
|
|
565
|
-
let t = e.get(this.jitter), n = e.get(this.video) ?? r.Milli.zero, i = e.get(this.audio) ?? r.Milli.zero, a = r.Milli.add(r.Milli.max(n, i), t);
|
|
566
|
-
this.#t.set(a), this.#n.resolve(), this.#n = Promise.withResolvers();
|
|
567
|
-
}
|
|
568
|
-
received(t, n = "") {
|
|
569
|
-
this.timestamp.update((e) => e === void 0 || t > e ? t : e);
|
|
570
|
-
let i = r.Milli.now(), a = r.Milli.sub(i, t), o = this.#e.peek();
|
|
571
|
-
if (o !== void 0) {
|
|
572
|
-
let t = r.Milli.add(r.Milli.sub(o, a), this.#t.peek());
|
|
573
|
-
if (t < 0) {
|
|
574
|
-
let e = this.#r.get(n);
|
|
575
|
-
e ? (e.count++, e.maxMs = Math.max(e.maxMs, -t)) : this.#r.set(n, {
|
|
576
|
-
count: 1,
|
|
577
|
-
maxMs: -t
|
|
578
|
-
});
|
|
579
|
-
} else {
|
|
580
|
-
let t = this.#r.get(n);
|
|
581
|
-
if (t) {
|
|
582
|
-
let r = n ? `sync[${n}]` : "sync", i = e.#c(t.maxMs);
|
|
583
|
-
console.debug(`${r}: ${t.count} late frame(s), max ${i} behind`), this.#r.delete(n);
|
|
584
|
-
}
|
|
585
|
-
}
|
|
586
|
-
if (a >= o) return;
|
|
587
|
-
}
|
|
588
|
-
this.#e.set(a), this.#n.resolve(), this.#n = Promise.withResolvers();
|
|
589
|
-
}
|
|
590
|
-
now() {
|
|
591
|
-
let e = this.#e.peek();
|
|
592
|
-
if (e !== void 0) return r.Milli.sub(r.Milli.sub(r.Milli.now(), e), this.#t.peek());
|
|
593
|
-
}
|
|
594
|
-
async wait(e) {
|
|
595
|
-
if (this.#e.peek() === void 0) throw Error("reference not set; call update() first");
|
|
596
|
-
for (;;) {
|
|
597
|
-
let t = r.Milli.now(), n = r.Milli.sub(t, e), i = this.#e.peek();
|
|
598
|
-
if (i === void 0) return;
|
|
599
|
-
let a = r.Milli.add(r.Milli.sub(i, n), this.#t.peek());
|
|
600
|
-
if (a <= 0 || a < 5) return;
|
|
601
|
-
let o = new Promise((e) => setTimeout(e, a)).then(() => !0);
|
|
602
|
-
if (await Promise.race([this.#n.promise, o])) return;
|
|
603
|
-
}
|
|
604
|
-
}
|
|
605
|
-
static #c(e) {
|
|
606
|
-
if (e = Math.round(e), e < 1e3) return `${e}ms`;
|
|
607
|
-
let t = e / 1e3;
|
|
608
|
-
if (t < 60) return `${Math.round(t * 10) / 10}s`;
|
|
609
|
-
let n = t / 60;
|
|
610
|
-
return `${Math.round(n * 10) / 10}m`;
|
|
611
|
-
}
|
|
612
|
-
close() {
|
|
613
|
-
this.signals.close();
|
|
614
|
-
}
|
|
615
|
-
}, oe = 500, se = 100, P = class {
|
|
797
|
+
}, B = 500, V = 100, H = class {
|
|
616
798
|
enabled;
|
|
617
799
|
source;
|
|
618
800
|
#e = new a(void 0);
|
|
@@ -635,7 +817,7 @@ var O = .001, k = .2, A = class {
|
|
|
635
817
|
}), this.#n.set(void 0);
|
|
636
818
|
}
|
|
637
819
|
constructor(e, t) {
|
|
638
|
-
this.enabled = a.from(t?.enabled ?? !1), this.source = e, this.source.supported.set(
|
|
820
|
+
this.enabled = a.from(t?.enabled ?? !1), this.source = e, this.source.supported.set(W), 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));
|
|
639
821
|
}
|
|
640
822
|
#l(e) {
|
|
641
823
|
let t = e.getAll([
|
|
@@ -653,7 +835,7 @@ var O = .001, k = .2, A = class {
|
|
|
653
835
|
this.#e.set(void 0), this.#c(), this.#o.set([]);
|
|
654
836
|
return;
|
|
655
837
|
}
|
|
656
|
-
let s = new
|
|
838
|
+
let s = new U({
|
|
657
839
|
source: this.source,
|
|
658
840
|
broadcast: o,
|
|
659
841
|
track: i,
|
|
@@ -665,7 +847,7 @@ var O = .001, k = .2, A = class {
|
|
|
665
847
|
let t = e.get(this.#e);
|
|
666
848
|
if (t) {
|
|
667
849
|
let n = e.get(s.timestamp), r = e.get(t.timestamp);
|
|
668
|
-
if (!n || r && r > n +
|
|
850
|
+
if (!n || r && r > n + V) return;
|
|
669
851
|
}
|
|
670
852
|
this.#e.set(s), s = void 0, e.close();
|
|
671
853
|
});
|
|
@@ -706,13 +888,13 @@ var O = .001, k = .2, A = class {
|
|
|
706
888
|
}
|
|
707
889
|
this.#i.set(!1), e.timer(() => {
|
|
708
890
|
this.#i.set(!0);
|
|
709
|
-
},
|
|
891
|
+
}, B);
|
|
710
892
|
}
|
|
711
893
|
}
|
|
712
894
|
close() {
|
|
713
895
|
this.#c(), this.#s.close();
|
|
714
896
|
}
|
|
715
|
-
},
|
|
897
|
+
}, U = class {
|
|
716
898
|
source;
|
|
717
899
|
broadcast;
|
|
718
900
|
track;
|
|
@@ -722,23 +904,24 @@ var O = .001, k = .2, A = class {
|
|
|
722
904
|
frame = new a(void 0);
|
|
723
905
|
buffered = new a([]);
|
|
724
906
|
#e = new a([]);
|
|
907
|
+
#t = 0;
|
|
725
908
|
signals = new i();
|
|
726
909
|
constructor(e) {
|
|
727
910
|
let { codedWidth: t, codedHeight: n, ...r } = e.config;
|
|
728
|
-
this.source = e.source, this.broadcast = e.broadcast, this.track = e.track, this.config = r, this.stats = e.stats, this.signals.run(this.#
|
|
911
|
+
this.source = e.source, this.broadcast = e.broadcast, this.track = e.track, this.config = r, this.stats = e.stats, this.signals.run(this.#n.bind(this));
|
|
729
912
|
}
|
|
730
|
-
#
|
|
913
|
+
#n(e) {
|
|
731
914
|
let t = this.broadcast.subscribe(this.track, o.PRIORITY.video);
|
|
732
915
|
e.cleanup(() => t.close());
|
|
733
916
|
let n = new VideoDecoder({
|
|
734
917
|
output: async (t) => {
|
|
735
918
|
try {
|
|
736
|
-
let n = r.Milli.fromMicro(t.timestamp);
|
|
737
|
-
if (
|
|
919
|
+
let n = this.#t, i = r.Milli.fromMicro(t.timestamp);
|
|
920
|
+
if (i < (this.timestamp.peek() ?? 0)) return;
|
|
738
921
|
this.frame.peek() === void 0 && this.frame.set(t.clone());
|
|
739
|
-
let
|
|
740
|
-
if (!await Promise.race([
|
|
741
|
-
this.timestamp.set(
|
|
922
|
+
let a = this.source.sync.wait(i).then(() => !0);
|
|
923
|
+
if (!await Promise.race([a, e.cancel]) || n !== this.#t || i < (this.timestamp.peek() ?? 0)) return;
|
|
924
|
+
this.timestamp.set(i), this.#s(i), this.frame.update((e) => (e?.close(), t.clone()));
|
|
742
925
|
} finally {
|
|
743
926
|
t.close();
|
|
744
927
|
}
|
|
@@ -749,9 +932,9 @@ var O = .001, k = .2, A = class {
|
|
|
749
932
|
});
|
|
750
933
|
e.cleanup(() => {
|
|
751
934
|
n.state !== "closed" && n.close();
|
|
752
|
-
}), this.config.container.kind === "cmaf" ? this.#
|
|
935
|
+
}), this.config.container.kind === "cmaf" ? this.#i(e, t, n) : this.#r(e, t, n);
|
|
753
936
|
}
|
|
754
|
-
#
|
|
937
|
+
#r(e, t, n) {
|
|
755
938
|
let i = this.config.container.kind === "loc" ? new c.Loc.Format() : new c.Legacy.Format(), a = new c.Consumer(t, {
|
|
756
939
|
format: i,
|
|
757
940
|
latency: this.source.sync.buffer
|
|
@@ -770,6 +953,7 @@ var O = .001, k = .2, A = class {
|
|
|
770
953
|
for (;;) {
|
|
771
954
|
let e = await a.next();
|
|
772
955
|
if (!e) break;
|
|
956
|
+
this.#a(e.discontinuity) && (o = void 0);
|
|
773
957
|
let { frame: t, group: i } = e;
|
|
774
958
|
if (!t) {
|
|
775
959
|
o && (o.final = !0);
|
|
@@ -789,7 +973,7 @@ var O = .001, k = .2, A = class {
|
|
|
789
973
|
let l = o;
|
|
790
974
|
if (l && (l.group === i || l.final && l.group + 1 === i)) {
|
|
791
975
|
let e = r.Milli.fromMicro(l.timestamp), n = r.Milli.fromMicro(t.timestamp);
|
|
792
|
-
this.#
|
|
976
|
+
this.#o(e, n);
|
|
793
977
|
}
|
|
794
978
|
o = {
|
|
795
979
|
timestamp: t.timestamp,
|
|
@@ -799,7 +983,7 @@ var O = .001, k = .2, A = class {
|
|
|
799
983
|
}
|
|
800
984
|
});
|
|
801
985
|
}
|
|
802
|
-
#
|
|
986
|
+
#i(e, t, n) {
|
|
803
987
|
if (this.config.container.kind !== "cmaf") return;
|
|
804
988
|
let i = p(this.config.container.init), a = c.Cmaf.decodeInitSegment(i), o = this.config.description ? l.Hex.toBytes(this.config.description) : a.description, s = new c.Consumer(t, {
|
|
805
989
|
format: new c.Cmaf.Format(a),
|
|
@@ -819,6 +1003,7 @@ var O = .001, k = .2, A = class {
|
|
|
819
1003
|
for (;;) {
|
|
820
1004
|
let e = await s.next();
|
|
821
1005
|
if (!e) break;
|
|
1006
|
+
this.#a(e.discontinuity) && (u = void 0);
|
|
822
1007
|
let { frame: t, group: i } = e;
|
|
823
1008
|
if (!t) {
|
|
824
1009
|
u && (u.final = !0);
|
|
@@ -832,7 +1017,7 @@ var O = .001, k = .2, A = class {
|
|
|
832
1017
|
let o = u;
|
|
833
1018
|
if (o && (o.group === i || o.final && o.group + 1 === i)) {
|
|
834
1019
|
let e = r.Milli.fromMicro(o.timestamp), n = r.Milli.fromMicro(t.timestamp);
|
|
835
|
-
this.#
|
|
1020
|
+
this.#o(e, n);
|
|
836
1021
|
}
|
|
837
1022
|
if (u = {
|
|
838
1023
|
timestamp: t.timestamp,
|
|
@@ -847,7 +1032,10 @@ var O = .001, k = .2, A = class {
|
|
|
847
1032
|
}
|
|
848
1033
|
});
|
|
849
1034
|
}
|
|
850
|
-
#
|
|
1035
|
+
#a(e) {
|
|
1036
|
+
return e === this.#t ? !1 : (this.#t = e, this.timestamp.set(void 0), this.#e.set([]), this.source.sync.reset(), !0);
|
|
1037
|
+
}
|
|
1038
|
+
#o(e, t) {
|
|
851
1039
|
e > t || this.#e.mutate((n) => {
|
|
852
1040
|
for (let i of n) if (i.start <= t && i.end >= e) {
|
|
853
1041
|
i.start = r.Milli.min(i.start, e), i.end = r.Milli.max(i.end, t);
|
|
@@ -859,7 +1047,7 @@ var O = .001, k = .2, A = class {
|
|
|
859
1047
|
}), n.sort((e, t) => e.start - t.start);
|
|
860
1048
|
});
|
|
861
1049
|
}
|
|
862
|
-
#
|
|
1050
|
+
#s(e) {
|
|
863
1051
|
this.#e.mutate((t) => {
|
|
864
1052
|
for (; t.length > 0;) {
|
|
865
1053
|
if (t[0].end >= e) {
|
|
@@ -876,7 +1064,7 @@ var O = .001, k = .2, A = class {
|
|
|
876
1064
|
});
|
|
877
1065
|
}
|
|
878
1066
|
};
|
|
879
|
-
async function
|
|
1067
|
+
async function W(e) {
|
|
880
1068
|
let t;
|
|
881
1069
|
if (e.description) t = l.Hex.toBytes(e.description);
|
|
882
1070
|
else if (e.container.kind === "cmaf") try {
|
|
@@ -902,7 +1090,7 @@ async function I(e) {
|
|
|
902
1090
|
}
|
|
903
1091
|
//#endregion
|
|
904
1092
|
//#region src/video/mse.ts
|
|
905
|
-
var
|
|
1093
|
+
var G = class {
|
|
906
1094
|
muxer;
|
|
907
1095
|
source;
|
|
908
1096
|
#e = new a(void 0);
|
|
@@ -915,7 +1103,7 @@ var L = class {
|
|
|
915
1103
|
timestamp = this.#r;
|
|
916
1104
|
signals = new i();
|
|
917
1105
|
constructor(e, t) {
|
|
918
|
-
this.muxer = e, this.source = t, this.source.supported.set(
|
|
1106
|
+
this.muxer = e, this.source = t, this.source.supported.set(K), this.signals.run(this.#i.bind(this)), this.signals.run(this.#c.bind(this)), this.signals.run(this.#l.bind(this));
|
|
919
1107
|
}
|
|
920
1108
|
#i(e) {
|
|
921
1109
|
let t = e.get(this.muxer.element);
|
|
@@ -936,7 +1124,7 @@ var L = class {
|
|
|
936
1124
|
}), e.event(c, "error", (e) => {
|
|
937
1125
|
console.error("[MSE] SourceBuffer error:", e);
|
|
938
1126
|
}), e.event(c, "updateend", () => {
|
|
939
|
-
this.#t.set(
|
|
1127
|
+
this.#t.set(N(c.buffered));
|
|
940
1128
|
}), o.container.kind === "cmaf" ? this.#o(e, i, a, o, c, t) : this.#s(e, i, a, o, c, t);
|
|
941
1129
|
}
|
|
942
1130
|
async #a(e, t) {
|
|
@@ -1023,12 +1211,12 @@ var L = class {
|
|
|
1023
1211
|
this.source.close(), this.signals.close();
|
|
1024
1212
|
}
|
|
1025
1213
|
};
|
|
1026
|
-
async function
|
|
1214
|
+
async function K(e) {
|
|
1027
1215
|
return MediaSource.isTypeSupported(`video/mp4; codecs="${e.codec}"`);
|
|
1028
1216
|
}
|
|
1029
1217
|
//#endregion
|
|
1030
1218
|
//#region src/video/renderer.ts
|
|
1031
|
-
var
|
|
1219
|
+
var q = .01, J = class {
|
|
1032
1220
|
decoder;
|
|
1033
1221
|
canvas;
|
|
1034
1222
|
paused;
|
|
@@ -1039,7 +1227,7 @@ var z = .01, B = class {
|
|
|
1039
1227
|
#t = new a(!1);
|
|
1040
1228
|
#n = new i();
|
|
1041
1229
|
constructor(e, t) {
|
|
1042
|
-
this.decoder = e, this.canvas = a.from(t?.canvas), this.paused = a.from(t?.paused ?? !1), this.visible = a.from(t?.visible ?? "
|
|
1230
|
+
this.decoder = e, this.canvas = a.from(t?.canvas), this.paused = a.from(t?.paused ?? !1), this.visible = a.from(t?.visible ?? "20%"), this.#n.run((e) => {
|
|
1043
1231
|
let t = e.get(this.canvas);
|
|
1044
1232
|
this.#e.set(t?.getContext("2d") ?? void 0);
|
|
1045
1233
|
}), this.#n.run(this.#i.bind(this)), this.#n.run(this.#a.bind(this)), this.#n.run(this.#o.bind(this)), this.#n.run(this.#r.bind(this));
|
|
@@ -1072,11 +1260,11 @@ var z = .01, B = class {
|
|
|
1072
1260
|
}, o;
|
|
1073
1261
|
try {
|
|
1074
1262
|
o = new IntersectionObserver(a, {
|
|
1075
|
-
threshold:
|
|
1263
|
+
threshold: q,
|
|
1076
1264
|
rootMargin: t
|
|
1077
1265
|
});
|
|
1078
1266
|
} catch {
|
|
1079
|
-
console.warn(`moq-watch: invalid visible margin "${t}", using "0px"`), o = new IntersectionObserver(a, { threshold:
|
|
1267
|
+
console.warn(`moq-watch: invalid visible margin "${t}", using "0px"`), o = new IntersectionObserver(a, { threshold: q });
|
|
1080
1268
|
}
|
|
1081
1269
|
i(), e.event(document, "visibilitychange", i), o.observe(n), e.cleanup(() => o.disconnect()), e.cleanup(() => this.#t.set(!1));
|
|
1082
1270
|
}
|
|
@@ -1116,7 +1304,7 @@ var z = .01, B = class {
|
|
|
1116
1304
|
};
|
|
1117
1305
|
//#endregion
|
|
1118
1306
|
//#region src/video/source.ts
|
|
1119
|
-
function
|
|
1307
|
+
function oe(e) {
|
|
1120
1308
|
return (t) => {
|
|
1121
1309
|
let n = [], r = [];
|
|
1122
1310
|
for (let [i, a] of t) if (a.codedWidth && a.codedHeight) {
|
|
@@ -1132,7 +1320,7 @@ function V(e) {
|
|
|
1132
1320
|
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);
|
|
1133
1321
|
};
|
|
1134
1322
|
}
|
|
1135
|
-
function
|
|
1323
|
+
function se(e, t) {
|
|
1136
1324
|
return (n) => {
|
|
1137
1325
|
let r = [], i = [];
|
|
1138
1326
|
for (let [a, o] of n) {
|
|
@@ -1149,7 +1337,7 @@ function H(e, t) {
|
|
|
1149
1337
|
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);
|
|
1150
1338
|
};
|
|
1151
1339
|
}
|
|
1152
|
-
function
|
|
1340
|
+
function ce(e) {
|
|
1153
1341
|
return (t) => {
|
|
1154
1342
|
let n = [], r = [];
|
|
1155
1343
|
for (let [i, a] of t) a.bitrate != null && a.bitrate <= e ? n.push({
|
|
@@ -1162,7 +1350,7 @@ function U(e) {
|
|
|
1162
1350
|
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);
|
|
1163
1351
|
};
|
|
1164
1352
|
}
|
|
1165
|
-
function
|
|
1353
|
+
function le(e) {
|
|
1166
1354
|
let t = e[0];
|
|
1167
1355
|
for (let n of e) {
|
|
1168
1356
|
let [, e] = n, [, r] = t, i = (e.codedWidth ?? 0) * (e.codedHeight ?? 0), a = (r.codedWidth ?? 0) * (r.codedHeight ?? 0);
|
|
@@ -1174,7 +1362,7 @@ function W(e) {
|
|
|
1174
1362
|
}
|
|
1175
1363
|
return t[0];
|
|
1176
1364
|
}
|
|
1177
|
-
var
|
|
1365
|
+
var Y = class {
|
|
1178
1366
|
broadcast;
|
|
1179
1367
|
target;
|
|
1180
1368
|
catalog;
|
|
@@ -1238,7 +1426,7 @@ var G = class {
|
|
|
1238
1426
|
if (n.length === 0) return;
|
|
1239
1427
|
if (n.length === 1) return n[0][0];
|
|
1240
1428
|
let r = [];
|
|
1241
|
-
if (t?.pixels != null && r.push(
|
|
1429
|
+
if (t?.pixels != null && r.push(oe(t.pixels)), (t?.width != null || t?.height != null) && r.push(se(t.width, t.height)), t?.bitrate != null && r.push(ce(t.bitrate)), r.length === 0) return le(n);
|
|
1242
1430
|
let i = r.map((e) => e(n)), a = i.map((e) => new Set(e));
|
|
1243
1431
|
for (let e of i[0]) if (a.every((t) => t.has(e))) return e;
|
|
1244
1432
|
console.warn("conflicting rendition filters, no rendition satisfies all criteria");
|
|
@@ -1246,26 +1434,12 @@ var G = class {
|
|
|
1246
1434
|
close() {
|
|
1247
1435
|
this.#r.close();
|
|
1248
1436
|
}
|
|
1249
|
-
},
|
|
1250
|
-
Decoder: () =>
|
|
1251
|
-
Mse: () =>
|
|
1252
|
-
Renderer: () =>
|
|
1253
|
-
Source: () =>
|
|
1254
|
-
})
|
|
1255
|
-
//#endregion
|
|
1256
|
-
//#region src/backend.ts
|
|
1257
|
-
function q(e) {
|
|
1258
|
-
let n = [];
|
|
1259
|
-
for (let r = 0; r < e.length; r++) {
|
|
1260
|
-
let i = t.Time.Milli.fromSecond(e.start(r)), a = t.Time.Milli.fromSecond(e.end(r));
|
|
1261
|
-
n.push({
|
|
1262
|
-
start: i,
|
|
1263
|
-
end: a
|
|
1264
|
-
});
|
|
1265
|
-
}
|
|
1266
|
-
return n;
|
|
1267
|
-
}
|
|
1268
|
-
var ce = class {
|
|
1437
|
+
}, ue = /* @__PURE__ */ f({
|
|
1438
|
+
Decoder: () => H,
|
|
1439
|
+
Mse: () => G,
|
|
1440
|
+
Renderer: () => J,
|
|
1441
|
+
Source: () => Y
|
|
1442
|
+
}), de = class {
|
|
1269
1443
|
source;
|
|
1270
1444
|
stats = new a(void 0);
|
|
1271
1445
|
stalled = new a(!1);
|
|
@@ -1274,7 +1448,7 @@ var ce = class {
|
|
|
1274
1448
|
constructor(e) {
|
|
1275
1449
|
this.source = e;
|
|
1276
1450
|
}
|
|
1277
|
-
},
|
|
1451
|
+
}, fe = class {
|
|
1278
1452
|
source;
|
|
1279
1453
|
volume = new a(.5);
|
|
1280
1454
|
muted = new a(!1);
|
|
@@ -1284,48 +1458,52 @@ var ce = class {
|
|
|
1284
1458
|
constructor(e) {
|
|
1285
1459
|
this.source = e;
|
|
1286
1460
|
}
|
|
1287
|
-
},
|
|
1461
|
+
}, pe = class {
|
|
1288
1462
|
element = new a(void 0);
|
|
1289
1463
|
broadcast;
|
|
1290
1464
|
latency;
|
|
1291
1465
|
jitter;
|
|
1466
|
+
buffered;
|
|
1292
1467
|
paused;
|
|
1293
1468
|
visible;
|
|
1294
1469
|
video;
|
|
1295
1470
|
#e;
|
|
1296
1471
|
audio;
|
|
1297
1472
|
#t;
|
|
1473
|
+
#n;
|
|
1298
1474
|
sync;
|
|
1299
1475
|
signals = new i();
|
|
1300
|
-
constructor(
|
|
1301
|
-
this.element = a.from(
|
|
1302
|
-
latency:
|
|
1303
|
-
connection:
|
|
1304
|
-
}), this.latency = this.sync.latency, this.jitter = this.sync.jitter, this.#e = new
|
|
1476
|
+
constructor(t) {
|
|
1477
|
+
this.element = a.from(t?.element), this.broadcast = a.from(t?.broadcast), this.sync = new e({
|
|
1478
|
+
latency: t?.latency,
|
|
1479
|
+
connection: t?.connection
|
|
1480
|
+
}), this.latency = this.sync.latency, this.jitter = this.sync.jitter, this.buffered = this.sync.buffered, this.#e = new Y(this.sync, { broadcast: this.broadcast }), this.#t = new F(this.sync, { broadcast: this.broadcast }), this.video = new de(this.#e), this.audio = new fe(this.#t), this.paused = a.from(t?.paused ?? !1), this.visible = a.from(t?.visible ?? "20%"), this.signals.run(this.#r.bind(this));
|
|
1305
1481
|
}
|
|
1306
|
-
#
|
|
1482
|
+
#r(e) {
|
|
1307
1483
|
let t = e.get(this.element);
|
|
1308
|
-
t && (t instanceof HTMLCanvasElement ? this.#
|
|
1484
|
+
t && (t instanceof HTMLCanvasElement ? this.#i(e, t) : t instanceof HTMLVideoElement && this.#a(e, t));
|
|
1309
1485
|
}
|
|
1310
|
-
#
|
|
1311
|
-
let n = new
|
|
1486
|
+
#i(e, t) {
|
|
1487
|
+
let n = new H(this.#e), r = new O(this.#t);
|
|
1488
|
+
this.#n = r;
|
|
1489
|
+
let i = new M(r, {
|
|
1312
1490
|
volume: this.audio.volume,
|
|
1313
1491
|
muted: this.audio.muted,
|
|
1314
1492
|
paused: this.paused
|
|
1315
|
-
}), a = new
|
|
1493
|
+
}), a = new J(n, {
|
|
1316
1494
|
canvas: t,
|
|
1317
1495
|
paused: this.paused,
|
|
1318
1496
|
visible: this.visible
|
|
1319
1497
|
});
|
|
1320
1498
|
e.cleanup(() => {
|
|
1321
|
-
n.close(), r.close(), i.close(), a.close();
|
|
1499
|
+
n.close(), r.close(), i.close(), a.close(), this.#n = void 0;
|
|
1322
1500
|
}), e.proxy(this.video.stats, n.stats), e.proxy(this.video.buffered, n.buffered), e.proxy(this.video.stalled, n.stalled), e.proxy(this.video.timestamp, n.timestamp), e.proxy(this.audio.stats, r.stats), e.proxy(this.audio.buffered, r.buffered), e.proxy(this.audio.context, r.context);
|
|
1323
1501
|
}
|
|
1324
|
-
#
|
|
1325
|
-
let n = new
|
|
1502
|
+
#a(e, t) {
|
|
1503
|
+
let n = new z(this.sync, {
|
|
1326
1504
|
paused: this.paused,
|
|
1327
1505
|
element: t
|
|
1328
|
-
}), r = new
|
|
1506
|
+
}), r = new G(n, this.#e), i = new P(n, this.#t, {
|
|
1329
1507
|
volume: this.audio.volume,
|
|
1330
1508
|
muted: this.audio.muted
|
|
1331
1509
|
});
|
|
@@ -1333,198 +1511,19 @@ var ce = class {
|
|
|
1333
1511
|
r.close(), i.close(), n.close();
|
|
1334
1512
|
}), e.proxy(this.video.stats, r.stats), e.proxy(this.video.buffered, r.buffered), e.proxy(this.video.stalled, r.stalled), e.proxy(this.video.timestamp, r.timestamp), e.proxy(this.audio.stats, i.stats), e.proxy(this.audio.buffered, i.buffered), e.proxy(this.audio.context, i.context);
|
|
1335
1513
|
}
|
|
1336
|
-
|
|
1337
|
-
this.
|
|
1338
|
-
}
|
|
1339
|
-
}, J = class {
|
|
1340
|
-
muxer;
|
|
1341
|
-
source;
|
|
1342
|
-
volume;
|
|
1343
|
-
muted;
|
|
1344
|
-
#e = new a(void 0);
|
|
1345
|
-
stats = this.#e;
|
|
1346
|
-
#t = new a([]);
|
|
1347
|
-
buffered = this.#t;
|
|
1348
|
-
context = new a(void 0);
|
|
1349
|
-
#n = new i();
|
|
1350
|
-
constructor(e, t, n) {
|
|
1351
|
-
this.muxer = e, this.source = t, this.source.supported.set(de), this.volume = a.from(n?.volume ?? .5), this.muted = a.from(n?.muted ?? !1), this.#n.run(this.#r.bind(this)), this.#n.run(this.#s.bind(this));
|
|
1352
|
-
}
|
|
1353
|
-
#r(e) {
|
|
1354
|
-
let t = e.get(this.muxer.element);
|
|
1355
|
-
if (!t) return;
|
|
1356
|
-
let n = e.get(this.muxer.mediaSource);
|
|
1357
|
-
if (!n) return;
|
|
1358
|
-
let r = e.get(this.source.broadcast);
|
|
1359
|
-
if (!r) return;
|
|
1360
|
-
let i = e.get(r.active);
|
|
1361
|
-
if (!i) return;
|
|
1362
|
-
let a = e.get(this.source.track);
|
|
1363
|
-
if (!a) return;
|
|
1364
|
-
let s = e.get(this.source.config);
|
|
1365
|
-
if (!s) return;
|
|
1366
|
-
let c = `audio/mp4; codecs="${s.codec}"`, l = n.addSourceBuffer(c);
|
|
1367
|
-
e.cleanup(() => {
|
|
1368
|
-
n.removeSourceBuffer(l), l.abort();
|
|
1369
|
-
}), e.event(l, "error", (e) => {
|
|
1370
|
-
console.error("[MSE] SourceBuffer error:", e);
|
|
1371
|
-
}), e.event(l, "updateend", () => {
|
|
1372
|
-
this.#t.set(q(l.buffered));
|
|
1373
|
-
});
|
|
1374
|
-
let u = i.subscribe(a, o.PRIORITY.audio);
|
|
1375
|
-
e.cleanup(() => u.close()), s.container.kind === "cmaf" ? this.#a(e, u, s, l, t) : this.#o(e, u, s, l, t);
|
|
1376
|
-
}
|
|
1377
|
-
async #i(e, t) {
|
|
1378
|
-
for (; e.updating;) await new Promise((t) => e.addEventListener("updateend", t, { once: !0 }));
|
|
1379
|
-
for (e.appendBuffer(t); e.updating;) await new Promise((t) => e.addEventListener("updateend", t, { once: !0 }));
|
|
1380
|
-
}
|
|
1381
|
-
#a(e, n, r, i, a) {
|
|
1382
|
-
if (r.container.kind !== "cmaf") throw Error("unreachable");
|
|
1383
|
-
let o = p(r.container.init), s = c.Cmaf.decodeInitSegment(o);
|
|
1384
|
-
e.spawn(async () => {
|
|
1385
|
-
for (await this.#i(i, o);;) {
|
|
1386
|
-
let e = await n.readFrame();
|
|
1387
|
-
if (!e) return;
|
|
1388
|
-
let r = c.Cmaf.decodeTimestamp(e, s);
|
|
1389
|
-
this.source.sync.received(t.Time.Milli.fromMicro(r), "audio"), await this.#i(i, e), a.buffered.length > 0 && a.currentTime < a.buffered.start(0) && (a.currentTime = a.buffered.start(0));
|
|
1390
|
-
}
|
|
1391
|
-
});
|
|
1392
|
-
}
|
|
1393
|
-
#o(e, n, r, i, a) {
|
|
1394
|
-
let o = r.container.kind === "loc" ? new c.Loc.Format() : new c.Legacy.Format(), s = new c.Consumer(n, {
|
|
1395
|
-
format: o,
|
|
1396
|
-
latency: this.source.sync.buffer
|
|
1397
|
-
});
|
|
1398
|
-
e.cleanup(() => s.close()), e.spawn(async () => {
|
|
1399
|
-
let e = c.Cmaf.createAudioInitSegment(r);
|
|
1400
|
-
await this.#i(i, e);
|
|
1401
|
-
let n = 1, o, l;
|
|
1402
|
-
for (;;) {
|
|
1403
|
-
let e = await s.next();
|
|
1404
|
-
if (!e) return;
|
|
1405
|
-
if (!e.frame) continue;
|
|
1406
|
-
l = e.frame;
|
|
1407
|
-
let n = t.Time.Milli.fromMicro(l.timestamp);
|
|
1408
|
-
this.source.sync.received(n, "audio");
|
|
1409
|
-
break;
|
|
1410
|
-
}
|
|
1411
|
-
for (;;) {
|
|
1412
|
-
let e = await s.next();
|
|
1413
|
-
if (e && !e.frame) continue;
|
|
1414
|
-
let r = e?.frame;
|
|
1415
|
-
if (r) {
|
|
1416
|
-
o = t.Time.Micro.sub(r.timestamp, l.timestamp);
|
|
1417
|
-
let e = t.Time.Milli.fromMicro(r.timestamp);
|
|
1418
|
-
this.source.sync.received(e, "audio");
|
|
1419
|
-
}
|
|
1420
|
-
let u = c.Cmaf.encodeDataSegment({
|
|
1421
|
-
data: l.data,
|
|
1422
|
-
timestamp: l.timestamp,
|
|
1423
|
-
duration: o ?? 0,
|
|
1424
|
-
keyframe: l.keyframe,
|
|
1425
|
-
sequence: n++
|
|
1426
|
-
});
|
|
1427
|
-
if (await this.#i(i, u), a.buffered.length > 0 && a.currentTime < a.buffered.start(0) && (a.currentTime = a.buffered.start(0)), !r) return;
|
|
1428
|
-
l = r;
|
|
1429
|
-
}
|
|
1430
|
-
});
|
|
1431
|
-
}
|
|
1432
|
-
#s(e) {
|
|
1433
|
-
let t = e.get(this.muxer.element);
|
|
1434
|
-
if (!t) return;
|
|
1435
|
-
let n = e.get(this.volume), r = e.get(this.muted);
|
|
1436
|
-
r && !t.muted ? t.muted = !0 : !r && t.muted && (t.muted = !1), n !== t.volume && (t.volume = n), e.event(t, "volumechange", () => {
|
|
1437
|
-
this.volume.set(t.volume);
|
|
1438
|
-
});
|
|
1514
|
+
reset() {
|
|
1515
|
+
this.sync.reset(), this.#n?.reset();
|
|
1439
1516
|
}
|
|
1440
1517
|
close() {
|
|
1441
|
-
this.#
|
|
1442
|
-
}
|
|
1443
|
-
};
|
|
1444
|
-
async function de(e) {
|
|
1445
|
-
return MediaSource.isTypeSupported(`audio/mp4; codecs="${e.codec}"`);
|
|
1446
|
-
}
|
|
1447
|
-
//#endregion
|
|
1448
|
-
//#region src/audio/source.ts
|
|
1449
|
-
var fe = 128, Y = class {
|
|
1450
|
-
broadcast;
|
|
1451
|
-
target;
|
|
1452
|
-
catalog;
|
|
1453
|
-
#e = new a({});
|
|
1454
|
-
available = this.#e;
|
|
1455
|
-
#t = new a(void 0);
|
|
1456
|
-
track = this.#t;
|
|
1457
|
-
#n = new a(void 0);
|
|
1458
|
-
config = this.#n;
|
|
1459
|
-
supported;
|
|
1460
|
-
sync;
|
|
1461
|
-
#r = new i();
|
|
1462
|
-
constructor(e, t) {
|
|
1463
|
-
this.sync = e, this.broadcast = a.from(t?.broadcast), this.target = a.from(t?.target), this.supported = a.from(t?.supported), this.catalog = this.#r.computed((e) => {
|
|
1464
|
-
let t = e.get(this.broadcast);
|
|
1465
|
-
return t ? e.get(t.catalog)?.audio : void 0;
|
|
1466
|
-
}), this.#r.run(this.#i.bind(this)), this.#r.run(this.#a.bind(this));
|
|
1467
|
-
}
|
|
1468
|
-
#i(e) {
|
|
1469
|
-
let t = e.get(this.catalog)?.renditions ?? {}, n = e.get(this.supported);
|
|
1470
|
-
n && e.spawn(async () => {
|
|
1471
|
-
let e = {};
|
|
1472
|
-
for (let [r, i] of Object.entries(t)) await n(i) && (e[r] = i);
|
|
1473
|
-
Object.keys(e).length === 0 && Object.keys(t).length > 0 && console.warn("no supported audio renditions found:", t), this.#e.set(e);
|
|
1474
|
-
});
|
|
1475
|
-
}
|
|
1476
|
-
#a(e) {
|
|
1477
|
-
let t = e.get(this.#e);
|
|
1478
|
-
if (Object.keys(t).length === 0) return;
|
|
1479
|
-
let n = e.get(this.target), r;
|
|
1480
|
-
if (n?.name && n.name in t) r = {
|
|
1481
|
-
track: n.name,
|
|
1482
|
-
config: t[n.name]
|
|
1483
|
-
};
|
|
1484
|
-
else if (r = this.#o(t), !r) return;
|
|
1485
|
-
e.set(this.#t, r.track), e.set(this.#n, r.config);
|
|
1486
|
-
let i = (r.config.jitter ?? pe(r.config) ?? 0) + Math.ceil(fe / r.config.sampleRate * 1e3);
|
|
1487
|
-
e.set(this.sync.audio, i);
|
|
1488
|
-
}
|
|
1489
|
-
#o(e) {
|
|
1490
|
-
let t = Object.entries(e);
|
|
1491
|
-
if (t.length !== 0) {
|
|
1492
|
-
for (let [e, n] of t) if (n.container.kind === "legacy") return {
|
|
1493
|
-
track: e,
|
|
1494
|
-
config: n
|
|
1495
|
-
};
|
|
1496
|
-
for (let [e, n] of t) if (n.container.kind === "loc") return {
|
|
1497
|
-
track: e,
|
|
1498
|
-
config: n
|
|
1499
|
-
};
|
|
1500
|
-
for (let [e, n] of t) if (n.container.kind === "cmaf") return {
|
|
1501
|
-
track: e,
|
|
1502
|
-
config: n
|
|
1503
|
-
};
|
|
1504
|
-
}
|
|
1505
|
-
}
|
|
1506
|
-
close() {
|
|
1507
|
-
this.#r.close();
|
|
1518
|
+
this.signals.close(), this.#e.close(), this.#t.close(), this.sync.close();
|
|
1508
1519
|
}
|
|
1509
|
-
};
|
|
1510
|
-
function
|
|
1511
|
-
if (e.codec.startsWith("opus")) return 20;
|
|
1512
|
-
if (e.codec.startsWith("mp4a")) return Math.ceil(1024 / e.sampleRate * 1e3);
|
|
1513
|
-
}
|
|
1514
|
-
//#endregion
|
|
1515
|
-
//#region src/audio/index.ts
|
|
1516
|
-
var me = /* @__PURE__ */ f({
|
|
1517
|
-
Decoder: () => E,
|
|
1518
|
-
Emitter: () => A,
|
|
1519
|
-
Mse: () => J,
|
|
1520
|
-
Source: () => Y
|
|
1521
|
-
}), he = 48e3, X = 2;
|
|
1522
|
-
function Z(e) {
|
|
1520
|
+
}, me = 48e3, X = 2;
|
|
1521
|
+
function he(e) {
|
|
1523
1522
|
let t = "";
|
|
1524
1523
|
for (let n = 0; n < e.length; n++) t += e[n].toString(16).padStart(2, "0");
|
|
1525
1524
|
return t;
|
|
1526
1525
|
}
|
|
1527
|
-
function
|
|
1526
|
+
function Z(e) {
|
|
1528
1527
|
let t;
|
|
1529
1528
|
try {
|
|
1530
1529
|
t = e.initData ? p(e.initData) : void 0;
|
|
@@ -1539,12 +1538,12 @@ function Q(e) {
|
|
|
1539
1538
|
description: void 0
|
|
1540
1539
|
} : {
|
|
1541
1540
|
container: { kind: "legacy" },
|
|
1542
|
-
description: t ?
|
|
1541
|
+
description: t ? he(t) : void 0
|
|
1543
1542
|
};
|
|
1544
1543
|
}
|
|
1545
1544
|
function ge(e) {
|
|
1546
1545
|
if (!e.codec) return;
|
|
1547
|
-
let { container: t, description: n } =
|
|
1546
|
+
let { container: t, description: n } = Z(e);
|
|
1548
1547
|
return {
|
|
1549
1548
|
codec: e.codec,
|
|
1550
1549
|
container: t,
|
|
@@ -1562,18 +1561,18 @@ function _e(e) {
|
|
|
1562
1561
|
if (!e.channelConfig) return X;
|
|
1563
1562
|
let t = Number.parseInt(e.channelConfig, 10);
|
|
1564
1563
|
return Number.isFinite(t) ? t : X;
|
|
1565
|
-
})(), { container: n, description: r } =
|
|
1564
|
+
})(), { container: n, description: r } = Z(e);
|
|
1566
1565
|
return {
|
|
1567
1566
|
codec: e.codec,
|
|
1568
1567
|
container: n,
|
|
1569
1568
|
description: r,
|
|
1570
|
-
sampleRate: s(e.samplerate ??
|
|
1569
|
+
sampleRate: s(e.samplerate ?? me),
|
|
1571
1570
|
numberOfChannels: s(t),
|
|
1572
1571
|
bitrate: e.bitrate == null ? void 0 : s(e.bitrate),
|
|
1573
1572
|
jitter: e.jitter == null ? void 0 : s(e.jitter)
|
|
1574
1573
|
};
|
|
1575
1574
|
}
|
|
1576
|
-
function
|
|
1575
|
+
function Q(e) {
|
|
1577
1576
|
let t = {}, n = {};
|
|
1578
1577
|
for (let r of e.tracks) if (r.role === "video") {
|
|
1579
1578
|
let e = ge(r);
|
|
@@ -1587,11 +1586,15 @@ function ve(e) {
|
|
|
1587
1586
|
}
|
|
1588
1587
|
//#endregion
|
|
1589
1588
|
//#region src/broadcast.ts
|
|
1590
|
-
var $ = [
|
|
1591
|
-
|
|
1589
|
+
var $ = [
|
|
1590
|
+
...o.FORMATS,
|
|
1591
|
+
"hangz",
|
|
1592
|
+
"manual"
|
|
1593
|
+
];
|
|
1594
|
+
function ve(e) {
|
|
1592
1595
|
if (e !== null) return $.find((t) => t === e);
|
|
1593
1596
|
}
|
|
1594
|
-
var
|
|
1597
|
+
var ye = class {
|
|
1595
1598
|
connection;
|
|
1596
1599
|
enabled;
|
|
1597
1600
|
name;
|
|
@@ -1605,15 +1608,19 @@ var be = class {
|
|
|
1605
1608
|
#n = new a(!1);
|
|
1606
1609
|
signals = new i();
|
|
1607
1610
|
constructor(e) {
|
|
1608
|
-
this.connection = a.from(e?.connection), this.name = a.from(e?.name ?? n.empty()), this.enabled = a.from(e?.enabled ?? !1), this.reload = a.from(e?.reload ?? !
|
|
1611
|
+
this.connection = a.from(e?.connection), this.name = a.from(e?.name ?? n.empty()), this.enabled = a.from(e?.enabled ?? !1), this.reload = a.from(e?.reload ?? !0), this.catalogFormat = a.from(e?.catalogFormat), this.catalog = a.from(e?.catalog), this.#t = e?.announced, this.signals.run(this.#r.bind(this)), this.signals.run(this.#i.bind(this)), this.signals.run(this.#a.bind(this));
|
|
1609
1612
|
}
|
|
1610
1613
|
#r(e) {
|
|
1611
1614
|
if (!e.get(this.reload)) {
|
|
1612
1615
|
this.#n.set(!0);
|
|
1613
1616
|
return;
|
|
1614
1617
|
}
|
|
1618
|
+
if (!this.#t) {
|
|
1619
|
+
this.#n.set(!0);
|
|
1620
|
+
return;
|
|
1621
|
+
}
|
|
1615
1622
|
if (e.get(this.connection)?.url.hostname.endsWith("mediaoverquic.com")) {
|
|
1616
|
-
|
|
1623
|
+
this.#n.set(!0);
|
|
1617
1624
|
return;
|
|
1618
1625
|
}
|
|
1619
1626
|
let t = e.get(this.name), n = e.get(this.#t);
|
|
@@ -1626,33 +1633,33 @@ var be = class {
|
|
|
1626
1633
|
let n = e.get(this.name), r = t.consume(n);
|
|
1627
1634
|
e.cleanup(() => r.close()), e.set(this.#e, r, void 0);
|
|
1628
1635
|
}
|
|
1629
|
-
#a(
|
|
1630
|
-
if (!
|
|
1631
|
-
let
|
|
1632
|
-
if (
|
|
1633
|
-
let
|
|
1634
|
-
this.status.set(
|
|
1636
|
+
#a(e) {
|
|
1637
|
+
if (!e.get(this.enabled)) return;
|
|
1638
|
+
let t = e.get(this.catalogFormat), n = e.get(this.name), r = t ?? o.detectFormat(n) ?? o.DEFAULT_FORMAT;
|
|
1639
|
+
if (r === "manual") {
|
|
1640
|
+
let t = e.get(this.catalog);
|
|
1641
|
+
this.status.set(t ? "live" : "loading");
|
|
1635
1642
|
return;
|
|
1636
1643
|
}
|
|
1637
|
-
let
|
|
1638
|
-
if (!
|
|
1644
|
+
let i = e.get(this.active);
|
|
1645
|
+
if (!i) return;
|
|
1639
1646
|
this.status.set("loading");
|
|
1640
|
-
let
|
|
1641
|
-
|
|
1642
|
-
let
|
|
1643
|
-
if (
|
|
1644
|
-
let
|
|
1645
|
-
|
|
1646
|
-
} else
|
|
1647
|
-
let e = await u.fetch(
|
|
1648
|
-
return e ?
|
|
1647
|
+
let a = r === "hang" ? o.TRACK : r === "hangz" ? o.TRACK_COMPRESSED : "catalog", s = i.subscribe(a, o.PRIORITY.catalog);
|
|
1648
|
+
e.cleanup(() => s.close());
|
|
1649
|
+
let c;
|
|
1650
|
+
if (r === "hang" || r === "hangz") {
|
|
1651
|
+
let e = new o.Consumer(s, { compression: r === "hangz" });
|
|
1652
|
+
c = () => e.next();
|
|
1653
|
+
} else c = async () => {
|
|
1654
|
+
let e = await u.fetch(s);
|
|
1655
|
+
return e ? Q(e) : void 0;
|
|
1649
1656
|
};
|
|
1650
|
-
|
|
1657
|
+
e.spawn(async () => {
|
|
1651
1658
|
try {
|
|
1652
1659
|
for (;;) {
|
|
1653
|
-
let
|
|
1654
|
-
if (!
|
|
1655
|
-
console.debug("received catalog",
|
|
1660
|
+
let t = await Promise.race([e.cancel, c()]);
|
|
1661
|
+
if (!t) break;
|
|
1662
|
+
console.debug("received catalog", r, this.name.peek(), t), this.catalog.set(t), this.status.set("live");
|
|
1656
1663
|
}
|
|
1657
1664
|
} catch (e) {
|
|
1658
1665
|
console.warn("error fetching catalog", this.name.peek(), e);
|
|
@@ -1675,6 +1682,6 @@ var be = class {
|
|
|
1675
1682
|
}
|
|
1676
1683
|
};
|
|
1677
1684
|
//#endregion
|
|
1678
|
-
export { ue as a, N as c,
|
|
1685
|
+
export { ue as a, N as c, pe as i, $ as n, R as o, ve as r, L as s, ye as t };
|
|
1679
1686
|
|
|
1680
|
-
//# sourceMappingURL=broadcast-
|
|
1687
|
+
//# sourceMappingURL=broadcast-Duw8w3D_.js.map
|