@streaming-cdn/rtc-web 1.3.15 → 1.3.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +35 -1
- package/dist/avatar-rig.d.ts +63 -0
- package/dist/avatar.d.ts +88 -0
- package/dist/index.d.ts +5 -1
- package/dist/rtc-web.es.js +552 -382
- package/dist/rtc-web.umd.js +1 -1
- package/package.json +1 -1
package/dist/rtc-web.es.js
CHANGED
|
@@ -1,25 +1,25 @@
|
|
|
1
|
-
const
|
|
2
|
-
function
|
|
3
|
-
const n =
|
|
1
|
+
const qe = 0.02, Oe = 1.4;
|
|
2
|
+
function oe(a, e, t = 0.02, i = 1.4) {
|
|
3
|
+
const n = a.filter((r) => r.level >= t);
|
|
4
4
|
if (n.length === 0) return null;
|
|
5
|
-
const s = n.reduce((
|
|
6
|
-
return
|
|
5
|
+
const s = n.reduce((r, c) => c.level > r.level ? c : r), o = n.find((r) => r.participantId === e);
|
|
6
|
+
return o ? s.participantId === e ? e : s.level >= o.level * i ? s.participantId : e : s.participantId;
|
|
7
7
|
}
|
|
8
|
-
function
|
|
8
|
+
function ce(a) {
|
|
9
9
|
const e = [];
|
|
10
|
-
for (const t of
|
|
10
|
+
for (const t of a) {
|
|
11
11
|
if (String(t.type ?? "") !== "inbound-rtp" || String(t.kind ?? t.mediaType ?? "") !== "audio") continue;
|
|
12
12
|
const i = Number(t.audioLevel ?? NaN);
|
|
13
13
|
Number.isFinite(i) && e.push({ mid: typeof t.mid == "string" ? t.mid : null, level: i });
|
|
14
14
|
}
|
|
15
15
|
return e;
|
|
16
16
|
}
|
|
17
|
-
const
|
|
17
|
+
const O = {
|
|
18
18
|
audio: { active: !1, maxBitrate: 0, maxFramerate: 0, scaleResolutionDownBy: 4 },
|
|
19
19
|
low: { active: !0, maxBitrate: 35e4, maxFramerate: 15, scaleResolutionDownBy: 4 },
|
|
20
20
|
medium: { active: !0, maxBitrate: 11e5, maxFramerate: 24, scaleResolutionDownBy: 2 },
|
|
21
21
|
high: { active: !0, maxBitrate: 28e5, maxFramerate: 30, scaleResolutionDownBy: 1 }
|
|
22
|
-
},
|
|
22
|
+
}, he = {
|
|
23
23
|
warmupSamples: 3,
|
|
24
24
|
poorSamplesToStepDown: 2,
|
|
25
25
|
goodSamplesToStepUp: 6,
|
|
@@ -31,46 +31,46 @@ const M = {
|
|
|
31
31
|
goodRttMs: 250,
|
|
32
32
|
sustainRatio: 0.8
|
|
33
33
|
};
|
|
34
|
-
function
|
|
35
|
-
const e = String(
|
|
34
|
+
function ue(a) {
|
|
35
|
+
const e = String(a ?? "").trim().toLowerCase();
|
|
36
36
|
return !e || e === "none" ? "" : e === "cpu" || e === "bandwidth" ? e : "other";
|
|
37
37
|
}
|
|
38
|
-
function
|
|
39
|
-
const s = { ...
|
|
40
|
-
return d > c ? { quality:
|
|
38
|
+
function me(a, e, t, i, n = {}) {
|
|
39
|
+
const s = { ...he, ...n.thresholds }, o = ["low", "medium", "high"], r = n.ceiling && n.ceiling !== "audio" ? n.ceiling : "high", c = o.indexOf(r), d = o.indexOf(a), l = (n.samplesSeen ?? s.warmupSamples) + 1, u = l <= s.warmupSamples, y = ue(e.qualityLimitationReason), f = e.packetLossPct ?? 0, w = e.rttMs ?? 0, m = e.availableOutgoingBitrateBps, S = O[a].maxBitrate, T = f >= s.criticalLossPct || w >= s.criticalRttMs || y === "cpu", k = T || f >= s.poorLossPct || w >= s.poorRttMs || y === "bandwidth", b = m == null || m >= S * s.sustainRatio, M = f < s.goodLossPct && w < s.goodRttMs && !y && b, I = k ? t + 1 : 0, g = M ? i + 1 : 0, p = { quality: a, poorSamples: I, goodSamples: g, samplesSeen: l, changed: !1 };
|
|
40
|
+
return d > c ? { quality: o[c], poorSamples: 0, goodSamples: 0, samplesSeen: l, changed: !0 } : u ? p : T && d > 0 ? { quality: o[d - 1], poorSamples: 0, goodSamples: 0, samplesSeen: l, changed: !0 } : I >= s.poorSamplesToStepDown && d > 0 ? { quality: o[d - 1], poorSamples: 0, goodSamples: 0, samplesSeen: l, changed: !0 } : g >= s.goodSamplesToStepUp && d < c ? { quality: o[d + 1], poorSamples: 0, goodSamples: 0, samplesSeen: l, changed: !0 } : p;
|
|
41
41
|
}
|
|
42
|
-
function
|
|
43
|
-
const t =
|
|
44
|
-
let i = 0, n = 0, s = null,
|
|
42
|
+
function pe(a, e) {
|
|
43
|
+
const t = a instanceof Map ? a : new Map(a);
|
|
44
|
+
let i = 0, n = 0, s = null, o = null, r = null;
|
|
45
45
|
for (const l of t.values()) {
|
|
46
|
-
const
|
|
47
|
-
if (
|
|
46
|
+
const u = String(l.type ?? "");
|
|
47
|
+
if (u === "outbound-rtp" && String(l.kind ?? "") === "video" && (i += Number(l.packetsSent ?? 0), s = l.qualityLimitationReason ?? s), u === "remote-inbound-rtp" && String(l.kind ?? "") === "video") {
|
|
48
48
|
n += Number(l.packetsLost ?? 0);
|
|
49
|
-
const
|
|
50
|
-
Number.isFinite(
|
|
49
|
+
const y = Number(l.roundTripTime ?? NaN);
|
|
50
|
+
Number.isFinite(y) && (o = y * 1e3);
|
|
51
51
|
}
|
|
52
|
-
if (
|
|
53
|
-
const
|
|
54
|
-
|
|
55
|
-
const
|
|
56
|
-
Number.isFinite(
|
|
52
|
+
if (u === "candidate-pair" && (l.nominated === !0 || String(l.state ?? "") === "succeeded")) {
|
|
53
|
+
const y = Number(l.currentRoundTripTime ?? NaN);
|
|
54
|
+
o == null && Number.isFinite(y) && (o = y * 1e3);
|
|
55
|
+
const f = Number(l.availableOutgoingBitrate ?? NaN);
|
|
56
|
+
Number.isFinite(f) && (r = f);
|
|
57
57
|
}
|
|
58
58
|
}
|
|
59
59
|
const c = { packetsSent: i, packetsLost: n, timestamp: Date.now() };
|
|
60
60
|
let d = null;
|
|
61
61
|
if (e) {
|
|
62
|
-
const l = i - e.packetsSent,
|
|
63
|
-
l > 0 &&
|
|
62
|
+
const l = i - e.packetsSent, u = n - e.packetsLost;
|
|
63
|
+
l > 0 && u >= 0 && (d = u / (l + u) * 100);
|
|
64
64
|
}
|
|
65
65
|
return {
|
|
66
|
-
sample: { packetLossPct: d, rttMs:
|
|
66
|
+
sample: { packetLossPct: d, rttMs: o, availableOutgoingBitrateBps: r, qualityLimitationReason: s },
|
|
67
67
|
counters: c
|
|
68
68
|
};
|
|
69
69
|
}
|
|
70
|
-
const
|
|
70
|
+
const fe = {
|
|
71
71
|
audio: { active: !1, maxBitrate: 0, maxFramerate: 0, scaleResolutionDownBy: 4 }
|
|
72
|
-
},
|
|
73
|
-
class
|
|
72
|
+
}, ge = { active: !0, maxBitrate: 4e6, maxFramerate: 30, scaleResolutionDownBy: 1 };
|
|
73
|
+
class x {
|
|
74
74
|
options;
|
|
75
75
|
socket = null;
|
|
76
76
|
localStream = null;
|
|
@@ -153,14 +153,14 @@ class Q {
|
|
|
153
153
|
async setDevice(e) {
|
|
154
154
|
const t = { deviceId: { exact: e.deviceId } }, i = await navigator.mediaDevices.getUserMedia(e.kind === "audioinput" ? { audio: t } : { video: { ...t, width: { ideal: 1920 }, height: { ideal: 1080 }, frameRate: { ideal: 30, max: 30 } } }), n = e.kind === "audioinput" ? i.getAudioTracks()[0] : i.getVideoTracks()[0];
|
|
155
155
|
if (!n) throw new Error("Selected media device is unavailable");
|
|
156
|
-
const s = e.kind === "audioinput" ? "audio" : "video",
|
|
157
|
-
if (this.localStream || (this.localStream = new MediaStream()),
|
|
158
|
-
this.screenStream?.getVideoTracks().some((
|
|
156
|
+
const s = e.kind === "audioinput" ? "audio" : "video", o = this.localStream?.getTracks().find((r) => r.kind === s);
|
|
157
|
+
if (this.localStream || (this.localStream = new MediaStream()), o && (this.localStream.removeTrack(o), o.stop()), this.localStream.addTrack(n), s === "video") {
|
|
158
|
+
this.screenStream?.getVideoTracks().some((r) => r.readyState === "live") || await this.replaceVideoTrack(n);
|
|
159
159
|
return;
|
|
160
160
|
}
|
|
161
|
-
for (const
|
|
162
|
-
const c =
|
|
163
|
-
c ? await c.replaceTrack(n) :
|
|
161
|
+
for (const r of this.peers.values()) {
|
|
162
|
+
const c = r.connection.getSenders().find((d) => d.track?.kind === s);
|
|
163
|
+
c ? await c.replaceTrack(n) : r.connection.addTrack(n, this.localStream);
|
|
164
164
|
}
|
|
165
165
|
await this.applyVideoQuality();
|
|
166
166
|
}
|
|
@@ -168,7 +168,7 @@ class Q {
|
|
|
168
168
|
this.quality = e;
|
|
169
169
|
for (const t of this.localStream?.getVideoTracks() ?? []) t.enabled = e !== "audio";
|
|
170
170
|
for (const t of this.peers.values())
|
|
171
|
-
t.quality =
|
|
171
|
+
t.quality = x.clampToCeiling(t.quality, e), t.poorSamples = 0, t.goodSamples = 0;
|
|
172
172
|
await this.applyVideoQuality();
|
|
173
173
|
}
|
|
174
174
|
static clampToCeiling(e, t) {
|
|
@@ -216,18 +216,18 @@ class Q {
|
|
|
216
216
|
i.protocol = i.protocol === "https:" ? "wss:" : "ws:";
|
|
217
217
|
const n = new Promise((c, d) => {
|
|
218
218
|
this.resolveJoin = c, this.rejectJoin = d;
|
|
219
|
-
}), s = new WebSocket(i, ["rtc-client", t.signalingToken]),
|
|
219
|
+
}), s = new WebSocket(i, ["rtc-client", t.signalingToken]), o = ++this.socketGeneration;
|
|
220
220
|
this.socket = s;
|
|
221
|
-
const
|
|
221
|
+
const r = setTimeout(() => this.rejectJoin?.(new Error("RTC signaling timed out")), 15e3);
|
|
222
222
|
s.addEventListener("open", () => {
|
|
223
223
|
this.heartbeatDeadline = Date.now() + 45e3, this.startHeartbeat(s), this.startQualitySampling(), this.send({ type: "rtc.room.join" });
|
|
224
224
|
}), s.addEventListener("message", (c) => {
|
|
225
225
|
const d = String(c.data);
|
|
226
226
|
this.signalQueue = this.signalQueue.then(async () => {
|
|
227
|
-
this.socket !== s || this.socketGeneration !==
|
|
227
|
+
this.socket !== s || this.socketGeneration !== o || await this.handleSignal(d);
|
|
228
228
|
}).catch((l) => {
|
|
229
|
-
const
|
|
230
|
-
this.options.onEvent("signalingerror", { message:
|
|
229
|
+
const u = l instanceof Error ? l.message : "RTC signaling processing failed";
|
|
230
|
+
this.options.onEvent("signalingerror", { message: u }), this.joined || this.rejectJoin?.(new Error(u));
|
|
231
231
|
});
|
|
232
232
|
}), s.addEventListener("error", () => this.rejectJoin?.(new Error("RTC signaling connection failed"))), s.addEventListener("close", (c) => {
|
|
233
233
|
if (this.socket !== s) return;
|
|
@@ -238,7 +238,7 @@ class Q {
|
|
|
238
238
|
try {
|
|
239
239
|
await n, this.joined = !0, this.options.onEvent("connected", { participantId: t.participantId, resumed: e });
|
|
240
240
|
} finally {
|
|
241
|
-
clearTimeout(
|
|
241
|
+
clearTimeout(r), this.resolveJoin = null, this.rejectJoin = null;
|
|
242
242
|
}
|
|
243
243
|
}
|
|
244
244
|
async handleSignal(e) {
|
|
@@ -270,11 +270,11 @@ class Q {
|
|
|
270
270
|
if (i === "rtc.offer" && t.sender && t.description) {
|
|
271
271
|
const n = this.ensurePeer(t.sender);
|
|
272
272
|
n.offerTask && await n.offerTask;
|
|
273
|
-
const s = n.connection.signalingState !== "stable",
|
|
274
|
-
if (s && !
|
|
273
|
+
const s = n.connection.signalingState !== "stable", o = !this.shouldInitiateOffer(t.sender);
|
|
274
|
+
if (s && !o) return;
|
|
275
275
|
s && await n.connection.setLocalDescription({ type: "rollback" }), await n.connection.setRemoteDescription(t.description);
|
|
276
|
-
const
|
|
277
|
-
await n.connection.setLocalDescription(
|
|
276
|
+
const r = await n.connection.createAnswer();
|
|
277
|
+
await n.connection.setLocalDescription(r), this.send({
|
|
278
278
|
type: "rtc.answer",
|
|
279
279
|
targetParticipantId: t.sender.participantId,
|
|
280
280
|
negotiationId: t.negotiationId,
|
|
@@ -313,7 +313,7 @@ class Q {
|
|
|
313
313
|
makingOffer: !1,
|
|
314
314
|
offerTask: null,
|
|
315
315
|
activeNegotiationId: null,
|
|
316
|
-
quality:
|
|
316
|
+
quality: x.startingQuality(this.quality),
|
|
317
317
|
poorSamples: 0,
|
|
318
318
|
goodSamples: 0,
|
|
319
319
|
samplesSeen: 0,
|
|
@@ -321,8 +321,8 @@ class Q {
|
|
|
321
321
|
};
|
|
322
322
|
this.peers.set(e.participantId, s);
|
|
323
323
|
for (const c of this.localStream?.getAudioTracks() ?? []) i.addTrack(c, this.localStream);
|
|
324
|
-
const
|
|
325
|
-
return
|
|
324
|
+
const o = this.screenStream?.getVideoTracks().some((c) => c.readyState === "live") ? this.screenStream : this.localStream, r = o?.getVideoTracks()[0];
|
|
325
|
+
return r && o && (s.videoSender = i.addTrack(r, o)), !this.localStream?.getAudioTracks().length && this.options.receiveAudio && i.addTransceiver("audio", { direction: "recvonly" }), !r && this.options.receiveVideo && (s.videoTransceiver = i.addTransceiver("video", { direction: "recvonly" }), s.videoSender = s.videoTransceiver.sender), this.applyCodecPreference(i), this.applyVideoQuality(i), i.addEventListener("icecandidate", (c) => {
|
|
326
326
|
c.candidate && this.send({ type: "rtc.ice", targetParticipantId: e.participantId, candidate: c.candidate.toJSON() });
|
|
327
327
|
}), i.addEventListener("track", (c) => {
|
|
328
328
|
n.getTracks().some((d) => d.id === c.track.id) || n.addTrack(c.track), this.options.onEvent("remotestream", { participant: e, stream: n, track: c.track });
|
|
@@ -351,7 +351,7 @@ class Q {
|
|
|
351
351
|
});
|
|
352
352
|
if (e.connection.signalingState !== "stable") return;
|
|
353
353
|
await e.connection.setLocalDescription(t);
|
|
354
|
-
const i =
|
|
354
|
+
const i = W();
|
|
355
355
|
e.activeNegotiationId = i, this.send({
|
|
356
356
|
type: "rtc.offer",
|
|
357
357
|
targetParticipantId: e.identity.participantId,
|
|
@@ -371,10 +371,10 @@ class Q {
|
|
|
371
371
|
async replaceVideoTrack(e) {
|
|
372
372
|
let t = !1;
|
|
373
373
|
for (const i of this.peers.values()) {
|
|
374
|
-
const n = i.videoSender ?? i.connection.getSenders().find((
|
|
374
|
+
const n = i.videoSender ?? i.connection.getSenders().find((o) => o.track?.kind === "video") ?? i.connection.getTransceivers().find((o) => o.receiver.track.kind === "video")?.sender, s = i.videoTransceiver ?? i.connection.getTransceivers().find((o) => o.sender === n);
|
|
375
375
|
if (n) {
|
|
376
|
-
const
|
|
377
|
-
s && s.direction !==
|
|
376
|
+
const o = e ? this.options.receiveVideo ? "sendrecv" : "sendonly" : this.options.receiveVideo ? "recvonly" : "inactive";
|
|
377
|
+
s && s.direction !== o && (s.direction = o, t = !0), await n.replaceTrack(e), i.videoSender = n, s && (i.videoTransceiver = s);
|
|
378
378
|
} else e && (i.videoSender = i.connection.addTrack(e, this.screenStream ?? this.localStream ?? new MediaStream([e])), t = !0);
|
|
379
379
|
}
|
|
380
380
|
t && await this.renegotiateAll(), await this.applyVideoQuality();
|
|
@@ -391,8 +391,8 @@ class Q {
|
|
|
391
391
|
async applyPeerVideoQuality(e) {
|
|
392
392
|
const t = this.screenStream?.getVideoTracks()[0]?.id;
|
|
393
393
|
for (const i of e.connection.getSenders().filter((n) => n.track?.kind === "video")) {
|
|
394
|
-
const n = !!(t && i.track?.id === t), s = n ?
|
|
395
|
-
|
|
394
|
+
const n = !!(t && i.track?.id === t), s = n ? ge : this.quality === "audio" ? fe.audio : O[e.quality], o = i.getParameters(), r = o.encodings?.length ? o.encodings : [{}];
|
|
395
|
+
o.encodings = r.map((c) => ({ ...c, ...s })), o.degradationPreference = n ? "maintain-resolution" : "maintain-framerate", await i.setParameters(o);
|
|
396
396
|
}
|
|
397
397
|
}
|
|
398
398
|
startQualitySampling() {
|
|
@@ -411,11 +411,11 @@ class Q {
|
|
|
411
411
|
if (i.connection.connectionState === "connected")
|
|
412
412
|
try {
|
|
413
413
|
const n = await i.connection.getStats();
|
|
414
|
-
for (const s of
|
|
414
|
+
for (const s of ce(n.values()))
|
|
415
415
|
e.push({ participantId: i.identity.participantId, level: s.level });
|
|
416
416
|
} catch {
|
|
417
417
|
}
|
|
418
|
-
const t =
|
|
418
|
+
const t = oe(e, this.activeSpeaker);
|
|
419
419
|
t !== this.activeSpeaker && (this.activeSpeaker = t, this.options.onEvent("activespeaker", { participantId: t }));
|
|
420
420
|
}
|
|
421
421
|
async samplePeerQuality() {
|
|
@@ -428,9 +428,9 @@ class Q {
|
|
|
428
428
|
} catch {
|
|
429
429
|
continue;
|
|
430
430
|
}
|
|
431
|
-
const { sample: i, counters: n } =
|
|
431
|
+
const { sample: i, counters: n } = pe(t, e.counters);
|
|
432
432
|
e.counters = n;
|
|
433
|
-
const s =
|
|
433
|
+
const s = me(e.quality, i, e.poorSamples, e.goodSamples, {
|
|
434
434
|
samplesSeen: e.samplesSeen,
|
|
435
435
|
ceiling: this.quality
|
|
436
436
|
});
|
|
@@ -487,7 +487,7 @@ class Q {
|
|
|
487
487
|
}
|
|
488
488
|
send(e) {
|
|
489
489
|
this.socket?.readyState === WebSocket.OPEN && this.socket.send(JSON.stringify({
|
|
490
|
-
clientMessageId: e.clientMessageId ??
|
|
490
|
+
clientMessageId: e.clientMessageId ?? W(),
|
|
491
491
|
...e
|
|
492
492
|
}));
|
|
493
493
|
}
|
|
@@ -495,15 +495,15 @@ class Q {
|
|
|
495
495
|
for (const t of e?.getTracks() ?? []) t.stop();
|
|
496
496
|
}
|
|
497
497
|
}
|
|
498
|
-
function
|
|
498
|
+
function W() {
|
|
499
499
|
return globalThis.crypto?.randomUUID?.() ?? `${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`;
|
|
500
500
|
}
|
|
501
|
-
const
|
|
502
|
-
{ rid: "a", maxBitrate:
|
|
503
|
-
{ rid: "b", maxBitrate:
|
|
504
|
-
{ rid: "c", maxBitrate:
|
|
505
|
-
],
|
|
506
|
-
class
|
|
501
|
+
const $ = { active: !0, maxBitrate: 4e6, maxFramerate: 30, scaleResolutionDownBy: 1 }, Y = [
|
|
502
|
+
{ rid: "a", maxBitrate: O.high.maxBitrate, maxFramerate: O.high.maxFramerate },
|
|
503
|
+
{ rid: "b", maxBitrate: O.medium.maxBitrate, maxFramerate: O.medium.maxFramerate, scaleResolutionDownBy: 2 },
|
|
504
|
+
{ rid: "c", maxBitrate: O.low.maxBitrate, maxFramerate: O.low.maxFramerate, scaleResolutionDownBy: 4 }
|
|
505
|
+
], G = { high: "a", medium: "b", low: "c" };
|
|
506
|
+
class ye {
|
|
507
507
|
options;
|
|
508
508
|
apiBase;
|
|
509
509
|
socket = null;
|
|
@@ -594,13 +594,13 @@ class he {
|
|
|
594
594
|
async setDevice(e) {
|
|
595
595
|
const t = { deviceId: { exact: e.deviceId } }, i = await navigator.mediaDevices.getUserMedia(e.kind === "audioinput" ? { audio: t } : { video: { ...t, width: { ideal: 1920 }, height: { ideal: 1080 }, frameRate: { ideal: 30, max: 30 } } }), n = e.kind === "audioinput" ? i.getAudioTracks()[0] : i.getVideoTracks()[0];
|
|
596
596
|
if (!n) throw new Error("Selected media device is unavailable");
|
|
597
|
-
const s = e.kind === "audioinput" ? "audio" : "video",
|
|
598
|
-
if (this.localStream || (this.localStream = new MediaStream()),
|
|
597
|
+
const s = e.kind === "audioinput" ? "audio" : "video", o = this.localStream?.getTracks().find((c) => c.kind === s);
|
|
598
|
+
if (this.localStream || (this.localStream = new MediaStream()), o && (this.localStream.removeTrack(o), o.stop()), this.localStream.addTrack(n), s === "video") {
|
|
599
599
|
this.screenStream?.getVideoTracks().some((c) => c.readyState === "live") || await this.replaceVideoTrack(n);
|
|
600
600
|
return;
|
|
601
601
|
}
|
|
602
|
-
const
|
|
603
|
-
|
|
602
|
+
const r = this.connection?.getSenders().find((c) => c.track?.kind === "audio");
|
|
603
|
+
r && await r.replaceTrack(n);
|
|
604
604
|
}
|
|
605
605
|
/** One uplink serves everyone, so the requested quality applies directly. */
|
|
606
606
|
async setQuality(e) {
|
|
@@ -640,18 +640,18 @@ class he {
|
|
|
640
640
|
i.protocol = i.protocol === "https:" ? "wss:" : "ws:";
|
|
641
641
|
const n = new Promise((c, d) => {
|
|
642
642
|
this.resolveJoin = c, this.rejectJoin = d;
|
|
643
|
-
}), s = new WebSocket(i, ["rtc-client", t.signalingToken]),
|
|
643
|
+
}), s = new WebSocket(i, ["rtc-client", t.signalingToken]), o = ++this.socketGeneration;
|
|
644
644
|
this.socket = s;
|
|
645
|
-
const
|
|
645
|
+
const r = setTimeout(() => this.rejectJoin?.(new Error("RTC signaling timed out")), 15e3);
|
|
646
646
|
s.addEventListener("open", () => {
|
|
647
647
|
this.heartbeatDeadline = Date.now() + 45e3, this.startHeartbeat(s), this.send({ type: "rtc.room.join" });
|
|
648
648
|
}), s.addEventListener("message", (c) => {
|
|
649
649
|
const d = String(c.data);
|
|
650
650
|
this.signalQueue = this.signalQueue.then(async () => {
|
|
651
|
-
this.socket !== s || this.socketGeneration !==
|
|
651
|
+
this.socket !== s || this.socketGeneration !== o || await this.handleSignal(d);
|
|
652
652
|
}).catch((l) => {
|
|
653
|
-
const
|
|
654
|
-
this.options.onEvent("signalingerror", { message:
|
|
653
|
+
const u = l instanceof Error ? l.message : "RTC signaling processing failed";
|
|
654
|
+
this.options.onEvent("signalingerror", { message: u }), this.joined || this.rejectJoin?.(new Error(u));
|
|
655
655
|
});
|
|
656
656
|
}), s.addEventListener("error", () => this.rejectJoin?.(new Error("RTC signaling connection failed"))), s.addEventListener("close", (c) => {
|
|
657
657
|
if (this.socket !== s) return;
|
|
@@ -662,7 +662,7 @@ class he {
|
|
|
662
662
|
try {
|
|
663
663
|
await n, this.joined = !0, this.options.onEvent("connected", { participantId: t.participantId, resumed: e });
|
|
664
664
|
} finally {
|
|
665
|
-
clearTimeout(
|
|
665
|
+
clearTimeout(r), this.resolveJoin = null, this.rejectJoin = null;
|
|
666
666
|
}
|
|
667
667
|
}
|
|
668
668
|
async handleSignal(e) {
|
|
@@ -710,30 +710,30 @@ class he {
|
|
|
710
710
|
iceServers: this.options.credential.iceServers ?? [],
|
|
711
711
|
iceTransportPolicy: this.options.iceTransportPolicy ?? "all"
|
|
712
712
|
});
|
|
713
|
-
this.connection = t, t.addEventListener("track", (
|
|
713
|
+
this.connection = t, t.addEventListener("track", (r) => this.handleRemoteTrack(r)), t.addEventListener("connectionstatechange", () => {
|
|
714
714
|
this.options.onEvent("peerconnectionstate", { participant: this.selfIdentity(), state: t.connectionState });
|
|
715
715
|
});
|
|
716
716
|
const i = await this.sfuFetch("POST", "/v1/rtc/sfu/sessions");
|
|
717
717
|
if (this.sessionId = i.sessionId, e.length === 0) return;
|
|
718
|
-
const n = e.map((
|
|
718
|
+
const n = e.map((r) => t.addTransceiver(r, {
|
|
719
719
|
direction: "sendonly",
|
|
720
720
|
streams: this.localStream ? [this.localStream] : [],
|
|
721
|
-
...
|
|
721
|
+
...r.kind === "video" ? { sendEncodings: Y.map((c) => ({ ...c })) } : {}
|
|
722
722
|
})), s = await t.createOffer();
|
|
723
723
|
await t.setLocalDescription(s);
|
|
724
|
-
const
|
|
724
|
+
const o = await this.sfuFetch(
|
|
725
725
|
"POST",
|
|
726
726
|
`/v1/rtc/sfu/sessions/${encodeURIComponent(i.sessionId)}/tracks`,
|
|
727
727
|
{
|
|
728
728
|
sessionDescription: t.localDescription,
|
|
729
|
-
tracks: n.map((
|
|
729
|
+
tracks: n.map((r) => ({
|
|
730
730
|
location: "local",
|
|
731
|
-
mid:
|
|
732
|
-
trackName: this.trackName(
|
|
731
|
+
mid: r.mid,
|
|
732
|
+
trackName: this.trackName(r.sender.track)
|
|
733
733
|
}))
|
|
734
734
|
}
|
|
735
735
|
);
|
|
736
|
-
|
|
736
|
+
o.sessionDescription && await t.setRemoteDescription(o.sessionDescription), this.videoSender = t.getSenders().find((r) => r.track?.kind === "video") ?? null, await this.applyVideoQuality();
|
|
737
737
|
}
|
|
738
738
|
trackName(e) {
|
|
739
739
|
return `${this.options.credential.participantId}/${e.kind}`;
|
|
@@ -747,13 +747,13 @@ class he {
|
|
|
747
747
|
e.length !== 0 && this.sendControl("sfu.tracks", { sessionId: this.sessionId, tracks: e });
|
|
748
748
|
}
|
|
749
749
|
async handleTrackAnnouncement(e, t) {
|
|
750
|
-
const i = String(t?.sessionId ?? ""), n = (t?.tracks ?? []).map((
|
|
750
|
+
const i = String(t?.sessionId ?? ""), n = (t?.tracks ?? []).map((r) => ({ trackName: String(r.trackName ?? ""), simulcast: r.simulcast === !0 })).filter((r) => !!r.trackName), s = n.map((r) => r.trackName);
|
|
751
751
|
if (!i || s.length === 0 || e.participantId === this.options.credential.participantId) return;
|
|
752
752
|
if (!this.connection || !this.sessionId) {
|
|
753
753
|
this.pendingAnnouncements.set(e.participantId, { sender: e, detail: t ?? {} });
|
|
754
754
|
return;
|
|
755
755
|
}
|
|
756
|
-
const
|
|
756
|
+
const o = this.remotes.get(e.participantId) ?? {
|
|
757
757
|
identity: e,
|
|
758
758
|
stream: new MediaStream(),
|
|
759
759
|
sessionId: i,
|
|
@@ -761,14 +761,14 @@ class he {
|
|
|
761
761
|
simulcastNames: /* @__PURE__ */ new Set(),
|
|
762
762
|
mids: /* @__PURE__ */ new Map()
|
|
763
763
|
};
|
|
764
|
-
|
|
765
|
-
for (const
|
|
766
|
-
|
|
767
|
-
this.remotes.set(e.participantId,
|
|
768
|
-
const
|
|
769
|
-
|
|
770
|
-
}).catch((
|
|
771
|
-
this.options.onEvent("signalingerror", { message:
|
|
764
|
+
o.sessionId = i;
|
|
765
|
+
for (const r of n)
|
|
766
|
+
r.simulcast && o.simulcastNames.add(r.trackName);
|
|
767
|
+
this.remotes.set(e.participantId, o), this.negotiationQueue = this.negotiationQueue.then(async () => {
|
|
768
|
+
const r = s.filter((c) => !o.trackNames.includes(c));
|
|
769
|
+
r.length !== 0 && await this.subscribe(o, r);
|
|
770
|
+
}).catch((r) => {
|
|
771
|
+
this.options.onEvent("signalingerror", { message: r instanceof Error ? r.message : "SFU subscribe failed" });
|
|
772
772
|
}), await this.negotiationQueue;
|
|
773
773
|
}
|
|
774
774
|
async subscribe(e, t) {
|
|
@@ -818,7 +818,7 @@ class he {
|
|
|
818
818
|
n && await this.sfuFetch("PUT", `/v1/rtc/sfu/sessions/${encodeURIComponent(this.sessionId)}/tracks/update`, {
|
|
819
819
|
tracks: [{
|
|
820
820
|
mid: n,
|
|
821
|
-
simulcast: { preferredRid:
|
|
821
|
+
simulcast: { preferredRid: G[t], priorityOrdering: "asciibetical", ridNotAvailable: "asciibetical" }
|
|
822
822
|
}]
|
|
823
823
|
});
|
|
824
824
|
}
|
|
@@ -830,16 +830,16 @@ class he {
|
|
|
830
830
|
if (!e) return;
|
|
831
831
|
const t = this.screenStream?.getVideoTracks()[0]?.id, i = !!(t && e.track?.id === t), n = e.getParameters(), s = n.encodings?.length ? n.encodings : [{}];
|
|
832
832
|
if (s.length > 1) {
|
|
833
|
-
const
|
|
834
|
-
n.encodings = s.map((
|
|
833
|
+
const o = this.quality === "audio" ? null : G[this.quality];
|
|
834
|
+
n.encodings = s.map((r) => {
|
|
835
835
|
if (i)
|
|
836
|
-
return { ...
|
|
837
|
-
const c =
|
|
838
|
-
return { ...
|
|
836
|
+
return { ...r, active: r.rid === "a", ...r.rid === "a" ? { maxBitrate: $.maxBitrate, maxFramerate: $.maxFramerate } : {} };
|
|
837
|
+
const c = Y.find((l) => l.rid === r.rid), d = o != null && String(r.rid ?? "") >= o;
|
|
838
|
+
return { ...r, ...c ?? {}, active: d };
|
|
839
839
|
});
|
|
840
840
|
} else {
|
|
841
|
-
const
|
|
842
|
-
n.encodings = s.map((c) => ({ ...c, ...
|
|
841
|
+
const o = this.quality === "audio" ? O.audio : O[this.quality], r = i ? $ : o;
|
|
842
|
+
n.encodings = s.map((c) => ({ ...c, ...r }));
|
|
843
843
|
}
|
|
844
844
|
n.degradationPreference = i ? "maintain-resolution" : "maintain-framerate", await e.setParameters(n);
|
|
845
845
|
}
|
|
@@ -905,11 +905,11 @@ class he {
|
|
|
905
905
|
return;
|
|
906
906
|
}
|
|
907
907
|
const i = [];
|
|
908
|
-
for (const s of
|
|
909
|
-
const
|
|
910
|
-
|
|
908
|
+
for (const s of ce(t.values())) {
|
|
909
|
+
const o = s.mid ? this.midToParticipant.get(s.mid) : void 0;
|
|
910
|
+
o && i.push({ participantId: o, level: s.level });
|
|
911
911
|
}
|
|
912
|
-
const n =
|
|
912
|
+
const n = oe(i, this.activeSpeaker);
|
|
913
913
|
n !== this.activeSpeaker && (this.activeSpeaker = n, this.options.onEvent("activespeaker", { participantId: n }));
|
|
914
914
|
}
|
|
915
915
|
clearTimers() {
|
|
@@ -926,7 +926,7 @@ class he {
|
|
|
926
926
|
}
|
|
927
927
|
send(e) {
|
|
928
928
|
this.socket?.readyState === WebSocket.OPEN && this.socket.send(JSON.stringify({
|
|
929
|
-
clientMessageId: e.clientMessageId ??
|
|
929
|
+
clientMessageId: e.clientMessageId ?? ve(),
|
|
930
930
|
...e
|
|
931
931
|
}));
|
|
932
932
|
}
|
|
@@ -934,24 +934,24 @@ class he {
|
|
|
934
934
|
for (const t of e?.getTracks() ?? []) t.stop();
|
|
935
935
|
}
|
|
936
936
|
}
|
|
937
|
-
function
|
|
937
|
+
function ve() {
|
|
938
938
|
return globalThis.crypto?.randomUUID?.() ?? `${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`;
|
|
939
939
|
}
|
|
940
|
-
function
|
|
940
|
+
function Ne(a, e = {}) {
|
|
941
941
|
const t = e.document ?? globalThis.document, i = !!(t && t.pictureInPictureEnabled);
|
|
942
942
|
let n = null;
|
|
943
943
|
function s() {
|
|
944
944
|
return n || (n = t.createElement("video"), n.muted = !0, n.playsInline = !0, n.style.position = "fixed", n.style.width = "1px", n.style.height = "1px", n.style.opacity = "0", n.style.pointerEvents = "none", n.addEventListener("leavepictureinpicture", () => e.onLeave?.()), t.body.appendChild(n), n);
|
|
945
945
|
}
|
|
946
|
-
function
|
|
947
|
-
const c =
|
|
948
|
-
return
|
|
946
|
+
function o(r) {
|
|
947
|
+
const c = a.getRemoteStreams();
|
|
948
|
+
return r ? c.find((d) => d.participant.participantId === r)?.stream ?? null : c[0]?.stream ?? a.getLocalStream();
|
|
949
949
|
}
|
|
950
950
|
return {
|
|
951
951
|
supported: i,
|
|
952
|
-
async enter(
|
|
952
|
+
async enter(r) {
|
|
953
953
|
if (!i) throw new Error("This browser does not support picture-in-picture");
|
|
954
|
-
const c =
|
|
954
|
+
const c = o(r);
|
|
955
955
|
if (!c) throw new Error("No video stream is available for picture-in-picture");
|
|
956
956
|
const d = s();
|
|
957
957
|
d.srcObject !== c && (d.srcObject = c), await d.play().catch(() => {
|
|
@@ -965,82 +965,82 @@ function Ee(r, e = {}) {
|
|
|
965
965
|
}
|
|
966
966
|
};
|
|
967
967
|
}
|
|
968
|
-
function
|
|
969
|
-
const t = e.document ?? globalThis.document, i = e.fetchImplementation ?? globalThis.fetch.bind(globalThis), n = new URL(e.credential.signalingUrl, globalThis.location?.href).origin, s = e.mimeType ?? "video/webm",
|
|
970
|
-
let c = null, d = null, l = null,
|
|
971
|
-
async function
|
|
972
|
-
const
|
|
973
|
-
method:
|
|
968
|
+
function je(a, e) {
|
|
969
|
+
const t = e.document ?? globalThis.document, i = e.fetchImplementation ?? globalThis.fetch.bind(globalThis), n = new URL(e.credential.signalingUrl, globalThis.location?.href).origin, s = e.mimeType ?? "video/webm", o = e.height ?? 720, r = Math.round(o * 16 / 9);
|
|
970
|
+
let c = null, d = null, l = null, u = null, y = 0, f = [], w = !1;
|
|
971
|
+
async function m(S, T, k, b = "application/json") {
|
|
972
|
+
const M = await i(`${n}${T}`, {
|
|
973
|
+
method: S,
|
|
974
974
|
headers: {
|
|
975
975
|
authorization: `Bearer ${e.credential.signalingToken}`,
|
|
976
|
-
"content-type":
|
|
976
|
+
"content-type": b
|
|
977
977
|
},
|
|
978
|
-
body:
|
|
978
|
+
body: k === void 0 ? void 0 : b === "application/json" ? JSON.stringify(k) : k
|
|
979
979
|
});
|
|
980
|
-
if (!
|
|
981
|
-
return
|
|
980
|
+
if (!M.ok) throw new Error(`Recording request failed with HTTP ${M.status}`);
|
|
981
|
+
return M.json();
|
|
982
982
|
}
|
|
983
983
|
return {
|
|
984
984
|
get recording() {
|
|
985
|
-
return
|
|
985
|
+
return w;
|
|
986
986
|
},
|
|
987
987
|
async start() {
|
|
988
|
-
if (
|
|
989
|
-
|
|
990
|
-
const
|
|
991
|
-
|
|
992
|
-
const
|
|
993
|
-
let
|
|
994
|
-
return
|
|
995
|
-
}),
|
|
988
|
+
if (w) return;
|
|
989
|
+
u = (await m("POST", "/v1/rtc/recordings")).recordingId;
|
|
990
|
+
const T = t.createElement("canvas");
|
|
991
|
+
T.width = r, T.height = o;
|
|
992
|
+
const k = T.getContext("2d"), b = /* @__PURE__ */ new Map(), M = (E, P) => {
|
|
993
|
+
let C = b.get(E);
|
|
994
|
+
return C || (C = t.createElement("video"), C.muted = !0, C.playsInline = !0, C.srcObject = P, C.play().catch(() => {
|
|
995
|
+
}), b.set(E, C)), C;
|
|
996
996
|
};
|
|
997
997
|
d = setInterval(() => {
|
|
998
|
-
const
|
|
999
|
-
...
|
|
998
|
+
const E = a.getRemoteStreams(), P = a.getLocalStream(), C = [
|
|
999
|
+
...E.map((j) => ({ key: j.participant.participantId, stream: j.stream, label: j.participant.displayName })),
|
|
1000
1000
|
...P ? [{ key: "local", stream: P, label: "me" }] : []
|
|
1001
1001
|
];
|
|
1002
|
-
|
|
1003
|
-
const
|
|
1004
|
-
|
|
1005
|
-
const
|
|
1006
|
-
|
|
1002
|
+
k.fillStyle = "#101418", k.fillRect(0, 0, r, o);
|
|
1003
|
+
const D = Math.max(1, Math.ceil(Math.sqrt(C.length))), v = Math.max(1, Math.ceil(C.length / D)), N = r / D, U = o / v;
|
|
1004
|
+
C.forEach((j, H) => {
|
|
1005
|
+
const _ = M(j.key, j.stream), B = H % D * N, F = Math.floor(H / D) * U;
|
|
1006
|
+
_.videoWidth > 0 && k.drawImage(_, B + 2, F + 2, N - 4, U - 4), k.fillStyle = "rgba(0,0,0,.6)", k.fillRect(B + 8, F + U - 30, Math.min(N - 16, 12 + j.label.length * 9), 22), k.fillStyle = "#fff", k.font = "14px system-ui", k.fillText(j.label, B + 14, F + U - 14);
|
|
1007
1007
|
});
|
|
1008
1008
|
}, 66);
|
|
1009
|
-
const
|
|
1009
|
+
const I = T.captureStream(15);
|
|
1010
1010
|
l = new AudioContext();
|
|
1011
|
-
const
|
|
1012
|
-
const
|
|
1013
|
-
...
|
|
1014
|
-
...
|
|
1011
|
+
const g = l.createMediaStreamDestination(), p = /* @__PURE__ */ new Set(), h = () => {
|
|
1012
|
+
const E = [
|
|
1013
|
+
...a.getRemoteStreams().map((P) => P.stream),
|
|
1014
|
+
...a.getLocalStream() ? [a.getLocalStream()] : []
|
|
1015
1015
|
];
|
|
1016
|
-
for (const P of
|
|
1017
|
-
for (const
|
|
1018
|
-
|
|
1016
|
+
for (const P of E)
|
|
1017
|
+
for (const C of P.getAudioTracks())
|
|
1018
|
+
p.has(C.id) || (p.add(C.id), l.createMediaStreamSource(new MediaStream([C])).connect(g));
|
|
1019
1019
|
};
|
|
1020
|
-
|
|
1021
|
-
const
|
|
1022
|
-
for (const
|
|
1023
|
-
c = (e.mediaRecorderFactory ?? ((
|
|
1024
|
-
|
|
1025
|
-
}), c.addEventListener("stop", L), c.start(1e3),
|
|
1020
|
+
h();
|
|
1021
|
+
const R = setInterval(h, 1e3), L = () => clearInterval(R);
|
|
1022
|
+
for (const E of g.stream.getAudioTracks()) I.addTrack(E);
|
|
1023
|
+
c = (e.mediaRecorderFactory ?? ((E, P) => new MediaRecorder(E, P)))(I, { mimeType: s }), f = [], c.addEventListener("dataavailable", (E) => {
|
|
1024
|
+
E.data && E.data.size > 0 && f.push(E.data);
|
|
1025
|
+
}), c.addEventListener("stop", L), c.start(1e3), y = Date.now(), w = !0;
|
|
1026
1026
|
},
|
|
1027
1027
|
async stop() {
|
|
1028
|
-
if (!
|
|
1029
|
-
|
|
1030
|
-
const
|
|
1031
|
-
|
|
1028
|
+
if (!w || !c || !u) throw new Error("The recorder is not running");
|
|
1029
|
+
w = !1;
|
|
1030
|
+
const S = c, T = new Promise((g) => S.addEventListener("stop", () => g(), { once: !0 }));
|
|
1031
|
+
S.stop(), await T, d && clearInterval(d), d = null, await l?.close().catch(() => {
|
|
1032
1032
|
}), l = null;
|
|
1033
|
-
const
|
|
1034
|
-
|
|
1035
|
-
const
|
|
1033
|
+
const k = new Blob(f, { type: s });
|
|
1034
|
+
f = [];
|
|
1035
|
+
const b = Math.max(1, Math.round((Date.now() - y) / 1e3)), M = await m(
|
|
1036
1036
|
"PUT",
|
|
1037
|
-
`/v1/rtc/recordings/${encodeURIComponent(
|
|
1038
|
-
|
|
1037
|
+
`/v1/rtc/recordings/${encodeURIComponent(u)}/media`,
|
|
1038
|
+
k,
|
|
1039
1039
|
s
|
|
1040
1040
|
);
|
|
1041
|
-
await
|
|
1042
|
-
const
|
|
1043
|
-
return
|
|
1041
|
+
await m("POST", `/v1/rtc/recordings/${encodeURIComponent(u)}/complete`, { durationSeconds: b });
|
|
1042
|
+
const I = { recordingId: u, sizeBytes: M.sizeBytes, durationSeconds: b };
|
|
1043
|
+
return u = null, c = null, I;
|
|
1044
1044
|
},
|
|
1045
1045
|
dispose() {
|
|
1046
1046
|
d && clearInterval(d), d = null;
|
|
@@ -1049,112 +1049,274 @@ function Re(r, e) {
|
|
|
1049
1049
|
} catch {
|
|
1050
1050
|
}
|
|
1051
1051
|
c = null, l?.close().catch(() => {
|
|
1052
|
-
}), l = null,
|
|
1052
|
+
}), l = null, w = !1;
|
|
1053
1053
|
}
|
|
1054
1054
|
};
|
|
1055
1055
|
}
|
|
1056
|
-
const
|
|
1057
|
-
aurora(
|
|
1058
|
-
const n =
|
|
1059
|
-
n.addColorStop(0, "#050b1e"), n.addColorStop(1, "#0b2540"),
|
|
1056
|
+
const Se = ["none", "blur", "aurora", "cybergrid", "bokeh", "sunset", "image"], ke = ["none", "snow", "confetti", "vignette"], K = {
|
|
1057
|
+
aurora(a, e, t, i) {
|
|
1058
|
+
const n = a.createLinearGradient(0, 0, 0, t);
|
|
1059
|
+
n.addColorStop(0, "#050b1e"), n.addColorStop(1, "#0b2540"), a.fillStyle = n, a.fillRect(0, 0, e, t);
|
|
1060
1060
|
for (let s = 0; s < 3; s += 1) {
|
|
1061
|
-
|
|
1062
|
-
for (let
|
|
1063
|
-
const
|
|
1064
|
-
|
|
1061
|
+
a.beginPath();
|
|
1062
|
+
for (let o = 0; o <= e; o += 16) {
|
|
1063
|
+
const r = t * 0.35 + s * 40 + Math.sin(o / 140 + i / 900 + s) * 60;
|
|
1064
|
+
o === 0 ? a.moveTo(o, r) : a.lineTo(o, r);
|
|
1065
1065
|
}
|
|
1066
|
-
|
|
1066
|
+
a.lineTo(e, 0), a.lineTo(0, 0), a.closePath(), a.fillStyle = `hsla(${140 + s * 40 + Math.sin(i / 1300) * 20}, 80%, 55%, 0.14)`, a.fill();
|
|
1067
1067
|
}
|
|
1068
1068
|
},
|
|
1069
|
-
cybergrid(
|
|
1070
|
-
|
|
1069
|
+
cybergrid(a, e, t, i) {
|
|
1070
|
+
a.fillStyle = "#0a0118", a.fillRect(0, 0, e, t), a.strokeStyle = "rgba(255,0,180,0.5)", a.lineWidth = 1.5;
|
|
1071
1071
|
const n = t * 0.45;
|
|
1072
|
-
for (let
|
|
1073
|
-
const
|
|
1074
|
-
|
|
1072
|
+
for (let o = 0; o < 12; o += 1) {
|
|
1073
|
+
const r = n + (o * 34 + i / 18) % (t - n);
|
|
1074
|
+
a.beginPath(), a.moveTo(0, r), a.lineTo(e, r), a.stroke();
|
|
1075
1075
|
}
|
|
1076
|
-
for (let
|
|
1077
|
-
|
|
1078
|
-
const s =
|
|
1079
|
-
s.addColorStop(0, "#ffd34d"), s.addColorStop(1, "#ff2d78"),
|
|
1076
|
+
for (let o = -8; o <= 8; o += 1)
|
|
1077
|
+
a.beginPath(), a.moveTo(e / 2 + o * 24, n), a.lineTo(e / 2 + o * e * 0.12, t), a.stroke();
|
|
1078
|
+
const s = a.createLinearGradient(0, t * 0.1, 0, n);
|
|
1079
|
+
s.addColorStop(0, "#ffd34d"), s.addColorStop(1, "#ff2d78"), a.fillStyle = s, a.beginPath(), a.arc(e / 2, n, t * 0.22, Math.PI, 0), a.fill();
|
|
1080
1080
|
},
|
|
1081
|
-
bokeh(
|
|
1082
|
-
|
|
1081
|
+
bokeh(a, e, t, i) {
|
|
1082
|
+
a.fillStyle = "#14100c", a.fillRect(0, 0, e, t);
|
|
1083
1083
|
for (let n = 0; n < 26; n += 1) {
|
|
1084
|
-
const s = (Math.sin(n * 12.9898) * 0.5 + 0.5) * e,
|
|
1085
|
-
|
|
1084
|
+
const s = (Math.sin(n * 12.9898) * 0.5 + 0.5) * e, o = (Math.sin(n * 78.233) * 0.5 + 0.5) * t + Math.sin(i / 1500 + n) * 12, r = 14 + n % 5 * 12;
|
|
1085
|
+
a.fillStyle = `hsla(${35 + n % 4 * 12}, 90%, 60%, ${0.1 + n % 3 * 0.05})`, a.beginPath(), a.arc(s, o, r, 0, Math.PI * 2), a.fill();
|
|
1086
1086
|
}
|
|
1087
1087
|
},
|
|
1088
|
-
sunset(
|
|
1089
|
-
const n =
|
|
1090
|
-
n.addColorStop(0, "#2b1055"), n.addColorStop(0.55, "#d1548a"), n.addColorStop(1, "#ffb36b"),
|
|
1088
|
+
sunset(a, e, t, i) {
|
|
1089
|
+
const n = a.createLinearGradient(0, 0, 0, t);
|
|
1090
|
+
n.addColorStop(0, "#2b1055"), n.addColorStop(0.55, "#d1548a"), n.addColorStop(1, "#ffb36b"), a.fillStyle = n, a.fillRect(0, 0, e, t), a.fillStyle = "#ffdf8e", a.beginPath(), a.arc(e * 0.5, t * 0.62 + Math.sin(i / 4e3) * 4, t * 0.13, 0, Math.PI * 2), a.fill(), a.fillStyle = "rgba(20,8,40,0.85)", a.fillRect(0, t * 0.78, e, t * 0.22);
|
|
1091
1091
|
}
|
|
1092
1092
|
};
|
|
1093
|
-
function
|
|
1094
|
-
const t = e.document ?? globalThis.document, i = e.width ?? 1280, n = e.height ?? 720, s = e.frameRate ?? 24,
|
|
1095
|
-
if (!
|
|
1096
|
-
let
|
|
1097
|
-
const
|
|
1098
|
-
|
|
1093
|
+
function Ve(a, e = {}) {
|
|
1094
|
+
const t = e.document ?? globalThis.document, i = e.width ?? 1280, n = e.height ?? 720, s = e.frameRate ?? 24, o = a instanceof MediaStreamTrack ? a : a.getVideoTracks()[0];
|
|
1095
|
+
if (!o) throw new Error("A video track is required");
|
|
1096
|
+
let r = e.background ?? "none", c = e.overlay ?? "none", d = e.backgroundImage ?? null, l = e.segmenter ?? null, u = null, y = !1;
|
|
1097
|
+
const f = t.createElement("video");
|
|
1098
|
+
f.muted = !0, f.playsInline = !0, f.srcObject = new MediaStream([o]), f.play().catch(() => {
|
|
1099
1099
|
});
|
|
1100
|
-
const
|
|
1101
|
-
|
|
1102
|
-
const
|
|
1103
|
-
|
|
1104
|
-
const
|
|
1105
|
-
x: (Math.sin(
|
|
1106
|
-
y: (Math.sin(
|
|
1107
|
-
speed: 0.6 +
|
|
1108
|
-
drift: Math.sin(
|
|
1109
|
-
size: 2 +
|
|
1110
|
-
hue:
|
|
1100
|
+
const w = t.createElement("canvas");
|
|
1101
|
+
w.width = i, w.height = n;
|
|
1102
|
+
const m = w.getContext("2d"), S = t.createElement("canvas");
|
|
1103
|
+
S.width = i, S.height = n;
|
|
1104
|
+
const T = S.getContext("2d"), k = Array.from({ length: 80 }, (p, h) => ({
|
|
1105
|
+
x: (Math.sin(h * 12.9898) * 0.5 + 0.5) * i,
|
|
1106
|
+
y: (Math.sin(h * 78.233) * 0.5 + 0.5) * n,
|
|
1107
|
+
speed: 0.6 + h % 5 * 0.5,
|
|
1108
|
+
drift: Math.sin(h) * 0.6,
|
|
1109
|
+
size: 2 + h % 4,
|
|
1110
|
+
hue: h * 47 % 360
|
|
1111
1111
|
}));
|
|
1112
|
-
function
|
|
1113
|
-
if (
|
|
1114
|
-
|
|
1112
|
+
function b() {
|
|
1113
|
+
if (u) {
|
|
1114
|
+
T.clearRect(0, 0, i, n), T.drawImage(u, 0, 0, i, n), T.globalCompositeOperation = "source-in", T.drawImage(f, 0, 0, i, n), T.globalCompositeOperation = "source-over", m.drawImage(S, 0, 0);
|
|
1115
1115
|
return;
|
|
1116
1116
|
}
|
|
1117
|
-
const
|
|
1118
|
-
|
|
1117
|
+
const p = i * 0.42, h = p * 9 / 16, R = i - p - 24, L = n - h - 24;
|
|
1118
|
+
m.save(), m.shadowColor = "rgba(0,0,0,.5)", m.shadowBlur = 24, m.beginPath(), m.roundRect(R, L, p, h, 14), m.clip(), m.drawImage(f, R, L, p, h), m.restore();
|
|
1119
1119
|
}
|
|
1120
|
-
function
|
|
1121
|
-
if (
|
|
1122
|
-
for (const
|
|
1123
|
-
|
|
1120
|
+
function M(p) {
|
|
1121
|
+
if (r === "none" ? m.drawImage(f, 0, 0, i, n) : r === "blur" ? (m.filter = "blur(14px)", m.drawImage(f, -16, -16, i + 32, n + 32), m.filter = "none", u && b()) : r === "image" && d ? (m.drawImage(d, 0, 0, i, n), b()) : ((K[r] ?? K.aurora)(m, i, n, p), b()), c === "snow" || c === "confetti")
|
|
1122
|
+
for (const h of k)
|
|
1123
|
+
h.y += h.speed * (c === "confetti" ? 1.6 : 1), h.x += h.drift, h.y > n && (h.y = -6, h.x = Math.random() * i), m.fillStyle = c === "snow" ? "rgba(255,255,255,.85)" : `hsl(${h.hue}, 90%, 60%)`, c === "confetti" ? m.fillRect(h.x, h.y, h.size + 2, h.size) : (m.beginPath(), m.arc(h.x, h.y, h.size / 2, 0, Math.PI * 2), m.fill());
|
|
1124
1124
|
else if (c === "vignette") {
|
|
1125
|
-
const
|
|
1126
|
-
|
|
1125
|
+
const h = m.createRadialGradient(i / 2, n / 2, n * 0.4, i / 2, n / 2, n * 0.85);
|
|
1126
|
+
h.addColorStop(0, "rgba(0,0,0,0)"), h.addColorStop(1, "rgba(0,0,0,0.55)"), m.fillStyle = h, m.fillRect(0, 0, i, n);
|
|
1127
1127
|
}
|
|
1128
1128
|
}
|
|
1129
|
-
const
|
|
1130
|
-
|
|
1131
|
-
|
|
1129
|
+
const I = setInterval(() => {
|
|
1130
|
+
M(Date.now()), l && !y && r !== "none" && (y = !0, l.segment(f).then((p) => {
|
|
1131
|
+
u = p;
|
|
1132
1132
|
}).catch(() => {
|
|
1133
|
-
|
|
1133
|
+
u = null;
|
|
1134
1134
|
}).finally(() => {
|
|
1135
|
-
|
|
1135
|
+
y = !1;
|
|
1136
1136
|
}));
|
|
1137
|
-
}, Math.round(1e3 / s)),
|
|
1137
|
+
}, Math.round(1e3 / s)), g = w.captureStream(s);
|
|
1138
1138
|
return {
|
|
1139
|
-
track:
|
|
1140
|
-
stream:
|
|
1141
|
-
setBackground(
|
|
1142
|
-
|
|
1139
|
+
track: g.getVideoTracks()[0],
|
|
1140
|
+
stream: g,
|
|
1141
|
+
setBackground(p, h) {
|
|
1142
|
+
r = Se.includes(p) ? p : "none", h !== void 0 && (d = h), r === "none" && (u = null);
|
|
1143
1143
|
},
|
|
1144
|
-
setOverlay(
|
|
1145
|
-
c =
|
|
1144
|
+
setOverlay(p) {
|
|
1145
|
+
c = ke.includes(p) ? p : "none";
|
|
1146
1146
|
},
|
|
1147
|
-
setSegmenter(
|
|
1148
|
-
l =
|
|
1147
|
+
setSegmenter(p) {
|
|
1148
|
+
l = p, p || (u = null);
|
|
1149
1149
|
},
|
|
1150
1150
|
dispose() {
|
|
1151
|
-
clearInterval(
|
|
1152
|
-
for (const
|
|
1153
|
-
|
|
1151
|
+
clearInterval(I), l?.close?.();
|
|
1152
|
+
for (const p of g.getTracks()) p.stop();
|
|
1153
|
+
f.srcObject = null;
|
|
1154
1154
|
}
|
|
1155
1155
|
};
|
|
1156
1156
|
}
|
|
1157
|
-
|
|
1157
|
+
function le() {
|
|
1158
|
+
return {
|
|
1159
|
+
blinkLeft: 0,
|
|
1160
|
+
blinkRight: 0,
|
|
1161
|
+
jawOpen: 0,
|
|
1162
|
+
smile: 0,
|
|
1163
|
+
browUp: 0,
|
|
1164
|
+
pupilX: 0,
|
|
1165
|
+
pupilY: 0,
|
|
1166
|
+
headYaw: 0,
|
|
1167
|
+
headPitch: 0,
|
|
1168
|
+
headRoll: 0,
|
|
1169
|
+
tracked: !1
|
|
1170
|
+
};
|
|
1171
|
+
}
|
|
1172
|
+
function A(a, e) {
|
|
1173
|
+
const t = a.find((i) => i.categoryName === e);
|
|
1174
|
+
return t ? Math.max(0, Math.min(1, t.score)) : 0;
|
|
1175
|
+
}
|
|
1176
|
+
function we(a) {
|
|
1177
|
+
if (!a || a.length < 16) return { yaw: 0, pitch: 0, roll: 0 };
|
|
1178
|
+
a[0], a[4];
|
|
1179
|
+
const e = a[8], t = a[1], i = a[5], n = a[9], s = a[10], o = Math.atan2(e, s), r = Math.asin(Math.max(-1, Math.min(1, -n))), c = Math.atan2(t, i);
|
|
1180
|
+
return { yaw: o, pitch: r, roll: c };
|
|
1181
|
+
}
|
|
1182
|
+
function Te(a, e, t = 1) {
|
|
1183
|
+
if (!a || a.length === 0) return le();
|
|
1184
|
+
const i = we(e), n = (A(a, "eyeLookOutRight") + A(a, "eyeLookInLeft")) / 2, s = (A(a, "eyeLookOutLeft") + A(a, "eyeLookInRight")) / 2, o = (A(a, "eyeLookUpLeft") + A(a, "eyeLookUpRight")) / 2, r = (A(a, "eyeLookDownLeft") + A(a, "eyeLookDownRight")) / 2, c = (A(a, "mouthSmileLeft") + A(a, "mouthSmileRight")) / 2, d = (A(a, "mouthFrownLeft") + A(a, "mouthFrownRight")) / 2, l = A(a, "eyeBlinkLeft"), u = A(a, "eyeBlinkRight"), y = Math.min(1, Math.abs(i.yaw) / 0.35) * Math.max(0, Math.min(1, t)), f = (l + u) / 2;
|
|
1185
|
+
return {
|
|
1186
|
+
blinkLeft: l + (f - l) * y,
|
|
1187
|
+
blinkRight: u + (f - u) * y,
|
|
1188
|
+
jawOpen: A(a, "jawOpen"),
|
|
1189
|
+
smile: c - d,
|
|
1190
|
+
browUp: (A(a, "browInnerUp") + A(a, "browOuterUpLeft") + A(a, "browOuterUpRight")) / 3,
|
|
1191
|
+
pupilX: n - s,
|
|
1192
|
+
pupilY: r - o,
|
|
1193
|
+
headYaw: i.yaw,
|
|
1194
|
+
headPitch: i.pitch,
|
|
1195
|
+
headRoll: i.roll,
|
|
1196
|
+
tracked: !0
|
|
1197
|
+
};
|
|
1198
|
+
}
|
|
1199
|
+
function X(a, e, t = 0.4) {
|
|
1200
|
+
const i = (n, s) => n + (s - n) * t;
|
|
1201
|
+
return {
|
|
1202
|
+
blinkLeft: i(a.blinkLeft, e.blinkLeft),
|
|
1203
|
+
blinkRight: i(a.blinkRight, e.blinkRight),
|
|
1204
|
+
jawOpen: i(a.jawOpen, e.jawOpen),
|
|
1205
|
+
smile: i(a.smile, e.smile),
|
|
1206
|
+
browUp: i(a.browUp, e.browUp),
|
|
1207
|
+
pupilX: i(a.pupilX, e.pupilX),
|
|
1208
|
+
pupilY: i(a.pupilY, e.pupilY),
|
|
1209
|
+
headYaw: i(a.headYaw, e.headYaw),
|
|
1210
|
+
headPitch: i(a.headPitch, e.headPitch),
|
|
1211
|
+
headRoll: i(a.headRoll, e.headRoll),
|
|
1212
|
+
tracked: e.tracked
|
|
1213
|
+
};
|
|
1214
|
+
}
|
|
1215
|
+
function be(a, e, t, i, n) {
|
|
1216
|
+
n || (a.fillStyle = "#101822", a.fillRect(0, 0, t, i));
|
|
1217
|
+
const s = n ? n.x + e.headYaw * n.radius * 0.1 : t / 2 + e.headYaw * t * 0.18, o = n ? n.y + e.headPitch * n.radius * 0.1 : i / 2 + e.headPitch * i * 0.18, r = n ? n.radius : Math.min(t, i) * 0.28;
|
|
1218
|
+
a.save(), a.translate(s, o), a.rotate(e.headRoll * 0.6);
|
|
1219
|
+
const c = Math.max(-1.35, Math.min(1.35, e.headYaw)), d = Math.max(-0.9, Math.min(0.9, e.headPitch)), l = Math.sin(c), u = (p) => Math.sin(p + c) * r, y = (p) => Math.cos(p + c), f = Math.sin(d) * r * 0.22;
|
|
1220
|
+
a.fillStyle = "#3a2a1c", a.beginPath(), a.ellipse(-l * r * 0.35, -r * 0.25, r * 0.98, r * 0.95, 0, 0, Math.PI * 2), a.fill(), a.fillStyle = e.tracked ? "#f2c9a0" : "#5a6470", a.beginPath(), a.ellipse(0, 0, r * (1 - Math.abs(l) * 0.12), r * 1.12, 0, 0, Math.PI * 2), a.fill(), a.fillStyle = "#3a2a1c", a.beginPath(), a.ellipse(-l * r * 0.28, -r * 0.72 + f * 0.4, r * 0.92, r * 0.5, 0, Math.PI, Math.PI * 2), a.fill();
|
|
1221
|
+
const w = 0;
|
|
1222
|
+
a.fillStyle = "#e5b58a", a.beginPath();
|
|
1223
|
+
const m = u(w) * 0.9, S = r * 0.12 + f;
|
|
1224
|
+
a.ellipse(m + l * r * 0.14, S, r * 0.11, r * 0.14, 0, 0, Math.PI * 2), a.fill();
|
|
1225
|
+
for (const p of [-1, 1]) {
|
|
1226
|
+
const h = p * 0.42, R = y(h);
|
|
1227
|
+
if (R <= 0.12) continue;
|
|
1228
|
+
const L = u(h) * 0.82, q = Math.max(0.2, R), E = p < 0 ? e.blinkLeft : e.blinkRight, P = Math.max(0.06, 1 - E), C = e.browUp * r * 0.14;
|
|
1229
|
+
a.strokeStyle = "#4a2e18", a.lineWidth = r * 0.07, a.lineCap = "round", a.beginPath(), a.moveTo(L - r * 0.2 * q, -r * 0.42 - C + f), a.quadraticCurveTo(L, -r * 0.52 - C + f, L + r * 0.2 * q, -r * 0.44 - C + f), a.stroke();
|
|
1230
|
+
const D = -r * 0.18 + f;
|
|
1231
|
+
a.fillStyle = "#ffffff", a.beginPath(), a.ellipse(L, D, r * 0.16 * q, r * 0.12 * P, 0, 0, Math.PI * 2), a.fill(), a.fillStyle = "#22303c", a.beginPath(), a.ellipse(
|
|
1232
|
+
L + e.pupilX * r * 0.07 * q,
|
|
1233
|
+
D + e.pupilY * r * 0.05,
|
|
1234
|
+
r * 0.06 * q,
|
|
1235
|
+
r * 0.06 * P,
|
|
1236
|
+
0,
|
|
1237
|
+
0,
|
|
1238
|
+
Math.PI * 2
|
|
1239
|
+
), a.fill();
|
|
1240
|
+
}
|
|
1241
|
+
const T = Math.max(0.25, y(0)), k = u(0) * 0.7, b = r * 0.55 * T, M = r * (0.04 + e.jawOpen * 0.34), I = e.smile * r * 0.12, g = r * 0.42 + f;
|
|
1242
|
+
a.fillStyle = "#8c2f2f", a.beginPath(), a.moveTo(k - b / 2, g - I), a.quadraticCurveTo(k, g + M, k + b / 2, g - I), a.quadraticCurveTo(k, g - M * 0.25, k - b / 2, g - I), a.closePath(), a.fill(), a.restore(), !e.tracked && !n && (a.fillStyle = "#9fb0bd", a.font = `${Math.round(i * 0.045)}px system-ui`, a.textAlign = "center", a.fillText("No face detected", t / 2, i * 0.9), a.textAlign = "left");
|
|
1243
|
+
}
|
|
1244
|
+
const Z = {
|
|
1245
|
+
mouthGain: 1.7,
|
|
1246
|
+
blinkGain: 1,
|
|
1247
|
+
eyeSync: 1,
|
|
1248
|
+
smoothing: 0.4,
|
|
1249
|
+
avatarScale: 1,
|
|
1250
|
+
avatarLift: 0,
|
|
1251
|
+
lostHoldMs: 400
|
|
1252
|
+
};
|
|
1253
|
+
function ee() {
|
|
1254
|
+
return {
|
|
1255
|
+
render(a, e, t, i, n) {
|
|
1256
|
+
be(a, e, t, i, n ?? void 0);
|
|
1257
|
+
}
|
|
1258
|
+
};
|
|
1259
|
+
}
|
|
1260
|
+
const z = (a) => Math.max(0, Math.min(1, a));
|
|
1261
|
+
function Ue(a, e = {}) {
|
|
1262
|
+
const t = e.document ?? globalThis.document, i = e.width ?? 1280, n = e.height ?? 720, s = e.frameRate ?? 24, o = a instanceof MediaStreamTrack ? a : a.getVideoTracks()[0];
|
|
1263
|
+
if (!o) throw new Error("A video track is required");
|
|
1264
|
+
let r = e.tracker ?? null, c = e.renderer ?? ee(), d = e.mode ?? "replace";
|
|
1265
|
+
const l = { ...Z, ...e.tuning }, u = e.backdrop ?? "#101822", y = t.createElement("video");
|
|
1266
|
+
y.muted = !0, y.playsInline = !0, y.srcObject = new MediaStream([o]), y.play().catch(() => {
|
|
1267
|
+
});
|
|
1268
|
+
const f = t.createElement("canvas");
|
|
1269
|
+
f.width = i, f.height = n;
|
|
1270
|
+
const w = f.getContext("2d");
|
|
1271
|
+
let m = le(), S = null, T = 0;
|
|
1272
|
+
function k(g) {
|
|
1273
|
+
if (g.length <= 454) return;
|
|
1274
|
+
const p = g[10], h = g[152], R = g[234], L = g[454], q = (R.x + L.x) / 2 * i, E = (R.y + L.y) / 2 * n, P = Math.hypot((h.x - p.x) * i, (h.y - p.y) * n), C = Math.max(0.6, Math.cos(m.headPitch)), D = { x: q, y: E, radius: Math.max(24, P / C * 0.8) };
|
|
1275
|
+
S = S ? { x: S.x + (D.x - S.x) * 0.4, y: S.y + (D.y - S.y) * 0.4, radius: S.radius + (D.radius - S.radius) * 0.15 } : D;
|
|
1276
|
+
}
|
|
1277
|
+
function b(g) {
|
|
1278
|
+
if (r && y.readyState >= 2) {
|
|
1279
|
+
let h = null;
|
|
1280
|
+
try {
|
|
1281
|
+
h = r.detect(y, g);
|
|
1282
|
+
} catch {
|
|
1283
|
+
}
|
|
1284
|
+
const R = Te(h?.categories ?? null, h?.matrix ?? null, l.eyeSync);
|
|
1285
|
+
R.jawOpen = z(R.jawOpen * l.mouthGain), R.blinkLeft = z(R.blinkLeft * l.blinkGain), R.blinkRight = z(R.blinkRight * l.blinkGain), R.tracked ? (T = g, m = X(m, R, l.smoothing), h?.landmarks && k(h.landmarks)) : m.tracked && g - T > l.lostHoldMs && (m = X(m, { ...m, jawOpen: 0, browUp: 0, smile: m.smile * 0.5, blinkLeft: 0.1, blinkRight: 0.1 }, 0.05));
|
|
1286
|
+
}
|
|
1287
|
+
d === "overlay" && y.readyState >= 2 ? w.drawImage(y, 0, 0, i, n) : (w.fillStyle = u, w.fillRect(0, 0, i, n));
|
|
1288
|
+
const p = d === "overlay" && S ? { x: S.x, y: S.y + l.avatarLift * S.radius, radius: S.radius * l.avatarScale } : null;
|
|
1289
|
+
c?.render(w, m, i, n, p);
|
|
1290
|
+
}
|
|
1291
|
+
const M = setInterval(() => b(Date.now()), Math.round(1e3 / s)), I = f.captureStream(s);
|
|
1292
|
+
return {
|
|
1293
|
+
track: I.getVideoTracks()[0],
|
|
1294
|
+
stream: I,
|
|
1295
|
+
getRig: () => ({ ...m }),
|
|
1296
|
+
setMode(g) {
|
|
1297
|
+
d = g === "overlay" ? "overlay" : "replace";
|
|
1298
|
+
},
|
|
1299
|
+
setTracker(g) {
|
|
1300
|
+
r?.close?.(), r = g;
|
|
1301
|
+
},
|
|
1302
|
+
setRenderer(g) {
|
|
1303
|
+
c?.dispose?.(), c = g ?? ee();
|
|
1304
|
+
},
|
|
1305
|
+
setTuning(g) {
|
|
1306
|
+
for (const p of Object.keys(Z)) {
|
|
1307
|
+
const h = g[p];
|
|
1308
|
+
typeof h == "number" && Number.isFinite(h) && (l[p] = h);
|
|
1309
|
+
}
|
|
1310
|
+
},
|
|
1311
|
+
getTuning: () => ({ ...l }),
|
|
1312
|
+
dispose() {
|
|
1313
|
+
clearInterval(M), r?.close?.(), c?.dispose?.();
|
|
1314
|
+
for (const g of I.getTracks()) g.stop();
|
|
1315
|
+
y.srcObject = null;
|
|
1316
|
+
}
|
|
1317
|
+
};
|
|
1318
|
+
}
|
|
1319
|
+
class Ce extends EventTarget {
|
|
1158
1320
|
mode;
|
|
1159
1321
|
options;
|
|
1160
1322
|
client = null;
|
|
@@ -1188,7 +1350,7 @@ class fe extends EventTarget {
|
|
|
1188
1350
|
async initialize() {
|
|
1189
1351
|
if (this.client) return this;
|
|
1190
1352
|
try {
|
|
1191
|
-
const t = (this.options.transport === "auto" ? this.mode === "meeting" ? "sfu" : "mesh" : this.options.transport ?? "mesh") === "sfu" ?
|
|
1353
|
+
const t = (this.options.transport === "auto" ? this.mode === "meeting" ? "sfu" : "mesh" : this.options.transport ?? "mesh") === "sfu" ? ye : x;
|
|
1192
1354
|
return this.client = new t({
|
|
1193
1355
|
credential: {
|
|
1194
1356
|
signalingToken: this.options.credential.signalingToken,
|
|
@@ -1207,19 +1369,19 @@ class fe extends EventTarget {
|
|
|
1207
1369
|
iceTransportPolicy: this.options.iceTransportPolicy ?? "all",
|
|
1208
1370
|
localStream: this.options.localStream,
|
|
1209
1371
|
onEvent: (i, n) => this.handleNativeEvent(i, n)
|
|
1210
|
-
}), await this.client.initialize(), this.startStats(), this.emit("initialized", { mode: this.mode, sdkVersion:
|
|
1372
|
+
}), await this.client.initialize(), this.startStats(), this.emit("initialized", { mode: this.mode, sdkVersion: De }), this.options.autoJoin && await this.join(), this;
|
|
1211
1373
|
} catch (e) {
|
|
1212
1374
|
this.state = "failed";
|
|
1213
|
-
const t =
|
|
1214
|
-
throw this.emit("error",
|
|
1375
|
+
const t = re(e, "RTC initialization failed");
|
|
1376
|
+
throw this.emit("error", V(t)), t;
|
|
1215
1377
|
}
|
|
1216
1378
|
}
|
|
1217
1379
|
async join() {
|
|
1218
1380
|
const e = this.requireClient();
|
|
1219
1381
|
return this.joinPromise ? this.joinPromise : (this.state = "joining", this.emit("joining", {}), this.joinPromise = e.join().catch((t) => {
|
|
1220
1382
|
this.state = "failed";
|
|
1221
|
-
const i =
|
|
1222
|
-
throw this.emit("error",
|
|
1383
|
+
const i = re(t, "RTC connection failed");
|
|
1384
|
+
throw this.emit("error", V(i)), i;
|
|
1223
1385
|
}).finally(() => {
|
|
1224
1386
|
this.joinPromise = null;
|
|
1225
1387
|
}), this.joinPromise);
|
|
@@ -1257,14 +1419,14 @@ class fe extends EventTarget {
|
|
|
1257
1419
|
return navigator.mediaDevices?.enumerateDevices ? navigator.mediaDevices.enumerateDevices() : [];
|
|
1258
1420
|
}
|
|
1259
1421
|
getParticipants() {
|
|
1260
|
-
return this.requireClient().getParticipants().map(
|
|
1422
|
+
return this.requireClient().getParticipants().map(ne);
|
|
1261
1423
|
}
|
|
1262
1424
|
getLocalStream() {
|
|
1263
1425
|
return this.client?.getLocalStream() ?? null;
|
|
1264
1426
|
}
|
|
1265
1427
|
getRemoteStreams() {
|
|
1266
1428
|
return (this.client?.getRemoteStreams() ?? []).map((e) => ({
|
|
1267
|
-
participant:
|
|
1429
|
+
participant: ne(e.participant),
|
|
1268
1430
|
stream: e.stream
|
|
1269
1431
|
}));
|
|
1270
1432
|
}
|
|
@@ -1333,19 +1495,19 @@ class fe extends EventTarget {
|
|
|
1333
1495
|
let n = "unavailable";
|
|
1334
1496
|
if (e.requestMedia !== !1 && navigator.mediaDevices?.getUserMedia)
|
|
1335
1497
|
try {
|
|
1336
|
-
(await navigator.mediaDevices.getUserMedia({ audio: this.options.audio, video: this.options.video })).getTracks().forEach((
|
|
1498
|
+
(await navigator.mediaDevices.getUserMedia({ audio: this.options.audio, video: this.options.video })).getTracks().forEach((y) => y.stop()), n = "granted";
|
|
1337
1499
|
} catch {
|
|
1338
1500
|
n = "denied", t.push("media_permission_denied");
|
|
1339
1501
|
}
|
|
1340
|
-
const s = navigator.mediaDevices?.enumerateDevices ? await navigator.mediaDevices.enumerateDevices().catch(() => []) : [],
|
|
1341
|
-
this.options.audio &&
|
|
1502
|
+
const s = navigator.mediaDevices?.enumerateDevices ? await navigator.mediaDevices.enumerateDevices().catch(() => []) : [], o = s.filter((u) => u.kind === "audioinput").length, r = s.filter((u) => u.kind === "videoinput").length;
|
|
1503
|
+
this.options.audio && o === 0 && t.push("microphone_unavailable"), this.options.video && r === 0 && t.push("camera_unavailable");
|
|
1342
1504
|
const c = e.probeUrl ?? this.options.preflightProbeUrl;
|
|
1343
1505
|
let d = null;
|
|
1344
1506
|
if (c) {
|
|
1345
|
-
const
|
|
1507
|
+
const u = performance.now();
|
|
1346
1508
|
try {
|
|
1347
|
-
const
|
|
1348
|
-
d = Math.round(performance.now() -
|
|
1509
|
+
const y = await fetch(c, { method: "HEAD", cache: "no-store", credentials: "omit" });
|
|
1510
|
+
d = Math.round(performance.now() - u), y.ok || t.push("network_probe_failed");
|
|
1349
1511
|
} catch {
|
|
1350
1512
|
t.push("network_probe_failed");
|
|
1351
1513
|
}
|
|
@@ -1355,10 +1517,10 @@ class fe extends EventTarget {
|
|
|
1355
1517
|
sampledAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1356
1518
|
secureContext: i,
|
|
1357
1519
|
mediaPermission: n,
|
|
1358
|
-
microphoneCount:
|
|
1359
|
-
cameraCount:
|
|
1520
|
+
microphoneCount: o,
|
|
1521
|
+
cameraCount: r,
|
|
1360
1522
|
probeLatencyMs: d,
|
|
1361
|
-
effectiveConnectionType:
|
|
1523
|
+
effectiveConnectionType: ae()?.effectiveType ?? null,
|
|
1362
1524
|
issues: t
|
|
1363
1525
|
};
|
|
1364
1526
|
return this.emit("preflight", l), this.options.autoReportStats && await this.reportQuality({
|
|
@@ -1371,7 +1533,7 @@ class fe extends EventTarget {
|
|
|
1371
1533
|
}), l;
|
|
1372
1534
|
}
|
|
1373
1535
|
async collectQualitySample(e = "runtime") {
|
|
1374
|
-
const t = this.options.statsProvider ? await this.options.statsProvider() : {}, i = this.peerConnection ? await
|
|
1536
|
+
const t = this.options.statsProvider ? await this.options.statsProvider() : {}, i = this.peerConnection ? await Pe(this.peerConnection, this.previousCounters) : null;
|
|
1375
1537
|
i?.counters && (this.previousCounters = i.counters);
|
|
1376
1538
|
const s = { ...{
|
|
1377
1539
|
sampleType: e,
|
|
@@ -1400,10 +1562,10 @@ class fe extends EventTarget {
|
|
|
1400
1562
|
transportProtocol: null,
|
|
1401
1563
|
candidateType: null,
|
|
1402
1564
|
qualityLimitationReason: null,
|
|
1403
|
-
deviceMemoryGb:
|
|
1404
|
-
effectiveConnectionType:
|
|
1405
|
-
}, ...i?.sample ?? {}, ...t, sampleType: e, sampledAt: (/* @__PURE__ */ new Date()).toISOString() },
|
|
1406
|
-
return s.networkScore =
|
|
1565
|
+
deviceMemoryGb: Le(),
|
|
1566
|
+
effectiveConnectionType: ae()?.effectiveType ?? null
|
|
1567
|
+
}, ...i?.sample ?? {}, ...t, sampleType: e, sampledAt: (/* @__PURE__ */ new Date()).toISOString() }, o = Ae(s);
|
|
1568
|
+
return s.networkScore = o.networkScore, s.estimatedMos = o.estimatedMos, this.latestQuality = s, s;
|
|
1407
1569
|
}
|
|
1408
1570
|
async reportQuality(e) {
|
|
1409
1571
|
const t = this.options.credential.telemetryToken, i = this.options.telemetryEndpoint ?? this.options.credential.telemetryEndpoint;
|
|
@@ -1453,7 +1615,7 @@ class fe extends EventTarget {
|
|
|
1453
1615
|
const i = Date.now(), n = e !== "runtime" || i - this.lastTelemetryAt >= this.options.telemetryInterval;
|
|
1454
1616
|
this.options.autoReportStats && n && (await this.reportQuality(t), this.lastTelemetryAt = i);
|
|
1455
1617
|
} catch (t) {
|
|
1456
|
-
this.emit("telemetryerror",
|
|
1618
|
+
this.emit("telemetryerror", V(t));
|
|
1457
1619
|
} finally {
|
|
1458
1620
|
this.statsRunning = !1;
|
|
1459
1621
|
}
|
|
@@ -1470,8 +1632,8 @@ class fe extends EventTarget {
|
|
|
1470
1632
|
}
|
|
1471
1633
|
const t = String(e.qualityLimitationReason ?? "").toLowerCase(), i = (e.packetLossPct ?? 0) >= 8 || (e.rttMs ?? 0) >= 800 || t === "cpu" || t === "bandwidth", n = i || (e.packetLossPct ?? 0) >= 3 || (e.rttMs ?? 0) >= 350 || e.availableOutgoingBitrateBps != null && e.availableOutgoingBitrateBps < 35e4, s = (e.packetLossPct ?? 100) < 1 && (e.rttMs ?? 1e3) < 180 && !t && (e.availableOutgoingBitrateBps == null || e.availableOutgoingBitrateBps > 1e6);
|
|
1472
1634
|
this.poorQualitySamples = n ? this.poorQualitySamples + 1 : 0, this.goodQualitySamples = s ? this.goodQualitySamples + 1 : 0;
|
|
1473
|
-
const
|
|
1474
|
-
i &&
|
|
1635
|
+
const o = ["low", "medium", "high"], r = o.indexOf(this.effectiveQuality);
|
|
1636
|
+
i && r > 0 ? (this.poorQualitySamples = 0, await this.applyEffectiveQuality("low", "network")) : this.poorQualitySamples >= 2 && r > 0 ? (this.poorQualitySamples = 0, await this.applyEffectiveQuality(o[r - 1], "network")) : this.goodQualitySamples >= 6 && r >= 0 && r < o.length - 1 && (this.goodQualitySamples = 0, await this.applyEffectiveQuality(o[r + 1], "network"));
|
|
1475
1637
|
}
|
|
1476
1638
|
async applyEffectiveQuality(e, t) {
|
|
1477
1639
|
if (this.effectiveQuality === e && this.client) return;
|
|
@@ -1487,21 +1649,21 @@ class fe extends EventTarget {
|
|
|
1487
1649
|
this.dispatchEvent(new CustomEvent(e, { detail: i })), this.options.onEvent?.(i);
|
|
1488
1650
|
}
|
|
1489
1651
|
}
|
|
1490
|
-
async function
|
|
1491
|
-
return new
|
|
1652
|
+
async function Qe(a) {
|
|
1653
|
+
return new Ce(a).initialize();
|
|
1492
1654
|
}
|
|
1493
|
-
let
|
|
1494
|
-
function
|
|
1495
|
-
if (
|
|
1496
|
-
const
|
|
1497
|
-
return e ? (
|
|
1655
|
+
let Q = null;
|
|
1656
|
+
function de() {
|
|
1657
|
+
if (Q) return Q;
|
|
1658
|
+
const a = globalThis, e = a.AudioContext ?? a.webkitAudioContext;
|
|
1659
|
+
return e ? (Q = new e(), Q) : null;
|
|
1498
1660
|
}
|
|
1499
|
-
async function
|
|
1500
|
-
const
|
|
1501
|
-
return
|
|
1502
|
-
}),
|
|
1661
|
+
async function Re() {
|
|
1662
|
+
const a = de();
|
|
1663
|
+
return a ? (a.state === "suspended" && await a.resume().catch(() => {
|
|
1664
|
+
}), a.state === "running") : !1;
|
|
1503
1665
|
}
|
|
1504
|
-
class
|
|
1666
|
+
class Ie {
|
|
1505
1667
|
options;
|
|
1506
1668
|
media = null;
|
|
1507
1669
|
cadenceTimer = null;
|
|
@@ -1510,7 +1672,7 @@ class ve {
|
|
|
1510
1672
|
this.options = e;
|
|
1511
1673
|
}
|
|
1512
1674
|
unlock() {
|
|
1513
|
-
return
|
|
1675
|
+
return Re();
|
|
1514
1676
|
}
|
|
1515
1677
|
startIncoming() {
|
|
1516
1678
|
this.start("incoming", this.options.ringtoneUrl);
|
|
@@ -1538,17 +1700,17 @@ class ve {
|
|
|
1538
1700
|
i(), this.cadenceTimer = setInterval(i, e === "incoming" ? 3e3 : 3500);
|
|
1539
1701
|
}
|
|
1540
1702
|
playBuiltInTone(e) {
|
|
1541
|
-
const t =
|
|
1703
|
+
const t = de();
|
|
1542
1704
|
if (!t || t.state !== "running") return;
|
|
1543
|
-
const i = e === "incoming" ? 1.25 : 1, n = e === "incoming" ? [440, 480] : [425], s = t.createGain(),
|
|
1544
|
-
s.gain.setValueAtTime(1e-4,
|
|
1545
|
-
for (const
|
|
1705
|
+
const i = e === "incoming" ? 1.25 : 1, n = e === "incoming" ? [440, 480] : [425], s = t.createGain(), o = t.currentTime;
|
|
1706
|
+
s.gain.setValueAtTime(1e-4, o), s.gain.exponentialRampToValueAtTime(0.045, o + 0.025), s.gain.setValueAtTime(0.045, o + i - 0.06), s.gain.exponentialRampToValueAtTime(1e-4, o + i), s.connect(t.destination);
|
|
1707
|
+
for (const r of n) {
|
|
1546
1708
|
const c = t.createOscillator();
|
|
1547
|
-
c.type = "sine", c.frequency.value =
|
|
1709
|
+
c.type = "sine", c.frequency.value = r, c.connect(s), this.oscillators.add(c), c.onended = () => this.oscillators.delete(c), c.start(o), c.stop(o + i + 0.02);
|
|
1548
1710
|
}
|
|
1549
1711
|
}
|
|
1550
1712
|
}
|
|
1551
|
-
class
|
|
1713
|
+
class Ee extends EventTarget {
|
|
1552
1714
|
options;
|
|
1553
1715
|
socket = null;
|
|
1554
1716
|
stopped = !1;
|
|
@@ -1575,14 +1737,14 @@ class ye extends EventTarget {
|
|
|
1575
1737
|
if (e.token && !e.token.startsWith("rtcc_")) throw new Error("A valid RTC client token is required");
|
|
1576
1738
|
if (!e.signalingUrl && !e.apiBaseUrl && !globalThis.location?.origin)
|
|
1577
1739
|
throw new Error("signalingUrl or apiBaseUrl is required outside a browser");
|
|
1578
|
-
this.options = e, this.currentToken = e.token ?? null, this.currentTokenExpiresAt = e.tokenExpiresAt, this.callAudio = new
|
|
1740
|
+
this.options = e, this.currentToken = e.token ?? null, this.currentTokenExpiresAt = e.tokenExpiresAt, this.callAudio = new Ie(e), this.mount = te(e.mount), this.scheduleTokenRefresh();
|
|
1579
1741
|
}
|
|
1580
1742
|
connect() {
|
|
1581
1743
|
if (!this.options.signalingUrl) throw new Error("signalingUrl is required to connect signaling");
|
|
1582
1744
|
return this.stopped = !1, this.scheduleTokenRefresh(), this.openSocket("initial"), this;
|
|
1583
1745
|
}
|
|
1584
1746
|
setMount(e) {
|
|
1585
|
-
this.clearUi(), this.mount =
|
|
1747
|
+
this.clearUi(), this.mount = te(e), this.currentCall && this.renderIncoming(this.currentCall);
|
|
1586
1748
|
}
|
|
1587
1749
|
/** Binds media lifetime to a call. Terminal call states automatically leave and destroy it. */
|
|
1588
1750
|
attachMediaClient(e, t) {
|
|
@@ -1610,8 +1772,8 @@ class ye extends EventTarget {
|
|
|
1610
1772
|
headers: e.idempotencyKey ? { "idempotency-key": e.idempotencyKey } : void 0,
|
|
1611
1773
|
body: JSON.stringify(i)
|
|
1612
1774
|
});
|
|
1613
|
-
} catch (
|
|
1614
|
-
throw this.callAudio.stop(),
|
|
1775
|
+
} catch (o) {
|
|
1776
|
+
throw this.callAudio.stop(), o;
|
|
1615
1777
|
}
|
|
1616
1778
|
return !s.credential && s.callerCredential && (s.credential = s.callerCredential), this.outgoingCallId = String(s.call?.id ?? "") || null, this.outgoingCallId && this.activeCallIds.add(this.outgoingCallId), this.emit("outgoingcall", s), s;
|
|
1617
1779
|
})();
|
|
@@ -1668,7 +1830,7 @@ class ye extends EventTarget {
|
|
|
1668
1830
|
/** Applies a call state received through the application's own push or signaling channel. */
|
|
1669
1831
|
handleCallUpdate(e) {
|
|
1670
1832
|
const t = e.id === this.currentCall?.id || e.id === this.outgoingCallId;
|
|
1671
|
-
t && e.status === "accepted" ? (this.activeCallIds.add(e.id), this.callAudio.stop(), this.dismiss(e.id)) : t && ["rejected", "busy", "cancelled", "ended", "failed", "missed"].includes(e.status) && this.showTerminal(e.id,
|
|
1833
|
+
t && e.status === "accepted" ? (this.activeCallIds.add(e.id), this.callAudio.stop(), this.dismiss(e.id)) : t && ["rejected", "busy", "cancelled", "ended", "failed", "missed"].includes(e.status) && this.showTerminal(e.id, Me(e.status)), ["rejected", "busy", "cancelled", "ended", "failed", "missed"].includes(e.status) && this.releaseMedia(e.id), this.emit("callupdated", e);
|
|
1672
1834
|
}
|
|
1673
1835
|
disconnect() {
|
|
1674
1836
|
this.stopped = !0, this.reconnectTimer && clearTimeout(this.reconnectTimer), this.heartbeatTimer && clearInterval(this.heartbeatTimer), this.tokenRefreshTimer && clearTimeout(this.tokenRefreshTimer), this.reconnectTimer = null, this.heartbeatTimer = null, this.tokenRefreshTimer = null, this.socket?.close(1e3, "Client disconnected"), this.socket = null, this.callAudio.stop(), this.dismiss();
|
|
@@ -1684,7 +1846,7 @@ class ye extends EventTarget {
|
|
|
1684
1846
|
try {
|
|
1685
1847
|
t = await this.resolveToken(e, e === "reconnect");
|
|
1686
1848
|
} catch (s) {
|
|
1687
|
-
this.emit("tokenerror",
|
|
1849
|
+
this.emit("tokenerror", V(s)), !this.stopped && this.options.reconnect !== !1 && this.scheduleReconnect();
|
|
1688
1850
|
return;
|
|
1689
1851
|
}
|
|
1690
1852
|
if (this.stopped || this.socket) return;
|
|
@@ -1692,8 +1854,8 @@ class ye extends EventTarget {
|
|
|
1692
1854
|
i.protocol = i.protocol === "https:" ? "wss:" : "ws:";
|
|
1693
1855
|
const n = new WebSocket(i, ["rtc-client", t]);
|
|
1694
1856
|
this.socket = n, n.addEventListener("open", () => {
|
|
1695
|
-
const s = this.reconnectAttempt > 0,
|
|
1696
|
-
this.reconnectAttempt = 0, this.heartbeatDeadline = Date.now() + 45e3, this.emit("signalingconnected", { resumed: s }),
|
|
1857
|
+
const s = this.reconnectAttempt > 0, o = this.lastDisconnect;
|
|
1858
|
+
this.reconnectAttempt = 0, this.heartbeatDeadline = Date.now() + 45e3, this.emit("signalingconnected", { resumed: s }), o && (this.reportSignalingDiagnostic({ event: "recovered", code: o.code, reason: o.reason, wasClean: o.wasClean, outageMs: Date.now() - o.at }), this.lastDisconnect = null), this.heartbeatTimer && clearInterval(this.heartbeatTimer), this.heartbeatTimer = setInterval(() => {
|
|
1697
1859
|
if (n.readyState === WebSocket.OPEN) {
|
|
1698
1860
|
if (Date.now() > this.heartbeatDeadline) {
|
|
1699
1861
|
n.close(4e3, "Signaling heartbeat timed out");
|
|
@@ -1707,14 +1869,14 @@ class ye extends EventTarget {
|
|
|
1707
1869
|
}), n.addEventListener("close", (s) => {
|
|
1708
1870
|
if (this.socket !== n) return;
|
|
1709
1871
|
this.socket = null, this.heartbeatTimer && clearInterval(this.heartbeatTimer), this.heartbeatTimer = null;
|
|
1710
|
-
const
|
|
1872
|
+
const o = !this.stopped && this.options.reconnect !== !1, r = {
|
|
1711
1873
|
code: s.code,
|
|
1712
1874
|
reason: s.reason,
|
|
1713
1875
|
wasClean: s.wasClean,
|
|
1714
|
-
willReconnect:
|
|
1876
|
+
willReconnect: o,
|
|
1715
1877
|
attempt: this.reconnectAttempt + 1
|
|
1716
1878
|
};
|
|
1717
|
-
|
|
1879
|
+
o && (this.lastDisconnect = { code: s.code, reason: s.reason, wasClean: s.wasClean, at: Date.now() }), this.emit("signalingdisconnected", r), this.reportSignalingDiagnostic({ event: o ? "reconnecting" : "disconnected", ...r }), o && this.scheduleReconnect();
|
|
1718
1880
|
}), n.addEventListener("error", () => {
|
|
1719
1881
|
const s = { message: "RTC signaling connection failed", reconnecting: !this.stopped && this.options.reconnect !== !1, attempt: this.reconnectAttempt + 1 };
|
|
1720
1882
|
this.emit("signalingerror", s), this.reportSignalingDiagnostic({ event: "error", attempt: s.attempt });
|
|
@@ -1748,9 +1910,9 @@ class ye extends EventTarget {
|
|
|
1748
1910
|
async request(e, t, i = !1) {
|
|
1749
1911
|
const n = this.options.apiBaseUrl ?? this.options.signalingUrl ?? globalThis.location?.origin;
|
|
1750
1912
|
if (!n) throw new Error("apiBaseUrl is required for call actions");
|
|
1751
|
-
const s = new URL(n, globalThis.location?.href),
|
|
1752
|
-
|
|
1753
|
-
const c = await fetch(new URL(e, s.origin), { ...t, headers:
|
|
1913
|
+
const s = new URL(n, globalThis.location?.href), o = await this.resolveToken("initial"), r = new Headers(t.headers);
|
|
1914
|
+
r.set("authorization", `Bearer ${o}`), r.set("content-type", "application/json");
|
|
1915
|
+
const c = await fetch(new URL(e, s.origin), { ...t, headers: r }), d = await c.json().catch(() => ({}));
|
|
1754
1916
|
if (c.status === 401 && this.options.tokenProvider && !i)
|
|
1755
1917
|
return await this.resolveToken("unauthorized", !0), this.request(e, t, !0);
|
|
1756
1918
|
if (!c.ok) {
|
|
@@ -1780,12 +1942,12 @@ class ye extends EventTarget {
|
|
|
1780
1942
|
n.textContent = e.caller.name, n.style.fontSize = "20px";
|
|
1781
1943
|
const s = document.createElement("div");
|
|
1782
1944
|
Object.assign(s.style, { display: "grid", gridTemplateColumns: "1fr 1fr", gap: "10px" });
|
|
1783
|
-
const
|
|
1784
|
-
|
|
1785
|
-
this.reject(e.id).catch((c) => this.emit("error",
|
|
1786
|
-
}),
|
|
1787
|
-
this.accept(e.id).catch((c) => this.emit("error",
|
|
1788
|
-
}), s.appendChild(
|
|
1945
|
+
const o = ie("Decline", "#fff", "#a32920", "#d9a09b"), r = ie("Answer", "#fff", "#08745f", "#08745f");
|
|
1946
|
+
o.addEventListener("click", () => {
|
|
1947
|
+
this.reject(e.id).catch((c) => this.emit("error", V(c)));
|
|
1948
|
+
}), r.addEventListener("click", () => {
|
|
1949
|
+
this.accept(e.id).catch((c) => this.emit("error", V(c)));
|
|
1950
|
+
}), s.appendChild(o), s.appendChild(r), t.appendChild(i), t.appendChild(n), t.appendChild(s), this.mount.replaceChildren(t);
|
|
1789
1951
|
}
|
|
1790
1952
|
dismiss(e) {
|
|
1791
1953
|
e && this.currentCall?.id !== e && this.outgoingCallId !== e || (this.currentCall = null, (!e || this.outgoingCallId === e) && (this.outgoingCallId = null), this.callAudio.stop(), this.clearUi());
|
|
@@ -1852,7 +2014,7 @@ class ye extends EventTarget {
|
|
|
1852
2014
|
const t = Math.max(0, e - this.refreshSkew(e));
|
|
1853
2015
|
this.tokenRefreshTimer = setTimeout(() => {
|
|
1854
2016
|
this.tokenRefreshTimer = null, this.resolveToken("expiring", !0).catch((i) => {
|
|
1855
|
-
this.emit("tokenerror",
|
|
2017
|
+
this.emit("tokenerror", V(i)), this.stopped || (this.tokenRefreshTimer = setTimeout(() => this.scheduleTokenRefresh(), 3e4));
|
|
1856
2018
|
});
|
|
1857
2019
|
}, Math.min(t, 2147e6));
|
|
1858
2020
|
}
|
|
@@ -1866,23 +2028,23 @@ class ye extends EventTarget {
|
|
|
1866
2028
|
this.options.reportSignalingDiagnostics === !1 || this.stopped || this.request("/v1/rtc/client/signaling-events", {
|
|
1867
2029
|
method: "POST",
|
|
1868
2030
|
body: JSON.stringify({ ...e, occurredAt: (/* @__PURE__ */ new Date()).toISOString() })
|
|
1869
|
-
}).catch((t) => this.emit("diagnosticserror",
|
|
2031
|
+
}).catch((t) => this.emit("diagnosticserror", V(t)));
|
|
1870
2032
|
}
|
|
1871
2033
|
emit(e, t) {
|
|
1872
2034
|
const i = { type: e, detail: t, timestamp: (/* @__PURE__ */ new Date()).toISOString() };
|
|
1873
2035
|
this.dispatchEvent(new CustomEvent(e, { detail: i })), this.options.onEvent?.(i);
|
|
1874
2036
|
}
|
|
1875
2037
|
}
|
|
1876
|
-
function
|
|
1877
|
-
const e = new
|
|
1878
|
-
return
|
|
2038
|
+
function xe(a) {
|
|
2039
|
+
const e = new Ee(a);
|
|
2040
|
+
return a.autoConnect !== !1 && a.signalingUrl && e.connect(), e;
|
|
1879
2041
|
}
|
|
1880
|
-
function
|
|
1881
|
-
return
|
|
2042
|
+
function te(a) {
|
|
2043
|
+
return a ? typeof a == "string" ? document.querySelector(a) : a : null;
|
|
1882
2044
|
}
|
|
1883
|
-
function
|
|
2045
|
+
function ie(a, e, t, i) {
|
|
1884
2046
|
const n = document.createElement("button");
|
|
1885
|
-
return n.type = "button", n.textContent =
|
|
2047
|
+
return n.type = "button", n.textContent = a, Object.assign(n.style, {
|
|
1886
2048
|
minHeight: "44px",
|
|
1887
2049
|
border: `1px solid ${i}`,
|
|
1888
2050
|
borderRadius: "6px",
|
|
@@ -1893,7 +2055,7 @@ function Y(r, e, t, i) {
|
|
|
1893
2055
|
fontWeight: "700"
|
|
1894
2056
|
}), n;
|
|
1895
2057
|
}
|
|
1896
|
-
function
|
|
2058
|
+
function Me(a) {
|
|
1897
2059
|
return {
|
|
1898
2060
|
rejected: "Call declined",
|
|
1899
2061
|
busy: "Line busy",
|
|
@@ -1901,96 +2063,104 @@ function Se(r) {
|
|
|
1901
2063
|
ended: "Call ended",
|
|
1902
2064
|
failed: "Call failed",
|
|
1903
2065
|
missed: "No answer"
|
|
1904
|
-
}[
|
|
2066
|
+
}[a] ?? "Call ended";
|
|
1905
2067
|
}
|
|
1906
|
-
function
|
|
2068
|
+
function ne(a) {
|
|
1907
2069
|
return {
|
|
1908
|
-
id:
|
|
1909
|
-
name:
|
|
2070
|
+
id: a.participantId,
|
|
2071
|
+
name: a.displayName,
|
|
1910
2072
|
role: "participant"
|
|
1911
2073
|
};
|
|
1912
2074
|
}
|
|
1913
|
-
async function
|
|
1914
|
-
const t = await
|
|
1915
|
-
let s = 0,
|
|
1916
|
-
t.forEach((
|
|
1917
|
-
n.set(
|
|
1918
|
-
}), t.forEach((
|
|
1919
|
-
if (
|
|
1920
|
-
|
|
1921
|
-
const
|
|
1922
|
-
|
|
2075
|
+
async function Pe(a, e) {
|
|
2076
|
+
const t = await a.getStats(), i = /* @__PURE__ */ new Map(), n = /* @__PURE__ */ new Map();
|
|
2077
|
+
let s = 0, o = 0, r = 0, c = 0, d = 0, l = 0, u = 0, y = 0, f = 0, w = 0, m = 0, S = 0, T = 0, k = null, b = null, M = null, I = null, g = null, p = null;
|
|
2078
|
+
t.forEach((v) => {
|
|
2079
|
+
n.set(v.id, v), v.type === "codec" && i.set(v.id, String(v.mimeType ?? ""));
|
|
2080
|
+
}), t.forEach((v) => {
|
|
2081
|
+
if (v.type === "inbound-rtp" && !v.isRemote && (s += Number(v.bytesReceived ?? 0), r += Math.max(0, Number(v.packetsLost ?? 0)), c += Math.max(0, Number(v.packetsReceived ?? 0)), Number.isFinite(v.jitter) && (d += Number(v.jitter), l += 1), u = Math.max(u, Number(v.framesPerSecond ?? 0)), y = Math.max(y, Number(v.frameWidth ?? 0)), f = Math.max(f, Number(v.frameHeight ?? 0)), w += Number(v.framesDropped ?? 0), m += Number(v.freezeCount ?? 0), S += Number(v.totalFreezesDuration ?? 0), T += Number(v.concealedSamples ?? 0), g ||= i.get(String(v.codecId ?? "")) ?? null), v.type === "outbound-rtp" && !v.isRemote && (o += Number(v.bytesSent ?? 0), p ||= v.qualityLimitationReason ? String(v.qualityLimitationReason) : null, g ||= i.get(String(v.codecId ?? "")) ?? null), v.type === "candidate-pair" && (v.selected || v.nominated) && v.state === "succeeded") {
|
|
2082
|
+
k = Number.isFinite(v.currentRoundTripTime) ? Number(v.currentRoundTripTime) : k, b = Number.isFinite(v.availableOutgoingBitrate) ? Number(v.availableOutgoingBitrate) : b;
|
|
2083
|
+
const N = n.get(v.localCandidateId);
|
|
2084
|
+
M = N?.candidateType ? String(N.candidateType) : M, I = N?.protocol ? String(N.protocol) : I;
|
|
1923
2085
|
}
|
|
1924
2086
|
});
|
|
1925
|
-
const
|
|
2087
|
+
const h = Date.now(), R = e ? Math.max(1e-3, (h - e.timestamp) / 1e3) : 0, L = e ? Math.max(0, Math.round((s - e.inboundBytes) * 8 / R)) : null, q = e ? Math.max(0, Math.round((o - e.outboundBytes) * 8 / R)) : null, E = r + c, P = e ? Math.max(0, r - e.packetsLost) : r, C = e ? Math.max(0, c - e.packetsReceived) : c, D = P + C;
|
|
1926
2088
|
return {
|
|
1927
|
-
counters: { timestamp:
|
|
2089
|
+
counters: { timestamp: h, inboundBytes: s, outboundBytes: o, packetsLost: r, packetsReceived: c },
|
|
1928
2090
|
sample: {
|
|
1929
|
-
rttMs:
|
|
2091
|
+
rttMs: k === null ? null : k * 1e3,
|
|
1930
2092
|
jitterMs: l ? d / l * 1e3 : null,
|
|
1931
|
-
packetLossPct:
|
|
1932
|
-
packetLossCumulativePct:
|
|
1933
|
-
packetsLost:
|
|
2093
|
+
packetLossPct: D ? P / D * 100 : null,
|
|
2094
|
+
packetLossCumulativePct: E ? r / E * 100 : null,
|
|
2095
|
+
packetsLost: r,
|
|
1934
2096
|
packetsReceived: c,
|
|
1935
2097
|
inboundBitrateBps: L,
|
|
1936
|
-
outboundBitrateBps:
|
|
1937
|
-
availableOutgoingBitrateBps:
|
|
1938
|
-
framesPerSecond:
|
|
1939
|
-
frameWidth:
|
|
1940
|
-
frameHeight:
|
|
1941
|
-
framesDropped:
|
|
1942
|
-
freezeCount:
|
|
1943
|
-
freezeDurationMs: Math.round(
|
|
1944
|
-
concealedSamples:
|
|
1945
|
-
codec:
|
|
1946
|
-
transportProtocol:
|
|
1947
|
-
candidateType:
|
|
1948
|
-
qualityLimitationReason:
|
|
2098
|
+
outboundBitrateBps: q,
|
|
2099
|
+
availableOutgoingBitrateBps: b,
|
|
2100
|
+
framesPerSecond: u || null,
|
|
2101
|
+
frameWidth: y || null,
|
|
2102
|
+
frameHeight: f || null,
|
|
2103
|
+
framesDropped: w,
|
|
2104
|
+
freezeCount: m,
|
|
2105
|
+
freezeDurationMs: Math.round(S * 1e3),
|
|
2106
|
+
concealedSamples: T,
|
|
2107
|
+
codec: g,
|
|
2108
|
+
transportProtocol: I,
|
|
2109
|
+
candidateType: M,
|
|
2110
|
+
qualityLimitationReason: p
|
|
1949
2111
|
}
|
|
1950
2112
|
};
|
|
1951
2113
|
}
|
|
1952
|
-
function
|
|
1953
|
-
let e =
|
|
1954
|
-
const t =
|
|
2114
|
+
function Ae(a) {
|
|
2115
|
+
let e = a.mediaScore == null ? 5 : Math.round(se(Number(a.mediaScore), 0, 5));
|
|
2116
|
+
const t = J(a.packetLossPct) ?? 0, i = J(a.rttMs) ?? 0, n = J(a.jitterMs) ?? 0, s = String(a.connectionState ?? "unknown").toLowerCase();
|
|
1955
2117
|
["failed", "closed", "disconnected"].includes(s) ? e = 0 : ["reconnecting", "checking"].includes(s) && (e = Math.min(e, 2)), t >= 15 ? e = Math.min(e, 0) : t >= 8 ? e = Math.min(e, 1) : t >= 3 ? e = Math.min(e, 2) : t >= 1 && (e = Math.min(e, 3)), i >= 1200 ? e = Math.min(e, 0) : i >= 800 ? e = Math.min(e, 1) : i >= 400 ? e = Math.min(e, 2) : i >= 250 && (e = Math.min(e, 3)), n >= 150 ? e = Math.min(e, 1) : n >= 80 ? e = Math.min(e, 2) : n >= 40 && (e = Math.min(e, 3));
|
|
1956
|
-
const
|
|
1957
|
-
return { networkScore: e, estimatedMos:
|
|
2118
|
+
const o = Number(se(4.5 - t * 0.09 - i * 11e-4 - n * 6e-3, 1, 4.5).toFixed(2));
|
|
2119
|
+
return { networkScore: e, estimatedMos: o };
|
|
1958
2120
|
}
|
|
1959
|
-
function
|
|
2121
|
+
function ae() {
|
|
1960
2122
|
return navigator.connection ?? null;
|
|
1961
2123
|
}
|
|
1962
|
-
function
|
|
1963
|
-
const
|
|
1964
|
-
return Number.isFinite(
|
|
2124
|
+
function Le() {
|
|
2125
|
+
const a = Number(navigator.deviceMemory);
|
|
2126
|
+
return Number.isFinite(a) ? a : null;
|
|
1965
2127
|
}
|
|
1966
|
-
function
|
|
1967
|
-
const e = Number(
|
|
2128
|
+
function J(a) {
|
|
2129
|
+
const e = Number(a);
|
|
1968
2130
|
return Number.isFinite(e) ? e : null;
|
|
1969
2131
|
}
|
|
1970
|
-
function
|
|
1971
|
-
return Math.min(t, Math.max(e,
|
|
2132
|
+
function se(a, e, t) {
|
|
2133
|
+
return Math.min(t, Math.max(e, a));
|
|
1972
2134
|
}
|
|
1973
|
-
function
|
|
1974
|
-
return
|
|
2135
|
+
function V(a) {
|
|
2136
|
+
return a instanceof Error ? { name: a.name, message: a.message } : { name: "ServiceError", message: String(a ?? "Service request failed") };
|
|
1975
2137
|
}
|
|
1976
|
-
function
|
|
1977
|
-
return
|
|
2138
|
+
function re(a, e) {
|
|
2139
|
+
return a instanceof Error ? a : new Error(e);
|
|
1978
2140
|
}
|
|
1979
|
-
const
|
|
2141
|
+
const De = "1.3.16";
|
|
1980
2142
|
export {
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
2143
|
+
Z as AVATAR_TUNING_DEFAULTS,
|
|
2144
|
+
Se as BACKGROUND_PRESETS,
|
|
2145
|
+
ke as OVERLAY_EFFECTS,
|
|
2146
|
+
Ce as RtcClient,
|
|
2147
|
+
Ee as RtcIncomingClient,
|
|
2148
|
+
qe as SPEAKER_NOISE_FLOOR,
|
|
2149
|
+
Oe as SPEAKER_TAKEOVER_RATIO,
|
|
2150
|
+
Ue as createAvatarPipeline,
|
|
2151
|
+
je as createCallRecorder,
|
|
2152
|
+
Ne as createPictureInPictureController,
|
|
2153
|
+
Qe as createRtcClient,
|
|
2154
|
+
xe as createRtcIncomingClient,
|
|
2155
|
+
Ve as createVideoEffectsPipeline,
|
|
2156
|
+
be as drawAvatar,
|
|
2157
|
+
we as headPoseFromMatrix,
|
|
2158
|
+
le as neutralRig,
|
|
2159
|
+
oe as pickActiveSpeaker,
|
|
2160
|
+
Te as rigFromBlendshapes,
|
|
2161
|
+
K as scenePainters,
|
|
2162
|
+
X as smoothRig,
|
|
2163
|
+
ee as stylizedAvatarRenderer,
|
|
2164
|
+
Re as unlockRtcCallAudio,
|
|
2165
|
+
De as version
|
|
1996
2166
|
};
|