@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.
- package/assets/audio-capture-worker-ubWDRLA3.js +1 -0
- package/assets/audio-playback-worker-CLT3Fd56.js +1 -0
- package/assets/protocol-worker-CFNK2Kvc.js +3 -0
- package/assets/video-capture-worker-Desm980E.js +1 -0
- package/assets/video-playback-worker-CsK7Q7OV.js +1 -0
- package/assets/viseme-worker-BXdOSahC.js +1 -0
- package/{channel-manager-ehgy3BJp.js → channel-manager-C1NK3o9-.js} +26 -26
- package/client/ikon-client-config.d.ts +19 -12
- package/client/ikon-client-config.d.ts.map +1 -1
- package/client/ikon-client.d.ts +14 -0
- package/client/ikon-client.d.ts.map +1 -1
- package/connection/authenticator.d.ts.map +1 -1
- package/{dist-BrkppKKs.js → dist-CNpJsuru.js} +3 -3
- package/errors/index.d.ts +10 -0
- package/errors/index.d.ts.map +1 -1
- package/functions/browser-functions.d.ts.map +1 -1
- package/functions/media-capture-functions.d.ts.map +1 -1
- package/functions/sound-functions.d.ts +4 -0
- package/functions/sound-functions.d.ts.map +1 -1
- package/{ikon-media-BQjL59S_.js → ikon-media-BNN-Q8p2.js} +28 -8
- package/{ikon-media-capture-4aEsbGgC.js → ikon-media-capture-BM64MF85.js} +131 -127
- package/index.d.ts +2 -2
- package/index.d.ts.map +1 -1
- package/index.js +2524 -2948
- package/media/ikon-media-capture.d.ts +1 -1
- package/media/ikon-media-capture.d.ts.map +1 -1
- package/media/ikon-video-capture.d.ts +11 -1
- package/media/ikon-video-capture.d.ts.map +1 -1
- package/media/ikon-video-playback.d.ts +12 -0
- package/media/ikon-video-playback.d.ts.map +1 -1
- package/media/index.d.ts +1 -1
- package/media/index.d.ts.map +1 -1
- package/media/viseme-tracker.d.ts +16 -5
- package/media/viseme-tracker.d.ts.map +1 -1
- package/{media-session-helper-Do-OxyU6.js → media-session-helper-CTZ867xv.js} +2 -2
- package/package.json +4 -1
- package/upload/file-upload.d.ts +4 -5
- package/upload/file-upload.d.ts.map +1 -1
- package/utils/query-params.d.ts +3 -1
- package/utils/query-params.d.ts.map +1 -1
- package/{viseme-tracker-CAtczW00.js → viseme-tracker-Ctuu8PRU.js} +69 -58
- package/{web-transport-support-Cdyk4mQe.js → web-transport-support-DcxJuxz4.js} +28 -22
- package/webrtc/webrtc-signaling.d.ts +38 -5
- package/webrtc/webrtc-signaling.d.ts.map +1 -1
- package/webrtc-signaling-C_GA-iWk.js +812 -0
- package/worker/video-playback-worker.d.ts +3 -0
- package/worker/video-playback-worker.d.ts.map +1 -1
- package/assets/audio-capture-worker-CJ5S-nQt.js +0 -1
- package/assets/audio-playback-worker-BA5LbdyM.js +0 -1
- package/assets/libopus-CnBCihDi.js +0 -1
- package/assets/protocol-worker-Byc-OmNW.js +0 -3
- package/assets/src-BKYD07QQ.js +0 -1
- package/assets/src-DOUWsCWT.js +0 -1
- package/assets/video-capture-worker-DRYxkwR0.js +0 -1
- package/assets/video-playback-worker-v179IJ-C.js +0 -1
- 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
|
|
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
|
|
56
|
-
return new Worker(new URL("assets/audio-capture-worker-
|
|
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
|
|
64
|
-
function
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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 || (
|
|
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 <
|
|
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++,
|
|
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,
|
|
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
|
-
|
|
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 <
|
|
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
|
|
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 <
|
|
268
|
-
|
|
268
|
+
if (!n && r - e.lastResumeAttemptTime < _) {
|
|
269
|
+
f.debug(`Resume attempt from ${t} skipped (cooldown)`);
|
|
269
270
|
return;
|
|
270
271
|
}
|
|
271
|
-
e.lastResumeAttemptTime = r,
|
|
272
|
-
|
|
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
|
-
|
|
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 (
|
|
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" && (
|
|
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 ?
|
|
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 ||
|
|
307
|
+
e.stopped || f.debug("Page hiding (BFCache) - audio may be suspended");
|
|
307
308
|
}, n = (t) => {
|
|
308
|
-
t.persisted && !e.stopped && (
|
|
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 =
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
383
|
+
f.warn(`Audio capture worker error: ${r}`);
|
|
383
384
|
return;
|
|
384
385
|
}
|
|
385
|
-
|
|
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 (
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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 <
|
|
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 =
|
|
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:
|
|
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 =
|
|
519
|
-
|
|
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([
|
|
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
|
-
|
|
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 ?
|
|
557
|
-
let n =
|
|
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,
|
|
574
|
+
let c, l;
|
|
574
575
|
try {
|
|
575
576
|
let t = await this.acquireMicrophoneStream(e);
|
|
576
|
-
c = t.stream,
|
|
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
|
|
586
|
-
if (!
|
|
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(),
|
|
589
|
-
r.source =
|
|
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 =
|
|
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
|
-
|
|
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
|
-
},
|
|
643
|
+
}, m.connect(x), x.connect(g), _ === "pcm" && (x.port.onmessage = (e) => {
|
|
643
644
|
let t = e.data;
|
|
644
|
-
if (
|
|
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:
|
|
658
|
+
track: d,
|
|
658
659
|
ctx: s,
|
|
659
|
-
source:
|
|
660
|
+
source: m,
|
|
660
661
|
worklet: x,
|
|
661
662
|
gain: g,
|
|
662
663
|
stopped: !1,
|
|
663
664
|
intendedDeviceId: S,
|
|
664
|
-
currentConstraints:
|
|
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
|
-
|
|
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
|
-
},
|
|
744
|
+
}, h);
|
|
744
745
|
let w = () => {
|
|
745
|
-
C.stopped || (
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
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 (
|
|
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) && (
|
|
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
|
-
},
|
|
893
|
-
function
|
|
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
|
|
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
|
|
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")),
|
|
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 } =
|
|
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
|
|
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")),
|
|
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 } =
|
|
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
|
|
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
|
|
1034
|
-
return t ? await
|
|
1034
|
+
let t = await D(e.facing);
|
|
1035
|
+
return t ? await O(t, e) : null;
|
|
1035
1036
|
}
|
|
1036
1037
|
};
|
|
1037
|
-
function
|
|
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
|
|
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 } =
|
|
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
|
|
1101
|
-
return new Worker(new URL("assets/video-capture-worker-
|
|
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
|
|
1109
|
-
function
|
|
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
|
|
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
|
|
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
|
|
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 ? (
|
|
1140
|
-
} else t?.type === "log" ?
|
|
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 (
|
|
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
|
-
|
|
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
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
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
|
|
1217
|
+
return i;
|
|
1217
1218
|
},
|
|
1218
1219
|
get currentOptions() {
|
|
1219
1220
|
return e.options;
|
|
1220
1221
|
},
|
|
1221
1222
|
async stop() {
|
|
1222
|
-
|
|
1223
|
+
i && (i = !1, await t.stopVideoCapture(0), a?.());
|
|
1223
1224
|
},
|
|
1224
1225
|
async updateOptions() {}
|
|
1225
1226
|
};
|
|
1226
|
-
return
|
|
1227
|
-
|
|
1228
|
-
}),
|
|
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
|
-
|
|
1234
|
-
e.options?.
|
|
1235
|
-
|
|
1236
|
-
|
|
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
|
|
1240
|
+
return a;
|
|
1241
1241
|
},
|
|
1242
1242
|
get currentOptions() {
|
|
1243
1243
|
return e.options;
|
|
1244
1244
|
},
|
|
1245
1245
|
async stop() {
|
|
1246
|
-
|
|
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
|
|
1251
|
-
|
|
1252
|
-
}),
|
|
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 ?
|
|
1260
|
-
let n =
|
|
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 (
|
|
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
|
-
},
|
|
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),
|
|
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
|
-
|
|
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
|
-
},
|
|
1414
|
+
}, F = class {
|
|
1411
1415
|
audio;
|
|
1412
1416
|
video;
|
|
1413
1417
|
image;
|
|
1414
|
-
constructor(e, t) {
|
|
1415
|
-
this.audio = new
|
|
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 {
|
|
1426
|
+
export { F as IkonMediaCapture };
|