@streaming-cdn/rtc-web 1.3.24 → 1.3.26
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 +25 -1
- package/dist/avatar-library.d.ts +82 -0
- package/dist/avatar-vrm.d.ts +53 -0
- package/dist/index.d.ts +3 -1
- package/dist/peer-quality.d.ts +14 -2
- package/dist/rtc-web-avatar-vrm.es.js +68 -0
- package/dist/rtc-web-avatar-vrm.umd.js +1 -0
- package/dist/rtc-web.es.js +541 -312
- package/dist/rtc-web.umd.js +1 -1
- package/dist/zip-reader.d.ts +31 -0
- package/package.json +19 -2
package/dist/rtc-web.es.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
const
|
|
2
|
-
function
|
|
1
|
+
const at = 0.02, st = 1.4;
|
|
2
|
+
function ge(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 ye(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 de(a) {
|
|
|
14
14
|
}
|
|
15
15
|
return e;
|
|
16
16
|
}
|
|
17
|
-
const
|
|
17
|
+
const V = {
|
|
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
|
+
}, Re = {
|
|
23
23
|
warmupSamples: 3,
|
|
24
24
|
poorSamplesToStepDown: 2,
|
|
25
25
|
goodSamplesToStepUp: 6,
|
|
@@ -30,31 +30,31 @@ const O = {
|
|
|
30
30
|
goodLossPct: 1,
|
|
31
31
|
goodRttMs: 250,
|
|
32
32
|
sustainRatio: 0.8,
|
|
33
|
-
|
|
33
|
+
bandwidthSustainRatio: 0.7
|
|
34
34
|
};
|
|
35
|
-
function
|
|
35
|
+
function Ie(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 ?
|
|
39
|
+
function Pe(a, e, t, i, n = {}) {
|
|
40
|
+
const s = { ...Re, ...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, v = Ie(e.qualityLimitationReason), p = e.packetLossPct ?? 0, S = e.rttMs ?? 0, T = e.availableOutgoingBitrateBps, y = V[a].maxBitrate, k = p >= s.criticalLossPct || S >= s.criticalRttMs || v === "cpu", f = v === "bandwidth" && (T == null || T < y * s.bandwidthSustainRatio), M = k || p >= s.poorLossPct || S >= s.poorRttMs || f, R = l < o.length - 1 ? V[o[l + 1]].maxBitrate : null, L = v === "bandwidth" && T != null && R != null && T >= R * s.bandwidthSustainRatio, P = T == null || T >= y * s.sustainRatio, A = p < s.goodLossPct && S < s.goodRttMs && (!v || L) && P, w = M ? t + 1 : 0, E = A ? i + 1 : 0, m = { quality: a, poorSamples: w, goodSamples: E, samplesSeen: d, changed: !1 };
|
|
41
|
+
return l > c ? { quality: o[c], poorSamples: 0, goodSamples: 0, samplesSeen: d, changed: !0 } : u ? m : k && l > 0 ? { quality: o[l - 1], poorSamples: 0, goodSamples: 0, samplesSeen: d, changed: !0 } : w >= s.poorSamplesToStepDown && l > 0 ? { quality: o[l - 1], poorSamples: 0, goodSamples: 0, samplesSeen: d, changed: !0 } : E >= s.goodSamplesToStepUp && l < c ? { quality: o[l + 1], poorSamples: 0, goodSamples: 0, samplesSeen: d, changed: !0 } : m;
|
|
42
42
|
}
|
|
43
|
-
function
|
|
43
|
+
function Ae(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()) {
|
|
47
47
|
const u = String(d.type ?? "");
|
|
48
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") {
|
|
49
49
|
n += Number(d.packetsLost ?? 0);
|
|
50
|
-
const
|
|
51
|
-
Number.isFinite(
|
|
50
|
+
const v = Number(d.roundTripTime ?? NaN);
|
|
51
|
+
Number.isFinite(v) && (o = v * 1e3);
|
|
52
52
|
}
|
|
53
53
|
if (u === "candidate-pair" && (d.nominated === !0 || String(d.state ?? "") === "succeeded")) {
|
|
54
|
-
const
|
|
55
|
-
o == null && Number.isFinite(
|
|
56
|
-
const
|
|
57
|
-
Number.isFinite(
|
|
54
|
+
const v = Number(d.currentRoundTripTime ?? NaN);
|
|
55
|
+
o == null && Number.isFinite(v) && (o = v * 1e3);
|
|
56
|
+
const p = Number(d.availableOutgoingBitrate ?? NaN);
|
|
57
|
+
Number.isFinite(p) && (r = p);
|
|
58
58
|
}
|
|
59
59
|
}
|
|
60
60
|
const c = { packetsSent: i, packetsLost: n, timestamp: Date.now() };
|
|
@@ -68,18 +68,18 @@ function ge(a, e) {
|
|
|
68
68
|
counters: c
|
|
69
69
|
};
|
|
70
70
|
}
|
|
71
|
-
function
|
|
71
|
+
function X(a, e) {
|
|
72
72
|
const t = new URL(String(a), e);
|
|
73
73
|
return t.protocol === "https:" ? t.protocol = "wss:" : t.protocol === "http:" && (t.protocol = "ws:"), t;
|
|
74
74
|
}
|
|
75
|
-
function
|
|
75
|
+
function Z(a, e) {
|
|
76
76
|
const t = new URL(String(a), e);
|
|
77
77
|
return t.protocol === "wss:" ? t.protocol = "https:" : t.protocol === "ws:" && (t.protocol = "http:"), t;
|
|
78
78
|
}
|
|
79
|
-
const
|
|
79
|
+
const Le = {
|
|
80
80
|
audio: { active: !1, maxBitrate: 0, maxFramerate: 0, scaleResolutionDownBy: 4 }
|
|
81
|
-
},
|
|
82
|
-
class
|
|
81
|
+
}, De = { active: !0, maxBitrate: 4e6, maxFramerate: 30, scaleResolutionDownBy: 1 };
|
|
82
|
+
class F {
|
|
83
83
|
options;
|
|
84
84
|
socket = null;
|
|
85
85
|
localStream = null;
|
|
@@ -177,7 +177,7 @@ class Q {
|
|
|
177
177
|
this.quality = e;
|
|
178
178
|
for (const t of this.localStream?.getVideoTracks() ?? []) t.enabled = e !== "audio";
|
|
179
179
|
for (const t of this.peers.values())
|
|
180
|
-
t.quality =
|
|
180
|
+
t.quality = F.clampToCeiling(t.quality, e), t.poorSamples = 0, t.goodSamples = 0;
|
|
181
181
|
await this.applyVideoQuality();
|
|
182
182
|
}
|
|
183
183
|
static clampToCeiling(e, t) {
|
|
@@ -221,7 +221,7 @@ class Q {
|
|
|
221
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);
|
|
222
222
|
}
|
|
223
223
|
async openSocket(e) {
|
|
224
|
-
const { credential: t } = this.options, i =
|
|
224
|
+
const { credential: t } = this.options, i = X(t.signalingUrl, globalThis.location?.href), n = new Promise((c, l) => {
|
|
225
225
|
this.resolveJoin = c, this.rejectJoin = l;
|
|
226
226
|
}), s = new WebSocket(i, ["rtc-client", t.signalingToken]), o = ++this.socketGeneration;
|
|
227
227
|
this.socket = s;
|
|
@@ -320,7 +320,7 @@ class Q {
|
|
|
320
320
|
makingOffer: !1,
|
|
321
321
|
offerTask: null,
|
|
322
322
|
activeNegotiationId: null,
|
|
323
|
-
quality:
|
|
323
|
+
quality: F.startingQuality(this.quality),
|
|
324
324
|
poorSamples: 0,
|
|
325
325
|
goodSamples: 0,
|
|
326
326
|
samplesSeen: 0,
|
|
@@ -358,7 +358,7 @@ class Q {
|
|
|
358
358
|
});
|
|
359
359
|
if (e.connection.signalingState !== "stable") return;
|
|
360
360
|
await e.connection.setLocalDescription(t);
|
|
361
|
-
const i =
|
|
361
|
+
const i = ie();
|
|
362
362
|
e.activeNegotiationId = i, this.send({
|
|
363
363
|
type: "rtc.offer",
|
|
364
364
|
targetParticipantId: e.identity.participantId,
|
|
@@ -398,7 +398,7 @@ class Q {
|
|
|
398
398
|
async applyPeerVideoQuality(e) {
|
|
399
399
|
const t = this.screenStream?.getVideoTracks()[0]?.id;
|
|
400
400
|
for (const i of e.connection.getSenders().filter((n) => n.track?.kind === "video")) {
|
|
401
|
-
const n = !!(t && i.track?.id === t), s = n ?
|
|
401
|
+
const n = !!(t && i.track?.id === t), s = n ? De : this.quality === "audio" ? Le.audio : V[e.quality], o = i.getParameters(), r = o.encodings?.length ? o.encodings : [{}];
|
|
402
402
|
o.encodings = r.map((c) => ({ ...c, ...s })), o.degradationPreference = n ? "maintain-resolution" : "maintain-framerate", await i.setParameters(o);
|
|
403
403
|
}
|
|
404
404
|
}
|
|
@@ -418,11 +418,11 @@ class Q {
|
|
|
418
418
|
if (i.connection.connectionState === "connected")
|
|
419
419
|
try {
|
|
420
420
|
const n = await i.connection.getStats();
|
|
421
|
-
for (const s of
|
|
421
|
+
for (const s of ye(n.values()))
|
|
422
422
|
e.push({ participantId: i.identity.participantId, level: s.level });
|
|
423
423
|
} catch {
|
|
424
424
|
}
|
|
425
|
-
const t =
|
|
425
|
+
const t = ge(e, this.activeSpeaker);
|
|
426
426
|
t !== this.activeSpeaker && (this.activeSpeaker = t, this.options.onEvent("activespeaker", { participantId: t }));
|
|
427
427
|
}
|
|
428
428
|
async samplePeerQuality() {
|
|
@@ -435,9 +435,9 @@ class Q {
|
|
|
435
435
|
} catch {
|
|
436
436
|
continue;
|
|
437
437
|
}
|
|
438
|
-
const { sample: i, counters: n } =
|
|
438
|
+
const { sample: i, counters: n } = Ae(t, e.counters);
|
|
439
439
|
e.counters = n;
|
|
440
|
-
const s =
|
|
440
|
+
const s = Pe(e.quality, i, e.poorSamples, e.goodSamples, {
|
|
441
441
|
samplesSeen: e.samplesSeen,
|
|
442
442
|
ceiling: this.quality
|
|
443
443
|
});
|
|
@@ -494,7 +494,7 @@ class Q {
|
|
|
494
494
|
}
|
|
495
495
|
send(e) {
|
|
496
496
|
this.socket?.readyState === WebSocket.OPEN && this.socket.send(JSON.stringify({
|
|
497
|
-
clientMessageId: e.clientMessageId ??
|
|
497
|
+
clientMessageId: e.clientMessageId ?? ie(),
|
|
498
498
|
...e
|
|
499
499
|
}));
|
|
500
500
|
}
|
|
@@ -502,15 +502,15 @@ class Q {
|
|
|
502
502
|
for (const t of e?.getTracks() ?? []) t.stop();
|
|
503
503
|
}
|
|
504
504
|
}
|
|
505
|
-
function
|
|
505
|
+
function ie() {
|
|
506
506
|
return globalThis.crypto?.randomUUID?.() ?? `${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`;
|
|
507
507
|
}
|
|
508
|
-
const
|
|
509
|
-
{ rid: "a", maxBitrate:
|
|
510
|
-
{ rid: "b", maxBitrate:
|
|
511
|
-
{ rid: "c", maxBitrate:
|
|
512
|
-
],
|
|
513
|
-
class
|
|
508
|
+
const J = { active: !0, maxBitrate: 4e6, maxFramerate: 30, scaleResolutionDownBy: 1 }, ne = [
|
|
509
|
+
{ rid: "a", maxBitrate: V.high.maxBitrate, maxFramerate: V.high.maxFramerate },
|
|
510
|
+
{ rid: "b", maxBitrate: V.medium.maxBitrate, maxFramerate: V.medium.maxFramerate, scaleResolutionDownBy: 2 },
|
|
511
|
+
{ rid: "c", maxBitrate: V.low.maxBitrate, maxFramerate: V.low.maxFramerate, scaleResolutionDownBy: 4 }
|
|
512
|
+
], ae = { high: "a", medium: "b", low: "c" };
|
|
513
|
+
class xe {
|
|
514
514
|
options;
|
|
515
515
|
apiBase;
|
|
516
516
|
socket = null;
|
|
@@ -542,7 +542,7 @@ class Se {
|
|
|
542
542
|
negotiationQueue = Promise.resolve();
|
|
543
543
|
socketGeneration = 0;
|
|
544
544
|
constructor(e) {
|
|
545
|
-
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 = Z(e.credential.signalingUrl, globalThis.location?.href).origin;
|
|
546
546
|
}
|
|
547
547
|
async initialize() {
|
|
548
548
|
if (!globalThis.RTCPeerConnection || !globalThis.WebSocket)
|
|
@@ -643,7 +643,7 @@ class Se {
|
|
|
643
643
|
}
|
|
644
644
|
// --- signaling -----------------------------------------------------------
|
|
645
645
|
async openSocket(e) {
|
|
646
|
-
const { credential: t } = this.options, i =
|
|
646
|
+
const { credential: t } = this.options, i = X(t.signalingUrl, globalThis.location?.href), n = new Promise((c, l) => {
|
|
647
647
|
this.resolveJoin = c, this.rejectJoin = l;
|
|
648
648
|
}), s = new WebSocket(i, ["rtc-client", t.signalingToken]), o = ++this.socketGeneration;
|
|
649
649
|
this.socket = s;
|
|
@@ -726,7 +726,7 @@ class Se {
|
|
|
726
726
|
// A single encoding when simulcast is off: constrained publishers
|
|
727
727
|
// (phone CPU, cellular uplink) should not pay for three encoders. The
|
|
728
728
|
// quality ladder then adapts that one encoding instead of gating layers.
|
|
729
|
-
...r.kind === "video" && this.simulcastEnabled() ? { sendEncodings:
|
|
729
|
+
...r.kind === "video" && this.simulcastEnabled() ? { sendEncodings: ne.map((c) => ({ ...c })) } : {}
|
|
730
730
|
})), s = await t.createOffer();
|
|
731
731
|
await t.setLocalDescription(s);
|
|
732
732
|
const o = await this.sfuFetch(
|
|
@@ -826,7 +826,7 @@ class Se {
|
|
|
826
826
|
n && await this.sfuFetch("PUT", `/v1/rtc/sfu/sessions/${encodeURIComponent(this.sessionId)}/tracks/update`, {
|
|
827
827
|
tracks: [{
|
|
828
828
|
mid: n,
|
|
829
|
-
simulcast: { preferredRid:
|
|
829
|
+
simulcast: { preferredRid: ae[t], priorityOrdering: "asciibetical", ridNotAvailable: "asciibetical" }
|
|
830
830
|
}]
|
|
831
831
|
});
|
|
832
832
|
}
|
|
@@ -841,15 +841,15 @@ class Se {
|
|
|
841
841
|
if (!e) return;
|
|
842
842
|
const t = this.screenStream?.getVideoTracks()[0]?.id, i = !!(t && e.track?.id === t), n = e.getParameters(), s = n.encodings?.length ? n.encodings : [{}];
|
|
843
843
|
if (s.length > 1) {
|
|
844
|
-
const o = this.quality === "audio" ? null :
|
|
844
|
+
const o = this.quality === "audio" ? null : ae[this.quality];
|
|
845
845
|
n.encodings = s.map((r) => {
|
|
846
846
|
if (i)
|
|
847
|
-
return { ...r, active: r.rid === "a", ...r.rid === "a" ? { maxBitrate:
|
|
848
|
-
const c =
|
|
847
|
+
return { ...r, active: r.rid === "a", ...r.rid === "a" ? { maxBitrate: J.maxBitrate, maxFramerate: J.maxFramerate } : {} };
|
|
848
|
+
const c = ne.find((d) => d.rid === r.rid), l = o != null && String(r.rid ?? "") >= o;
|
|
849
849
|
return { ...r, ...c ?? {}, active: l };
|
|
850
850
|
});
|
|
851
851
|
} else {
|
|
852
|
-
const o = this.quality === "audio" ?
|
|
852
|
+
const o = this.quality === "audio" ? V.audio : V[this.quality], r = i ? J : o;
|
|
853
853
|
n.encodings = s.map((c) => ({ ...c, ...r }));
|
|
854
854
|
}
|
|
855
855
|
n.degradationPreference = i ? "maintain-resolution" : "maintain-framerate", await e.setParameters(n);
|
|
@@ -916,11 +916,11 @@ class Se {
|
|
|
916
916
|
return;
|
|
917
917
|
}
|
|
918
918
|
const i = [];
|
|
919
|
-
for (const s of
|
|
919
|
+
for (const s of ye(t.values())) {
|
|
920
920
|
const o = s.mid ? this.midToParticipant.get(s.mid) : void 0;
|
|
921
921
|
o && i.push({ participantId: o, level: s.level });
|
|
922
922
|
}
|
|
923
|
-
const n =
|
|
923
|
+
const n = ge(i, this.activeSpeaker);
|
|
924
924
|
n !== this.activeSpeaker && (this.activeSpeaker = n, this.options.onEvent("activespeaker", { participantId: n }));
|
|
925
925
|
}
|
|
926
926
|
clearTimers() {
|
|
@@ -937,7 +937,7 @@ class Se {
|
|
|
937
937
|
}
|
|
938
938
|
send(e) {
|
|
939
939
|
this.socket?.readyState === WebSocket.OPEN && this.socket.send(JSON.stringify({
|
|
940
|
-
clientMessageId: e.clientMessageId ??
|
|
940
|
+
clientMessageId: e.clientMessageId ?? Ue(),
|
|
941
941
|
...e
|
|
942
942
|
}));
|
|
943
943
|
}
|
|
@@ -945,10 +945,10 @@ class Se {
|
|
|
945
945
|
for (const t of e?.getTracks() ?? []) t.stop();
|
|
946
946
|
}
|
|
947
947
|
}
|
|
948
|
-
function
|
|
948
|
+
function Ue() {
|
|
949
949
|
return globalThis.crypto?.randomUUID?.() ?? `${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`;
|
|
950
950
|
}
|
|
951
|
-
function
|
|
951
|
+
function rt(a, e = {}) {
|
|
952
952
|
const t = e.document ?? globalThis.document, i = !!(t && t.pictureInPictureEnabled);
|
|
953
953
|
let n = null;
|
|
954
954
|
function s() {
|
|
@@ -976,81 +976,81 @@ function je(a, e = {}) {
|
|
|
976
976
|
}
|
|
977
977
|
};
|
|
978
978
|
}
|
|
979
|
-
function
|
|
980
|
-
const t = e.document ?? globalThis.document, i = e.fetchImplementation ?? globalThis.fetch.bind(globalThis), n =
|
|
981
|
-
let c = null, l = null, d = null, u = null,
|
|
982
|
-
async function
|
|
983
|
-
const
|
|
979
|
+
function ot(a, e) {
|
|
980
|
+
const t = e.document ?? globalThis.document, i = e.fetchImplementation ?? globalThis.fetch.bind(globalThis), n = Z(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, v = 0, p = [], S = !1;
|
|
982
|
+
async function T(y, k, f, M = "application/json") {
|
|
983
|
+
const R = await i(`${n}${k}`, {
|
|
984
984
|
method: y,
|
|
985
985
|
headers: {
|
|
986
986
|
authorization: `Bearer ${e.credential.signalingToken}`,
|
|
987
|
-
"content-type":
|
|
987
|
+
"content-type": M
|
|
988
988
|
},
|
|
989
|
-
body:
|
|
989
|
+
body: f === void 0 ? void 0 : M === "application/json" ? JSON.stringify(f) : f
|
|
990
990
|
});
|
|
991
|
-
if (!
|
|
992
|
-
return
|
|
991
|
+
if (!R.ok) throw new Error(`Recording request failed with HTTP ${R.status}`);
|
|
992
|
+
return R.json();
|
|
993
993
|
}
|
|
994
994
|
return {
|
|
995
995
|
get recording() {
|
|
996
|
-
return
|
|
996
|
+
return S;
|
|
997
997
|
},
|
|
998
998
|
async start() {
|
|
999
|
-
if (
|
|
1000
|
-
u = (await
|
|
1001
|
-
const
|
|
1002
|
-
|
|
1003
|
-
const
|
|
1004
|
-
let
|
|
1005
|
-
return
|
|
1006
|
-
}),
|
|
999
|
+
if (S) return;
|
|
1000
|
+
u = (await T("POST", "/v1/rtc/recordings")).recordingId;
|
|
1001
|
+
const k = t.createElement("canvas");
|
|
1002
|
+
k.width = r, k.height = o;
|
|
1003
|
+
const f = k.getContext("2d"), M = /* @__PURE__ */ new Map(), R = (b, I) => {
|
|
1004
|
+
let C = M.get(b);
|
|
1005
|
+
return C || (C = t.createElement("video"), C.muted = !0, C.playsInline = !0, C.srcObject = I, C.play().catch(() => {
|
|
1006
|
+
}), M.set(b, C)), C;
|
|
1007
1007
|
};
|
|
1008
1008
|
l = setInterval(() => {
|
|
1009
|
-
const
|
|
1010
|
-
...
|
|
1011
|
-
...
|
|
1009
|
+
const b = a.getRemoteStreams(), I = a.getLocalStream(), C = [
|
|
1010
|
+
...b.map((U) => ({ key: U.participant.participantId, stream: U.stream, label: U.participant.displayName })),
|
|
1011
|
+
...I ? [{ key: "local", stream: I, label: "me" }] : []
|
|
1012
1012
|
];
|
|
1013
|
-
|
|
1014
|
-
const
|
|
1015
|
-
|
|
1016
|
-
const
|
|
1017
|
-
|
|
1013
|
+
f.fillStyle = "#101418", f.fillRect(0, 0, r, o);
|
|
1014
|
+
const N = Math.max(1, Math.ceil(Math.sqrt(C.length))), Q = Math.max(1, Math.ceil(C.length / N)), O = r / N, g = o / Q;
|
|
1015
|
+
C.forEach((U, ee) => {
|
|
1016
|
+
const te = R(U.key, U.stream), $ = ee % N * O, W = Math.floor(ee / N) * g;
|
|
1017
|
+
te.videoWidth > 0 && f.drawImage(te, $ + 2, W + 2, O - 4, g - 4), f.fillStyle = "rgba(0,0,0,.6)", f.fillRect($ + 8, W + g - 30, Math.min(O - 16, 12 + U.label.length * 9), 22), f.fillStyle = "#fff", f.font = "14px system-ui", f.fillText(U.label, $ + 14, W + g - 14);
|
|
1018
1018
|
});
|
|
1019
1019
|
}, 66);
|
|
1020
|
-
const L =
|
|
1020
|
+
const L = k.captureStream(15);
|
|
1021
1021
|
d = new AudioContext();
|
|
1022
|
-
const
|
|
1023
|
-
const
|
|
1024
|
-
...a.getRemoteStreams().map((
|
|
1022
|
+
const P = d.createMediaStreamDestination(), A = /* @__PURE__ */ new Set(), w = () => {
|
|
1023
|
+
const b = [
|
|
1024
|
+
...a.getRemoteStreams().map((I) => I.stream),
|
|
1025
1025
|
...a.getLocalStream() ? [a.getLocalStream()] : []
|
|
1026
1026
|
];
|
|
1027
|
-
for (const
|
|
1028
|
-
for (const
|
|
1029
|
-
A.has(
|
|
1027
|
+
for (const I of b)
|
|
1028
|
+
for (const C of I.getAudioTracks())
|
|
1029
|
+
A.has(C.id) || (A.add(C.id), d.createMediaStreamSource(new MediaStream([C])).connect(P));
|
|
1030
1030
|
};
|
|
1031
|
-
|
|
1032
|
-
const
|
|
1033
|
-
for (const
|
|
1034
|
-
c = (e.mediaRecorderFactory ?? ((
|
|
1035
|
-
|
|
1036
|
-
}), c.addEventListener("stop", m), c.start(1e3),
|
|
1031
|
+
w();
|
|
1032
|
+
const E = setInterval(w, 1e3), m = () => clearInterval(E);
|
|
1033
|
+
for (const b of P.stream.getAudioTracks()) L.addTrack(b);
|
|
1034
|
+
c = (e.mediaRecorderFactory ?? ((b, I) => new MediaRecorder(b, I)))(L, { mimeType: s }), p = [], c.addEventListener("dataavailable", (b) => {
|
|
1035
|
+
b.data && b.data.size > 0 && p.push(b.data);
|
|
1036
|
+
}), c.addEventListener("stop", m), c.start(1e3), v = Date.now(), S = !0;
|
|
1037
1037
|
},
|
|
1038
1038
|
async stop() {
|
|
1039
|
-
if (!
|
|
1040
|
-
|
|
1041
|
-
const y = c,
|
|
1042
|
-
y.stop(), await
|
|
1039
|
+
if (!S || !c || !u) throw new Error("The recorder is not running");
|
|
1040
|
+
S = !1;
|
|
1041
|
+
const y = c, k = new Promise((P) => y.addEventListener("stop", () => P(), { once: !0 }));
|
|
1042
|
+
y.stop(), await k, l && clearInterval(l), l = null, await d?.close().catch(() => {
|
|
1043
1043
|
}), d = null;
|
|
1044
|
-
const
|
|
1045
|
-
|
|
1046
|
-
const
|
|
1044
|
+
const f = new Blob(p, { type: s });
|
|
1045
|
+
p = [];
|
|
1046
|
+
const M = Math.max(1, Math.round((Date.now() - v) / 1e3)), R = await T(
|
|
1047
1047
|
"PUT",
|
|
1048
1048
|
`/v1/rtc/recordings/${encodeURIComponent(u)}/media`,
|
|
1049
|
-
|
|
1049
|
+
f,
|
|
1050
1050
|
s
|
|
1051
1051
|
);
|
|
1052
|
-
await
|
|
1053
|
-
const L = { recordingId: u, sizeBytes:
|
|
1052
|
+
await T("POST", `/v1/rtc/recordings/${encodeURIComponent(u)}/complete`, { durationSeconds: M });
|
|
1053
|
+
const L = { recordingId: u, sizeBytes: R.sizeBytes, durationSeconds: M };
|
|
1054
1054
|
return u = null, c = null, L;
|
|
1055
1055
|
},
|
|
1056
1056
|
dispose() {
|
|
@@ -1060,11 +1060,11 @@ function Ve(a, e) {
|
|
|
1060
1060
|
} catch {
|
|
1061
1061
|
}
|
|
1062
1062
|
c = null, d?.close().catch(() => {
|
|
1063
|
-
}), d = null,
|
|
1063
|
+
}), d = null, S = !1;
|
|
1064
1064
|
}
|
|
1065
1065
|
};
|
|
1066
1066
|
}
|
|
1067
|
-
const
|
|
1067
|
+
const Ne = ["none", "blur", "aurora", "cybergrid", "bokeh", "sunset", "image"], qe = ["none", "snow", "confetti", "vignette"], se = {
|
|
1068
1068
|
aurora(a, e, t, i) {
|
|
1069
1069
|
const n = a.createLinearGradient(0, 0, 0, t);
|
|
1070
1070
|
n.addColorStop(0, "#050b1e"), n.addColorStop(1, "#0b2540"), a.fillStyle = n, a.fillRect(0, 0, e, t);
|
|
@@ -1101,20 +1101,20 @@ const we = ["none", "blur", "aurora", "cybergrid", "bokeh", "sunset", "image"],
|
|
|
1101
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);
|
|
1102
1102
|
}
|
|
1103
1103
|
};
|
|
1104
|
-
function
|
|
1104
|
+
function ct(a, e = {}) {
|
|
1105
1105
|
const t = e.document ?? globalThis.document;
|
|
1106
1106
|
let i = e.width ?? 1280, n = e.height ?? 720;
|
|
1107
1107
|
const s = !!(e.width || e.height), o = e.frameRate ?? 24, r = a instanceof MediaStreamTrack ? a : a.getVideoTracks()[0];
|
|
1108
1108
|
if (!r) throw new Error("A video track is required");
|
|
1109
|
-
let c = e.background ?? "none", l = e.overlay ?? "none", d = e.backgroundImage ?? null, u = e.segmenter ?? null,
|
|
1110
|
-
const
|
|
1111
|
-
|
|
1109
|
+
let c = e.background ?? "none", l = e.overlay ?? "none", d = e.backgroundImage ?? null, u = e.segmenter ?? null, v = null, p = !1;
|
|
1110
|
+
const S = t.createElement("video");
|
|
1111
|
+
S.muted = !0, S.playsInline = !0, S.srcObject = new MediaStream([r]), S.play().catch(() => {
|
|
1112
1112
|
});
|
|
1113
|
-
const
|
|
1114
|
-
|
|
1115
|
-
const y =
|
|
1116
|
-
|
|
1117
|
-
const
|
|
1113
|
+
const T = t.createElement("canvas");
|
|
1114
|
+
T.width = i, T.height = n;
|
|
1115
|
+
const y = T.getContext("2d"), k = t.createElement("canvas");
|
|
1116
|
+
k.width = i, k.height = n;
|
|
1117
|
+
const f = k.getContext("2d"), M = () => Array.from({ length: 80 }, (m, h) => ({
|
|
1118
1118
|
x: (Math.sin(h * 12.9898) * 0.5 + 0.5) * i,
|
|
1119
1119
|
y: (Math.sin(h * 78.233) * 0.5 + 0.5) * n,
|
|
1120
1120
|
speed: 0.6 + h % 5 * 0.5,
|
|
@@ -1122,61 +1122,61 @@ function Ue(a, e = {}) {
|
|
|
1122
1122
|
size: 2 + h % 4,
|
|
1123
1123
|
hue: h * 47 % 360
|
|
1124
1124
|
}));
|
|
1125
|
-
let
|
|
1125
|
+
let R = M();
|
|
1126
1126
|
const L = () => {
|
|
1127
1127
|
if (s) return;
|
|
1128
|
-
const m =
|
|
1128
|
+
const m = S.videoWidth, h = S.videoHeight;
|
|
1129
1129
|
if (!m || !h) return;
|
|
1130
|
-
const
|
|
1131
|
-
|
|
1130
|
+
const b = Math.min(1, 1280 / Math.max(m, h)), I = Math.round(m * b), C = Math.round(h * b);
|
|
1131
|
+
I === i && C === n || (i = I, n = C, T.width = i, T.height = n, k.width = i, k.height = n, R = M());
|
|
1132
1132
|
};
|
|
1133
|
-
|
|
1134
|
-
function
|
|
1135
|
-
if (
|
|
1136
|
-
|
|
1133
|
+
S.addEventListener?.("loadedmetadata", L), S.addEventListener?.("resize", L);
|
|
1134
|
+
function P() {
|
|
1135
|
+
if (v) {
|
|
1136
|
+
f.clearRect(0, 0, i, n), f.drawImage(v, 0, 0, i, n), f.globalCompositeOperation = "source-in", f.drawImage(S, 0, 0, i, n), f.globalCompositeOperation = "source-over", y.drawImage(k, 0, 0);
|
|
1137
1137
|
return;
|
|
1138
1138
|
}
|
|
1139
|
-
const m = i * 0.42, h = m * 9 / 16,
|
|
1140
|
-
y.save(), y.shadowColor = "rgba(0,0,0,.5)", y.shadowBlur = 24, y.beginPath(), y.roundRect(
|
|
1139
|
+
const m = i * 0.42, h = m * 9 / 16, b = i - m - 24, I = n - h - 24;
|
|
1140
|
+
y.save(), y.shadowColor = "rgba(0,0,0,.5)", y.shadowBlur = 24, y.beginPath(), y.roundRect(b, I, m, h, 14), y.clip(), y.drawImage(S, b, I, m, h), y.restore();
|
|
1141
1141
|
}
|
|
1142
1142
|
function A(m) {
|
|
1143
|
-
if (c === "none" ? y.drawImage(
|
|
1144
|
-
for (const h of
|
|
1143
|
+
if (c === "none" ? y.drawImage(S, 0, 0, i, n) : c === "blur" ? (y.filter = "blur(14px)", y.drawImage(S, -16, -16, i + 32, n + 32), y.filter = "none", v && P()) : c === "image" && d ? (y.drawImage(d, 0, 0, i, n), P()) : ((se[c] ?? se.aurora)(y, i, n, m), P()), l === "snow" || l === "confetti")
|
|
1144
|
+
for (const h of R)
|
|
1145
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());
|
|
1146
1146
|
else if (l === "vignette") {
|
|
1147
1147
|
const h = y.createRadialGradient(i / 2, n / 2, n * 0.4, i / 2, n / 2, n * 0.85);
|
|
1148
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);
|
|
1149
1149
|
}
|
|
1150
1150
|
}
|
|
1151
|
-
const
|
|
1152
|
-
A(Date.now()), u && !
|
|
1153
|
-
|
|
1151
|
+
const w = setInterval(() => {
|
|
1152
|
+
A(Date.now()), u && !p && c !== "none" && (p = !0, u.segment(S).then((m) => {
|
|
1153
|
+
v = m;
|
|
1154
1154
|
}).catch(() => {
|
|
1155
|
-
|
|
1155
|
+
v = null;
|
|
1156
1156
|
}).finally(() => {
|
|
1157
|
-
|
|
1157
|
+
p = !1;
|
|
1158
1158
|
}));
|
|
1159
|
-
}, Math.round(1e3 / o)),
|
|
1159
|
+
}, Math.round(1e3 / o)), E = T.captureStream(o);
|
|
1160
1160
|
return {
|
|
1161
|
-
track:
|
|
1162
|
-
stream:
|
|
1161
|
+
track: E.getVideoTracks()[0],
|
|
1162
|
+
stream: E,
|
|
1163
1163
|
setBackground(m, h) {
|
|
1164
|
-
c =
|
|
1164
|
+
c = Ne.includes(m) ? m : "none", h !== void 0 && (d = h), c === "none" && (v = null);
|
|
1165
1165
|
},
|
|
1166
1166
|
setOverlay(m) {
|
|
1167
|
-
l =
|
|
1167
|
+
l = qe.includes(m) ? m : "none";
|
|
1168
1168
|
},
|
|
1169
1169
|
setSegmenter(m) {
|
|
1170
|
-
u = m, m || (
|
|
1170
|
+
u = m, m || (v = null);
|
|
1171
1171
|
},
|
|
1172
1172
|
dispose() {
|
|
1173
|
-
clearInterval(
|
|
1174
|
-
for (const m of
|
|
1175
|
-
|
|
1173
|
+
clearInterval(w), u?.close?.();
|
|
1174
|
+
for (const m of E.getTracks()) m.stop();
|
|
1175
|
+
S.srcObject = null;
|
|
1176
1176
|
}
|
|
1177
1177
|
};
|
|
1178
1178
|
}
|
|
1179
|
-
function
|
|
1179
|
+
function ve() {
|
|
1180
1180
|
return {
|
|
1181
1181
|
blinkLeft: 0,
|
|
1182
1182
|
blinkRight: 0,
|
|
@@ -1195,18 +1195,18 @@ function D(a, e) {
|
|
|
1195
1195
|
const t = a.find((i) => i.categoryName === e);
|
|
1196
1196
|
return t ? Math.max(0, Math.min(1, t.score)) : 0;
|
|
1197
1197
|
}
|
|
1198
|
-
function
|
|
1198
|
+
function Oe(a) {
|
|
1199
1199
|
if (!a || a.length < 16) return { yaw: 0, pitch: 0, roll: 0 };
|
|
1200
1200
|
a[0], a[4];
|
|
1201
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);
|
|
1202
1202
|
return { yaw: o, pitch: r, roll: c };
|
|
1203
1203
|
}
|
|
1204
|
-
function
|
|
1205
|
-
if (!a || a.length === 0) return
|
|
1206
|
-
const i =
|
|
1204
|
+
function Ve(a, e, t = 1) {
|
|
1205
|
+
if (!a || a.length === 0) return ve();
|
|
1206
|
+
const i = Oe(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"), v = Math.min(1, Math.abs(i.yaw) / 0.35) * Math.max(0, Math.min(1, t)), p = (d + u) / 2;
|
|
1207
1207
|
return {
|
|
1208
|
-
blinkLeft: d + (
|
|
1209
|
-
blinkRight: u + (
|
|
1208
|
+
blinkLeft: d + (p - d) * v,
|
|
1209
|
+
blinkRight: u + (p - u) * v,
|
|
1210
1210
|
jawOpen: D(a, "jawOpen"),
|
|
1211
1211
|
smile: c - l,
|
|
1212
1212
|
browUp: (D(a, "browInnerUp") + D(a, "browOuterUpLeft") + D(a, "browOuterUpRight")) / 3,
|
|
@@ -1218,7 +1218,7 @@ function Ce(a, e, t = 1) {
|
|
|
1218
1218
|
tracked: !0
|
|
1219
1219
|
};
|
|
1220
1220
|
}
|
|
1221
|
-
function
|
|
1221
|
+
function re(a, e, t = 0.4) {
|
|
1222
1222
|
const i = (n, s) => n + (s - n) * t;
|
|
1223
1223
|
return {
|
|
1224
1224
|
blinkLeft: i(a.blinkLeft, e.blinkLeft),
|
|
@@ -1234,36 +1234,36 @@ function ee(a, e, t = 0.4) {
|
|
|
1234
1234
|
tracked: e.tracked
|
|
1235
1235
|
};
|
|
1236
1236
|
}
|
|
1237
|
-
function
|
|
1237
|
+
function je(a, e, t, i, n) {
|
|
1238
1238
|
n || (a.fillStyle = "#101822", a.fillRect(0, 0, t, i));
|
|
1239
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;
|
|
1240
1240
|
a.save(), a.translate(s, o), a.rotate(e.headRoll * 0.6);
|
|
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,
|
|
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 +
|
|
1243
|
-
const
|
|
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, v = (A) => Math.cos(A + c), p = Math.sin(l) * r * 0.22;
|
|
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 + p * 0.4, r * 0.92, r * 0.5, 0, Math.PI, Math.PI * 2), a.fill();
|
|
1243
|
+
const S = 0;
|
|
1244
1244
|
a.fillStyle = "#e5b58a", a.beginPath();
|
|
1245
|
-
const
|
|
1246
|
-
a.ellipse(
|
|
1245
|
+
const T = u(S) * 0.9, y = r * 0.12 + p;
|
|
1246
|
+
a.ellipse(T + d * r * 0.14, y, r * 0.11, r * 0.14, 0, 0, Math.PI * 2), a.fill();
|
|
1247
1247
|
for (const A of [-1, 1]) {
|
|
1248
|
-
const
|
|
1249
|
-
if (
|
|
1250
|
-
const m = u(
|
|
1251
|
-
a.strokeStyle = "#4a2e18", a.lineWidth = r * 0.07, a.lineCap = "round", a.beginPath(), a.moveTo(m - r * 0.2 * h, -r * 0.42 -
|
|
1252
|
-
const
|
|
1253
|
-
a.fillStyle = "#ffffff", a.beginPath(), a.ellipse(m,
|
|
1248
|
+
const w = A * 0.42, E = v(w);
|
|
1249
|
+
if (E <= 0.12) continue;
|
|
1250
|
+
const m = u(w) * 0.82, h = Math.max(0.2, E), b = A < 0 ? e.blinkLeft : e.blinkRight, I = Math.max(0.06, 1 - b), C = e.browUp * r * 0.14;
|
|
1251
|
+
a.strokeStyle = "#4a2e18", a.lineWidth = r * 0.07, a.lineCap = "round", a.beginPath(), a.moveTo(m - r * 0.2 * h, -r * 0.42 - C + p), a.quadraticCurveTo(m, -r * 0.52 - C + p, m + r * 0.2 * h, -r * 0.44 - C + p), a.stroke();
|
|
1252
|
+
const N = -r * 0.18 + p;
|
|
1253
|
+
a.fillStyle = "#ffffff", a.beginPath(), a.ellipse(m, N, r * 0.16 * h, r * 0.12 * I, 0, 0, Math.PI * 2), a.fill(), a.fillStyle = "#22303c", a.beginPath(), a.ellipse(
|
|
1254
1254
|
m + e.pupilX * r * 0.07 * h,
|
|
1255
|
-
|
|
1255
|
+
N + e.pupilY * r * 0.05,
|
|
1256
1256
|
r * 0.06 * h,
|
|
1257
|
-
r * 0.06 *
|
|
1257
|
+
r * 0.06 * I,
|
|
1258
1258
|
0,
|
|
1259
1259
|
0,
|
|
1260
1260
|
Math.PI * 2
|
|
1261
1261
|
), a.fill();
|
|
1262
1262
|
}
|
|
1263
|
-
const
|
|
1264
|
-
a.fillStyle = "#8c2f2f", a.beginPath(), a.moveTo(
|
|
1263
|
+
const k = Math.max(0.25, v(0)), f = u(0) * 0.7, M = r * 0.55 * k, R = r * (0.04 + e.jawOpen * 0.34), L = e.smile * r * 0.12, P = r * 0.42 + p;
|
|
1264
|
+
a.fillStyle = "#8c2f2f", a.beginPath(), a.moveTo(f - M / 2, P - L), a.quadraticCurveTo(f, P + R, f + M / 2, P - L), a.quadraticCurveTo(f, P - R * 0.25, f - M / 2, P - 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");
|
|
1265
1265
|
}
|
|
1266
|
-
const
|
|
1266
|
+
const oe = {
|
|
1267
1267
|
mouthGain: 1.7,
|
|
1268
1268
|
blinkGain: 1,
|
|
1269
1269
|
eyeSync: 1,
|
|
@@ -1272,82 +1272,303 @@ const te = {
|
|
|
1272
1272
|
avatarLift: 0,
|
|
1273
1273
|
lostHoldMs: 400
|
|
1274
1274
|
};
|
|
1275
|
-
function
|
|
1275
|
+
function ce() {
|
|
1276
1276
|
return {
|
|
1277
1277
|
render(a, e, t, i, n) {
|
|
1278
|
-
|
|
1278
|
+
je(a, e, t, i, n ?? void 0);
|
|
1279
1279
|
}
|
|
1280
1280
|
};
|
|
1281
1281
|
}
|
|
1282
|
-
const
|
|
1283
|
-
function
|
|
1282
|
+
const G = (a) => Math.max(0, Math.min(1, a));
|
|
1283
|
+
function lt(a, e = {}) {
|
|
1284
1284
|
const t = e.document ?? globalThis.document;
|
|
1285
1285
|
let i = e.width ?? 1280, n = e.height ?? 720;
|
|
1286
1286
|
const s = !!(e.width || e.height), o = e.frameRate ?? 24, r = a instanceof MediaStreamTrack ? a : a.getVideoTracks()[0];
|
|
1287
1287
|
if (!r) throw new Error("A video track is required");
|
|
1288
|
-
let c = e.tracker ?? null, l = e.renderer ??
|
|
1289
|
-
const u = { ...
|
|
1290
|
-
|
|
1288
|
+
let c = e.tracker ?? null, l = e.renderer ?? ce(), d = e.mode ?? "replace";
|
|
1289
|
+
const u = { ...oe, ...e.tuning }, v = e.backdrop ?? "#101822", p = t.createElement("video");
|
|
1290
|
+
p.muted = !0, p.playsInline = !0, p.srcObject = new MediaStream([r]), p.play().catch(() => {
|
|
1291
1291
|
});
|
|
1292
|
-
const
|
|
1293
|
-
|
|
1294
|
-
const
|
|
1292
|
+
const S = t.createElement("canvas");
|
|
1293
|
+
S.width = i, S.height = n;
|
|
1294
|
+
const T = S.getContext("2d"), y = () => {
|
|
1295
1295
|
if (s) return;
|
|
1296
|
-
const
|
|
1297
|
-
if (!
|
|
1298
|
-
const m = Math.min(1, 1280 / Math.max(
|
|
1299
|
-
(!(h === i ||
|
|
1296
|
+
const w = p.videoWidth, E = p.videoHeight;
|
|
1297
|
+
if (!w || !E) return;
|
|
1298
|
+
const m = Math.min(1, 1280 / Math.max(w, E)), h = Math.round(w * m), b = Math.round(E * m);
|
|
1299
|
+
(!(h === i || b === n) || h !== i || b !== n) && (i = h, n = b, S.width = i, S.height = n);
|
|
1300
1300
|
};
|
|
1301
|
-
|
|
1302
|
-
let
|
|
1303
|
-
function
|
|
1304
|
-
if (
|
|
1305
|
-
const
|
|
1306
|
-
|
|
1307
|
-
}
|
|
1308
|
-
function L(
|
|
1309
|
-
if (c &&
|
|
1301
|
+
p.addEventListener?.("loadedmetadata", y), p.addEventListener?.("resize", y);
|
|
1302
|
+
let k = ve(), f = null, M = 0;
|
|
1303
|
+
function R(w) {
|
|
1304
|
+
if (w.length <= 454) return;
|
|
1305
|
+
const E = w[10], m = w[152], h = w[234], b = w[454], I = (h.x + b.x) / 2 * i, C = (h.y + b.y) / 2 * n, N = Math.hypot((m.x - E.x) * i, (m.y - E.y) * n), Q = Math.max(0.6, Math.cos(k.headPitch)), O = { x: I, y: C, radius: Math.max(24, N / Q * 0.8) };
|
|
1306
|
+
f = f ? { x: f.x + (O.x - f.x) * 0.4, y: f.y + (O.y - f.y) * 0.4, radius: f.radius + (O.radius - f.radius) * 0.15 } : O;
|
|
1307
|
+
}
|
|
1308
|
+
function L(w) {
|
|
1309
|
+
if (c && p.readyState >= 2) {
|
|
1310
1310
|
let m = null;
|
|
1311
1311
|
try {
|
|
1312
|
-
m = c.detect(
|
|
1312
|
+
m = c.detect(p, w);
|
|
1313
1313
|
} catch {
|
|
1314
1314
|
}
|
|
1315
|
-
const h =
|
|
1316
|
-
h.jawOpen =
|
|
1315
|
+
const h = Ve(m?.categories ?? null, m?.matrix ?? null, u.eyeSync);
|
|
1316
|
+
h.jawOpen = G(h.jawOpen * u.mouthGain), h.blinkLeft = G(h.blinkLeft * u.blinkGain), h.blinkRight = G(h.blinkRight * u.blinkGain), h.tracked ? (M = w, k = re(k, h, u.smoothing), m?.landmarks && R(m.landmarks)) : k.tracked && w - M > u.lostHoldMs && (k = re(k, { ...k, jawOpen: 0, browUp: 0, smile: k.smile * 0.5, blinkLeft: 0.1, blinkRight: 0.1 }, 0.05));
|
|
1317
1317
|
}
|
|
1318
|
-
d === "overlay" &&
|
|
1319
|
-
const
|
|
1320
|
-
l?.render(
|
|
1318
|
+
d === "overlay" && p.readyState >= 2 ? T.drawImage(p, 0, 0, i, n) : (T.fillStyle = v, T.fillRect(0, 0, i, n));
|
|
1319
|
+
const E = f ? { x: f.x, y: f.y + u.avatarLift * f.radius, radius: f.radius * u.avatarScale } : null;
|
|
1320
|
+
l?.render(T, k, i, n, E);
|
|
1321
1321
|
}
|
|
1322
|
-
const
|
|
1322
|
+
const P = setInterval(() => L(Date.now()), Math.round(1e3 / o)), A = S.captureStream(o);
|
|
1323
1323
|
return {
|
|
1324
1324
|
track: A.getVideoTracks()[0],
|
|
1325
1325
|
stream: A,
|
|
1326
|
-
getRig: () => ({ ...
|
|
1327
|
-
setMode(
|
|
1328
|
-
d =
|
|
1326
|
+
getRig: () => ({ ...k }),
|
|
1327
|
+
setMode(w) {
|
|
1328
|
+
d = w === "overlay" ? "overlay" : "replace";
|
|
1329
1329
|
},
|
|
1330
|
-
setTracker(
|
|
1331
|
-
c?.close?.(), c =
|
|
1330
|
+
setTracker(w) {
|
|
1331
|
+
c?.close?.(), c = w;
|
|
1332
1332
|
},
|
|
1333
|
-
setRenderer(
|
|
1334
|
-
l?.dispose?.(), l =
|
|
1333
|
+
setRenderer(w) {
|
|
1334
|
+
l?.dispose?.(), l = w ?? ce();
|
|
1335
1335
|
},
|
|
1336
|
-
setTuning(
|
|
1337
|
-
for (const
|
|
1338
|
-
const m =
|
|
1339
|
-
typeof m == "number" && Number.isFinite(m) && (u[
|
|
1336
|
+
setTuning(w) {
|
|
1337
|
+
for (const E of Object.keys(oe)) {
|
|
1338
|
+
const m = w[E];
|
|
1339
|
+
typeof m == "number" && Number.isFinite(m) && (u[E] = m);
|
|
1340
1340
|
}
|
|
1341
1341
|
},
|
|
1342
1342
|
getTuning: () => ({ ...u }),
|
|
1343
1343
|
dispose() {
|
|
1344
|
-
clearInterval(
|
|
1345
|
-
for (const
|
|
1346
|
-
|
|
1344
|
+
clearInterval(P), c?.close?.(), l?.dispose?.();
|
|
1345
|
+
for (const w of A.getTracks()) w.stop();
|
|
1346
|
+
p.srcObject = null;
|
|
1347
1347
|
}
|
|
1348
1348
|
};
|
|
1349
1349
|
}
|
|
1350
|
-
class
|
|
1350
|
+
class j extends Error {
|
|
1351
|
+
constructor(e, t) {
|
|
1352
|
+
super(t), this.code = e, this.name = "ZipError";
|
|
1353
|
+
}
|
|
1354
|
+
code;
|
|
1355
|
+
}
|
|
1356
|
+
const Se = 101010256, we = 33639248, ke = 67324752, K = 4294967295;
|
|
1357
|
+
function Te(a) {
|
|
1358
|
+
if (a.byteLength < 4) return !1;
|
|
1359
|
+
const e = new DataView(a).getUint32(0, !0);
|
|
1360
|
+
return e === ke || e === we || e === Se;
|
|
1361
|
+
}
|
|
1362
|
+
function Be(a) {
|
|
1363
|
+
const e = Math.max(0, a.byteLength - 22 - 65535);
|
|
1364
|
+
for (let t = a.byteLength - 22; t >= e; t -= 1)
|
|
1365
|
+
if (a.getUint32(t, !0) === Se) return t;
|
|
1366
|
+
throw new j("zip_unreadable", "The archive index could not be found.");
|
|
1367
|
+
}
|
|
1368
|
+
function be(a) {
|
|
1369
|
+
const e = new DataView(a), t = Be(e), i = e.getUint16(t + 10, !0);
|
|
1370
|
+
let n = e.getUint32(t + 16, !0);
|
|
1371
|
+
if (n === K) throw new j("zip_unsupported", "ZIP64 archives are not supported.");
|
|
1372
|
+
const s = new TextDecoder(), o = [];
|
|
1373
|
+
for (let r = 0; r < i; r += 1) {
|
|
1374
|
+
if (n + 46 > a.byteLength || e.getUint32(n, !0) !== we)
|
|
1375
|
+
throw new j("zip_unreadable", "The archive index is malformed.");
|
|
1376
|
+
const c = e.getUint16(n + 8, !0), l = e.getUint16(n + 10, !0), d = e.getUint32(n + 20, !0), u = e.getUint32(n + 24, !0), v = e.getUint16(n + 28, !0), p = e.getUint16(n + 30, !0), S = e.getUint16(n + 32, !0), T = e.getUint32(n + 42, !0), y = s.decode(new Uint8Array(a, n + 46, v));
|
|
1377
|
+
o.push({
|
|
1378
|
+
path: y,
|
|
1379
|
+
bytes: u,
|
|
1380
|
+
compressedBytes: d,
|
|
1381
|
+
compressionMethod: l,
|
|
1382
|
+
encrypted: (c & 1) !== 0,
|
|
1383
|
+
localHeaderOffset: T
|
|
1384
|
+
}), n += 46 + v + p + S;
|
|
1385
|
+
}
|
|
1386
|
+
return o;
|
|
1387
|
+
}
|
|
1388
|
+
async function Qe(a, e) {
|
|
1389
|
+
if (e.encrypted) throw new j("zip_encrypted", "The archive is password protected.");
|
|
1390
|
+
if (e.bytes === K || e.compressedBytes === K)
|
|
1391
|
+
throw new j("zip_unsupported", "ZIP64 archives are not supported.");
|
|
1392
|
+
const t = new DataView(a), i = e.localHeaderOffset;
|
|
1393
|
+
if (i + 30 > a.byteLength || t.getUint32(i, !0) !== ke)
|
|
1394
|
+
throw new j("zip_unreadable", "An archive entry header is malformed.");
|
|
1395
|
+
const n = t.getUint16(i + 26, !0), s = t.getUint16(i + 28, !0), o = i + 30 + n + s;
|
|
1396
|
+
if (o + e.compressedBytes > a.byteLength)
|
|
1397
|
+
throw new j("zip_unreadable", "An archive entry runs past the end of the file.");
|
|
1398
|
+
const r = a.slice(o, o + e.compressedBytes);
|
|
1399
|
+
if (e.compressionMethod === 0) return r;
|
|
1400
|
+
if (e.compressionMethod !== 8)
|
|
1401
|
+
throw new j("zip_unsupported", `Archive compression method ${e.compressionMethod} is not supported.`);
|
|
1402
|
+
if (typeof DecompressionStream > "u")
|
|
1403
|
+
throw new j("zip_unsupported", "This browser cannot expand compressed archives.");
|
|
1404
|
+
const c = new Blob([r]).stream().pipeThrough(new DecompressionStream("deflate-raw"));
|
|
1405
|
+
return new Response(c).arrayBuffer();
|
|
1406
|
+
}
|
|
1407
|
+
async function dt(a) {
|
|
1408
|
+
const e = typeof File < "u" && a instanceof File ? await a.arrayBuffer() : a;
|
|
1409
|
+
if (!Te(e)) return [];
|
|
1410
|
+
try {
|
|
1411
|
+
return Ce(be(e)).map((t) => t.path);
|
|
1412
|
+
} catch {
|
|
1413
|
+
return [];
|
|
1414
|
+
}
|
|
1415
|
+
}
|
|
1416
|
+
const _e = 64 * 1024 * 1024, Fe = "streaming-cdn-avatars", z = "models", ze = 1179937895, He = 1313821514;
|
|
1417
|
+
class x extends Error {
|
|
1418
|
+
constructor(e, t, i = []) {
|
|
1419
|
+
super(t), this.code = e, this.name = "AvatarModelError", this.choices = i;
|
|
1420
|
+
}
|
|
1421
|
+
code;
|
|
1422
|
+
/**
|
|
1423
|
+
* The characters found inside an archive. Set only for
|
|
1424
|
+
* "archive_many_models", so the caller can ask which one to import and pass
|
|
1425
|
+
* it back as importAvatarModel's entryPath.
|
|
1426
|
+
*/
|
|
1427
|
+
choices;
|
|
1428
|
+
}
|
|
1429
|
+
function Ce(a) {
|
|
1430
|
+
return a.filter((e) => /\.vrm$/i.test(e.path) && !e.path.endsWith("/") && !e.path.split("/").some((t) => t === "__MACOSX" || t.startsWith("._")));
|
|
1431
|
+
}
|
|
1432
|
+
function q(a) {
|
|
1433
|
+
const e = typeof a == "string" ? a.trim() : "";
|
|
1434
|
+
return e.length > 0 ? e : null;
|
|
1435
|
+
}
|
|
1436
|
+
function $e(a) {
|
|
1437
|
+
const e = new DataView(a);
|
|
1438
|
+
if (a.byteLength < 20 || e.getUint32(0, !0) !== ze)
|
|
1439
|
+
throw new x("model_not_glb", "The file is not a binary glTF (.vrm / .glb) model.");
|
|
1440
|
+
let t = 12, i = null;
|
|
1441
|
+
for (; t + 8 <= a.byteLength; ) {
|
|
1442
|
+
const r = e.getUint32(t, !0), c = e.getUint32(t + 4, !0), l = t + 8;
|
|
1443
|
+
if (l + r > a.byteLength) break;
|
|
1444
|
+
if (c === He) {
|
|
1445
|
+
try {
|
|
1446
|
+
const d = new TextDecoder().decode(new Uint8Array(a, l, r)).replace(/[\s\u0000]+$/, "");
|
|
1447
|
+
i = JSON.parse(d);
|
|
1448
|
+
} catch {
|
|
1449
|
+
throw new x("model_unreadable", "The model's glTF descriptor could not be read.");
|
|
1450
|
+
}
|
|
1451
|
+
break;
|
|
1452
|
+
}
|
|
1453
|
+
t = l + r + (4 - r % 4) % 4;
|
|
1454
|
+
}
|
|
1455
|
+
const n = i?.extensions ?? {}, s = n.VRM?.meta, o = n.VRMC_vrm?.meta;
|
|
1456
|
+
if (!s && !o) return null;
|
|
1457
|
+
if (o) {
|
|
1458
|
+
const r = Array.isArray(o.authors) ? o.authors.filter((c) => typeof c == "string") : [];
|
|
1459
|
+
return {
|
|
1460
|
+
title: q(o.name),
|
|
1461
|
+
author: r.length ? r.join(", ") : null,
|
|
1462
|
+
allowedUser: q(o.avatarPermission),
|
|
1463
|
+
commercialUse: q(o.commercialUsage),
|
|
1464
|
+
licenseName: q(o.licenseUrl) ? "VRM 1.0" : null,
|
|
1465
|
+
licenseUrl: q(o.licenseUrl) ?? q(o.otherLicenseUrl)
|
|
1466
|
+
};
|
|
1467
|
+
}
|
|
1468
|
+
return {
|
|
1469
|
+
title: q(s?.title),
|
|
1470
|
+
author: q(s?.author),
|
|
1471
|
+
allowedUser: q(s?.allowedUserName),
|
|
1472
|
+
commercialUse: q(s?.commercialUssageName),
|
|
1473
|
+
licenseName: q(s?.licenseName),
|
|
1474
|
+
licenseUrl: q(s?.otherLicenseUrl)
|
|
1475
|
+
};
|
|
1476
|
+
}
|
|
1477
|
+
function We() {
|
|
1478
|
+
return new Promise((a, e) => {
|
|
1479
|
+
if (typeof indexedDB > "u") {
|
|
1480
|
+
e(new x("storage_unavailable", "This browser cannot store imported avatar models."));
|
|
1481
|
+
return;
|
|
1482
|
+
}
|
|
1483
|
+
const t = indexedDB.open(Fe, 1);
|
|
1484
|
+
t.onupgradeneeded = () => {
|
|
1485
|
+
t.result.objectStoreNames.contains(z) || t.result.createObjectStore(z, { keyPath: "id" });
|
|
1486
|
+
}, t.onsuccess = () => a(t.result), t.onerror = () => e(new x("storage_unavailable", "Imported avatar storage could not be opened."));
|
|
1487
|
+
});
|
|
1488
|
+
}
|
|
1489
|
+
async function H(a, e) {
|
|
1490
|
+
const t = await We();
|
|
1491
|
+
try {
|
|
1492
|
+
return await new Promise((i, n) => {
|
|
1493
|
+
const s = e(t.transaction(z, a).objectStore(z));
|
|
1494
|
+
s.onsuccess = () => i(s.result), s.onerror = () => n(new x("storage_unavailable", "The imported avatar could not be stored."));
|
|
1495
|
+
});
|
|
1496
|
+
} finally {
|
|
1497
|
+
t.close();
|
|
1498
|
+
}
|
|
1499
|
+
}
|
|
1500
|
+
const Ee = (a) => ({
|
|
1501
|
+
id: a.id,
|
|
1502
|
+
name: a.name,
|
|
1503
|
+
bytes: a.bytes,
|
|
1504
|
+
importedAt: a.importedAt,
|
|
1505
|
+
license: a.license
|
|
1506
|
+
});
|
|
1507
|
+
async function ht(a, e = {}) {
|
|
1508
|
+
const t = e.maxBytes ?? _e, i = typeof File < "u" && a instanceof File;
|
|
1509
|
+
let n = i ? a.name : null, s = i ? await a.arrayBuffer() : a;
|
|
1510
|
+
if (Te(s)) {
|
|
1511
|
+
const l = await Je(s, e.entryPath, t);
|
|
1512
|
+
s = l.buffer, n = l.path.split("/").pop() ?? n;
|
|
1513
|
+
}
|
|
1514
|
+
if (s.byteLength > t)
|
|
1515
|
+
throw new x(
|
|
1516
|
+
"model_too_large",
|
|
1517
|
+
"The model is larger than the " + Math.round(t / 1024 / 1024) + " MB limit."
|
|
1518
|
+
);
|
|
1519
|
+
const o = $e(s);
|
|
1520
|
+
if (!o)
|
|
1521
|
+
throw new x("model_not_vrm", "The file is a glTF model but carries no VRM character data.");
|
|
1522
|
+
const r = o.title || (n ? n.replace(/\.(vrm|glb)$/i, "") : null), c = {
|
|
1523
|
+
id: "avatar_" + Date.now().toString(36) + "_" + Math.random().toString(36).slice(2, 8),
|
|
1524
|
+
name: e.name?.trim() || r || "Imported avatar",
|
|
1525
|
+
bytes: s.byteLength,
|
|
1526
|
+
importedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1527
|
+
license: o,
|
|
1528
|
+
data: s
|
|
1529
|
+
};
|
|
1530
|
+
return await H("readwrite", (l) => l.put(c)), Ee(c);
|
|
1531
|
+
}
|
|
1532
|
+
async function Je(a, e, t) {
|
|
1533
|
+
let i;
|
|
1534
|
+
try {
|
|
1535
|
+
i = Ce(be(a));
|
|
1536
|
+
} catch (s) {
|
|
1537
|
+
throw s instanceof j ? new x(le(s.code), s.message) : new x("archive_unreadable", "The archive could not be read.");
|
|
1538
|
+
}
|
|
1539
|
+
if (i.length === 0)
|
|
1540
|
+
throw new x("archive_no_model", "The archive contains no .vrm character.");
|
|
1541
|
+
const n = e ? i.find((s) => s.path === e) : i.length === 1 ? i[0] : null;
|
|
1542
|
+
if (!n)
|
|
1543
|
+
throw new x(
|
|
1544
|
+
"archive_many_models",
|
|
1545
|
+
"The archive contains several characters; choose one.",
|
|
1546
|
+
i.map((s) => s.path)
|
|
1547
|
+
);
|
|
1548
|
+
if (n.bytes > t)
|
|
1549
|
+
throw new x(
|
|
1550
|
+
"model_too_large",
|
|
1551
|
+
"The character inside the archive is larger than the " + Math.round(t / 1024 / 1024) + " MB limit."
|
|
1552
|
+
);
|
|
1553
|
+
try {
|
|
1554
|
+
return { buffer: await Qe(a, n), path: n.path };
|
|
1555
|
+
} catch (s) {
|
|
1556
|
+
throw s instanceof j ? new x(le(s.code), s.message) : new x("archive_unreadable", "The character could not be expanded from the archive.");
|
|
1557
|
+
}
|
|
1558
|
+
}
|
|
1559
|
+
function le(a) {
|
|
1560
|
+
return a === "zip_encrypted" ? "archive_encrypted" : a === "zip_unsupported" ? "archive_unsupported" : "archive_unreadable";
|
|
1561
|
+
}
|
|
1562
|
+
async function ut() {
|
|
1563
|
+
return (await H("readonly", (e) => e.getAll()) ?? []).map(Ee).sort((e, t) => t.importedAt.localeCompare(e.importedAt));
|
|
1564
|
+
}
|
|
1565
|
+
async function mt(a) {
|
|
1566
|
+
return (await H("readonly", (t) => t.get(a)))?.data ?? null;
|
|
1567
|
+
}
|
|
1568
|
+
async function pt(a) {
|
|
1569
|
+
await H("readwrite", (e) => e.delete(a));
|
|
1570
|
+
}
|
|
1571
|
+
class Ge extends EventTarget {
|
|
1351
1572
|
mode;
|
|
1352
1573
|
options;
|
|
1353
1574
|
client = null;
|
|
@@ -1381,7 +1602,7 @@ class Ee extends EventTarget {
|
|
|
1381
1602
|
async initialize() {
|
|
1382
1603
|
if (this.client) return this;
|
|
1383
1604
|
try {
|
|
1384
|
-
const t = (this.options.transport === "auto" ? this.mode === "meeting" ? "sfu" : "mesh" : this.options.transport ?? "mesh") === "sfu" ?
|
|
1605
|
+
const t = (this.options.transport === "auto" ? this.mode === "meeting" ? "sfu" : "mesh" : this.options.transport ?? "mesh") === "sfu" ? xe : F;
|
|
1385
1606
|
return this.client = new t({
|
|
1386
1607
|
credential: {
|
|
1387
1608
|
signalingToken: this.options.credential.signalingToken,
|
|
@@ -1401,19 +1622,19 @@ class Ee extends EventTarget {
|
|
|
1401
1622
|
localStream: this.options.localStream,
|
|
1402
1623
|
simulcast: this.options.simulcast ?? !0,
|
|
1403
1624
|
onEvent: (i, n) => this.handleNativeEvent(i, n)
|
|
1404
|
-
}), await this.client.initialize(), this.startStats(), this.emit("initialized", { mode: this.mode, sdkVersion:
|
|
1625
|
+
}), await this.client.initialize(), this.startStats(), this.emit("initialized", { mode: this.mode, sdkVersion: nt }), this.options.autoJoin && await this.join(), this;
|
|
1405
1626
|
} catch (e) {
|
|
1406
1627
|
this.state = "failed";
|
|
1407
|
-
const t =
|
|
1408
|
-
throw this.emit("error",
|
|
1628
|
+
const t = fe(e, "RTC initialization failed");
|
|
1629
|
+
throw this.emit("error", B(t)), t;
|
|
1409
1630
|
}
|
|
1410
1631
|
}
|
|
1411
1632
|
async join() {
|
|
1412
1633
|
const e = this.requireClient();
|
|
1413
1634
|
return this.joinPromise ? this.joinPromise : (this.state = "joining", this.emit("joining", {}), this.joinPromise = e.join().catch((t) => {
|
|
1414
1635
|
this.state = "failed";
|
|
1415
|
-
const i =
|
|
1416
|
-
throw this.emit("error",
|
|
1636
|
+
const i = fe(t, "RTC connection failed");
|
|
1637
|
+
throw this.emit("error", B(i)), i;
|
|
1417
1638
|
}).finally(() => {
|
|
1418
1639
|
this.joinPromise = null;
|
|
1419
1640
|
}), this.joinPromise);
|
|
@@ -1451,14 +1672,14 @@ class Ee extends EventTarget {
|
|
|
1451
1672
|
return navigator.mediaDevices?.enumerateDevices ? navigator.mediaDevices.enumerateDevices() : [];
|
|
1452
1673
|
}
|
|
1453
1674
|
getParticipants() {
|
|
1454
|
-
return this.requireClient().getParticipants().map(
|
|
1675
|
+
return this.requireClient().getParticipants().map(ue);
|
|
1455
1676
|
}
|
|
1456
1677
|
getLocalStream() {
|
|
1457
1678
|
return this.client?.getLocalStream() ?? null;
|
|
1458
1679
|
}
|
|
1459
1680
|
getRemoteStreams() {
|
|
1460
1681
|
return (this.client?.getRemoteStreams() ?? []).map((e) => ({
|
|
1461
|
-
participant:
|
|
1682
|
+
participant: ue(e.participant),
|
|
1462
1683
|
stream: e.stream
|
|
1463
1684
|
}));
|
|
1464
1685
|
}
|
|
@@ -1527,7 +1748,7 @@ class Ee extends EventTarget {
|
|
|
1527
1748
|
let n = "unavailable";
|
|
1528
1749
|
if (e.requestMedia !== !1 && navigator.mediaDevices?.getUserMedia)
|
|
1529
1750
|
try {
|
|
1530
|
-
(await navigator.mediaDevices.getUserMedia({ audio: this.options.audio, video: this.options.video })).getTracks().forEach((
|
|
1751
|
+
(await navigator.mediaDevices.getUserMedia({ audio: this.options.audio, video: this.options.video })).getTracks().forEach((v) => v.stop()), n = "granted";
|
|
1531
1752
|
} catch {
|
|
1532
1753
|
n = "denied", t.push("media_permission_denied");
|
|
1533
1754
|
}
|
|
@@ -1538,8 +1759,8 @@ class Ee extends EventTarget {
|
|
|
1538
1759
|
if (c) {
|
|
1539
1760
|
const u = performance.now();
|
|
1540
1761
|
try {
|
|
1541
|
-
const
|
|
1542
|
-
l = Math.round(performance.now() - u),
|
|
1762
|
+
const v = await fetch(c, { method: "HEAD", cache: "no-store", credentials: "omit" });
|
|
1763
|
+
l = Math.round(performance.now() - u), v.ok || t.push("network_probe_failed");
|
|
1543
1764
|
} catch {
|
|
1544
1765
|
t.push("network_probe_failed");
|
|
1545
1766
|
}
|
|
@@ -1552,7 +1773,7 @@ class Ee extends EventTarget {
|
|
|
1552
1773
|
microphoneCount: o,
|
|
1553
1774
|
cameraCount: r,
|
|
1554
1775
|
probeLatencyMs: l,
|
|
1555
|
-
effectiveConnectionType:
|
|
1776
|
+
effectiveConnectionType: me()?.effectiveType ?? null,
|
|
1556
1777
|
issues: t
|
|
1557
1778
|
};
|
|
1558
1779
|
return this.emit("preflight", d), this.options.autoReportStats && await this.reportQuality({
|
|
@@ -1565,7 +1786,7 @@ class Ee extends EventTarget {
|
|
|
1565
1786
|
}), d;
|
|
1566
1787
|
}
|
|
1567
1788
|
async collectQualitySample(e = "runtime") {
|
|
1568
|
-
const t = this.options.statsProvider ? await this.options.statsProvider() : {}, i = this.peerConnection ? await
|
|
1789
|
+
const t = this.options.statsProvider ? await this.options.statsProvider() : {}, i = this.peerConnection ? await et(this.peerConnection, this.previousCounters) : null;
|
|
1569
1790
|
i?.counters && (this.previousCounters = i.counters);
|
|
1570
1791
|
const s = { ...{
|
|
1571
1792
|
sampleType: e,
|
|
@@ -1598,9 +1819,9 @@ class Ee extends EventTarget {
|
|
|
1598
1819
|
transportProtocol: null,
|
|
1599
1820
|
candidateType: null,
|
|
1600
1821
|
qualityLimitationReason: null,
|
|
1601
|
-
deviceMemoryGb:
|
|
1602
|
-
effectiveConnectionType:
|
|
1603
|
-
}, ...i?.sample ?? {}, ...t, sampleType: e, sampledAt: (/* @__PURE__ */ new Date()).toISOString() }, o =
|
|
1822
|
+
deviceMemoryGb: it(),
|
|
1823
|
+
effectiveConnectionType: me()?.effectiveType ?? null
|
|
1824
|
+
}, ...i?.sample ?? {}, ...t, sampleType: e, sampledAt: (/* @__PURE__ */ new Date()).toISOString() }, o = tt(s);
|
|
1604
1825
|
return s.networkScore = o.networkScore, s.estimatedMos = o.estimatedMos, this.latestQuality = s, s;
|
|
1605
1826
|
}
|
|
1606
1827
|
async reportQuality(e) {
|
|
@@ -1651,7 +1872,7 @@ class Ee extends EventTarget {
|
|
|
1651
1872
|
const i = Date.now(), n = e !== "runtime" || i - this.lastTelemetryAt >= this.options.telemetryInterval;
|
|
1652
1873
|
this.options.autoReportStats && n && (await this.reportQuality(t), this.lastTelemetryAt = i);
|
|
1653
1874
|
} catch (t) {
|
|
1654
|
-
this.emit("telemetryerror",
|
|
1875
|
+
this.emit("telemetryerror", B(t));
|
|
1655
1876
|
} finally {
|
|
1656
1877
|
this.statsRunning = !1;
|
|
1657
1878
|
}
|
|
@@ -1685,21 +1906,21 @@ class Ee extends EventTarget {
|
|
|
1685
1906
|
this.dispatchEvent(new CustomEvent(e, { detail: i })), this.options.onEvent?.(i);
|
|
1686
1907
|
}
|
|
1687
1908
|
}
|
|
1688
|
-
async function
|
|
1689
|
-
return new
|
|
1909
|
+
async function ft(a) {
|
|
1910
|
+
return new Ge(a).initialize();
|
|
1690
1911
|
}
|
|
1691
|
-
let
|
|
1692
|
-
function
|
|
1693
|
-
if (
|
|
1912
|
+
let _ = null;
|
|
1913
|
+
function Me() {
|
|
1914
|
+
if (_) return _;
|
|
1694
1915
|
const a = globalThis, e = a.AudioContext ?? a.webkitAudioContext;
|
|
1695
|
-
return e ? (
|
|
1916
|
+
return e ? (_ = new e(), _) : null;
|
|
1696
1917
|
}
|
|
1697
|
-
async function
|
|
1698
|
-
const a =
|
|
1918
|
+
async function Ye() {
|
|
1919
|
+
const a = Me();
|
|
1699
1920
|
return a ? (a.state === "suspended" && await a.resume().catch(() => {
|
|
1700
1921
|
}), a.state === "running") : !1;
|
|
1701
1922
|
}
|
|
1702
|
-
class
|
|
1923
|
+
class Ke {
|
|
1703
1924
|
options;
|
|
1704
1925
|
media = null;
|
|
1705
1926
|
cadenceTimer = null;
|
|
@@ -1708,7 +1929,7 @@ class Me {
|
|
|
1708
1929
|
this.options = e;
|
|
1709
1930
|
}
|
|
1710
1931
|
unlock() {
|
|
1711
|
-
return
|
|
1932
|
+
return Ye();
|
|
1712
1933
|
}
|
|
1713
1934
|
startIncoming() {
|
|
1714
1935
|
this.start("incoming", this.options.ringtoneUrl);
|
|
@@ -1736,7 +1957,7 @@ class Me {
|
|
|
1736
1957
|
i(), this.cadenceTimer = setInterval(i, e === "incoming" ? 3e3 : 3500);
|
|
1737
1958
|
}
|
|
1738
1959
|
playBuiltInTone(e) {
|
|
1739
|
-
const t =
|
|
1960
|
+
const t = Me();
|
|
1740
1961
|
if (!t || t.state !== "running") return;
|
|
1741
1962
|
const i = e === "incoming" ? 1.25 : 1, n = e === "incoming" ? [440, 480] : [425], s = t.createGain(), o = t.currentTime;
|
|
1742
1963
|
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);
|
|
@@ -1746,7 +1967,7 @@ class Me {
|
|
|
1746
1967
|
}
|
|
1747
1968
|
}
|
|
1748
1969
|
}
|
|
1749
|
-
class
|
|
1970
|
+
class Xe extends EventTarget {
|
|
1750
1971
|
options;
|
|
1751
1972
|
socket = null;
|
|
1752
1973
|
stopped = !1;
|
|
@@ -1774,14 +1995,14 @@ class Pe extends EventTarget {
|
|
|
1774
1995
|
if (e.token && !e.token.startsWith("rtcc_")) throw new Error("A valid RTC client token is required");
|
|
1775
1996
|
if (!e.signalingUrl && !e.callActionsUrl && !e.apiBaseUrl && !globalThis.location?.origin)
|
|
1776
1997
|
throw new Error("signalingUrl or callActionsUrl is required outside a browser");
|
|
1777
|
-
this.options = e, this.currentToken = e.token ?? null, this.currentTokenExpiresAt = e.tokenExpiresAt, this.callAudio = new
|
|
1998
|
+
this.options = e, this.currentToken = e.token ?? null, this.currentTokenExpiresAt = e.tokenExpiresAt, this.callAudio = new Ke(e), this.mount = de(e.mount), this.scheduleTokenRefresh();
|
|
1778
1999
|
}
|
|
1779
2000
|
connect() {
|
|
1780
2001
|
if (!this.options.signalingUrl) throw new Error("signalingUrl is required to connect signaling");
|
|
1781
2002
|
return this.stopped = !1, this.scheduleTokenRefresh(), this.openSocket("initial"), this;
|
|
1782
2003
|
}
|
|
1783
2004
|
setMount(e) {
|
|
1784
|
-
this.clearUi(), this.mount =
|
|
2005
|
+
this.clearUi(), this.mount = de(e), this.currentCall && this.renderIncoming(this.currentCall);
|
|
1785
2006
|
}
|
|
1786
2007
|
/** Binds media lifetime to a call. Terminal call states automatically leave and destroy it. */
|
|
1787
2008
|
attachMediaClient(e, t) {
|
|
@@ -1892,7 +2113,7 @@ class Pe extends EventTarget {
|
|
|
1892
2113
|
/** Applies a call state received through the application's own push or signaling channel. */
|
|
1893
2114
|
handleCallUpdate(e) {
|
|
1894
2115
|
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,
|
|
2116
|
+
(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, Ze(e.status)), i.includes(e.status) && this.releaseMedia(e.id), this.emit("callupdated", e);
|
|
1896
2117
|
}
|
|
1897
2118
|
disconnect() {
|
|
1898
2119
|
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();
|
|
@@ -1910,11 +2131,11 @@ class Pe extends EventTarget {
|
|
|
1910
2131
|
try {
|
|
1911
2132
|
t = await this.resolveToken(e, e === "reconnect");
|
|
1912
2133
|
} catch (s) {
|
|
1913
|
-
this.emit("tokenerror",
|
|
2134
|
+
this.emit("tokenerror", B(s)), !this.stopped && this.options.reconnect !== !1 && this.scheduleReconnect();
|
|
1914
2135
|
return;
|
|
1915
2136
|
}
|
|
1916
2137
|
if (this.stopped || this.socket) return;
|
|
1917
|
-
const i =
|
|
2138
|
+
const i = X(this.options.signalingUrl, globalThis.location?.href), n = new WebSocket(i, ["rtc-client", t]);
|
|
1918
2139
|
this.socket = n, n.addEventListener("open", () => {
|
|
1919
2140
|
const s = this.reconnectAttempt > 0, o = this.lastDisconnect;
|
|
1920
2141
|
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(() => {
|
|
@@ -1976,7 +2197,7 @@ class Pe extends EventTarget {
|
|
|
1976
2197
|
async request(e, t, i = !1) {
|
|
1977
2198
|
const n = this.options.callActionsUrl ?? this.options.apiBaseUrl ?? this.options.signalingUrl ?? globalThis.location?.origin;
|
|
1978
2199
|
if (!n) throw new Error("callActionsUrl is required for call actions");
|
|
1979
|
-
const s =
|
|
2200
|
+
const s = Z(n, globalThis.location?.href), o = await this.resolveToken("initial"), r = new Headers(t.headers);
|
|
1980
2201
|
r.set("authorization", `Bearer ${o}`), r.set("content-type", "application/json");
|
|
1981
2202
|
const c = await fetch(new URL(e, s.origin), { ...t, headers: r }), l = await c.json().catch(() => ({}));
|
|
1982
2203
|
if (c.status === 401 && this.options.tokenProvider && !i)
|
|
@@ -2008,11 +2229,11 @@ class Pe extends EventTarget {
|
|
|
2008
2229
|
n.textContent = e.caller.name, n.style.fontSize = "20px";
|
|
2009
2230
|
const s = document.createElement("div");
|
|
2010
2231
|
Object.assign(s.style, { display: "grid", gridTemplateColumns: "1fr 1fr", gap: "10px" });
|
|
2011
|
-
const o =
|
|
2232
|
+
const o = he("Decline", "#fff", "#a32920", "#d9a09b"), r = he("Answer", "#fff", "#08745f", "#08745f");
|
|
2012
2233
|
o.addEventListener("click", () => {
|
|
2013
|
-
this.reject(e.id).catch((c) => this.emit("error",
|
|
2234
|
+
this.reject(e.id).catch((c) => this.emit("error", B(c)));
|
|
2014
2235
|
}), r.addEventListener("click", () => {
|
|
2015
|
-
this.accept(e.id).catch((c) => this.emit("error",
|
|
2236
|
+
this.accept(e.id).catch((c) => this.emit("error", B(c)));
|
|
2016
2237
|
}), s.appendChild(o), s.appendChild(r), t.appendChild(i), t.appendChild(n), t.appendChild(s), this.mount.replaceChildren(t);
|
|
2017
2238
|
}
|
|
2018
2239
|
dismiss(e) {
|
|
@@ -2080,7 +2301,7 @@ class Pe extends EventTarget {
|
|
|
2080
2301
|
const t = Math.max(0, e - this.refreshSkew(e));
|
|
2081
2302
|
this.tokenRefreshTimer = setTimeout(() => {
|
|
2082
2303
|
this.tokenRefreshTimer = null, this.resolveToken("expiring", !0).catch((i) => {
|
|
2083
|
-
this.emit("tokenerror",
|
|
2304
|
+
this.emit("tokenerror", B(i)), this.stopped || (this.tokenRefreshTimer = setTimeout(() => this.scheduleTokenRefresh(), 3e4));
|
|
2084
2305
|
});
|
|
2085
2306
|
}, Math.min(t, 2147e6));
|
|
2086
2307
|
}
|
|
@@ -2094,21 +2315,21 @@ class Pe extends EventTarget {
|
|
|
2094
2315
|
this.options.reportSignalingDiagnostics === !1 || this.stopped || this.request("/v1/rtc/client/signaling-events", {
|
|
2095
2316
|
method: "POST",
|
|
2096
2317
|
body: JSON.stringify({ ...e, occurredAt: (/* @__PURE__ */ new Date()).toISOString() })
|
|
2097
|
-
}).catch((t) => this.emit("diagnosticserror",
|
|
2318
|
+
}).catch((t) => this.emit("diagnosticserror", B(t)));
|
|
2098
2319
|
}
|
|
2099
2320
|
emit(e, t) {
|
|
2100
2321
|
const i = { type: e, detail: t, timestamp: (/* @__PURE__ */ new Date()).toISOString() };
|
|
2101
2322
|
this.dispatchEvent(new CustomEvent(e, { detail: i })), this.options.onEvent?.(i);
|
|
2102
2323
|
}
|
|
2103
2324
|
}
|
|
2104
|
-
function
|
|
2105
|
-
const e = new
|
|
2325
|
+
function gt(a) {
|
|
2326
|
+
const e = new Xe(a);
|
|
2106
2327
|
return a.autoConnect !== !1 && a.signalingUrl && e.connect(), e;
|
|
2107
2328
|
}
|
|
2108
|
-
function
|
|
2329
|
+
function de(a) {
|
|
2109
2330
|
return a ? typeof a == "string" ? document.querySelector(a) : a : null;
|
|
2110
2331
|
}
|
|
2111
|
-
function
|
|
2332
|
+
function he(a, e, t, i) {
|
|
2112
2333
|
const n = document.createElement("button");
|
|
2113
2334
|
return n.type = "button", n.textContent = a, Object.assign(n.style, {
|
|
2114
2335
|
minHeight: "44px",
|
|
@@ -2121,7 +2342,7 @@ function ae(a, e, t, i) {
|
|
|
2121
2342
|
fontWeight: "700"
|
|
2122
2343
|
}), n;
|
|
2123
2344
|
}
|
|
2124
|
-
function
|
|
2345
|
+
function Ze(a) {
|
|
2125
2346
|
return {
|
|
2126
2347
|
rejected: "Call declined",
|
|
2127
2348
|
busy: "Line busy",
|
|
@@ -2132,106 +2353,114 @@ function Ae(a) {
|
|
|
2132
2353
|
answered_elsewhere: "Answered on another device"
|
|
2133
2354
|
}[a] ?? "Call ended";
|
|
2134
2355
|
}
|
|
2135
|
-
function
|
|
2356
|
+
function ue(a) {
|
|
2136
2357
|
return {
|
|
2137
2358
|
id: a.participantId,
|
|
2138
2359
|
name: a.displayName,
|
|
2139
2360
|
role: "participant"
|
|
2140
2361
|
};
|
|
2141
2362
|
}
|
|
2142
|
-
async function
|
|
2363
|
+
async function et(a, e) {
|
|
2143
2364
|
const t = await a.getStats(), i = /* @__PURE__ */ new Map(), n = /* @__PURE__ */ new Map();
|
|
2144
|
-
let s = 0, o = 0, r = 0, c = 0, l = 0, d = 0, u = 0,
|
|
2365
|
+
let s = 0, o = 0, r = 0, c = 0, l = 0, d = 0, u = 0, v = 0, p = 0, S = 0, T = 0, y = 0, k = 0, f = 0, M = 0, R = null, L = null, P = null, A = null, w = null, E = null;
|
|
2145
2366
|
t.forEach((g) => {
|
|
2146
2367
|
n.set(g.id, g), g.type === "codec" && i.set(g.id, String(g.mimeType ?? ""));
|
|
2147
2368
|
}), t.forEach((g) => {
|
|
2148
|
-
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)),
|
|
2149
|
-
|
|
2150
|
-
const
|
|
2151
|
-
|
|
2369
|
+
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)), v = Math.max(v, Number(g.frameWidth ?? 0)), T = Math.max(T, Number(g.frameHeight ?? 0)), y += Number(g.framesDropped ?? 0), k += Number(g.freezeCount ?? 0), f += Number(g.totalFreezesDuration ?? 0), M += Number(g.concealedSamples ?? 0), w ||= i.get(String(g.codecId ?? "")) ?? null), g.type === "outbound-rtp" && !g.isRemote && (p = Math.max(p, Number(g.frameWidth ?? 0)), S = Math.max(S, Number(g.frameHeight ?? 0)), o += Number(g.bytesSent ?? 0), E ||= g.qualityLimitationReason ? String(g.qualityLimitationReason) : null, w ||= i.get(String(g.codecId ?? "")) ?? null), g.type === "candidate-pair" && (g.selected || g.nominated) && g.state === "succeeded") {
|
|
2370
|
+
R = Number.isFinite(g.currentRoundTripTime) ? Number(g.currentRoundTripTime) : R, L = Number.isFinite(g.availableOutgoingBitrate) ? Number(g.availableOutgoingBitrate) : L;
|
|
2371
|
+
const U = n.get(g.localCandidateId);
|
|
2372
|
+
P = U?.candidateType ? String(U.candidateType) : P, A = U?.protocol ? String(U.protocol) : A;
|
|
2152
2373
|
}
|
|
2153
2374
|
});
|
|
2154
|
-
const m = Date.now(), h = e ? Math.max(1e-3, (m - e.timestamp) / 1e3) : 0,
|
|
2375
|
+
const m = Date.now(), h = e ? Math.max(1e-3, (m - e.timestamp) / 1e3) : 0, b = e ? Math.max(0, Math.round((s - e.inboundBytes) * 8 / h)) : null, I = e ? Math.max(0, Math.round((o - e.outboundBytes) * 8 / h)) : null, C = r + c, N = e ? Math.max(0, r - e.packetsLost) : r, Q = e ? Math.max(0, c - e.packetsReceived) : c, O = N + Q;
|
|
2155
2376
|
return {
|
|
2156
2377
|
counters: { timestamp: m, inboundBytes: s, outboundBytes: o, packetsLost: r, packetsReceived: c },
|
|
2157
2378
|
sample: {
|
|
2158
|
-
rttMs:
|
|
2379
|
+
rttMs: R === null ? null : R * 1e3,
|
|
2159
2380
|
jitterMs: d ? l / d * 1e3 : null,
|
|
2160
|
-
packetLossPct:
|
|
2161
|
-
packetLossCumulativePct:
|
|
2381
|
+
packetLossPct: O ? N / O * 100 : null,
|
|
2382
|
+
packetLossCumulativePct: C ? r / C * 100 : null,
|
|
2162
2383
|
packetsLost: r,
|
|
2163
2384
|
packetsReceived: c,
|
|
2164
|
-
inboundBitrateBps:
|
|
2165
|
-
outboundBitrateBps:
|
|
2385
|
+
inboundBitrateBps: b,
|
|
2386
|
+
outboundBitrateBps: I,
|
|
2166
2387
|
availableOutgoingBitrateBps: L,
|
|
2167
2388
|
framesPerSecond: u || null,
|
|
2168
|
-
frameWidth:
|
|
2169
|
-
frameHeight:
|
|
2170
|
-
inboundFrameWidth:
|
|
2171
|
-
inboundFrameHeight:
|
|
2172
|
-
outboundFrameWidth:
|
|
2173
|
-
outboundFrameHeight:
|
|
2389
|
+
frameWidth: v || null,
|
|
2390
|
+
frameHeight: T || null,
|
|
2391
|
+
inboundFrameWidth: v || null,
|
|
2392
|
+
inboundFrameHeight: T || null,
|
|
2393
|
+
outboundFrameWidth: p || null,
|
|
2394
|
+
outboundFrameHeight: S || null,
|
|
2174
2395
|
framesDropped: y,
|
|
2175
|
-
freezeCount:
|
|
2176
|
-
freezeDurationMs: Math.round(
|
|
2177
|
-
concealedSamples:
|
|
2178
|
-
codec:
|
|
2396
|
+
freezeCount: k,
|
|
2397
|
+
freezeDurationMs: Math.round(f * 1e3),
|
|
2398
|
+
concealedSamples: M,
|
|
2399
|
+
codec: w,
|
|
2179
2400
|
transportProtocol: A,
|
|
2180
|
-
candidateType:
|
|
2181
|
-
qualityLimitationReason:
|
|
2401
|
+
candidateType: P,
|
|
2402
|
+
qualityLimitationReason: E
|
|
2182
2403
|
}
|
|
2183
2404
|
};
|
|
2184
2405
|
}
|
|
2185
|
-
function
|
|
2186
|
-
let e = a.mediaScore == null ? 5 : Math.round(
|
|
2187
|
-
const t =
|
|
2406
|
+
function tt(a) {
|
|
2407
|
+
let e = a.mediaScore == null ? 5 : Math.round(pe(Number(a.mediaScore), 0, 5));
|
|
2408
|
+
const t = Y(a.packetLossPct) ?? 0, i = Y(a.rttMs) ?? 0, n = Y(a.jitterMs) ?? 0, s = String(a.connectionState ?? "unknown").toLowerCase();
|
|
2188
2409
|
["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));
|
|
2189
|
-
const o = Number(
|
|
2410
|
+
const o = Number(pe(4.5 - t * 0.09 - i * 11e-4 - n * 6e-3, 1, 4.5).toFixed(2));
|
|
2190
2411
|
return { networkScore: e, estimatedMos: o };
|
|
2191
2412
|
}
|
|
2192
|
-
function
|
|
2413
|
+
function me() {
|
|
2193
2414
|
return navigator.connection ?? null;
|
|
2194
2415
|
}
|
|
2195
|
-
function
|
|
2416
|
+
function it() {
|
|
2196
2417
|
const a = Number(navigator.deviceMemory);
|
|
2197
2418
|
return Number.isFinite(a) ? a : null;
|
|
2198
2419
|
}
|
|
2199
|
-
function
|
|
2420
|
+
function Y(a) {
|
|
2200
2421
|
const e = Number(a);
|
|
2201
2422
|
return Number.isFinite(e) ? e : null;
|
|
2202
2423
|
}
|
|
2203
|
-
function
|
|
2424
|
+
function pe(a, e, t) {
|
|
2204
2425
|
return Math.min(t, Math.max(e, a));
|
|
2205
2426
|
}
|
|
2206
|
-
function
|
|
2427
|
+
function B(a) {
|
|
2207
2428
|
return a instanceof Error ? { name: a.name, message: a.message } : { name: "ServiceError", message: String(a ?? "Service request failed") };
|
|
2208
2429
|
}
|
|
2209
|
-
function
|
|
2430
|
+
function fe(a, e) {
|
|
2210
2431
|
return a instanceof Error ? a : new Error(e);
|
|
2211
2432
|
}
|
|
2212
|
-
const
|
|
2433
|
+
const nt = "1.3.25";
|
|
2213
2434
|
export {
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2435
|
+
_e as AVATAR_MODEL_MAX_BYTES,
|
|
2436
|
+
oe as AVATAR_TUNING_DEFAULTS,
|
|
2437
|
+
x as AvatarModelError,
|
|
2438
|
+
Ne as BACKGROUND_PRESETS,
|
|
2439
|
+
qe as OVERLAY_EFFECTS,
|
|
2440
|
+
Ge as RtcClient,
|
|
2441
|
+
Xe as RtcIncomingClient,
|
|
2442
|
+
at as SPEAKER_NOISE_FLOOR,
|
|
2443
|
+
st as SPEAKER_TAKEOVER_RATIO,
|
|
2444
|
+
lt as createAvatarPipeline,
|
|
2445
|
+
ot as createCallRecorder,
|
|
2446
|
+
rt as createPictureInPictureController,
|
|
2447
|
+
ft as createRtcClient,
|
|
2448
|
+
gt as createRtcIncomingClient,
|
|
2449
|
+
ct as createVideoEffectsPipeline,
|
|
2450
|
+
je as drawAvatar,
|
|
2451
|
+
Oe as headPoseFromMatrix,
|
|
2452
|
+
ht as importAvatarModel,
|
|
2453
|
+
dt as listArchiveModels,
|
|
2454
|
+
ut as listAvatarModels,
|
|
2455
|
+
ve as neutralRig,
|
|
2456
|
+
ge as pickActiveSpeaker,
|
|
2457
|
+
mt as readAvatarModel,
|
|
2458
|
+
$e as readAvatarModelMetadata,
|
|
2459
|
+
pt as removeAvatarModel,
|
|
2460
|
+
Ve as rigFromBlendshapes,
|
|
2461
|
+
se as scenePainters,
|
|
2462
|
+
re as smoothRig,
|
|
2463
|
+
ce as stylizedAvatarRenderer,
|
|
2464
|
+
Ye as unlockRtcCallAudio,
|
|
2465
|
+
nt as version
|
|
2237
2466
|
};
|