@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.
@@ -1,11 +1,11 @@
1
- const qe = 0.02, Oe = 1.4;
2
- function oe(a, e, t = 0.02, i = 1.4) {
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 ce(a) {
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 j = {
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
- }, he = {
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 ue(a) {
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 me(a, e, t, i, n = {}) {
40
- const s = { ...he, ...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 = ue(e.qualityLimitationReason), f = e.packetLossPct ?? 0, v = e.rttMs ?? 0, C = e.availableOutgoingBitrateBps, y = j[a].maxBitrate, w = f >= s.criticalLossPct || v >= s.criticalRttMs || k === "cpu", p = k === "bandwidth" && (C == null || C < y * s.bandwidthHeadroomRatio), R = w || f >= s.poorLossPct || v >= s.poorRttMs || p, P = C == null || C >= y * s.sustainRatio, L = f < s.goodLossPct && v < s.goodRttMs && !k && P, I = R ? t + 1 : 0, A = L ? i + 1 : 0, S = { quality: a, poorSamples: I, goodSamples: A, samplesSeen: d, changed: !1 };
41
- return l > c ? { quality: o[c], poorSamples: 0, goodSamples: 0, samplesSeen: d, changed: !0 } : u ? S : w && l > 0 ? { quality: o[l - 1], poorSamples: 0, goodSamples: 0, samplesSeen: d, changed: !0 } : I >= s.poorSamplesToStepDown && l > 0 ? { quality: o[l - 1], poorSamples: 0, goodSamples: 0, samplesSeen: d, changed: !0 } : A >= s.goodSamplesToStepUp && l < c ? { quality: o[l + 1], poorSamples: 0, goodSamples: 0, samplesSeen: d, changed: !0 } : S;
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 pe(a, e) {
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
- const fe = {
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
- }, ge = { active: !0, maxBitrate: 4e6, maxFramerate: 30, scaleResolutionDownBy: 1 };
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 = new URL(t.signalingUrl, globalThis.location?.href);
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 ? ge : this.quality === "audio" ? fe.audio : j[e.quality], o = i.getParameters(), r = o.encodings?.length ? o.encodings : [{}];
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 ce(n.values()))
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 = oe(e, this.activeSpeaker);
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 } = pe(t, e.counters);
438
+ const { sample: i, counters: n } = ge(t, e.counters);
433
439
  e.counters = n;
434
- const s = me(e.quality, i, e.poorSamples, e.goodSamples, {
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 }, Y = [
503
- { rid: "a", maxBitrate: j.high.maxBitrate, maxFramerate: j.high.maxFramerate },
504
- { rid: "b", maxBitrate: j.medium.maxBitrate, maxFramerate: j.medium.maxFramerate, scaleResolutionDownBy: 2 },
505
- { rid: "c", maxBitrate: j.low.maxBitrate, maxFramerate: j.low.maxFramerate, scaleResolutionDownBy: 4 }
506
- ], G = { high: "a", medium: "b", low: "c" };
507
- class ye {
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 = new URL(e.credential.signalingUrl, globalThis.location?.href).origin;
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 = new URL(t.signalingUrl, globalThis.location?.href);
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: Y.map((c) => ({ ...c })) } : {}
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: G[t], priorityOrdering: "asciibetical", ridNotAvailable: "asciibetical" }
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 : G[this.quality];
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 = Y.find((d) => d.rid === r.rid), l = o != null && String(r.rid ?? "") >= o;
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" ? j.audio : j[this.quality], r = i ? H : o;
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 ce(t.values())) {
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 = oe(i, this.activeSpeaker);
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 ?? ve(),
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 ve() {
948
+ function ke() {
945
949
  return globalThis.crypto?.randomUUID?.() ?? `${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`;
946
950
  }
947
- function Ne(a, e = {}) {
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 je(a, e) {
976
- const t = e.document ?? globalThis.document, i = e.fetchImplementation ?? globalThis.fetch.bind(globalThis), n = new URL(e.credential.signalingUrl, globalThis.location?.href).origin, s = e.mimeType ?? "video/webm", o = e.height ?? 720, r = Math.round(o * 16 / 9);
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 O = Math.max(1, Math.ceil(Math.sqrt(b.length))), V = Math.max(1, Math.ceil(b.length / O)), N = r / O, g = o / V;
1011
- b.forEach((q, $) => {
1012
- const J = P(q.key, q.stream), B = $ % O * N, F = Math.floor($ / O) * g;
1013
- J.videoWidth > 0 && p.drawImage(J, 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
+ 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 I = d.createMediaStreamDestination(), A = /* @__PURE__ */ new Set(), S = () => {
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(I));
1029
+ A.has(b.id) || (A.add(b.id), d.createMediaStreamSource(new MediaStream([b])).connect(E));
1026
1030
  };
1027
1031
  S();
1028
- const E = setInterval(S, 1e3), m = () => clearInterval(E);
1029
- for (const T of I.stream.getAudioTracks()) L.addTrack(T);
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((I) => y.addEventListener("stop", () => I(), { once: !0 }));
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 Se = ["none", "blur", "aurora", "cybergrid", "bokeh", "sunset", "image"], ke = ["none", "snow", "confetti", "vignette"], K = {
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 xe(a, e = {}) {
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 I() {
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 && I()) : c === "image" && d ? (y.drawImage(d, 0, 0, i, n), I()) : ((K[c] ?? K.aurora)(y, i, n, m), I()), l === "snow" || l === "confetti")
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)), E = C.captureStream(o);
1159
+ }, Math.round(1e3 / o)), I = C.captureStream(o);
1156
1160
  return {
1157
- track: E.getVideoTracks()[0],
1158
- stream: E,
1161
+ track: I.getVideoTracks()[0],
1162
+ stream: I,
1159
1163
  setBackground(m, h) {
1160
- c = Se.includes(m) ? m : "none", h !== void 0 && (d = h), c === "none" && (k = null);
1164
+ c = we.includes(m) ? m : "none", h !== void 0 && (d = h), c === "none" && (k = null);
1161
1165
  },
1162
1166
  setOverlay(m) {
1163
- l = ke.includes(m) ? m : "none";
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 E.getTracks()) m.stop();
1174
+ for (const m of I.getTracks()) m.stop();
1171
1175
  v.srcObject = null;
1172
1176
  }
1173
1177
  };
1174
1178
  }
1175
- function le() {
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 we(a) {
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 Te(a, e, t = 1) {
1201
- if (!a || a.length === 0) return le();
1202
- const i = we(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;
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 X(a, e, t = 0.4) {
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 be(a, e, t, i, n) {
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, E = k(S);
1245
- if (E <= 0.12) continue;
1246
- const m = u(S) * 0.82, h = Math.max(0.2, E), T = A < 0 ? e.blinkLeft : e.blinkRight, M = Math.max(0.06, 1 - T), b = e.browUp * r * 0.14;
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 O = -r * 0.18 + f;
1249
- a.fillStyle = "#ffffff", a.beginPath(), a.ellipse(m, O, r * 0.16 * h, r * 0.12 * M, 0, 0, Math.PI * 2), a.fill(), a.fillStyle = "#22303c", a.beginPath(), a.ellipse(
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
- O + e.pupilY * r * 0.05,
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, I = r * 0.42 + f;
1260
- a.fillStyle = "#8c2f2f", a.beginPath(), a.moveTo(p - R / 2, I - L), a.quadraticCurveTo(p, I + P, p + R / 2, I - L), a.quadraticCurveTo(p, I - P * 0.25, p - R / 2, I - L), a.closePath(), a.fill(), a.restore(), !e.tracked && !n && (a.fillStyle = "#9fb0bd", a.font = `${Math.round(i * 0.045)}px system-ui`, a.textAlign = "center", a.fillText("No face detected", t / 2, i * 0.9), a.textAlign = "left");
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 Z = {
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 ee() {
1275
+ function ie() {
1272
1276
  return {
1273
1277
  render(a, e, t, i, n) {
1274
- be(a, e, t, i, n ?? void 0);
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 Ve(a, e = {}) {
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 ?? ee(), d = e.mode ?? "replace";
1285
- const u = { ...Z, ...e.tuning }, k = e.backdrop ?? "#101822", f = t.createElement("video");
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, E = f.videoHeight;
1293
- if (!S || !E) return;
1294
- const m = Math.min(1, 1280 / Math.max(S, E)), h = Math.round(S * m), T = Math.round(E * m);
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 = le(), p = null, R = 0;
1302
+ let w = he(), p = null, R = 0;
1299
1303
  function P(S) {
1300
1304
  if (S.length <= 454) return;
1301
- const E = S[10], m = S[152], h = S[234], T = S[454], M = (h.x + T.x) / 2 * i, b = (h.y + T.y) / 2 * n, O = Math.hypot((m.x - E.x) * i, (m.y - E.y) * n), V = Math.max(0.6, Math.cos(w.headPitch)), N = { x: M, y: b, radius: Math.max(24, O / V * 0.8) };
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 = Te(m?.categories ?? null, m?.matrix ?? null, u.eyeSync);
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 = X(w, h, u.smoothing), m?.landmarks && P(m.landmarks)) : w.tracked && S - R > u.lostHoldMs && (w = X(w, { ...w, jawOpen: 0, browUp: 0, smile: w.smile * 0.5, blinkLeft: 0.1, blinkRight: 0.1 }, 0.05));
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 E = p ? { x: p.x, y: p.y + u.avatarLift * p.radius, radius: p.radius * u.avatarScale } : null;
1316
- l?.render(C, w, i, n, E);
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 I = setInterval(() => L(Date.now()), Math.round(1e3 / o)), A = v.captureStream(o);
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 ?? ee();
1334
+ l?.dispose?.(), l = S ?? ie();
1331
1335
  },
1332
1336
  setTuning(S) {
1333
- for (const E of Object.keys(Z)) {
1334
- const m = S[E];
1335
- typeof m == "number" && Number.isFinite(m) && (u[E] = m);
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(I), c?.close?.(), l?.dispose?.();
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 Ce extends EventTarget {
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" ? ye : Q;
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: De }), this.options.autoJoin && await this.join(), this;
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 = re(e, "RTC initialization failed");
1404
- throw this.emit("error", x(t)), t;
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 = re(t, "RTC connection failed");
1412
- throw this.emit("error", x(i)), i;
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(ne);
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: ne(e.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: ae()?.effectiveType ?? null,
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 Pe(this.peerConnection, this.previousCounters) : null;
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: Le(),
1598
- effectiveConnectionType: ae()?.effectiveType ?? null
1599
- }, ...i?.sample ?? {}, ...t, sampleType: e, sampledAt: (/* @__PURE__ */ new Date()).toISOString() }, o = Ae(s);
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", x(t));
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 Ue(a) {
1685
- return new Ce(a).initialize();
1688
+ async function Be(a) {
1689
+ return new Ee(a).initialize();
1686
1690
  }
1687
1691
  let U = null;
1688
- function de() {
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 Re() {
1694
- const a = de();
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 Ie {
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 Re();
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 = de();
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 Ee extends EventTarget {
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 Ie(e), this.mount = te(e.mount), this.scheduleTokenRefresh();
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 = te(e), this.currentCall && this.renderIncoming(this.currentCall);
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 && ["rejected", "busy", "cancelled", "ended", "failed", "missed"].includes(e.status) && this.showTerminal(e.id, Me(e.status)), ["rejected", "busy", "cancelled", "ended", "failed", "missed"].includes(e.status) && this.releaseMedia(e.id), this.emit("callupdated", e);
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", x(s)), !this.stopped && this.options.reconnect !== !1 && this.scheduleReconnect();
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 = new URL(this.options.signalingUrl, globalThis.location?.href);
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 = new URL(n, globalThis.location?.href), o = await this.resolveToken("initial"), r = new Headers(t.headers);
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 = ie("Decline", "#fff", "#a32920", "#d9a09b"), r = ie("Answer", "#fff", "#08745f", "#08745f");
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", x(c)));
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", x(c)));
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", x(i)), this.stopped || (this.tokenRefreshTimer = setTimeout(() => this.scheduleTokenRefresh(), 3e4));
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", x(t)));
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 Qe(a) {
2071
- const e = new Ee(a);
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 te(a) {
2104
+ function ne(a) {
2075
2105
  return a ? typeof a == "string" ? document.querySelector(a) : a : null;
2076
2106
  }
2077
- function ie(a, e, t, i) {
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 Me(a) {
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 ne(a) {
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 Pe(a, e) {
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, I = null, A = null, S = null, E = 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), E ||= g.qualityLimitationReason ? String(g.qualityLimitationReason) : null, S ||= i.get(String(g.codecId ?? "")) ?? null), g.type === "candidate-pair" && (g.selected || g.nominated) && g.state === "succeeded") {
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
- I = q?.candidateType ? String(q.candidateType) : I, A = q?.protocol ? String(q.protocol) : A;
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, O = e ? Math.max(0, r - e.packetsLost) : r, V = e ? Math.max(0, c - e.packetsReceived) : c, N = O + V;
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 ? O / N * 100 : null,
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: I,
2146
- qualityLimitationReason: E
2176
+ candidateType: E,
2177
+ qualityLimitationReason: I
2147
2178
  }
2148
2179
  };
2149
2180
  }
2150
- function Ae(a) {
2151
- let e = a.mediaScore == null ? 5 : Math.round(se(Number(a.mediaScore), 0, 5));
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(se(4.5 - t * 0.09 - i * 11e-4 - n * 6e-3, 1, 4.5).toFixed(2));
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 ae() {
2188
+ function re() {
2158
2189
  return navigator.connection ?? null;
2159
2190
  }
2160
- function Le() {
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 se(a, e, t) {
2199
+ function oe(a, e, t) {
2169
2200
  return Math.min(t, Math.max(e, a));
2170
2201
  }
2171
- function x(a) {
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 re(a, e) {
2205
+ function ce(a, e) {
2175
2206
  return a instanceof Error ? a : new Error(e);
2176
2207
  }
2177
- const De = "1.3.21";
2208
+ const xe = "1.3.23";
2178
2209
  export {
2179
- Z as AVATAR_TUNING_DEFAULTS,
2180
- Se as BACKGROUND_PRESETS,
2181
- ke as OVERLAY_EFFECTS,
2182
- Ce as RtcClient,
2183
- Ee as RtcIncomingClient,
2184
- qe as SPEAKER_NOISE_FLOOR,
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
- Ve as createAvatarPipeline,
2187
- je as createCallRecorder,
2188
- Ne as createPictureInPictureController,
2189
- Ue as createRtcClient,
2190
- Qe as createRtcIncomingClient,
2191
- xe as createVideoEffectsPipeline,
2192
- be as drawAvatar,
2193
- we as headPoseFromMatrix,
2194
- le as neutralRig,
2195
- oe as pickActiveSpeaker,
2196
- Te as rigFromBlendshapes,
2197
- K as scenePainters,
2198
- X as smoothRig,
2199
- ee as stylizedAvatarRenderer,
2200
- Re as unlockRtcCallAudio,
2201
- De as version
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
  };