@ikonai/sdk 1.11.3 → 1.13.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 (56) hide show
  1. package/assets/audio-capture-worker-ubWDRLA3.js +1 -0
  2. package/assets/audio-playback-worker-CLT3Fd56.js +1 -0
  3. package/assets/protocol-worker-CFNK2Kvc.js +3 -0
  4. package/assets/video-capture-worker-Desm980E.js +1 -0
  5. package/assets/video-playback-worker-CsK7Q7OV.js +1 -0
  6. package/assets/viseme-worker-BXdOSahC.js +1 -0
  7. package/{channel-manager-ehgy3BJp.js → channel-manager-C1NK3o9-.js} +26 -26
  8. package/client/ikon-client-config.d.ts +19 -12
  9. package/client/ikon-client-config.d.ts.map +1 -1
  10. package/client/ikon-client.d.ts +14 -0
  11. package/client/ikon-client.d.ts.map +1 -1
  12. package/connection/authenticator.d.ts.map +1 -1
  13. package/{dist-BrkppKKs.js → dist-CNpJsuru.js} +3 -3
  14. package/errors/index.d.ts +10 -0
  15. package/errors/index.d.ts.map +1 -1
  16. package/functions/browser-functions.d.ts.map +1 -1
  17. package/functions/media-capture-functions.d.ts.map +1 -1
  18. package/functions/sound-functions.d.ts +4 -0
  19. package/functions/sound-functions.d.ts.map +1 -1
  20. package/{ikon-media-BQjL59S_.js → ikon-media-BNN-Q8p2.js} +28 -8
  21. package/{ikon-media-capture-4aEsbGgC.js → ikon-media-capture-BM64MF85.js} +131 -127
  22. package/index.d.ts +2 -2
  23. package/index.d.ts.map +1 -1
  24. package/index.js +2524 -2948
  25. package/media/ikon-media-capture.d.ts +1 -1
  26. package/media/ikon-media-capture.d.ts.map +1 -1
  27. package/media/ikon-video-capture.d.ts +11 -1
  28. package/media/ikon-video-capture.d.ts.map +1 -1
  29. package/media/ikon-video-playback.d.ts +12 -0
  30. package/media/ikon-video-playback.d.ts.map +1 -1
  31. package/media/index.d.ts +1 -1
  32. package/media/index.d.ts.map +1 -1
  33. package/media/viseme-tracker.d.ts +16 -5
  34. package/media/viseme-tracker.d.ts.map +1 -1
  35. package/{media-session-helper-Do-OxyU6.js → media-session-helper-CTZ867xv.js} +2 -2
  36. package/package.json +4 -1
  37. package/upload/file-upload.d.ts +4 -5
  38. package/upload/file-upload.d.ts.map +1 -1
  39. package/utils/query-params.d.ts +3 -1
  40. package/utils/query-params.d.ts.map +1 -1
  41. package/{viseme-tracker-CAtczW00.js → viseme-tracker-Ctuu8PRU.js} +69 -58
  42. package/{web-transport-support-Cdyk4mQe.js → web-transport-support-DcxJuxz4.js} +28 -22
  43. package/webrtc/webrtc-signaling.d.ts +38 -5
  44. package/webrtc/webrtc-signaling.d.ts.map +1 -1
  45. package/webrtc-signaling-C_GA-iWk.js +812 -0
  46. package/worker/video-playback-worker.d.ts +3 -0
  47. package/worker/video-playback-worker.d.ts.map +1 -1
  48. package/assets/audio-capture-worker-CJ5S-nQt.js +0 -1
  49. package/assets/audio-playback-worker-BA5LbdyM.js +0 -1
  50. package/assets/libopus-CnBCihDi.js +0 -1
  51. package/assets/protocol-worker-Byc-OmNW.js +0 -3
  52. package/assets/src-BKYD07QQ.js +0 -1
  53. package/assets/src-DOUWsCWT.js +0 -1
  54. package/assets/video-capture-worker-DRYxkwR0.js +0 -1
  55. package/assets/video-playback-worker-v179IJ-C.js +0 -1
  56. package/assets/viseme-worker-CmvzHAbf.js +0 -1
@@ -1,7 +1,8 @@
1
1
  import { c as e, n as t } from "./logger-gjegmH6K.js";
2
2
  import { _ as n, d as r, m as i, n as a, r as o, s, t as c } from "./capabilities-ljRyAKpA.js";
3
+ import { r as l } from "./webrtc-signaling-C_GA-iWk.js";
3
4
  //#region src/media/ring-buffer.ts
4
- var l = class {
5
+ var u = class {
5
6
  static getStorageForCapacity(e, t) {
6
7
  let n = Int32Array.BYTES_PER_ELEMENT * 2, r = t.BYTES_PER_ELEMENT * e;
7
8
  return new SharedArrayBuffer(n + r);
@@ -52,19 +53,19 @@ var l = class {
52
53
  };
53
54
  //#endregion
54
55
  //#region src/worker/audio-capture-worker.ts?worker
55
- function u(e) {
56
- return new Worker(new URL("assets/audio-capture-worker-CJ5S-nQt.js", import.meta.url).href, {
56
+ function d(e) {
57
+ return new Worker(new URL("assets/audio-capture-worker-ubWDRLA3.js", import.meta.url).href, {
57
58
  type: "module",
58
59
  name: e?.name
59
60
  });
60
61
  }
61
62
  //#endregion
62
63
  //#region src/media/ikon-audio-capture.ts
63
- var d = t("IkonAudioCapture"), f = 3, p = 200, m = 2e3, h = 5e3, g = 3e3;
64
- function _(e) {
64
+ var f = t("IkonAudioCapture"), p = 3, m = 200, h = 2e3, g = 5e3, _ = 3e3;
65
+ function v(e) {
65
66
  return new Promise((t) => setTimeout(t, e));
66
67
  }
67
- function v(e) {
68
+ function y(e) {
68
69
  switch (e.name) {
69
70
  case "NotReadableError": return {
70
71
  action: "retry",
@@ -100,14 +101,14 @@ function v(e) {
100
101
  };
101
102
  }
102
103
  }
103
- function y() {
104
+ function b() {
104
105
  let e = globalThis.crypto;
105
106
  return e?.randomUUID ? e.randomUUID() : `cap_${Date.now()}_${Math.floor(Math.random() * 1e9)}`;
106
107
  }
107
- function b() {
108
+ function x() {
108
109
  return "\nclass RingBuffer {\n static getStorageForCapacity(capacity, type) {\n const indexBytes = Int32Array.BYTES_PER_ELEMENT * 2;\n const dataBytes = type.BYTES_PER_ELEMENT * capacity;\n return new SharedArrayBuffer(indexBytes + dataBytes);\n }\n\n constructor(sharedArrayBuffer, type) {\n this.buf = sharedArrayBuffer;\n this.readWrite = new Int32Array(sharedArrayBuffer, 0, 2);\n const dataOffset = Int32Array.BYTES_PER_ELEMENT * 2;\n const dataLength = (sharedArrayBuffer.byteLength - dataOffset) / Float32Array.BYTES_PER_ELEMENT;\n this.storage = new type(sharedArrayBuffer, dataOffset, dataLength);\n }\n\n get capacity() {\n return this.storage.length;\n }\n\n available_read() {\n const read = Atomics.load(this.readWrite, 0);\n const write = Atomics.load(this.readWrite, 1);\n if (write >= read) return write - read;\n return this.capacity - (read - write);\n }\n\n available_write() {\n return this.capacity - this.available_read() - 1;\n }\n\n push(input) {\n const writable = Math.min(this.available_write(), input.length);\n if (writable <= 0) return 0;\n\n const read = Atomics.load(this.readWrite, 0);\n let write = Atomics.load(this.readWrite, 1);\n\n const firstPart = Math.min(writable, this.capacity - write);\n this.storage.set(input.subarray(0, firstPart), write);\n const remaining = writable - firstPart;\n if (remaining > 0) {\n this.storage.set(input.subarray(firstPart, firstPart + remaining), 0);\n }\n\n write = (write + writable) % this.capacity;\n Atomics.store(this.readWrite, 1, write);\n Atomics.notify(this.readWrite, 1);\n if (this.available_read() > this.capacity - 2) {\n Atomics.store(this.readWrite, 0, read);\n }\n\n return writable;\n }\n}\n\nconst RENDER_QUANTUM_SIZE = 128;\n\nclass IkonAudioCaptureProcessor extends AudioWorkletProcessor {\n constructor(options) {\n super();\n const cfg = options?.processorOptions || {};\n this.channels = cfg.channels || 1;\n this.transport = cfg.transport || 'pcm';\n this.ring = null;\n this.temp = new Float32Array(RENDER_QUANTUM_SIZE * this.channels);\n\n if (this.transport === 'sab' && cfg.sharedArrayBuffer) {\n this.ring = new RingBuffer(cfg.sharedArrayBuffer, Float32Array);\n }\n\n // Pre-allocated rotating transfer buffers for PCM mode\n // We use two buffers and alternate between them since postMessage transfers ownership\n this.transferBuffers = [\n new Float32Array(RENDER_QUANTUM_SIZE),\n new Float32Array(RENDER_QUANTUM_SIZE)\n ];\n this.transferBufferIndex = 0;\n\n this.port.postMessage({ type: 'ready' });\n }\n\n process(inputs) {\n const input = inputs[0];\n if (!input || input.length === 0) {\n return true;\n }\n\n const frames = input[0]?.length || 0;\n if (frames === 0) {\n return true;\n }\n\n const channelCount = input.length;\n for (let i = 0; i < frames; i++) {\n let sum = 0;\n for (let ch = 0; ch < channelCount; ch++) {\n const channel = input[ch];\n sum += channel ? (channel[i] || 0) : 0;\n }\n this.temp[i] = sum / channelCount;\n }\n\n const out = this.temp.subarray(0, frames);\n if (this.transport === 'sab' && this.ring) {\n this.ring.push(out);\n return true;\n }\n\n // Use rotating pre-allocated transfer buffer\n let buffer = this.transferBuffers[this.transferBufferIndex];\n // If buffer was transferred (detached), recreate it\n if (buffer.byteLength === 0) {\n buffer = new Float32Array(RENDER_QUANTUM_SIZE);\n this.transferBuffers[this.transferBufferIndex] = buffer;\n }\n buffer.set(out);\n const toSend = buffer.subarray(0, frames);\n this.port.postMessage({ type: 'pcm', pcm: toSend }, [buffer.buffer]);\n // Flip to next buffer for next call\n this.transferBufferIndex = (this.transferBufferIndex + 1) % 2;\n return true;\n }\n}\n\nregisterProcessor('ikon-audio-capture', IkonAudioCaptureProcessor);\n";
109
110
  }
110
- var x = class t {
111
+ var S = class t {
111
112
  client;
112
113
  static RESUME_TIMEOUT_MS = 3e3;
113
114
  worker = null;
@@ -164,13 +165,13 @@ var x = class t {
164
165
  for (let t of e) {
165
166
  if (t.stopped) continue;
166
167
  let e = t.intendedDeviceId ?? t.track.getSettings().deviceId, n = await this.isMicrophoneAvailable(e ?? void 0);
167
- t.stopped || n || (d.warn(`Microphone device disconnected, deviceId=${e?.substring(0, 8) ?? "default"}`), this.config.deviceDisconnectPolicy?.autoStop ?? !0 ? this.handleRecoverableError(t, /* @__PURE__ */ Error("Microphone device disconnected"), "device-disconnected") : this.notifyError(t, /* @__PURE__ */ Error("Microphone device disconnected"), "device-disconnected", !0));
168
+ t.stopped || n || (f.warn(`Microphone device disconnected, deviceId=${e?.substring(0, 8) ?? "default"}`), this.config.deviceDisconnectPolicy?.autoStop ?? !0 ? this.handleRecoverableError(t, /* @__PURE__ */ Error("Microphone device disconnected"), "device-disconnected") : this.notifyError(t, /* @__PURE__ */ Error("Microphone device disconnected"), "device-disconnected", !0));
168
169
  }
169
170
  }
170
171
  notifyError(e, t, n, r) {
171
172
  if (e.stopped) return;
172
173
  let i = Date.now(), a = t.name;
173
- if (e.lastErrorReason === n && e.lastErrorName === a && i - e.lastErrorTime < h) return;
174
+ if (e.lastErrorReason === n && e.lastErrorName === a && i - e.lastErrorTime < g) return;
174
175
  e.lastErrorTime = i, e.lastErrorReason = n, e.lastErrorName = a;
175
176
  let o = this.config.autoRestartPolicy;
176
177
  if (o?.enabled && r) {
@@ -181,7 +182,7 @@ var x = class t {
181
182
  ];
182
183
  if (i - e.lastStableTime > 3e4 && (e.restartCount = 0), r.includes(n) && e.restartCount < a) {
183
184
  let r = s[Math.min(e.restartCount, s.length - 1)];
184
- if (e.restartCount++, d.info(`Auto-restarting capture (attempt ${e.restartCount}/${a}) in ${r}ms, reason=${n}`), this.emitDiagnostic({
185
+ if (e.restartCount++, f.info(`Auto-restarting capture (attempt ${e.restartCount}/${a}) in ${r}ms, reason=${n}`), this.emitDiagnostic({
185
186
  event: "auto-restart",
186
187
  captureId: e.captureId,
187
188
  details: {
@@ -202,11 +203,11 @@ var x = class t {
202
203
  onStateChange: e.onStateChange
203
204
  };
204
205
  e.pendingRestartTimer = setTimeout(() => {
205
- e.pendingRestartTimer = null, !(!e.stopped || e.stoppedReason !== "recoverable-error") && this.startMic(c).then((e) => {
206
+ e.pendingRestartTimer = null, e.stopped && e.stoppedReason === "recoverable-error" && this.startMic(c).then((e) => {
206
207
  let t = this.captures.get(e.captureId);
207
208
  t && (t.restartCount = i, t.lastStableTime = Date.now());
208
209
  }).catch((e) => {
209
- d.warn(`Auto-restart failed: ${e}`);
210
+ f.warn(`Auto-restart failed: ${e}`);
210
211
  let t = e instanceof Error ? e : Error(String(e)), n = "unknown";
211
212
  if (t.name === "NotAllowedError" && (n = "permission-revoked"), o) try {
212
213
  o(/* @__PURE__ */ Error(`Auto-restart failed: ${t.message}`), n, i < a && n !== "permission-revoked");
@@ -228,7 +229,7 @@ var x = class t {
228
229
  if (e.ctx.state === "running") return !0;
229
230
  if (e.ctx.state !== "suspended") return !1;
230
231
  let r = Date.now();
231
- if (!n && r - e.lastResumeAttemptTime < g) return d.debug(`Resume attempt from ${t} skipped (cooldown)`), !1;
232
+ if (!n && r - e.lastResumeAttemptTime < _) return f.debug(`Resume attempt from ${t} skipped (cooldown)`), !1;
232
233
  e.lastResumeAttemptTime = r, this.emitDiagnostic({
233
234
  event: "resume-attempt",
234
235
  captureId: e.captureId,
@@ -250,7 +251,7 @@ var x = class t {
250
251
  }
251
252
  }), r;
252
253
  } catch (r) {
253
- return d.warn(`Failed to resume AudioContext from ${t}: ${r}`), this.emitDiagnostic({
254
+ return f.warn(`Failed to resume AudioContext from ${t}: ${r}`), this.emitDiagnostic({
254
255
  event: "resume-result",
255
256
  captureId: e.captureId,
256
257
  details: {
@@ -264,28 +265,28 @@ var x = class t {
264
265
  attemptResume(e, t, n = !1) {
265
266
  if (e.stopped || e.ctx.state !== "suspended") return;
266
267
  let r = Date.now();
267
- if (!n && r - e.lastResumeAttemptTime < g) {
268
- d.debug(`Resume attempt from ${t} skipped (cooldown)`);
268
+ if (!n && r - e.lastResumeAttemptTime < _) {
269
+ f.debug(`Resume attempt from ${t} skipped (cooldown)`);
269
270
  return;
270
271
  }
271
- e.lastResumeAttemptTime = r, d.info(`Attempting AudioContext resume from ${t}`), e.ctx.resume().then(() => {
272
- d.debug("AudioContext resumed successfully");
272
+ e.lastResumeAttemptTime = r, f.info(`Attempting AudioContext resume from ${t}`), e.ctx.resume().then(() => {
273
+ f.debug("AudioContext resumed successfully");
273
274
  }).catch((t) => {
274
- d.warn(`Failed to resume AudioContext: ${t}`), n && this.notifyError(e, /* @__PURE__ */ Error("AudioContext suspended - user gesture required"), "context-suspended", !0);
275
+ f.warn(`Failed to resume AudioContext: ${t}`), n && this.notifyError(e, /* @__PURE__ */ Error("AudioContext suspended - user gesture required"), "context-suspended", !0);
275
276
  });
276
277
  }
277
278
  setupAudioContextStateListener(e, t) {
278
279
  let n = () => {
279
280
  if (t.stopped) return;
280
281
  let n = e.state;
281
- if (d.debug(`AudioContext state changed to: ${n}`), this.emitDiagnostic({
282
+ if (f.debug(`AudioContext state changed to: ${n}`), this.emitDiagnostic({
282
283
  event: "state-change",
283
284
  captureId: t.captureId,
284
285
  details: { state: n }
285
286
  }), t.onStateChange) try {
286
287
  t.onStateChange(n);
287
288
  } catch {}
288
- n === "suspended" && (this.attemptResume(t, "statechange"), this.notifyError(t, /* @__PURE__ */ Error("AudioContext suspended - user gesture may be required"), "context-suspended", !0)), n === "interrupted" && (d.info("AudioContext interrupted (iOS), waiting for user to return"), this.notifyError(t, /* @__PURE__ */ Error("Audio interrupted - waiting for user to return"), "context-interrupted", !0));
289
+ n === "suspended" && (this.attemptResume(t, "statechange"), this.notifyError(t, /* @__PURE__ */ Error("AudioContext suspended - user gesture may be required"), "context-suspended", !0)), n === "interrupted" && (f.info("AudioContext interrupted (iOS), waiting for user to return"), this.notifyError(t, /* @__PURE__ */ Error("Audio interrupted - waiting for user to return"), "context-interrupted", !0));
289
290
  };
290
291
  e.addEventListener("statechange", n), t.stateChangeHandler = n;
291
292
  }
@@ -294,7 +295,7 @@ var x = class t {
294
295
  }
295
296
  setupVisibilityChangeListener(e) {
296
297
  let t = () => {
297
- document.visibilityState === "hidden" && !e.stopped ? d.debug("Page hidden - audio may be suspended soon") : document.visibilityState === "visible" && !e.stopped && this.attemptResume(e, "visibilitychange");
298
+ document.visibilityState === "hidden" && !e.stopped ? f.debug("Page hidden - audio may be suspended soon") : document.visibilityState === "visible" && !e.stopped && this.attemptResume(e, "visibilitychange");
298
299
  };
299
300
  document.addEventListener("visibilitychange", t), e.visibilityHandler = t;
300
301
  }
@@ -303,9 +304,9 @@ var x = class t {
303
304
  }
304
305
  setupBFCacheHandlers(e) {
305
306
  let t = () => {
306
- e.stopped || d.debug("Page hiding (BFCache) - audio may be suspended");
307
+ e.stopped || f.debug("Page hiding (BFCache) - audio may be suspended");
307
308
  }, n = (t) => {
308
- t.persisted && !e.stopped && (d.info("Page restored from BFCache - checking audio state"), e.ctx.state === "suspended" && this.attemptResume(e, "bfcache"));
309
+ t.persisted && !e.stopped && (f.info("Page restored from BFCache - checking audio state"), e.ctx.state === "suspended" && this.attemptResume(e, "bfcache"));
309
310
  };
310
311
  window.addEventListener("pagehide", t), window.addEventListener("pageshow", n), e.pagehideHandler = t, e.pageshowHandler = n;
311
312
  }
@@ -324,11 +325,11 @@ var x = class t {
324
325
  let r = "webrtc-audio", i = !0, a = e.constraints ?? {}, o = e.options ?? {};
325
326
  t.onAudioCaptureError = (t) => {
326
327
  if (!i || !e.onError) return;
327
- let n = v(t);
328
+ let n = y(t);
328
329
  try {
329
330
  e.onError(t, n.reason === "permission-denied" ? "permission-revoked" : n.reason, n.canRetry);
330
331
  } catch (e) {
331
- d.warn(`onError callback threw: ${e}`);
332
+ f.warn(`onError callback threw: ${e}`);
332
333
  }
333
334
  };
334
335
  let s = () => {
@@ -373,16 +374,16 @@ var x = class t {
373
374
  }
374
375
  ensureWorker() {
375
376
  if (this.worker) return this.worker;
376
- let e = new u();
377
+ let e = new d();
377
378
  return this.worker = e, e.addEventListener("message", (e) => {
378
379
  let t = e.data;
379
380
  if (t?.type !== "error") return;
380
381
  let n = t.error, r = `${n?.name ?? "Error"} ${n?.message ?? ""}`.trim(), i = typeof t.captureId == "string" ? this.captures.get(t.captureId) : void 0;
381
382
  if (!i || i.stopped) {
382
- d.warn(`Audio capture worker error: ${r}`);
383
+ f.warn(`Audio capture worker error: ${r}`);
383
384
  return;
384
385
  }
385
- d.error(`Audio capture worker error, stopping captureId=${i.captureId.substring(0, 8)}: ${r}`), this.handleRecoverableError(i, /* @__PURE__ */ Error(`Audio capture worker error: ${r}`), "unknown");
386
+ f.error(`Audio capture worker error, stopping captureId=${i.captureId.substring(0, 8)}: ${r}`), this.handleRecoverableError(i, /* @__PURE__ */ Error(`Audio capture worker error: ${r}`), "unknown");
386
387
  }), e.addEventListener("error", (t) => {
387
388
  let n = [
388
389
  t.message,
@@ -390,7 +391,7 @@ var x = class t {
390
391
  t.lineno,
391
392
  t.colno
392
393
  ].filter((e) => e != null && String(e).length > 0);
393
- if (d.error(`Audio capture worker failed: ${n.join(" ")}`.trim()), this.worker === e) {
394
+ if (f.error(`Audio capture worker failed: ${n.join(" ")}`.trim()), this.worker === e) {
394
395
  try {
395
396
  e.terminate();
396
397
  } catch {}
@@ -420,9 +421,9 @@ var x = class t {
420
421
  let t = e.createGain();
421
422
  t.gain.value = 0, t.connect(e.destination);
422
423
  let n = e.createOscillator();
423
- n.connect(t), n.start(), this.keepAliveGain = t, this.keepAliveSource = n, d.debug("Audio keep-alive started - capture will survive a backgrounded tab");
424
+ n.connect(t), n.start(), this.keepAliveGain = t, this.keepAliveSource = n, f.debug("Audio keep-alive started - capture will survive a backgrounded tab");
424
425
  } catch (e) {
425
- d.debug("Could not start the audio keep-alive", e), this.stopKeepAlive();
426
+ f.debug("Could not start the audio keep-alive", e), this.stopKeepAlive();
426
427
  }
427
428
  }
428
429
  stopKeepAlive() {
@@ -466,7 +467,7 @@ var x = class t {
466
467
  constraints: n
467
468
  };
468
469
  if (i.errorInfo.action === "fallback-constraints") {
469
- d.info(`Constraints failed (${i.error.name}), trying fallback constraints`), this.emitDiagnostic({
470
+ f.info(`Constraints failed (${i.error.name}), trying fallback constraints`), this.emitDiagnostic({
470
471
  event: "fallback",
471
472
  details: {
472
473
  errorName: i.error.name,
@@ -474,7 +475,7 @@ var x = class t {
474
475
  }
475
476
  });
476
477
  let e = await this.tryGetUserMediaWithRetries(r);
477
- if (e.stream) return d.info("getUserMedia succeeded with fallback constraints"), {
478
+ if (e.stream) return f.info("getUserMedia succeeded with fallback constraints"), {
478
479
  stream: e.stream,
479
480
  constraints: r
480
481
  };
@@ -498,25 +499,25 @@ var x = class t {
498
499
  reason: "unknown",
499
500
  canRetry: !1
500
501
  };
501
- for (let r = 0; r < f; r++) try {
502
+ for (let r = 0; r < p; r++) try {
502
503
  return {
503
504
  stream: await navigator.mediaDevices.getUserMedia({ audio: e }),
504
505
  error: t,
505
506
  errorInfo: n
506
507
  };
507
508
  } catch (e) {
508
- if (t = e instanceof Error ? e : Error(String(e)), n = v(t), d.debug(`getUserMedia attempt ${r + 1}/${f} failed: ${t.name} (action: ${n.action})`), this.emitDiagnostic({
509
+ if (t = e instanceof Error ? e : Error(String(e)), n = y(t), f.debug(`getUserMedia attempt ${r + 1}/${p} failed: ${t.name} (action: ${n.action})`), this.emitDiagnostic({
509
510
  event: "retry",
510
511
  details: {
511
512
  attempt: r + 1,
512
- maxAttempts: f,
513
+ maxAttempts: p,
513
514
  errorName: t.name,
514
515
  action: n.action
515
516
  }
516
517
  }), n.action !== "retry") break;
517
518
  if (r < 2) {
518
- let e = p * (r + 1);
519
- d.debug(`Retrying getUserMedia in ${e}ms`), await _(e);
519
+ let e = m * (r + 1);
520
+ f.debug(`Retrying getUserMedia in ${e}ms`), await v(e);
520
521
  }
521
522
  }
522
523
  return {
@@ -527,7 +528,7 @@ var x = class t {
527
528
  }
528
529
  async ensureWorklet(e) {
529
530
  if (!c(e)) throw Error("AudioWorklet is not supported in this browser");
530
- if (this.workletModuleUrl ||= URL.createObjectURL(new Blob([b()], { type: "text/javascript" })), this.workletReady && this.workletContext === e) try {
531
+ if (this.workletModuleUrl ||= URL.createObjectURL(new Blob([x()], { type: "text/javascript" })), this.workletReady && this.workletContext === e) try {
531
532
  await this.workletReady;
532
533
  return;
533
534
  } catch {
@@ -544,7 +545,7 @@ var x = class t {
544
545
  }
545
546
  handleWebRtcTransportLost() {
546
547
  if (this.activeWebRtcCaptureInvalidate) {
547
- d.warn("WebRTC transport lost during active capture; invalidating the capture handle");
548
+ f.warn("WebRTC transport lost during active capture; invalidating the capture handle");
548
549
  let e = this.activeWebRtcCaptureInvalidate;
549
550
  this.activeWebRtcCaptureInvalidate = null, e();
550
551
  }
@@ -553,8 +554,8 @@ var x = class t {
553
554
  let t = this.client.sessionId;
554
555
  if (!t) throw Error("Cannot start audio capture before client is connected");
555
556
  if (this.client.isWebRtcCaptureAvailable) return this.startMicWebRtc(e);
556
- this.client.isWebRtcFirstConnecting ? d.debug("WebRTC still connecting, capturing audio via protocol channel") : this.client.isWebRtcEnabled && d.warn("WebRTC unavailable, capturing audio via protocol channel");
557
- let n = y(), r = {
557
+ this.client.isWebRtcFirstConnecting ? f.debug("WebRTC still connecting, capturing audio via protocol channel") : this.client.isWebRtcEnabled && f.warn("WebRTC unavailable, capturing audio via protocol channel");
558
+ let n = b(), r = {
558
559
  captureId: n,
559
560
  aborted: !1,
560
561
  stream: null,
@@ -570,10 +571,10 @@ var x = class t {
570
571
  this.ensureSendPort();
571
572
  let s = await this.ensureAudioContext();
572
573
  i();
573
- let c, u;
574
+ let c, l;
574
575
  try {
575
576
  let t = await this.acquireMicrophoneStream(e);
576
- c = t.stream, u = t.constraints, r.stream = c;
577
+ c = t.stream, l = t.constraints, r.stream = c;
577
578
  } catch (t) {
578
579
  let n = t instanceof Error ? t : Error(String(t)), r = n.captureReason ?? "unknown";
579
580
  if (e.onError) try {
@@ -582,17 +583,17 @@ var x = class t {
582
583
  throw t;
583
584
  }
584
585
  i();
585
- let f = c.getAudioTracks()[0];
586
- if (!f) throw c.getTracks().forEach((e) => e.stop()), Error("No audio track available");
586
+ let d = c.getAudioTracks()[0];
587
+ if (!d) throw c.getTracks().forEach((e) => e.stop()), Error("No audio track available");
587
588
  await this.ensureWorklet(s), i();
588
- let p = this.allocateTrackId(), h = s.createMediaStreamSource(c);
589
- r.source = h;
589
+ let p = this.allocateTrackId(), m = s.createMediaStreamSource(c);
590
+ r.source = m;
590
591
  let g = s.createGain();
591
592
  g.gain.value = 0, g.connect(s.destination), r.gain = g;
592
593
  let _ = a() ? "sab" : "pcm", v;
593
594
  if (_ === "sab") {
594
595
  let e = Math.floor(s.sampleRate * 10);
595
- v = l.getStorageForCapacity(e, Float32Array);
596
+ v = u.getStorageForCapacity(e, Float32Array);
596
597
  }
597
598
  let y = this.ensureWorker(), b = e.onStopped;
598
599
  y.postMessage({
@@ -636,12 +637,12 @@ var x = class t {
636
637
  }
637
638
  });
638
639
  r.worklet = x, x.onprocessorerror = () => {
639
- d.error(`Audio capture worklet processor crashed (captureId=${n})`);
640
+ f.error(`Audio capture worklet processor crashed (captureId=${n})`);
640
641
  let e = this.captures.get(n);
641
642
  e && !e.stopped && this.notifyError(e, /* @__PURE__ */ Error("Audio capture worklet processor crashed"), "unknown", !0);
642
- }, h.connect(x), x.connect(g), _ === "pcm" && (x.port.onmessage = (e) => {
643
+ }, m.connect(x), x.connect(g), _ === "pcm" && (x.port.onmessage = (e) => {
643
644
  let t = e.data;
644
- if (!(!t || typeof t != "object") && t.type === "pcm" && t.pcm instanceof Float32Array) {
645
+ if (t && typeof t == "object" && t.type === "pcm" && t.pcm instanceof Float32Array) {
645
646
  let e = t.pcm;
646
647
  y.postMessage({
647
648
  type: "pcm",
@@ -654,14 +655,14 @@ var x = class t {
654
655
  captureId: n,
655
656
  trackId: p,
656
657
  stream: c,
657
- track: f,
658
+ track: d,
658
659
  ctx: s,
659
- source: h,
660
+ source: m,
660
661
  worklet: x,
661
662
  gain: g,
662
663
  stopped: !1,
663
664
  intendedDeviceId: S,
664
- currentConstraints: u,
665
+ currentConstraints: l,
665
666
  currentOptions: e.options ?? {},
666
667
  healthCheckTimer: null,
667
668
  visibilityHandler: null,
@@ -703,7 +704,7 @@ var x = class t {
703
704
  }
704
705
  this.removeAudioContextStateListener(s, C);
705
706
  try {
706
- h.disconnect();
707
+ m.disconnect();
707
708
  } catch {}
708
709
  try {
709
710
  x.disconnect();
@@ -740,11 +741,11 @@ var x = class t {
740
741
  };
741
742
  this.setupAudioContextStateListener(s, C), this.setupVisibilityChangeListener(C), this.setupBFCacheHandlers(C), C.healthCheckTimer = setInterval(() => {
742
743
  this.performHealthCheck(C);
743
- }, m);
744
+ }, h);
744
745
  let w = () => {
745
- C.stopped || (d.warn(`Microphone track ended unexpectedly, captureId=${n.substring(0, 8)}`), this.handleRecoverableError(C, /* @__PURE__ */ Error("Microphone track ended unexpectedly"), "track-ended"));
746
+ C.stopped || (f.warn(`Microphone track ended unexpectedly, captureId=${n.substring(0, 8)}`), this.handleRecoverableError(C, /* @__PURE__ */ Error("Microphone track ended unexpectedly"), "track-ended"));
746
747
  };
747
- return C.trackEndedHandler = w, f.addEventListener("ended", w), this.captures.set(n, C), this.startKeepAlive(C.ctx), this.pendingCaptures.delete(n), {
748
+ return C.trackEndedHandler = w, d.addEventListener("ended", w), this.captures.set(n, C), this.startKeepAlive(C.ctx), this.pendingCaptures.delete(n), {
748
749
  captureId: n,
749
750
  streamId: n,
750
751
  get isActive() {
@@ -837,23 +838,23 @@ var x = class t {
837
838
  performHealthCheck(e) {
838
839
  if (e.stopped) return;
839
840
  if (e.track.readyState !== "live") {
840
- d.warn(`Health check: track is ${e.track.readyState}, captureId=${e.captureId.substring(0, 8)}`), this.handleRecoverableError(e, /* @__PURE__ */ Error(`Microphone track is ${e.track.readyState}`), "track-ended");
841
+ f.warn(`Health check: track is ${e.track.readyState}, captureId=${e.captureId.substring(0, 8)}`), this.handleRecoverableError(e, /* @__PURE__ */ Error(`Microphone track is ${e.track.readyState}`), "track-ended");
841
842
  return;
842
843
  }
843
844
  let t = e.ctx.state;
844
845
  if (t === "closed") {
845
- d.warn(`Health check: AudioContext closed, captureId=${e.captureId.substring(0, 8)}`), this.notifyError(e, /* @__PURE__ */ Error("AudioContext was closed"), "context-closed", !1), e.stop("dispose");
846
+ f.warn(`Health check: AudioContext closed, captureId=${e.captureId.substring(0, 8)}`), this.notifyError(e, /* @__PURE__ */ Error("AudioContext was closed"), "context-closed", !1), e.stop("dispose");
846
847
  return;
847
848
  }
848
849
  t === "suspended" && this.attemptResume(e, "healthcheck"), e.track.readyState === "live" && t === "running" && (e.lastStableTime = Date.now());
849
850
  let n = this.config.mutedInputDetection;
850
851
  if (e.track.muted) {
851
- if (d.debug(`Health check: track is muted, captureId=${e.captureId.substring(0, 8)}`), n?.enabled) {
852
+ if (f.debug(`Health check: track is muted, captureId=${e.captureId.substring(0, 8)}`), n?.enabled) {
852
853
  let t = Date.now();
853
854
  if (e.mutedSinceTime === null) e.mutedSinceTime = t;
854
855
  else {
855
856
  let r = t - e.mutedSinceTime;
856
- r >= (n.durationMs ?? 5e3) && (d.warn(`Health check: input muted for ${r}ms, captureId=${e.captureId.substring(0, 8)}`), this.notifyError(e, /* @__PURE__ */ Error(`Microphone input muted for ${Math.round(r / 1e3)}s`), "input-muted", !0), e.mutedSinceTime = t);
857
+ r >= (n.durationMs ?? 5e3) && (f.warn(`Health check: input muted for ${r}ms, captureId=${e.captureId.substring(0, 8)}`), this.notifyError(e, /* @__PURE__ */ Error(`Microphone input muted for ${Math.round(r / 1e3)}s`), "input-muted", !0), e.mutedSinceTime = t);
857
858
  }
858
859
  }
859
860
  } else e.mutedSinceTime = null;
@@ -889,8 +890,8 @@ var x = class t {
889
890
  let t = this.captures.get(e);
890
891
  return !t || t.stopped ? !1 : this.attemptResumeAsync(t, "userGesture", !0);
891
892
  }
892
- }, S = 3e3;
893
- function C(e, t, n, r) {
893
+ }, C = 3e3;
894
+ function w(e, t, n, r) {
894
895
  if (!n && !r) return {
895
896
  width: e,
896
897
  height: t
@@ -901,7 +902,7 @@ function C(e, t, n, r) {
901
902
  height: Math.max(1, Math.floor(t * o))
902
903
  };
903
904
  }
904
- async function w(e, t) {
905
+ async function T(e, t) {
905
906
  let n = t.mime ?? "image/jpeg", r = t.quality ?? .92;
906
907
  if (typeof OffscreenCanvas < "u" && e instanceof OffscreenCanvas) try {
907
908
  return await e.convertToBlob({
@@ -916,7 +917,7 @@ async function w(e, t) {
916
917
  }, n, r);
917
918
  });
918
919
  }
919
- var T = class {
920
+ var E = class {
920
921
  async captureFromStream(e, t = {}) {
921
922
  let n = e.getVideoTracks()[0];
922
923
  if (!n) throw Error("No video track available in the provided stream");
@@ -927,7 +928,7 @@ var T = class {
927
928
  } catch {}
928
929
  try {
929
930
  await new Promise((e, t) => {
930
- let n = setTimeout(() => t(/* @__PURE__ */ Error("Timed out waiting for video metadata")), S);
931
+ let n = setTimeout(() => t(/* @__PURE__ */ Error("Timed out waiting for video metadata")), C);
931
932
  r.addEventListener("loadedmetadata", () => {
932
933
  clearTimeout(n), e();
933
934
  }, { once: !0 }), r.addEventListener("error", () => {
@@ -937,7 +938,7 @@ var T = class {
937
938
  try {
938
939
  await r.play();
939
940
  } catch {}
940
- let { width: e, height: i } = C(r.videoWidth || (n.getSettings().width ?? 1280), r.videoHeight || (n.getSettings().height ?? 720), t.width, t.height), a;
941
+ let { width: e, height: i } = w(r.videoWidth || (n.getSettings().width ?? 1280), r.videoHeight || (n.getSettings().height ?? 720), t.width, t.height), a;
941
942
  if (typeof OffscreenCanvas < "u") a = new OffscreenCanvas(e, i);
942
943
  else {
943
944
  let t = document.createElement("canvas");
@@ -946,7 +947,7 @@ var T = class {
946
947
  let o = a.getContext("2d", { alpha: !1 });
947
948
  if (!o) throw Error("2D canvas context unavailable");
948
949
  o.drawImage(r, 0, 0, e, i);
949
- let s = await w(a, t), c = await s.arrayBuffer();
950
+ let s = await T(a, t), c = await s.arrayBuffer();
950
951
  return {
951
952
  mime: s.type || t.mime || "image/jpeg",
952
953
  width: e,
@@ -987,7 +988,7 @@ var T = class {
987
988
  } catch {}
988
989
  try {
989
990
  await new Promise((e, t) => {
990
- let n = setTimeout(() => t(/* @__PURE__ */ Error("Timed out waiting for video metadata")), S);
991
+ let n = setTimeout(() => t(/* @__PURE__ */ Error("Timed out waiting for video metadata")), C);
991
992
  r.addEventListener("loadedmetadata", () => {
992
993
  clearTimeout(n), e();
993
994
  }, { once: !0 }), r.addEventListener("error", () => {
@@ -997,7 +998,7 @@ var T = class {
997
998
  try {
998
999
  await r.play();
999
1000
  } catch {}
1000
- let { width: t, height: i } = C(r.videoWidth || (n.getSettings().width ?? 1280), r.videoHeight || (n.getSettings().height ?? 720), e.width, e.height), a;
1001
+ let { width: t, height: i } = w(r.videoWidth || (n.getSettings().width ?? 1280), r.videoHeight || (n.getSettings().height ?? 720), e.width, e.height), a;
1001
1002
  if (typeof OffscreenCanvas < "u") a = new OffscreenCanvas(t, i);
1002
1003
  else {
1003
1004
  let e = document.createElement("canvas");
@@ -1006,7 +1007,7 @@ var T = class {
1006
1007
  let o = a.getContext("2d", { alpha: !1 });
1007
1008
  if (!o) throw Error("2D canvas context unavailable");
1008
1009
  o.drawImage(r, 0, 0, t, i);
1009
- let s = await w(a, e), c = await s.arrayBuffer();
1010
+ let s = await T(a, e), c = await s.arrayBuffer();
1010
1011
  return {
1011
1012
  mime: s.type || e.mime || "image/jpeg",
1012
1013
  width: t,
@@ -1030,11 +1031,11 @@ var T = class {
1030
1031
  }
1031
1032
  async captureFromNativeCamera(e = {}) {
1032
1033
  if (typeof document > "u") throw Error("Native camera capture requires a DOM environment");
1033
- let t = await E(e.facing);
1034
- return t ? await D(t, e) : null;
1034
+ let t = await D(e.facing);
1035
+ return t ? await O(t, e) : null;
1035
1036
  }
1036
1037
  };
1037
- function E(e) {
1038
+ function D(e) {
1038
1039
  return new Promise((t) => {
1039
1040
  let n = document.createElement("input");
1040
1041
  n.type = "file", n.accept = "image/*", n.setAttribute("capture", e ?? "environment"), n.style.position = "fixed", n.style.left = "-99999px", n.style.top = "0";
@@ -1060,7 +1061,7 @@ function E(e) {
1060
1061
  n.click();
1061
1062
  });
1062
1063
  }
1063
- async function D(e, t) {
1064
+ async function O(e, t) {
1064
1065
  let n = URL.createObjectURL(e), r;
1065
1066
  try {
1066
1067
  r = await new Promise((e, t) => {
@@ -1070,7 +1071,7 @@ async function D(e, t) {
1070
1071
  } finally {
1071
1072
  URL.revokeObjectURL(n);
1072
1073
  }
1073
- let i = r.naturalWidth || r.width, a = r.naturalHeight || r.height, { width: o, height: s } = C(i, a, t.width, t.height), c = t.mime ?? (e.type === "image/png" ? "image/png" : "image/jpeg"), l = t.quality ?? .92;
1074
+ let i = r.naturalWidth || r.width, a = r.naturalHeight || r.height, { width: o, height: s } = w(i, a, t.width, t.height), c = t.mime ?? (e.type === "image/png" ? "image/png" : "image/jpeg"), l = t.quality ?? .92;
1074
1075
  if (o === i && s === a && e.type === c) {
1075
1076
  let t = await e.arrayBuffer();
1076
1077
  return {
@@ -1097,33 +1098,34 @@ async function D(e, t) {
1097
1098
  }
1098
1099
  //#endregion
1099
1100
  //#region src/worker/video-capture-worker.ts?worker
1100
- function O(e) {
1101
- return new Worker(new URL("assets/video-capture-worker-DRYxkwR0.js", import.meta.url).href, {
1101
+ function k(e) {
1102
+ return new Worker(new URL("assets/video-capture-worker-Desm980E.js", import.meta.url).href, {
1102
1103
  type: "module",
1103
1104
  name: e?.name
1104
1105
  });
1105
1106
  }
1106
1107
  //#endregion
1107
1108
  //#region src/media/ikon-video-capture.ts
1108
- var k = t("IkonVideoCapture"), A = 1e4;
1109
- function j() {
1109
+ var A = t("IkonVideoCapture"), j = 1e4;
1110
+ function M() {
1110
1111
  let e = globalThis.crypto;
1111
1112
  return e?.randomUUID ? e.randomUUID() : `cap_${Date.now()}_${Math.floor(Math.random() * 1e9)}`;
1112
1113
  }
1113
- function M() {
1114
+ function N() {
1114
1115
  let e = globalThis.MediaStreamTrackProcessor;
1115
1116
  if (!e) throw Error("MediaStreamTrackProcessor is not available in this browser");
1116
1117
  return e;
1117
1118
  }
1118
- var N = class {
1119
+ var P = class {
1119
1120
  client;
1121
+ onCapturesChanged;
1120
1122
  worker = null;
1121
1123
  protocolPort = null;
1122
1124
  sendPort = null;
1123
1125
  nextTrackId = 1;
1124
1126
  captures = /* @__PURE__ */ new Map();
1125
- constructor(e) {
1126
- this.client = e;
1127
+ constructor(e, t) {
1128
+ this.client = e, this.onCapturesChanged = t;
1127
1129
  }
1128
1130
  allocateTrackId() {
1129
1131
  let e = this.nextTrackId;
@@ -1131,13 +1133,13 @@ var N = class {
1131
1133
  }
1132
1134
  ensureWorker() {
1133
1135
  if (this.worker) return this.worker;
1134
- let e = new O();
1136
+ let e = new k();
1135
1137
  return this.worker = e, e.addEventListener("message", (e) => {
1136
1138
  let t = e.data;
1137
1139
  if (t?.type === "error") {
1138
1140
  let e = t.error, n = `${e?.name ?? "Error"} ${e?.message ?? ""}`.trim(), r = typeof t.captureId == "string" ? this.captures.get(t.captureId) : void 0;
1139
- r && !r.stopped ? (k.error(`Video capture worker error, stopping captureId=${r.captureId.substring(0, 8)}: ${n}`), this.failCapture(r, /* @__PURE__ */ Error(`Video capture worker error: ${n}`))) : typeof t.captureId == "string" ? k.debug(`Video capture worker error for an inactive capture: ${n}`) : k.warn(`Video capture worker error: ${n}`);
1140
- } else t?.type === "log" ? k.info(t.message) : t?.type === "debug" && k.debug(t.message);
1141
+ r && !r.stopped ? (A.error(`Video capture worker error, stopping captureId=${r.captureId.substring(0, 8)}: ${n}`), this.failCapture(r, /* @__PURE__ */ Error(`Video capture worker error: ${n}`))) : typeof t.captureId == "string" ? A.debug(`Video capture worker error for an inactive capture: ${n}`) : A.warn(`Video capture worker error: ${n}`);
1142
+ } else t?.type === "log" ? A.info(t.message) : t?.type === "debug" && A.debug(t.message);
1141
1143
  }), e.addEventListener("error", (t) => {
1142
1144
  let n = [
1143
1145
  t.message,
@@ -1145,7 +1147,7 @@ var N = class {
1145
1147
  t.lineno,
1146
1148
  t.colno
1147
1149
  ].filter((e) => e != null && String(e).length > 0);
1148
- if (k.error(`Video capture worker failed: ${n.join(" ")}`.trim()), this.worker === e) {
1150
+ if (A.error(`Video capture worker failed: ${n.join(" ")}`.trim()), this.worker === e) {
1149
1151
  try {
1150
1152
  e.terminate();
1151
1153
  } catch {}
@@ -1159,7 +1161,7 @@ var N = class {
1159
1161
  try {
1160
1162
  e.onError?.(t);
1161
1163
  } catch (t) {
1162
- k.warn(`onError callback threw for captureId=${e.captureId.substring(0, 8)}: ${t}`);
1164
+ A.warn(`onError callback threw for captureId=${e.captureId.substring(0, 8)}: ${t}`);
1163
1165
  }
1164
1166
  e.stop();
1165
1167
  }
@@ -1206,64 +1208,62 @@ var N = class {
1206
1208
  async startCameraWebRtc(e) {
1207
1209
  let t = this.client.webRtcSignaling;
1208
1210
  if (!t) throw Error("WebRTC signaling is not connected");
1209
- let n = { ...e.constraints };
1210
- e.options?.width && !n.width && (n.width = { ideal: e.options.width }), e.options?.height && !n.height && (n.height = { ideal: e.options.height }), e.options?.framerate && !n.frameRate && (n.frameRate = { ideal: e.options.framerate }), typeof n.deviceId == "string" && (n.deviceId = { exact: n.deviceId }), t.sendVideoCaptureCorrelation(0, e.correlationId);
1211
- let r = (await t.startVideoCapture(Object.keys(n).length > 0 ? n : void 0, e.options?.bitrate, 0, e.correlationId)).getVideoTracks()[0], i = "webrtc-video", a = !0, o = e.onStopped, s = {
1212
- captureId: i,
1213
- streamId: i,
1211
+ t.sendVideoCaptureCorrelation(0, e.correlationId);
1212
+ let n = (await t.startVideoCapture(l("camera", e.options, e.constraints), e.options?.bitrate, 0, e.correlationId)).getVideoTracks()[0], r = "webrtc-video", i = !0, a = e.onStopped, o = {
1213
+ captureId: r,
1214
+ streamId: r,
1214
1215
  sourceType: "camera",
1215
1216
  get isActive() {
1216
- return a;
1217
+ return i;
1217
1218
  },
1218
1219
  get currentOptions() {
1219
1220
  return e.options;
1220
1221
  },
1221
1222
  async stop() {
1222
- a && (a = !1, await t.stopVideoCapture(0), o?.());
1223
+ i && (i = !1, await t.stopVideoCapture(0), a?.());
1223
1224
  },
1224
1225
  async updateOptions() {}
1225
1226
  };
1226
- return r && r.addEventListener("ended", () => {
1227
- s.stop();
1228
- }), s;
1227
+ return n && n.addEventListener("ended", () => {
1228
+ o.stop();
1229
+ }), o;
1229
1230
  }
1230
1231
  async startScreenWebRtc(e) {
1231
1232
  let t = this.client.webRtcSignaling;
1232
1233
  if (!t) throw Error("WebRTC signaling is not connected");
1233
- let n = { ...e.constraints };
1234
- e.options?.framerate && !n.frameRate && (n.frameRate = { ideal: e.options.framerate }), t.sendVideoCaptureCorrelation(1, e.correlationId);
1235
- let r = await t.startScreenCapture(Object.keys(n).length > 0 ? n : void 0, e.options?.bitrate, 1, e.correlationId), i = r.getVideoTracks()[0], a = "webrtc-screen", o = !0, s = e.onStopped, c = {
1236
- captureId: a,
1237
- streamId: a,
1234
+ t.sendVideoCaptureCorrelation(1, e.correlationId);
1235
+ let n = await t.startScreenCapture(l("screen", e.options, e.constraints), e.options?.bitrate, 1, e.correlationId), r = n.getVideoTracks()[0], i = "webrtc-screen", a = !0, o = e.onStopped, s = {
1236
+ captureId: i,
1237
+ streamId: i,
1238
1238
  sourceType: "screen",
1239
1239
  get isActive() {
1240
- return o;
1240
+ return a;
1241
1241
  },
1242
1242
  get currentOptions() {
1243
1243
  return e.options;
1244
1244
  },
1245
1245
  async stop() {
1246
- o && (o = !1, r.getTracks().forEach((e) => e.stop()), await t.stopVideoCapture(1), s?.());
1246
+ a && (a = !1, n.getTracks().forEach((e) => e.stop()), await t.stopVideoCapture(1), o?.());
1247
1247
  },
1248
1248
  async updateOptions() {}
1249
1249
  };
1250
- return i && i.addEventListener("ended", () => {
1251
- c.stop();
1252
- }), c;
1250
+ return r && r.addEventListener("ended", () => {
1251
+ s.stop();
1252
+ }), s;
1253
1253
  }
1254
1254
  async start(e) {
1255
1255
  let t = this.client.sessionId;
1256
1256
  if (!t) throw Error("Cannot start video capture before client is connected");
1257
1257
  if (this.client.isWebRtcCaptureAvailable && e.sourceType === "camera") return this.startCameraWebRtc(e);
1258
1258
  if (this.client.isWebRtcCaptureAvailable && e.sourceType === "screen") return this.startScreenWebRtc(e);
1259
- this.client.isWebRtcFirstConnecting ? k.debug("WebRTC still connecting, capturing video via protocol channel") : this.client.isWebRtcEnabled && k.warn("WebRTC unavailable, capturing video via protocol channel"), this.ensurePorts();
1260
- let n = j(), r = await this.getMediaStream(e), i = r.getVideoTracks()[0];
1259
+ this.client.isWebRtcFirstConnecting ? A.debug("WebRTC still connecting, capturing video via protocol channel") : this.client.isWebRtcEnabled && A.warn("WebRTC unavailable, capturing video via protocol channel"), this.ensurePorts();
1260
+ let n = M(), r = await this.getMediaStream(e), i = r.getVideoTracks()[0];
1261
1261
  if (!i) throw r.getTracks().forEach((e) => e.stop()), Error("No video track available");
1262
1262
  e.sourceType === "screen" && await new Promise((e) => setTimeout(e, 200));
1263
- let a = i.getSettings(), o = e.sourceType === "screen" ? a.width ?? 1280 : e.options?.width ?? a.width ?? 1280, s = e.sourceType === "screen" ? a.height ?? 720 : e.options?.height ?? a.height ?? 720, c = new (M())({ track: i }).readable, l = this.allocateTrackId(), u = this.ensureWorker(), d = e.sourceType, f = e.onStopped, p = new Promise((e, t) => {
1263
+ let a = i.getSettings(), o = e.sourceType === "screen" ? a.width ?? 1280 : e.options?.width ?? a.width ?? 1280, s = e.sourceType === "screen" ? a.height ?? 720 : e.options?.height ?? a.height ?? 720, c = new (N())({ track: i }).readable, l = this.allocateTrackId(), u = this.ensureWorker(), d = e.sourceType, f = e.onStopped, p = new Promise((e, t) => {
1264
1264
  let r = setTimeout(() => {
1265
1265
  u.removeEventListener("message", i), t(/* @__PURE__ */ Error("Video capture worker start timeout"));
1266
- }, A), i = (a) => {
1266
+ }, j), i = (a) => {
1267
1267
  let o = a.data;
1268
1268
  if (o?.captureId === n) {
1269
1269
  if (o.type === "started") clearTimeout(r), u.removeEventListener("message", i), e();
@@ -1311,7 +1311,7 @@ var N = class {
1311
1311
  onError: e.onError,
1312
1312
  stop: async () => {
1313
1313
  if (!m.stopped) {
1314
- m.stopped = !0, this.captures.delete(n), m.dimensionCheckInterval &&= (clearInterval(m.dimensionCheckInterval), void 0);
1314
+ m.stopped = !0, this.captures.delete(n), this.onCapturesChanged?.(), m.dimensionCheckInterval &&= (clearInterval(m.dimensionCheckInterval), void 0);
1315
1315
  try {
1316
1316
  r.getTracks().forEach((e) => e.stop());
1317
1317
  } catch {}
@@ -1329,9 +1329,9 @@ var N = class {
1329
1329
  let t = e.width !== void 0 && e.width !== m.currentOptions?.width, n = e.height !== void 0 && e.height !== m.currentOptions?.height, r = e.framerate !== void 0 && e.framerate !== m.currentOptions?.framerate;
1330
1330
  if (t || n || r) try {
1331
1331
  let t = {};
1332
- e.width !== void 0 && (t.width = { ideal: e.width }), e.height !== void 0 && (t.height = { ideal: e.height }), e.framerate !== void 0 && (t.frameRate = { ideal: e.framerate }), await i.applyConstraints(t), k.info(`Camera track constraints updated: ${e.width}x${e.height}@${e.framerate}fps`);
1332
+ e.width !== void 0 && (t.width = { ideal: e.width }), e.height !== void 0 && (t.height = { ideal: e.height }), e.framerate !== void 0 && (t.frameRate = { ideal: e.framerate }), await i.applyConstraints(t), A.info(`Camera track constraints updated: ${e.width}x${e.height}@${e.framerate}fps`);
1333
1333
  } catch (e) {
1334
- k.warn(`Failed to apply camera constraints: ${e}`);
1334
+ A.warn(`Failed to apply camera constraints: ${e}`);
1335
1335
  }
1336
1336
  }
1337
1337
  m.currentOptions = e, u.postMessage({
@@ -1360,7 +1360,7 @@ var N = class {
1360
1360
  }
1361
1361
  return i.addEventListener("ended", () => {
1362
1362
  m.stop();
1363
- }), this.captures.set(n, m), {
1363
+ }), this.captures.set(n, m), this.onCapturesChanged?.(), {
1364
1364
  captureId: n,
1365
1365
  streamId: n,
1366
1366
  sourceType: e.sourceType,
@@ -1394,8 +1394,12 @@ var N = class {
1394
1394
  for (let e of this.captures.values()) if (e.sourceType === "screen") return e.stream;
1395
1395
  return null;
1396
1396
  }
1397
+ getLocalStreamByStreamId(e) {
1398
+ let t = this.captures.get(e);
1399
+ return t && !t.stopped && t.stream.active ? t.stream : null;
1400
+ }
1397
1401
  dispose() {
1398
- for (let e of this.captures.values()) e.stop();
1402
+ for (let e of [...this.captures.values()]) e.stop();
1399
1403
  if (this.captures.clear(), this.worker) {
1400
1404
  try {
1401
1405
  this.worker.postMessage({ type: "dispose" });
@@ -1407,16 +1411,16 @@ var N = class {
1407
1411
  }
1408
1412
  this.protocolPort?.close(), this.protocolPort = null, this.sendPort?.close(), this.sendPort = null;
1409
1413
  }
1410
- }, P = class {
1414
+ }, F = class {
1411
1415
  audio;
1412
1416
  video;
1413
1417
  image;
1414
- constructor(e, t) {
1415
- this.audio = new x(e, t?.audio), this.video = new N(e), this.image = new T();
1418
+ constructor(e, t, n) {
1419
+ this.audio = new S(e, t?.audio), this.video = new P(e, n), this.image = new E();
1416
1420
  }
1417
1421
  dispose() {
1418
1422
  this.audio.dispose(), this.video.dispose();
1419
1423
  }
1420
1424
  };
1421
1425
  //#endregion
1422
- export { P as IkonMediaCapture };
1426
+ export { F as IkonMediaCapture };