@ikonai/sdk 1.7.0 → 1.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/app-messaging.d.ts +11 -1
  2. package/assets/audio-playback-worker-D9_GcJw4.js +1 -0
  3. package/assets/protocol-worker-DA6wieqV.js +3 -0
  4. package/assets/video-capture-worker-DLndrZf8.js +1 -0
  5. package/assets/video-playback-worker-DAAVfeBm.js +1 -0
  6. package/assets/viseme-worker-Bfd95xP6.js +1 -0
  7. package/capabilities-lcsAlVUh.js +1146 -0
  8. package/channel/channel-manager.d.ts +1 -0
  9. package/client/ikon-client-config.d.ts +3 -0
  10. package/client/ikon-client.d.ts +37 -28
  11. package/functions/download-functions.d.ts +8 -0
  12. package/functions/index.d.ts +1 -0
  13. package/index.d.ts +5 -4
  14. package/index.js +5179 -2534
  15. package/media/ikon-audio-capture.d.ts +22 -0
  16. package/media/ikon-audio-playback.d.ts +1 -0
  17. package/media/ikon-video-capture.d.ts +8 -0
  18. package/media/index.d.ts +2 -0
  19. package/media/media-permission.d.ts +47 -0
  20. package/package.json +5 -2
  21. package/storage.d.ts +1 -1
  22. package/transport/http-stream-transport.d.ts +2 -1
  23. package/transport/keepalive-watchdog.d.ts +28 -0
  24. package/transport/transport.d.ts +7 -0
  25. package/transport/web-socket-transport.d.ts +2 -1
  26. package/transport/web-transport-transport.d.ts +2 -4
  27. package/utils/boot-signal.d.ts +14 -0
  28. package/utils/browser-compat.d.ts +17 -0
  29. package/utils/browser-support.d.ts +15 -10
  30. package/utils/client-identity.d.ts +13 -0
  31. package/utils/parent-log-forward.d.ts +22 -0
  32. package/utils/query-params.d.ts +18 -0
  33. package/webrtc/webrtc-signaling.d.ts +7 -0
  34. package/assets/audio-playback-worker-BXZR_9iK.js +0 -1
  35. package/assets/protocol-worker-CW7oSQmQ.js +0 -3
  36. package/assets/video-capture-worker-mvwKyjOn.js +0 -1
  37. package/assets/video-playback-worker-DqNjooZJ.js +0 -1
  38. package/assets/viseme-worker-D0AKWUTO.js +0 -1
  39. package/capabilities-xDnE0vqq.js +0 -105
  40. package/ikon-media-CdIF9gbL.js +0 -3154
@@ -1,3154 +0,0 @@
1
- import { a as e, f as t, i as n, l as r, n as i, o as a, r as o, t as s, u as c, v as l } from "./capabilities-xDnE0vqq.js";
2
- //#region \0rolldown/runtime.js
3
- var u = Object.defineProperty, d = (e, t) => {
4
- let n = {};
5
- for (var r in e) u(n, r, {
6
- get: e[r],
7
- enumerable: !0
8
- });
9
- return t || u(n, Symbol.toStringTag, { value: "Module" }), n;
10
- }, f = {
11
- None: 0,
12
- SendBackToSender: 1,
13
- Delayable: 2,
14
- SendToUser: 4,
15
- Compressed: 8,
16
- Unreliable: 16
17
- };
18
- function p(e) {
19
- return e;
20
- }
21
- function m(e) {
22
- if (e.length < 8) throw Error("Protocol message too short");
23
- return (e[4] | e[5] << 8 | e[6] << 16 | e[7] << 24) >>> 0;
24
- }
25
- function h(e) {
26
- return m(e) & 4294901760;
27
- }
28
- function g(e) {
29
- let t = R(e), n = new DataView(t.buffer, t.byteOffset, t.byteLength);
30
- if (t.length < 27) throw Error("Protocol payload too short");
31
- let r = n.getUint32(0, !0), i = n.getUint32(4, !0), a = n.getUint32(8, !0), o = n.getUint32(12, !0), s = n.getUint32(16, !0), c = n.getUint32(20, !0), l = n.getUint8(24), u = n.getUint8(25), d = n.getUint8(26);
32
- if (27 + c * 4 > t.length) throw Error("Protocol header exceeds payload length");
33
- let f = [], p = 27;
34
- for (let e = 0; e < c; e++) f.push(n.getUint32(p, !0)), p += 4;
35
- return {
36
- length: r,
37
- opcode: i,
38
- senderId: a,
39
- trackId: o,
40
- sequenceId: s,
41
- targetIds: f,
42
- payloadVersion: l,
43
- payloadType: u,
44
- flags: d
45
- };
46
- }
47
- function ee(e, t, n) {
48
- let r = R(e), i = g(r);
49
- if (t !== void 0 && i.opcode !== t) throw Error(`Unexpected opcode ${i.opcode}`);
50
- if (i.payloadType !== 8) throw Error(`Unexpected payload type ${i.payloadType}`);
51
- let a = 27 + i.targetIds.length * 4;
52
- return r.subarray(a, i.length);
53
- }
54
- async function te(e, t, n) {
55
- let r = R(e), i = g(r);
56
- if (t !== void 0 && i.opcode !== t) throw Error(`Unexpected opcode ${i.opcode}`);
57
- if (i.payloadType !== 8) throw Error(`Unexpected payload type ${i.payloadType}`);
58
- let a = 27 + i.targetIds.length * 4, o = r.subarray(a, i.length);
59
- return (i.flags & f.Compressed) !== 0 && (o = await ne(o)), o;
60
- }
61
- function _(e, t, n, r, i) {
62
- let a = i?.trackId ?? 0, o = i?.sequenceId ?? 0, s = i?.flags ?? 0, c = i?.targetIds ?? [], l = i?.payloadType ?? 8, u = 27 + c.length * 4, d = u + t.length, f = new Uint8Array(d), m = new DataView(f.buffer);
63
- m.setUint32(0, d, !0), m.setUint32(4, e >>> 0, !0), m.setUint32(8, r >>> 0, !0), m.setUint32(12, a >>> 0, !0), m.setUint32(16, o >>> 0, !0), m.setUint32(20, c.length >>> 0, !0), m.setUint8(24, n & 255), m.setUint8(25, l & 255), m.setUint8(26, s & 255);
64
- let h = 27;
65
- for (let e = 0; e < c.length; e++) m.setUint32(h, c[e] >>> 0, !0), h += 4;
66
- return f.set(t, u), p(f);
67
- }
68
- async function ne(e) {
69
- if (typeof DecompressionStream > "u") throw Error("DecompressionStream not supported");
70
- let t = new DecompressionStream("gzip"), n = t.writable.getWriter(), r = new Uint8Array(e);
71
- n.write(r).then(() => n.close()).catch(() => void 0);
72
- let i = t.readable.getReader(), a = [], o = 0;
73
- for (;;) {
74
- let { done: e, value: t } = await i.read();
75
- if (e) break;
76
- a.push(t), o += t.length;
77
- }
78
- let s = new Uint8Array(o), c = 0;
79
- for (let e = 0; e < a.length; e++) s.set(a[e], c), c += a[e].length;
80
- return s;
81
- }
82
- var v = /* @__PURE__ */ function(e) {
83
- return e[e.Null = 1] = "Null", e[e.Bool = 2] = "Bool", e[e.Int32 = 3] = "Int32", e[e.Int64 = 4] = "Int64", e[e.UInt32 = 5] = "UInt32", e[e.UInt64 = 6] = "UInt64", e[e.Float32 = 7] = "Float32", e[e.Float64 = 8] = "Float64", e[e.Array = 9] = "Array", e[e.Dict = 10] = "Dict", e[e.Object = 11] = "Object", e[e.String = 12] = "String", e[e.Binary = 13] = "Binary", e[e.Guid = 14] = "Guid", e;
84
- }({}), y = 161, b = 162, x = new TextEncoder(), re = new TextDecoder("utf-8", { fatal: !0 }), S = class e {
85
- buffer = new O();
86
- cached;
87
- constructor(e = 1) {
88
- this.buffer.writeByte(y), this.buffer.writeVarUInt(e >>> 0);
89
- }
90
- writeInt32Field(e, t) {
91
- this.writeFixedField(e, 3, () => this.buffer.writeInt32(t | 0));
92
- }
93
- writeUInt32Field(e, t) {
94
- this.writeFixedField(e, 5, () => this.buffer.writeUInt32(t >>> 0));
95
- }
96
- writeInt64Field(e, t) {
97
- this.writeFixedField(e, 4, () => this.buffer.writeBigInt64(t));
98
- }
99
- writeUInt64Field(e, t) {
100
- this.writeFixedField(e, 6, () => this.buffer.writeBigUInt64(t));
101
- }
102
- writeFloat32Field(e, t) {
103
- this.writeFixedField(e, 7, () => this.buffer.writeFloat32(t));
104
- }
105
- writeFloat64Field(e, t) {
106
- this.writeFixedField(e, 8, () => this.buffer.writeFloat64(t));
107
- }
108
- writeBoolField(e, t) {
109
- this.writeFixedField(e, 2, () => this.buffer.writeByte(+!!t));
110
- }
111
- writeGuidField(e, t) {
112
- let n = t instanceof D ? t.asBytes() : t;
113
- if (n.length !== 16) throw Error("Guid payload must be 16 bytes");
114
- this.writeFixedField(e, 14, () => this.buffer.writeBytes(n));
115
- }
116
- writeStringField(e, t) {
117
- let n = x.encode(t ?? "");
118
- this.writeVariableField(e, 12, n);
119
- }
120
- writeBinaryField(e, t) {
121
- this.writeVariableField(e, 13, t);
122
- }
123
- writeObjectField(t, n, r) {
124
- let i = new e(n);
125
- r(i);
126
- let a = i.finish();
127
- this.writeVariableField(t, 11, a);
128
- }
129
- writeArrayField(e, t, n) {
130
- let r = new ie(t);
131
- n(r);
132
- let i = r.finish();
133
- this.writeVariableField(e, 9, i);
134
- }
135
- writeDictionaryField(e, t, n, r) {
136
- let i = new C(t, n);
137
- r(i);
138
- let a = i.finish();
139
- this.writeVariableField(e, 10, a);
140
- }
141
- finish() {
142
- return this.cached ||= (this.buffer.writeByte(b), this.buffer.toUint8Array()), this.cached;
143
- }
144
- writeFixedField(e, t, n) {
145
- this.writeFieldHeader(e, t, 0), n();
146
- }
147
- writeVariableField(e, t, n) {
148
- this.writeFieldHeader(e, t, n.length), this.buffer.writeBytes(n);
149
- }
150
- writeFieldHeader(e, t, n) {
151
- this.buffer.writeUInt32(e >>> 0), this.buffer.writeByte(A(t)), de(t) && this.buffer.writeVarUInt(n >>> 0);
152
- }
153
- }, ie = class e {
154
- elementType;
155
- payload = new O();
156
- count = 0;
157
- constructor(e) {
158
- this.elementType = e;
159
- }
160
- writeInt32(e) {
161
- this.ensureElementType(3), this.count++, this.payload.writeInt32(e | 0);
162
- }
163
- writeUInt32(e) {
164
- this.ensureElementType(5), this.count++, this.payload.writeUInt32(e >>> 0);
165
- }
166
- writeInt64(e) {
167
- this.ensureElementType(4), this.count++, this.payload.writeBigInt64(e);
168
- }
169
- writeUInt64(e) {
170
- this.ensureElementType(6), this.count++, this.payload.writeBigUInt64(e);
171
- }
172
- writeFloat32(e) {
173
- this.ensureElementType(7), this.count++, this.payload.writeFloat32(e);
174
- }
175
- writeFloat64(e) {
176
- this.ensureElementType(8), this.count++, this.payload.writeFloat64(e);
177
- }
178
- writeBool(e) {
179
- this.ensureElementType(2), this.count++, this.payload.writeByte(+!!e);
180
- }
181
- writeGuid(e) {
182
- this.ensureElementType(14), this.count++;
183
- let t = e instanceof D ? e.asBytes() : e;
184
- if (t.length !== 16) throw Error("Guid payload must be 16 bytes");
185
- this.payload.writeBytes(t);
186
- }
187
- writeString(e) {
188
- this.ensureElementType(12), this.count++;
189
- let t = x.encode(e ?? "");
190
- this.payload.writeVarUInt(t.length), this.payload.writeBytes(t);
191
- }
192
- writeBinary(e) {
193
- this.ensureElementType(13), this.count++, this.payload.writeVarUInt(e.length), this.payload.writeBytes(e);
194
- }
195
- writeObject(e, t) {
196
- this.ensureElementType(11), this.count++;
197
- let n = new S(e);
198
- t(n);
199
- let r = n.finish();
200
- this.payload.writeVarUInt(r.length), this.payload.writeBytes(r);
201
- }
202
- writeArray(t, n) {
203
- this.ensureElementType(9), this.count++;
204
- let r = new e(t);
205
- n(r);
206
- let i = r.finish();
207
- this.payload.writeBytes(i);
208
- }
209
- writeDictionary(e, t, n) {
210
- this.ensureElementType(10), this.count++;
211
- let r = new C(e, t);
212
- n(r);
213
- let i = r.finish();
214
- this.payload.writeBytes(i);
215
- }
216
- finish() {
217
- let e = new O();
218
- return e.writeByte(A(this.elementType)), e.writeVarUInt(this.count), e.writeBytes(this.payload.toUint8Array()), e.toUint8Array();
219
- }
220
- ensureElementType(e) {
221
- if (this.elementType !== e) throw Error(`Array element type is ${v[this.elementType]}, expected ${v[e]}`);
222
- }
223
- }, C = class {
224
- keyType;
225
- valueType;
226
- payload = new O();
227
- count = 0;
228
- entryOpen = !1;
229
- constructor(e, t) {
230
- this.keyType = e, this.valueType = t, M(e);
231
- }
232
- beginEntry() {
233
- if (this.entryOpen) throw Error("Previous dictionary entry not completed");
234
- return this.count++, this.entryOpen = !0, new ae(this.keyType, this.valueType, this.payload, () => {
235
- this.entryOpen = !1;
236
- });
237
- }
238
- finish() {
239
- if (this.entryOpen) throw Error("Dictionary entry not completed");
240
- let e = new O();
241
- return e.writeByte(A(this.keyType)), e.writeByte(A(this.valueType)), e.writeVarUInt(this.count), e.writeBytes(this.payload.toUint8Array()), e.toUint8Array();
242
- }
243
- }, ae = class {
244
- keyType;
245
- valueType;
246
- payload;
247
- onComplete;
248
- keyWritten = !1;
249
- valueWritten = !1;
250
- completed = !1;
251
- constructor(e, t, n, r) {
252
- this.keyType = e, this.valueType = t, this.payload = n, this.onComplete = r;
253
- }
254
- writeKeyInt32(e) {
255
- this.ensureKeyType(3), this.payload.writeInt32(e | 0), this.keyWritten = !0;
256
- }
257
- writeKeyUInt32(e) {
258
- this.ensureKeyType(5), this.payload.writeUInt32(e >>> 0), this.keyWritten = !0;
259
- }
260
- writeKeyInt64(e) {
261
- this.ensureKeyType(4), this.payload.writeBigInt64(e), this.keyWritten = !0;
262
- }
263
- writeKeyUInt64(e) {
264
- this.ensureKeyType(6), this.payload.writeBigUInt64(e), this.keyWritten = !0;
265
- }
266
- writeKeyFloat32(e) {
267
- this.ensureKeyType(7), this.payload.writeFloat32(e), this.keyWritten = !0;
268
- }
269
- writeKeyFloat64(e) {
270
- this.ensureKeyType(8), this.payload.writeFloat64(e), this.keyWritten = !0;
271
- }
272
- writeKeyBool(e) {
273
- this.ensureKeyType(2), this.payload.writeByte(+!!e), this.keyWritten = !0;
274
- }
275
- writeKeyGuid(e) {
276
- this.ensureKeyType(14);
277
- let t = e instanceof D ? e.asBytes() : e;
278
- if (t.length !== 16) throw Error("Guid payload must be 16 bytes");
279
- this.payload.writeBytes(t), this.keyWritten = !0;
280
- }
281
- writeKeyString(e) {
282
- this.ensureKeyType(12);
283
- let t = x.encode(e ?? "");
284
- this.payload.writeVarUInt(t.length), this.payload.writeBytes(t), this.keyWritten = !0;
285
- }
286
- writeKeyBinary(e) {
287
- this.ensureKeyType(13), this.payload.writeVarUInt(e.length), this.payload.writeBytes(e), this.keyWritten = !0;
288
- }
289
- writeValueInt32(e) {
290
- this.ensureValueType(3), this.payload.writeInt32(e | 0), this.valueWritten = !0;
291
- }
292
- writeValueUInt32(e) {
293
- this.ensureValueType(5), this.payload.writeUInt32(e >>> 0), this.valueWritten = !0;
294
- }
295
- writeValueInt64(e) {
296
- this.ensureValueType(4), this.payload.writeBigInt64(e), this.valueWritten = !0;
297
- }
298
- writeValueUInt64(e) {
299
- this.ensureValueType(6), this.payload.writeBigUInt64(e), this.valueWritten = !0;
300
- }
301
- writeValueFloat32(e) {
302
- this.ensureValueType(7), this.payload.writeFloat32(e), this.valueWritten = !0;
303
- }
304
- writeValueFloat64(e) {
305
- this.ensureValueType(8), this.payload.writeFloat64(e), this.valueWritten = !0;
306
- }
307
- writeValueBool(e) {
308
- this.ensureValueType(2), this.payload.writeByte(+!!e), this.valueWritten = !0;
309
- }
310
- writeValueGuid(e) {
311
- this.ensureValueType(14);
312
- let t = e instanceof D ? e.asBytes() : e;
313
- if (t.length !== 16) throw Error("Guid payload must be 16 bytes");
314
- this.payload.writeBytes(t), this.valueWritten = !0;
315
- }
316
- writeNullValue() {
317
- this.ensureValueType(1), this.valueWritten = !0;
318
- }
319
- writeValueBinary(e) {
320
- this.ensureValueType(13), this.payload.writeVarUInt(e.length), this.payload.writeBytes(e), this.valueWritten = !0;
321
- }
322
- writeValueString(e) {
323
- this.ensureValueType(12);
324
- let t = x.encode(e ?? "");
325
- this.payload.writeVarUInt(t.length), this.payload.writeBytes(t), this.valueWritten = !0;
326
- }
327
- writeValueObject(e, t) {
328
- this.ensureValueType(11);
329
- let n = new S(e);
330
- t(n);
331
- let r = n.finish();
332
- this.payload.writeVarUInt(r.length), this.payload.writeBytes(r), this.valueWritten = !0;
333
- }
334
- writeValueArray(e, t) {
335
- this.ensureValueType(9);
336
- let n = new ie(e);
337
- t(n);
338
- let r = n.finish();
339
- this.payload.writeBytes(r), this.valueWritten = !0;
340
- }
341
- writeValueDictionary(e, t, n) {
342
- this.ensureValueType(10);
343
- let r = new C(e, t);
344
- n(r);
345
- let i = r.finish();
346
- this.payload.writeBytes(i), this.valueWritten = !0;
347
- }
348
- complete() {
349
- if (!this.completed) {
350
- if (!this.keyWritten || !this.valueWritten) throw Error("Dictionary entry must write both key and value");
351
- this.completed = !0, this.onComplete();
352
- }
353
- }
354
- ensureKeyType(e) {
355
- if (this.keyType !== e) throw Error(`Dictionary key type is ${v[this.keyType]}, expected ${v[e]}`);
356
- }
357
- ensureValueType(e) {
358
- if (this.valueType !== e) throw Error(`Dictionary value type is ${v[this.valueType]}, expected ${v[e]}`);
359
- }
360
- }, w = class e {
361
- buffer;
362
- version;
363
- offset;
364
- end;
365
- constructor(e, t, n) {
366
- this.buffer = e, this.version = t, this.offset = n, this.end = e.length - 1;
367
- }
368
- static create(t) {
369
- let n = R(t);
370
- if (n.length < 2) throw Error("Teleport payload too short");
371
- if (n[0] !== y || n[n.length - 1] !== b) throw Error("Teleport object missing markers");
372
- let r = { offset: 1 }, i = k(n, r, "InvalidLength");
373
- return new e(n, i, r.offset);
374
- }
375
- next() {
376
- if (this.offset >= this.end) return null;
377
- if (this.offset + 5 > this.buffer.length) throw Error("Teleport object truncated");
378
- let e = fe(this.buffer, this.offset);
379
- this.offset += 4;
380
- let t = this.buffer[this.offset++], n = t >> 4 & 15;
381
- if (t & 15) throw Error("Teleport field flags must be zero");
382
- let r = j(n), i;
383
- if (r >= 0) N(this.buffer, this.offset, r), i = this.buffer.subarray(this.offset, this.offset + r), this.offset += r;
384
- else {
385
- let e = { offset: this.offset }, t = k(this.buffer, e, "InvalidLength");
386
- N(this.buffer, e.offset, t), i = this.buffer.subarray(e.offset, e.offset + t), this.offset = e.offset + t;
387
- }
388
- return new oe(e, n, i);
389
- }
390
- }, T = class {
391
- type;
392
- payload;
393
- constructor(e, t) {
394
- this.type = e, this.payload = t;
395
- }
396
- asInt32() {
397
- return this.ensureType(3), new DataView(this.payload.buffer, this.payload.byteOffset, 4).getInt32(0, !0);
398
- }
399
- asUInt32() {
400
- return this.ensureType(5), new DataView(this.payload.buffer, this.payload.byteOffset, 4).getUint32(0, !0);
401
- }
402
- asInt64() {
403
- return this.ensureType(4), new DataView(this.payload.buffer, this.payload.byteOffset, 8).getBigInt64(0, !0);
404
- }
405
- asUInt64() {
406
- return this.ensureType(6), new DataView(this.payload.buffer, this.payload.byteOffset, 8).getBigUint64(0, !0);
407
- }
408
- asFloat32() {
409
- return this.ensureType(7), new DataView(this.payload.buffer, this.payload.byteOffset, 4).getFloat32(0, !0);
410
- }
411
- asFloat64() {
412
- return this.ensureType(8), new DataView(this.payload.buffer, this.payload.byteOffset, 8).getFloat64(0, !0);
413
- }
414
- asBool() {
415
- return this.ensureType(2), this.payload.length > 0 && this.payload[0] !== 0;
416
- }
417
- asBinary() {
418
- return this.ensureType(13), this.payload;
419
- }
420
- asUtf8() {
421
- return this.ensureType(12), this.payload;
422
- }
423
- asString() {
424
- return this.ensureType(12), re.decode(this.payload);
425
- }
426
- asGuid() {
427
- return this.ensureType(14), D.fromBytes(this.payload);
428
- }
429
- asObject() {
430
- return this.ensureType(11), w.create(this.payload);
431
- }
432
- asArray() {
433
- return this.ensureType(9), se.create(this.payload);
434
- }
435
- asDictionary() {
436
- return this.ensureType(10), ce.create(this.payload);
437
- }
438
- ensureType(e) {
439
- if (this.type !== e) throw Error(`Teleport value has type ${v[this.type]}, expected ${v[e]}`);
440
- }
441
- }, oe = class extends T {
442
- fieldId;
443
- constructor(e, t, n) {
444
- super(t, n), this.fieldId = e;
445
- }
446
- get isNull() {
447
- return this.type === 1;
448
- }
449
- }, se = class e {
450
- payload;
451
- elementType;
452
- count;
453
- offset;
454
- index = 0;
455
- constructor(e) {
456
- if (this.payload = e, e.length === 0) throw Error("Array payload too short");
457
- let t = e[0];
458
- if (this.elementType = t >> 4 & 15, t & 15) throw Error("Array flags must be zero");
459
- let n = { offset: 1 };
460
- this.count = k(e, n, "ArrayMalformed"), this.offset = n.offset;
461
- }
462
- static create(t) {
463
- return new e(R(t));
464
- }
465
- next() {
466
- if (this.index >= this.count) {
467
- if (this.offset !== this.payload.length) throw Error("Array payload contains trailing data");
468
- return null;
469
- }
470
- let e = this.readValue();
471
- return this.index++, e;
472
- }
473
- readValue() {
474
- switch (this.elementType) {
475
- case 3:
476
- case 5:
477
- case 7:
478
- case 8:
479
- case 2:
480
- case 4:
481
- case 6:
482
- case 14: {
483
- let e = j(this.elementType);
484
- N(this.payload, this.offset, e);
485
- let t = this.payload.subarray(this.offset, this.offset + e);
486
- return this.offset += e, new E(this.elementType, t);
487
- }
488
- case 12:
489
- case 13: {
490
- let e = { offset: this.offset }, t = k(this.payload, e, "ArrayMalformed");
491
- N(this.payload, e.offset, t);
492
- let n = this.payload.subarray(e.offset, e.offset + t);
493
- return this.offset = e.offset + t, new E(this.elementType, n);
494
- }
495
- case 11: {
496
- let e = { offset: this.offset }, t = k(this.payload, e, "ArrayMalformed");
497
- N(this.payload, e.offset, t);
498
- let n = this.payload.subarray(e.offset, e.offset + t);
499
- return this.offset = e.offset + t, new E(11, n);
500
- }
501
- case 9: {
502
- let e = P(this.payload, this.offset), t = this.payload.subarray(this.offset, this.offset + e);
503
- return this.offset += e, new E(9, t);
504
- }
505
- case 10: {
506
- let e = F(this.payload, this.offset), t = this.payload.subarray(this.offset, this.offset + e);
507
- return this.offset += e, new E(10, t);
508
- }
509
- default: throw Error(`Unsupported array element type ${v[this.elementType]}`);
510
- }
511
- }
512
- }, E = class extends T {
513
- constructor(e, t) {
514
- super(e, t);
515
- }
516
- }, ce = class e {
517
- payload;
518
- keyType;
519
- valueType;
520
- count;
521
- offset;
522
- index = 0;
523
- constructor(e) {
524
- if (this.payload = e, e.length < 2) throw Error("Dictionary payload too short");
525
- if (this.keyType = e[0] >> 4 & 15, this.valueType = e[1] >> 4 & 15, e[0] & 15 || e[1] & 15) throw Error("Dictionary key/value flags must be zero");
526
- M(this.keyType);
527
- let t = { offset: 2 };
528
- this.count = k(e, t, "DictMalformed"), this.offset = t.offset;
529
- }
530
- static create(t) {
531
- return new e(R(t));
532
- }
533
- next() {
534
- if (this.index >= this.count) {
535
- if (this.offset !== this.payload.length) throw Error("Dictionary payload contains trailing data");
536
- return null;
537
- }
538
- let e = this.readKey(), t = this.readValue();
539
- return this.index++, new le(e, t);
540
- }
541
- readKey() {
542
- let e = j(this.keyType);
543
- if (e >= 0) {
544
- N(this.payload, this.offset, e);
545
- let t = this.payload.subarray(this.offset, this.offset + e);
546
- return this.offset += e, new T(this.keyType, t);
547
- }
548
- if (this.keyType === 12 || this.keyType === 13) {
549
- let e = { offset: this.offset }, t = k(this.payload, e, "DictMalformed");
550
- N(this.payload, e.offset, t);
551
- let n = this.payload.subarray(e.offset, e.offset + t);
552
- return this.offset = e.offset + t, new T(this.keyType, n);
553
- }
554
- throw Error("Unsupported dictionary key type");
555
- }
556
- readValue() {
557
- switch (this.valueType) {
558
- case 12:
559
- case 13: {
560
- let e = { offset: this.offset }, t = k(this.payload, e, "DictMalformed");
561
- N(this.payload, e.offset, t);
562
- let n = this.payload.subarray(e.offset, e.offset + t);
563
- return this.offset = e.offset + t, new T(this.valueType, n);
564
- }
565
- case 11: {
566
- let e = { offset: this.offset }, t = k(this.payload, e, "DictMalformed");
567
- N(this.payload, e.offset, t);
568
- let n = this.payload.subarray(e.offset, e.offset + t);
569
- return this.offset = e.offset + t, new T(11, n);
570
- }
571
- case 9: {
572
- let e = P(this.payload, this.offset), t = this.payload.subarray(this.offset, this.offset + e);
573
- return this.offset += e, new T(9, t);
574
- }
575
- case 10: {
576
- let e = F(this.payload, this.offset), t = this.payload.subarray(this.offset, this.offset + e);
577
- return this.offset += e, new T(10, t);
578
- }
579
- case 3:
580
- case 5:
581
- case 7:
582
- case 8:
583
- case 2:
584
- case 4:
585
- case 6:
586
- case 14:
587
- case 1: {
588
- let e = j(this.valueType);
589
- N(this.payload, this.offset, e);
590
- let t = this.payload.subarray(this.offset, this.offset + e);
591
- return this.offset += e, new T(this.valueType, t);
592
- }
593
- default: throw Error(`Unsupported dictionary value type ${v[this.valueType]}`);
594
- }
595
- }
596
- }, le = class {
597
- key;
598
- value;
599
- constructor(e, t) {
600
- this.key = e, this.value = t;
601
- }
602
- }, D = class e {
603
- bytes;
604
- constructor(e) {
605
- this.bytes = e;
606
- }
607
- static fromString(t) {
608
- if (!t) throw Error("Guid string is empty");
609
- let n = t.replace(/-/g, "");
610
- if (n.length !== 32) throw Error("Guid string must be 32 hex characters");
611
- let r = /* @__PURE__ */ new Uint8Array(16), i = e.parseHexSlice(n, 0, 8), a = e.parseHexSlice(n, 8, 4), o = e.parseHexSlice(n, 12, 4);
612
- e.writeUInt32LE(r, 0, i), e.writeUInt16LE(r, 4, a), e.writeUInt16LE(r, 6, o);
613
- for (let t = 0; t < 8; t++) r[8 + t] = e.parseHexSlice(n, 16 + t * 2, 2);
614
- return new e(r);
615
- }
616
- static fromBytes(t) {
617
- if (t.length !== 16) throw Error("Guid byte array must be 16 bytes");
618
- return new e(Uint8Array.from(t));
619
- }
620
- static createZero() {
621
- return new e(/* @__PURE__ */ new Uint8Array(16));
622
- }
623
- static createRandom() {
624
- let t = /* @__PURE__ */ new Uint8Array(16), n = globalThis.crypto;
625
- if (n?.getRandomValues) n.getRandomValues(t);
626
- else for (let e = 0; e < t.length; e++) t[e] = Math.floor(Math.random() * 256);
627
- return t[6] = t[6] & 15 | 64, t[8] = t[8] & 63 | 128, new e(t);
628
- }
629
- toString() {
630
- let t = this.bytes;
631
- return [
632
- e.toHex(e.readUInt32LE(t, 0), 8),
633
- e.toHex(e.readUInt16LE(t, 4), 4),
634
- e.toHex(e.readUInt16LE(t, 6), 4),
635
- L(t.subarray(8, 10)),
636
- L(t.subarray(10, 16))
637
- ].join("-");
638
- }
639
- asBytes() {
640
- return this.bytes.slice();
641
- }
642
- static parseHexSlice(e, t, n) {
643
- let r = e.substr(t, n), i = Number.parseInt(r, 16);
644
- if (Number.isNaN(i)) throw Error("Guid string contains invalid characters");
645
- return i >>> 0;
646
- }
647
- static writeUInt32LE(e, t, n) {
648
- let r = n >>> 0;
649
- e[t] = r & 255, e[t + 1] = r >>> 8 & 255, e[t + 2] = r >>> 16 & 255, e[t + 3] = r >>> 24 & 255;
650
- }
651
- static writeUInt16LE(e, t, n) {
652
- let r = n & 65535;
653
- e[t] = r & 255, e[t + 1] = r >>> 8 & 255;
654
- }
655
- static readUInt32LE(e, t) {
656
- return (e[t] | e[t + 1] << 8 | e[t + 2] << 16 | e[t + 3] << 24) >>> 0;
657
- }
658
- static readUInt16LE(e, t) {
659
- return (e[t] | e[t + 1] << 8) & 65535;
660
- }
661
- static toHex(e, t) {
662
- return (e >>> 0).toString(16).padStart(t, "0");
663
- }
664
- }, O = class e {
665
- static INITIAL_CAPACITY = 256;
666
- buffer;
667
- dataView;
668
- length = 0;
669
- constructor() {
670
- this.buffer = new Uint8Array(e.INITIAL_CAPACITY), this.dataView = new DataView(this.buffer.buffer);
671
- }
672
- ensureCapacity(e) {
673
- let t = this.length + e;
674
- if (t <= this.buffer.length) return;
675
- let n = this.buffer.length;
676
- for (; n < t;) n *= 2;
677
- let r = new Uint8Array(n);
678
- r.set(this.buffer.subarray(0, this.length)), this.buffer = r, this.dataView = new DataView(this.buffer.buffer);
679
- }
680
- writeByte(e) {
681
- this.ensureCapacity(1), this.buffer[this.length++] = e & 255;
682
- }
683
- writeBytes(e) {
684
- this.ensureCapacity(e.length), this.buffer.set(e, this.length), this.length += e.length;
685
- }
686
- writeUInt32(e) {
687
- this.ensureCapacity(4), this.dataView.setUint32(this.length, e >>> 0, !0), this.length += 4;
688
- }
689
- writeInt32(e) {
690
- this.ensureCapacity(4), this.dataView.setInt32(this.length, e | 0, !0), this.length += 4;
691
- }
692
- writeFloat32(e) {
693
- this.ensureCapacity(4), this.dataView.setFloat32(this.length, e, !0), this.length += 4;
694
- }
695
- writeFloat64(e) {
696
- this.ensureCapacity(8), this.dataView.setFloat64(this.length, e, !0), this.length += 8;
697
- }
698
- writeBigInt64(e) {
699
- this.ensureCapacity(8), this.dataView.setBigInt64(this.length, e, !0), this.length += 8;
700
- }
701
- writeBigUInt64(e) {
702
- this.ensureCapacity(8), this.dataView.setBigUint64(this.length, e, !0), this.length += 8;
703
- }
704
- writeVarUInt(e) {
705
- let t = e >>> 0;
706
- for (; t >= 128;) this.ensureCapacity(1), this.buffer[this.length++] = t & 127 | 128, t >>>= 7;
707
- this.ensureCapacity(1), this.buffer[this.length++] = t & 127;
708
- }
709
- toUint8Array() {
710
- return this.buffer.slice(0, this.length);
711
- }
712
- };
713
- function k(e, t, n) {
714
- if (t.offset >= e.length) throw Error(n);
715
- let r = 0, i = 0, a = 0;
716
- for (; t.offset < e.length;) {
717
- let n = e[t.offset++];
718
- if (a++, r |= (n & 127) << i, !(n & 128)) {
719
- if (a !== ue(r)) throw Error("Teleport VarUInt is not canonical");
720
- return r >>> 0;
721
- }
722
- if (i += 7, i >= 35) throw Error("Teleport VarUInt exceeds 32-bit range");
723
- }
724
- throw Error(n);
725
- }
726
- function ue(e) {
727
- return e < 128 ? 1 : e < 16384 ? 2 : e < 2097152 ? 3 : e < 268435456 ? 4 : 5;
728
- }
729
- function A(e, t = 0) {
730
- if (t & 240) throw Error("Teleport flags must fit into 4 bits");
731
- return (e & 15) << 4 | t & 15;
732
- }
733
- function de(e) {
734
- return e === 12 || e === 13 || e === 9 || e === 11 || e === 10;
735
- }
736
- function j(e) {
737
- switch (e) {
738
- case 3:
739
- case 5:
740
- case 7: return 4;
741
- case 4:
742
- case 6:
743
- case 8: return 8;
744
- case 14: return 16;
745
- case 2: return 1;
746
- case 1: return 0;
747
- default: return -1;
748
- }
749
- }
750
- function M(e) {
751
- if (e === 9 || e === 11 || e === 10 || e === 1) throw Error("Dictionary keys must be primitive Teleport types");
752
- }
753
- function N(e, t, n) {
754
- if (t < 0 || n < 0 || t + n > e.length) throw Error("Teleport payload exceeds bounds");
755
- }
756
- function fe(e, t) {
757
- return (e[t] | e[t + 1] << 8 | e[t + 2] << 16 | e[t + 3] << 24) >>> 0;
758
- }
759
- function P(e, t) {
760
- if (t >= e.length) throw Error("Array payload exceeds bounds");
761
- let n = e[t], r = n >> 4 & 15;
762
- if (n & 15) throw Error("Array flags must be zero");
763
- let i = { offset: t + 1 }, a = k(e, i, "ArrayMalformed"), o = j(r);
764
- if (o >= 0) {
765
- let n = o * a;
766
- return N(e, i.offset, n), i.offset + n - t;
767
- }
768
- let s = i.offset;
769
- for (let t = 0; t < a; t++) s = I(r, e, s, "ArrayMalformed");
770
- return s - t;
771
- }
772
- function F(e, t) {
773
- if (t + 2 > e.length) throw Error("Dictionary payload too short");
774
- let n = e[t] >> 4 & 15, r = e[t + 1] >> 4 & 15;
775
- if (e[t] & 15 || e[t + 1] & 15) throw Error("Dictionary key/value flags must be zero");
776
- M(n);
777
- let i = { offset: t + 2 }, a = k(e, i, "DictMalformed"), o = i.offset;
778
- for (let t = 0; t < a; t++) o = I(n, e, o, "DictMalformed"), o = I(r, e, o, "DictMalformed");
779
- return o - t;
780
- }
781
- function I(e, t, n, r) {
782
- let i = j(e);
783
- if (i >= 0) return N(t, n, i), n + i;
784
- switch (e) {
785
- case 12:
786
- case 13: {
787
- let e = { offset: n }, i = k(t, e, r);
788
- return N(t, e.offset, i), e.offset + i;
789
- }
790
- case 11: {
791
- let e = { offset: n }, i = k(t, e, r);
792
- return N(t, e.offset, i), e.offset + i;
793
- }
794
- case 9: return n + P(t, n);
795
- case 10: return n + F(t, n);
796
- default: throw Error(`Unsupported Teleport type ${v[e]}`);
797
- }
798
- }
799
- function L(e) {
800
- return Array.from(e).map((e) => e.toString(16).padStart(2, "0")).join("");
801
- }
802
- function R(e) {
803
- return e instanceof Uint8Array ? e : new Uint8Array(e);
804
- }
805
- //#endregion
806
- //#region ../../shared/protocol/src/enums/log-type.ts
807
- var pe = /* @__PURE__ */ function(e) {
808
- return e[e.None = 0] = "None", e[e.Trace = 1] = "Trace", e[e.Debug = 2] = "Debug", e[e.Info = 4] = "Info", e[e.Warning = 8] = "Warning", e[e.Error = 16] = "Error", e[e.Critical = 32] = "Critical", e[e.Event = 64] = "Event", e[e.Usage = 128] = "Usage", e[e.Exception = 256] = "Exception", e;
809
- }({}), z = /* @__PURE__ */ function(e) {
810
- return e[e.Unknown = 0] = "Unknown", e[e.Playing = 1] = "Playing", e[e.Blocked = 2] = "Blocked", e[e.Hidden = 3] = "Hidden", e;
811
- }({}), me = /* @__PURE__ */ function(e) {
812
- return e[e.Unknown = 0] = "Unknown", e[e.Opus = 1] = "Opus", e[e.Mp3 = 2] = "Mp3", e[e.RawPcm16 = 3] = "RawPcm16", e;
813
- }({}), he = /* @__PURE__ */ function(e) {
814
- return e[e.Unknown = 0] = "Unknown", e[e.MobileWeb = 1] = "MobileWeb", e[e.MobileApp = 2] = "MobileApp", e[e.DesktopWeb = 3] = "DesktopWeb", e[e.DesktopApp = 4] = "DesktopApp", e;
815
- }({}), ge = /* @__PURE__ */ function(e) {
816
- return e[e.Unknown = 0] = "Unknown", e[e.Backend = 2] = "Backend", e[e.Server = 4] = "Server", e[e.Plugin = 8] = "Plugin", e[e.Browser = 16] = "Browser", e[e.Native = 32] = "Native", e;
817
- }({}), _e = /* @__PURE__ */ function(e) {
818
- return e[e.None = 0] = "None", e[e.WebSocket = 1] = "WebSocket", e[e.WebSocketProxy = 2] = "WebSocketProxy", e[e.WebTransport = 4] = "WebTransport", e[e.WebTransportProxy = 8] = "WebTransportProxy", e[e.Tcp = 16] = "Tcp", e[e.TcpProxy = 32] = "TcpProxy", e[e.Https = 64] = "Https", e[e.WebRTC = 128] = "WebRTC", e[e.TcpTls = 256] = "TcpTls", e[e.Udp = 512] = "Udp", e[e.UdpDtls = 1024] = "UdpDtls", e[e.HttpStream = 2048] = "HttpStream", e[e.HttpStreamProxy = 4096] = "HttpStreamProxy", e;
819
- }({}), ve = /* @__PURE__ */ function(e) {
820
- return e[e.None = 0] = "None", e[e.SendBackToSender = 1] = "SendBackToSender", e[e.Delayable = 2] = "Delayable", e[e.SendToUser = 4] = "SendToUser", e[e.Compressed = 8] = "Compressed", e[e.Unreliable = 16] = "Unreliable", e;
821
- }({}), ye = /* @__PURE__ */ function(e) {
822
- return e[e.Unknown = 0] = "Unknown", e[e.MessagePack = 1] = "MessagePack", e[e.MemoryPack = 2] = "MemoryPack", e[e.Json = 4] = "Json", e[e.Teleport = 8] = "Teleport", e[e.All = 15] = "All", e;
823
- }({}), be = /* @__PURE__ */ function(e) {
824
- return e[e.Css = 0] = "Css", e[e.Flutter = 1] = "Flutter", e;
825
- }({}), xe = /* @__PURE__ */ function(e) {
826
- return e[e.Unknown = 0] = "Unknown", e[e.Machine = 1] = "Machine", e[e.Human = 2] = "Human", e;
827
- }({}), B = /* @__PURE__ */ function(e) {
828
- return e[e.Unknown = 0] = "Unknown", e[e.H264 = 1] = "H264", e[e.Vp8 = 2] = "Vp8", e[e.Vp9 = 3] = "Vp9", e[e.Av1 = 4] = "Av1", e;
829
- }({}), Se = /* @__PURE__ */ function(e) {
830
- return e[e.Unknown = 0] = "Unknown", e[e.DotNet = 1] = "DotNet", e[e.TypeScript = 2] = "TypeScript", e[e.Cpp = 3] = "Cpp", e[e.Dart = 4] = "Dart", e[e.Rust = 5] = "Rust", e;
831
- }({}), Ce = /* @__PURE__ */ function(e) {
832
- return e[e.Local = 0] = "Local", e[e.Cloud = 1] = "Cloud", e;
833
- }({}), we = 4194311, Te = 112206629, Ee = 420935914, De = 4086360332, Oe = 4253308507;
834
- function V(e) {
835
- let t = {};
836
- return ke(t), e && Object.assign(t, e), t;
837
- }
838
- function ke(e) {
839
- return e.Epoch = 0, e.PlayedSeconds = 0, e.BufferedMs = 0, e.State = z.Unknown, e;
840
- }
841
- function Ae(e) {
842
- let t = new S(1);
843
- return je(e, t), t.finish();
844
- }
845
- function je(e, t) {
846
- t.writeFloat32Field(Te, e.BufferedMs), t.writeInt32Field(Ee, e.State), t.writeUInt32Field(De, e.Epoch >>> 0), t.writeFloat64Field(Oe, e.PlayedSeconds);
847
- }
848
- function H(e, t, n) {
849
- return _(we, Ae(e), 1, t, n);
850
- }
851
- var Me = 161083277, Ne = 265814330, Pe = 1368629611, Fe = 2431514951, Ie = 2514959030, Le = 2745379226, Re = 3282782683, ze = 3284746250, Be = 4101844078;
852
- function U(e) {
853
- let t = {};
854
- return W(t), e && Object.assign(t, e), t;
855
- }
856
- function W(e) {
857
- return e.StreamId = "", e.Description = "", e.SourceType = "", e.Codec = me.Unknown, e.CodecDetails = "", e.SampleRate = 0, e.Channels = 0, e.ShapeSets = void 0, e.CorrelationId = void 0, e;
858
- }
859
- function Ve(e, t) {
860
- let n = t ?? U();
861
- return W(n), He(e, n), n;
862
- }
863
- function He(e, t) {
864
- let n;
865
- for (; (n = e.next()) !== null;) switch (n.fieldId) {
866
- case Me:
867
- if (n.isNull) throw Error();
868
- t.StreamId = n.asString();
869
- break;
870
- case Ne:
871
- if (n.isNull) {
872
- t.ShapeSets = void 0;
873
- break;
874
- }
875
- t.ShapeSets = Ue(n.asArray());
876
- break;
877
- case Pe:
878
- if (n.isNull) throw Error();
879
- t.Description = n.asString();
880
- break;
881
- case Fe:
882
- if (n.isNull) throw Error();
883
- t.Channels = n.asInt32();
884
- break;
885
- case Ie:
886
- if (n.isNull) {
887
- t.CorrelationId = void 0;
888
- break;
889
- }
890
- t.CorrelationId = n.asString();
891
- break;
892
- case Le:
893
- if (n.isNull) throw Error();
894
- t.CodecDetails = n.asString();
895
- break;
896
- case Re:
897
- if (n.isNull) throw Error();
898
- t.SourceType = n.asString();
899
- break;
900
- case ze:
901
- if (n.isNull) throw Error();
902
- t.Codec = n.asInt32();
903
- break;
904
- case Be:
905
- if (n.isNull) throw Error();
906
- t.SampleRate = n.asInt32();
907
- }
908
- }
909
- function Ue(e) {
910
- let t = [], n;
911
- for (; (n = e.next()) !== null;) t.push(Je(n.asObject()));
912
- return t;
913
- }
914
- var We = 1107713536, Ge = 1154362099, Ke = 1185721362;
915
- function qe(e) {
916
- let t = {};
917
- return G(t), e && Object.assign(t, e), t;
918
- }
919
- function G(e) {
920
- return e.SetId = 0, e.Name = "", e.ShapeNames = [], e;
921
- }
922
- function Je(e, t) {
923
- let n = t ?? qe();
924
- return G(n), Ye(e, n), n;
925
- }
926
- function Ye(e, t) {
927
- let n;
928
- for (; (n = e.next()) !== null;) switch (n.fieldId) {
929
- case We:
930
- if (n.isNull) throw Error();
931
- t.Name = n.asString();
932
- break;
933
- case Ge:
934
- if (n.isNull) throw Error();
935
- t.SetId = n.asUInt32();
936
- break;
937
- case Ke:
938
- if (n.isNull) throw Error();
939
- t.ShapeNames = Xe(n.asArray());
940
- }
941
- }
942
- function Xe(e) {
943
- let t = [], n;
944
- for (; (n = e.next()) !== null;) t.push(n.asString());
945
- return t;
946
- }
947
- var Ze = 8388612;
948
- function Qe(e) {
949
- let t = {};
950
- return e && Object.assign(t, e), t;
951
- }
952
- function $e(e) {
953
- return new S(1).finish();
954
- }
955
- function et(e, t, n) {
956
- return _(Ze, $e(e), 1, t, n);
957
- }
958
- var tt = 8388609, K = 161083277, q = 164808083, nt = 1368629611, rt = 2514959030, it = 2745379226, at = 2950031986, ot = 3282782683, st = 3284746250, ct = 4065070594;
959
- function lt(e) {
960
- let t = {};
961
- return ut(t), e && Object.assign(t, e), t;
962
- }
963
- function ut(e) {
964
- return e.StreamId = "", e.Description = "", e.SourceType = "", e.Codec = B.H264, e.CodecDetails = "", e.Width = 0, e.Height = 0, e.Framerate = 30, e.CorrelationId = void 0, e;
965
- }
966
- function dt(e) {
967
- let t = new S(6);
968
- return ft(e, t), t.finish();
969
- }
970
- function ft(e, t) {
971
- t.writeStringField(K, e.StreamId), t.writeFloat64Field(q, e.Framerate), t.writeStringField(nt, e.Description);
972
- let n = e.CorrelationId;
973
- n != null && t.writeStringField(rt, n), t.writeStringField(it, e.CodecDetails), t.writeInt32Field(at, e.Height | 0), t.writeStringField(ot, e.SourceType), t.writeInt32Field(st, e.Codec), t.writeInt32Field(ct, e.Width | 0);
974
- }
975
- function pt(e, t) {
976
- let n = t ?? lt();
977
- return ut(n), mt(e, n), n;
978
- }
979
- function mt(e, t) {
980
- let n;
981
- for (; (n = e.next()) !== null;) switch (n.fieldId) {
982
- case K:
983
- if (n.isNull) throw Error();
984
- t.StreamId = n.asString();
985
- break;
986
- case q:
987
- if (n.isNull) throw Error();
988
- t.Framerate = n.asFloat64();
989
- break;
990
- case nt:
991
- if (n.isNull) throw Error();
992
- t.Description = n.asString();
993
- break;
994
- case rt:
995
- if (n.isNull) {
996
- t.CorrelationId = void 0;
997
- break;
998
- }
999
- t.CorrelationId = n.asString();
1000
- break;
1001
- case it:
1002
- if (n.isNull) throw Error();
1003
- t.CodecDetails = n.asString();
1004
- break;
1005
- case at:
1006
- if (n.isNull) throw Error();
1007
- t.Height = n.asInt32();
1008
- break;
1009
- case ot:
1010
- if (n.isNull) throw Error();
1011
- t.SourceType = n.asString();
1012
- break;
1013
- case st:
1014
- if (n.isNull) throw Error();
1015
- t.Codec = n.asInt32();
1016
- break;
1017
- case ct:
1018
- if (n.isNull) throw Error();
1019
- t.Width = n.asInt32();
1020
- }
1021
- }
1022
- function ht(e, t, n) {
1023
- return _(tt, dt(e), 6, t, n);
1024
- }
1025
- var gt = 8388610;
1026
- function _t(e) {
1027
- let t = {};
1028
- return e && Object.assign(t, e), t;
1029
- }
1030
- function vt(e) {
1031
- return new S(1).finish();
1032
- }
1033
- function yt(e, t, n) {
1034
- return _(gt, vt(e), 1, t, n);
1035
- }
1036
- //#endregion
1037
- //#region src/media/media-session-helper.ts
1038
- function bt() {
1039
- let e = 44100, t = /* @__PURE__ */ new ArrayBuffer(882044), n = new DataView(t), r = (e, t) => {
1040
- for (let r = 0; r < t.length; r++) n.setUint8(e + r, t.charCodeAt(r));
1041
- };
1042
- r(0, "RIFF"), n.setUint32(4, 882036, !0), r(8, "WAVE"), r(12, "fmt "), n.setUint32(16, 16, !0), n.setUint16(20, 1, !0), n.setUint16(22, 1, !0), n.setUint32(24, e, !0), n.setUint32(28, e * 2, !0), n.setUint16(32, 2, !0), n.setUint16(34, 16, !0), r(36, "data"), n.setUint32(40, 882e3, !0);
1043
- let i = new Blob([t], { type: "audio/wav" });
1044
- return URL.createObjectURL(i);
1045
- }
1046
- var xt = class {
1047
- _silentAudioElement = null;
1048
- get silentAudioElement() {
1049
- return this._silentAudioElement;
1050
- }
1051
- ensureSilentPlaybackElement() {
1052
- typeof document > "u" || (this._silentAudioElement || (this._silentAudioElement = document.createElement("audio"), this._silentAudioElement.src = bt(), this._silentAudioElement.loop = !0, this._silentAudioElement.volume = .01), this._silentAudioElement.paused && this._silentAudioElement.play().catch(() => {}));
1053
- }
1054
- setup(e, t) {
1055
- if (!(typeof document > "u") && (this.ensureSilentPlaybackElement(), typeof navigator < "u" && "mediaSession" in navigator)) {
1056
- let n = e ?? {};
1057
- navigator.mediaSession.metadata = new MediaMetadata({
1058
- title: n.title || "Audio",
1059
- artist: n.artist || "Ikon AI App"
1060
- }), navigator.mediaSession.playbackState = "playing";
1061
- try {
1062
- navigator.mediaSession.setPositionState({
1063
- duration: 86400,
1064
- playbackRate: 1,
1065
- position: 0
1066
- });
1067
- } catch {}
1068
- navigator.mediaSession.setActionHandler("play", () => {
1069
- t.onPlay(), this._silentAudioElement?.play().catch(() => {}), navigator.mediaSession.playbackState = "playing";
1070
- }), navigator.mediaSession.setActionHandler("pause", () => {
1071
- t.onPause(), this._silentAudioElement?.pause(), navigator.mediaSession.playbackState = "paused";
1072
- });
1073
- }
1074
- }
1075
- cleanup() {
1076
- if (this._silentAudioElement) try {
1077
- this._silentAudioElement.pause();
1078
- let e = this._silentAudioElement.src;
1079
- this._silentAudioElement.src = "", e.startsWith("blob:") && URL.revokeObjectURL(e), this._silentAudioElement = null;
1080
- } catch {}
1081
- if (typeof navigator < "u" && "mediaSession" in navigator) try {
1082
- navigator.mediaSession.setActionHandler("play", null), navigator.mediaSession.setActionHandler("pause", null);
1083
- } catch {}
1084
- }
1085
- };
1086
- //#endregion
1087
- //#region src/worker/audio-playback-worker.ts?worker
1088
- function St(e) {
1089
- return new Worker("" + new URL("assets/audio-playback-worker-BXZR_9iK.js", import.meta.url).href, {
1090
- type: "module",
1091
- name: e?.name
1092
- });
1093
- }
1094
- //#endregion
1095
- //#region src/media/ikon-audio-playback.ts
1096
- var J = t("IkonAudioPlayback"), Ct = {
1097
- enabled: !1,
1098
- statusIntervalMs: 1e3
1099
- };
1100
- function Y(e) {
1101
- return e instanceof Error ? `${e.name}: ${e.message}` : String(e);
1102
- }
1103
- function wt(e) {
1104
- return `
1105
- // Audio buffer constants
1106
- const OUTPUT_SAMPLE_RATE_HZ = ${e.outputSampleRateHz};
1107
- const DEFAULT_FRAME_SAMPLES_PER_CHANNEL = Math.max(1, Math.round(OUTPUT_SAMPLE_RATE_HZ * 0.02));
1108
- const BUFFER_TARGET_MIN_MS = 120;
1109
- const BUFFER_TARGET_MAX_MS = 300;
1110
- const JITTER_MULTIPLIER = 4;
1111
- const LOCAL_BUFFER_MAX_MS = ${o};
1112
- const CONTROL_PERIOD_MS = 200;
1113
- const UNDERRUN_JUMP_MS = 100;
1114
- const STABLE_TIME_TO_DECREASE_MS = ${a};
1115
- const DECREASE_STEP_MS = 10;
1116
- const DEFAULT_STATS_INTERVAL_SAMPLES = OUTPUT_SAMPLE_RATE_HZ;
1117
- const PLAYBACK_REPORT_INTERVAL_SAMPLES = Math.round(OUTPUT_SAMPLE_RATE_HZ / 2);
1118
-
1119
- // Pre-computed reciprocals for division-free calculations
1120
- const INV_OUTPUT_SAMPLE_RATE_HZ = 1 / OUTPUT_SAMPLE_RATE_HZ;
1121
- const MS_PER_SAMPLE = 1000 * INV_OUTPUT_SAMPLE_RATE_HZ;
1122
-
1123
- // Fade envelope constants
1124
- const FADE_IN_DURATION_MS = 100;
1125
- const FADE_OUT_DURATION_MS = 50;
1126
- const FADE_IN_DURATION_SAMPLES = Math.round(OUTPUT_SAMPLE_RATE_HZ * FADE_IN_DURATION_MS / 1000);
1127
- const FADE_OUT_DURATION_SAMPLES = Math.round(OUTPUT_SAMPLE_RATE_HZ * FADE_OUT_DURATION_MS / 1000);
1128
- const FADE_IN_INCREMENT = 1.0 / FADE_IN_DURATION_SAMPLES;
1129
- const FADE_OUT_INCREMENT = 1.0 / FADE_OUT_DURATION_SAMPLES;
1130
-
1131
- // Render quantum size (standard Web Audio API value)
1132
- const RENDER_QUANTUM_SIZE = 128;
1133
-
1134
- // Buffer reduction crossfade constants (align to quantum boundary to avoid partial quanta)
1135
- const BUFFER_REDUCTION_CROSSFADE_MS = 20;
1136
- const BUFFER_REDUCTION_CROSSFADE_SAMPLES_RAW = Math.round(OUTPUT_SAMPLE_RATE_HZ * BUFFER_REDUCTION_CROSSFADE_MS / 1000);
1137
- const BUFFER_REDUCTION_CROSSFADE_SAMPLES = Math.ceil(BUFFER_REDUCTION_CROSSFADE_SAMPLES_RAW / RENDER_QUANTUM_SIZE) * RENDER_QUANTUM_SIZE;
1138
-
1139
- class RingBuffer {
1140
- static getStorageForCapacity(capacity, type) {
1141
- const indexBytes = Int32Array.BYTES_PER_ELEMENT * 2;
1142
- const dataBytes = type.BYTES_PER_ELEMENT * capacity;
1143
- return new SharedArrayBuffer(indexBytes + dataBytes);
1144
- }
1145
-
1146
- constructor(sharedArrayBuffer, type, channels = 1) {
1147
- this.buf = sharedArrayBuffer;
1148
- this.readWrite = new Int32Array(sharedArrayBuffer, 0, 2);
1149
- const dataOffset = Int32Array.BYTES_PER_ELEMENT * 2;
1150
- const dataLength = (sharedArrayBuffer.byteLength - dataOffset) / Float32Array.BYTES_PER_ELEMENT;
1151
- this.storage = new type(sharedArrayBuffer, dataOffset, dataLength);
1152
- this.channels = channels;
1153
- }
1154
-
1155
- get capacity() {
1156
- return this.storage.length;
1157
- }
1158
-
1159
- availableRead() {
1160
- const read = Atomics.load(this.readWrite, 0);
1161
- const write = Atomics.load(this.readWrite, 1);
1162
- if (write >= read) return write - read;
1163
- return this.capacity - (read - write);
1164
- }
1165
-
1166
- pop(target) {
1167
- const rawReadable = Math.min(this.availableRead(), target.length);
1168
- const readable = Math.floor(rawReadable / this.channels) * this.channels;
1169
- if (readable <= 0) {
1170
- target.fill(0);
1171
- return 0;
1172
- }
1173
-
1174
- let read = Atomics.load(this.readWrite, 0);
1175
- const firstPart = Math.min(readable, this.capacity - read);
1176
- for (let i = 0; i < firstPart; i++) {
1177
- target[i] = this.storage[read + i];
1178
- }
1179
- const remaining = readable - firstPart;
1180
- if (remaining > 0) {
1181
- for (let i = 0; i < remaining; i++) {
1182
- target[firstPart + i] = this.storage[i];
1183
- }
1184
- }
1185
- if (readable < target.length) {
1186
- target.fill(0, readable);
1187
- }
1188
- read = (read + readable) % this.capacity;
1189
- Atomics.store(this.readWrite, 0, read);
1190
- return readable;
1191
- }
1192
-
1193
- skip(count) {
1194
- const rawReadable = Math.min(this.availableRead(), count);
1195
- const readable = Math.floor(rawReadable / this.channels) * this.channels;
1196
- if (readable <= 0) return 0;
1197
-
1198
- let read = Atomics.load(this.readWrite, 0);
1199
- read = (read + readable) % this.capacity;
1200
- Atomics.store(this.readWrite, 0, read);
1201
- return readable;
1202
- }
1203
-
1204
- flush() {
1205
- Atomics.store(this.readWrite, 0, 0);
1206
- Atomics.store(this.readWrite, 1, 0);
1207
- }
1208
- }
1209
-
1210
- // Simple queue buffer for non-SAB fallback
1211
- class QueueBuffer {
1212
- constructor(maxSamples, channels = 1) {
1213
- this.chunks = [];
1214
- this.headIndex = 0;
1215
- this.offset = 0;
1216
- this.maxSamples = maxSamples;
1217
- this.totalSamples = 0;
1218
- this.channels = channels;
1219
- this.needsCompaction = false;
1220
- }
1221
-
1222
- available() {
1223
- return this.totalSamples;
1224
- }
1225
-
1226
- availableRead() {
1227
- return this.totalSamples;
1228
- }
1229
-
1230
- compact() {
1231
- if (!this.needsCompaction || this.headIndex === 0) return;
1232
- const activeCount = this.chunks.length - this.headIndex;
1233
- for (let i = 0; i < activeCount; i++) {
1234
- this.chunks[i] = this.chunks[this.headIndex + i];
1235
- }
1236
- this.chunks.length = activeCount;
1237
- this.headIndex = 0;
1238
- this.needsCompaction = false;
1239
- }
1240
-
1241
- push(chunk) {
1242
- this.chunks.push(chunk);
1243
- this.totalSamples += chunk.length;
1244
- if (typeof this.maxSamples === 'number' && this.maxSamples > 0) {
1245
- if (this.totalSamples > this.maxSamples) {
1246
- this.skip(this.totalSamples - this.maxSamples);
1247
- }
1248
- }
1249
- }
1250
-
1251
- pop(target) {
1252
- if (this.totalSamples <= 0) {
1253
- target.fill(0);
1254
- return 0;
1255
- }
1256
-
1257
- const rawRequired = Math.min(target.length, this.totalSamples);
1258
- const required = Math.floor(rawRequired / this.channels) * this.channels;
1259
- if (required <= 0) {
1260
- target.fill(0);
1261
- return 0;
1262
- }
1263
-
1264
- let written = 0;
1265
- while (written < required && this.headIndex < this.chunks.length) {
1266
- const current = this.chunks[this.headIndex];
1267
- const available = current.length - this.offset;
1268
- const toCopy = Math.min(available, required - written);
1269
- for (let i = 0; i < toCopy; i++) {
1270
- target[written + i] = current[this.offset + i];
1271
- }
1272
- written += toCopy;
1273
- this.offset += toCopy;
1274
- this.totalSamples -= toCopy;
1275
- if (this.offset >= current.length) {
1276
- this.headIndex += 1;
1277
- this.offset = 0;
1278
- }
1279
- }
1280
-
1281
- if (written < target.length) {
1282
- target.fill(0, written);
1283
- }
1284
-
1285
- if (this.headIndex > 32 && this.headIndex > this.chunks.length / 2) {
1286
- this.needsCompaction = true;
1287
- }
1288
-
1289
- return written;
1290
- }
1291
-
1292
- skip(count) {
1293
- if (this.totalSamples <= 0 || count <= 0) return 0;
1294
-
1295
- const alignedCount = Math.floor(count / this.channels) * this.channels;
1296
- if (alignedCount <= 0) return 0;
1297
-
1298
- let remaining = alignedCount;
1299
- while (remaining > 0 && this.headIndex < this.chunks.length) {
1300
- const current = this.chunks[this.headIndex];
1301
- const available = current.length - this.offset;
1302
- if (remaining < available) {
1303
- this.offset += remaining;
1304
- this.totalSamples -= remaining;
1305
- return alignedCount;
1306
- }
1307
- remaining -= available;
1308
- this.totalSamples -= available;
1309
- this.headIndex += 1;
1310
- this.offset = 0;
1311
- }
1312
-
1313
- if (this.headIndex > 32 && this.headIndex > this.chunks.length / 2) {
1314
- this.needsCompaction = true;
1315
- }
1316
- return alignedCount - remaining;
1317
- }
1318
-
1319
- flush() {
1320
- this.chunks.length = 0;
1321
- this.headIndex = 0;
1322
- this.offset = 0;
1323
- this.totalSamples = 0;
1324
- this.needsCompaction = false;
1325
- }
1326
- }
1327
-
1328
- class IkonAudioPlayerProcessor extends AudioWorkletProcessor {
1329
- constructor(options) {
1330
- super();
1331
- const cfg = options?.processorOptions?.outputAudioConfig || {};
1332
- const outputChannels = options?.processorOptions?.outputChannels;
1333
- this.channels = typeof outputChannels === 'number' && outputChannels > 0 ? outputChannels : ${e.outputChannels};
1334
- this.useSharedArrayBuffer = options?.processorOptions?.useSharedArrayBuffer !== false;
1335
- this.queueMaxSamples = Math.floor((OUTPUT_SAMPLE_RATE_HZ * this.channels * LOCAL_BUFFER_MAX_MS) / 1000);
1336
- this.suspendedMaxSamples = Math.floor((OUTPUT_SAMPLE_RATE_HZ * this.channels * BUFFER_TARGET_MIN_MS) / 1000);
1337
- this.isPlaybackActive = false;
1338
-
1339
- // Diagnostics config
1340
- const diagCfg = cfg.diagnostics || {};
1341
- this.diagnosticsEnabled = diagCfg.enabled === true;
1342
- const statusIntervalMs = typeof diagCfg.statusIntervalMs === 'number' && diagCfg.statusIntervalMs > 0 ? diagCfg.statusIntervalMs : 1000;
1343
- this.statsIntervalSamples = Math.max(1, Math.round((OUTPUT_SAMPLE_RATE_HZ * statusIntervalMs) / 1000));
1344
-
1345
- // Normalization config (hardcoded)
1346
- this.normalizationEnabled = true;
1347
-
1348
- // Stream states for audio buffer
1349
- this.streams = new Map();
1350
- this.ringBuffers = new Map();
1351
- this.queueBuffers = new Map();
1352
- this.tempInterleaved = new Float32Array(RENDER_QUANTUM_SIZE * this.channels);
1353
-
1354
- // Pre-allocated crossfade buffers for buffer reduction (no allocations in render path)
1355
- const crossfadeSamples = BUFFER_REDUCTION_CROSSFADE_SAMPLES * this.channels;
1356
- this.crossfadePreSkip = new Float32Array(crossfadeSamples);
1357
- this.crossfadePostSkip = new Float32Array(crossfadeSamples);
1358
- this.crossfadeResult = new Float32Array(crossfadeSamples);
1359
- this.crossfadeOffset = 0;
1360
- this.crossfadeRemaining = 0;
1361
-
1362
- // Stats reporting
1363
- this.samplesSinceLastStats = 0;
1364
- this.lastControlTime = 0;
1365
- this.drainedStreamIds = [];
1366
- this.activeStreamIds = [];
1367
- this.activeStreams = [];
1368
- this.activeStreamIdIndices = new Map();
1369
-
1370
- // Pre-allocated message objects to avoid allocation in hot path
1371
- this._drainedMsg = { type: 'streamDrained', streamId: '' };
1372
- this._statsMsg = { type: 'stats', streamId: '', bufferMs: 0, targetMs: 0, state: '', inputDrained: false, jitterMs: 0, underrunCount: 0, dropCount: 0 };
1373
- this._playbackMsg = { type: 'playback', streamId: '', epoch: 0, playedSeconds: 0, bufferMs: 0 };
1374
- this.samplesSincePlaybackReport = 0;
1375
-
1376
- this.port.onmessage = (event) => {
1377
- const data = event.data;
1378
- if (!data || typeof data !== 'object') return;
1379
-
1380
- if (data.type === 'streamBegin') {
1381
- const streamId = data.streamId;
1382
- const sab = data.sharedArrayBuffer;
1383
- const useSab = this.useSharedArrayBuffer && sab;
1384
-
1385
- let buffer;
1386
- if (useSab) {
1387
- buffer = new RingBuffer(sab, Float32Array, this.channels);
1388
- this.ringBuffers.set(streamId, buffer);
1389
- this.queueBuffers.delete(streamId);
1390
- } else {
1391
- buffer = new QueueBuffer(this.queueMaxSamples, this.channels);
1392
- this.queueBuffers.set(streamId, buffer);
1393
- this.ringBuffers.delete(streamId);
1394
- }
1395
-
1396
- // Initialize audio buffer stream state
1397
- const stream = {
1398
- buffer,
1399
- state: 'BUFFERING',
1400
- currentEpoch: -1,
1401
- streamEnding: false,
1402
- inputDrained: false,
1403
- epochSet: false,
1404
- epochTimestampInterleavedSamples: 0,
1405
- playoutInterleavedSamples: 0,
1406
- jitterMs: 0,
1407
- bufferTargetMs: BUFFER_TARGET_MIN_MS,
1408
- stableDurationMs: 0,
1409
- totalUnderrunCount: 0,
1410
- totalDropCount: 0,
1411
- frameSamplesPerChannel: DEFAULT_FRAME_SAMPLES_PER_CHANNEL,
1412
- lastOut: new Float32Array(RENDER_QUANTUM_SIZE * this.channels),
1413
- hasLastOut: false,
1414
- transport: useSab ? 'sab' : 'queue',
1415
- // Fade envelope state
1416
- fadeGain: 0.0,
1417
- fadeDirection: 'none',
1418
- needsFadeIn: true,
1419
- needsFadeOut: false,
1420
- underrunPending: false,
1421
- // Diagnostic logging counter
1422
- bufferingLogCounter: 0
1423
- };
1424
- this.streams.set(streamId, stream);
1425
- this.activeStreamIdIndices.set(streamId, this.activeStreamIds.length);
1426
- this.activeStreamIds.push(streamId);
1427
- this.activeStreams.push(stream);
1428
- return;
1429
- }
1430
-
1431
- if (data.type === 'streamEnd') {
1432
- const streamId = data.streamId;
1433
- const stream = this.streams.get(streamId);
1434
- if (stream) {
1435
- stream.streamEnding = true;
1436
- }
1437
- return;
1438
- }
1439
-
1440
- if (data.type === 'pcm') {
1441
- const q = this.queueBuffers.get(data.streamId);
1442
- if (!q) return;
1443
- q.compact();
1444
- if (data.pcm instanceof Float32Array) {
1445
- q.push(data.pcm);
1446
- // Apply buffer limit based on playback state
1447
- const maxSamples = this.isPlaybackActive ? this.queueMaxSamples : this.suspendedMaxSamples;
1448
- if (q.totalSamples > maxSamples) {
1449
- q.skip(q.totalSamples - maxSamples);
1450
- }
1451
- }
1452
- return;
1453
- }
1454
-
1455
- if (data.type === 'frame') {
1456
- const stream = this.streams.get(data.streamId);
1457
- if (!stream) return;
1458
-
1459
- const epoch = data.epoch;
1460
- const timestampInterleavedSamples = data.timestampInterleavedSamples;
1461
-
1462
- // Epoch change → reset stream state
1463
- if (stream.currentEpoch !== epoch) {
1464
- this.port.postMessage({
1465
- type: 'log',
1466
- level: 'info',
1467
- message: 'Epoch change ' + stream.currentEpoch + '->' + epoch + ', bufferTargetMs=' + stream.bufferTargetMs.toFixed(0) + 'ms (not reset)',
1468
- streamId: data.streamId
1469
- });
1470
- stream.currentEpoch = epoch;
1471
- stream.epochSet = false;
1472
- stream.playoutInterleavedSamples = 0;
1473
- stream.streamEnding = false;
1474
- stream.inputDrained = false;
1475
- stream.state = 'BUFFERING';
1476
- stream.frameSamplesPerChannel = DEFAULT_FRAME_SAMPLES_PER_CHANNEL;
1477
- stream.hasLastOut = false;
1478
- // Reset fade state for new epoch
1479
- stream.fadeGain = 0.0;
1480
- stream.fadeDirection = 'none';
1481
- stream.needsFadeIn = true;
1482
- stream.needsFadeOut = false;
1483
- stream.underrunPending = false;
1484
-
1485
- const ring = this.ringBuffers.get(data.streamId);
1486
- if (ring) ring.flush();
1487
- const q = this.queueBuffers.get(data.streamId);
1488
- if (q) q.flush();
1489
- }
1490
-
1491
- // Establish initial timestamp mapping
1492
- if (!stream.epochSet) {
1493
- stream.epochSet = true;
1494
- stream.epochTimestampInterleavedSamples = timestampInterleavedSamples;
1495
- }
1496
-
1497
- // Update jitter estimate
1498
- stream.jitterMs = data.jitterMs;
1499
- if (typeof data.frameSizeInterleavedSamples === 'number' && data.frameSizeInterleavedSamples > 0) {
1500
- stream.frameSamplesPerChannel = Math.max(1, Math.round(data.frameSizeInterleavedSamples / this.channels));
1501
- }
1502
-
1503
- // Trigger fade-in if receiving audio on a drained stream (even without isFirst)
1504
- if (stream.inputDrained && !data.isFirst) {
1505
- stream.needsFadeIn = true;
1506
- stream.needsFadeOut = false;
1507
- stream.fadeGain = 0.0;
1508
- stream.fadeDirection = 'in';
1509
- stream.inputDrained = false;
1510
- stream.underrunPending = false;
1511
- }
1512
-
1513
- // Track isFirst/isLast for fade triggers
1514
- if (data.isFirst) {
1515
- // New audio segment starting - fade in from silence
1516
- stream.needsFadeIn = true;
1517
- stream.needsFadeOut = false;
1518
- stream.fadeGain = 0.0;
1519
- stream.fadeDirection = 'in';
1520
- stream.inputDrained = false;
1521
- stream.underrunPending = false;
1522
- }
1523
- if (data.isLast) {
1524
- // Audio segment ending - schedule fade out
1525
- stream.needsFadeOut = true;
1526
- stream.inputDrained = true;
1527
- this.port.postMessage({
1528
- type: 'log',
1529
- level: 'info',
1530
- message: 'Received isLast=true, setting inputDrained=true',
1531
- streamId: data.streamId
1532
- });
1533
- }
1534
-
1535
- // Enforce buffer limit when not actively playing (for SAB mode)
1536
- if (!this.isPlaybackActive) {
1537
- const maxSamples = this.suspendedMaxSamples;
1538
- const ring = this.ringBuffers.get(data.streamId);
1539
- if (ring) {
1540
- const available = ring.availableRead();
1541
- if (available > maxSamples) {
1542
- ring.skip(available - maxSamples);
1543
- }
1544
- }
1545
- }
1546
- return;
1547
- }
1548
-
1549
- if (data.type === 'playbackActive') {
1550
- const wasActive = this.isPlaybackActive;
1551
- this.isPlaybackActive = data.active;
1552
-
1553
- // When switching to inactive, trim all buffers to suspended limit
1554
- if (wasActive && !data.active) {
1555
- const maxSamples = this.suspendedMaxSamples;
1556
- for (const q of this.queueBuffers.values()) {
1557
- if (q.totalSamples > maxSamples) {
1558
- q.skip(q.totalSamples - maxSamples);
1559
- }
1560
- }
1561
- for (const ring of this.ringBuffers.values()) {
1562
- const available = ring.availableRead();
1563
- if (available > maxSamples) {
1564
- ring.skip(available - maxSamples);
1565
- }
1566
- }
1567
- }
1568
- return;
1569
- }
1570
- };
1571
- }
1572
-
1573
- availableSamples(stream) {
1574
- const buf = stream.buffer;
1575
- return buf ? buf.availableRead() : 0;
1576
- }
1577
-
1578
- skipSamples(stream, count) {
1579
- const buf = stream.buffer;
1580
- return buf ? buf.skip(count) : 0;
1581
- }
1582
-
1583
- readInto(stream, target) {
1584
- const buf = stream.buffer;
1585
- if (buf) return buf.pop(target);
1586
- target.fill(0);
1587
- return 0;
1588
- }
1589
-
1590
- // Crossfade skip for buffer reduction - smoothly skips samples with crossfade to avoid clicks
1591
- crossfadeSkipSamples(stream, samplesToSkip) {
1592
- const fadeLen = BUFFER_REDUCTION_CROSSFADE_SAMPLES * this.channels;
1593
-
1594
- // 1. Read pre-skip tail into pre-allocated buffer
1595
- const preRead = this.readInto(stream, this.crossfadePreSkip);
1596
- if (preRead < fadeLen) return 0;
1597
-
1598
- // 2. Skip the excess (minus crossfade portion)
1599
- const skipAmount = samplesToSkip - fadeLen;
1600
- if (skipAmount > 0) {
1601
- this.skipSamples(stream, skipAmount);
1602
- }
1603
-
1604
- // 3. Read post-skip head into pre-allocated buffer
1605
- const postRead = this.readInto(stream, this.crossfadePostSkip);
1606
- if (postRead < fadeLen) {
1607
- // Copy pre-skip to result buffer, output what we have
1608
- for (let i = 0; i < fadeLen; i++) {
1609
- this.crossfadeResult[i] = this.crossfadePreSkip[i];
1610
- }
1611
- this.crossfadeOffset = 0;
1612
- this.crossfadeRemaining = postRead > 0 ? fadeLen : 0;
1613
- return samplesToSkip;
1614
- }
1615
-
1616
- // 4. Linear crossfade in-place to pre-allocated result buffer
1617
- const invFadeLen = 1.0 / fadeLen;
1618
- for (let i = 0; i < fadeLen; i++) {
1619
- const t = i * invFadeLen;
1620
- this.crossfadeResult[i] = this.crossfadePreSkip[i] * (1 - t) + this.crossfadePostSkip[i] * t;
1621
- }
1622
-
1623
- this.crossfadeOffset = 0;
1624
- this.crossfadeRemaining = fadeLen;
1625
-
1626
- return samplesToSkip;
1627
- }
1628
-
1629
- // Returns the minimum safe audio buffer target based on jitter
1630
- getBufferFloorMs(stream) {
1631
- return BUFFER_TARGET_MIN_MS + JITTER_MULTIPLIER * stream.jitterMs;
1632
- }
1633
-
1634
- // ALL buffer target changes go through this function
1635
- updateBufferTarget(stream, action) {
1636
- const floorMs = this.getBufferFloorMs(stream);
1637
- let target = Math.max(stream.bufferTargetMs, floorMs);
1638
-
1639
- if (action === 'underrun') {
1640
- // Simple: every underrun adds a fixed amount
1641
- target += UNDERRUN_JUMP_MS;
1642
- stream.stableDurationMs = 0;
1643
- } else if (action === 'stable-decrease') {
1644
- // Decrease: gradual, never below floor
1645
- target = Math.max(floorMs, target - DECREASE_STEP_MS);
1646
- }
1647
- // action === 'enforce-floor' just enforces floor, no other changes
1648
-
1649
- stream.bufferTargetMs = Math.min(BUFFER_TARGET_MAX_MS, target);
1650
- }
1651
-
1652
- // Immediate response to underrun - called from process() after fade-out completes
1653
- handleUnderrun(streamId, stream) {
1654
- stream.totalUnderrunCount++;
1655
- stream.state = 'BUFFERING';
1656
- stream.needsFadeIn = true;
1657
- stream.underrunPending = false;
1658
- // Note: fadeGain/fadeDirection not reset here - fade-out has already completed
1659
- this.updateBufferTarget(stream, 'underrun');
1660
-
1661
- this.port.postMessage({
1662
- type: 'log',
1663
- level: 'warn',
1664
- message: 'Buffer underrun, count=' + stream.totalUnderrunCount + ', newTarget=' + stream.bufferTargetMs.toFixed(0) + 'ms',
1665
- streamId
1666
- });
1667
- }
1668
-
1669
- controlTick(streamId, stream, nowMs) {
1670
- if (!stream.epochSet || stream.state === 'ENDED') return;
1671
-
1672
- // Always enforce buffer floor
1673
- this.updateBufferTarget(stream, 'enforce-floor');
1674
-
1675
- // Stability tracking and gradual decrease (only when playing, not ending)
1676
- if (stream.state === 'PLAYING' && !stream.streamEnding) {
1677
- stream.stableDurationMs += CONTROL_PERIOD_MS;
1678
-
1679
- if (stream.stableDurationMs >= STABLE_TIME_TO_DECREASE_MS) {
1680
- this.updateBufferTarget(stream, 'stable-decrease');
1681
- stream.stableDurationMs = 0;
1682
- }
1683
- }
1684
- }
1685
-
1686
- process(_inputs, outputs) {
1687
- const output = outputs[0];
1688
- if (!output || output.length === 0) {
1689
- return true;
1690
- }
1691
-
1692
- const now = currentTime;
1693
- const nowMs = now * 1000;
1694
- const outputChannels = output.length;
1695
- const requestSamples = RENDER_QUANTUM_SIZE * this.channels;
1696
-
1697
- for (let ch = 0; ch < outputChannels; ch++) {
1698
- output[ch].fill(0);
1699
- }
1700
-
1701
- // Run control loop periodically
1702
- if (nowMs - this.lastControlTime >= CONTROL_PERIOD_MS) {
1703
- for (let i = 0; i < this.activeStreamIds.length; i++) {
1704
- const streamId = this.activeStreamIds[i];
1705
- const stream = this.activeStreams[i];
1706
- if (stream) this.controlTick(streamId, stream, nowMs);
1707
- }
1708
- this.lastControlTime = nowMs;
1709
- }
1710
-
1711
- let activeStreamCount = 0;
1712
- const drainedStreamIds = this.drainedStreamIds;
1713
- drainedStreamIds.length = 0;
1714
-
1715
- for (let i = 0; i < this.activeStreamIds.length; i++) {
1716
- const streamId = this.activeStreamIds[i];
1717
- const stream = this.activeStreams[i];
1718
- if (!stream || stream.state === 'ENDED') {
1719
- continue;
1720
- }
1721
-
1722
- const available = this.availableSamples(stream);
1723
-
1724
- if (stream.state === 'BUFFERING') {
1725
- if (stream.streamEnding) {
1726
- if (available <= 0) {
1727
- stream.state = 'ENDED';
1728
- drainedStreamIds.push(streamId);
1729
- continue;
1730
- }
1731
- this.port.postMessage({
1732
- type: 'log',
1733
- level: 'info',
1734
- message: 'BUFFERING->PLAYING (streamEnding)',
1735
- streamId
1736
- });
1737
- stream.state = 'PLAYING';
1738
- } else {
1739
- const bufferSamples = available / this.channels;
1740
- const bufferLevelMs = bufferSamples * MS_PER_SAMPLE;
1741
- if (bufferLevelMs >= stream.bufferTargetMs) {
1742
- this.port.postMessage({
1743
- type: 'log',
1744
- level: 'info',
1745
- message: 'BUFFERING->PLAYING, buffer=' + bufferLevelMs.toFixed(0) + 'ms, target=' + stream.bufferTargetMs.toFixed(0) + 'ms',
1746
- streamId
1747
- });
1748
- stream.state = 'PLAYING';
1749
- stream.bufferingLogCounter = 0;
1750
- if (stream.needsFadeIn) {
1751
- stream.fadeDirection = 'in';
1752
- } else {
1753
- stream.fadeGain = 1.0;
1754
- }
1755
- } else {
1756
- // Log periodically when stuck in BUFFERING with data available
1757
- if (available > 0) {
1758
- stream.bufferingLogCounter = (stream.bufferingLogCounter || 0) + 1;
1759
- // Log every ~1 second (approximately 43 calls at 128 samples / 48kHz)
1760
- if (stream.bufferingLogCounter >= 43) {
1761
- this.port.postMessage({
1762
- type: 'log',
1763
- level: 'info',
1764
- message: 'BUFFERING: buffer=' + bufferLevelMs.toFixed(0) + 'ms, target=' + stream.bufferTargetMs.toFixed(0) + 'ms, waiting...',
1765
- streamId
1766
- });
1767
- stream.bufferingLogCounter = 0;
1768
- }
1769
- }
1770
- continue;
1771
- }
1772
- }
1773
- }
1774
-
1775
- // Buffer reduction: if buffer exceeds target max, drain with crossfade
1776
- // Skip if we're still outputting a previous crossfade
1777
- const bufferSamplesForReduction = available / this.channels;
1778
- const bufferLevelMsForReduction = bufferSamplesForReduction * MS_PER_SAMPLE;
1779
- if (this.crossfadeRemaining <= 0 && bufferLevelMsForReduction > BUFFER_TARGET_MAX_MS && stream.state === 'PLAYING' && !stream.streamEnding) {
1780
- const excessMs = bufferLevelMsForReduction - BUFFER_TARGET_MAX_MS;
1781
- const fadeLen = BUFFER_REDUCTION_CROSSFADE_SAMPLES * this.channels;
1782
- // Need: fadeLen (pre-skip read) + skip amount + fadeLen (post-skip read)
1783
- // Skip amount must be > fadeLen for crossfade to make sense
1784
- // Cap at ~2x speed: skip up to 1 quantum worth per render, but at least fadeLen + 1
1785
- const excessSamples = Math.round((excessMs * OUTPUT_SAMPLE_RATE_HZ * this.channels) / 1000);
1786
- const samplesToSkip = Math.min(
1787
- Math.max(fadeLen + RENDER_QUANTUM_SIZE, RENDER_QUANTUM_SIZE * this.channels * 2),
1788
- excessSamples
1789
- );
1790
- // Check we have enough buffer: need fadeLen + samplesToSkip for the operation
1791
- if (samplesToSkip > fadeLen && available >= fadeLen + samplesToSkip) {
1792
- this.crossfadeSkipSamples(stream, samplesToSkip);
1793
- stream.totalDropCount++;
1794
- }
1795
- }
1796
-
1797
- // Output pending crossfade samples first (from processor-level pre-allocated buffer)
1798
- if (this.crossfadeRemaining > 0) {
1799
- const framesToOutput = Math.min(Math.floor(this.crossfadeRemaining / this.channels), RENDER_QUANTUM_SIZE);
1800
- let idx = this.crossfadeOffset;
1801
- for (let frame = 0; frame < framesToOutput; frame++) {
1802
- // Update fade envelope during crossfade output (critical for initial unlock scenario)
1803
- if (stream.fadeDirection === 'in') {
1804
- stream.fadeGain = Math.min(1.0, stream.fadeGain + FADE_IN_INCREMENT);
1805
- if (stream.fadeGain >= 1.0) {
1806
- stream.fadeDirection = 'none';
1807
- stream.needsFadeIn = false;
1808
- }
1809
- } else if (stream.fadeDirection === 'out') {
1810
- stream.fadeGain = Math.max(0.0, stream.fadeGain - FADE_OUT_INCREMENT);
1811
- if (stream.fadeGain <= 0.0) {
1812
- stream.fadeDirection = 'none';
1813
- stream.needsFadeOut = false;
1814
- }
1815
- }
1816
- for (let ch = 0; ch < this.channels && ch < outputChannels; ch++) {
1817
- output[ch][frame] += this.crossfadeResult[idx++] * stream.fadeGain;
1818
- }
1819
- }
1820
- this.crossfadeOffset += framesToOutput * this.channels;
1821
- this.crossfadeRemaining -= framesToOutput * this.channels;
1822
- // Always continue after crossfade output to avoid overlapping with normal playback
1823
- activeStreamCount++;
1824
- continue;
1825
- }
1826
-
1827
- const bufferMs = (available / this.channels) * MS_PER_SAMPLE;
1828
-
1829
- // Start fade-out when buffer is low and isLast was received
1830
- if (stream.needsFadeOut && stream.fadeDirection !== 'out' && bufferMs <= FADE_OUT_DURATION_MS * 2.0) {
1831
- stream.fadeDirection = 'out';
1832
- }
1833
-
1834
- const countRead = this.readInto(stream, this.tempInterleaved);
1835
- const framesRead = Math.floor(countRead / this.channels);
1836
-
1837
- if (countRead >= requestSamples) {
1838
- stream.lastOut.set(this.tempInterleaved);
1839
- stream.hasLastOut = true;
1840
-
1841
- // Apply per-sample fade envelope
1842
- let sampleIdx = 0;
1843
- for (let frame = 0; frame < RENDER_QUANTUM_SIZE; frame++) {
1844
- // Update fade envelope
1845
- if (stream.fadeDirection === 'in') {
1846
- stream.fadeGain = Math.min(1.0, stream.fadeGain + FADE_IN_INCREMENT);
1847
- if (stream.fadeGain >= 1.0) {
1848
- stream.fadeDirection = 'none';
1849
- stream.needsFadeIn = false;
1850
- }
1851
- } else if (stream.fadeDirection === 'out') {
1852
- stream.fadeGain = Math.max(0.0, stream.fadeGain - FADE_OUT_INCREMENT);
1853
- if (stream.fadeGain <= 0.0) {
1854
- stream.fadeDirection = 'none';
1855
- stream.needsFadeOut = false;
1856
- }
1857
- }
1858
- for (let ch = 0; ch < this.channels && ch < outputChannels; ch++) {
1859
- output[ch][frame] += this.tempInterleaved[sampleIdx++] * stream.fadeGain;
1860
- }
1861
- }
1862
- stream.playoutInterleavedSamples += countRead;
1863
- activeStreamCount++;
1864
- } else if (countRead > 0) {
1865
- // Partial data: smooth tail to avoid hard discontinuities
1866
- const endingOrDrained = stream.streamEnding || stream.inputDrained;
1867
-
1868
- const holdFrameIndex = Math.max(0, framesRead - 1);
1869
- const holdBaseIdx = holdFrameIndex * this.channels;
1870
- let fillIdx = framesRead * this.channels;
1871
- for (let frame = framesRead; frame < RENDER_QUANTUM_SIZE; frame++) {
1872
- for (let ch = 0; ch < this.channels; ch++) {
1873
- this.tempInterleaved[fillIdx++] = this.tempInterleaved[holdBaseIdx + ch];
1874
- }
1875
- }
1876
-
1877
- stream.lastOut.set(this.tempInterleaved);
1878
- stream.hasLastOut = true;
1879
-
1880
- // Render valid frames first with the current fade state
1881
- let sampleIdx = 0;
1882
- for (let frame = 0; frame < framesRead; frame++) {
1883
- if (stream.fadeDirection === 'in') {
1884
- stream.fadeGain = Math.min(1.0, stream.fadeGain + FADE_IN_INCREMENT);
1885
- if (stream.fadeGain >= 1.0) {
1886
- stream.fadeDirection = 'none';
1887
- stream.needsFadeIn = false;
1888
- }
1889
- } else if (stream.fadeDirection === 'out') {
1890
- stream.fadeGain = Math.max(0.0, stream.fadeGain - FADE_OUT_INCREMENT);
1891
- if (stream.fadeGain <= 0.0) {
1892
- stream.fadeDirection = 'none';
1893
- stream.needsFadeOut = false;
1894
- }
1895
- }
1896
- for (let ch = 0; ch < this.channels && ch < outputChannels; ch++) {
1897
- output[ch][frame] += this.tempInterleaved[sampleIdx++] * stream.fadeGain;
1898
- }
1899
- }
1900
-
1901
- // Tail: force fade-out so the transition remains bounded
1902
- if (stream.fadeGain > 0.001) {
1903
- stream.fadeDirection = 'out';
1904
- sampleIdx = framesRead * this.channels;
1905
- for (let frame = framesRead; frame < RENDER_QUANTUM_SIZE; frame++) {
1906
- stream.fadeGain = Math.max(0.0, stream.fadeGain - FADE_OUT_INCREMENT);
1907
- if (stream.fadeGain <= 0.0) {
1908
- stream.fadeDirection = 'none';
1909
- stream.needsFadeOut = false;
1910
- }
1911
- for (let ch = 0; ch < this.channels && ch < outputChannels; ch++) {
1912
- output[ch][frame] += this.tempInterleaved[sampleIdx++] * stream.fadeGain;
1913
- }
1914
- }
1915
- }
1916
-
1917
- stream.playoutInterleavedSamples += countRead;
1918
-
1919
- if (endingOrDrained) {
1920
- if (stream.fadeGain <= 0.001 && stream.streamEnding) {
1921
- stream.state = 'ENDED';
1922
- drainedStreamIds.push(streamId);
1923
- }
1924
- } else {
1925
- // Mark underrun pending - will transition to BUFFERING after fade-out completes
1926
- stream.underrunPending = true;
1927
- if (stream.fadeGain <= 0.001) {
1928
- this.handleUnderrun(streamId, stream);
1929
- }
1930
- }
1931
- activeStreamCount++;
1932
- } else {
1933
- // No data available
1934
- const endingOrDrained = stream.streamEnding || stream.inputDrained;
1935
-
1936
- if (stream.hasLastOut && stream.fadeGain > 0.001) {
1937
- // Continue fade-out using sample-hold from lastOut
1938
- stream.fadeDirection = 'out';
1939
- if (!endingOrDrained) {
1940
- stream.underrunPending = true;
1941
- }
1942
- // Hold the LAST sample constant (not cycling through the buffer)
1943
- const holdBaseIdx = (RENDER_QUANTUM_SIZE - 1) * this.channels;
1944
- for (let frame = 0; frame < RENDER_QUANTUM_SIZE; frame++) {
1945
- stream.fadeGain = Math.max(0.0, stream.fadeGain - FADE_OUT_INCREMENT);
1946
- if (stream.fadeGain <= 0.0) {
1947
- stream.fadeDirection = 'none';
1948
- stream.needsFadeOut = false;
1949
- }
1950
- for (let ch = 0; ch < this.channels && ch < outputChannels; ch++) {
1951
- output[ch][frame] += stream.lastOut[holdBaseIdx + ch] * stream.fadeGain;
1952
- }
1953
- }
1954
- } else if (endingOrDrained && stream.fadeDirection === 'out' && stream.fadeGain > 0.001) {
1955
- for (let frame = 0; frame < RENDER_QUANTUM_SIZE; frame++) {
1956
- stream.fadeGain = Math.max(0.0, stream.fadeGain - FADE_OUT_INCREMENT);
1957
- if (stream.fadeGain <= 0.001) {
1958
- stream.fadeGain = 0;
1959
- stream.fadeDirection = 'none';
1960
- stream.needsFadeOut = false;
1961
- break;
1962
- }
1963
- }
1964
- }
1965
-
1966
- if (endingOrDrained) {
1967
- if (stream.fadeGain <= 0.001) {
1968
- if (stream.streamEnding) {
1969
- stream.state = 'ENDED';
1970
- drainedStreamIds.push(streamId);
1971
- } else if (stream.inputDrained) {
1972
- this.port.postMessage({
1973
- type: 'log',
1974
- level: 'info',
1975
- message: 'PLAYING->BUFFERING (inputDrained), bufferTargetMs=' + stream.bufferTargetMs.toFixed(0) + 'ms',
1976
- streamId
1977
- });
1978
- stream.state = 'BUFFERING';
1979
- stream.needsFadeIn = true;
1980
- }
1981
- }
1982
- } else if (stream.underrunPending && stream.fadeGain <= 0.001) {
1983
- // Fade-out complete, now transition to BUFFERING
1984
- this.handleUnderrun(streamId, stream);
1985
- } else if (!stream.underrunPending && !stream.hasLastOut) {
1986
- // No lastOut to fade from, immediate underrun
1987
- stream.underrunPending = true;
1988
- this.handleUnderrun(streamId, stream);
1989
- }
1990
- }
1991
- }
1992
-
1993
- // Cleanup drained streams
1994
- if (drainedStreamIds.length > 0) {
1995
- for (let i = 0; i < drainedStreamIds.length; i++) {
1996
- const streamId = drainedStreamIds[i];
1997
- // Remove from activeStreamIds/activeStreams using O(1) index lookup + swap-remove
1998
- const idx = this.activeStreamIdIndices.get(streamId);
1999
- if (idx !== undefined) {
2000
- const lastIdx = this.activeStreamIds.length - 1;
2001
- if (idx !== lastIdx) {
2002
- const lastStreamId = this.activeStreamIds[lastIdx];
2003
- this.activeStreamIds[idx] = lastStreamId;
2004
- this.activeStreams[idx] = this.activeStreams[lastIdx];
2005
- this.activeStreamIdIndices.set(lastStreamId, idx);
2006
- }
2007
- this.activeStreamIds.length--;
2008
- this.activeStreams.length--;
2009
- this.activeStreamIdIndices.delete(streamId);
2010
- }
2011
- this.ringBuffers.delete(streamId);
2012
- this.queueBuffers.delete(streamId);
2013
- this.streams.delete(streamId);
2014
- try {
2015
- this._drainedMsg.streamId = streamId;
2016
- this.port.postMessage(this._drainedMsg);
2017
- } catch {
2018
- // ignore
2019
- }
2020
- }
2021
- }
2022
-
2023
- // Combined normalization + soft clipping (single pass)
2024
- const needsNormalization = this.normalizationEnabled && activeStreamCount > 1;
2025
- const normFactor = needsNormalization ? 1.0 / Math.sqrt(activeStreamCount) : 1.0;
2026
- for (let frame = 0; frame < RENDER_QUANTUM_SIZE; frame++) {
2027
- for (let ch = 0; ch < outputChannels; ch++) {
2028
- let v = output[ch][frame];
2029
- if (needsNormalization) {
2030
- v *= normFactor;
2031
- }
2032
- // NaN check: v !== v is true only for NaN; clipping handles ±Infinity
2033
- if (v !== v) v = 0;
2034
- output[ch][frame] = v > 1 ? 1 : v < -1 ? -1 : v;
2035
- }
2036
- }
2037
-
2038
- // Periodic playback-position reports (always on — feeds client->server audibility
2039
- // reporting, which apps use to pace speech to what listeners actually heard)
2040
- this.samplesSincePlaybackReport += RENDER_QUANTUM_SIZE;
2041
- if (this.samplesSincePlaybackReport >= PLAYBACK_REPORT_INTERVAL_SAMPLES) {
2042
- this.samplesSincePlaybackReport = 0;
2043
-
2044
- for (let i = 0; i < this.activeStreamIds.length; i++) {
2045
- const stream = this.activeStreams[i];
2046
- if (!stream || !stream.epochSet) continue;
2047
-
2048
- this._playbackMsg.streamId = this.activeStreamIds[i];
2049
- this._playbackMsg.epoch = stream.currentEpoch;
2050
- this._playbackMsg.playedSeconds = stream.playoutInterleavedSamples / (OUTPUT_SAMPLE_RATE_HZ * this.channels);
2051
- this._playbackMsg.bufferMs = (this.availableSamples(stream) / this.channels) * MS_PER_SAMPLE;
2052
- this.port.postMessage(this._playbackMsg);
2053
- }
2054
- }
2055
-
2056
- // Stats reporting
2057
- if (!this.diagnosticsEnabled) {
2058
- return true;
2059
- }
2060
-
2061
- this.samplesSinceLastStats += RENDER_QUANTUM_SIZE;
2062
- if (this.samplesSinceLastStats >= this.statsIntervalSamples) {
2063
- this.samplesSinceLastStats = 0;
2064
-
2065
- for (let i = 0; i < this.activeStreamIds.length; i++) {
2066
- const streamId = this.activeStreamIds[i];
2067
- const stream = this.activeStreams[i];
2068
- if (!stream) continue;
2069
- const bufferSamples = this.availableSamples(stream) / this.channels;
2070
- const bufferMs = bufferSamples * MS_PER_SAMPLE;
2071
-
2072
- this._statsMsg.streamId = streamId;
2073
- this._statsMsg.bufferMs = bufferMs;
2074
- this._statsMsg.targetMs = stream.bufferTargetMs;
2075
- this._statsMsg.state = stream.state;
2076
- this._statsMsg.inputDrained = stream.inputDrained;
2077
- this._statsMsg.jitterMs = stream.jitterMs;
2078
- this._statsMsg.underrunCount = stream.totalUnderrunCount;
2079
- this._statsMsg.dropCount = stream.totalDropCount;
2080
- this.port.postMessage(this._statsMsg);
2081
- }
2082
- }
2083
-
2084
- return true;
2085
- }
2086
- }
2087
-
2088
- registerProcessor('ikon-audio-player', IkonAudioPlayerProcessor);
2089
- `;
2090
- }
2091
- var Tt = class t {
2092
- client;
2093
- config;
2094
- enabled = !1;
2095
- stateUnsubscribe = null;
2096
- isMobile = c();
2097
- boundVisibilityChange = null;
2098
- boundPageHide = null;
2099
- unlockHandler = null;
2100
- awaitingUnlock = !1;
2101
- recoveryTask = null;
2102
- static RESUME_TIMEOUT_MS = 100;
2103
- static MAX_WORKER_REBUILD_ATTEMPTS = 3;
2104
- workerRebuildAttempts = 0;
2105
- audioContext = null;
2106
- outputSampleRateHz = e;
2107
- audioWorkletNode = null;
2108
- scriptProcessorNode = null;
2109
- scriptDiagnosticsTimer = null;
2110
- workletModuleUrl = null;
2111
- workletModuleKey = null;
2112
- workletReady = null;
2113
- pendingWorkletMessages = [];
2114
- audioWorker = null;
2115
- protocolPort = null;
2116
- mediaSessionHelper = new xt();
2117
- hiddenMuted = !1;
2118
- lastReportedPlaybackState = null;
2119
- lastPlaybackByStream = /* @__PURE__ */ new Map();
2120
- fallbackQueues = /* @__PURE__ */ new Map();
2121
- activeStreams = /* @__PURE__ */ new Set();
2122
- mediaSessionConfig = null;
2123
- constructor(e, t) {
2124
- this.client = e, this.config = t ?? {}, J.debug(`Audio playback initialized, isMobile=${this.isMobile}`);
2125
- }
2126
- setMediaSession(e) {
2127
- this.mediaSessionConfig = e;
2128
- }
2129
- async setEnabled(e, t) {
2130
- if (e && t?.userGesture && this.audioContext) try {
2131
- await this.resumeWithTimeout(this.audioContext), this.audioContext.state === "running" && this.removeUnlockHandler();
2132
- } catch {}
2133
- if (e === this.enabled) {
2134
- e && (await this.ensureAudioGraph(t, { promptForUnlock: !0 }), await this.ensureWorkers());
2135
- return;
2136
- }
2137
- if (this.enabled = e, this.ensureStateSubscription(), !e) {
2138
- this.stopAudioGraph(), this.stopWorkers();
2139
- return;
2140
- }
2141
- await this.ensureAudioGraph(t, { promptForUnlock: !0 }), await this.ensureWorkers();
2142
- }
2143
- enable(e) {
2144
- return this.setEnabled(!0, e);
2145
- }
2146
- disable() {
2147
- return this.setEnabled(!1);
2148
- }
2149
- pause() {
2150
- if (this.audioContext) {
2151
- this.notifyPlaybackActive(!1);
2152
- try {
2153
- this.audioWorkletNode && this.audioWorkletNode.disconnect(), this.scriptProcessorNode && this.scriptProcessorNode.disconnect();
2154
- } catch {}
2155
- }
2156
- }
2157
- resume() {
2158
- if (!this.audioContext) return;
2159
- try {
2160
- this.audioWorkletNode && this.audioWorkletNode.connect(this.audioContext.destination), this.scriptProcessorNode && this.scriptProcessorNode.connect(this.audioContext.destination);
2161
- } catch {}
2162
- let e = this.getContextState(this.audioContext) === "running";
2163
- this.notifyPlaybackActive(e);
2164
- }
2165
- requestRecovery() {
2166
- if (this.enabled && r() && this.audioContext) {
2167
- this.stopAudioGraph();
2168
- try {
2169
- let t = new AudioContext({
2170
- sampleRate: e,
2171
- latencyHint: n
2172
- });
2173
- this.audioContext = t, this.outputSampleRateHz = t.sampleRate, t.resume().catch(() => void 0), this.setupAudioGraphAfterRecreate();
2174
- } catch (e) {
2175
- J.error(`iOS audio recovery failed: ${Y(e)}`), this.addUnlockHandler();
2176
- }
2177
- return;
2178
- }
2179
- }
2180
- async setupAudioGraphAfterRecreate() {
2181
- if (!this.audioContext) return;
2182
- let e = this.audioContext, t = this.resolveDiagnosticsConfig();
2183
- try {
2184
- await this.ensureAudioWorklet(e, t, void 0, { promptForUnlock: !1 });
2185
- } catch {
2186
- this.ensureScriptProcessor(e, t);
2187
- }
2188
- }
2189
- syncStreamsFromGlobalState(e) {
2190
- if (!this.audioWorker) return;
2191
- let t = Object.values(e.AudioStreams ?? {}).map((e) => ({
2192
- senderId: e.ClientSessionId,
2193
- trackId: e.TrackId,
2194
- info: e.Info
2195
- }));
2196
- if (t.length !== 0) try {
2197
- this.audioWorker.postMessage({
2198
- type: "syncStreams",
2199
- streams: t
2200
- });
2201
- } catch {}
2202
- }
2203
- setWebRtcActive(e) {
2204
- if (this.audioWorker) try {
2205
- this.audioWorker.postMessage({
2206
- type: "setWebRtcEnabled",
2207
- enabled: e
2208
- });
2209
- } catch {}
2210
- }
2211
- handleProtocolTransportLost() {
2212
- this.audioWorker && this.stopWorkers();
2213
- }
2214
- dispose() {
2215
- this.enabled = !1, this.activeStreams.clear(), this.removeUnlockHandler(), this.removeVisibilityHandler(), this.stateUnsubscribe?.(), this.stateUnsubscribe = null, this.stopAudioGraph(), this.stopWorkers();
2216
- }
2217
- resolveDiagnosticsConfig() {
2218
- let e = this.config.diagnostics ?? {};
2219
- return {
2220
- enabled: e.enabled ?? Ct.enabled,
2221
- statusIntervalMs: e.statusIntervalMs ?? Ct.statusIntervalMs
2222
- };
2223
- }
2224
- resolveBackgroundConfig() {
2225
- let e = this.config.background ?? {};
2226
- return {
2227
- allowOnDesktop: e.allowOnDesktop ?? !0,
2228
- allowOnMobile: e.allowOnMobile ?? !1
2229
- };
2230
- }
2231
- async ensureAudioGraph(t, i) {
2232
- if (typeof window > "u") return;
2233
- if (!this.audioContext) {
2234
- let t = e, r = n;
2235
- try {
2236
- this.audioContext = new AudioContext({
2237
- sampleRate: t,
2238
- latencyHint: r
2239
- });
2240
- } catch (e) {
2241
- try {
2242
- this.audioContext = new AudioContext({ latencyHint: r });
2243
- } catch (e) {
2244
- try {
2245
- this.audioContext = new AudioContext();
2246
- } catch (e) {
2247
- J.warn(`Failed to create AudioContext: ${Y(e)}`), this.audioContext = null;
2248
- return;
2249
- }
2250
- J.debug(`AudioContext latencyHint unsupported: ${Y(e)}`);
2251
- }
2252
- J.debug(`AudioContext sample rate request unsupported: ${Y(e)}`);
2253
- }
2254
- this.outputSampleRateHz = this.audioContext.sampleRate || 48e3, this.outputSampleRateHz !== t && J.debug(`AudioContext running at ${this.outputSampleRateHz}Hz (requested ${t}Hz)`), this.attachAudioContextHealthHandlers(this.audioContext);
2255
- }
2256
- r() && this.mediaSessionHelper.ensureSilentPlaybackElement();
2257
- let a = this.audioContext, o = this.resolveDiagnosticsConfig();
2258
- if ((this.config.performance?.preferAudioWorklet ?? !0) && s(a)) {
2259
- await this.ensureAudioWorklet(a, o, t, i);
2260
- return;
2261
- }
2262
- this.ensureScriptProcessor(a, o), await this.resumeAudioContextIfPossible(a, t, i), this.rebindWorkerTransportIfNeeded();
2263
- }
2264
- attachAudioContextHealthHandlers(e) {
2265
- e.__ikonAudioHealthAttached !== !0 && (Object.defineProperty(e, "__ikonAudioHealthAttached", {
2266
- value: !0,
2267
- enumerable: !1
2268
- }), e.onstatechange = () => {
2269
- let t = this.getContextState(e), n = t === "running";
2270
- this.notifyPlaybackActive(n), this.enabled && !n && (J.warn(`AudioContext state changed to '${t}', attempting recovery`), this.recoverAudioContext({ reason: "statechange" }));
2271
- }, this.attachVisibilityHandler());
2272
- }
2273
- attachVisibilityHandler() {
2274
- if (this.boundVisibilityChange || typeof document > "u") return;
2275
- let e = this.resolveBackgroundConfig(), t = this.isMobile ? e.allowOnMobile : e.allowOnDesktop;
2276
- t && this.setupMediaSession();
2277
- let n = () => {
2278
- if (!(!this.enabled || !this.audioContext || t)) {
2279
- this.hiddenMuted = !0, this.notifyPlaybackActive(!1);
2280
- try {
2281
- this.audioWorkletNode && this.audioWorkletNode.disconnect(), this.scriptProcessorNode && this.scriptProcessorNode.disconnect();
2282
- } catch {}
2283
- }
2284
- }, r = () => {
2285
- if (!this.enabled || !this.audioContext) return;
2286
- this.hiddenMuted = !1;
2287
- try {
2288
- this.audioWorkletNode && this.audioWorkletNode.connect(this.audioContext.destination), this.scriptProcessorNode && this.scriptProcessorNode.connect(this.audioContext.destination);
2289
- } catch {}
2290
- let e = this.getContextState(this.audioContext) === "running";
2291
- this.notifyPlaybackActive(e);
2292
- }, i = () => {
2293
- if (this.enabled) {
2294
- if (document.visibilityState === "visible") {
2295
- r(), this.audioContext && this.getContextState(this.audioContext) !== "running" && this.recoverAudioContext({ reason: "visibilityVisible" });
2296
- return;
2297
- }
2298
- n();
2299
- }
2300
- }, a = () => {
2301
- n();
2302
- };
2303
- this.boundVisibilityChange = i, this.boundPageHide = a, document.addEventListener("visibilitychange", i), t || window.addEventListener("pagehide", a);
2304
- }
2305
- setupMediaSession() {
2306
- this.mediaSessionHelper.setup(this.mediaSessionConfig ?? void 0, {
2307
- onPlay: () => this.resume(),
2308
- onPause: () => this.pause()
2309
- });
2310
- }
2311
- cleanupMediaSession() {
2312
- this.mediaSessionHelper.cleanup();
2313
- }
2314
- removeVisibilityHandler() {
2315
- typeof document < "u" && this.boundVisibilityChange && document.removeEventListener("visibilitychange", this.boundVisibilityChange), typeof window < "u" && this.boundPageHide && (window.removeEventListener("pagehide", this.boundPageHide), window.removeEventListener("blur", this.boundPageHide)), this.boundVisibilityChange = null, this.boundPageHide = null, this.cleanupMediaSession();
2316
- }
2317
- getContextState(e) {
2318
- return e?.state ?? "suspended";
2319
- }
2320
- addUnlockHandler() {
2321
- if (this.enabled && !this.awaitingUnlock && !(typeof document > "u")) {
2322
- this.awaitingUnlock = !0, this.unlockHandler = () => {
2323
- let e = this.audioContext;
2324
- if (e && this.getContextState(e) !== "running") try {
2325
- e.resume().catch(() => void 0);
2326
- } catch {}
2327
- let t = this.mediaSessionHelper.silentAudioElement;
2328
- if (t && t.paused) try {
2329
- t.play().catch(() => void 0);
2330
- } catch {}
2331
- if ((e ? this.getContextState(e) : "suspended") === "running") {
2332
- this.removeUnlockHandler();
2333
- return;
2334
- }
2335
- this.recoveryTask || this.recoverAudioContext({
2336
- reason: "gesture",
2337
- fromUserGesture: !0
2338
- }).finally(() => {
2339
- let e = this.audioContext;
2340
- e && this.getContextState(e) === "running" && this.removeUnlockHandler();
2341
- });
2342
- };
2343
- for (let e of [
2344
- "touchstart",
2345
- "touchend",
2346
- "click",
2347
- "pointerdown",
2348
- "pointerup",
2349
- "keydown",
2350
- "mouseup"
2351
- ]) document.addEventListener(e, this.unlockHandler, { capture: !0 });
2352
- }
2353
- }
2354
- removeUnlockHandler() {
2355
- if (!this.unlockHandler) {
2356
- this.awaitingUnlock = !1;
2357
- return;
2358
- }
2359
- if (typeof document < "u") for (let e of [
2360
- "touchstart",
2361
- "touchend",
2362
- "click",
2363
- "pointerdown",
2364
- "pointerup",
2365
- "keydown",
2366
- "mouseup"
2367
- ]) document.removeEventListener(e, this.unlockHandler, { capture: !0 });
2368
- this.unlockHandler = null, this.awaitingUnlock = !1, this.reportPlaybackStateIfChanged();
2369
- }
2370
- async resumeWithTimeout(e) {
2371
- let n = e.resume(), r = new Promise((e, n) => {
2372
- setTimeout(() => n(/* @__PURE__ */ Error("AudioContext.resume() timed out")), t.RESUME_TIMEOUT_MS);
2373
- });
2374
- await Promise.race([n, r]);
2375
- }
2376
- async ensureAudioWorklet(e, t, n, r) {
2377
- if (this.audioWorkletNode) {
2378
- await this.resumeAudioContextIfPossible(e, n, r);
2379
- return;
2380
- }
2381
- if (n?.userGesture && this.getContextState(e) !== "running") try {
2382
- await this.resumeWithTimeout(e), this.getContextState(e) === "running" && this.removeUnlockHandler();
2383
- } catch {}
2384
- let a = `${this.outputSampleRateHz}_2`;
2385
- if (!this.workletModuleUrl || this.workletModuleKey !== a) {
2386
- if (this.workletModuleUrl) try {
2387
- URL.revokeObjectURL(this.workletModuleUrl);
2388
- } catch {}
2389
- this.workletModuleKey = a, this.workletReady = null, this.workletModuleUrl = URL.createObjectURL(new Blob([wt({
2390
- outputSampleRateHz: this.outputSampleRateHz,
2391
- outputChannels: 2
2392
- })], { type: "text/javascript" }));
2393
- }
2394
- this.workletReady ||= e.audioWorklet.addModule(this.workletModuleUrl).catch((e) => {
2395
- throw J.warn(`Failed to load AudioWorklet module, falling back: ${Y(e)}`), e;
2396
- });
2397
- try {
2398
- await this.workletReady;
2399
- } catch {
2400
- this.workletReady = null, this.ensureScriptProcessor(e, t);
2401
- return;
2402
- }
2403
- this.stopScriptProcessor();
2404
- let o = (this.config.performance?.preferSharedArrayBuffer ?? !0) && i();
2405
- this.audioWorkletNode = new AudioWorkletNode(e, "ikon-audio-player", {
2406
- numberOfInputs: 0,
2407
- numberOfOutputs: 1,
2408
- outputChannelCount: [2],
2409
- processorOptions: {
2410
- outputAudioConfig: { diagnostics: t },
2411
- useSharedArrayBuffer: o,
2412
- outputChannels: 2
2413
- }
2414
- }), this.audioWorkletNode.onprocessorerror = () => {
2415
- J.error("Audio playback worklet processor crashed, rebuilding audio pipeline"), this.stopAudioWorklet(), this.setupAudioGraphAfterRecreate();
2416
- }, this.audioWorkletNode.port.onmessage = (e) => {
2417
- let n = e.data;
2418
- if (!(!n || typeof n != "object")) {
2419
- if (n.type === "log") {
2420
- let e = n, t = e.streamId ? ` [stream=${e.streamId.substring(0, 8)}]` : "";
2421
- e.level === "error" ? J.error(`[Worklet]${t} ${e.message}`) : e.level === "warn" ? J.warn(`[Worklet]${t} ${e.message}`) : J.info(`[Worklet]${t} ${e.message}`);
2422
- return;
2423
- }
2424
- if (n.type === "stats") {
2425
- if (!t.enabled) return;
2426
- let e = n;
2427
- J.debug(`[Audio] stream=${e.streamId.substring(0, 8)} state=${e.state} buffer=${e.bufferMs.toFixed(0)}ms target=${e.targetMs.toFixed(0)}ms jitter=${e.jitterMs.toFixed(1)}ms underrun=${e.underrunCount} drop=${e.dropCount}`);
2428
- return;
2429
- }
2430
- if (n.type === "playback") {
2431
- let e = n;
2432
- this.lastPlaybackByStream.set(e.streamId, {
2433
- epoch: e.epoch,
2434
- playedSeconds: e.playedSeconds,
2435
- bufferMs: e.bufferMs
2436
- }), this.sendPlaybackReport(e.streamId, e.epoch, e.playedSeconds, e.bufferMs);
2437
- return;
2438
- }
2439
- if (n.type === "streamDrained" && "streamId" in n && typeof n.streamId == "string") {
2440
- let e = n.streamId;
2441
- this.activeStreams.delete(e), this.lastPlaybackByStream.delete(e), this.activeStreams.size === 0 && this.removeUnlockHandler();
2442
- return;
2443
- }
2444
- }
2445
- }, this.audioWorkletNode.connect(e.destination), this.stopScriptProcessorDiagnostics(), await this.resumeAudioContextIfPossible(e, n, r), this.rebindWorkerTransportIfNeeded();
2446
- let s = this.pendingWorkletMessages.splice(0);
2447
- for (let e of s) this.postToWorklet(e);
2448
- let c = this.getContextState(e) === "running";
2449
- this.notifyPlaybackActive(c);
2450
- }
2451
- ensureScriptProcessor(e, t) {
2452
- if (this.scriptProcessorNode) return;
2453
- this.stopAudioWorklet(), this.pendingWorkletMessages = [];
2454
- let n = 1024, r = new Float32Array(n * 2), i = Math.round(this.outputSampleRateHz * 100 / 1e3), a = Math.round(this.outputSampleRateHz * 50 / 1e3), o = 1 / i, s = 1 / a, c = [, ,], l = [], u = e.createScriptProcessor(n, 0, 2);
2455
- u.onaudioprocess = (e) => {
2456
- let t = e.outputBuffer, n = t.numberOfChannels, i = t.length;
2457
- for (let e = 0; e < n; e++) {
2458
- let n = t.getChannelData(e);
2459
- n.fill(0), c[e] = n;
2460
- }
2461
- let a = 0;
2462
- l.length = 0;
2463
- for (let [e, t] of this.fallbackQueues.entries()) {
2464
- t.totalSamples > 0 && (a += 1), (t.ending || t.inputDrained) && t.fadeDirection !== "out" && t.totalSamples / n * 1e3 / this.outputSampleRateHz <= 100 && (t.fadeDirection = "out"), this.readFromFallbackQueue(t, r), (t.totalSamples > 0 || !t.hasLastOut) && ((!t.lastOut || t.lastOut.length !== r.length) && (t.lastOut = new Float32Array(r.length)), t.lastOut.set(r), t.hasLastOut = !0);
2465
- for (let e = 0; e < i; e++) {
2466
- t.fadeDirection === "in" ? (t.fadeGain = Math.min(1, t.fadeGain + o), t.fadeGain >= 1 && (t.fadeDirection = "none")) : t.fadeDirection === "out" && (t.fadeGain = Math.max(0, t.fadeGain - s), t.fadeGain <= 0 && (t.fadeDirection = "none"));
2467
- for (let i = 0; i < n; i++) {
2468
- let a = r[e * n + i];
2469
- c[i][e] += a * t.fadeGain;
2470
- }
2471
- }
2472
- let u = t.ending || t.inputDrained;
2473
- if (u && t.totalSamples <= 0) {
2474
- if (t.fadeDirection === "out" && t.fadeGain > .001) {
2475
- for (let e = 0; e < i; e++) if (t.fadeGain = Math.max(0, t.fadeGain - s), t.fadeGain <= .001) {
2476
- t.fadeGain = 0, t.fadeDirection = "none";
2477
- break;
2478
- }
2479
- }
2480
- t.fadeGain <= .001 && t.ending && l.push(e);
2481
- } else if (!u && t.totalSamples <= 0 && t.hasLastOut && t.lastOut && t.fadeGain > .001) {
2482
- t.fadeDirection = "out", t.underrunPending = !0;
2483
- let e = t.lastOut, r = i - 1;
2484
- for (let a = 0; a < i; a++) {
2485
- t.fadeGain = Math.max(0, t.fadeGain - s), t.fadeGain <= 0 && (t.fadeDirection = "none");
2486
- for (let i = 0; i < n; i++) {
2487
- let o = e[r * n + i];
2488
- c[i][a] += o * t.fadeGain;
2489
- }
2490
- }
2491
- }
2492
- }
2493
- if (l.length > 0) {
2494
- for (let e of l) this.fallbackQueues.delete(e), this.activeStreams.delete(e);
2495
- this.activeStreams.size === 0 && this.removeUnlockHandler();
2496
- }
2497
- if (a > 1) {
2498
- let e = 1 / Math.sqrt(a);
2499
- for (let t = 0; t < i; t++) for (let r = 0; r < n; r++) c[r][t] *= e;
2500
- }
2501
- for (let e = 0; e < i; e++) for (let t = 0; t < n; t++) {
2502
- let n = c[t][e];
2503
- c[t][e] = n > 1 ? 1 : n < -1 ? -1 : n;
2504
- }
2505
- }, u.connect(e.destination), this.scriptProcessorNode = u, this.ensureScriptProcessorDiagnostics(t);
2506
- }
2507
- compactFallbackQueue(e) {
2508
- if (e.headIndex <= 32 || e.headIndex <= e.chunks.length / 2) return;
2509
- let t = e.chunks.length - e.headIndex;
2510
- for (let n = 0; n < t; n++) e.chunks[n] = e.chunks[e.headIndex + n];
2511
- e.chunks.length = t, e.headIndex = 0;
2512
- }
2513
- skipFromFallbackQueue(e, t) {
2514
- if (t <= 0) return;
2515
- let n = t;
2516
- for (; n > 0 && e.headIndex < e.chunks.length;) {
2517
- let t = e.chunks[e.headIndex], r = t.length - e.offset, i = Math.min(r, n);
2518
- e.offset += i, e.totalSamples -= i, n -= i, e.offset >= t.length && (e.headIndex += 1, e.offset = 0);
2519
- }
2520
- e.totalSamples < 0 && (e.totalSamples = 0), this.compactFallbackQueue(e);
2521
- }
2522
- trimFallbackQueue(e) {
2523
- let t = Math.floor(this.outputSampleRateHz * 2 * o / 1e3), n = e.totalSamples - t;
2524
- n <= 0 || this.skipFromFallbackQueue(e, n);
2525
- }
2526
- stopScriptProcessorDiagnostics() {
2527
- this.scriptDiagnosticsTimer &&= (clearInterval(this.scriptDiagnosticsTimer), null);
2528
- }
2529
- ensureScriptProcessorDiagnostics(e) {
2530
- if (!e.enabled) {
2531
- this.stopScriptProcessorDiagnostics();
2532
- return;
2533
- }
2534
- if (this.scriptDiagnosticsTimer) return;
2535
- let t = Math.max(250, e.statusIntervalMs);
2536
- this.scriptDiagnosticsTimer = setInterval(() => {
2537
- if (this.scriptProcessorNode) for (let [e, t] of this.fallbackQueues.entries()) {
2538
- if (t.totalSamples <= 0) continue;
2539
- let n = t.totalSamples / 2 * 1e3 / this.outputSampleRateHz;
2540
- J.debug(`[Audio] stream=${e.substring(0, 8)} buffer=${n.toFixed(0)}ms renderer=ScriptProcessor`);
2541
- }
2542
- }, t);
2543
- }
2544
- readFromFallbackQueue(e, t) {
2545
- let n = 0;
2546
- for (; n < t.length && e.headIndex < e.chunks.length;) {
2547
- let r = e.chunks[e.headIndex], i = r.length - e.offset, a = Math.min(i, t.length - n);
2548
- t.set(r.subarray(e.offset, e.offset + a), n), n += a, e.offset += a, e.totalSamples = Math.max(0, e.totalSamples - a), e.offset >= r.length && (e.headIndex += 1, e.offset = 0);
2549
- }
2550
- n < t.length && t.fill(0, n), this.compactFallbackQueue(e);
2551
- }
2552
- async resumeAudioContextIfPossible(e, t, n) {
2553
- if (this.getContextState(e) === "running") {
2554
- this.removeUnlockHandler();
2555
- return;
2556
- }
2557
- let r = n?.promptForUnlock ?? !0;
2558
- if (!(t?.userGesture ?? !1)) {
2559
- if (!r) return;
2560
- this.addUnlockHandler();
2561
- return;
2562
- }
2563
- try {
2564
- await this.resumeWithTimeout(e), this.removeUnlockHandler();
2565
- } catch (e) {
2566
- J.warn(`Failed to resume AudioContext: ${Y(e)}`), this.addUnlockHandler();
2567
- }
2568
- }
2569
- async recoverAudioContext(e) {
2570
- if (e.fromUserGesture && this.recoveryTask && this.audioContext) try {
2571
- if (await this.resumeWithTimeout(this.audioContext), this.audioContext.state === "running") {
2572
- this.removeUnlockHandler();
2573
- return;
2574
- }
2575
- } catch {}
2576
- if (this.recoveryTask) {
2577
- await this.recoveryTask;
2578
- return;
2579
- }
2580
- this.recoveryTask = this.recoverAudioContextInternal(e).finally(() => {
2581
- this.recoveryTask = null;
2582
- }), await this.recoveryTask;
2583
- }
2584
- async recoverAudioContextInternal(e) {
2585
- if (!this.enabled) return;
2586
- let t = this.activeStreams.size > 0, n = this.audioContext;
2587
- if (!n) {
2588
- if (!t) return;
2589
- await this.ensureAudioGraph(void 0, { promptForUnlock: !0 });
2590
- return;
2591
- }
2592
- if (n.sampleRate !== this.outputSampleRateHz) {
2593
- J.warn(`AudioContext sample rate drifted (${n.sampleRate} Hz vs worklet ${this.outputSampleRateHz} Hz), rebuilding audio graph`), this.stopAudioGraph(), t && await this.ensureAudioGraph(void 0, { promptForUnlock: !0 });
2594
- return;
2595
- }
2596
- if (this.getContextState(n) === "running") {
2597
- this.removeUnlockHandler();
2598
- return;
2599
- }
2600
- if (t) {
2601
- try {
2602
- if (await this.resumeWithTimeout(n), this.getContextState(n) === "running") {
2603
- this.removeUnlockHandler();
2604
- return;
2605
- }
2606
- } catch (t) {
2607
- J.debug(`AudioContext resume failed or timed out (${e.reason}): ${t}`);
2608
- }
2609
- this.addUnlockHandler();
2610
- }
2611
- }
2612
- rebindWorkerTransportIfNeeded() {
2613
- if (!this.audioWorker || !this.audioContext) return;
2614
- let e = (this.config.performance?.preferSharedArrayBuffer ?? !0) && this.audioWorkletNode && i() ? "sab" : "pcm";
2615
- try {
2616
- this.audioWorker.postMessage({
2617
- type: "rebind",
2618
- transport: e,
2619
- outputSampleRate: this.outputSampleRateHz,
2620
- outputChannels: 2
2621
- });
2622
- } catch {}
2623
- }
2624
- async ensureWorkers() {
2625
- if (this.audioWorker) return;
2626
- if (typeof Worker > "u") {
2627
- J.warn("Audio decode worker unavailable (Workers not supported)");
2628
- return;
2629
- }
2630
- let e = this.client.createProtocolMessagePort({ opcodeGroupsMask: l.GROUP_AUDIO });
2631
- if (!e) return;
2632
- this.protocolPort = e;
2633
- try {
2634
- this.audioWorker = new St();
2635
- } catch (e) {
2636
- J.warn(`Failed to create audio worker: ${Y(e)}`), this.protocolPort.close(), this.protocolPort = null;
2637
- return;
2638
- }
2639
- let t = this.audioWorker;
2640
- t.addEventListener("message", (e) => this.onAudioWorkerMessage(e.data)), t.addEventListener("error", (e) => {
2641
- let t = [
2642
- e.message,
2643
- e.filename,
2644
- e.lineno,
2645
- e.colno
2646
- ].filter((e) => e != null && String(e).length > 0);
2647
- J.error(`Audio worker failed: ${t.join(" ")}`.trim()), this.handleWorkerCrash();
2648
- });
2649
- let n = (this.config.performance?.preferSharedArrayBuffer ?? !0) && !!this.audioWorkletNode && i(), r = this.config.performance?.preferWebCodecs ?? !0, a = this.client.isWebRtcMediaActive, o = {
2650
- type: "configure",
2651
- transport: n ? "sab" : "pcm",
2652
- outputSampleRate: this.outputSampleRateHz,
2653
- outputChannels: 2,
2654
- preferWebCodecs: r,
2655
- webRtcEnabled: a
2656
- };
2657
- t.postMessage(o), t.postMessage({
2658
- type: "attachProtocolPort",
2659
- port: e.port
2660
- }, [e.port]);
2661
- let s = this.client.globalState;
2662
- s && this.syncStreamsFromGlobalState(s);
2663
- let c = this.audioWorkletNode ? "AudioWorklet" : "ScriptProcessor", u = n ? "SharedArrayBuffer" : "MessagePort", d = a ? "WebRTC (native)" : r && typeof AudioDecoder < "u" ? "WebCodecs" : "WASM Opus";
2664
- J.debug(`Audio initialized: renderer=${c}, transport=${u}, decoder=${d}, output=${this.outputSampleRateHz}Hz/2ch`);
2665
- }
2666
- onAudioWorkerMessage(e) {
2667
- if (e.type === "streamBegin") {
2668
- this.activeStreams.add(e.streamId);
2669
- let t = this.audioContext;
2670
- if (this.enabled && t && this.getContextState(t) !== "running" && this.recoverAudioContext({ reason: "streamBegin" }), this.audioWorkletNode) {
2671
- this.postToWorklet({
2672
- type: "streamBegin",
2673
- streamId: e.streamId,
2674
- sharedArrayBuffer: e.sharedArrayBuffer
2675
- });
2676
- return;
2677
- }
2678
- this.fallbackQueues.set(e.streamId, {
2679
- chunks: [],
2680
- headIndex: 0,
2681
- offset: 0,
2682
- totalSamples: 0,
2683
- ending: !1,
2684
- inputDrained: !1,
2685
- fadeGain: 0,
2686
- fadeDirection: "in",
2687
- lastOut: null,
2688
- hasLastOut: !1,
2689
- underrunPending: !1
2690
- });
2691
- return;
2692
- }
2693
- if (e.type === "streamEnd") {
2694
- let t = this.fallbackQueues.get(e.streamId);
2695
- if (t) {
2696
- t.ending = !0, t.totalSamples <= 0 && (this.fallbackQueues.delete(e.streamId), this.activeStreams.delete(e.streamId), this.activeStreams.size === 0 && this.removeUnlockHandler());
2697
- return;
2698
- }
2699
- if (this.audioWorkletNode) {
2700
- this.postToWorklet({
2701
- type: "streamEnd",
2702
- streamId: e.streamId
2703
- });
2704
- return;
2705
- }
2706
- this.activeStreams.delete(e.streamId), this.activeStreams.size === 0 && this.removeUnlockHandler();
2707
- return;
2708
- }
2709
- if (e.type === "pcm") {
2710
- if (this.audioWorkletNode) {
2711
- this.postToWorklet({
2712
- type: "pcm",
2713
- streamId: e.streamId,
2714
- pcm: e.pcm
2715
- }, [e.pcm.buffer]);
2716
- return;
2717
- }
2718
- let t = this.fallbackQueues.get(e.streamId);
2719
- t && (t.underrunPending && t.totalSamples === 0 && (t.fadeGain = 0, t.fadeDirection = "in", t.underrunPending = !1), t.chunks.push(e.pcm), t.totalSamples += e.pcm.length, this.trimFallbackQueue(t));
2720
- return;
2721
- }
2722
- if (e.type === "frame") {
2723
- let t = this.fallbackQueues.get(e.streamId);
2724
- t && (t.inputDrained && !e.isFirst && (t.inputDrained = !1, t.fadeGain = 0, t.fadeDirection = "in", t.underrunPending = !1), e.isFirst && (t.inputDrained = !1, t.fadeGain = 0, t.fadeDirection = "in", t.underrunPending = !1), e.isLast && (t.inputDrained = !0)), this.postToWorklet({
2725
- type: "frame",
2726
- streamId: e.streamId,
2727
- epoch: e.epoch,
2728
- timestampInterleavedSamples: e.timestampInterleavedSamples,
2729
- frameSizeInterleavedSamples: e.frameSizeInterleavedSamples,
2730
- isFirst: e.isFirst,
2731
- isLast: e.isLast,
2732
- jitterMs: e.jitterMs
2733
- });
2734
- return;
2735
- }
2736
- e.type === "error" && J.warn(`Audio worker error${e.streamId ? ` (stream ${e.streamId})` : ""}: ${e.error.message}`);
2737
- }
2738
- postToWorklet(e, t) {
2739
- if (!this.audioWorkletNode) {
2740
- if (this.scriptProcessorNode) return;
2741
- this.enqueuePendingWorkletMessage(e);
2742
- return;
2743
- }
2744
- try {
2745
- this.audioWorkletNode.port.postMessage(e, t ?? []);
2746
- } catch {
2747
- this.enqueuePendingWorkletMessage(e);
2748
- }
2749
- }
2750
- notifyPlaybackActive(e) {
2751
- this.postToWorklet({
2752
- type: "playbackActive",
2753
- active: e
2754
- }), this.reportPlaybackStateIfChanged();
2755
- }
2756
- computePlaybackState() {
2757
- let e = this.audioContext;
2758
- return !e || this.getContextState(e) !== "running" || this.awaitingUnlock ? z.Blocked : this.hiddenMuted ? z.Hidden : z.Playing;
2759
- }
2760
- sendPlaybackReport(e, t, n, r) {
2761
- let i = e.indexOf("_");
2762
- if (i <= 0) return;
2763
- let a = Number(e.substring(0, i)), o = Number(e.substring(i + 1));
2764
- if (!Number.isFinite(a) || !Number.isFinite(o)) return;
2765
- let s = this.computePlaybackState();
2766
- this.lastReportedPlaybackState = s;
2767
- try {
2768
- let e = V({
2769
- Epoch: t,
2770
- PlayedSeconds: n,
2771
- BufferedMs: r,
2772
- State: s
2773
- });
2774
- this.client.sendProtocolMessage(H(e, this.client.sessionId ?? 0, {
2775
- trackId: o,
2776
- targetIds: [a]
2777
- }));
2778
- } catch {}
2779
- }
2780
- reportPlaybackStateIfChanged() {
2781
- let e = this.computePlaybackState();
2782
- if (e !== this.lastReportedPlaybackState) {
2783
- for (let [e, t] of this.lastPlaybackByStream) this.sendPlaybackReport(e, t.epoch, t.playedSeconds, t.bufferMs);
2784
- this.lastReportedPlaybackState = e;
2785
- }
2786
- }
2787
- enqueuePendingWorkletMessage(e) {
2788
- if (e.type === "streamBegin") {
2789
- let t = this.pendingWorkletMessages.findIndex((t) => t.type === "streamBegin" && t.streamId === e.streamId);
2790
- t >= 0 && this.pendingWorkletMessages.splice(t, 1);
2791
- }
2792
- if (this.pendingWorkletMessages.push(e), !(this.pendingWorkletMessages.length <= 512)) for (; !(this.pendingWorkletMessages.length <= 512);) {
2793
- let e = this.pendingWorkletMessages.findIndex((e) => e.type !== "streamBegin");
2794
- if (e < 0) break;
2795
- this.pendingWorkletMessages.splice(e, 1);
2796
- }
2797
- }
2798
- stopAudioWorklet() {
2799
- if (this.audioWorkletNode) {
2800
- try {
2801
- this.audioWorkletNode.disconnect();
2802
- } catch {}
2803
- this.audioWorkletNode = null;
2804
- }
2805
- }
2806
- stopScriptProcessor() {
2807
- if (this.scriptProcessorNode) {
2808
- try {
2809
- this.scriptProcessorNode.disconnect();
2810
- } catch {}
2811
- this.scriptProcessorNode.onaudioprocess = null, this.scriptProcessorNode = null;
2812
- }
2813
- this.stopScriptProcessorDiagnostics();
2814
- }
2815
- stopAudioGraph() {
2816
- if (this.stopAudioWorklet(), this.stopScriptProcessor(), this.fallbackQueues.clear(), this.audioContext &&= (this.audioContext.close().catch(() => void 0), null), this.workletModuleUrl) {
2817
- try {
2818
- URL.revokeObjectURL(this.workletModuleUrl);
2819
- } catch {}
2820
- this.workletModuleUrl = null, this.workletModuleKey = null;
2821
- }
2822
- this.workletReady = null, this.pendingWorkletMessages = [];
2823
- }
2824
- handleWorkerCrash() {
2825
- if (this.stopWorkers(), this.workerRebuildAttempts >= t.MAX_WORKER_REBUILD_ATTEMPTS) {
2826
- J.error("Audio worker crashed repeatedly, giving up on rebuilds");
2827
- return;
2828
- }
2829
- this.workerRebuildAttempts++, this.ensureWorkers().then(() => {
2830
- let e = this.client.globalState;
2831
- e && this.syncStreamsFromGlobalState(e);
2832
- });
2833
- }
2834
- stopWorkers() {
2835
- let e = Array.from(this.activeStreams);
2836
- if (this.audioWorker) {
2837
- try {
2838
- this.audioWorker.postMessage({ type: "dispose" });
2839
- } catch {}
2840
- try {
2841
- this.audioWorker.terminate();
2842
- } catch {}
2843
- this.audioWorker = null;
2844
- }
2845
- if (this.protocolPort &&= (this.protocolPort.close(), null), this.audioWorkletNode) for (let t of e) this.postToWorklet({
2846
- type: "streamEnd",
2847
- streamId: t
2848
- });
2849
- this.activeStreams.clear(), this.fallbackQueues.clear(), this.removeUnlockHandler();
2850
- }
2851
- ensureStateSubscription() {
2852
- this.stateUnsubscribe ||= this.client.subscribeToState((e) => {
2853
- if (this.enabled) {
2854
- if (e === "connected" || e === "reconnecting") {
2855
- this.ensureWorkers();
2856
- return;
2857
- }
2858
- (e === "idle" || e === "offline" || e === "offlineError" || e === "connecting" || e === "connectingSlow") && this.stopWorkers();
2859
- }
2860
- });
2861
- }
2862
- };
2863
- //#endregion
2864
- //#region src/worker/video-playback-worker.ts?worker
2865
- function Et(e) {
2866
- return new Worker("" + new URL("assets/video-playback-worker-DqNjooZJ.js", import.meta.url).href, {
2867
- type: "module",
2868
- name: e?.name
2869
- });
2870
- }
2871
- //#endregion
2872
- //#region src/media/ikon-video-playback.ts
2873
- var X = t("IkonVideoPlayback");
2874
- function Z(e) {
2875
- return e instanceof Error ? `${e.name}: ${e.message}` : String(e);
2876
- }
2877
- var Q = class e {
2878
- static MAX_WORKER_REBUILD_ATTEMPTS = 3;
2879
- client;
2880
- config;
2881
- enabled = !0;
2882
- workerRebuildAttempts = 0;
2883
- stateUnsubscribe = null;
2884
- worker = null;
2885
- protocolPort = null;
2886
- surfaces = /* @__PURE__ */ new Map();
2887
- constructor(e, t) {
2888
- this.client = e, this.config = t ?? {}, this.ensureStateSubscription();
2889
- }
2890
- async attachCanvas(e, t) {
2891
- if (!e || typeof e != "string") throw Error("streamId is required");
2892
- this.detachCanvas(e);
2893
- let n = this.canUseOffscreenCanvas(t) ? "offscreen" : "bitmap", r = null, i = null;
2894
- if (n === "bitmap" && (i = t.getContext("bitmaprenderer", { alpha: !1 }), i || (r = t.getContext("2d", {
2895
- alpha: !1,
2896
- desynchronized: !0
2897
- }))), this.surfaces.set(e, {
2898
- canvas: t,
2899
- ctx2d: r,
2900
- ctxBitmap: i,
2901
- mode: n,
2902
- attachedToWorker: !1
2903
- }), this.ensureStateSubscription(), !this.enabled) {
2904
- X.warn(`Canvas for stream ${e} not attached to the worker: video playback is disabled`);
2905
- return;
2906
- }
2907
- await this.ensureWorker(), this.ensureProtocolPort(), this.syncStreamToWorker(e), this.surfaces.get(e)?.attachedToWorker || X.warn(`Canvas for stream ${e} did not reach the worker; it will stay blank`);
2908
- }
2909
- detachCanvas(e) {
2910
- let t = this.surfaces.get(e);
2911
- if (t && (this.surfaces.delete(e), this.worker)) try {
2912
- this.worker.postMessage({
2913
- type: "unwatchStream",
2914
- streamId: e
2915
- }), t.mode === "offscreen" && this.worker.postMessage({
2916
- type: "detachSurface",
2917
- streamId: e
2918
- });
2919
- } catch {}
2920
- }
2921
- async setEnabled(e) {
2922
- if (this.enabled = e, this.ensureStateSubscription(), !e) {
2923
- if (this.worker) try {
2924
- this.worker.postMessage({
2925
- type: "setEnabled",
2926
- enabled: !1
2927
- });
2928
- } catch {}
2929
- this.detachProtocolPort();
2930
- return;
2931
- }
2932
- if (await this.ensureWorker(), this.ensureProtocolPort(), this.worker) {
2933
- try {
2934
- this.worker.postMessage({
2935
- type: "setEnabled",
2936
- enabled: !0
2937
- });
2938
- } catch {}
2939
- this.syncAllStreamsToWorker();
2940
- }
2941
- }
2942
- dispose() {
2943
- this.enabled = !1, this.stateUnsubscribe?.(), this.stateUnsubscribe = null, this.surfaces.clear(), this.stopWorker();
2944
- }
2945
- canUseOffscreenCanvas(e) {
2946
- return this.config.performance?.preferOffscreenCanvas ?? !0 ? "transferControlToOffscreen" in e && typeof e.transferControlToOffscreen == "function" : !1;
2947
- }
2948
- async ensureWorker() {
2949
- if (!this.enabled || this.worker) return;
2950
- if (typeof Worker > "u") {
2951
- X.warn("Video decode worker unavailable (Workers not supported)");
2952
- return;
2953
- }
2954
- let e;
2955
- try {
2956
- e = new Et();
2957
- } catch (e) {
2958
- X.warn(`Failed to create video worker: ${Z(e)}`);
2959
- return;
2960
- }
2961
- this.worker = e, e.addEventListener("message", (e) => this.onWorkerMessage(e.data)), e.addEventListener("error", (e) => {
2962
- let t = [
2963
- e.message,
2964
- e.filename,
2965
- e.lineno,
2966
- e.colno
2967
- ].filter((e) => e != null && String(e).length > 0);
2968
- X.error(`Video worker failed: ${t.join(" ")}`.trim()), this.handleWorkerCrash();
2969
- }), e.postMessage({
2970
- type: "configure",
2971
- webRtcEnabled: this.client.isWebRtcMediaActive
2972
- }), e.postMessage({
2973
- type: "setEnabled",
2974
- enabled: this.enabled
2975
- }), this.syncAllStreamsToWorker();
2976
- let t = this.client.globalState;
2977
- t && this.syncStreamsFromGlobalState(t);
2978
- }
2979
- onWorkerMessage(e) {
2980
- if (e.type !== "streamBegin" && e.type !== "streamEnd") {
2981
- if (e.type === "frame") {
2982
- let t = this.surfaces.get(e.streamId);
2983
- if (!t || t.mode !== "bitmap") {
2984
- try {
2985
- e.bitmap.close();
2986
- } catch {}
2987
- return;
2988
- }
2989
- if (t.ctxBitmap) {
2990
- try {
2991
- t.ctxBitmap.transferFromImageBitmap(e.bitmap);
2992
- } catch {}
2993
- return;
2994
- }
2995
- if (!t.ctx2d) {
2996
- try {
2997
- e.bitmap.close();
2998
- } catch {}
2999
- return;
3000
- }
3001
- (t.canvas.width !== e.width || t.canvas.height !== e.height) && (t.canvas.width = e.width, t.canvas.height = e.height);
3002
- try {
3003
- t.ctx2d.drawImage(e.bitmap, 0, 0, e.width, e.height);
3004
- } finally {
3005
- try {
3006
- e.bitmap.close();
3007
- } catch {}
3008
- }
3009
- return;
3010
- }
3011
- if (e.type === "requestIdr") {
3012
- this.requestIdrForStream(e.senderId, e.trackId);
3013
- return;
3014
- }
3015
- if (e.type === "error") {
3016
- X.warn(`Video worker error: ${e.error.message}`);
3017
- return;
3018
- }
3019
- e.type === "log" ? X.info(e.message) : e.type === "debug" && X.debug(e.message);
3020
- }
3021
- }
3022
- syncAllStreamsToWorker() {
3023
- for (let e of this.surfaces.keys()) this.syncStreamToWorker(e);
3024
- }
3025
- syncStreamToWorker(e) {
3026
- if (!this.worker) return;
3027
- let t = this.surfaces.get(e);
3028
- if (t && !t.attachedToWorker) {
3029
- if (t.mode === "offscreen") {
3030
- try {
3031
- let n = t.canvas.transferControlToOffscreen();
3032
- this.worker.postMessage({
3033
- type: "attachSurface",
3034
- streamId: e,
3035
- canvas: n
3036
- }, [n]), t.attachedToWorker = !0;
3037
- } catch (n) {
3038
- X.warn(`Failed to attach offscreen canvas for stream ${e}: ${Z(n)}`), t.mode = "bitmap", t.ctxBitmap = t.canvas.getContext("bitmaprenderer", { alpha: !1 }), t.ctxBitmap || (t.ctx2d = t.canvas.getContext("2d", {
3039
- alpha: !1,
3040
- desynchronized: !0
3041
- }));
3042
- try {
3043
- this.worker.postMessage({
3044
- type: "watchStream",
3045
- streamId: e
3046
- }), t.attachedToWorker = !0;
3047
- } catch {}
3048
- }
3049
- return;
3050
- }
3051
- try {
3052
- this.worker.postMessage({
3053
- type: "watchStream",
3054
- streamId: e
3055
- }), t.attachedToWorker = !0;
3056
- } catch {}
3057
- }
3058
- }
3059
- requestIdrForStream(e, t) {
3060
- let n = et(Qe(), this.client.sessionId ?? 0, {
3061
- trackId: t,
3062
- targetIds: [e]
3063
- });
3064
- this.client.sendProtocolMessage(n);
3065
- }
3066
- detachProtocolPort() {
3067
- if (this.protocolPort) {
3068
- try {
3069
- this.protocolPort.close();
3070
- } catch {}
3071
- this.protocolPort = null;
3072
- }
3073
- }
3074
- ensureProtocolPort() {
3075
- if (!this.worker || this.protocolPort) return;
3076
- let e = this.client.createProtocolMessagePort({ opcodeGroupsMask: l.GROUP_VIDEO });
3077
- if (e) {
3078
- this.protocolPort = e;
3079
- try {
3080
- this.worker.postMessage({
3081
- type: "attachProtocolPort",
3082
- port: e.port
3083
- }, [e.port]);
3084
- } catch (e) {
3085
- X.warn(`Failed to attach video protocol port: ${Z(e)}`), this.protocolPort.close(), this.protocolPort = null;
3086
- }
3087
- }
3088
- }
3089
- syncStreamsFromGlobalState(e) {
3090
- if (!this.worker) return;
3091
- let t = Object.values(e.VideoStreams ?? {}).map((e) => ({
3092
- senderId: e.ClientSessionId,
3093
- trackId: e.TrackId,
3094
- info: e.Info
3095
- }));
3096
- if (t.length !== 0) try {
3097
- this.worker.postMessage({
3098
- type: "syncStreams",
3099
- streams: t
3100
- });
3101
- } catch {}
3102
- }
3103
- setWebRtcActive(e) {
3104
- if (this.worker) try {
3105
- this.worker.postMessage({
3106
- type: "setWebRtcEnabled",
3107
- enabled: e
3108
- });
3109
- } catch {}
3110
- }
3111
- handleProtocolTransportLost() {
3112
- this.worker && this.stopWorker();
3113
- }
3114
- handleWorkerCrash() {
3115
- if (this.stopWorker(), this.workerRebuildAttempts >= e.MAX_WORKER_REBUILD_ATTEMPTS) {
3116
- X.error("Video worker crashed repeatedly, giving up on rebuilds");
3117
- return;
3118
- }
3119
- this.workerRebuildAttempts++, this.ensureWorker().then(() => this.ensureProtocolPort());
3120
- }
3121
- stopWorker() {
3122
- if (this.detachProtocolPort(), this.worker) {
3123
- try {
3124
- this.worker.postMessage({ type: "dispose" });
3125
- } catch {}
3126
- try {
3127
- this.worker.terminate();
3128
- } catch {}
3129
- this.worker = null;
3130
- }
3131
- }
3132
- ensureStateSubscription() {
3133
- this.stateUnsubscribe ||= this.client.subscribeToState((e) => {
3134
- if (this.enabled) {
3135
- if (e === "connected" || e === "reconnecting") {
3136
- this.ensureWorker().then(() => this.ensureProtocolPort());
3137
- return;
3138
- }
3139
- (e === "idle" || e === "offline" || e === "offlineError" || e === "connecting" || e === "connectingSlow") && this.detachProtocolPort();
3140
- }
3141
- });
3142
- }
3143
- }, Dt = /* @__PURE__ */ d({ IkonMedia: () => $ }), $ = class {
3144
- audio;
3145
- video;
3146
- constructor(e, t) {
3147
- this.audio = new Tt(e, t?.audio), this.video = new Q(e, t?.video), t?.mediaSession && this.audio.setMediaSession(t.mediaSession);
3148
- }
3149
- dispose() {
3150
- this.audio.dispose(), this.video.dispose();
3151
- }
3152
- };
3153
- //#endregion
3154
- export { v as A, Ce as C, D, B as E, g as F, ee as I, te as L, _ as M, m as N, w as O, h as P, d as R, Se as S, xe as T, ge as _, xt as a, ve as b, pt as c, V as d, U as f, he as g, z as h, Tt as i, p as j, S as k, ht as l, H as m, Dt as n, lt as o, Ve as p, Q as r, _t as s, $ as t, yt as u, _e as v, be as w, ye as x, pe as y };