@streaming-cdn/rtc-web 1.3.21 → 1.3.23
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/dist/index.d.ts +16 -1
- package/dist/rtc-web.es.js +217 -186
- 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, Oe = 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 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
|
+
}, me = {
|
|
23
23
|
warmupSamples: 3,
|
|
24
24
|
poorSamplesToStepDown: 2,
|
|
25
25
|
goodSamplesToStepUp: 6,
|
|
@@ -32,15 +32,15 @@ const j = {
|
|
|
32
32
|
sustainRatio: 0.8,
|
|
33
33
|
bandwidthHeadroomRatio: 1.25
|
|
34
34
|
};
|
|
35
|
-
function
|
|
35
|
+
function pe(a) {
|
|
36
36
|
const e = String(a ?? "").trim().toLowerCase();
|
|
37
37
|
return !e || e === "none" ? "" : e === "cpu" || e === "bandwidth" ? e : "other";
|
|
38
38
|
}
|
|
39
|
-
function
|
|
40
|
-
const s = { ...
|
|
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 } :
|
|
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 = O[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, E = R ? t + 1 : 0, A = L ? i + 1 : 0, S = { quality: a, poorSamples: E, 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 } : E >= 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;
|
|
42
42
|
}
|
|
43
|
-
function
|
|
43
|
+
function ge(a, e) {
|
|
44
44
|
const t = a instanceof Map ? a : new Map(a);
|
|
45
45
|
let i = 0, n = 0, s = null, o = null, r = null;
|
|
46
46
|
for (const d of t.values()) {
|
|
@@ -68,9 +68,17 @@ function pe(a, e) {
|
|
|
68
68
|
counters: c
|
|
69
69
|
};
|
|
70
70
|
}
|
|
71
|
-
|
|
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 = {
|
|
72
80
|
audio: { active: !1, maxBitrate: 0, maxFramerate: 0, scaleResolutionDownBy: 4 }
|
|
73
|
-
},
|
|
81
|
+
}, ve = { active: !0, maxBitrate: 4e6, maxFramerate: 30, scaleResolutionDownBy: 1 };
|
|
74
82
|
class Q {
|
|
75
83
|
options;
|
|
76
84
|
socket = null;
|
|
@@ -213,9 +221,7 @@ class Q {
|
|
|
213
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);
|
|
214
222
|
}
|
|
215
223
|
async openSocket(e) {
|
|
216
|
-
const { credential: t } = this.options, i =
|
|
217
|
-
i.protocol = i.protocol === "https:" ? "wss:" : "ws:";
|
|
218
|
-
const n = new Promise((c, l) => {
|
|
224
|
+
const { credential: t } = this.options, i = $(t.signalingUrl, globalThis.location?.href), n = new Promise((c, l) => {
|
|
219
225
|
this.resolveJoin = c, this.rejectJoin = l;
|
|
220
226
|
}), s = new WebSocket(i, ["rtc-client", t.signalingToken]), o = ++this.socketGeneration;
|
|
221
227
|
this.socket = s;
|
|
@@ -352,7 +358,7 @@ class Q {
|
|
|
352
358
|
});
|
|
353
359
|
if (e.connection.signalingState !== "stable") return;
|
|
354
360
|
await e.connection.setLocalDescription(t);
|
|
355
|
-
const i =
|
|
361
|
+
const i = G();
|
|
356
362
|
e.activeNegotiationId = i, this.send({
|
|
357
363
|
type: "rtc.offer",
|
|
358
364
|
targetParticipantId: e.identity.participantId,
|
|
@@ -392,7 +398,7 @@ class Q {
|
|
|
392
398
|
async applyPeerVideoQuality(e) {
|
|
393
399
|
const t = this.screenStream?.getVideoTracks()[0]?.id;
|
|
394
400
|
for (const i of e.connection.getSenders().filter((n) => n.track?.kind === "video")) {
|
|
395
|
-
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 : O[e.quality], o = i.getParameters(), r = o.encodings?.length ? o.encodings : [{}];
|
|
396
402
|
o.encodings = r.map((c) => ({ ...c, ...s })), o.degradationPreference = n ? "maintain-resolution" : "maintain-framerate", await i.setParameters(o);
|
|
397
403
|
}
|
|
398
404
|
}
|
|
@@ -412,11 +418,11 @@ class Q {
|
|
|
412
418
|
if (i.connection.connectionState === "connected")
|
|
413
419
|
try {
|
|
414
420
|
const n = await i.connection.getStats();
|
|
415
|
-
for (const s of
|
|
421
|
+
for (const s of de(n.values()))
|
|
416
422
|
e.push({ participantId: i.identity.participantId, level: s.level });
|
|
417
423
|
} catch {
|
|
418
424
|
}
|
|
419
|
-
const t =
|
|
425
|
+
const t = le(e, this.activeSpeaker);
|
|
420
426
|
t !== this.activeSpeaker && (this.activeSpeaker = t, this.options.onEvent("activespeaker", { participantId: t }));
|
|
421
427
|
}
|
|
422
428
|
async samplePeerQuality() {
|
|
@@ -429,9 +435,9 @@ class Q {
|
|
|
429
435
|
} catch {
|
|
430
436
|
continue;
|
|
431
437
|
}
|
|
432
|
-
const { sample: i, counters: n } =
|
|
438
|
+
const { sample: i, counters: n } = ge(t, e.counters);
|
|
433
439
|
e.counters = n;
|
|
434
|
-
const s =
|
|
440
|
+
const s = fe(e.quality, i, e.poorSamples, e.goodSamples, {
|
|
435
441
|
samplesSeen: e.samplesSeen,
|
|
436
442
|
ceiling: this.quality
|
|
437
443
|
});
|
|
@@ -488,7 +494,7 @@ class Q {
|
|
|
488
494
|
}
|
|
489
495
|
send(e) {
|
|
490
496
|
this.socket?.readyState === WebSocket.OPEN && this.socket.send(JSON.stringify({
|
|
491
|
-
clientMessageId: e.clientMessageId ??
|
|
497
|
+
clientMessageId: e.clientMessageId ?? G(),
|
|
492
498
|
...e
|
|
493
499
|
}));
|
|
494
500
|
}
|
|
@@ -496,15 +502,15 @@ class Q {
|
|
|
496
502
|
for (const t of e?.getTracks() ?? []) t.stop();
|
|
497
503
|
}
|
|
498
504
|
}
|
|
499
|
-
function
|
|
505
|
+
function G() {
|
|
500
506
|
return globalThis.crypto?.randomUUID?.() ?? `${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`;
|
|
501
507
|
}
|
|
502
|
-
const H = { active: !0, maxBitrate: 4e6, maxFramerate: 30, scaleResolutionDownBy: 1 },
|
|
503
|
-
{ rid: "a", maxBitrate:
|
|
504
|
-
{ rid: "b", maxBitrate:
|
|
505
|
-
{ rid: "c", maxBitrate:
|
|
506
|
-
],
|
|
507
|
-
class
|
|
508
|
+
const H = { active: !0, maxBitrate: 4e6, maxFramerate: 30, scaleResolutionDownBy: 1 }, K = [
|
|
509
|
+
{ rid: "a", maxBitrate: O.high.maxBitrate, maxFramerate: O.high.maxFramerate },
|
|
510
|
+
{ rid: "b", maxBitrate: O.medium.maxBitrate, maxFramerate: O.medium.maxFramerate, scaleResolutionDownBy: 2 },
|
|
511
|
+
{ rid: "c", maxBitrate: O.low.maxBitrate, maxFramerate: O.low.maxFramerate, scaleResolutionDownBy: 4 }
|
|
512
|
+
], X = { high: "a", medium: "b", low: "c" };
|
|
513
|
+
class Se {
|
|
508
514
|
options;
|
|
509
515
|
apiBase;
|
|
510
516
|
socket = null;
|
|
@@ -536,7 +542,7 @@ class ye {
|
|
|
536
542
|
negotiationQueue = Promise.resolve();
|
|
537
543
|
socketGeneration = 0;
|
|
538
544
|
constructor(e) {
|
|
539
|
-
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;
|
|
540
546
|
}
|
|
541
547
|
async initialize() {
|
|
542
548
|
if (!globalThis.RTCPeerConnection || !globalThis.WebSocket)
|
|
@@ -637,9 +643,7 @@ class ye {
|
|
|
637
643
|
}
|
|
638
644
|
// --- signaling -----------------------------------------------------------
|
|
639
645
|
async openSocket(e) {
|
|
640
|
-
const { credential: t } = this.options, i =
|
|
641
|
-
i.protocol = i.protocol === "https:" ? "wss:" : "ws:";
|
|
642
|
-
const n = new Promise((c, l) => {
|
|
646
|
+
const { credential: t } = this.options, i = $(t.signalingUrl, globalThis.location?.href), n = new Promise((c, l) => {
|
|
643
647
|
this.resolveJoin = c, this.rejectJoin = l;
|
|
644
648
|
}), s = new WebSocket(i, ["rtc-client", t.signalingToken]), o = ++this.socketGeneration;
|
|
645
649
|
this.socket = s;
|
|
@@ -722,7 +726,7 @@ class ye {
|
|
|
722
726
|
// A single encoding when simulcast is off: constrained publishers
|
|
723
727
|
// (phone CPU, cellular uplink) should not pay for three encoders. The
|
|
724
728
|
// quality ladder then adapts that one encoding instead of gating layers.
|
|
725
|
-
...r.kind === "video" && this.simulcastEnabled() ? { sendEncodings:
|
|
729
|
+
...r.kind === "video" && this.simulcastEnabled() ? { sendEncodings: K.map((c) => ({ ...c })) } : {}
|
|
726
730
|
})), s = await t.createOffer();
|
|
727
731
|
await t.setLocalDescription(s);
|
|
728
732
|
const o = await this.sfuFetch(
|
|
@@ -822,7 +826,7 @@ class ye {
|
|
|
822
826
|
n && await this.sfuFetch("PUT", `/v1/rtc/sfu/sessions/${encodeURIComponent(this.sessionId)}/tracks/update`, {
|
|
823
827
|
tracks: [{
|
|
824
828
|
mid: n,
|
|
825
|
-
simulcast: { preferredRid:
|
|
829
|
+
simulcast: { preferredRid: X[t], priorityOrdering: "asciibetical", ridNotAvailable: "asciibetical" }
|
|
826
830
|
}]
|
|
827
831
|
});
|
|
828
832
|
}
|
|
@@ -837,15 +841,15 @@ class ye {
|
|
|
837
841
|
if (!e) return;
|
|
838
842
|
const t = this.screenStream?.getVideoTracks()[0]?.id, i = !!(t && e.track?.id === t), n = e.getParameters(), s = n.encodings?.length ? n.encodings : [{}];
|
|
839
843
|
if (s.length > 1) {
|
|
840
|
-
const o = this.quality === "audio" ? null :
|
|
844
|
+
const o = this.quality === "audio" ? null : X[this.quality];
|
|
841
845
|
n.encodings = s.map((r) => {
|
|
842
846
|
if (i)
|
|
843
847
|
return { ...r, active: r.rid === "a", ...r.rid === "a" ? { maxBitrate: H.maxBitrate, maxFramerate: H.maxFramerate } : {} };
|
|
844
|
-
const c =
|
|
848
|
+
const c = K.find((d) => d.rid === r.rid), l = o != null && String(r.rid ?? "") >= o;
|
|
845
849
|
return { ...r, ...c ?? {}, active: l };
|
|
846
850
|
});
|
|
847
851
|
} else {
|
|
848
|
-
const o = this.quality === "audio" ?
|
|
852
|
+
const o = this.quality === "audio" ? O.audio : O[this.quality], r = i ? H : o;
|
|
849
853
|
n.encodings = s.map((c) => ({ ...c, ...r }));
|
|
850
854
|
}
|
|
851
855
|
n.degradationPreference = i ? "maintain-resolution" : "maintain-framerate", await e.setParameters(n);
|
|
@@ -912,11 +916,11 @@ class ye {
|
|
|
912
916
|
return;
|
|
913
917
|
}
|
|
914
918
|
const i = [];
|
|
915
|
-
for (const s of
|
|
919
|
+
for (const s of de(t.values())) {
|
|
916
920
|
const o = s.mid ? this.midToParticipant.get(s.mid) : void 0;
|
|
917
921
|
o && i.push({ participantId: o, level: s.level });
|
|
918
922
|
}
|
|
919
|
-
const n =
|
|
923
|
+
const n = le(i, this.activeSpeaker);
|
|
920
924
|
n !== this.activeSpeaker && (this.activeSpeaker = n, this.options.onEvent("activespeaker", { participantId: n }));
|
|
921
925
|
}
|
|
922
926
|
clearTimers() {
|
|
@@ -933,7 +937,7 @@ class ye {
|
|
|
933
937
|
}
|
|
934
938
|
send(e) {
|
|
935
939
|
this.socket?.readyState === WebSocket.OPEN && this.socket.send(JSON.stringify({
|
|
936
|
-
clientMessageId: e.clientMessageId ??
|
|
940
|
+
clientMessageId: e.clientMessageId ?? ke(),
|
|
937
941
|
...e
|
|
938
942
|
}));
|
|
939
943
|
}
|
|
@@ -941,10 +945,10 @@ class ye {
|
|
|
941
945
|
for (const t of e?.getTracks() ?? []) t.stop();
|
|
942
946
|
}
|
|
943
947
|
}
|
|
944
|
-
function
|
|
948
|
+
function ke() {
|
|
945
949
|
return globalThis.crypto?.randomUUID?.() ?? `${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`;
|
|
946
950
|
}
|
|
947
|
-
function
|
|
951
|
+
function je(a, e = {}) {
|
|
948
952
|
const t = e.document ?? globalThis.document, i = !!(t && t.pictureInPictureEnabled);
|
|
949
953
|
let n = null;
|
|
950
954
|
function s() {
|
|
@@ -972,8 +976,8 @@ function Ne(a, e = {}) {
|
|
|
972
976
|
}
|
|
973
977
|
};
|
|
974
978
|
}
|
|
975
|
-
function
|
|
976
|
-
const t = e.document ?? globalThis.document, i = e.fetchImplementation ?? globalThis.fetch.bind(globalThis), 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);
|
|
977
981
|
let c = null, l = null, d = null, u = null, k = 0, f = [], v = !1;
|
|
978
982
|
async function C(y, w, p, R = "application/json") {
|
|
979
983
|
const P = await i(`${n}${w}`, {
|
|
@@ -1007,26 +1011,26 @@ function je(a, e) {
|
|
|
1007
1011
|
...M ? [{ key: "local", stream: M, label: "me" }] : []
|
|
1008
1012
|
];
|
|
1009
1013
|
p.fillStyle = "#101418", p.fillRect(0, 0, r, o);
|
|
1010
|
-
const
|
|
1011
|
-
b.forEach((q,
|
|
1012
|
-
const
|
|
1013
|
-
|
|
1014
|
+
const x = Math.max(1, Math.ceil(Math.sqrt(b.length))), V = Math.max(1, Math.ceil(b.length / x)), N = r / x, g = o / V;
|
|
1015
|
+
b.forEach((q, _) => {
|
|
1016
|
+
const Y = P(q.key, q.stream), B = _ % x * N, F = Math.floor(_ / x) * 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);
|
|
1014
1018
|
});
|
|
1015
1019
|
}, 66);
|
|
1016
1020
|
const L = w.captureStream(15);
|
|
1017
1021
|
d = new AudioContext();
|
|
1018
|
-
const
|
|
1022
|
+
const E = d.createMediaStreamDestination(), A = /* @__PURE__ */ new Set(), S = () => {
|
|
1019
1023
|
const T = [
|
|
1020
1024
|
...a.getRemoteStreams().map((M) => M.stream),
|
|
1021
1025
|
...a.getLocalStream() ? [a.getLocalStream()] : []
|
|
1022
1026
|
];
|
|
1023
1027
|
for (const M of T)
|
|
1024
1028
|
for (const b of M.getAudioTracks())
|
|
1025
|
-
A.has(b.id) || (A.add(b.id), d.createMediaStreamSource(new MediaStream([b])).connect(
|
|
1029
|
+
A.has(b.id) || (A.add(b.id), d.createMediaStreamSource(new MediaStream([b])).connect(E));
|
|
1026
1030
|
};
|
|
1027
1031
|
S();
|
|
1028
|
-
const
|
|
1029
|
-
for (const T of
|
|
1032
|
+
const I = setInterval(S, 1e3), m = () => clearInterval(I);
|
|
1033
|
+
for (const T of E.stream.getAudioTracks()) L.addTrack(T);
|
|
1030
1034
|
c = (e.mediaRecorderFactory ?? ((T, M) => new MediaRecorder(T, M)))(L, { mimeType: s }), f = [], c.addEventListener("dataavailable", (T) => {
|
|
1031
1035
|
T.data && T.data.size > 0 && f.push(T.data);
|
|
1032
1036
|
}), c.addEventListener("stop", m), c.start(1e3), k = Date.now(), v = !0;
|
|
@@ -1034,7 +1038,7 @@ function je(a, e) {
|
|
|
1034
1038
|
async stop() {
|
|
1035
1039
|
if (!v || !c || !u) throw new Error("The recorder is not running");
|
|
1036
1040
|
v = !1;
|
|
1037
|
-
const y = c, w = new Promise((
|
|
1041
|
+
const y = c, w = new Promise((E) => y.addEventListener("stop", () => E(), { once: !0 }));
|
|
1038
1042
|
y.stop(), await w, l && clearInterval(l), l = null, await d?.close().catch(() => {
|
|
1039
1043
|
}), d = null;
|
|
1040
1044
|
const p = new Blob(f, { type: s });
|
|
@@ -1060,7 +1064,7 @@ function je(a, e) {
|
|
|
1060
1064
|
}
|
|
1061
1065
|
};
|
|
1062
1066
|
}
|
|
1063
|
-
const
|
|
1067
|
+
const we = ["none", "blur", "aurora", "cybergrid", "bokeh", "sunset", "image"], Te = ["none", "snow", "confetti", "vignette"], Z = {
|
|
1064
1068
|
aurora(a, e, t, i) {
|
|
1065
1069
|
const n = a.createLinearGradient(0, 0, 0, t);
|
|
1066
1070
|
n.addColorStop(0, "#050b1e"), n.addColorStop(1, "#0b2540"), a.fillStyle = n, a.fillRect(0, 0, e, t);
|
|
@@ -1097,7 +1101,7 @@ const Se = ["none", "blur", "aurora", "cybergrid", "bokeh", "sunset", "image"],
|
|
|
1097
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);
|
|
1098
1102
|
}
|
|
1099
1103
|
};
|
|
1100
|
-
function
|
|
1104
|
+
function Ue(a, e = {}) {
|
|
1101
1105
|
const t = e.document ?? globalThis.document;
|
|
1102
1106
|
let i = e.width ?? 1280, n = e.height ?? 720;
|
|
1103
1107
|
const s = !!(e.width || e.height), o = e.frameRate ?? 24, r = a instanceof MediaStreamTrack ? a : a.getVideoTracks()[0];
|
|
@@ -1127,7 +1131,7 @@ function xe(a, e = {}) {
|
|
|
1127
1131
|
M === i && b === n || (i = M, n = b, C.width = i, C.height = n, w.width = i, w.height = n, P = R());
|
|
1128
1132
|
};
|
|
1129
1133
|
v.addEventListener?.("loadedmetadata", L), v.addEventListener?.("resize", L);
|
|
1130
|
-
function
|
|
1134
|
+
function E() {
|
|
1131
1135
|
if (k) {
|
|
1132
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);
|
|
1133
1137
|
return;
|
|
@@ -1136,7 +1140,7 @@ function xe(a, e = {}) {
|
|
|
1136
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();
|
|
1137
1141
|
}
|
|
1138
1142
|
function A(m) {
|
|
1139
|
-
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 &&
|
|
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 && E()) : c === "image" && d ? (y.drawImage(d, 0, 0, i, n), E()) : ((Z[c] ?? Z.aurora)(y, i, n, m), E()), l === "snow" || l === "confetti")
|
|
1140
1144
|
for (const h of P)
|
|
1141
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());
|
|
1142
1146
|
else if (l === "vignette") {
|
|
@@ -1152,27 +1156,27 @@ function xe(a, e = {}) {
|
|
|
1152
1156
|
}).finally(() => {
|
|
1153
1157
|
f = !1;
|
|
1154
1158
|
}));
|
|
1155
|
-
}, Math.round(1e3 / o)),
|
|
1159
|
+
}, Math.round(1e3 / o)), I = C.captureStream(o);
|
|
1156
1160
|
return {
|
|
1157
|
-
track:
|
|
1158
|
-
stream:
|
|
1161
|
+
track: I.getVideoTracks()[0],
|
|
1162
|
+
stream: I,
|
|
1159
1163
|
setBackground(m, h) {
|
|
1160
|
-
c =
|
|
1164
|
+
c = we.includes(m) ? m : "none", h !== void 0 && (d = h), c === "none" && (k = null);
|
|
1161
1165
|
},
|
|
1162
1166
|
setOverlay(m) {
|
|
1163
|
-
l =
|
|
1167
|
+
l = Te.includes(m) ? m : "none";
|
|
1164
1168
|
},
|
|
1165
1169
|
setSegmenter(m) {
|
|
1166
1170
|
u = m, m || (k = null);
|
|
1167
1171
|
},
|
|
1168
1172
|
dispose() {
|
|
1169
1173
|
clearInterval(S), u?.close?.();
|
|
1170
|
-
for (const m of
|
|
1174
|
+
for (const m of I.getTracks()) m.stop();
|
|
1171
1175
|
v.srcObject = null;
|
|
1172
1176
|
}
|
|
1173
1177
|
};
|
|
1174
1178
|
}
|
|
1175
|
-
function
|
|
1179
|
+
function he() {
|
|
1176
1180
|
return {
|
|
1177
1181
|
blinkLeft: 0,
|
|
1178
1182
|
blinkRight: 0,
|
|
@@ -1191,15 +1195,15 @@ function D(a, e) {
|
|
|
1191
1195
|
const t = a.find((i) => i.categoryName === e);
|
|
1192
1196
|
return t ? Math.max(0, Math.min(1, t.score)) : 0;
|
|
1193
1197
|
}
|
|
1194
|
-
function
|
|
1198
|
+
function be(a) {
|
|
1195
1199
|
if (!a || a.length < 16) return { yaw: 0, pitch: 0, roll: 0 };
|
|
1196
1200
|
a[0], a[4];
|
|
1197
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);
|
|
1198
1202
|
return { yaw: o, pitch: r, roll: c };
|
|
1199
1203
|
}
|
|
1200
|
-
function
|
|
1201
|
-
if (!a || a.length === 0) return
|
|
1202
|
-
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;
|
|
1203
1207
|
return {
|
|
1204
1208
|
blinkLeft: d + (f - d) * k,
|
|
1205
1209
|
blinkRight: u + (f - u) * k,
|
|
@@ -1214,7 +1218,7 @@ function Te(a, e, t = 1) {
|
|
|
1214
1218
|
tracked: !0
|
|
1215
1219
|
};
|
|
1216
1220
|
}
|
|
1217
|
-
function
|
|
1221
|
+
function ee(a, e, t = 0.4) {
|
|
1218
1222
|
const i = (n, s) => n + (s - n) * t;
|
|
1219
1223
|
return {
|
|
1220
1224
|
blinkLeft: i(a.blinkLeft, e.blinkLeft),
|
|
@@ -1230,7 +1234,7 @@ function X(a, e, t = 0.4) {
|
|
|
1230
1234
|
tracked: e.tracked
|
|
1231
1235
|
};
|
|
1232
1236
|
}
|
|
1233
|
-
function
|
|
1237
|
+
function Re(a, e, t, i, n) {
|
|
1234
1238
|
n || (a.fillStyle = "#101822", a.fillRect(0, 0, t, i));
|
|
1235
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;
|
|
1236
1240
|
a.save(), a.translate(s, o), a.rotate(e.headRoll * 0.6);
|
|
@@ -1241,14 +1245,14 @@ function be(a, e, t, i, n) {
|
|
|
1241
1245
|
const C = u(v) * 0.9, y = r * 0.12 + f;
|
|
1242
1246
|
a.ellipse(C + d * r * 0.14, y, r * 0.11, r * 0.14, 0, 0, Math.PI * 2), a.fill();
|
|
1243
1247
|
for (const A of [-1, 1]) {
|
|
1244
|
-
const S = A * 0.42,
|
|
1245
|
-
if (
|
|
1246
|
-
const m = u(S) * 0.82, h = Math.max(0.2,
|
|
1248
|
+
const S = A * 0.42, I = k(S);
|
|
1249
|
+
if (I <= 0.12) continue;
|
|
1250
|
+
const m = u(S) * 0.82, h = Math.max(0.2, I), T = A < 0 ? e.blinkLeft : e.blinkRight, M = Math.max(0.06, 1 - T), b = e.browUp * r * 0.14;
|
|
1247
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();
|
|
1248
|
-
const
|
|
1249
|
-
a.fillStyle = "#ffffff", a.beginPath(), a.ellipse(m,
|
|
1252
|
+
const x = -r * 0.18 + f;
|
|
1253
|
+
a.fillStyle = "#ffffff", a.beginPath(), a.ellipse(m, x, r * 0.16 * h, r * 0.12 * M, 0, 0, Math.PI * 2), a.fill(), a.fillStyle = "#22303c", a.beginPath(), a.ellipse(
|
|
1250
1254
|
m + e.pupilX * r * 0.07 * h,
|
|
1251
|
-
|
|
1255
|
+
x + e.pupilY * r * 0.05,
|
|
1252
1256
|
r * 0.06 * h,
|
|
1253
1257
|
r * 0.06 * M,
|
|
1254
1258
|
0,
|
|
@@ -1256,10 +1260,10 @@ function be(a, e, t, i, n) {
|
|
|
1256
1260
|
Math.PI * 2
|
|
1257
1261
|
), a.fill();
|
|
1258
1262
|
}
|
|
1259
|
-
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,
|
|
1260
|
-
a.fillStyle = "#8c2f2f", a.beginPath(), a.moveTo(p - R / 2,
|
|
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, E = r * 0.42 + f;
|
|
1264
|
+
a.fillStyle = "#8c2f2f", a.beginPath(), a.moveTo(p - R / 2, E - L), a.quadraticCurveTo(p, E + P, p + R / 2, E - L), a.quadraticCurveTo(p, E - P * 0.25, p - R / 2, E - 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");
|
|
1261
1265
|
}
|
|
1262
|
-
const
|
|
1266
|
+
const te = {
|
|
1263
1267
|
mouthGain: 1.7,
|
|
1264
1268
|
blinkGain: 1,
|
|
1265
1269
|
eyeSync: 1,
|
|
@@ -1268,37 +1272,37 @@ const Z = {
|
|
|
1268
1272
|
avatarLift: 0,
|
|
1269
1273
|
lostHoldMs: 400
|
|
1270
1274
|
};
|
|
1271
|
-
function
|
|
1275
|
+
function ie() {
|
|
1272
1276
|
return {
|
|
1273
1277
|
render(a, e, t, i, n) {
|
|
1274
|
-
|
|
1278
|
+
Re(a, e, t, i, n ?? void 0);
|
|
1275
1279
|
}
|
|
1276
1280
|
};
|
|
1277
1281
|
}
|
|
1278
1282
|
const z = (a) => Math.max(0, Math.min(1, a));
|
|
1279
|
-
function
|
|
1283
|
+
function Qe(a, e = {}) {
|
|
1280
1284
|
const t = e.document ?? globalThis.document;
|
|
1281
1285
|
let i = e.width ?? 1280, n = e.height ?? 720;
|
|
1282
1286
|
const s = !!(e.width || e.height), o = e.frameRate ?? 24, r = a instanceof MediaStreamTrack ? a : a.getVideoTracks()[0];
|
|
1283
1287
|
if (!r) throw new Error("A video track is required");
|
|
1284
|
-
let c = e.tracker ?? null, l = e.renderer ??
|
|
1285
|
-
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");
|
|
1286
1290
|
f.muted = !0, f.playsInline = !0, f.srcObject = new MediaStream([r]), f.play().catch(() => {
|
|
1287
1291
|
});
|
|
1288
1292
|
const v = t.createElement("canvas");
|
|
1289
1293
|
v.width = i, v.height = n;
|
|
1290
1294
|
const C = v.getContext("2d"), y = () => {
|
|
1291
1295
|
if (s) return;
|
|
1292
|
-
const S = f.videoWidth,
|
|
1293
|
-
if (!S || !
|
|
1294
|
-
const m = Math.min(1, 1280 / Math.max(S,
|
|
1296
|
+
const S = f.videoWidth, I = f.videoHeight;
|
|
1297
|
+
if (!S || !I) return;
|
|
1298
|
+
const m = Math.min(1, 1280 / Math.max(S, I)), h = Math.round(S * m), T = Math.round(I * m);
|
|
1295
1299
|
(!(h === i || T === n) || h !== i || T !== n) && (i = h, n = T, v.width = i, v.height = n);
|
|
1296
1300
|
};
|
|
1297
1301
|
f.addEventListener?.("loadedmetadata", y), f.addEventListener?.("resize", y);
|
|
1298
|
-
let w =
|
|
1302
|
+
let w = he(), p = null, R = 0;
|
|
1299
1303
|
function P(S) {
|
|
1300
1304
|
if (S.length <= 454) return;
|
|
1301
|
-
const
|
|
1305
|
+
const I = 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, x = Math.hypot((m.x - I.x) * i, (m.y - I.y) * n), V = Math.max(0.6, Math.cos(w.headPitch)), N = { x: M, y: b, radius: Math.max(24, x / V * 0.8) };
|
|
1302
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;
|
|
1303
1307
|
}
|
|
1304
1308
|
function L(S) {
|
|
@@ -1308,14 +1312,14 @@ function Ve(a, e = {}) {
|
|
|
1308
1312
|
m = c.detect(f, S);
|
|
1309
1313
|
} catch {
|
|
1310
1314
|
}
|
|
1311
|
-
const h =
|
|
1312
|
-
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 =
|
|
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));
|
|
1313
1317
|
}
|
|
1314
1318
|
d === "overlay" && f.readyState >= 2 ? C.drawImage(f, 0, 0, i, n) : (C.fillStyle = k, C.fillRect(0, 0, i, n));
|
|
1315
|
-
const
|
|
1316
|
-
l?.render(C, w, i, n,
|
|
1319
|
+
const I = p ? { x: p.x, y: p.y + u.avatarLift * p.radius, radius: p.radius * u.avatarScale } : null;
|
|
1320
|
+
l?.render(C, w, i, n, I);
|
|
1317
1321
|
}
|
|
1318
|
-
const
|
|
1322
|
+
const E = setInterval(() => L(Date.now()), Math.round(1e3 / o)), A = v.captureStream(o);
|
|
1319
1323
|
return {
|
|
1320
1324
|
track: A.getVideoTracks()[0],
|
|
1321
1325
|
stream: A,
|
|
@@ -1327,23 +1331,23 @@ function Ve(a, e = {}) {
|
|
|
1327
1331
|
c?.close?.(), c = S;
|
|
1328
1332
|
},
|
|
1329
1333
|
setRenderer(S) {
|
|
1330
|
-
l?.dispose?.(), l = S ??
|
|
1334
|
+
l?.dispose?.(), l = S ?? ie();
|
|
1331
1335
|
},
|
|
1332
1336
|
setTuning(S) {
|
|
1333
|
-
for (const
|
|
1334
|
-
const m = S[
|
|
1335
|
-
typeof m == "number" && Number.isFinite(m) && (u[
|
|
1337
|
+
for (const I of Object.keys(te)) {
|
|
1338
|
+
const m = S[I];
|
|
1339
|
+
typeof m == "number" && Number.isFinite(m) && (u[I] = m);
|
|
1336
1340
|
}
|
|
1337
1341
|
},
|
|
1338
1342
|
getTuning: () => ({ ...u }),
|
|
1339
1343
|
dispose() {
|
|
1340
|
-
clearInterval(
|
|
1344
|
+
clearInterval(E), c?.close?.(), l?.dispose?.();
|
|
1341
1345
|
for (const S of A.getTracks()) S.stop();
|
|
1342
1346
|
f.srcObject = null;
|
|
1343
1347
|
}
|
|
1344
1348
|
};
|
|
1345
1349
|
}
|
|
1346
|
-
class
|
|
1350
|
+
class Ee extends EventTarget {
|
|
1347
1351
|
mode;
|
|
1348
1352
|
options;
|
|
1349
1353
|
client = null;
|
|
@@ -1377,7 +1381,7 @@ class Ce extends EventTarget {
|
|
|
1377
1381
|
async initialize() {
|
|
1378
1382
|
if (this.client) return this;
|
|
1379
1383
|
try {
|
|
1380
|
-
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;
|
|
1381
1385
|
return this.client = new t({
|
|
1382
1386
|
credential: {
|
|
1383
1387
|
signalingToken: this.options.credential.signalingToken,
|
|
@@ -1397,19 +1401,19 @@ class Ce extends EventTarget {
|
|
|
1397
1401
|
localStream: this.options.localStream,
|
|
1398
1402
|
simulcast: this.options.simulcast ?? !0,
|
|
1399
1403
|
onEvent: (i, n) => this.handleNativeEvent(i, n)
|
|
1400
|
-
}), 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: xe }), this.options.autoJoin && await this.join(), this;
|
|
1401
1405
|
} catch (e) {
|
|
1402
1406
|
this.state = "failed";
|
|
1403
|
-
const t =
|
|
1404
|
-
throw this.emit("error",
|
|
1407
|
+
const t = ce(e, "RTC initialization failed");
|
|
1408
|
+
throw this.emit("error", j(t)), t;
|
|
1405
1409
|
}
|
|
1406
1410
|
}
|
|
1407
1411
|
async join() {
|
|
1408
1412
|
const e = this.requireClient();
|
|
1409
1413
|
return this.joinPromise ? this.joinPromise : (this.state = "joining", this.emit("joining", {}), this.joinPromise = e.join().catch((t) => {
|
|
1410
1414
|
this.state = "failed";
|
|
1411
|
-
const i =
|
|
1412
|
-
throw this.emit("error",
|
|
1415
|
+
const i = ce(t, "RTC connection failed");
|
|
1416
|
+
throw this.emit("error", j(i)), i;
|
|
1413
1417
|
}).finally(() => {
|
|
1414
1418
|
this.joinPromise = null;
|
|
1415
1419
|
}), this.joinPromise);
|
|
@@ -1447,14 +1451,14 @@ class Ce extends EventTarget {
|
|
|
1447
1451
|
return navigator.mediaDevices?.enumerateDevices ? navigator.mediaDevices.enumerateDevices() : [];
|
|
1448
1452
|
}
|
|
1449
1453
|
getParticipants() {
|
|
1450
|
-
return this.requireClient().getParticipants().map(
|
|
1454
|
+
return this.requireClient().getParticipants().map(se);
|
|
1451
1455
|
}
|
|
1452
1456
|
getLocalStream() {
|
|
1453
1457
|
return this.client?.getLocalStream() ?? null;
|
|
1454
1458
|
}
|
|
1455
1459
|
getRemoteStreams() {
|
|
1456
1460
|
return (this.client?.getRemoteStreams() ?? []).map((e) => ({
|
|
1457
|
-
participant:
|
|
1461
|
+
participant: se(e.participant),
|
|
1458
1462
|
stream: e.stream
|
|
1459
1463
|
}));
|
|
1460
1464
|
}
|
|
@@ -1548,7 +1552,7 @@ class Ce extends EventTarget {
|
|
|
1548
1552
|
microphoneCount: o,
|
|
1549
1553
|
cameraCount: r,
|
|
1550
1554
|
probeLatencyMs: l,
|
|
1551
|
-
effectiveConnectionType:
|
|
1555
|
+
effectiveConnectionType: re()?.effectiveType ?? null,
|
|
1552
1556
|
issues: t
|
|
1553
1557
|
};
|
|
1554
1558
|
return this.emit("preflight", d), this.options.autoReportStats && await this.reportQuality({
|
|
@@ -1561,7 +1565,7 @@ class Ce extends EventTarget {
|
|
|
1561
1565
|
}), d;
|
|
1562
1566
|
}
|
|
1563
1567
|
async collectQualitySample(e = "runtime") {
|
|
1564
|
-
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;
|
|
1565
1569
|
i?.counters && (this.previousCounters = i.counters);
|
|
1566
1570
|
const s = { ...{
|
|
1567
1571
|
sampleType: e,
|
|
@@ -1594,9 +1598,9 @@ class Ce extends EventTarget {
|
|
|
1594
1598
|
transportProtocol: null,
|
|
1595
1599
|
candidateType: null,
|
|
1596
1600
|
qualityLimitationReason: null,
|
|
1597
|
-
deviceMemoryGb:
|
|
1598
|
-
effectiveConnectionType:
|
|
1599
|
-
}, ...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);
|
|
1600
1604
|
return s.networkScore = o.networkScore, s.estimatedMos = o.estimatedMos, this.latestQuality = s, s;
|
|
1601
1605
|
}
|
|
1602
1606
|
async reportQuality(e) {
|
|
@@ -1647,7 +1651,7 @@ class Ce extends EventTarget {
|
|
|
1647
1651
|
const i = Date.now(), n = e !== "runtime" || i - this.lastTelemetryAt >= this.options.telemetryInterval;
|
|
1648
1652
|
this.options.autoReportStats && n && (await this.reportQuality(t), this.lastTelemetryAt = i);
|
|
1649
1653
|
} catch (t) {
|
|
1650
|
-
this.emit("telemetryerror",
|
|
1654
|
+
this.emit("telemetryerror", j(t));
|
|
1651
1655
|
} finally {
|
|
1652
1656
|
this.statsRunning = !1;
|
|
1653
1657
|
}
|
|
@@ -1681,21 +1685,21 @@ class Ce extends EventTarget {
|
|
|
1681
1685
|
this.dispatchEvent(new CustomEvent(e, { detail: i })), this.options.onEvent?.(i);
|
|
1682
1686
|
}
|
|
1683
1687
|
}
|
|
1684
|
-
async function
|
|
1685
|
-
return new
|
|
1688
|
+
async function Be(a) {
|
|
1689
|
+
return new Ee(a).initialize();
|
|
1686
1690
|
}
|
|
1687
1691
|
let U = null;
|
|
1688
|
-
function
|
|
1692
|
+
function ue() {
|
|
1689
1693
|
if (U) return U;
|
|
1690
1694
|
const a = globalThis, e = a.AudioContext ?? a.webkitAudioContext;
|
|
1691
1695
|
return e ? (U = new e(), U) : null;
|
|
1692
1696
|
}
|
|
1693
|
-
async function
|
|
1694
|
-
const a =
|
|
1697
|
+
async function Ie() {
|
|
1698
|
+
const a = ue();
|
|
1695
1699
|
return a ? (a.state === "suspended" && await a.resume().catch(() => {
|
|
1696
1700
|
}), a.state === "running") : !1;
|
|
1697
1701
|
}
|
|
1698
|
-
class
|
|
1702
|
+
class Me {
|
|
1699
1703
|
options;
|
|
1700
1704
|
media = null;
|
|
1701
1705
|
cadenceTimer = null;
|
|
@@ -1704,7 +1708,7 @@ class Ie {
|
|
|
1704
1708
|
this.options = e;
|
|
1705
1709
|
}
|
|
1706
1710
|
unlock() {
|
|
1707
|
-
return
|
|
1711
|
+
return Ie();
|
|
1708
1712
|
}
|
|
1709
1713
|
startIncoming() {
|
|
1710
1714
|
this.start("incoming", this.options.ringtoneUrl);
|
|
@@ -1732,7 +1736,7 @@ class Ie {
|
|
|
1732
1736
|
i(), this.cadenceTimer = setInterval(i, e === "incoming" ? 3e3 : 3500);
|
|
1733
1737
|
}
|
|
1734
1738
|
playBuiltInTone(e) {
|
|
1735
|
-
const t =
|
|
1739
|
+
const t = ue();
|
|
1736
1740
|
if (!t || t.state !== "running") return;
|
|
1737
1741
|
const i = e === "incoming" ? 1.25 : 1, n = e === "incoming" ? [440, 480] : [425], s = t.createGain(), o = t.currentTime;
|
|
1738
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);
|
|
@@ -1742,7 +1746,7 @@ class Ie {
|
|
|
1742
1746
|
}
|
|
1743
1747
|
}
|
|
1744
1748
|
}
|
|
1745
|
-
class
|
|
1749
|
+
class Pe extends EventTarget {
|
|
1746
1750
|
options;
|
|
1747
1751
|
socket = null;
|
|
1748
1752
|
stopped = !1;
|
|
@@ -1762,6 +1766,7 @@ class Ee extends EventTarget {
|
|
|
1762
1766
|
mediaClients = /* @__PURE__ */ new Map();
|
|
1763
1767
|
activeCallIds = /* @__PURE__ */ new Set();
|
|
1764
1768
|
seenInvitationIds = /* @__PURE__ */ new Set();
|
|
1769
|
+
invitationExpiryTimers = /* @__PURE__ */ new Map();
|
|
1765
1770
|
startCallRequest = null;
|
|
1766
1771
|
lastDisconnect = null;
|
|
1767
1772
|
constructor(e) {
|
|
@@ -1769,14 +1774,14 @@ class Ee extends EventTarget {
|
|
|
1769
1774
|
if (e.token && !e.token.startsWith("rtcc_")) throw new Error("A valid RTC client token is required");
|
|
1770
1775
|
if (!e.signalingUrl && !e.callActionsUrl && !e.apiBaseUrl && !globalThis.location?.origin)
|
|
1771
1776
|
throw new Error("signalingUrl or callActionsUrl is required outside a browser");
|
|
1772
|
-
this.options = e, this.currentToken = e.token ?? null, this.currentTokenExpiresAt = e.tokenExpiresAt, this.callAudio = new
|
|
1777
|
+
this.options = e, this.currentToken = e.token ?? null, this.currentTokenExpiresAt = e.tokenExpiresAt, this.callAudio = new Me(e), this.mount = ne(e.mount), this.scheduleTokenRefresh();
|
|
1773
1778
|
}
|
|
1774
1779
|
connect() {
|
|
1775
1780
|
if (!this.options.signalingUrl) throw new Error("signalingUrl is required to connect signaling");
|
|
1776
1781
|
return this.stopped = !1, this.scheduleTokenRefresh(), this.openSocket("initial"), this;
|
|
1777
1782
|
}
|
|
1778
1783
|
setMount(e) {
|
|
1779
|
-
this.clearUi(), this.mount =
|
|
1784
|
+
this.clearUi(), this.mount = ne(e), this.currentCall && this.renderIncoming(this.currentCall);
|
|
1780
1785
|
}
|
|
1781
1786
|
/** Binds media lifetime to a call. Terminal call states automatically leave and destroy it. */
|
|
1782
1787
|
attachMediaClient(e, t) {
|
|
@@ -1819,7 +1824,7 @@ class Ee extends EventTarget {
|
|
|
1819
1824
|
async accept(e = this.currentCall?.id) {
|
|
1820
1825
|
if (!e) throw new Error("No incoming call is available");
|
|
1821
1826
|
const t = await this.callAction(e, "accept");
|
|
1822
|
-
return this.activeCallIds.add(e), this.callAudio.stop(), this.dismiss(e), this.emit("callaccepted", t), t;
|
|
1827
|
+
return this.activeCallIds.add(e), this.clearInvitationExpiry(e), this.callAudio.stop(), this.dismiss(e), this.emit("callaccepted", t), t;
|
|
1823
1828
|
}
|
|
1824
1829
|
async reject(e = this.currentCall?.id) {
|
|
1825
1830
|
if (!e) throw new Error("No incoming call is available");
|
|
@@ -1857,15 +1862,42 @@ class Ee extends EventTarget {
|
|
|
1857
1862
|
this.emit("callrestored", e);
|
|
1858
1863
|
return;
|
|
1859
1864
|
}
|
|
1860
|
-
this.seenInvitationIds.add(e.id), this.activeCallIds.add(e.id), this.currentCall = e, this.callAudio.startIncoming(), this.renderIncoming(e), this.emit("incomingcall", e);
|
|
1865
|
+
this.seenInvitationIds.add(e.id), this.activeCallIds.add(e.id), this.scheduleInvitationExpiry(e.id, e.expiresAt), this.currentCall = e, this.callAudio.startIncoming(), this.renderIncoming(e), this.emit("incomingcall", e);
|
|
1866
|
+
}
|
|
1867
|
+
/**
|
|
1868
|
+
* B20 (PingSafe): a recipient who correctly does NOTHING with an invitation
|
|
1869
|
+
* must not lose the ability to place calls for the life of the process. The
|
|
1870
|
+
* invitation self-releases shortly after its expiry unless it was accepted.
|
|
1871
|
+
*/
|
|
1872
|
+
scheduleInvitationExpiry(e, t) {
|
|
1873
|
+
const i = t ? Date.parse(t) : Date.now() + 45e3, n = Math.min(18e4, Math.max(5e3, (Number.isFinite(i) ? i : Date.now() + 45e3) - Date.now() + 1e4));
|
|
1874
|
+
this.clearInvitationExpiry(e), this.invitationExpiryTimers.set(e, setTimeout(() => {
|
|
1875
|
+
this.invitationExpiryTimers.delete(e), !(!this.activeCallIds.has(e) || this.mediaClients.has(e)) && (this.emit("callexpired", { id: e, expiresAt: t ?? null }), this.release(e));
|
|
1876
|
+
}, n));
|
|
1877
|
+
}
|
|
1878
|
+
clearInvitationExpiry(e) {
|
|
1879
|
+
const t = this.invitationExpiryTimers.get(e);
|
|
1880
|
+
t && clearTimeout(t), this.invitationExpiryTimers.delete(e);
|
|
1881
|
+
}
|
|
1882
|
+
/**
|
|
1883
|
+
* Locally forgets a call WITHOUT any server action (B20): clears it from the
|
|
1884
|
+
* active set, stops ringing UI if it is the current call, and tears down any
|
|
1885
|
+
* attached media client. For declining, use reject()/busy() — this is the
|
|
1886
|
+
* escape hatch for calls that ended in ways this device never heard about.
|
|
1887
|
+
*/
|
|
1888
|
+
release(e) {
|
|
1889
|
+
if (!e.trim()) throw new Error("callId is required");
|
|
1890
|
+
this.clearInvitationExpiry(e), this.currentCall?.id === e && (this.callAudio.stop(), this.dismiss(e)), this.outgoingCallId === e && (this.outgoingCallId = null), this.releaseMedia(e), this.emit("callreleased", { id: e });
|
|
1861
1891
|
}
|
|
1862
1892
|
/** Applies a call state received through the application's own push or signaling channel. */
|
|
1863
1893
|
handleCallUpdate(e) {
|
|
1864
|
-
const t = e.id === this.currentCall?.id || e.id === this.outgoingCallId;
|
|
1865
|
-
t && e.status === "accepted" ? (this.activeCallIds.add(e.id), this.callAudio.stop(), this.dismiss(e.id)) : t &&
|
|
1894
|
+
const t = e.id === this.currentCall?.id || e.id === this.outgoingCallId, i = ["answered_elsewhere", "rejected", "busy", "cancelled", "ended", "failed", "missed"];
|
|
1895
|
+
(e.status === "accepted" || i.includes(e.status)) && this.clearInvitationExpiry(e.id), t && e.status === "accepted" ? (this.activeCallIds.add(e.id), this.callAudio.stop(), this.dismiss(e.id)) : t && i.includes(e.status) && this.showTerminal(e.id, Ae(e.status)), i.includes(e.status) && this.releaseMedia(e.id), this.emit("callupdated", e);
|
|
1866
1896
|
}
|
|
1867
1897
|
disconnect() {
|
|
1868
1898
|
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();
|
|
1899
|
+
for (const e of this.invitationExpiryTimers.values()) clearTimeout(e);
|
|
1900
|
+
this.invitationExpiryTimers.clear();
|
|
1869
1901
|
for (const e of this.mediaClients.keys()) this.releaseMedia(e);
|
|
1870
1902
|
this.activeCallIds.clear(), this.seenInvitationIds.clear();
|
|
1871
1903
|
}
|
|
@@ -1878,13 +1910,11 @@ class Ee extends EventTarget {
|
|
|
1878
1910
|
try {
|
|
1879
1911
|
t = await this.resolveToken(e, e === "reconnect");
|
|
1880
1912
|
} catch (s) {
|
|
1881
|
-
this.emit("tokenerror",
|
|
1913
|
+
this.emit("tokenerror", j(s)), !this.stopped && this.options.reconnect !== !1 && this.scheduleReconnect();
|
|
1882
1914
|
return;
|
|
1883
1915
|
}
|
|
1884
1916
|
if (this.stopped || this.socket) return;
|
|
1885
|
-
const i =
|
|
1886
|
-
i.protocol = i.protocol === "https:" ? "wss:" : "ws:";
|
|
1887
|
-
const n = new WebSocket(i, ["rtc-client", t]);
|
|
1917
|
+
const i = $(this.options.signalingUrl, globalThis.location?.href), n = new WebSocket(i, ["rtc-client", t]);
|
|
1888
1918
|
this.socket = n, n.addEventListener("open", () => {
|
|
1889
1919
|
const s = this.reconnectAttempt > 0, o = this.lastDisconnect;
|
|
1890
1920
|
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(() => {
|
|
@@ -1942,7 +1972,7 @@ class Ee extends EventTarget {
|
|
|
1942
1972
|
async request(e, t, i = !1) {
|
|
1943
1973
|
const n = this.options.callActionsUrl ?? this.options.apiBaseUrl ?? this.options.signalingUrl ?? globalThis.location?.origin;
|
|
1944
1974
|
if (!n) throw new Error("callActionsUrl is required for call actions");
|
|
1945
|
-
const s =
|
|
1975
|
+
const s = J(n, globalThis.location?.href), o = await this.resolveToken("initial"), r = new Headers(t.headers);
|
|
1946
1976
|
r.set("authorization", `Bearer ${o}`), r.set("content-type", "application/json");
|
|
1947
1977
|
const c = await fetch(new URL(e, s.origin), { ...t, headers: r }), l = await c.json().catch(() => ({}));
|
|
1948
1978
|
if (c.status === 401 && this.options.tokenProvider && !i)
|
|
@@ -1974,11 +2004,11 @@ class Ee extends EventTarget {
|
|
|
1974
2004
|
n.textContent = e.caller.name, n.style.fontSize = "20px";
|
|
1975
2005
|
const s = document.createElement("div");
|
|
1976
2006
|
Object.assign(s.style, { display: "grid", gridTemplateColumns: "1fr 1fr", gap: "10px" });
|
|
1977
|
-
const o =
|
|
2007
|
+
const o = ae("Decline", "#fff", "#a32920", "#d9a09b"), r = ae("Answer", "#fff", "#08745f", "#08745f");
|
|
1978
2008
|
o.addEventListener("click", () => {
|
|
1979
|
-
this.reject(e.id).catch((c) => this.emit("error",
|
|
2009
|
+
this.reject(e.id).catch((c) => this.emit("error", j(c)));
|
|
1980
2010
|
}), r.addEventListener("click", () => {
|
|
1981
|
-
this.accept(e.id).catch((c) => this.emit("error",
|
|
2011
|
+
this.accept(e.id).catch((c) => this.emit("error", j(c)));
|
|
1982
2012
|
}), s.appendChild(o), s.appendChild(r), t.appendChild(i), t.appendChild(n), t.appendChild(s), this.mount.replaceChildren(t);
|
|
1983
2013
|
}
|
|
1984
2014
|
dismiss(e) {
|
|
@@ -2046,7 +2076,7 @@ class Ee extends EventTarget {
|
|
|
2046
2076
|
const t = Math.max(0, e - this.refreshSkew(e));
|
|
2047
2077
|
this.tokenRefreshTimer = setTimeout(() => {
|
|
2048
2078
|
this.tokenRefreshTimer = null, this.resolveToken("expiring", !0).catch((i) => {
|
|
2049
|
-
this.emit("tokenerror",
|
|
2079
|
+
this.emit("tokenerror", j(i)), this.stopped || (this.tokenRefreshTimer = setTimeout(() => this.scheduleTokenRefresh(), 3e4));
|
|
2050
2080
|
});
|
|
2051
2081
|
}, Math.min(t, 2147e6));
|
|
2052
2082
|
}
|
|
@@ -2060,21 +2090,21 @@ class Ee extends EventTarget {
|
|
|
2060
2090
|
this.options.reportSignalingDiagnostics === !1 || this.stopped || this.request("/v1/rtc/client/signaling-events", {
|
|
2061
2091
|
method: "POST",
|
|
2062
2092
|
body: JSON.stringify({ ...e, occurredAt: (/* @__PURE__ */ new Date()).toISOString() })
|
|
2063
|
-
}).catch((t) => this.emit("diagnosticserror",
|
|
2093
|
+
}).catch((t) => this.emit("diagnosticserror", j(t)));
|
|
2064
2094
|
}
|
|
2065
2095
|
emit(e, t) {
|
|
2066
2096
|
const i = { type: e, detail: t, timestamp: (/* @__PURE__ */ new Date()).toISOString() };
|
|
2067
2097
|
this.dispatchEvent(new CustomEvent(e, { detail: i })), this.options.onEvent?.(i);
|
|
2068
2098
|
}
|
|
2069
2099
|
}
|
|
2070
|
-
function
|
|
2071
|
-
const e = new
|
|
2100
|
+
function Fe(a) {
|
|
2101
|
+
const e = new Pe(a);
|
|
2072
2102
|
return a.autoConnect !== !1 && a.signalingUrl && e.connect(), e;
|
|
2073
2103
|
}
|
|
2074
|
-
function
|
|
2104
|
+
function ne(a) {
|
|
2075
2105
|
return a ? typeof a == "string" ? document.querySelector(a) : a : null;
|
|
2076
2106
|
}
|
|
2077
|
-
function
|
|
2107
|
+
function ae(a, e, t, i) {
|
|
2078
2108
|
const n = document.createElement("button");
|
|
2079
2109
|
return n.type = "button", n.textContent = a, Object.assign(n.style, {
|
|
2080
2110
|
minHeight: "44px",
|
|
@@ -2087,42 +2117,43 @@ function ie(a, e, t, i) {
|
|
|
2087
2117
|
fontWeight: "700"
|
|
2088
2118
|
}), n;
|
|
2089
2119
|
}
|
|
2090
|
-
function
|
|
2120
|
+
function Ae(a) {
|
|
2091
2121
|
return {
|
|
2092
2122
|
rejected: "Call declined",
|
|
2093
2123
|
busy: "Line busy",
|
|
2094
2124
|
cancelled: "Call cancelled",
|
|
2095
2125
|
ended: "Call ended",
|
|
2096
2126
|
failed: "Call failed",
|
|
2097
|
-
missed: "No answer"
|
|
2127
|
+
missed: "No answer",
|
|
2128
|
+
answered_elsewhere: "Answered on another device"
|
|
2098
2129
|
}[a] ?? "Call ended";
|
|
2099
2130
|
}
|
|
2100
|
-
function
|
|
2131
|
+
function se(a) {
|
|
2101
2132
|
return {
|
|
2102
2133
|
id: a.participantId,
|
|
2103
2134
|
name: a.displayName,
|
|
2104
2135
|
role: "participant"
|
|
2105
2136
|
};
|
|
2106
2137
|
}
|
|
2107
|
-
async function
|
|
2138
|
+
async function Le(a, e) {
|
|
2108
2139
|
const t = await a.getStats(), i = /* @__PURE__ */ new Map(), n = /* @__PURE__ */ new Map();
|
|
2109
|
-
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,
|
|
2140
|
+
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, E = null, A = null, S = null, I = null;
|
|
2110
2141
|
t.forEach((g) => {
|
|
2111
2142
|
n.set(g.id, g), g.type === "codec" && i.set(g.id, String(g.mimeType ?? ""));
|
|
2112
2143
|
}), t.forEach((g) => {
|
|
2113
|
-
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),
|
|
2144
|
+
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), I ||= g.qualityLimitationReason ? String(g.qualityLimitationReason) : null, S ||= i.get(String(g.codecId ?? "")) ?? null), g.type === "candidate-pair" && (g.selected || g.nominated) && g.state === "succeeded") {
|
|
2114
2145
|
P = Number.isFinite(g.currentRoundTripTime) ? Number(g.currentRoundTripTime) : P, L = Number.isFinite(g.availableOutgoingBitrate) ? Number(g.availableOutgoingBitrate) : L;
|
|
2115
2146
|
const q = n.get(g.localCandidateId);
|
|
2116
|
-
|
|
2147
|
+
E = q?.candidateType ? String(q.candidateType) : E, A = q?.protocol ? String(q.protocol) : A;
|
|
2117
2148
|
}
|
|
2118
2149
|
});
|
|
2119
|
-
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,
|
|
2150
|
+
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, x = e ? Math.max(0, r - e.packetsLost) : r, V = e ? Math.max(0, c - e.packetsReceived) : c, N = x + V;
|
|
2120
2151
|
return {
|
|
2121
2152
|
counters: { timestamp: m, inboundBytes: s, outboundBytes: o, packetsLost: r, packetsReceived: c },
|
|
2122
2153
|
sample: {
|
|
2123
2154
|
rttMs: P === null ? null : P * 1e3,
|
|
2124
2155
|
jitterMs: d ? l / d * 1e3 : null,
|
|
2125
|
-
packetLossPct: N ?
|
|
2156
|
+
packetLossPct: N ? x / N * 100 : null,
|
|
2126
2157
|
packetLossCumulativePct: b ? r / b * 100 : null,
|
|
2127
2158
|
packetsLost: r,
|
|
2128
2159
|
packetsReceived: c,
|
|
@@ -2142,22 +2173,22 @@ async function Pe(a, e) {
|
|
|
2142
2173
|
concealedSamples: R,
|
|
2143
2174
|
codec: S,
|
|
2144
2175
|
transportProtocol: A,
|
|
2145
|
-
candidateType:
|
|
2146
|
-
qualityLimitationReason:
|
|
2176
|
+
candidateType: E,
|
|
2177
|
+
qualityLimitationReason: I
|
|
2147
2178
|
}
|
|
2148
2179
|
};
|
|
2149
2180
|
}
|
|
2150
|
-
function
|
|
2151
|
-
let e = a.mediaScore == null ? 5 : Math.round(
|
|
2181
|
+
function De(a) {
|
|
2182
|
+
let e = a.mediaScore == null ? 5 : Math.round(oe(Number(a.mediaScore), 0, 5));
|
|
2152
2183
|
const t = W(a.packetLossPct) ?? 0, i = W(a.rttMs) ?? 0, n = W(a.jitterMs) ?? 0, s = String(a.connectionState ?? "unknown").toLowerCase();
|
|
2153
2184
|
["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));
|
|
2154
|
-
const o = Number(
|
|
2185
|
+
const o = Number(oe(4.5 - t * 0.09 - i * 11e-4 - n * 6e-3, 1, 4.5).toFixed(2));
|
|
2155
2186
|
return { networkScore: e, estimatedMos: o };
|
|
2156
2187
|
}
|
|
2157
|
-
function
|
|
2188
|
+
function re() {
|
|
2158
2189
|
return navigator.connection ?? null;
|
|
2159
2190
|
}
|
|
2160
|
-
function
|
|
2191
|
+
function qe() {
|
|
2161
2192
|
const a = Number(navigator.deviceMemory);
|
|
2162
2193
|
return Number.isFinite(a) ? a : null;
|
|
2163
2194
|
}
|
|
@@ -2165,38 +2196,38 @@ function W(a) {
|
|
|
2165
2196
|
const e = Number(a);
|
|
2166
2197
|
return Number.isFinite(e) ? e : null;
|
|
2167
2198
|
}
|
|
2168
|
-
function
|
|
2199
|
+
function oe(a, e, t) {
|
|
2169
2200
|
return Math.min(t, Math.max(e, a));
|
|
2170
2201
|
}
|
|
2171
|
-
function
|
|
2202
|
+
function j(a) {
|
|
2172
2203
|
return a instanceof Error ? { name: a.name, message: a.message } : { name: "ServiceError", message: String(a ?? "Service request failed") };
|
|
2173
2204
|
}
|
|
2174
|
-
function
|
|
2205
|
+
function ce(a, e) {
|
|
2175
2206
|
return a instanceof Error ? a : new Error(e);
|
|
2176
2207
|
}
|
|
2177
|
-
const
|
|
2208
|
+
const xe = "1.3.23";
|
|
2178
2209
|
export {
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2210
|
+
te as AVATAR_TUNING_DEFAULTS,
|
|
2211
|
+
we as BACKGROUND_PRESETS,
|
|
2212
|
+
Te as OVERLAY_EFFECTS,
|
|
2213
|
+
Ee as RtcClient,
|
|
2214
|
+
Pe as RtcIncomingClient,
|
|
2215
|
+
Ne as SPEAKER_NOISE_FLOOR,
|
|
2185
2216
|
Oe as SPEAKER_TAKEOVER_RATIO,
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2217
|
+
Qe as createAvatarPipeline,
|
|
2218
|
+
Ve as createCallRecorder,
|
|
2219
|
+
je as createPictureInPictureController,
|
|
2220
|
+
Be as createRtcClient,
|
|
2221
|
+
Fe as createRtcIncomingClient,
|
|
2222
|
+
Ue as createVideoEffectsPipeline,
|
|
2223
|
+
Re as drawAvatar,
|
|
2224
|
+
be as headPoseFromMatrix,
|
|
2225
|
+
he as neutralRig,
|
|
2226
|
+
le as pickActiveSpeaker,
|
|
2227
|
+
Ce as rigFromBlendshapes,
|
|
2228
|
+
Z as scenePainters,
|
|
2229
|
+
ee as smoothRig,
|
|
2230
|
+
ie as stylizedAvatarRenderer,
|
|
2231
|
+
Ie as unlockRtcCallAudio,
|
|
2232
|
+
xe as version
|
|
2202
2233
|
};
|