@moq/watch 0.2.17 → 0.2.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/audio/backend.d.ts +1 -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 +2 -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 +17 -18
- package/backend.d.ts.map +1 -1
- package/{broadcast-80k1hgfM.js → broadcast-oQKyLEQ1.js} +435 -436
- package/broadcast-oQKyLEQ1.js.map +1 -0
- package/broadcast.d.ts +3 -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 +59 -35
- 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 +1 -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.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 __getOwnPropNames = Object.getOwnPropertyNames;\nvar __esm = (fn, res, err) => function __init() {\n if (err) throw err[0];\n try {\n return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;\n } catch (e) {\n throw err = [e], e;\n }\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 // 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,211 @@ 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
|
+
}
|
|
728
|
+
//#endregion
|
|
729
|
+
//#region src/audio/index.ts
|
|
730
|
+
var L = /* @__PURE__ */ f({
|
|
731
|
+
Decoder: () => O,
|
|
732
|
+
Emitter: () => M,
|
|
733
|
+
Mse: () => P,
|
|
734
|
+
Source: () => F
|
|
735
|
+
}), R = /* @__PURE__ */ f({ Muxer: () => z }), z = class {
|
|
471
736
|
element;
|
|
472
737
|
paused;
|
|
473
738
|
#e;
|
|
@@ -502,11 +767,8 @@ var O = .001, k = .2, A = class {
|
|
|
502
767
|
let t = e.get(this.element);
|
|
503
768
|
if (!t) return;
|
|
504
769
|
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
|
-
}
|
|
770
|
+
n && e.interval(() => {
|
|
771
|
+
for (let e of n.sourceBuffers) e.updating || t.currentTime > 10 && e.remove(0, t.currentTime - 10);
|
|
510
772
|
}, 1e3);
|
|
511
773
|
}
|
|
512
774
|
#o(e) {
|
|
@@ -528,91 +790,7 @@ var O = .001, k = .2, A = class {
|
|
|
528
790
|
close() {
|
|
529
791
|
this.#n.close();
|
|
530
792
|
}
|
|
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 {
|
|
793
|
+
}, B = 500, V = 100, H = class {
|
|
616
794
|
enabled;
|
|
617
795
|
source;
|
|
618
796
|
#e = new a(void 0);
|
|
@@ -635,7 +813,7 @@ var O = .001, k = .2, A = class {
|
|
|
635
813
|
}), this.#n.set(void 0);
|
|
636
814
|
}
|
|
637
815
|
constructor(e, t) {
|
|
638
|
-
this.enabled = a.from(t?.enabled ?? !1), this.source = e, this.source.supported.set(
|
|
816
|
+
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
817
|
}
|
|
640
818
|
#l(e) {
|
|
641
819
|
let t = e.getAll([
|
|
@@ -653,7 +831,7 @@ var O = .001, k = .2, A = class {
|
|
|
653
831
|
this.#e.set(void 0), this.#c(), this.#o.set([]);
|
|
654
832
|
return;
|
|
655
833
|
}
|
|
656
|
-
let s = new
|
|
834
|
+
let s = new U({
|
|
657
835
|
source: this.source,
|
|
658
836
|
broadcast: o,
|
|
659
837
|
track: i,
|
|
@@ -665,7 +843,7 @@ var O = .001, k = .2, A = class {
|
|
|
665
843
|
let t = e.get(this.#e);
|
|
666
844
|
if (t) {
|
|
667
845
|
let n = e.get(s.timestamp), r = e.get(t.timestamp);
|
|
668
|
-
if (!n || r && r > n +
|
|
846
|
+
if (!n || r && r > n + V) return;
|
|
669
847
|
}
|
|
670
848
|
this.#e.set(s), s = void 0, e.close();
|
|
671
849
|
});
|
|
@@ -706,13 +884,13 @@ var O = .001, k = .2, A = class {
|
|
|
706
884
|
}
|
|
707
885
|
this.#i.set(!1), e.timer(() => {
|
|
708
886
|
this.#i.set(!0);
|
|
709
|
-
},
|
|
887
|
+
}, B);
|
|
710
888
|
}
|
|
711
889
|
}
|
|
712
890
|
close() {
|
|
713
891
|
this.#c(), this.#s.close();
|
|
714
892
|
}
|
|
715
|
-
},
|
|
893
|
+
}, U = class {
|
|
716
894
|
source;
|
|
717
895
|
broadcast;
|
|
718
896
|
track;
|
|
@@ -722,23 +900,24 @@ var O = .001, k = .2, A = class {
|
|
|
722
900
|
frame = new a(void 0);
|
|
723
901
|
buffered = new a([]);
|
|
724
902
|
#e = new a([]);
|
|
903
|
+
#t = 0;
|
|
725
904
|
signals = new i();
|
|
726
905
|
constructor(e) {
|
|
727
906
|
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.#
|
|
907
|
+
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
908
|
}
|
|
730
|
-
#
|
|
909
|
+
#n(e) {
|
|
731
910
|
let t = this.broadcast.subscribe(this.track, o.PRIORITY.video);
|
|
732
911
|
e.cleanup(() => t.close());
|
|
733
912
|
let n = new VideoDecoder({
|
|
734
913
|
output: async (t) => {
|
|
735
914
|
try {
|
|
736
|
-
let n = r.Milli.fromMicro(t.timestamp);
|
|
737
|
-
if (
|
|
915
|
+
let n = this.#t, i = r.Milli.fromMicro(t.timestamp);
|
|
916
|
+
if (i < (this.timestamp.peek() ?? 0)) return;
|
|
738
917
|
this.frame.peek() === void 0 && this.frame.set(t.clone());
|
|
739
|
-
let
|
|
740
|
-
if (!await Promise.race([
|
|
741
|
-
this.timestamp.set(
|
|
918
|
+
let a = this.source.sync.wait(i).then(() => !0);
|
|
919
|
+
if (!await Promise.race([a, e.cancel]) || n !== this.#t || i < (this.timestamp.peek() ?? 0)) return;
|
|
920
|
+
this.timestamp.set(i), this.#s(i), this.frame.update((e) => (e?.close(), t.clone()));
|
|
742
921
|
} finally {
|
|
743
922
|
t.close();
|
|
744
923
|
}
|
|
@@ -749,9 +928,9 @@ var O = .001, k = .2, A = class {
|
|
|
749
928
|
});
|
|
750
929
|
e.cleanup(() => {
|
|
751
930
|
n.state !== "closed" && n.close();
|
|
752
|
-
}), this.config.container.kind === "cmaf" ? this.#
|
|
931
|
+
}), this.config.container.kind === "cmaf" ? this.#i(e, t, n) : this.#r(e, t, n);
|
|
753
932
|
}
|
|
754
|
-
#
|
|
933
|
+
#r(e, t, n) {
|
|
755
934
|
let i = this.config.container.kind === "loc" ? new c.Loc.Format() : new c.Legacy.Format(), a = new c.Consumer(t, {
|
|
756
935
|
format: i,
|
|
757
936
|
latency: this.source.sync.buffer
|
|
@@ -770,6 +949,7 @@ var O = .001, k = .2, A = class {
|
|
|
770
949
|
for (;;) {
|
|
771
950
|
let e = await a.next();
|
|
772
951
|
if (!e) break;
|
|
952
|
+
this.#a(e.discontinuity) && (o = void 0);
|
|
773
953
|
let { frame: t, group: i } = e;
|
|
774
954
|
if (!t) {
|
|
775
955
|
o && (o.final = !0);
|
|
@@ -789,7 +969,7 @@ var O = .001, k = .2, A = class {
|
|
|
789
969
|
let l = o;
|
|
790
970
|
if (l && (l.group === i || l.final && l.group + 1 === i)) {
|
|
791
971
|
let e = r.Milli.fromMicro(l.timestamp), n = r.Milli.fromMicro(t.timestamp);
|
|
792
|
-
this.#
|
|
972
|
+
this.#o(e, n);
|
|
793
973
|
}
|
|
794
974
|
o = {
|
|
795
975
|
timestamp: t.timestamp,
|
|
@@ -799,7 +979,7 @@ var O = .001, k = .2, A = class {
|
|
|
799
979
|
}
|
|
800
980
|
});
|
|
801
981
|
}
|
|
802
|
-
#
|
|
982
|
+
#i(e, t, n) {
|
|
803
983
|
if (this.config.container.kind !== "cmaf") return;
|
|
804
984
|
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
985
|
format: new c.Cmaf.Format(a),
|
|
@@ -819,6 +999,7 @@ var O = .001, k = .2, A = class {
|
|
|
819
999
|
for (;;) {
|
|
820
1000
|
let e = await s.next();
|
|
821
1001
|
if (!e) break;
|
|
1002
|
+
this.#a(e.discontinuity) && (u = void 0);
|
|
822
1003
|
let { frame: t, group: i } = e;
|
|
823
1004
|
if (!t) {
|
|
824
1005
|
u && (u.final = !0);
|
|
@@ -832,7 +1013,7 @@ var O = .001, k = .2, A = class {
|
|
|
832
1013
|
let o = u;
|
|
833
1014
|
if (o && (o.group === i || o.final && o.group + 1 === i)) {
|
|
834
1015
|
let e = r.Milli.fromMicro(o.timestamp), n = r.Milli.fromMicro(t.timestamp);
|
|
835
|
-
this.#
|
|
1016
|
+
this.#o(e, n);
|
|
836
1017
|
}
|
|
837
1018
|
if (u = {
|
|
838
1019
|
timestamp: t.timestamp,
|
|
@@ -847,7 +1028,10 @@ var O = .001, k = .2, A = class {
|
|
|
847
1028
|
}
|
|
848
1029
|
});
|
|
849
1030
|
}
|
|
850
|
-
#
|
|
1031
|
+
#a(e) {
|
|
1032
|
+
return e === this.#t ? !1 : (this.#t = e, this.timestamp.set(void 0), this.#e.set([]), this.source.sync.reset(), !0);
|
|
1033
|
+
}
|
|
1034
|
+
#o(e, t) {
|
|
851
1035
|
e > t || this.#e.mutate((n) => {
|
|
852
1036
|
for (let i of n) if (i.start <= t && i.end >= e) {
|
|
853
1037
|
i.start = r.Milli.min(i.start, e), i.end = r.Milli.max(i.end, t);
|
|
@@ -859,7 +1043,7 @@ var O = .001, k = .2, A = class {
|
|
|
859
1043
|
}), n.sort((e, t) => e.start - t.start);
|
|
860
1044
|
});
|
|
861
1045
|
}
|
|
862
|
-
#
|
|
1046
|
+
#s(e) {
|
|
863
1047
|
this.#e.mutate((t) => {
|
|
864
1048
|
for (; t.length > 0;) {
|
|
865
1049
|
if (t[0].end >= e) {
|
|
@@ -876,7 +1060,7 @@ var O = .001, k = .2, A = class {
|
|
|
876
1060
|
});
|
|
877
1061
|
}
|
|
878
1062
|
};
|
|
879
|
-
async function
|
|
1063
|
+
async function W(e) {
|
|
880
1064
|
let t;
|
|
881
1065
|
if (e.description) t = l.Hex.toBytes(e.description);
|
|
882
1066
|
else if (e.container.kind === "cmaf") try {
|
|
@@ -902,7 +1086,7 @@ async function I(e) {
|
|
|
902
1086
|
}
|
|
903
1087
|
//#endregion
|
|
904
1088
|
//#region src/video/mse.ts
|
|
905
|
-
var
|
|
1089
|
+
var G = class {
|
|
906
1090
|
muxer;
|
|
907
1091
|
source;
|
|
908
1092
|
#e = new a(void 0);
|
|
@@ -915,7 +1099,7 @@ var L = class {
|
|
|
915
1099
|
timestamp = this.#r;
|
|
916
1100
|
signals = new i();
|
|
917
1101
|
constructor(e, t) {
|
|
918
|
-
this.muxer = e, this.source = t, this.source.supported.set(
|
|
1102
|
+
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
1103
|
}
|
|
920
1104
|
#i(e) {
|
|
921
1105
|
let t = e.get(this.muxer.element);
|
|
@@ -936,7 +1120,7 @@ var L = class {
|
|
|
936
1120
|
}), e.event(c, "error", (e) => {
|
|
937
1121
|
console.error("[MSE] SourceBuffer error:", e);
|
|
938
1122
|
}), e.event(c, "updateend", () => {
|
|
939
|
-
this.#t.set(
|
|
1123
|
+
this.#t.set(N(c.buffered));
|
|
940
1124
|
}), o.container.kind === "cmaf" ? this.#o(e, i, a, o, c, t) : this.#s(e, i, a, o, c, t);
|
|
941
1125
|
}
|
|
942
1126
|
async #a(e, t) {
|
|
@@ -1023,12 +1207,12 @@ var L = class {
|
|
|
1023
1207
|
this.source.close(), this.signals.close();
|
|
1024
1208
|
}
|
|
1025
1209
|
};
|
|
1026
|
-
async function
|
|
1210
|
+
async function K(e) {
|
|
1027
1211
|
return MediaSource.isTypeSupported(`video/mp4; codecs="${e.codec}"`);
|
|
1028
1212
|
}
|
|
1029
1213
|
//#endregion
|
|
1030
1214
|
//#region src/video/renderer.ts
|
|
1031
|
-
var
|
|
1215
|
+
var q = .01, J = class {
|
|
1032
1216
|
decoder;
|
|
1033
1217
|
canvas;
|
|
1034
1218
|
paused;
|
|
@@ -1072,11 +1256,11 @@ var z = .01, B = class {
|
|
|
1072
1256
|
}, o;
|
|
1073
1257
|
try {
|
|
1074
1258
|
o = new IntersectionObserver(a, {
|
|
1075
|
-
threshold:
|
|
1259
|
+
threshold: q,
|
|
1076
1260
|
rootMargin: t
|
|
1077
1261
|
});
|
|
1078
1262
|
} catch {
|
|
1079
|
-
console.warn(`moq-watch: invalid visible margin "${t}", using "0px"`), o = new IntersectionObserver(a, { threshold:
|
|
1263
|
+
console.warn(`moq-watch: invalid visible margin "${t}", using "0px"`), o = new IntersectionObserver(a, { threshold: q });
|
|
1080
1264
|
}
|
|
1081
1265
|
i(), e.event(document, "visibilitychange", i), o.observe(n), e.cleanup(() => o.disconnect()), e.cleanup(() => this.#t.set(!1));
|
|
1082
1266
|
}
|
|
@@ -1116,7 +1300,7 @@ var z = .01, B = class {
|
|
|
1116
1300
|
};
|
|
1117
1301
|
//#endregion
|
|
1118
1302
|
//#region src/video/source.ts
|
|
1119
|
-
function
|
|
1303
|
+
function oe(e) {
|
|
1120
1304
|
return (t) => {
|
|
1121
1305
|
let n = [], r = [];
|
|
1122
1306
|
for (let [i, a] of t) if (a.codedWidth && a.codedHeight) {
|
|
@@ -1132,7 +1316,7 @@ function V(e) {
|
|
|
1132
1316
|
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
1317
|
};
|
|
1134
1318
|
}
|
|
1135
|
-
function
|
|
1319
|
+
function se(e, t) {
|
|
1136
1320
|
return (n) => {
|
|
1137
1321
|
let r = [], i = [];
|
|
1138
1322
|
for (let [a, o] of n) {
|
|
@@ -1149,7 +1333,7 @@ function H(e, t) {
|
|
|
1149
1333
|
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
1334
|
};
|
|
1151
1335
|
}
|
|
1152
|
-
function
|
|
1336
|
+
function ce(e) {
|
|
1153
1337
|
return (t) => {
|
|
1154
1338
|
let n = [], r = [];
|
|
1155
1339
|
for (let [i, a] of t) a.bitrate != null && a.bitrate <= e ? n.push({
|
|
@@ -1162,7 +1346,7 @@ function U(e) {
|
|
|
1162
1346
|
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
1347
|
};
|
|
1164
1348
|
}
|
|
1165
|
-
function
|
|
1349
|
+
function le(e) {
|
|
1166
1350
|
let t = e[0];
|
|
1167
1351
|
for (let n of e) {
|
|
1168
1352
|
let [, e] = n, [, r] = t, i = (e.codedWidth ?? 0) * (e.codedHeight ?? 0), a = (r.codedWidth ?? 0) * (r.codedHeight ?? 0);
|
|
@@ -1174,7 +1358,7 @@ function W(e) {
|
|
|
1174
1358
|
}
|
|
1175
1359
|
return t[0];
|
|
1176
1360
|
}
|
|
1177
|
-
var
|
|
1361
|
+
var Y = class {
|
|
1178
1362
|
broadcast;
|
|
1179
1363
|
target;
|
|
1180
1364
|
catalog;
|
|
@@ -1238,7 +1422,7 @@ var G = class {
|
|
|
1238
1422
|
if (n.length === 0) return;
|
|
1239
1423
|
if (n.length === 1) return n[0][0];
|
|
1240
1424
|
let r = [];
|
|
1241
|
-
if (t?.pixels != null && r.push(
|
|
1425
|
+
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
1426
|
let i = r.map((e) => e(n)), a = i.map((e) => new Set(e));
|
|
1243
1427
|
for (let e of i[0]) if (a.every((t) => t.has(e))) return e;
|
|
1244
1428
|
console.warn("conflicting rendition filters, no rendition satisfies all criteria");
|
|
@@ -1246,26 +1430,12 @@ var G = class {
|
|
|
1246
1430
|
close() {
|
|
1247
1431
|
this.#r.close();
|
|
1248
1432
|
}
|
|
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 {
|
|
1433
|
+
}, ue = /* @__PURE__ */ f({
|
|
1434
|
+
Decoder: () => H,
|
|
1435
|
+
Mse: () => G,
|
|
1436
|
+
Renderer: () => J,
|
|
1437
|
+
Source: () => Y
|
|
1438
|
+
}), de = class {
|
|
1269
1439
|
source;
|
|
1270
1440
|
stats = new a(void 0);
|
|
1271
1441
|
stalled = new a(!1);
|
|
@@ -1274,7 +1444,7 @@ var ce = class {
|
|
|
1274
1444
|
constructor(e) {
|
|
1275
1445
|
this.source = e;
|
|
1276
1446
|
}
|
|
1277
|
-
},
|
|
1447
|
+
}, fe = class {
|
|
1278
1448
|
source;
|
|
1279
1449
|
volume = new a(.5);
|
|
1280
1450
|
muted = new a(!1);
|
|
@@ -1284,48 +1454,52 @@ var ce = class {
|
|
|
1284
1454
|
constructor(e) {
|
|
1285
1455
|
this.source = e;
|
|
1286
1456
|
}
|
|
1287
|
-
},
|
|
1457
|
+
}, pe = class {
|
|
1288
1458
|
element = new a(void 0);
|
|
1289
1459
|
broadcast;
|
|
1290
1460
|
latency;
|
|
1291
1461
|
jitter;
|
|
1462
|
+
buffered;
|
|
1292
1463
|
paused;
|
|
1293
1464
|
visible;
|
|
1294
1465
|
video;
|
|
1295
1466
|
#e;
|
|
1296
1467
|
audio;
|
|
1297
1468
|
#t;
|
|
1469
|
+
#n;
|
|
1298
1470
|
sync;
|
|
1299
1471
|
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
|
|
1472
|
+
constructor(t) {
|
|
1473
|
+
this.element = a.from(t?.element), this.broadcast = a.from(t?.broadcast), this.sync = new e({
|
|
1474
|
+
latency: t?.latency,
|
|
1475
|
+
connection: t?.connection
|
|
1476
|
+
}), 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 ?? "0px"), this.signals.run(this.#r.bind(this));
|
|
1305
1477
|
}
|
|
1306
|
-
#
|
|
1478
|
+
#r(e) {
|
|
1307
1479
|
let t = e.get(this.element);
|
|
1308
|
-
t && (t instanceof HTMLCanvasElement ? this.#
|
|
1480
|
+
t && (t instanceof HTMLCanvasElement ? this.#i(e, t) : t instanceof HTMLVideoElement && this.#a(e, t));
|
|
1309
1481
|
}
|
|
1310
|
-
#
|
|
1311
|
-
let n = new
|
|
1482
|
+
#i(e, t) {
|
|
1483
|
+
let n = new H(this.#e), r = new O(this.#t);
|
|
1484
|
+
this.#n = r;
|
|
1485
|
+
let i = new M(r, {
|
|
1312
1486
|
volume: this.audio.volume,
|
|
1313
1487
|
muted: this.audio.muted,
|
|
1314
1488
|
paused: this.paused
|
|
1315
|
-
}), a = new
|
|
1489
|
+
}), a = new J(n, {
|
|
1316
1490
|
canvas: t,
|
|
1317
1491
|
paused: this.paused,
|
|
1318
1492
|
visible: this.visible
|
|
1319
1493
|
});
|
|
1320
1494
|
e.cleanup(() => {
|
|
1321
|
-
n.close(), r.close(), i.close(), a.close();
|
|
1495
|
+
n.close(), r.close(), i.close(), a.close(), this.#n = void 0;
|
|
1322
1496
|
}), 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
1497
|
}
|
|
1324
|
-
#
|
|
1325
|
-
let n = new
|
|
1498
|
+
#a(e, t) {
|
|
1499
|
+
let n = new z(this.sync, {
|
|
1326
1500
|
paused: this.paused,
|
|
1327
1501
|
element: t
|
|
1328
|
-
}), r = new
|
|
1502
|
+
}), r = new G(n, this.#e), i = new P(n, this.#t, {
|
|
1329
1503
|
volume: this.audio.volume,
|
|
1330
1504
|
muted: this.audio.muted
|
|
1331
1505
|
});
|
|
@@ -1333,198 +1507,19 @@ var ce = class {
|
|
|
1333
1507
|
r.close(), i.close(), n.close();
|
|
1334
1508
|
}), 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
1509
|
}
|
|
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
|
-
});
|
|
1439
|
-
}
|
|
1440
|
-
close() {
|
|
1441
|
-
this.#n.close();
|
|
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
|
-
}
|
|
1510
|
+
reset() {
|
|
1511
|
+
this.sync.reset(), this.#n?.reset();
|
|
1505
1512
|
}
|
|
1506
1513
|
close() {
|
|
1507
|
-
this.#
|
|
1514
|
+
this.signals.close(), this.#e.close(), this.#t.close(), this.sync.close();
|
|
1508
1515
|
}
|
|
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) {
|
|
1516
|
+
}, me = 48e3, X = 2;
|
|
1517
|
+
function he(e) {
|
|
1523
1518
|
let t = "";
|
|
1524
1519
|
for (let n = 0; n < e.length; n++) t += e[n].toString(16).padStart(2, "0");
|
|
1525
1520
|
return t;
|
|
1526
1521
|
}
|
|
1527
|
-
function
|
|
1522
|
+
function Z(e) {
|
|
1528
1523
|
let t;
|
|
1529
1524
|
try {
|
|
1530
1525
|
t = e.initData ? p(e.initData) : void 0;
|
|
@@ -1539,12 +1534,12 @@ function Q(e) {
|
|
|
1539
1534
|
description: void 0
|
|
1540
1535
|
} : {
|
|
1541
1536
|
container: { kind: "legacy" },
|
|
1542
|
-
description: t ?
|
|
1537
|
+
description: t ? he(t) : void 0
|
|
1543
1538
|
};
|
|
1544
1539
|
}
|
|
1545
1540
|
function ge(e) {
|
|
1546
1541
|
if (!e.codec) return;
|
|
1547
|
-
let { container: t, description: n } =
|
|
1542
|
+
let { container: t, description: n } = Z(e);
|
|
1548
1543
|
return {
|
|
1549
1544
|
codec: e.codec,
|
|
1550
1545
|
container: t,
|
|
@@ -1562,18 +1557,18 @@ function _e(e) {
|
|
|
1562
1557
|
if (!e.channelConfig) return X;
|
|
1563
1558
|
let t = Number.parseInt(e.channelConfig, 10);
|
|
1564
1559
|
return Number.isFinite(t) ? t : X;
|
|
1565
|
-
})(), { container: n, description: r } =
|
|
1560
|
+
})(), { container: n, description: r } = Z(e);
|
|
1566
1561
|
return {
|
|
1567
1562
|
codec: e.codec,
|
|
1568
1563
|
container: n,
|
|
1569
1564
|
description: r,
|
|
1570
|
-
sampleRate: s(e.samplerate ??
|
|
1565
|
+
sampleRate: s(e.samplerate ?? me),
|
|
1571
1566
|
numberOfChannels: s(t),
|
|
1572
1567
|
bitrate: e.bitrate == null ? void 0 : s(e.bitrate),
|
|
1573
1568
|
jitter: e.jitter == null ? void 0 : s(e.jitter)
|
|
1574
1569
|
};
|
|
1575
1570
|
}
|
|
1576
|
-
function
|
|
1571
|
+
function Q(e) {
|
|
1577
1572
|
let t = {}, n = {};
|
|
1578
1573
|
for (let r of e.tracks) if (r.role === "video") {
|
|
1579
1574
|
let e = ge(r);
|
|
@@ -1587,11 +1582,15 @@ function ve(e) {
|
|
|
1587
1582
|
}
|
|
1588
1583
|
//#endregion
|
|
1589
1584
|
//#region src/broadcast.ts
|
|
1590
|
-
var $ = [
|
|
1591
|
-
|
|
1585
|
+
var $ = [
|
|
1586
|
+
...o.FORMATS,
|
|
1587
|
+
"hangz",
|
|
1588
|
+
"manual"
|
|
1589
|
+
];
|
|
1590
|
+
function ve(e) {
|
|
1592
1591
|
if (e !== null) return $.find((t) => t === e);
|
|
1593
1592
|
}
|
|
1594
|
-
var
|
|
1593
|
+
var ye = class {
|
|
1595
1594
|
connection;
|
|
1596
1595
|
enabled;
|
|
1597
1596
|
name;
|
|
@@ -1626,33 +1625,33 @@ var be = class {
|
|
|
1626
1625
|
let n = e.get(this.name), r = t.consume(n);
|
|
1627
1626
|
e.cleanup(() => r.close()), e.set(this.#e, r, void 0);
|
|
1628
1627
|
}
|
|
1629
|
-
#a(
|
|
1630
|
-
if (!
|
|
1631
|
-
let
|
|
1632
|
-
if (
|
|
1633
|
-
let
|
|
1634
|
-
this.status.set(
|
|
1628
|
+
#a(e) {
|
|
1629
|
+
if (!e.get(this.enabled)) return;
|
|
1630
|
+
let t = e.get(this.catalogFormat), n = e.get(this.name), r = t ?? o.detectFormat(n) ?? o.DEFAULT_FORMAT;
|
|
1631
|
+
if (r === "manual") {
|
|
1632
|
+
let t = e.get(this.catalog);
|
|
1633
|
+
this.status.set(t ? "live" : "loading");
|
|
1635
1634
|
return;
|
|
1636
1635
|
}
|
|
1637
|
-
let
|
|
1638
|
-
if (!
|
|
1636
|
+
let i = e.get(this.active);
|
|
1637
|
+
if (!i) return;
|
|
1639
1638
|
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 ?
|
|
1639
|
+
let a = r === "hang" ? o.TRACK : r === "hangz" ? o.TRACK_COMPRESSED : "catalog", s = i.subscribe(a, o.PRIORITY.catalog);
|
|
1640
|
+
e.cleanup(() => s.close());
|
|
1641
|
+
let c;
|
|
1642
|
+
if (r === "hang" || r === "hangz") {
|
|
1643
|
+
let e = new o.Consumer(s, { compression: r === "hangz" });
|
|
1644
|
+
c = () => e.next();
|
|
1645
|
+
} else c = async () => {
|
|
1646
|
+
let e = await u.fetch(s);
|
|
1647
|
+
return e ? Q(e) : void 0;
|
|
1649
1648
|
};
|
|
1650
|
-
|
|
1649
|
+
e.spawn(async () => {
|
|
1651
1650
|
try {
|
|
1652
1651
|
for (;;) {
|
|
1653
|
-
let
|
|
1654
|
-
if (!
|
|
1655
|
-
console.debug("received catalog",
|
|
1652
|
+
let t = await Promise.race([e.cancel, c()]);
|
|
1653
|
+
if (!t) break;
|
|
1654
|
+
console.debug("received catalog", r, this.name.peek(), t), this.catalog.set(t), this.status.set("live");
|
|
1656
1655
|
}
|
|
1657
1656
|
} catch (e) {
|
|
1658
1657
|
console.warn("error fetching catalog", this.name.peek(), e);
|
|
@@ -1675,6 +1674,6 @@ var be = class {
|
|
|
1675
1674
|
}
|
|
1676
1675
|
};
|
|
1677
1676
|
//#endregion
|
|
1678
|
-
export { ue as a, N as c,
|
|
1677
|
+
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
1678
|
|
|
1680
|
-
//# sourceMappingURL=broadcast-
|
|
1679
|
+
//# sourceMappingURL=broadcast-oQKyLEQ1.js.map
|