@streaming-cdn/rtc-web 1.3.20 → 1.3.22
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 +12 -1
- package/dist/index.d.ts +14 -1
- package/dist/peer-quality.d.ts +2 -0
- package/dist/rtc-web.es.js +284 -273
- package/dist/rtc-web.umd.js +1 -1
- package/dist/url-scheme.d.ts +13 -0
- package/package.json +1 -1
package/dist/rtc-web.es.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
const
|
|
2
|
-
function
|
|
1
|
+
const Ne = 0.02, je = 1.4;
|
|
2
|
+
function le(a, e, t = 0.02, i = 1.4) {
|
|
3
3
|
const n = a.filter((r) => r.level >= t);
|
|
4
4
|
if (n.length === 0) return null;
|
|
5
5
|
const s = n.reduce((r, c) => c.level > r.level ? c : r), o = n.find((r) => r.participantId === e);
|
|
6
6
|
return o ? s.participantId === e ? e : s.level >= o.level * i ? s.participantId : e : s.participantId;
|
|
7
7
|
}
|
|
8
|
-
function
|
|
8
|
+
function de(a) {
|
|
9
9
|
const e = [];
|
|
10
10
|
for (const t of a) {
|
|
11
11
|
if (String(t.type ?? "") !== "inbound-rtp" || String(t.kind ?? t.mediaType ?? "") !== "audio") continue;
|
|
@@ -14,12 +14,12 @@ function ce(a) {
|
|
|
14
14
|
}
|
|
15
15
|
return e;
|
|
16
16
|
}
|
|
17
|
-
const
|
|
17
|
+
const j = {
|
|
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
|
+
}, me = {
|
|
23
23
|
warmupSamples: 3,
|
|
24
24
|
poorSamplesToStepDown: 2,
|
|
25
25
|
goodSamplesToStepUp: 6,
|
|
@@ -29,29 +29,30 @@ const N = {
|
|
|
29
29
|
poorRttMs: 350,
|
|
30
30
|
goodLossPct: 1,
|
|
31
31
|
goodRttMs: 250,
|
|
32
|
-
sustainRatio: 0.8
|
|
32
|
+
sustainRatio: 0.8,
|
|
33
|
+
bandwidthHeadroomRatio: 1.25
|
|
33
34
|
};
|
|
34
|
-
function
|
|
35
|
+
function pe(a) {
|
|
35
36
|
const e = String(a ?? "").trim().toLowerCase();
|
|
36
37
|
return !e || e === "none" ? "" : e === "cpu" || e === "bandwidth" ? e : "other";
|
|
37
38
|
}
|
|
38
|
-
function
|
|
39
|
-
const s = { ...
|
|
40
|
-
return l > c ? { quality: o[c], poorSamples: 0, goodSamples: 0, samplesSeen: d, changed: !0 } : u ?
|
|
39
|
+
function fe(a, e, t, i, n = {}) {
|
|
40
|
+
const s = { ...me, ...n.thresholds }, o = ["low", "medium", "high"], r = n.ceiling && n.ceiling !== "audio" ? n.ceiling : "high", c = o.indexOf(r), l = o.indexOf(a), d = (n.samplesSeen ?? s.warmupSamples) + 1, u = d <= s.warmupSamples, k = pe(e.qualityLimitationReason), f = e.packetLossPct ?? 0, v = e.rttMs ?? 0, C = e.availableOutgoingBitrateBps, y = j[a].maxBitrate, w = f >= s.criticalLossPct || v >= s.criticalRttMs || k === "cpu", p = k === "bandwidth" && (C == null || C < y * s.bandwidthHeadroomRatio), R = w || f >= s.poorLossPct || v >= s.poorRttMs || p, P = C == null || C >= y * s.sustainRatio, L = f < s.goodLossPct && v < s.goodRttMs && !k && P, I = R ? t + 1 : 0, A = L ? i + 1 : 0, S = { quality: a, poorSamples: I, goodSamples: A, samplesSeen: d, changed: !1 };
|
|
41
|
+
return l > c ? { quality: o[c], poorSamples: 0, goodSamples: 0, samplesSeen: d, changed: !0 } : u ? S : w && l > 0 ? { quality: o[l - 1], poorSamples: 0, goodSamples: 0, samplesSeen: d, changed: !0 } : I >= s.poorSamplesToStepDown && l > 0 ? { quality: o[l - 1], poorSamples: 0, goodSamples: 0, samplesSeen: d, changed: !0 } : A >= s.goodSamplesToStepUp && l < c ? { quality: o[l + 1], poorSamples: 0, goodSamples: 0, samplesSeen: d, changed: !0 } : S;
|
|
41
42
|
}
|
|
42
|
-
function
|
|
43
|
+
function ge(a, e) {
|
|
43
44
|
const t = a instanceof Map ? a : new Map(a);
|
|
44
45
|
let i = 0, n = 0, s = null, o = null, r = null;
|
|
45
46
|
for (const d of t.values()) {
|
|
46
47
|
const u = String(d.type ?? "");
|
|
47
48
|
if (u === "outbound-rtp" && String(d.kind ?? "") === "video" && (i += Number(d.packetsSent ?? 0), s = d.qualityLimitationReason ?? s), u === "remote-inbound-rtp" && String(d.kind ?? "") === "video") {
|
|
48
49
|
n += Number(d.packetsLost ?? 0);
|
|
49
|
-
const
|
|
50
|
-
Number.isFinite(
|
|
50
|
+
const k = Number(d.roundTripTime ?? NaN);
|
|
51
|
+
Number.isFinite(k) && (o = k * 1e3);
|
|
51
52
|
}
|
|
52
53
|
if (u === "candidate-pair" && (d.nominated === !0 || String(d.state ?? "") === "succeeded")) {
|
|
53
|
-
const
|
|
54
|
-
o == null && Number.isFinite(
|
|
54
|
+
const k = Number(d.currentRoundTripTime ?? NaN);
|
|
55
|
+
o == null && Number.isFinite(k) && (o = k * 1e3);
|
|
55
56
|
const f = Number(d.availableOutgoingBitrate ?? NaN);
|
|
56
57
|
Number.isFinite(f) && (r = f);
|
|
57
58
|
}
|
|
@@ -67,9 +68,17 @@ function pe(a, e) {
|
|
|
67
68
|
counters: c
|
|
68
69
|
};
|
|
69
70
|
}
|
|
70
|
-
|
|
71
|
+
function $(a, e) {
|
|
72
|
+
const t = new URL(String(a), e);
|
|
73
|
+
return t.protocol === "https:" ? t.protocol = "wss:" : t.protocol === "http:" && (t.protocol = "ws:"), t;
|
|
74
|
+
}
|
|
75
|
+
function J(a, e) {
|
|
76
|
+
const t = new URL(String(a), e);
|
|
77
|
+
return t.protocol === "wss:" ? t.protocol = "https:" : t.protocol === "ws:" && (t.protocol = "http:"), t;
|
|
78
|
+
}
|
|
79
|
+
const ye = {
|
|
71
80
|
audio: { active: !1, maxBitrate: 0, maxFramerate: 0, scaleResolutionDownBy: 4 }
|
|
72
|
-
},
|
|
81
|
+
}, ve = { active: !0, maxBitrate: 4e6, maxFramerate: 30, scaleResolutionDownBy: 1 };
|
|
73
82
|
class Q {
|
|
74
83
|
options;
|
|
75
84
|
socket = null;
|
|
@@ -212,9 +221,7 @@ class Q {
|
|
|
212
221
|
this.stopped = !1, !this.localStream && (this.options.audio || this.options.video) && (this.localStream = await navigator.mediaDevices.getUserMedia({ audio: this.options.audio, video: this.options.video })), this.localStream && this.options.onEvent("localstream", { stream: this.localStream }), await this.openSocket(!1);
|
|
213
222
|
}
|
|
214
223
|
async openSocket(e) {
|
|
215
|
-
const { credential: t } = this.options, i =
|
|
216
|
-
i.protocol = i.protocol === "https:" ? "wss:" : "ws:";
|
|
217
|
-
const n = new Promise((c, l) => {
|
|
224
|
+
const { credential: t } = this.options, i = $(t.signalingUrl, globalThis.location?.href), n = new Promise((c, l) => {
|
|
218
225
|
this.resolveJoin = c, this.rejectJoin = l;
|
|
219
226
|
}), s = new WebSocket(i, ["rtc-client", t.signalingToken]), o = ++this.socketGeneration;
|
|
220
227
|
this.socket = s;
|
|
@@ -351,7 +358,7 @@ class Q {
|
|
|
351
358
|
});
|
|
352
359
|
if (e.connection.signalingState !== "stable") return;
|
|
353
360
|
await e.connection.setLocalDescription(t);
|
|
354
|
-
const i =
|
|
361
|
+
const i = G();
|
|
355
362
|
e.activeNegotiationId = i, this.send({
|
|
356
363
|
type: "rtc.offer",
|
|
357
364
|
targetParticipantId: e.identity.participantId,
|
|
@@ -391,7 +398,7 @@ class Q {
|
|
|
391
398
|
async applyPeerVideoQuality(e) {
|
|
392
399
|
const t = this.screenStream?.getVideoTracks()[0]?.id;
|
|
393
400
|
for (const i of e.connection.getSenders().filter((n) => n.track?.kind === "video")) {
|
|
394
|
-
const n = !!(t && i.track?.id === t), s = n ?
|
|
401
|
+
const n = !!(t && i.track?.id === t), s = n ? ve : this.quality === "audio" ? ye.audio : j[e.quality], o = i.getParameters(), r = o.encodings?.length ? o.encodings : [{}];
|
|
395
402
|
o.encodings = r.map((c) => ({ ...c, ...s })), o.degradationPreference = n ? "maintain-resolution" : "maintain-framerate", await i.setParameters(o);
|
|
396
403
|
}
|
|
397
404
|
}
|
|
@@ -411,11 +418,11 @@ class Q {
|
|
|
411
418
|
if (i.connection.connectionState === "connected")
|
|
412
419
|
try {
|
|
413
420
|
const n = await i.connection.getStats();
|
|
414
|
-
for (const s of
|
|
421
|
+
for (const s of de(n.values()))
|
|
415
422
|
e.push({ participantId: i.identity.participantId, level: s.level });
|
|
416
423
|
} catch {
|
|
417
424
|
}
|
|
418
|
-
const t =
|
|
425
|
+
const t = le(e, this.activeSpeaker);
|
|
419
426
|
t !== this.activeSpeaker && (this.activeSpeaker = t, this.options.onEvent("activespeaker", { participantId: t }));
|
|
420
427
|
}
|
|
421
428
|
async samplePeerQuality() {
|
|
@@ -428,9 +435,9 @@ class Q {
|
|
|
428
435
|
} catch {
|
|
429
436
|
continue;
|
|
430
437
|
}
|
|
431
|
-
const { sample: i, counters: n } =
|
|
438
|
+
const { sample: i, counters: n } = ge(t, e.counters);
|
|
432
439
|
e.counters = n;
|
|
433
|
-
const s =
|
|
440
|
+
const s = fe(e.quality, i, e.poorSamples, e.goodSamples, {
|
|
434
441
|
samplesSeen: e.samplesSeen,
|
|
435
442
|
ceiling: this.quality
|
|
436
443
|
});
|
|
@@ -487,7 +494,7 @@ class Q {
|
|
|
487
494
|
}
|
|
488
495
|
send(e) {
|
|
489
496
|
this.socket?.readyState === WebSocket.OPEN && this.socket.send(JSON.stringify({
|
|
490
|
-
clientMessageId: e.clientMessageId ??
|
|
497
|
+
clientMessageId: e.clientMessageId ?? G(),
|
|
491
498
|
...e
|
|
492
499
|
}));
|
|
493
500
|
}
|
|
@@ -495,15 +502,15 @@ class Q {
|
|
|
495
502
|
for (const t of e?.getTracks() ?? []) t.stop();
|
|
496
503
|
}
|
|
497
504
|
}
|
|
498
|
-
function
|
|
505
|
+
function G() {
|
|
499
506
|
return globalThis.crypto?.randomUUID?.() ?? `${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`;
|
|
500
507
|
}
|
|
501
|
-
const
|
|
502
|
-
{ rid: "a", maxBitrate:
|
|
503
|
-
{ rid: "b", maxBitrate:
|
|
504
|
-
{ rid: "c", maxBitrate:
|
|
505
|
-
],
|
|
506
|
-
class
|
|
508
|
+
const H = { active: !0, maxBitrate: 4e6, maxFramerate: 30, scaleResolutionDownBy: 1 }, K = [
|
|
509
|
+
{ rid: "a", maxBitrate: j.high.maxBitrate, maxFramerate: j.high.maxFramerate },
|
|
510
|
+
{ rid: "b", maxBitrate: j.medium.maxBitrate, maxFramerate: j.medium.maxFramerate, scaleResolutionDownBy: 2 },
|
|
511
|
+
{ rid: "c", maxBitrate: j.low.maxBitrate, maxFramerate: j.low.maxFramerate, scaleResolutionDownBy: 4 }
|
|
512
|
+
], X = { high: "a", medium: "b", low: "c" };
|
|
513
|
+
class Se {
|
|
507
514
|
options;
|
|
508
515
|
apiBase;
|
|
509
516
|
socket = null;
|
|
@@ -535,7 +542,7 @@ class ye {
|
|
|
535
542
|
negotiationQueue = Promise.resolve();
|
|
536
543
|
socketGeneration = 0;
|
|
537
544
|
constructor(e) {
|
|
538
|
-
this.options = e, this.localStream = e.localStream ?? null, this.quality = e.quality ?? "high", this.apiBase =
|
|
545
|
+
this.options = e, this.localStream = e.localStream ?? null, this.quality = e.quality ?? "high", this.apiBase = J(e.credential.signalingUrl, globalThis.location?.href).origin;
|
|
539
546
|
}
|
|
540
547
|
async initialize() {
|
|
541
548
|
if (!globalThis.RTCPeerConnection || !globalThis.WebSocket)
|
|
@@ -636,9 +643,7 @@ class ye {
|
|
|
636
643
|
}
|
|
637
644
|
// --- signaling -----------------------------------------------------------
|
|
638
645
|
async openSocket(e) {
|
|
639
|
-
const { credential: t } = this.options, i =
|
|
640
|
-
i.protocol = i.protocol === "https:" ? "wss:" : "ws:";
|
|
641
|
-
const n = new Promise((c, l) => {
|
|
646
|
+
const { credential: t } = this.options, i = $(t.signalingUrl, globalThis.location?.href), n = new Promise((c, l) => {
|
|
642
647
|
this.resolveJoin = c, this.rejectJoin = l;
|
|
643
648
|
}), s = new WebSocket(i, ["rtc-client", t.signalingToken]), o = ++this.socketGeneration;
|
|
644
649
|
this.socket = s;
|
|
@@ -721,7 +726,7 @@ class ye {
|
|
|
721
726
|
// A single encoding when simulcast is off: constrained publishers
|
|
722
727
|
// (phone CPU, cellular uplink) should not pay for three encoders. The
|
|
723
728
|
// quality ladder then adapts that one encoding instead of gating layers.
|
|
724
|
-
...r.kind === "video" && this.simulcastEnabled() ? { sendEncodings:
|
|
729
|
+
...r.kind === "video" && this.simulcastEnabled() ? { sendEncodings: K.map((c) => ({ ...c })) } : {}
|
|
725
730
|
})), s = await t.createOffer();
|
|
726
731
|
await t.setLocalDescription(s);
|
|
727
732
|
const o = await this.sfuFetch(
|
|
@@ -821,7 +826,7 @@ class ye {
|
|
|
821
826
|
n && await this.sfuFetch("PUT", `/v1/rtc/sfu/sessions/${encodeURIComponent(this.sessionId)}/tracks/update`, {
|
|
822
827
|
tracks: [{
|
|
823
828
|
mid: n,
|
|
824
|
-
simulcast: { preferredRid:
|
|
829
|
+
simulcast: { preferredRid: X[t], priorityOrdering: "asciibetical", ridNotAvailable: "asciibetical" }
|
|
825
830
|
}]
|
|
826
831
|
});
|
|
827
832
|
}
|
|
@@ -836,15 +841,15 @@ class ye {
|
|
|
836
841
|
if (!e) return;
|
|
837
842
|
const t = this.screenStream?.getVideoTracks()[0]?.id, i = !!(t && e.track?.id === t), n = e.getParameters(), s = n.encodings?.length ? n.encodings : [{}];
|
|
838
843
|
if (s.length > 1) {
|
|
839
|
-
const o = this.quality === "audio" ? null :
|
|
844
|
+
const o = this.quality === "audio" ? null : X[this.quality];
|
|
840
845
|
n.encodings = s.map((r) => {
|
|
841
846
|
if (i)
|
|
842
|
-
return { ...r, active: r.rid === "a", ...r.rid === "a" ? { maxBitrate:
|
|
843
|
-
const c =
|
|
847
|
+
return { ...r, active: r.rid === "a", ...r.rid === "a" ? { maxBitrate: H.maxBitrate, maxFramerate: H.maxFramerate } : {} };
|
|
848
|
+
const c = K.find((d) => d.rid === r.rid), l = o != null && String(r.rid ?? "") >= o;
|
|
844
849
|
return { ...r, ...c ?? {}, active: l };
|
|
845
850
|
});
|
|
846
851
|
} else {
|
|
847
|
-
const o = this.quality === "audio" ?
|
|
852
|
+
const o = this.quality === "audio" ? j.audio : j[this.quality], r = i ? H : o;
|
|
848
853
|
n.encodings = s.map((c) => ({ ...c, ...r }));
|
|
849
854
|
}
|
|
850
855
|
n.degradationPreference = i ? "maintain-resolution" : "maintain-framerate", await e.setParameters(n);
|
|
@@ -911,11 +916,11 @@ class ye {
|
|
|
911
916
|
return;
|
|
912
917
|
}
|
|
913
918
|
const i = [];
|
|
914
|
-
for (const s of
|
|
919
|
+
for (const s of de(t.values())) {
|
|
915
920
|
const o = s.mid ? this.midToParticipant.get(s.mid) : void 0;
|
|
916
921
|
o && i.push({ participantId: o, level: s.level });
|
|
917
922
|
}
|
|
918
|
-
const n =
|
|
923
|
+
const n = le(i, this.activeSpeaker);
|
|
919
924
|
n !== this.activeSpeaker && (this.activeSpeaker = n, this.options.onEvent("activespeaker", { participantId: n }));
|
|
920
925
|
}
|
|
921
926
|
clearTimers() {
|
|
@@ -932,7 +937,7 @@ class ye {
|
|
|
932
937
|
}
|
|
933
938
|
send(e) {
|
|
934
939
|
this.socket?.readyState === WebSocket.OPEN && this.socket.send(JSON.stringify({
|
|
935
|
-
clientMessageId: e.clientMessageId ??
|
|
940
|
+
clientMessageId: e.clientMessageId ?? ke(),
|
|
936
941
|
...e
|
|
937
942
|
}));
|
|
938
943
|
}
|
|
@@ -940,10 +945,10 @@ class ye {
|
|
|
940
945
|
for (const t of e?.getTracks() ?? []) t.stop();
|
|
941
946
|
}
|
|
942
947
|
}
|
|
943
|
-
function
|
|
948
|
+
function ke() {
|
|
944
949
|
return globalThis.crypto?.randomUUID?.() ?? `${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`;
|
|
945
950
|
}
|
|
946
|
-
function
|
|
951
|
+
function xe(a, e = {}) {
|
|
947
952
|
const t = e.document ?? globalThis.document, i = !!(t && t.pictureInPictureEnabled);
|
|
948
953
|
let n = null;
|
|
949
954
|
function s() {
|
|
@@ -971,17 +976,17 @@ function Ne(a, e = {}) {
|
|
|
971
976
|
}
|
|
972
977
|
};
|
|
973
978
|
}
|
|
974
|
-
function
|
|
975
|
-
const t = e.document ?? globalThis.document, i = e.fetchImplementation ?? globalThis.fetch.bind(globalThis), n =
|
|
976
|
-
let c = null, l = null, d = null, u = null,
|
|
977
|
-
async function
|
|
978
|
-
const P = await i(`${n}${
|
|
979
|
+
function Ve(a, e) {
|
|
980
|
+
const t = e.document ?? globalThis.document, i = e.fetchImplementation ?? globalThis.fetch.bind(globalThis), n = J(e.credential.signalingUrl, globalThis.location?.href).origin, s = e.mimeType ?? "video/webm", o = e.height ?? 720, r = Math.round(o * 16 / 9);
|
|
981
|
+
let c = null, l = null, d = null, u = null, k = 0, f = [], v = !1;
|
|
982
|
+
async function C(y, w, p, R = "application/json") {
|
|
983
|
+
const P = await i(`${n}${w}`, {
|
|
979
984
|
method: y,
|
|
980
985
|
headers: {
|
|
981
986
|
authorization: `Bearer ${e.credential.signalingToken}`,
|
|
982
|
-
"content-type":
|
|
987
|
+
"content-type": R
|
|
983
988
|
},
|
|
984
|
-
body: p === void 0 ? void 0 :
|
|
989
|
+
body: p === void 0 ? void 0 : R === "application/json" ? JSON.stringify(p) : p
|
|
985
990
|
});
|
|
986
991
|
if (!P.ok) throw new Error(`Recording request failed with HTTP ${P.status}`);
|
|
987
992
|
return P.json();
|
|
@@ -992,60 +997,60 @@ function je(a, e) {
|
|
|
992
997
|
},
|
|
993
998
|
async start() {
|
|
994
999
|
if (v) return;
|
|
995
|
-
u = (await
|
|
996
|
-
const
|
|
997
|
-
|
|
998
|
-
const p =
|
|
999
|
-
let b =
|
|
1000
|
-
return b || (b = t.createElement("video"), b.muted = !0, b.playsInline = !0, b.srcObject =
|
|
1001
|
-
}),
|
|
1000
|
+
u = (await C("POST", "/v1/rtc/recordings")).recordingId;
|
|
1001
|
+
const w = t.createElement("canvas");
|
|
1002
|
+
w.width = r, w.height = o;
|
|
1003
|
+
const p = w.getContext("2d"), R = /* @__PURE__ */ new Map(), P = (T, M) => {
|
|
1004
|
+
let b = R.get(T);
|
|
1005
|
+
return b || (b = t.createElement("video"), b.muted = !0, b.playsInline = !0, b.srcObject = M, b.play().catch(() => {
|
|
1006
|
+
}), R.set(T, b)), b;
|
|
1002
1007
|
};
|
|
1003
1008
|
l = setInterval(() => {
|
|
1004
|
-
const T = a.getRemoteStreams(),
|
|
1005
|
-
...T.map((
|
|
1006
|
-
...
|
|
1009
|
+
const T = a.getRemoteStreams(), M = a.getLocalStream(), b = [
|
|
1010
|
+
...T.map((q) => ({ key: q.participant.participantId, stream: q.stream, label: q.participant.displayName })),
|
|
1011
|
+
...M ? [{ key: "local", stream: M, label: "me" }] : []
|
|
1007
1012
|
];
|
|
1008
1013
|
p.fillStyle = "#101418", p.fillRect(0, 0, r, o);
|
|
1009
|
-
const O = Math.max(1, Math.ceil(Math.sqrt(b.length))),
|
|
1010
|
-
b.forEach((
|
|
1011
|
-
const
|
|
1012
|
-
|
|
1014
|
+
const O = Math.max(1, Math.ceil(Math.sqrt(b.length))), V = Math.max(1, Math.ceil(b.length / O)), N = r / O, g = o / V;
|
|
1015
|
+
b.forEach((q, _) => {
|
|
1016
|
+
const Y = P(q.key, q.stream), B = _ % O * N, F = Math.floor(_ / O) * g;
|
|
1017
|
+
Y.videoWidth > 0 && p.drawImage(Y, B + 2, F + 2, N - 4, g - 4), p.fillStyle = "rgba(0,0,0,.6)", p.fillRect(B + 8, F + g - 30, Math.min(N - 16, 12 + q.label.length * 9), 22), p.fillStyle = "#fff", p.font = "14px system-ui", p.fillText(q.label, B + 14, F + g - 14);
|
|
1013
1018
|
});
|
|
1014
1019
|
}, 66);
|
|
1015
|
-
const L =
|
|
1020
|
+
const L = w.captureStream(15);
|
|
1016
1021
|
d = new AudioContext();
|
|
1017
|
-
const
|
|
1022
|
+
const I = d.createMediaStreamDestination(), A = /* @__PURE__ */ new Set(), S = () => {
|
|
1018
1023
|
const T = [
|
|
1019
|
-
...a.getRemoteStreams().map((
|
|
1024
|
+
...a.getRemoteStreams().map((M) => M.stream),
|
|
1020
1025
|
...a.getLocalStream() ? [a.getLocalStream()] : []
|
|
1021
1026
|
];
|
|
1022
|
-
for (const
|
|
1023
|
-
for (const b of
|
|
1024
|
-
A.has(b.id) || (A.add(b.id), d.createMediaStreamSource(new MediaStream([b])).connect(
|
|
1027
|
+
for (const M of T)
|
|
1028
|
+
for (const b of M.getAudioTracks())
|
|
1029
|
+
A.has(b.id) || (A.add(b.id), d.createMediaStreamSource(new MediaStream([b])).connect(I));
|
|
1025
1030
|
};
|
|
1026
|
-
|
|
1027
|
-
const
|
|
1028
|
-
for (const T of
|
|
1029
|
-
c = (e.mediaRecorderFactory ?? ((T,
|
|
1031
|
+
S();
|
|
1032
|
+
const E = setInterval(S, 1e3), m = () => clearInterval(E);
|
|
1033
|
+
for (const T of I.stream.getAudioTracks()) L.addTrack(T);
|
|
1034
|
+
c = (e.mediaRecorderFactory ?? ((T, M) => new MediaRecorder(T, M)))(L, { mimeType: s }), f = [], c.addEventListener("dataavailable", (T) => {
|
|
1030
1035
|
T.data && T.data.size > 0 && f.push(T.data);
|
|
1031
|
-
}), c.addEventListener("stop", m), c.start(1e3),
|
|
1036
|
+
}), c.addEventListener("stop", m), c.start(1e3), k = Date.now(), v = !0;
|
|
1032
1037
|
},
|
|
1033
1038
|
async stop() {
|
|
1034
1039
|
if (!v || !c || !u) throw new Error("The recorder is not running");
|
|
1035
1040
|
v = !1;
|
|
1036
|
-
const y = c,
|
|
1037
|
-
y.stop(), await
|
|
1041
|
+
const y = c, w = new Promise((I) => y.addEventListener("stop", () => I(), { once: !0 }));
|
|
1042
|
+
y.stop(), await w, l && clearInterval(l), l = null, await d?.close().catch(() => {
|
|
1038
1043
|
}), d = null;
|
|
1039
1044
|
const p = new Blob(f, { type: s });
|
|
1040
1045
|
f = [];
|
|
1041
|
-
const
|
|
1046
|
+
const R = Math.max(1, Math.round((Date.now() - k) / 1e3)), P = await C(
|
|
1042
1047
|
"PUT",
|
|
1043
1048
|
`/v1/rtc/recordings/${encodeURIComponent(u)}/media`,
|
|
1044
1049
|
p,
|
|
1045
1050
|
s
|
|
1046
1051
|
);
|
|
1047
|
-
await
|
|
1048
|
-
const L = { recordingId: u, sizeBytes: P.sizeBytes, durationSeconds:
|
|
1052
|
+
await C("POST", `/v1/rtc/recordings/${encodeURIComponent(u)}/complete`, { durationSeconds: R });
|
|
1053
|
+
const L = { recordingId: u, sizeBytes: P.sizeBytes, durationSeconds: R };
|
|
1049
1054
|
return u = null, c = null, L;
|
|
1050
1055
|
},
|
|
1051
1056
|
dispose() {
|
|
@@ -1059,7 +1064,7 @@ function je(a, e) {
|
|
|
1059
1064
|
}
|
|
1060
1065
|
};
|
|
1061
1066
|
}
|
|
1062
|
-
const
|
|
1067
|
+
const we = ["none", "blur", "aurora", "cybergrid", "bokeh", "sunset", "image"], Te = ["none", "snow", "confetti", "vignette"], Z = {
|
|
1063
1068
|
aurora(a, e, t, i) {
|
|
1064
1069
|
const n = a.createLinearGradient(0, 0, 0, t);
|
|
1065
1070
|
n.addColorStop(0, "#050b1e"), n.addColorStop(1, "#0b2540"), a.fillStyle = n, a.fillRect(0, 0, e, t);
|
|
@@ -1096,20 +1101,20 @@ const Se = ["none", "blur", "aurora", "cybergrid", "bokeh", "sunset", "image"],
|
|
|
1096
1101
|
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);
|
|
1097
1102
|
}
|
|
1098
1103
|
};
|
|
1099
|
-
function
|
|
1104
|
+
function Ue(a, e = {}) {
|
|
1100
1105
|
const t = e.document ?? globalThis.document;
|
|
1101
1106
|
let i = e.width ?? 1280, n = e.height ?? 720;
|
|
1102
1107
|
const s = !!(e.width || e.height), o = e.frameRate ?? 24, r = a instanceof MediaStreamTrack ? a : a.getVideoTracks()[0];
|
|
1103
1108
|
if (!r) throw new Error("A video track is required");
|
|
1104
|
-
let c = e.background ?? "none", l = e.overlay ?? "none", d = e.backgroundImage ?? null, u = e.segmenter ?? null,
|
|
1109
|
+
let c = e.background ?? "none", l = e.overlay ?? "none", d = e.backgroundImage ?? null, u = e.segmenter ?? null, k = null, f = !1;
|
|
1105
1110
|
const v = t.createElement("video");
|
|
1106
1111
|
v.muted = !0, v.playsInline = !0, v.srcObject = new MediaStream([r]), v.play().catch(() => {
|
|
1107
1112
|
});
|
|
1108
|
-
const
|
|
1109
|
-
|
|
1110
|
-
const y =
|
|
1111
|
-
|
|
1112
|
-
const p =
|
|
1113
|
+
const C = t.createElement("canvas");
|
|
1114
|
+
C.width = i, C.height = n;
|
|
1115
|
+
const y = C.getContext("2d"), w = t.createElement("canvas");
|
|
1116
|
+
w.width = i, w.height = n;
|
|
1117
|
+
const p = w.getContext("2d"), R = () => Array.from({ length: 80 }, (m, h) => ({
|
|
1113
1118
|
x: (Math.sin(h * 12.9898) * 0.5 + 0.5) * i,
|
|
1114
1119
|
y: (Math.sin(h * 78.233) * 0.5 + 0.5) * n,
|
|
1115
1120
|
speed: 0.6 + h % 5 * 0.5,
|
|
@@ -1117,25 +1122,25 @@ function Ve(a, e = {}) {
|
|
|
1117
1122
|
size: 2 + h % 4,
|
|
1118
1123
|
hue: h * 47 % 360
|
|
1119
1124
|
}));
|
|
1120
|
-
let P =
|
|
1125
|
+
let P = R();
|
|
1121
1126
|
const L = () => {
|
|
1122
1127
|
if (s) return;
|
|
1123
1128
|
const m = v.videoWidth, h = v.videoHeight;
|
|
1124
1129
|
if (!m || !h) return;
|
|
1125
|
-
const T = Math.min(1, 1280 / Math.max(m, h)),
|
|
1126
|
-
|
|
1130
|
+
const T = Math.min(1, 1280 / Math.max(m, h)), M = Math.round(m * T), b = Math.round(h * T);
|
|
1131
|
+
M === i && b === n || (i = M, n = b, C.width = i, C.height = n, w.width = i, w.height = n, P = R());
|
|
1127
1132
|
};
|
|
1128
1133
|
v.addEventListener?.("loadedmetadata", L), v.addEventListener?.("resize", L);
|
|
1129
|
-
function
|
|
1130
|
-
if (
|
|
1131
|
-
p.clearRect(0, 0, i, n), p.drawImage(
|
|
1134
|
+
function I() {
|
|
1135
|
+
if (k) {
|
|
1136
|
+
p.clearRect(0, 0, i, n), p.drawImage(k, 0, 0, i, n), p.globalCompositeOperation = "source-in", p.drawImage(v, 0, 0, i, n), p.globalCompositeOperation = "source-over", y.drawImage(w, 0, 0);
|
|
1132
1137
|
return;
|
|
1133
1138
|
}
|
|
1134
|
-
const m = i * 0.42, h = m * 9 / 16, T = i - m - 24,
|
|
1135
|
-
y.save(), y.shadowColor = "rgba(0,0,0,.5)", y.shadowBlur = 24, y.beginPath(), y.roundRect(T,
|
|
1139
|
+
const m = i * 0.42, h = m * 9 / 16, T = i - m - 24, M = n - h - 24;
|
|
1140
|
+
y.save(), y.shadowColor = "rgba(0,0,0,.5)", y.shadowBlur = 24, y.beginPath(), y.roundRect(T, M, m, h, 14), y.clip(), y.drawImage(v, T, M, m, h), y.restore();
|
|
1136
1141
|
}
|
|
1137
1142
|
function A(m) {
|
|
1138
|
-
if (c === "none" ? y.drawImage(v, 0, 0, i, n) : c === "blur" ? (y.filter = "blur(14px)", y.drawImage(v, -16, -16, i + 32, n + 32), y.filter = "none",
|
|
1143
|
+
if (c === "none" ? y.drawImage(v, 0, 0, i, n) : c === "blur" ? (y.filter = "blur(14px)", y.drawImage(v, -16, -16, i + 32, n + 32), y.filter = "none", k && I()) : c === "image" && d ? (y.drawImage(d, 0, 0, i, n), I()) : ((Z[c] ?? Z.aurora)(y, i, n, m), I()), l === "snow" || l === "confetti")
|
|
1139
1144
|
for (const h of P)
|
|
1140
1145
|
h.y += h.speed * (l === "confetti" ? 1.6 : 1), h.x += h.drift, h.y > n && (h.y = -6, h.x = Math.random() * i), y.fillStyle = l === "snow" ? "rgba(255,255,255,.85)" : `hsl(${h.hue}, 90%, 60%)`, l === "confetti" ? y.fillRect(h.x, h.y, h.size + 2, h.size) : (y.beginPath(), y.arc(h.x, h.y, h.size / 2, 0, Math.PI * 2), y.fill());
|
|
1141
1146
|
else if (l === "vignette") {
|
|
@@ -1143,35 +1148,35 @@ function Ve(a, e = {}) {
|
|
|
1143
1148
|
h.addColorStop(0, "rgba(0,0,0,0)"), h.addColorStop(1, "rgba(0,0,0,0.55)"), y.fillStyle = h, y.fillRect(0, 0, i, n);
|
|
1144
1149
|
}
|
|
1145
1150
|
}
|
|
1146
|
-
const
|
|
1151
|
+
const S = setInterval(() => {
|
|
1147
1152
|
A(Date.now()), u && !f && c !== "none" && (f = !0, u.segment(v).then((m) => {
|
|
1148
|
-
|
|
1153
|
+
k = m;
|
|
1149
1154
|
}).catch(() => {
|
|
1150
|
-
|
|
1155
|
+
k = null;
|
|
1151
1156
|
}).finally(() => {
|
|
1152
1157
|
f = !1;
|
|
1153
1158
|
}));
|
|
1154
|
-
}, Math.round(1e3 / o)),
|
|
1159
|
+
}, Math.round(1e3 / o)), E = C.captureStream(o);
|
|
1155
1160
|
return {
|
|
1156
|
-
track:
|
|
1157
|
-
stream:
|
|
1161
|
+
track: E.getVideoTracks()[0],
|
|
1162
|
+
stream: E,
|
|
1158
1163
|
setBackground(m, h) {
|
|
1159
|
-
c =
|
|
1164
|
+
c = we.includes(m) ? m : "none", h !== void 0 && (d = h), c === "none" && (k = null);
|
|
1160
1165
|
},
|
|
1161
1166
|
setOverlay(m) {
|
|
1162
|
-
l =
|
|
1167
|
+
l = Te.includes(m) ? m : "none";
|
|
1163
1168
|
},
|
|
1164
1169
|
setSegmenter(m) {
|
|
1165
|
-
u = m, m || (
|
|
1170
|
+
u = m, m || (k = null);
|
|
1166
1171
|
},
|
|
1167
1172
|
dispose() {
|
|
1168
|
-
clearInterval(
|
|
1169
|
-
for (const m of
|
|
1173
|
+
clearInterval(S), u?.close?.();
|
|
1174
|
+
for (const m of E.getTracks()) m.stop();
|
|
1170
1175
|
v.srcObject = null;
|
|
1171
1176
|
}
|
|
1172
1177
|
};
|
|
1173
1178
|
}
|
|
1174
|
-
function
|
|
1179
|
+
function he() {
|
|
1175
1180
|
return {
|
|
1176
1181
|
blinkLeft: 0,
|
|
1177
1182
|
blinkRight: 0,
|
|
@@ -1190,18 +1195,18 @@ function D(a, e) {
|
|
|
1190
1195
|
const t = a.find((i) => i.categoryName === e);
|
|
1191
1196
|
return t ? Math.max(0, Math.min(1, t.score)) : 0;
|
|
1192
1197
|
}
|
|
1193
|
-
function
|
|
1198
|
+
function be(a) {
|
|
1194
1199
|
if (!a || a.length < 16) return { yaw: 0, pitch: 0, roll: 0 };
|
|
1195
1200
|
a[0], a[4];
|
|
1196
1201
|
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);
|
|
1197
1202
|
return { yaw: o, pitch: r, roll: c };
|
|
1198
1203
|
}
|
|
1199
|
-
function
|
|
1200
|
-
if (!a || a.length === 0) return
|
|
1201
|
-
const i =
|
|
1204
|
+
function Ce(a, e, t = 1) {
|
|
1205
|
+
if (!a || a.length === 0) return he();
|
|
1206
|
+
const i = be(e), n = (D(a, "eyeLookOutRight") + D(a, "eyeLookInLeft")) / 2, s = (D(a, "eyeLookOutLeft") + D(a, "eyeLookInRight")) / 2, o = (D(a, "eyeLookUpLeft") + D(a, "eyeLookUpRight")) / 2, r = (D(a, "eyeLookDownLeft") + D(a, "eyeLookDownRight")) / 2, c = (D(a, "mouthSmileLeft") + D(a, "mouthSmileRight")) / 2, l = (D(a, "mouthFrownLeft") + D(a, "mouthFrownRight")) / 2, d = D(a, "eyeBlinkLeft"), u = D(a, "eyeBlinkRight"), k = Math.min(1, Math.abs(i.yaw) / 0.35) * Math.max(0, Math.min(1, t)), f = (d + u) / 2;
|
|
1202
1207
|
return {
|
|
1203
|
-
blinkLeft: d + (f - d) *
|
|
1204
|
-
blinkRight: u + (f - u) *
|
|
1208
|
+
blinkLeft: d + (f - d) * k,
|
|
1209
|
+
blinkRight: u + (f - u) * k,
|
|
1205
1210
|
jawOpen: D(a, "jawOpen"),
|
|
1206
1211
|
smile: c - l,
|
|
1207
1212
|
browUp: (D(a, "browInnerUp") + D(a, "browOuterUpLeft") + D(a, "browOuterUpRight")) / 3,
|
|
@@ -1213,7 +1218,7 @@ function Te(a, e, t = 1) {
|
|
|
1213
1218
|
tracked: !0
|
|
1214
1219
|
};
|
|
1215
1220
|
}
|
|
1216
|
-
function
|
|
1221
|
+
function ee(a, e, t = 0.4) {
|
|
1217
1222
|
const i = (n, s) => n + (s - n) * t;
|
|
1218
1223
|
return {
|
|
1219
1224
|
blinkLeft: i(a.blinkLeft, e.blinkLeft),
|
|
@@ -1229,36 +1234,36 @@ function X(a, e, t = 0.4) {
|
|
|
1229
1234
|
tracked: e.tracked
|
|
1230
1235
|
};
|
|
1231
1236
|
}
|
|
1232
|
-
function
|
|
1237
|
+
function Re(a, e, t, i, n) {
|
|
1233
1238
|
n || (a.fillStyle = "#101822", a.fillRect(0, 0, t, i));
|
|
1234
1239
|
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;
|
|
1235
1240
|
a.save(), a.translate(s, o), a.rotate(e.headRoll * 0.6);
|
|
1236
|
-
const c = Math.max(-1.35, Math.min(1.35, e.headYaw)), l = Math.max(-0.9, Math.min(0.9, e.headPitch)), d = Math.sin(c), u = (A) => Math.sin(A + c) * r,
|
|
1241
|
+
const c = Math.max(-1.35, Math.min(1.35, e.headYaw)), l = Math.max(-0.9, Math.min(0.9, e.headPitch)), d = Math.sin(c), u = (A) => Math.sin(A + c) * r, k = (A) => Math.cos(A + c), f = Math.sin(l) * r * 0.22;
|
|
1237
1242
|
a.fillStyle = "#3a2a1c", a.beginPath(), a.ellipse(-d * 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(d) * 0.12), r * 1.12, 0, 0, Math.PI * 2), a.fill(), a.fillStyle = "#3a2a1c", a.beginPath(), a.ellipse(-d * r * 0.28, -r * 0.72 + f * 0.4, r * 0.92, r * 0.5, 0, Math.PI, Math.PI * 2), a.fill();
|
|
1238
1243
|
const v = 0;
|
|
1239
1244
|
a.fillStyle = "#e5b58a", a.beginPath();
|
|
1240
|
-
const
|
|
1241
|
-
a.ellipse(
|
|
1245
|
+
const C = u(v) * 0.9, y = r * 0.12 + f;
|
|
1246
|
+
a.ellipse(C + d * r * 0.14, y, r * 0.11, r * 0.14, 0, 0, Math.PI * 2), a.fill();
|
|
1242
1247
|
for (const A of [-1, 1]) {
|
|
1243
|
-
const
|
|
1244
|
-
if (
|
|
1245
|
-
const m = u(
|
|
1248
|
+
const S = A * 0.42, E = k(S);
|
|
1249
|
+
if (E <= 0.12) continue;
|
|
1250
|
+
const m = u(S) * 0.82, h = Math.max(0.2, E), T = A < 0 ? e.blinkLeft : e.blinkRight, M = Math.max(0.06, 1 - T), b = e.browUp * r * 0.14;
|
|
1246
1251
|
a.strokeStyle = "#4a2e18", a.lineWidth = r * 0.07, a.lineCap = "round", a.beginPath(), a.moveTo(m - r * 0.2 * h, -r * 0.42 - b + f), a.quadraticCurveTo(m, -r * 0.52 - b + f, m + r * 0.2 * h, -r * 0.44 - b + f), a.stroke();
|
|
1247
1252
|
const O = -r * 0.18 + f;
|
|
1248
|
-
a.fillStyle = "#ffffff", a.beginPath(), a.ellipse(m, O, r * 0.16 * h, r * 0.12 *
|
|
1253
|
+
a.fillStyle = "#ffffff", a.beginPath(), a.ellipse(m, O, r * 0.16 * h, r * 0.12 * M, 0, 0, Math.PI * 2), a.fill(), a.fillStyle = "#22303c", a.beginPath(), a.ellipse(
|
|
1249
1254
|
m + e.pupilX * r * 0.07 * h,
|
|
1250
1255
|
O + e.pupilY * r * 0.05,
|
|
1251
1256
|
r * 0.06 * h,
|
|
1252
|
-
r * 0.06 *
|
|
1257
|
+
r * 0.06 * M,
|
|
1253
1258
|
0,
|
|
1254
1259
|
0,
|
|
1255
1260
|
Math.PI * 2
|
|
1256
1261
|
), a.fill();
|
|
1257
1262
|
}
|
|
1258
|
-
const
|
|
1259
|
-
a.fillStyle = "#8c2f2f", a.beginPath(), a.moveTo(p -
|
|
1263
|
+
const w = Math.max(0.25, k(0)), p = u(0) * 0.7, R = r * 0.55 * w, P = r * (0.04 + e.jawOpen * 0.34), L = e.smile * r * 0.12, I = r * 0.42 + f;
|
|
1264
|
+
a.fillStyle = "#8c2f2f", a.beginPath(), a.moveTo(p - R / 2, I - L), a.quadraticCurveTo(p, I + P, p + R / 2, I - L), a.quadraticCurveTo(p, I - P * 0.25, p - R / 2, I - L), 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");
|
|
1260
1265
|
}
|
|
1261
|
-
const
|
|
1266
|
+
const te = {
|
|
1262
1267
|
mouthGain: 1.7,
|
|
1263
1268
|
blinkGain: 1,
|
|
1264
1269
|
eyeSync: 1,
|
|
@@ -1267,82 +1272,82 @@ const Z = {
|
|
|
1267
1272
|
avatarLift: 0,
|
|
1268
1273
|
lostHoldMs: 400
|
|
1269
1274
|
};
|
|
1270
|
-
function
|
|
1275
|
+
function ie() {
|
|
1271
1276
|
return {
|
|
1272
1277
|
render(a, e, t, i, n) {
|
|
1273
|
-
|
|
1278
|
+
Re(a, e, t, i, n ?? void 0);
|
|
1274
1279
|
}
|
|
1275
1280
|
};
|
|
1276
1281
|
}
|
|
1277
|
-
const
|
|
1278
|
-
function
|
|
1282
|
+
const z = (a) => Math.max(0, Math.min(1, a));
|
|
1283
|
+
function Qe(a, e = {}) {
|
|
1279
1284
|
const t = e.document ?? globalThis.document;
|
|
1280
1285
|
let i = e.width ?? 1280, n = e.height ?? 720;
|
|
1281
1286
|
const s = !!(e.width || e.height), o = e.frameRate ?? 24, r = a instanceof MediaStreamTrack ? a : a.getVideoTracks()[0];
|
|
1282
1287
|
if (!r) throw new Error("A video track is required");
|
|
1283
|
-
let c = e.tracker ?? null, l = e.renderer ??
|
|
1284
|
-
const u = { ...
|
|
1288
|
+
let c = e.tracker ?? null, l = e.renderer ?? ie(), d = e.mode ?? "replace";
|
|
1289
|
+
const u = { ...te, ...e.tuning }, k = e.backdrop ?? "#101822", f = t.createElement("video");
|
|
1285
1290
|
f.muted = !0, f.playsInline = !0, f.srcObject = new MediaStream([r]), f.play().catch(() => {
|
|
1286
1291
|
});
|
|
1287
1292
|
const v = t.createElement("canvas");
|
|
1288
1293
|
v.width = i, v.height = n;
|
|
1289
|
-
const
|
|
1294
|
+
const C = v.getContext("2d"), y = () => {
|
|
1290
1295
|
if (s) return;
|
|
1291
|
-
const
|
|
1292
|
-
if (!
|
|
1293
|
-
const m = Math.min(1, 1280 / Math.max(
|
|
1296
|
+
const S = f.videoWidth, E = f.videoHeight;
|
|
1297
|
+
if (!S || !E) return;
|
|
1298
|
+
const m = Math.min(1, 1280 / Math.max(S, E)), h = Math.round(S * m), T = Math.round(E * m);
|
|
1294
1299
|
(!(h === i || T === n) || h !== i || T !== n) && (i = h, n = T, v.width = i, v.height = n);
|
|
1295
1300
|
};
|
|
1296
1301
|
f.addEventListener?.("loadedmetadata", y), f.addEventListener?.("resize", y);
|
|
1297
|
-
let
|
|
1298
|
-
function P(
|
|
1299
|
-
if (
|
|
1300
|
-
const
|
|
1301
|
-
p = p ? { x: p.x + (
|
|
1302
|
+
let w = he(), p = null, R = 0;
|
|
1303
|
+
function P(S) {
|
|
1304
|
+
if (S.length <= 454) return;
|
|
1305
|
+
const E = S[10], m = S[152], h = S[234], T = S[454], M = (h.x + T.x) / 2 * i, b = (h.y + T.y) / 2 * n, O = Math.hypot((m.x - E.x) * i, (m.y - E.y) * n), V = Math.max(0.6, Math.cos(w.headPitch)), N = { x: M, y: b, radius: Math.max(24, O / V * 0.8) };
|
|
1306
|
+
p = p ? { x: p.x + (N.x - p.x) * 0.4, y: p.y + (N.y - p.y) * 0.4, radius: p.radius + (N.radius - p.radius) * 0.15 } : N;
|
|
1302
1307
|
}
|
|
1303
|
-
function L(
|
|
1308
|
+
function L(S) {
|
|
1304
1309
|
if (c && f.readyState >= 2) {
|
|
1305
1310
|
let m = null;
|
|
1306
1311
|
try {
|
|
1307
|
-
m = c.detect(f,
|
|
1312
|
+
m = c.detect(f, S);
|
|
1308
1313
|
} catch {
|
|
1309
1314
|
}
|
|
1310
|
-
const h =
|
|
1311
|
-
h.jawOpen =
|
|
1315
|
+
const h = Ce(m?.categories ?? null, m?.matrix ?? null, u.eyeSync);
|
|
1316
|
+
h.jawOpen = z(h.jawOpen * u.mouthGain), h.blinkLeft = z(h.blinkLeft * u.blinkGain), h.blinkRight = z(h.blinkRight * u.blinkGain), h.tracked ? (R = S, w = ee(w, h, u.smoothing), m?.landmarks && P(m.landmarks)) : w.tracked && S - R > u.lostHoldMs && (w = ee(w, { ...w, jawOpen: 0, browUp: 0, smile: w.smile * 0.5, blinkLeft: 0.1, blinkRight: 0.1 }, 0.05));
|
|
1312
1317
|
}
|
|
1313
|
-
d === "overlay" && f.readyState >= 2 ?
|
|
1314
|
-
const
|
|
1315
|
-
l?.render(
|
|
1318
|
+
d === "overlay" && f.readyState >= 2 ? C.drawImage(f, 0, 0, i, n) : (C.fillStyle = k, C.fillRect(0, 0, i, n));
|
|
1319
|
+
const E = p ? { x: p.x, y: p.y + u.avatarLift * p.radius, radius: p.radius * u.avatarScale } : null;
|
|
1320
|
+
l?.render(C, w, i, n, E);
|
|
1316
1321
|
}
|
|
1317
|
-
const
|
|
1322
|
+
const I = setInterval(() => L(Date.now()), Math.round(1e3 / o)), A = v.captureStream(o);
|
|
1318
1323
|
return {
|
|
1319
1324
|
track: A.getVideoTracks()[0],
|
|
1320
1325
|
stream: A,
|
|
1321
|
-
getRig: () => ({ ...
|
|
1322
|
-
setMode(
|
|
1323
|
-
d =
|
|
1326
|
+
getRig: () => ({ ...w }),
|
|
1327
|
+
setMode(S) {
|
|
1328
|
+
d = S === "overlay" ? "overlay" : "replace";
|
|
1324
1329
|
},
|
|
1325
|
-
setTracker(
|
|
1326
|
-
c?.close?.(), c =
|
|
1330
|
+
setTracker(S) {
|
|
1331
|
+
c?.close?.(), c = S;
|
|
1327
1332
|
},
|
|
1328
|
-
setRenderer(
|
|
1329
|
-
l?.dispose?.(), l =
|
|
1333
|
+
setRenderer(S) {
|
|
1334
|
+
l?.dispose?.(), l = S ?? ie();
|
|
1330
1335
|
},
|
|
1331
|
-
setTuning(
|
|
1332
|
-
for (const
|
|
1333
|
-
const m =
|
|
1334
|
-
typeof m == "number" && Number.isFinite(m) && (u[
|
|
1336
|
+
setTuning(S) {
|
|
1337
|
+
for (const E of Object.keys(te)) {
|
|
1338
|
+
const m = S[E];
|
|
1339
|
+
typeof m == "number" && Number.isFinite(m) && (u[E] = m);
|
|
1335
1340
|
}
|
|
1336
1341
|
},
|
|
1337
1342
|
getTuning: () => ({ ...u }),
|
|
1338
1343
|
dispose() {
|
|
1339
|
-
clearInterval(
|
|
1340
|
-
for (const
|
|
1344
|
+
clearInterval(I), c?.close?.(), l?.dispose?.();
|
|
1345
|
+
for (const S of A.getTracks()) S.stop();
|
|
1341
1346
|
f.srcObject = null;
|
|
1342
1347
|
}
|
|
1343
1348
|
};
|
|
1344
1349
|
}
|
|
1345
|
-
class
|
|
1350
|
+
class Ie extends EventTarget {
|
|
1346
1351
|
mode;
|
|
1347
1352
|
options;
|
|
1348
1353
|
client = null;
|
|
@@ -1376,7 +1381,7 @@ class Ce extends EventTarget {
|
|
|
1376
1381
|
async initialize() {
|
|
1377
1382
|
if (this.client) return this;
|
|
1378
1383
|
try {
|
|
1379
|
-
const t = (this.options.transport === "auto" ? this.mode === "meeting" ? "sfu" : "mesh" : this.options.transport ?? "mesh") === "sfu" ?
|
|
1384
|
+
const t = (this.options.transport === "auto" ? this.mode === "meeting" ? "sfu" : "mesh" : this.options.transport ?? "mesh") === "sfu" ? Se : Q;
|
|
1380
1385
|
return this.client = new t({
|
|
1381
1386
|
credential: {
|
|
1382
1387
|
signalingToken: this.options.credential.signalingToken,
|
|
@@ -1396,19 +1401,19 @@ class Ce extends EventTarget {
|
|
|
1396
1401
|
localStream: this.options.localStream,
|
|
1397
1402
|
simulcast: this.options.simulcast ?? !0,
|
|
1398
1403
|
onEvent: (i, n) => this.handleNativeEvent(i, n)
|
|
1399
|
-
}), await this.client.initialize(), this.startStats(), this.emit("initialized", { mode: this.mode, sdkVersion:
|
|
1404
|
+
}), await this.client.initialize(), this.startStats(), this.emit("initialized", { mode: this.mode, sdkVersion: Oe }), this.options.autoJoin && await this.join(), this;
|
|
1400
1405
|
} catch (e) {
|
|
1401
1406
|
this.state = "failed";
|
|
1402
|
-
const t =
|
|
1403
|
-
throw this.emit("error",
|
|
1407
|
+
const t = ce(e, "RTC initialization failed");
|
|
1408
|
+
throw this.emit("error", x(t)), t;
|
|
1404
1409
|
}
|
|
1405
1410
|
}
|
|
1406
1411
|
async join() {
|
|
1407
1412
|
const e = this.requireClient();
|
|
1408
1413
|
return this.joinPromise ? this.joinPromise : (this.state = "joining", this.emit("joining", {}), this.joinPromise = e.join().catch((t) => {
|
|
1409
1414
|
this.state = "failed";
|
|
1410
|
-
const i =
|
|
1411
|
-
throw this.emit("error",
|
|
1415
|
+
const i = ce(t, "RTC connection failed");
|
|
1416
|
+
throw this.emit("error", x(i)), i;
|
|
1412
1417
|
}).finally(() => {
|
|
1413
1418
|
this.joinPromise = null;
|
|
1414
1419
|
}), this.joinPromise);
|
|
@@ -1446,14 +1451,14 @@ class Ce extends EventTarget {
|
|
|
1446
1451
|
return navigator.mediaDevices?.enumerateDevices ? navigator.mediaDevices.enumerateDevices() : [];
|
|
1447
1452
|
}
|
|
1448
1453
|
getParticipants() {
|
|
1449
|
-
return this.requireClient().getParticipants().map(
|
|
1454
|
+
return this.requireClient().getParticipants().map(se);
|
|
1450
1455
|
}
|
|
1451
1456
|
getLocalStream() {
|
|
1452
1457
|
return this.client?.getLocalStream() ?? null;
|
|
1453
1458
|
}
|
|
1454
1459
|
getRemoteStreams() {
|
|
1455
1460
|
return (this.client?.getRemoteStreams() ?? []).map((e) => ({
|
|
1456
|
-
participant:
|
|
1461
|
+
participant: se(e.participant),
|
|
1457
1462
|
stream: e.stream
|
|
1458
1463
|
}));
|
|
1459
1464
|
}
|
|
@@ -1522,7 +1527,7 @@ class Ce extends EventTarget {
|
|
|
1522
1527
|
let n = "unavailable";
|
|
1523
1528
|
if (e.requestMedia !== !1 && navigator.mediaDevices?.getUserMedia)
|
|
1524
1529
|
try {
|
|
1525
|
-
(await navigator.mediaDevices.getUserMedia({ audio: this.options.audio, video: this.options.video })).getTracks().forEach((
|
|
1530
|
+
(await navigator.mediaDevices.getUserMedia({ audio: this.options.audio, video: this.options.video })).getTracks().forEach((k) => k.stop()), n = "granted";
|
|
1526
1531
|
} catch {
|
|
1527
1532
|
n = "denied", t.push("media_permission_denied");
|
|
1528
1533
|
}
|
|
@@ -1533,8 +1538,8 @@ class Ce extends EventTarget {
|
|
|
1533
1538
|
if (c) {
|
|
1534
1539
|
const u = performance.now();
|
|
1535
1540
|
try {
|
|
1536
|
-
const
|
|
1537
|
-
l = Math.round(performance.now() - u),
|
|
1541
|
+
const k = await fetch(c, { method: "HEAD", cache: "no-store", credentials: "omit" });
|
|
1542
|
+
l = Math.round(performance.now() - u), k.ok || t.push("network_probe_failed");
|
|
1538
1543
|
} catch {
|
|
1539
1544
|
t.push("network_probe_failed");
|
|
1540
1545
|
}
|
|
@@ -1547,7 +1552,7 @@ class Ce extends EventTarget {
|
|
|
1547
1552
|
microphoneCount: o,
|
|
1548
1553
|
cameraCount: r,
|
|
1549
1554
|
probeLatencyMs: l,
|
|
1550
|
-
effectiveConnectionType:
|
|
1555
|
+
effectiveConnectionType: re()?.effectiveType ?? null,
|
|
1551
1556
|
issues: t
|
|
1552
1557
|
};
|
|
1553
1558
|
return this.emit("preflight", d), this.options.autoReportStats && await this.reportQuality({
|
|
@@ -1560,7 +1565,7 @@ class Ce extends EventTarget {
|
|
|
1560
1565
|
}), d;
|
|
1561
1566
|
}
|
|
1562
1567
|
async collectQualitySample(e = "runtime") {
|
|
1563
|
-
const t = this.options.statsProvider ? await this.options.statsProvider() : {}, i = this.peerConnection ? await
|
|
1568
|
+
const t = this.options.statsProvider ? await this.options.statsProvider() : {}, i = this.peerConnection ? await Le(this.peerConnection, this.previousCounters) : null;
|
|
1564
1569
|
i?.counters && (this.previousCounters = i.counters);
|
|
1565
1570
|
const s = { ...{
|
|
1566
1571
|
sampleType: e,
|
|
@@ -1581,6 +1586,10 @@ class Ce extends EventTarget {
|
|
|
1581
1586
|
framesPerSecond: null,
|
|
1582
1587
|
frameWidth: null,
|
|
1583
1588
|
frameHeight: null,
|
|
1589
|
+
inboundFrameWidth: null,
|
|
1590
|
+
inboundFrameHeight: null,
|
|
1591
|
+
outboundFrameWidth: null,
|
|
1592
|
+
outboundFrameHeight: null,
|
|
1584
1593
|
framesDropped: null,
|
|
1585
1594
|
freezeCount: null,
|
|
1586
1595
|
freezeDurationMs: null,
|
|
@@ -1589,9 +1598,9 @@ class Ce extends EventTarget {
|
|
|
1589
1598
|
transportProtocol: null,
|
|
1590
1599
|
candidateType: null,
|
|
1591
1600
|
qualityLimitationReason: null,
|
|
1592
|
-
deviceMemoryGb:
|
|
1593
|
-
effectiveConnectionType:
|
|
1594
|
-
}, ...i?.sample ?? {}, ...t, sampleType: e, sampledAt: (/* @__PURE__ */ new Date()).toISOString() }, o =
|
|
1601
|
+
deviceMemoryGb: qe(),
|
|
1602
|
+
effectiveConnectionType: re()?.effectiveType ?? null
|
|
1603
|
+
}, ...i?.sample ?? {}, ...t, sampleType: e, sampledAt: (/* @__PURE__ */ new Date()).toISOString() }, o = De(s);
|
|
1595
1604
|
return s.networkScore = o.networkScore, s.estimatedMos = o.estimatedMos, this.latestQuality = s, s;
|
|
1596
1605
|
}
|
|
1597
1606
|
async reportQuality(e) {
|
|
@@ -1642,7 +1651,7 @@ class Ce extends EventTarget {
|
|
|
1642
1651
|
const i = Date.now(), n = e !== "runtime" || i - this.lastTelemetryAt >= this.options.telemetryInterval;
|
|
1643
1652
|
this.options.autoReportStats && n && (await this.reportQuality(t), this.lastTelemetryAt = i);
|
|
1644
1653
|
} catch (t) {
|
|
1645
|
-
this.emit("telemetryerror",
|
|
1654
|
+
this.emit("telemetryerror", x(t));
|
|
1646
1655
|
} finally {
|
|
1647
1656
|
this.statsRunning = !1;
|
|
1648
1657
|
}
|
|
@@ -1676,21 +1685,21 @@ class Ce extends EventTarget {
|
|
|
1676
1685
|
this.dispatchEvent(new CustomEvent(e, { detail: i })), this.options.onEvent?.(i);
|
|
1677
1686
|
}
|
|
1678
1687
|
}
|
|
1679
|
-
async function
|
|
1680
|
-
return new
|
|
1688
|
+
async function Be(a) {
|
|
1689
|
+
return new Ie(a).initialize();
|
|
1681
1690
|
}
|
|
1682
1691
|
let U = null;
|
|
1683
|
-
function
|
|
1692
|
+
function ue() {
|
|
1684
1693
|
if (U) return U;
|
|
1685
1694
|
const a = globalThis, e = a.AudioContext ?? a.webkitAudioContext;
|
|
1686
1695
|
return e ? (U = new e(), U) : null;
|
|
1687
1696
|
}
|
|
1688
|
-
async function
|
|
1689
|
-
const a =
|
|
1697
|
+
async function Ee() {
|
|
1698
|
+
const a = ue();
|
|
1690
1699
|
return a ? (a.state === "suspended" && await a.resume().catch(() => {
|
|
1691
1700
|
}), a.state === "running") : !1;
|
|
1692
1701
|
}
|
|
1693
|
-
class
|
|
1702
|
+
class Me {
|
|
1694
1703
|
options;
|
|
1695
1704
|
media = null;
|
|
1696
1705
|
cadenceTimer = null;
|
|
@@ -1699,7 +1708,7 @@ class Ie {
|
|
|
1699
1708
|
this.options = e;
|
|
1700
1709
|
}
|
|
1701
1710
|
unlock() {
|
|
1702
|
-
return
|
|
1711
|
+
return Ee();
|
|
1703
1712
|
}
|
|
1704
1713
|
startIncoming() {
|
|
1705
1714
|
this.start("incoming", this.options.ringtoneUrl);
|
|
@@ -1727,7 +1736,7 @@ class Ie {
|
|
|
1727
1736
|
i(), this.cadenceTimer = setInterval(i, e === "incoming" ? 3e3 : 3500);
|
|
1728
1737
|
}
|
|
1729
1738
|
playBuiltInTone(e) {
|
|
1730
|
-
const t =
|
|
1739
|
+
const t = ue();
|
|
1731
1740
|
if (!t || t.state !== "running") return;
|
|
1732
1741
|
const i = e === "incoming" ? 1.25 : 1, n = e === "incoming" ? [440, 480] : [425], s = t.createGain(), o = t.currentTime;
|
|
1733
1742
|
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);
|
|
@@ -1737,7 +1746,7 @@ class Ie {
|
|
|
1737
1746
|
}
|
|
1738
1747
|
}
|
|
1739
1748
|
}
|
|
1740
|
-
class
|
|
1749
|
+
class Pe extends EventTarget {
|
|
1741
1750
|
options;
|
|
1742
1751
|
socket = null;
|
|
1743
1752
|
stopped = !1;
|
|
@@ -1764,14 +1773,14 @@ class Ee extends EventTarget {
|
|
|
1764
1773
|
if (e.token && !e.token.startsWith("rtcc_")) throw new Error("A valid RTC client token is required");
|
|
1765
1774
|
if (!e.signalingUrl && !e.callActionsUrl && !e.apiBaseUrl && !globalThis.location?.origin)
|
|
1766
1775
|
throw new Error("signalingUrl or callActionsUrl is required outside a browser");
|
|
1767
|
-
this.options = e, this.currentToken = e.token ?? null, this.currentTokenExpiresAt = e.tokenExpiresAt, this.callAudio = new
|
|
1776
|
+
this.options = e, this.currentToken = e.token ?? null, this.currentTokenExpiresAt = e.tokenExpiresAt, this.callAudio = new Me(e), this.mount = ne(e.mount), this.scheduleTokenRefresh();
|
|
1768
1777
|
}
|
|
1769
1778
|
connect() {
|
|
1770
1779
|
if (!this.options.signalingUrl) throw new Error("signalingUrl is required to connect signaling");
|
|
1771
1780
|
return this.stopped = !1, this.scheduleTokenRefresh(), this.openSocket("initial"), this;
|
|
1772
1781
|
}
|
|
1773
1782
|
setMount(e) {
|
|
1774
|
-
this.clearUi(), this.mount =
|
|
1783
|
+
this.clearUi(), this.mount = ne(e), this.currentCall && this.renderIncoming(this.currentCall);
|
|
1775
1784
|
}
|
|
1776
1785
|
/** Binds media lifetime to a call. Terminal call states automatically leave and destroy it. */
|
|
1777
1786
|
attachMediaClient(e, t) {
|
|
@@ -1857,7 +1866,7 @@ class Ee extends EventTarget {
|
|
|
1857
1866
|
/** Applies a call state received through the application's own push or signaling channel. */
|
|
1858
1867
|
handleCallUpdate(e) {
|
|
1859
1868
|
const t = e.id === this.currentCall?.id || e.id === this.outgoingCallId;
|
|
1860
|
-
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,
|
|
1869
|
+
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, Ae(e.status)), ["rejected", "busy", "cancelled", "ended", "failed", "missed"].includes(e.status) && this.releaseMedia(e.id), this.emit("callupdated", e);
|
|
1861
1870
|
}
|
|
1862
1871
|
disconnect() {
|
|
1863
1872
|
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();
|
|
@@ -1873,13 +1882,11 @@ class Ee extends EventTarget {
|
|
|
1873
1882
|
try {
|
|
1874
1883
|
t = await this.resolveToken(e, e === "reconnect");
|
|
1875
1884
|
} catch (s) {
|
|
1876
|
-
this.emit("tokenerror",
|
|
1885
|
+
this.emit("tokenerror", x(s)), !this.stopped && this.options.reconnect !== !1 && this.scheduleReconnect();
|
|
1877
1886
|
return;
|
|
1878
1887
|
}
|
|
1879
1888
|
if (this.stopped || this.socket) return;
|
|
1880
|
-
const i =
|
|
1881
|
-
i.protocol = i.protocol === "https:" ? "wss:" : "ws:";
|
|
1882
|
-
const n = new WebSocket(i, ["rtc-client", t]);
|
|
1889
|
+
const i = $(this.options.signalingUrl, globalThis.location?.href), n = new WebSocket(i, ["rtc-client", t]);
|
|
1883
1890
|
this.socket = n, n.addEventListener("open", () => {
|
|
1884
1891
|
const s = this.reconnectAttempt > 0, o = this.lastDisconnect;
|
|
1885
1892
|
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(() => {
|
|
@@ -1937,7 +1944,7 @@ class Ee extends EventTarget {
|
|
|
1937
1944
|
async request(e, t, i = !1) {
|
|
1938
1945
|
const n = this.options.callActionsUrl ?? this.options.apiBaseUrl ?? this.options.signalingUrl ?? globalThis.location?.origin;
|
|
1939
1946
|
if (!n) throw new Error("callActionsUrl is required for call actions");
|
|
1940
|
-
const s =
|
|
1947
|
+
const s = J(n, globalThis.location?.href), o = await this.resolveToken("initial"), r = new Headers(t.headers);
|
|
1941
1948
|
r.set("authorization", `Bearer ${o}`), r.set("content-type", "application/json");
|
|
1942
1949
|
const c = await fetch(new URL(e, s.origin), { ...t, headers: r }), l = await c.json().catch(() => ({}));
|
|
1943
1950
|
if (c.status === 401 && this.options.tokenProvider && !i)
|
|
@@ -1969,11 +1976,11 @@ class Ee extends EventTarget {
|
|
|
1969
1976
|
n.textContent = e.caller.name, n.style.fontSize = "20px";
|
|
1970
1977
|
const s = document.createElement("div");
|
|
1971
1978
|
Object.assign(s.style, { display: "grid", gridTemplateColumns: "1fr 1fr", gap: "10px" });
|
|
1972
|
-
const o =
|
|
1979
|
+
const o = ae("Decline", "#fff", "#a32920", "#d9a09b"), r = ae("Answer", "#fff", "#08745f", "#08745f");
|
|
1973
1980
|
o.addEventListener("click", () => {
|
|
1974
|
-
this.reject(e.id).catch((c) => this.emit("error",
|
|
1981
|
+
this.reject(e.id).catch((c) => this.emit("error", x(c)));
|
|
1975
1982
|
}), r.addEventListener("click", () => {
|
|
1976
|
-
this.accept(e.id).catch((c) => this.emit("error",
|
|
1983
|
+
this.accept(e.id).catch((c) => this.emit("error", x(c)));
|
|
1977
1984
|
}), s.appendChild(o), s.appendChild(r), t.appendChild(i), t.appendChild(n), t.appendChild(s), this.mount.replaceChildren(t);
|
|
1978
1985
|
}
|
|
1979
1986
|
dismiss(e) {
|
|
@@ -2041,7 +2048,7 @@ class Ee extends EventTarget {
|
|
|
2041
2048
|
const t = Math.max(0, e - this.refreshSkew(e));
|
|
2042
2049
|
this.tokenRefreshTimer = setTimeout(() => {
|
|
2043
2050
|
this.tokenRefreshTimer = null, this.resolveToken("expiring", !0).catch((i) => {
|
|
2044
|
-
this.emit("tokenerror",
|
|
2051
|
+
this.emit("tokenerror", x(i)), this.stopped || (this.tokenRefreshTimer = setTimeout(() => this.scheduleTokenRefresh(), 3e4));
|
|
2045
2052
|
});
|
|
2046
2053
|
}, Math.min(t, 2147e6));
|
|
2047
2054
|
}
|
|
@@ -2055,21 +2062,21 @@ class Ee extends EventTarget {
|
|
|
2055
2062
|
this.options.reportSignalingDiagnostics === !1 || this.stopped || this.request("/v1/rtc/client/signaling-events", {
|
|
2056
2063
|
method: "POST",
|
|
2057
2064
|
body: JSON.stringify({ ...e, occurredAt: (/* @__PURE__ */ new Date()).toISOString() })
|
|
2058
|
-
}).catch((t) => this.emit("diagnosticserror",
|
|
2065
|
+
}).catch((t) => this.emit("diagnosticserror", x(t)));
|
|
2059
2066
|
}
|
|
2060
2067
|
emit(e, t) {
|
|
2061
2068
|
const i = { type: e, detail: t, timestamp: (/* @__PURE__ */ new Date()).toISOString() };
|
|
2062
2069
|
this.dispatchEvent(new CustomEvent(e, { detail: i })), this.options.onEvent?.(i);
|
|
2063
2070
|
}
|
|
2064
2071
|
}
|
|
2065
|
-
function
|
|
2066
|
-
const e = new
|
|
2072
|
+
function Fe(a) {
|
|
2073
|
+
const e = new Pe(a);
|
|
2067
2074
|
return a.autoConnect !== !1 && a.signalingUrl && e.connect(), e;
|
|
2068
2075
|
}
|
|
2069
|
-
function
|
|
2076
|
+
function ne(a) {
|
|
2070
2077
|
return a ? typeof a == "string" ? document.querySelector(a) : a : null;
|
|
2071
2078
|
}
|
|
2072
|
-
function
|
|
2079
|
+
function ae(a, e, t, i) {
|
|
2073
2080
|
const n = document.createElement("button");
|
|
2074
2081
|
return n.type = "button", n.textContent = a, Object.assign(n.style, {
|
|
2075
2082
|
minHeight: "44px",
|
|
@@ -2082,7 +2089,7 @@ function ie(a, e, t, i) {
|
|
|
2082
2089
|
fontWeight: "700"
|
|
2083
2090
|
}), n;
|
|
2084
2091
|
}
|
|
2085
|
-
function
|
|
2092
|
+
function Ae(a) {
|
|
2086
2093
|
return {
|
|
2087
2094
|
rejected: "Call declined",
|
|
2088
2095
|
busy: "Line busy",
|
|
@@ -2092,102 +2099,106 @@ function Me(a) {
|
|
|
2092
2099
|
missed: "No answer"
|
|
2093
2100
|
}[a] ?? "Call ended";
|
|
2094
2101
|
}
|
|
2095
|
-
function
|
|
2102
|
+
function se(a) {
|
|
2096
2103
|
return {
|
|
2097
2104
|
id: a.participantId,
|
|
2098
2105
|
name: a.displayName,
|
|
2099
2106
|
role: "participant"
|
|
2100
2107
|
};
|
|
2101
2108
|
}
|
|
2102
|
-
async function
|
|
2109
|
+
async function Le(a, e) {
|
|
2103
2110
|
const t = await a.getStats(), i = /* @__PURE__ */ new Map(), n = /* @__PURE__ */ new Map();
|
|
2104
|
-
let s = 0, o = 0, r = 0, c = 0, l = 0, d = 0, u = 0,
|
|
2111
|
+
let s = 0, o = 0, r = 0, c = 0, l = 0, d = 0, u = 0, k = 0, f = 0, v = 0, C = 0, y = 0, w = 0, p = 0, R = 0, P = null, L = null, I = null, A = null, S = null, E = null;
|
|
2105
2112
|
t.forEach((g) => {
|
|
2106
2113
|
n.set(g.id, g), g.type === "codec" && i.set(g.id, String(g.mimeType ?? ""));
|
|
2107
2114
|
}), t.forEach((g) => {
|
|
2108
|
-
if (g.type === "inbound-rtp" && !g.isRemote && (s += Number(g.bytesReceived ?? 0), r += Math.max(0, Number(g.packetsLost ?? 0)), c += Math.max(0, Number(g.packetsReceived ?? 0)), Number.isFinite(g.jitter) && (l += Number(g.jitter), d += 1), u = Math.max(u, Number(g.framesPerSecond ?? 0)),
|
|
2109
|
-
|
|
2115
|
+
if (g.type === "inbound-rtp" && !g.isRemote && (s += Number(g.bytesReceived ?? 0), r += Math.max(0, Number(g.packetsLost ?? 0)), c += Math.max(0, Number(g.packetsReceived ?? 0)), Number.isFinite(g.jitter) && (l += Number(g.jitter), d += 1), u = Math.max(u, Number(g.framesPerSecond ?? 0)), k = Math.max(k, Number(g.frameWidth ?? 0)), C = Math.max(C, Number(g.frameHeight ?? 0)), y += Number(g.framesDropped ?? 0), w += Number(g.freezeCount ?? 0), p += Number(g.totalFreezesDuration ?? 0), R += Number(g.concealedSamples ?? 0), S ||= i.get(String(g.codecId ?? "")) ?? null), g.type === "outbound-rtp" && !g.isRemote && (f = Math.max(f, Number(g.frameWidth ?? 0)), v = Math.max(v, Number(g.frameHeight ?? 0)), o += Number(g.bytesSent ?? 0), E ||= g.qualityLimitationReason ? String(g.qualityLimitationReason) : null, S ||= i.get(String(g.codecId ?? "")) ?? null), g.type === "candidate-pair" && (g.selected || g.nominated) && g.state === "succeeded") {
|
|
2116
|
+
P = Number.isFinite(g.currentRoundTripTime) ? Number(g.currentRoundTripTime) : P, L = Number.isFinite(g.availableOutgoingBitrate) ? Number(g.availableOutgoingBitrate) : L;
|
|
2110
2117
|
const q = n.get(g.localCandidateId);
|
|
2111
|
-
|
|
2118
|
+
I = q?.candidateType ? String(q.candidateType) : I, A = q?.protocol ? String(q.protocol) : A;
|
|
2112
2119
|
}
|
|
2113
2120
|
});
|
|
2114
|
-
const
|
|
2121
|
+
const m = Date.now(), h = e ? Math.max(1e-3, (m - e.timestamp) / 1e3) : 0, T = e ? Math.max(0, Math.round((s - e.inboundBytes) * 8 / h)) : null, M = e ? Math.max(0, Math.round((o - e.outboundBytes) * 8 / h)) : null, b = r + c, O = e ? Math.max(0, r - e.packetsLost) : r, V = e ? Math.max(0, c - e.packetsReceived) : c, N = O + V;
|
|
2115
2122
|
return {
|
|
2116
|
-
counters: { timestamp:
|
|
2123
|
+
counters: { timestamp: m, inboundBytes: s, outboundBytes: o, packetsLost: r, packetsReceived: c },
|
|
2117
2124
|
sample: {
|
|
2118
|
-
rttMs:
|
|
2125
|
+
rttMs: P === null ? null : P * 1e3,
|
|
2119
2126
|
jitterMs: d ? l / d * 1e3 : null,
|
|
2120
|
-
packetLossPct:
|
|
2121
|
-
packetLossCumulativePct:
|
|
2127
|
+
packetLossPct: N ? O / N * 100 : null,
|
|
2128
|
+
packetLossCumulativePct: b ? r / b * 100 : null,
|
|
2122
2129
|
packetsLost: r,
|
|
2123
2130
|
packetsReceived: c,
|
|
2124
|
-
inboundBitrateBps:
|
|
2125
|
-
outboundBitrateBps:
|
|
2126
|
-
availableOutgoingBitrateBps:
|
|
2131
|
+
inboundBitrateBps: T,
|
|
2132
|
+
outboundBitrateBps: M,
|
|
2133
|
+
availableOutgoingBitrateBps: L,
|
|
2127
2134
|
framesPerSecond: u || null,
|
|
2128
|
-
frameWidth:
|
|
2129
|
-
frameHeight:
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2135
|
+
frameWidth: k || null,
|
|
2136
|
+
frameHeight: C || null,
|
|
2137
|
+
inboundFrameWidth: k || null,
|
|
2138
|
+
inboundFrameHeight: C || null,
|
|
2139
|
+
outboundFrameWidth: f || null,
|
|
2140
|
+
outboundFrameHeight: v || null,
|
|
2141
|
+
framesDropped: y,
|
|
2142
|
+
freezeCount: w,
|
|
2143
|
+
freezeDurationMs: Math.round(p * 1e3),
|
|
2144
|
+
concealedSamples: R,
|
|
2145
|
+
codec: S,
|
|
2146
|
+
transportProtocol: A,
|
|
2147
|
+
candidateType: I,
|
|
2148
|
+
qualityLimitationReason: E
|
|
2138
2149
|
}
|
|
2139
2150
|
};
|
|
2140
2151
|
}
|
|
2141
|
-
function
|
|
2142
|
-
let e = a.mediaScore == null ? 5 : Math.round(
|
|
2143
|
-
const t =
|
|
2152
|
+
function De(a) {
|
|
2153
|
+
let e = a.mediaScore == null ? 5 : Math.round(oe(Number(a.mediaScore), 0, 5));
|
|
2154
|
+
const t = W(a.packetLossPct) ?? 0, i = W(a.rttMs) ?? 0, n = W(a.jitterMs) ?? 0, s = String(a.connectionState ?? "unknown").toLowerCase();
|
|
2144
2155
|
["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));
|
|
2145
|
-
const o = Number(
|
|
2156
|
+
const o = Number(oe(4.5 - t * 0.09 - i * 11e-4 - n * 6e-3, 1, 4.5).toFixed(2));
|
|
2146
2157
|
return { networkScore: e, estimatedMos: o };
|
|
2147
2158
|
}
|
|
2148
|
-
function
|
|
2159
|
+
function re() {
|
|
2149
2160
|
return navigator.connection ?? null;
|
|
2150
2161
|
}
|
|
2151
|
-
function
|
|
2162
|
+
function qe() {
|
|
2152
2163
|
const a = Number(navigator.deviceMemory);
|
|
2153
2164
|
return Number.isFinite(a) ? a : null;
|
|
2154
2165
|
}
|
|
2155
|
-
function
|
|
2166
|
+
function W(a) {
|
|
2156
2167
|
const e = Number(a);
|
|
2157
2168
|
return Number.isFinite(e) ? e : null;
|
|
2158
2169
|
}
|
|
2159
|
-
function
|
|
2170
|
+
function oe(a, e, t) {
|
|
2160
2171
|
return Math.min(t, Math.max(e, a));
|
|
2161
2172
|
}
|
|
2162
|
-
function
|
|
2173
|
+
function x(a) {
|
|
2163
2174
|
return a instanceof Error ? { name: a.name, message: a.message } : { name: "ServiceError", message: String(a ?? "Service request failed") };
|
|
2164
2175
|
}
|
|
2165
|
-
function
|
|
2176
|
+
function ce(a, e) {
|
|
2166
2177
|
return a instanceof Error ? a : new Error(e);
|
|
2167
2178
|
}
|
|
2168
|
-
const
|
|
2179
|
+
const Oe = "1.3.22";
|
|
2169
2180
|
export {
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2181
|
+
te as AVATAR_TUNING_DEFAULTS,
|
|
2182
|
+
we as BACKGROUND_PRESETS,
|
|
2183
|
+
Te as OVERLAY_EFFECTS,
|
|
2184
|
+
Ie as RtcClient,
|
|
2185
|
+
Pe as RtcIncomingClient,
|
|
2186
|
+
Ne as SPEAKER_NOISE_FLOOR,
|
|
2187
|
+
je as SPEAKER_TAKEOVER_RATIO,
|
|
2188
|
+
Qe as createAvatarPipeline,
|
|
2189
|
+
Ve as createCallRecorder,
|
|
2190
|
+
xe as createPictureInPictureController,
|
|
2191
|
+
Be as createRtcClient,
|
|
2192
|
+
Fe as createRtcIncomingClient,
|
|
2193
|
+
Ue as createVideoEffectsPipeline,
|
|
2194
|
+
Re as drawAvatar,
|
|
2195
|
+
be as headPoseFromMatrix,
|
|
2196
|
+
he as neutralRig,
|
|
2197
|
+
le as pickActiveSpeaker,
|
|
2198
|
+
Ce as rigFromBlendshapes,
|
|
2199
|
+
Z as scenePainters,
|
|
2200
|
+
ee as smoothRig,
|
|
2201
|
+
ie as stylizedAvatarRenderer,
|
|
2202
|
+
Ee as unlockRtcCallAudio,
|
|
2203
|
+
Oe as version
|
|
2193
2204
|
};
|