@streaming-cdn/rtc-web 1.3.16 → 1.3.18

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.
@@ -14,7 +14,7 @@ function ce(a) {
14
14
  }
15
15
  return e;
16
16
  }
17
- const O = {
17
+ const N = {
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 },
@@ -36,41 +36,41 @@ function ue(a) {
36
36
  return !e || e === "none" ? "" : e === "cpu" || e === "bandwidth" ? e : "other";
37
37
  }
38
38
  function me(a, e, t, i, n = {}) {
39
- const s = { ...he, ...n.thresholds }, o = ["low", "medium", "high"], r = n.ceiling && n.ceiling !== "audio" ? n.ceiling : "high", c = o.indexOf(r), d = o.indexOf(a), l = (n.samplesSeen ?? s.warmupSamples) + 1, u = l <= s.warmupSamples, y = ue(e.qualityLimitationReason), f = e.packetLossPct ?? 0, w = e.rttMs ?? 0, m = e.availableOutgoingBitrateBps, S = O[a].maxBitrate, T = f >= s.criticalLossPct || w >= s.criticalRttMs || y === "cpu", k = T || f >= s.poorLossPct || w >= s.poorRttMs || y === "bandwidth", b = m == null || m >= S * s.sustainRatio, M = f < s.goodLossPct && w < s.goodRttMs && !y && b, I = k ? t + 1 : 0, g = M ? i + 1 : 0, p = { quality: a, poorSamples: I, goodSamples: g, samplesSeen: l, changed: !1 };
40
- return d > c ? { quality: o[c], poorSamples: 0, goodSamples: 0, samplesSeen: l, changed: !0 } : u ? p : T && d > 0 ? { quality: o[d - 1], poorSamples: 0, goodSamples: 0, samplesSeen: l, changed: !0 } : I >= s.poorSamplesToStepDown && d > 0 ? { quality: o[d - 1], poorSamples: 0, goodSamples: 0, samplesSeen: l, changed: !0 } : g >= s.goodSamplesToStepUp && d < c ? { quality: o[d + 1], poorSamples: 0, goodSamples: 0, samplesSeen: l, changed: !0 } : p;
39
+ 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, S = ue(e.qualityLimitationReason), f = e.packetLossPct ?? 0, v = e.rttMs ?? 0, I = e.availableOutgoingBitrateBps, y = N[a].maxBitrate, k = f >= s.criticalLossPct || v >= s.criticalRttMs || S === "cpu", p = k || f >= s.poorLossPct || v >= s.poorRttMs || S === "bandwidth", C = I == null || I >= y * s.sustainRatio, P = f < s.goodLossPct && v < s.goodRttMs && !S && C, L = p ? t + 1 : 0, E = P ? i + 1 : 0, A = { quality: a, poorSamples: L, goodSamples: E, samplesSeen: d, changed: !1 };
40
+ return l > c ? { quality: o[c], poorSamples: 0, goodSamples: 0, samplesSeen: d, changed: !0 } : u ? A : k && l > 0 ? { quality: o[l - 1], poorSamples: 0, goodSamples: 0, samplesSeen: d, changed: !0 } : L >= 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 } : A;
41
41
  }
42
42
  function pe(a, e) {
43
43
  const t = a instanceof Map ? a : new Map(a);
44
44
  let i = 0, n = 0, s = null, o = null, r = null;
45
- for (const l of t.values()) {
46
- const u = String(l.type ?? "");
47
- if (u === "outbound-rtp" && String(l.kind ?? "") === "video" && (i += Number(l.packetsSent ?? 0), s = l.qualityLimitationReason ?? s), u === "remote-inbound-rtp" && String(l.kind ?? "") === "video") {
48
- n += Number(l.packetsLost ?? 0);
49
- const y = Number(l.roundTripTime ?? NaN);
50
- Number.isFinite(y) && (o = y * 1e3);
45
+ for (const d of t.values()) {
46
+ const u = String(d.type ?? "");
47
+ if (u === "outbound-rtp" && String(d.kind ?? "") === "video" && (i += Number(d.packetsSent ?? 0), s = d.qualityLimitationReason ?? s), u === "remote-inbound-rtp" && String(d.kind ?? "") === "video") {
48
+ n += Number(d.packetsLost ?? 0);
49
+ const S = Number(d.roundTripTime ?? NaN);
50
+ Number.isFinite(S) && (o = S * 1e3);
51
51
  }
52
- if (u === "candidate-pair" && (l.nominated === !0 || String(l.state ?? "") === "succeeded")) {
53
- const y = Number(l.currentRoundTripTime ?? NaN);
54
- o == null && Number.isFinite(y) && (o = y * 1e3);
55
- const f = Number(l.availableOutgoingBitrate ?? NaN);
52
+ if (u === "candidate-pair" && (d.nominated === !0 || String(d.state ?? "") === "succeeded")) {
53
+ const S = Number(d.currentRoundTripTime ?? NaN);
54
+ o == null && Number.isFinite(S) && (o = S * 1e3);
55
+ const f = Number(d.availableOutgoingBitrate ?? NaN);
56
56
  Number.isFinite(f) && (r = f);
57
57
  }
58
58
  }
59
59
  const c = { packetsSent: i, packetsLost: n, timestamp: Date.now() };
60
- let d = null;
60
+ let l = null;
61
61
  if (e) {
62
- const l = i - e.packetsSent, u = n - e.packetsLost;
63
- l > 0 && u >= 0 && (d = u / (l + u) * 100);
62
+ const d = i - e.packetsSent, u = n - e.packetsLost;
63
+ d > 0 && u >= 0 && (l = u / (d + u) * 100);
64
64
  }
65
65
  return {
66
- sample: { packetLossPct: d, rttMs: o, availableOutgoingBitrateBps: r, qualityLimitationReason: s },
66
+ sample: { packetLossPct: l, rttMs: o, availableOutgoingBitrateBps: r, qualityLimitationReason: s },
67
67
  counters: c
68
68
  };
69
69
  }
70
70
  const fe = {
71
71
  audio: { active: !1, maxBitrate: 0, maxFramerate: 0, scaleResolutionDownBy: 4 }
72
72
  }, ge = { active: !0, maxBitrate: 4e6, maxFramerate: 30, scaleResolutionDownBy: 1 };
73
- class x {
73
+ class Q {
74
74
  options;
75
75
  socket = null;
76
76
  localStream = null;
@@ -159,7 +159,7 @@ class x {
159
159
  return;
160
160
  }
161
161
  for (const r of this.peers.values()) {
162
- const c = r.connection.getSenders().find((d) => d.track?.kind === s);
162
+ const c = r.connection.getSenders().find((l) => l.track?.kind === s);
163
163
  c ? await c.replaceTrack(n) : r.connection.addTrack(n, this.localStream);
164
164
  }
165
165
  await this.applyVideoQuality();
@@ -168,7 +168,7 @@ class x {
168
168
  this.quality = e;
169
169
  for (const t of this.localStream?.getVideoTracks() ?? []) t.enabled = e !== "audio";
170
170
  for (const t of this.peers.values())
171
- t.quality = x.clampToCeiling(t.quality, e), t.poorSamples = 0, t.goodSamples = 0;
171
+ t.quality = Q.clampToCeiling(t.quality, e), t.poorSamples = 0, t.goodSamples = 0;
172
172
  await this.applyVideoQuality();
173
173
  }
174
174
  static clampToCeiling(e, t) {
@@ -214,26 +214,26 @@ class x {
214
214
  async openSocket(e) {
215
215
  const { credential: t } = this.options, i = new URL(t.signalingUrl, globalThis.location?.href);
216
216
  i.protocol = i.protocol === "https:" ? "wss:" : "ws:";
217
- const n = new Promise((c, d) => {
218
- this.resolveJoin = c, this.rejectJoin = d;
217
+ const n = new Promise((c, l) => {
218
+ this.resolveJoin = c, this.rejectJoin = l;
219
219
  }), s = new WebSocket(i, ["rtc-client", t.signalingToken]), o = ++this.socketGeneration;
220
220
  this.socket = s;
221
221
  const r = setTimeout(() => this.rejectJoin?.(new Error("RTC signaling timed out")), 15e3);
222
222
  s.addEventListener("open", () => {
223
223
  this.heartbeatDeadline = Date.now() + 45e3, this.startHeartbeat(s), this.startQualitySampling(), this.send({ type: "rtc.room.join" });
224
224
  }), s.addEventListener("message", (c) => {
225
- const d = String(c.data);
225
+ const l = String(c.data);
226
226
  this.signalQueue = this.signalQueue.then(async () => {
227
- this.socket !== s || this.socketGeneration !== o || await this.handleSignal(d);
228
- }).catch((l) => {
229
- const u = l instanceof Error ? l.message : "RTC signaling processing failed";
227
+ this.socket !== s || this.socketGeneration !== o || await this.handleSignal(l);
228
+ }).catch((d) => {
229
+ const u = d instanceof Error ? d.message : "RTC signaling processing failed";
230
230
  this.options.onEvent("signalingerror", { message: u }), this.joined || this.rejectJoin?.(new Error(u));
231
231
  });
232
232
  }), s.addEventListener("error", () => this.rejectJoin?.(new Error("RTC signaling connection failed"))), s.addEventListener("close", (c) => {
233
233
  if (this.socket !== s) return;
234
234
  this.socket = null, this.stopHeartbeat(), this.stopQualitySampling(), !this.joined && !e && this.rejectJoin?.(new Error(c.reason || "RTC signaling connection closed"));
235
- const d = !this.stopped && (this.joined || e);
236
- this.joined = !1, d ? (this.resetPeers(), this.options.onEvent("reconnecting", { reason: c.reason, code: c.code, attempt: this.reconnectAttempt + 1 }), this.scheduleReconnect()) : this.stopped || this.options.onEvent("disconnected", { reason: c.reason, code: c.code });
235
+ const l = !this.stopped && (this.joined || e);
236
+ this.joined = !1, l ? (this.resetPeers(), this.options.onEvent("reconnecting", { reason: c.reason, code: c.code, attempt: this.reconnectAttempt + 1 }), this.scheduleReconnect()) : this.stopped || this.options.onEvent("disconnected", { reason: c.reason, code: c.code });
237
237
  });
238
238
  try {
239
239
  await n, this.joined = !0, this.options.onEvent("connected", { participantId: t.participantId, resumed: e });
@@ -313,7 +313,7 @@ class x {
313
313
  makingOffer: !1,
314
314
  offerTask: null,
315
315
  activeNegotiationId: null,
316
- quality: x.startingQuality(this.quality),
316
+ quality: Q.startingQuality(this.quality),
317
317
  poorSamples: 0,
318
318
  goodSamples: 0,
319
319
  samplesSeen: 0,
@@ -325,7 +325,7 @@ class x {
325
325
  return r && o && (s.videoSender = i.addTrack(r, o)), !this.localStream?.getAudioTracks().length && this.options.receiveAudio && i.addTransceiver("audio", { direction: "recvonly" }), !r && this.options.receiveVideo && (s.videoTransceiver = i.addTransceiver("video", { direction: "recvonly" }), s.videoSender = s.videoTransceiver.sender), this.applyCodecPreference(i), this.applyVideoQuality(i), i.addEventListener("icecandidate", (c) => {
326
326
  c.candidate && this.send({ type: "rtc.ice", targetParticipantId: e.participantId, candidate: c.candidate.toJSON() });
327
327
  }), i.addEventListener("track", (c) => {
328
- n.getTracks().some((d) => d.id === c.track.id) || n.addTrack(c.track), this.options.onEvent("remotestream", { participant: e, stream: n, track: c.track });
328
+ n.getTracks().some((l) => l.id === c.track.id) || n.addTrack(c.track), this.options.onEvent("remotestream", { participant: e, stream: n, track: c.track });
329
329
  }), i.addEventListener("connectionstatechange", () => {
330
330
  ["failed", "closed"].includes(i.connectionState) && this.removePeer(e.participantId), this.options.onEvent("peerconnectionstate", { participant: e, state: i.connectionState });
331
331
  }), s;
@@ -351,7 +351,7 @@ class x {
351
351
  });
352
352
  if (e.connection.signalingState !== "stable") return;
353
353
  await e.connection.setLocalDescription(t);
354
- const i = W();
354
+ const i = _();
355
355
  e.activeNegotiationId = i, this.send({
356
356
  type: "rtc.offer",
357
357
  targetParticipantId: e.identity.participantId,
@@ -391,7 +391,7 @@ class x {
391
391
  async applyPeerVideoQuality(e) {
392
392
  const t = this.screenStream?.getVideoTracks()[0]?.id;
393
393
  for (const i of e.connection.getSenders().filter((n) => n.track?.kind === "video")) {
394
- const n = !!(t && i.track?.id === t), s = n ? ge : this.quality === "audio" ? fe.audio : O[e.quality], o = i.getParameters(), r = o.encodings?.length ? o.encodings : [{}];
394
+ const n = !!(t && i.track?.id === t), s = n ? ge : this.quality === "audio" ? fe.audio : N[e.quality], o = i.getParameters(), r = o.encodings?.length ? o.encodings : [{}];
395
395
  o.encodings = r.map((c) => ({ ...c, ...s })), o.degradationPreference = n ? "maintain-resolution" : "maintain-framerate", await i.setParameters(o);
396
396
  }
397
397
  }
@@ -487,7 +487,7 @@ class x {
487
487
  }
488
488
  send(e) {
489
489
  this.socket?.readyState === WebSocket.OPEN && this.socket.send(JSON.stringify({
490
- clientMessageId: e.clientMessageId ?? W(),
490
+ clientMessageId: e.clientMessageId ?? _(),
491
491
  ...e
492
492
  }));
493
493
  }
@@ -495,13 +495,13 @@ class x {
495
495
  for (const t of e?.getTracks() ?? []) t.stop();
496
496
  }
497
497
  }
498
- function W() {
498
+ function _() {
499
499
  return globalThis.crypto?.randomUUID?.() ?? `${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`;
500
500
  }
501
- const $ = { active: !0, maxBitrate: 4e6, maxFramerate: 30, scaleResolutionDownBy: 1 }, Y = [
502
- { rid: "a", maxBitrate: O.high.maxBitrate, maxFramerate: O.high.maxFramerate },
503
- { rid: "b", maxBitrate: O.medium.maxBitrate, maxFramerate: O.medium.maxFramerate, scaleResolutionDownBy: 2 },
504
- { rid: "c", maxBitrate: O.low.maxBitrate, maxFramerate: O.low.maxFramerate, scaleResolutionDownBy: 4 }
501
+ const z = { active: !0, maxBitrate: 4e6, maxFramerate: 30, scaleResolutionDownBy: 1 }, Y = [
502
+ { rid: "a", maxBitrate: N.high.maxBitrate, maxFramerate: N.high.maxFramerate },
503
+ { rid: "b", maxBitrate: N.medium.maxBitrate, maxFramerate: N.medium.maxFramerate, scaleResolutionDownBy: 2 },
504
+ { rid: "c", maxBitrate: N.low.maxBitrate, maxFramerate: N.low.maxFramerate, scaleResolutionDownBy: 4 }
505
505
  ], G = { high: "a", medium: "b", low: "c" };
506
506
  class ye {
507
507
  options;
@@ -638,26 +638,26 @@ class ye {
638
638
  async openSocket(e) {
639
639
  const { credential: t } = this.options, i = new URL(t.signalingUrl, globalThis.location?.href);
640
640
  i.protocol = i.protocol === "https:" ? "wss:" : "ws:";
641
- const n = new Promise((c, d) => {
642
- this.resolveJoin = c, this.rejectJoin = d;
641
+ const n = new Promise((c, l) => {
642
+ this.resolveJoin = c, this.rejectJoin = l;
643
643
  }), s = new WebSocket(i, ["rtc-client", t.signalingToken]), o = ++this.socketGeneration;
644
644
  this.socket = s;
645
645
  const r = setTimeout(() => this.rejectJoin?.(new Error("RTC signaling timed out")), 15e3);
646
646
  s.addEventListener("open", () => {
647
647
  this.heartbeatDeadline = Date.now() + 45e3, this.startHeartbeat(s), this.send({ type: "rtc.room.join" });
648
648
  }), s.addEventListener("message", (c) => {
649
- const d = String(c.data);
649
+ const l = String(c.data);
650
650
  this.signalQueue = this.signalQueue.then(async () => {
651
- this.socket !== s || this.socketGeneration !== o || await this.handleSignal(d);
652
- }).catch((l) => {
653
- const u = l instanceof Error ? l.message : "RTC signaling processing failed";
651
+ this.socket !== s || this.socketGeneration !== o || await this.handleSignal(l);
652
+ }).catch((d) => {
653
+ const u = d instanceof Error ? d.message : "RTC signaling processing failed";
654
654
  this.options.onEvent("signalingerror", { message: u }), this.joined || this.rejectJoin?.(new Error(u));
655
655
  });
656
656
  }), s.addEventListener("error", () => this.rejectJoin?.(new Error("RTC signaling connection failed"))), s.addEventListener("close", (c) => {
657
657
  if (this.socket !== s) return;
658
658
  this.socket = null, this.stopHeartbeat(), !this.joined && !e && this.rejectJoin?.(new Error(c.reason || "RTC signaling connection closed"));
659
- const d = !this.stopped && (this.joined || e);
660
- this.joined = !1, d ? (this.options.onEvent("reconnecting", { reason: c.reason, code: c.code, attempt: this.reconnectAttempt + 1 }), this.scheduleReconnect()) : this.stopped || this.options.onEvent("disconnected", { reason: c.reason, code: c.code });
659
+ const l = !this.stopped && (this.joined || e);
660
+ this.joined = !1, l ? (this.options.onEvent("reconnecting", { reason: c.reason, code: c.code, attempt: this.reconnectAttempt + 1 }), this.scheduleReconnect()) : this.stopped || this.options.onEvent("disconnected", { reason: c.reason, code: c.code });
661
661
  });
662
662
  try {
663
663
  await n, this.joined = !0, this.options.onEvent("connected", { participantId: t.participantId, resumed: e });
@@ -718,7 +718,10 @@ class ye {
718
718
  const n = e.map((r) => t.addTransceiver(r, {
719
719
  direction: "sendonly",
720
720
  streams: this.localStream ? [this.localStream] : [],
721
- ...r.kind === "video" ? { sendEncodings: Y.map((c) => ({ ...c })) } : {}
721
+ // A single encoding when simulcast is off: constrained publishers
722
+ // (phone CPU, cellular uplink) should not pay for three encoders. The
723
+ // quality ladder then adapts that one encoding instead of gating layers.
724
+ ...r.kind === "video" && this.simulcastEnabled() ? { sendEncodings: Y.map((c) => ({ ...c })) } : {}
722
725
  })), s = await t.createOffer();
723
726
  await t.setLocalDescription(s);
724
727
  const o = await this.sfuFetch(
@@ -742,7 +745,7 @@ class ye {
742
745
  if (!this.sessionId) return;
743
746
  const e = [
744
747
  ...(this.localStream?.getAudioTracks() ?? []).map((t) => ({ trackName: this.trackName(t), kind: t.kind, simulcast: !1 })),
745
- ...(this.localStream?.getVideoTracks() ?? []).map((t) => ({ trackName: this.trackName(t), kind: t.kind, simulcast: !0 }))
748
+ ...(this.localStream?.getVideoTracks() ?? []).map((t) => ({ trackName: this.trackName(t), kind: t.kind, simulcast: this.simulcastEnabled() }))
746
749
  ];
747
750
  e.length !== 0 && this.sendControl("sfu.tracks", { sessionId: this.sessionId, tracks: e });
748
751
  }
@@ -825,6 +828,9 @@ class ye {
825
828
  async replaceVideoTrack(e) {
826
829
  this.videoSender && (await this.videoSender.replaceTrack(e), await this.applyVideoQuality());
827
830
  }
831
+ simulcastEnabled() {
832
+ return this.options.simulcast !== !1;
833
+ }
828
834
  async applyVideoQuality() {
829
835
  const e = this.videoSender;
830
836
  if (!e) return;
@@ -833,12 +839,12 @@ class ye {
833
839
  const o = this.quality === "audio" ? null : G[this.quality];
834
840
  n.encodings = s.map((r) => {
835
841
  if (i)
836
- return { ...r, active: r.rid === "a", ...r.rid === "a" ? { maxBitrate: $.maxBitrate, maxFramerate: $.maxFramerate } : {} };
837
- const c = Y.find((l) => l.rid === r.rid), d = o != null && String(r.rid ?? "") >= o;
838
- return { ...r, ...c ?? {}, active: d };
842
+ return { ...r, active: r.rid === "a", ...r.rid === "a" ? { maxBitrate: z.maxBitrate, maxFramerate: z.maxFramerate } : {} };
843
+ const c = Y.find((d) => d.rid === r.rid), l = o != null && String(r.rid ?? "") >= o;
844
+ return { ...r, ...c ?? {}, active: l };
839
845
  });
840
846
  } else {
841
- const o = this.quality === "audio" ? O.audio : O[this.quality], r = i ? $ : o;
847
+ const o = this.quality === "audio" ? N.audio : N[this.quality], r = i ? z : o;
842
848
  n.encodings = s.map((c) => ({ ...c, ...r }));
843
849
  }
844
850
  n.degradationPreference = i ? "maintain-resolution" : "maintain-framerate", await e.setParameters(n);
@@ -945,7 +951,7 @@ function Ne(a, e = {}) {
945
951
  }
946
952
  function o(r) {
947
953
  const c = a.getRemoteStreams();
948
- return r ? c.find((d) => d.participant.participantId === r)?.stream ?? null : c[0]?.stream ?? a.getLocalStream();
954
+ return r ? c.find((l) => l.participant.participantId === r)?.stream ?? null : c[0]?.stream ?? a.getLocalStream();
949
955
  }
950
956
  return {
951
957
  supported: i,
@@ -953,9 +959,9 @@ function Ne(a, e = {}) {
953
959
  if (!i) throw new Error("This browser does not support picture-in-picture");
954
960
  const c = o(r);
955
961
  if (!c) throw new Error("No video stream is available for picture-in-picture");
956
- const d = s();
957
- d.srcObject !== c && (d.srcObject = c), await d.play().catch(() => {
958
- }), await d.requestPictureInPicture();
962
+ const l = s();
963
+ l.srcObject !== c && (l.srcObject = c), await l.play().catch(() => {
964
+ }), await l.requestPictureInPicture();
959
965
  },
960
966
  async exit() {
961
967
  t.pictureInPictureElement && typeof t.exitPictureInPicture == "function" && await t.exitPictureInPicture();
@@ -967,89 +973,89 @@ function Ne(a, e = {}) {
967
973
  }
968
974
  function je(a, e) {
969
975
  const t = e.document ?? globalThis.document, i = e.fetchImplementation ?? globalThis.fetch.bind(globalThis), n = new URL(e.credential.signalingUrl, globalThis.location?.href).origin, s = e.mimeType ?? "video/webm", o = e.height ?? 720, r = Math.round(o * 16 / 9);
970
- let c = null, d = null, l = null, u = null, y = 0, f = [], w = !1;
971
- async function m(S, T, k, b = "application/json") {
972
- const M = await i(`${n}${T}`, {
973
- method: S,
976
+ let c = null, l = null, d = null, u = null, S = 0, f = [], v = !1;
977
+ async function I(y, k, p, C = "application/json") {
978
+ const P = await i(`${n}${k}`, {
979
+ method: y,
974
980
  headers: {
975
981
  authorization: `Bearer ${e.credential.signalingToken}`,
976
- "content-type": b
982
+ "content-type": C
977
983
  },
978
- body: k === void 0 ? void 0 : b === "application/json" ? JSON.stringify(k) : k
984
+ body: p === void 0 ? void 0 : C === "application/json" ? JSON.stringify(p) : p
979
985
  });
980
- if (!M.ok) throw new Error(`Recording request failed with HTTP ${M.status}`);
981
- return M.json();
986
+ if (!P.ok) throw new Error(`Recording request failed with HTTP ${P.status}`);
987
+ return P.json();
982
988
  }
983
989
  return {
984
990
  get recording() {
985
- return w;
991
+ return v;
986
992
  },
987
993
  async start() {
988
- if (w) return;
989
- u = (await m("POST", "/v1/rtc/recordings")).recordingId;
990
- const T = t.createElement("canvas");
991
- T.width = r, T.height = o;
992
- const k = T.getContext("2d"), b = /* @__PURE__ */ new Map(), M = (E, P) => {
993
- let C = b.get(E);
994
- return C || (C = t.createElement("video"), C.muted = !0, C.playsInline = !0, C.srcObject = P, C.play().catch(() => {
995
- }), b.set(E, C)), C;
994
+ if (v) return;
995
+ u = (await I("POST", "/v1/rtc/recordings")).recordingId;
996
+ const k = t.createElement("canvas");
997
+ k.width = r, k.height = o;
998
+ const p = k.getContext("2d"), C = /* @__PURE__ */ new Map(), P = (T, R) => {
999
+ let b = C.get(T);
1000
+ return b || (b = t.createElement("video"), b.muted = !0, b.playsInline = !0, b.srcObject = R, b.play().catch(() => {
1001
+ }), C.set(T, b)), b;
996
1002
  };
997
- d = setInterval(() => {
998
- const E = a.getRemoteStreams(), P = a.getLocalStream(), C = [
999
- ...E.map((j) => ({ key: j.participant.participantId, stream: j.stream, label: j.participant.displayName })),
1000
- ...P ? [{ key: "local", stream: P, label: "me" }] : []
1003
+ l = setInterval(() => {
1004
+ const T = a.getRemoteStreams(), R = a.getLocalStream(), b = [
1005
+ ...T.map((j) => ({ key: j.participant.participantId, stream: j.stream, label: j.participant.displayName })),
1006
+ ...R ? [{ key: "local", stream: R, label: "me" }] : []
1001
1007
  ];
1002
- k.fillStyle = "#101418", k.fillRect(0, 0, r, o);
1003
- const D = Math.max(1, Math.ceil(Math.sqrt(C.length))), v = Math.max(1, Math.ceil(C.length / D)), N = r / D, U = o / v;
1004
- C.forEach((j, H) => {
1005
- const _ = M(j.key, j.stream), B = H % D * N, F = Math.floor(H / D) * U;
1006
- _.videoWidth > 0 && k.drawImage(_, B + 2, F + 2, N - 4, U - 4), k.fillStyle = "rgba(0,0,0,.6)", k.fillRect(B + 8, F + U - 30, Math.min(N - 16, 12 + j.label.length * 9), 22), k.fillStyle = "#fff", k.font = "14px system-ui", k.fillText(j.label, B + 14, F + U - 14);
1008
+ p.fillStyle = "#101418", p.fillRect(0, 0, r, o);
1009
+ const O = Math.max(1, Math.ceil(Math.sqrt(b.length))), g = Math.max(1, Math.ceil(b.length / O)), q = r / O, x = o / g;
1010
+ b.forEach((j, J) => {
1011
+ const W = P(j.key, j.stream), B = J % O * q, F = Math.floor(J / O) * x;
1012
+ W.videoWidth > 0 && p.drawImage(W, B + 2, F + 2, q - 4, x - 4), p.fillStyle = "rgba(0,0,0,.6)", p.fillRect(B + 8, F + x - 30, Math.min(q - 16, 12 + j.label.length * 9), 22), p.fillStyle = "#fff", p.font = "14px system-ui", p.fillText(j.label, B + 14, F + x - 14);
1007
1013
  });
1008
1014
  }, 66);
1009
- const I = T.captureStream(15);
1010
- l = new AudioContext();
1011
- const g = l.createMediaStreamDestination(), p = /* @__PURE__ */ new Set(), h = () => {
1012
- const E = [
1013
- ...a.getRemoteStreams().map((P) => P.stream),
1015
+ const L = k.captureStream(15);
1016
+ d = new AudioContext();
1017
+ const E = d.createMediaStreamDestination(), A = /* @__PURE__ */ new Set(), w = () => {
1018
+ const T = [
1019
+ ...a.getRemoteStreams().map((R) => R.stream),
1014
1020
  ...a.getLocalStream() ? [a.getLocalStream()] : []
1015
1021
  ];
1016
- for (const P of E)
1017
- for (const C of P.getAudioTracks())
1018
- p.has(C.id) || (p.add(C.id), l.createMediaStreamSource(new MediaStream([C])).connect(g));
1022
+ for (const R of T)
1023
+ for (const b of R.getAudioTracks())
1024
+ A.has(b.id) || (A.add(b.id), d.createMediaStreamSource(new MediaStream([b])).connect(E));
1019
1025
  };
1020
- h();
1021
- const R = setInterval(h, 1e3), L = () => clearInterval(R);
1022
- for (const E of g.stream.getAudioTracks()) I.addTrack(E);
1023
- c = (e.mediaRecorderFactory ?? ((E, P) => new MediaRecorder(E, P)))(I, { mimeType: s }), f = [], c.addEventListener("dataavailable", (E) => {
1024
- E.data && E.data.size > 0 && f.push(E.data);
1025
- }), c.addEventListener("stop", L), c.start(1e3), y = Date.now(), w = !0;
1026
+ w();
1027
+ const M = setInterval(w, 1e3), m = () => clearInterval(M);
1028
+ for (const T of E.stream.getAudioTracks()) L.addTrack(T);
1029
+ c = (e.mediaRecorderFactory ?? ((T, R) => new MediaRecorder(T, R)))(L, { mimeType: s }), f = [], c.addEventListener("dataavailable", (T) => {
1030
+ T.data && T.data.size > 0 && f.push(T.data);
1031
+ }), c.addEventListener("stop", m), c.start(1e3), S = Date.now(), v = !0;
1026
1032
  },
1027
1033
  async stop() {
1028
- if (!w || !c || !u) throw new Error("The recorder is not running");
1029
- w = !1;
1030
- const S = c, T = new Promise((g) => S.addEventListener("stop", () => g(), { once: !0 }));
1031
- S.stop(), await T, d && clearInterval(d), d = null, await l?.close().catch(() => {
1032
- }), l = null;
1033
- const k = new Blob(f, { type: s });
1034
+ if (!v || !c || !u) throw new Error("The recorder is not running");
1035
+ v = !1;
1036
+ const y = c, k = new Promise((E) => y.addEventListener("stop", () => E(), { once: !0 }));
1037
+ y.stop(), await k, l && clearInterval(l), l = null, await d?.close().catch(() => {
1038
+ }), d = null;
1039
+ const p = new Blob(f, { type: s });
1034
1040
  f = [];
1035
- const b = Math.max(1, Math.round((Date.now() - y) / 1e3)), M = await m(
1041
+ const C = Math.max(1, Math.round((Date.now() - S) / 1e3)), P = await I(
1036
1042
  "PUT",
1037
1043
  `/v1/rtc/recordings/${encodeURIComponent(u)}/media`,
1038
- k,
1044
+ p,
1039
1045
  s
1040
1046
  );
1041
- await m("POST", `/v1/rtc/recordings/${encodeURIComponent(u)}/complete`, { durationSeconds: b });
1042
- const I = { recordingId: u, sizeBytes: M.sizeBytes, durationSeconds: b };
1043
- return u = null, c = null, I;
1047
+ await I("POST", `/v1/rtc/recordings/${encodeURIComponent(u)}/complete`, { durationSeconds: C });
1048
+ const L = { recordingId: u, sizeBytes: P.sizeBytes, durationSeconds: C };
1049
+ return u = null, c = null, L;
1044
1050
  },
1045
1051
  dispose() {
1046
- d && clearInterval(d), d = null;
1052
+ l && clearInterval(l), l = null;
1047
1053
  try {
1048
1054
  c?.stop();
1049
1055
  } catch {
1050
1056
  }
1051
- c = null, l?.close().catch(() => {
1052
- }), l = null, w = !1;
1057
+ c = null, d?.close().catch(() => {
1058
+ }), d = null, v = !1;
1053
1059
  }
1054
1060
  };
1055
1061
  }
@@ -1091,17 +1097,19 @@ const Se = ["none", "blur", "aurora", "cybergrid", "bokeh", "sunset", "image"],
1091
1097
  }
1092
1098
  };
1093
1099
  function Ve(a, e = {}) {
1094
- const t = e.document ?? globalThis.document, i = e.width ?? 1280, n = e.height ?? 720, s = e.frameRate ?? 24, o = a instanceof MediaStreamTrack ? a : a.getVideoTracks()[0];
1095
- if (!o) throw new Error("A video track is required");
1096
- let r = e.background ?? "none", c = e.overlay ?? "none", d = e.backgroundImage ?? null, l = e.segmenter ?? null, u = null, y = !1;
1097
- const f = t.createElement("video");
1098
- f.muted = !0, f.playsInline = !0, f.srcObject = new MediaStream([o]), f.play().catch(() => {
1100
+ const t = e.document ?? globalThis.document;
1101
+ let i = e.width ?? 1280, n = e.height ?? 720;
1102
+ const s = !!(e.width || e.height), o = e.frameRate ?? 24, r = a instanceof MediaStreamTrack ? a : a.getVideoTracks()[0];
1103
+ if (!r) throw new Error("A video track is required");
1104
+ let c = e.background ?? "none", l = e.overlay ?? "none", d = e.backgroundImage ?? null, u = e.segmenter ?? null, S = null, f = !1;
1105
+ const v = t.createElement("video");
1106
+ v.muted = !0, v.playsInline = !0, v.srcObject = new MediaStream([r]), v.play().catch(() => {
1099
1107
  });
1100
- const w = t.createElement("canvas");
1101
- w.width = i, w.height = n;
1102
- const m = w.getContext("2d"), S = t.createElement("canvas");
1103
- S.width = i, S.height = n;
1104
- const T = S.getContext("2d"), k = Array.from({ length: 80 }, (p, h) => ({
1108
+ const I = t.createElement("canvas");
1109
+ I.width = i, I.height = n;
1110
+ const y = I.getContext("2d"), k = t.createElement("canvas");
1111
+ k.width = i, k.height = n;
1112
+ const p = k.getContext("2d"), C = () => Array.from({ length: 80 }, (m, h) => ({
1105
1113
  x: (Math.sin(h * 12.9898) * 0.5 + 0.5) * i,
1106
1114
  y: (Math.sin(h * 78.233) * 0.5 + 0.5) * n,
1107
1115
  speed: 0.6 + h % 5 * 0.5,
@@ -1109,48 +1117,57 @@ function Ve(a, e = {}) {
1109
1117
  size: 2 + h % 4,
1110
1118
  hue: h * 47 % 360
1111
1119
  }));
1112
- function b() {
1113
- if (u) {
1114
- T.clearRect(0, 0, i, n), T.drawImage(u, 0, 0, i, n), T.globalCompositeOperation = "source-in", T.drawImage(f, 0, 0, i, n), T.globalCompositeOperation = "source-over", m.drawImage(S, 0, 0);
1120
+ let P = C();
1121
+ const L = () => {
1122
+ if (s) return;
1123
+ const m = v.videoWidth, h = v.videoHeight;
1124
+ if (!m || !h) return;
1125
+ const T = Math.min(1, 1280 / Math.max(m, h)), R = Math.round(m * T), b = Math.round(h * T);
1126
+ R === i && b === n || (i = R, n = b, I.width = i, I.height = n, k.width = i, k.height = n, P = C());
1127
+ };
1128
+ v.addEventListener?.("loadedmetadata", L), v.addEventListener?.("resize", L);
1129
+ function E() {
1130
+ if (S) {
1131
+ p.clearRect(0, 0, i, n), p.drawImage(S, 0, 0, i, n), p.globalCompositeOperation = "source-in", p.drawImage(v, 0, 0, i, n), p.globalCompositeOperation = "source-over", y.drawImage(k, 0, 0);
1115
1132
  return;
1116
1133
  }
1117
- const p = i * 0.42, h = p * 9 / 16, R = i - p - 24, L = n - h - 24;
1118
- m.save(), m.shadowColor = "rgba(0,0,0,.5)", m.shadowBlur = 24, m.beginPath(), m.roundRect(R, L, p, h, 14), m.clip(), m.drawImage(f, R, L, p, h), m.restore();
1119
- }
1120
- function M(p) {
1121
- if (r === "none" ? m.drawImage(f, 0, 0, i, n) : r === "blur" ? (m.filter = "blur(14px)", m.drawImage(f, -16, -16, i + 32, n + 32), m.filter = "none", u && b()) : r === "image" && d ? (m.drawImage(d, 0, 0, i, n), b()) : ((K[r] ?? K.aurora)(m, i, n, p), b()), c === "snow" || c === "confetti")
1122
- for (const h of k)
1123
- h.y += h.speed * (c === "confetti" ? 1.6 : 1), h.x += h.drift, h.y > n && (h.y = -6, h.x = Math.random() * i), m.fillStyle = c === "snow" ? "rgba(255,255,255,.85)" : `hsl(${h.hue}, 90%, 60%)`, c === "confetti" ? m.fillRect(h.x, h.y, h.size + 2, h.size) : (m.beginPath(), m.arc(h.x, h.y, h.size / 2, 0, Math.PI * 2), m.fill());
1124
- else if (c === "vignette") {
1125
- const h = m.createRadialGradient(i / 2, n / 2, n * 0.4, i / 2, n / 2, n * 0.85);
1126
- h.addColorStop(0, "rgba(0,0,0,0)"), h.addColorStop(1, "rgba(0,0,0,0.55)"), m.fillStyle = h, m.fillRect(0, 0, i, n);
1134
+ const m = i * 0.42, h = m * 9 / 16, T = i - m - 24, R = n - h - 24;
1135
+ y.save(), y.shadowColor = "rgba(0,0,0,.5)", y.shadowBlur = 24, y.beginPath(), y.roundRect(T, R, m, h, 14), y.clip(), y.drawImage(v, T, R, m, h), y.restore();
1136
+ }
1137
+ function A(m) {
1138
+ if (c === "none" ? y.drawImage(v, 0, 0, i, n) : c === "blur" ? (y.filter = "blur(14px)", y.drawImage(v, -16, -16, i + 32, n + 32), y.filter = "none", S && E()) : c === "image" && d ? (y.drawImage(d, 0, 0, i, n), E()) : ((K[c] ?? K.aurora)(y, i, n, m), E()), l === "snow" || l === "confetti")
1139
+ for (const h of P)
1140
+ h.y += h.speed * (l === "confetti" ? 1.6 : 1), h.x += h.drift, h.y > n && (h.y = -6, h.x = Math.random() * i), y.fillStyle = l === "snow" ? "rgba(255,255,255,.85)" : `hsl(${h.hue}, 90%, 60%)`, l === "confetti" ? y.fillRect(h.x, h.y, h.size + 2, h.size) : (y.beginPath(), y.arc(h.x, h.y, h.size / 2, 0, Math.PI * 2), y.fill());
1141
+ else if (l === "vignette") {
1142
+ const h = y.createRadialGradient(i / 2, n / 2, n * 0.4, i / 2, n / 2, n * 0.85);
1143
+ 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);
1127
1144
  }
1128
1145
  }
1129
- const I = setInterval(() => {
1130
- M(Date.now()), l && !y && r !== "none" && (y = !0, l.segment(f).then((p) => {
1131
- u = p;
1146
+ const w = setInterval(() => {
1147
+ A(Date.now()), u && !f && c !== "none" && (f = !0, u.segment(v).then((m) => {
1148
+ S = m;
1132
1149
  }).catch(() => {
1133
- u = null;
1150
+ S = null;
1134
1151
  }).finally(() => {
1135
- y = !1;
1152
+ f = !1;
1136
1153
  }));
1137
- }, Math.round(1e3 / s)), g = w.captureStream(s);
1154
+ }, Math.round(1e3 / o)), M = I.captureStream(o);
1138
1155
  return {
1139
- track: g.getVideoTracks()[0],
1140
- stream: g,
1141
- setBackground(p, h) {
1142
- r = Se.includes(p) ? p : "none", h !== void 0 && (d = h), r === "none" && (u = null);
1156
+ track: M.getVideoTracks()[0],
1157
+ stream: M,
1158
+ setBackground(m, h) {
1159
+ c = Se.includes(m) ? m : "none", h !== void 0 && (d = h), c === "none" && (S = null);
1143
1160
  },
1144
- setOverlay(p) {
1145
- c = ke.includes(p) ? p : "none";
1161
+ setOverlay(m) {
1162
+ l = ke.includes(m) ? m : "none";
1146
1163
  },
1147
- setSegmenter(p) {
1148
- l = p, p || (u = null);
1164
+ setSegmenter(m) {
1165
+ u = m, m || (S = null);
1149
1166
  },
1150
1167
  dispose() {
1151
- clearInterval(I), l?.close?.();
1152
- for (const p of g.getTracks()) p.stop();
1153
- f.srcObject = null;
1168
+ clearInterval(w), u?.close?.();
1169
+ for (const m of M.getTracks()) m.stop();
1170
+ v.srcObject = null;
1154
1171
  }
1155
1172
  };
1156
1173
  }
@@ -1169,7 +1186,7 @@ function le() {
1169
1186
  tracked: !1
1170
1187
  };
1171
1188
  }
1172
- function A(a, e) {
1189
+ function D(a, e) {
1173
1190
  const t = a.find((i) => i.categoryName === e);
1174
1191
  return t ? Math.max(0, Math.min(1, t.score)) : 0;
1175
1192
  }
@@ -1181,13 +1198,13 @@ function we(a) {
1181
1198
  }
1182
1199
  function Te(a, e, t = 1) {
1183
1200
  if (!a || a.length === 0) return le();
1184
- const i = we(e), n = (A(a, "eyeLookOutRight") + A(a, "eyeLookInLeft")) / 2, s = (A(a, "eyeLookOutLeft") + A(a, "eyeLookInRight")) / 2, o = (A(a, "eyeLookUpLeft") + A(a, "eyeLookUpRight")) / 2, r = (A(a, "eyeLookDownLeft") + A(a, "eyeLookDownRight")) / 2, c = (A(a, "mouthSmileLeft") + A(a, "mouthSmileRight")) / 2, d = (A(a, "mouthFrownLeft") + A(a, "mouthFrownRight")) / 2, l = A(a, "eyeBlinkLeft"), u = A(a, "eyeBlinkRight"), y = Math.min(1, Math.abs(i.yaw) / 0.35) * Math.max(0, Math.min(1, t)), f = (l + u) / 2;
1201
+ 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"), S = Math.min(1, Math.abs(i.yaw) / 0.35) * Math.max(0, Math.min(1, t)), f = (d + u) / 2;
1185
1202
  return {
1186
- blinkLeft: l + (f - l) * y,
1187
- blinkRight: u + (f - u) * y,
1188
- jawOpen: A(a, "jawOpen"),
1189
- smile: c - d,
1190
- browUp: (A(a, "browInnerUp") + A(a, "browOuterUpLeft") + A(a, "browOuterUpRight")) / 3,
1203
+ blinkLeft: d + (f - d) * S,
1204
+ blinkRight: u + (f - u) * S,
1205
+ jawOpen: D(a, "jawOpen"),
1206
+ smile: c - l,
1207
+ browUp: (D(a, "browInnerUp") + D(a, "browOuterUpLeft") + D(a, "browOuterUpRight")) / 3,
1191
1208
  pupilX: n - s,
1192
1209
  pupilY: r - o,
1193
1210
  headYaw: i.yaw,
@@ -1216,30 +1233,30 @@ function be(a, e, t, i, n) {
1216
1233
  n || (a.fillStyle = "#101822", a.fillRect(0, 0, t, i));
1217
1234
  const s = n ? n.x + e.headYaw * n.radius * 0.1 : t / 2 + e.headYaw * t * 0.18, o = n ? n.y + e.headPitch * n.radius * 0.1 : i / 2 + e.headPitch * i * 0.18, r = n ? n.radius : Math.min(t, i) * 0.28;
1218
1235
  a.save(), a.translate(s, o), a.rotate(e.headRoll * 0.6);
1219
- const c = Math.max(-1.35, Math.min(1.35, e.headYaw)), d = Math.max(-0.9, Math.min(0.9, e.headPitch)), l = Math.sin(c), u = (p) => Math.sin(p + c) * r, y = (p) => Math.cos(p + c), f = Math.sin(d) * r * 0.22;
1220
- a.fillStyle = "#3a2a1c", a.beginPath(), a.ellipse(-l * r * 0.35, -r * 0.25, r * 0.98, r * 0.95, 0, 0, Math.PI * 2), a.fill(), a.fillStyle = e.tracked ? "#f2c9a0" : "#5a6470", a.beginPath(), a.ellipse(0, 0, r * (1 - Math.abs(l) * 0.12), r * 1.12, 0, 0, Math.PI * 2), a.fill(), a.fillStyle = "#3a2a1c", a.beginPath(), a.ellipse(-l * r * 0.28, -r * 0.72 + f * 0.4, r * 0.92, r * 0.5, 0, Math.PI, Math.PI * 2), a.fill();
1221
- const w = 0;
1236
+ const c = Math.max(-1.35, Math.min(1.35, e.headYaw)), l = Math.max(-0.9, Math.min(0.9, e.headPitch)), d = Math.sin(c), u = (A) => Math.sin(A + c) * r, S = (A) => Math.cos(A + c), f = Math.sin(l) * r * 0.22;
1237
+ a.fillStyle = "#3a2a1c", a.beginPath(), a.ellipse(-d * r * 0.35, -r * 0.25, r * 0.98, r * 0.95, 0, 0, Math.PI * 2), a.fill(), a.fillStyle = e.tracked ? "#f2c9a0" : "#5a6470", a.beginPath(), a.ellipse(0, 0, r * (1 - Math.abs(d) * 0.12), r * 1.12, 0, 0, Math.PI * 2), a.fill(), a.fillStyle = "#3a2a1c", a.beginPath(), a.ellipse(-d * r * 0.28, -r * 0.72 + f * 0.4, r * 0.92, r * 0.5, 0, Math.PI, Math.PI * 2), a.fill();
1238
+ const v = 0;
1222
1239
  a.fillStyle = "#e5b58a", a.beginPath();
1223
- const m = u(w) * 0.9, S = r * 0.12 + f;
1224
- a.ellipse(m + l * r * 0.14, S, r * 0.11, r * 0.14, 0, 0, Math.PI * 2), a.fill();
1225
- for (const p of [-1, 1]) {
1226
- const h = p * 0.42, R = y(h);
1227
- if (R <= 0.12) continue;
1228
- const L = u(h) * 0.82, q = Math.max(0.2, R), E = p < 0 ? e.blinkLeft : e.blinkRight, P = Math.max(0.06, 1 - E), C = e.browUp * r * 0.14;
1229
- a.strokeStyle = "#4a2e18", a.lineWidth = r * 0.07, a.lineCap = "round", a.beginPath(), a.moveTo(L - r * 0.2 * q, -r * 0.42 - C + f), a.quadraticCurveTo(L, -r * 0.52 - C + f, L + r * 0.2 * q, -r * 0.44 - C + f), a.stroke();
1230
- const D = -r * 0.18 + f;
1231
- a.fillStyle = "#ffffff", a.beginPath(), a.ellipse(L, D, r * 0.16 * q, r * 0.12 * P, 0, 0, Math.PI * 2), a.fill(), a.fillStyle = "#22303c", a.beginPath(), a.ellipse(
1232
- L + e.pupilX * r * 0.07 * q,
1233
- D + e.pupilY * r * 0.05,
1234
- r * 0.06 * q,
1235
- r * 0.06 * P,
1240
+ const I = u(v) * 0.9, y = r * 0.12 + f;
1241
+ a.ellipse(I + d * r * 0.14, y, r * 0.11, r * 0.14, 0, 0, Math.PI * 2), a.fill();
1242
+ for (const A of [-1, 1]) {
1243
+ const w = A * 0.42, M = S(w);
1244
+ if (M <= 0.12) continue;
1245
+ const m = u(w) * 0.82, h = Math.max(0.2, M), T = A < 0 ? e.blinkLeft : e.blinkRight, R = Math.max(0.06, 1 - T), b = e.browUp * r * 0.14;
1246
+ a.strokeStyle = "#4a2e18", a.lineWidth = r * 0.07, a.lineCap = "round", a.beginPath(), a.moveTo(m - r * 0.2 * h, -r * 0.42 - b + f), a.quadraticCurveTo(m, -r * 0.52 - b + f, m + r * 0.2 * h, -r * 0.44 - b + f), a.stroke();
1247
+ const O = -r * 0.18 + f;
1248
+ a.fillStyle = "#ffffff", a.beginPath(), a.ellipse(m, O, r * 0.16 * h, r * 0.12 * R, 0, 0, Math.PI * 2), a.fill(), a.fillStyle = "#22303c", a.beginPath(), a.ellipse(
1249
+ m + e.pupilX * r * 0.07 * h,
1250
+ O + e.pupilY * r * 0.05,
1251
+ r * 0.06 * h,
1252
+ r * 0.06 * R,
1236
1253
  0,
1237
1254
  0,
1238
1255
  Math.PI * 2
1239
1256
  ), a.fill();
1240
1257
  }
1241
- const T = Math.max(0.25, y(0)), k = u(0) * 0.7, b = r * 0.55 * T, M = r * (0.04 + e.jawOpen * 0.34), I = e.smile * r * 0.12, g = r * 0.42 + f;
1242
- a.fillStyle = "#8c2f2f", a.beginPath(), a.moveTo(k - b / 2, g - I), a.quadraticCurveTo(k, g + M, k + b / 2, g - I), a.quadraticCurveTo(k, g - M * 0.25, k - b / 2, g - I), a.closePath(), a.fill(), a.restore(), !e.tracked && !n && (a.fillStyle = "#9fb0bd", a.font = `${Math.round(i * 0.045)}px system-ui`, a.textAlign = "center", a.fillText("No face detected", t / 2, i * 0.9), a.textAlign = "left");
1258
+ const k = Math.max(0.25, S(0)), p = u(0) * 0.7, C = r * 0.55 * k, P = r * (0.04 + e.jawOpen * 0.34), L = e.smile * r * 0.12, E = r * 0.42 + f;
1259
+ a.fillStyle = "#8c2f2f", a.beginPath(), a.moveTo(p - C / 2, E - L), a.quadraticCurveTo(p, E + P, p + C / 2, E - L), a.quadraticCurveTo(p, E - P * 0.25, p - C / 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");
1243
1260
  }
1244
1261
  const Z = {
1245
1262
  mouthGain: 1.7,
@@ -1257,62 +1274,71 @@ function ee() {
1257
1274
  }
1258
1275
  };
1259
1276
  }
1260
- const z = (a) => Math.max(0, Math.min(1, a));
1261
- function Ue(a, e = {}) {
1262
- const t = e.document ?? globalThis.document, i = e.width ?? 1280, n = e.height ?? 720, s = e.frameRate ?? 24, o = a instanceof MediaStreamTrack ? a : a.getVideoTracks()[0];
1263
- if (!o) throw new Error("A video track is required");
1264
- let r = e.tracker ?? null, c = e.renderer ?? ee(), d = e.mode ?? "replace";
1265
- const l = { ...Z, ...e.tuning }, u = e.backdrop ?? "#101822", y = t.createElement("video");
1266
- y.muted = !0, y.playsInline = !0, y.srcObject = new MediaStream([o]), y.play().catch(() => {
1277
+ const $ = (a) => Math.max(0, Math.min(1, a));
1278
+ function xe(a, e = {}) {
1279
+ const t = e.document ?? globalThis.document;
1280
+ let i = e.width ?? 1280, n = e.height ?? 720;
1281
+ const s = !!(e.width || e.height), o = e.frameRate ?? 24, r = a instanceof MediaStreamTrack ? a : a.getVideoTracks()[0];
1282
+ if (!r) throw new Error("A video track is required");
1283
+ let c = e.tracker ?? null, l = e.renderer ?? ee(), d = e.mode ?? "replace";
1284
+ const u = { ...Z, ...e.tuning }, S = e.backdrop ?? "#101822", f = t.createElement("video");
1285
+ f.muted = !0, f.playsInline = !0, f.srcObject = new MediaStream([r]), f.play().catch(() => {
1267
1286
  });
1268
- const f = t.createElement("canvas");
1269
- f.width = i, f.height = n;
1270
- const w = f.getContext("2d");
1271
- let m = le(), S = null, T = 0;
1272
- function k(g) {
1273
- if (g.length <= 454) return;
1274
- const p = g[10], h = g[152], R = g[234], L = g[454], q = (R.x + L.x) / 2 * i, E = (R.y + L.y) / 2 * n, P = Math.hypot((h.x - p.x) * i, (h.y - p.y) * n), C = Math.max(0.6, Math.cos(m.headPitch)), D = { x: q, y: E, radius: Math.max(24, P / C * 0.8) };
1275
- S = S ? { x: S.x + (D.x - S.x) * 0.4, y: S.y + (D.y - S.y) * 0.4, radius: S.radius + (D.radius - S.radius) * 0.15 } : D;
1276
- }
1277
- function b(g) {
1278
- if (r && y.readyState >= 2) {
1279
- let h = null;
1287
+ const v = t.createElement("canvas");
1288
+ v.width = i, v.height = n;
1289
+ const I = v.getContext("2d"), y = () => {
1290
+ if (s) return;
1291
+ const w = f.videoWidth, M = f.videoHeight;
1292
+ if (!w || !M) return;
1293
+ const m = Math.min(1, 1280 / Math.max(w, M)), h = Math.round(w * m), T = Math.round(M * m);
1294
+ (!(h === i || T === n) || h !== i || T !== n) && (i = h, n = T, v.width = i, v.height = n);
1295
+ };
1296
+ f.addEventListener?.("loadedmetadata", y), f.addEventListener?.("resize", y);
1297
+ let k = le(), p = null, C = 0;
1298
+ function P(w) {
1299
+ if (w.length <= 454) return;
1300
+ const M = w[10], m = w[152], h = w[234], T = w[454], R = (h.x + T.x) / 2 * i, b = (h.y + T.y) / 2 * n, O = Math.hypot((m.x - M.x) * i, (m.y - M.y) * n), g = Math.max(0.6, Math.cos(k.headPitch)), q = { x: R, y: b, radius: Math.max(24, O / g * 0.8) };
1301
+ p = p ? { x: p.x + (q.x - p.x) * 0.4, y: p.y + (q.y - p.y) * 0.4, radius: p.radius + (q.radius - p.radius) * 0.15 } : q;
1302
+ }
1303
+ function L(w) {
1304
+ if (c && f.readyState >= 2) {
1305
+ let m = null;
1280
1306
  try {
1281
- h = r.detect(y, g);
1307
+ m = c.detect(f, w);
1282
1308
  } catch {
1283
1309
  }
1284
- const R = Te(h?.categories ?? null, h?.matrix ?? null, l.eyeSync);
1285
- R.jawOpen = z(R.jawOpen * l.mouthGain), R.blinkLeft = z(R.blinkLeft * l.blinkGain), R.blinkRight = z(R.blinkRight * l.blinkGain), R.tracked ? (T = g, m = X(m, R, l.smoothing), h?.landmarks && k(h.landmarks)) : m.tracked && g - T > l.lostHoldMs && (m = X(m, { ...m, jawOpen: 0, browUp: 0, smile: m.smile * 0.5, blinkLeft: 0.1, blinkRight: 0.1 }, 0.05));
1310
+ const h = Te(m?.categories ?? null, m?.matrix ?? null, u.eyeSync);
1311
+ h.jawOpen = $(h.jawOpen * u.mouthGain), h.blinkLeft = $(h.blinkLeft * u.blinkGain), h.blinkRight = $(h.blinkRight * u.blinkGain), h.tracked ? (C = w, k = X(k, h, u.smoothing), m?.landmarks && P(m.landmarks)) : k.tracked && w - C > u.lostHoldMs && (k = X(k, { ...k, jawOpen: 0, browUp: 0, smile: k.smile * 0.5, blinkLeft: 0.1, blinkRight: 0.1 }, 0.05));
1286
1312
  }
1287
- d === "overlay" && y.readyState >= 2 ? w.drawImage(y, 0, 0, i, n) : (w.fillStyle = u, w.fillRect(0, 0, i, n));
1288
- const p = d === "overlay" && S ? { x: S.x, y: S.y + l.avatarLift * S.radius, radius: S.radius * l.avatarScale } : null;
1289
- c?.render(w, m, i, n, p);
1313
+ d === "overlay" && f.readyState >= 2 ? I.drawImage(f, 0, 0, i, n) : (I.fillStyle = S, I.fillRect(0, 0, i, n));
1314
+ const M = d === "overlay" && p ? { x: p.x, y: p.y + u.avatarLift * p.radius, radius: p.radius * u.avatarScale } : null;
1315
+ l?.render(I, k, i, n, M);
1290
1316
  }
1291
- const M = setInterval(() => b(Date.now()), Math.round(1e3 / s)), I = f.captureStream(s);
1317
+ const E = setInterval(() => L(Date.now()), Math.round(1e3 / o)), A = v.captureStream(o);
1292
1318
  return {
1293
- track: I.getVideoTracks()[0],
1294
- stream: I,
1295
- getRig: () => ({ ...m }),
1296
- setMode(g) {
1297
- d = g === "overlay" ? "overlay" : "replace";
1319
+ track: A.getVideoTracks()[0],
1320
+ stream: A,
1321
+ getRig: () => ({ ...k }),
1322
+ setMode(w) {
1323
+ d = w === "overlay" ? "overlay" : "replace";
1298
1324
  },
1299
- setTracker(g) {
1300
- r?.close?.(), r = g;
1325
+ setTracker(w) {
1326
+ c?.close?.(), c = w;
1301
1327
  },
1302
- setRenderer(g) {
1303
- c?.dispose?.(), c = g ?? ee();
1328
+ setRenderer(w) {
1329
+ l?.dispose?.(), l = w ?? ee();
1304
1330
  },
1305
- setTuning(g) {
1306
- for (const p of Object.keys(Z)) {
1307
- const h = g[p];
1308
- typeof h == "number" && Number.isFinite(h) && (l[p] = h);
1331
+ setTuning(w) {
1332
+ for (const M of Object.keys(Z)) {
1333
+ const m = w[M];
1334
+ typeof m == "number" && Number.isFinite(m) && (u[M] = m);
1309
1335
  }
1310
1336
  },
1311
- getTuning: () => ({ ...l }),
1337
+ getTuning: () => ({ ...u }),
1312
1338
  dispose() {
1313
- clearInterval(M), r?.close?.(), c?.dispose?.();
1314
- for (const g of I.getTracks()) g.stop();
1315
- y.srcObject = null;
1339
+ clearInterval(E), c?.close?.(), l?.dispose?.();
1340
+ for (const w of A.getTracks()) w.stop();
1341
+ f.srcObject = null;
1316
1342
  }
1317
1343
  };
1318
1344
  }
@@ -1350,7 +1376,7 @@ class Ce extends EventTarget {
1350
1376
  async initialize() {
1351
1377
  if (this.client) return this;
1352
1378
  try {
1353
- const t = (this.options.transport === "auto" ? this.mode === "meeting" ? "sfu" : "mesh" : this.options.transport ?? "mesh") === "sfu" ? ye : x;
1379
+ const t = (this.options.transport === "auto" ? this.mode === "meeting" ? "sfu" : "mesh" : this.options.transport ?? "mesh") === "sfu" ? ye : Q;
1354
1380
  return this.client = new t({
1355
1381
  credential: {
1356
1382
  signalingToken: this.options.credential.signalingToken,
@@ -1368,6 +1394,7 @@ class Ce extends EventTarget {
1368
1394
  preferredVideoCodec: this.options.preferredVideoCodec ?? "auto",
1369
1395
  iceTransportPolicy: this.options.iceTransportPolicy ?? "all",
1370
1396
  localStream: this.options.localStream,
1397
+ simulcast: this.options.simulcast ?? !0,
1371
1398
  onEvent: (i, n) => this.handleNativeEvent(i, n)
1372
1399
  }), await this.client.initialize(), this.startStats(), this.emit("initialized", { mode: this.mode, sdkVersion: De }), this.options.autoJoin && await this.join(), this;
1373
1400
  } catch (e) {
@@ -1495,42 +1522,42 @@ class Ce extends EventTarget {
1495
1522
  let n = "unavailable";
1496
1523
  if (e.requestMedia !== !1 && navigator.mediaDevices?.getUserMedia)
1497
1524
  try {
1498
- (await navigator.mediaDevices.getUserMedia({ audio: this.options.audio, video: this.options.video })).getTracks().forEach((y) => y.stop()), n = "granted";
1525
+ (await navigator.mediaDevices.getUserMedia({ audio: this.options.audio, video: this.options.video })).getTracks().forEach((S) => S.stop()), n = "granted";
1499
1526
  } catch {
1500
1527
  n = "denied", t.push("media_permission_denied");
1501
1528
  }
1502
1529
  const s = navigator.mediaDevices?.enumerateDevices ? await navigator.mediaDevices.enumerateDevices().catch(() => []) : [], o = s.filter((u) => u.kind === "audioinput").length, r = s.filter((u) => u.kind === "videoinput").length;
1503
1530
  this.options.audio && o === 0 && t.push("microphone_unavailable"), this.options.video && r === 0 && t.push("camera_unavailable");
1504
1531
  const c = e.probeUrl ?? this.options.preflightProbeUrl;
1505
- let d = null;
1532
+ let l = null;
1506
1533
  if (c) {
1507
1534
  const u = performance.now();
1508
1535
  try {
1509
- const y = await fetch(c, { method: "HEAD", cache: "no-store", credentials: "omit" });
1510
- d = Math.round(performance.now() - u), y.ok || t.push("network_probe_failed");
1536
+ const S = await fetch(c, { method: "HEAD", cache: "no-store", credentials: "omit" });
1537
+ l = Math.round(performance.now() - u), S.ok || t.push("network_probe_failed");
1511
1538
  } catch {
1512
1539
  t.push("network_probe_failed");
1513
1540
  }
1514
1541
  }
1515
- const l = {
1542
+ const d = {
1516
1543
  passed: t.length === 0,
1517
1544
  sampledAt: (/* @__PURE__ */ new Date()).toISOString(),
1518
1545
  secureContext: i,
1519
1546
  mediaPermission: n,
1520
1547
  microphoneCount: o,
1521
1548
  cameraCount: r,
1522
- probeLatencyMs: d,
1549
+ probeLatencyMs: l,
1523
1550
  effectiveConnectionType: ae()?.effectiveType ?? null,
1524
1551
  issues: t
1525
1552
  };
1526
- return this.emit("preflight", l), this.options.autoReportStats && await this.reportQuality({
1553
+ return this.emit("preflight", d), this.options.autoReportStats && await this.reportQuality({
1527
1554
  sampleType: "preflight",
1528
- sampledAt: l.sampledAt,
1529
- connectionState: l.passed ? "ready" : "failed",
1530
- rttMs: l.probeLatencyMs,
1531
- effectiveConnectionType: l.effectiveConnectionType
1555
+ sampledAt: d.sampledAt,
1556
+ connectionState: d.passed ? "ready" : "failed",
1557
+ rttMs: d.probeLatencyMs,
1558
+ effectiveConnectionType: d.effectiveConnectionType
1532
1559
  }).catch(() => {
1533
- }), l;
1560
+ }), d;
1534
1561
  }
1535
1562
  async collectQualitySample(e = "runtime") {
1536
1563
  const t = this.options.statsProvider ? await this.options.statsProvider() : {}, i = this.peerConnection ? await Pe(this.peerConnection, this.previousCounters) : null;
@@ -1649,14 +1676,14 @@ class Ce extends EventTarget {
1649
1676
  this.dispatchEvent(new CustomEvent(e, { detail: i })), this.options.onEvent?.(i);
1650
1677
  }
1651
1678
  }
1652
- async function Qe(a) {
1679
+ async function Ue(a) {
1653
1680
  return new Ce(a).initialize();
1654
1681
  }
1655
- let Q = null;
1682
+ let U = null;
1656
1683
  function de() {
1657
- if (Q) return Q;
1684
+ if (U) return U;
1658
1685
  const a = globalThis, e = a.AudioContext ?? a.webkitAudioContext;
1659
- return e ? (Q = new e(), Q) : null;
1686
+ return e ? (U = new e(), U) : null;
1660
1687
  }
1661
1688
  async function Re() {
1662
1689
  const a = de();
@@ -1912,14 +1939,14 @@ class Ee extends EventTarget {
1912
1939
  if (!n) throw new Error("apiBaseUrl is required for call actions");
1913
1940
  const s = new URL(n, globalThis.location?.href), o = await this.resolveToken("initial"), r = new Headers(t.headers);
1914
1941
  r.set("authorization", `Bearer ${o}`), r.set("content-type", "application/json");
1915
- const c = await fetch(new URL(e, s.origin), { ...t, headers: r }), d = await c.json().catch(() => ({}));
1942
+ const c = await fetch(new URL(e, s.origin), { ...t, headers: r }), l = await c.json().catch(() => ({}));
1916
1943
  if (c.status === 401 && this.options.tokenProvider && !i)
1917
1944
  return await this.resolveToken("unauthorized", !0), this.request(e, t, !0);
1918
1945
  if (!c.ok) {
1919
- const l = d.error;
1920
- throw new Error(typeof l == "string" ? l : l?.message || `RTC API failed with HTTP ${c.status}`);
1946
+ const d = l.error;
1947
+ throw new Error(typeof d == "string" ? d : d?.message || `RTC API failed with HTTP ${c.status}`);
1921
1948
  }
1922
- return d;
1949
+ return l;
1923
1950
  }
1924
1951
  renderIncoming(e) {
1925
1952
  if (!this.mount) return;
@@ -2035,7 +2062,7 @@ class Ee extends EventTarget {
2035
2062
  this.dispatchEvent(new CustomEvent(e, { detail: i })), this.options.onEvent?.(i);
2036
2063
  }
2037
2064
  }
2038
- function xe(a) {
2065
+ function Qe(a) {
2039
2066
  const e = new Ee(a);
2040
2067
  return a.autoConnect !== !1 && a.signalingUrl && e.connect(), e;
2041
2068
  }
@@ -2074,46 +2101,46 @@ function ne(a) {
2074
2101
  }
2075
2102
  async function Pe(a, e) {
2076
2103
  const t = await a.getStats(), i = /* @__PURE__ */ new Map(), n = /* @__PURE__ */ new Map();
2077
- let s = 0, o = 0, r = 0, c = 0, d = 0, l = 0, u = 0, y = 0, f = 0, w = 0, m = 0, S = 0, T = 0, k = null, b = null, M = null, I = null, g = null, p = null;
2078
- t.forEach((v) => {
2079
- n.set(v.id, v), v.type === "codec" && i.set(v.id, String(v.mimeType ?? ""));
2080
- }), t.forEach((v) => {
2081
- if (v.type === "inbound-rtp" && !v.isRemote && (s += Number(v.bytesReceived ?? 0), r += Math.max(0, Number(v.packetsLost ?? 0)), c += Math.max(0, Number(v.packetsReceived ?? 0)), Number.isFinite(v.jitter) && (d += Number(v.jitter), l += 1), u = Math.max(u, Number(v.framesPerSecond ?? 0)), y = Math.max(y, Number(v.frameWidth ?? 0)), f = Math.max(f, Number(v.frameHeight ?? 0)), w += Number(v.framesDropped ?? 0), m += Number(v.freezeCount ?? 0), S += Number(v.totalFreezesDuration ?? 0), T += Number(v.concealedSamples ?? 0), g ||= i.get(String(v.codecId ?? "")) ?? null), v.type === "outbound-rtp" && !v.isRemote && (o += Number(v.bytesSent ?? 0), p ||= v.qualityLimitationReason ? String(v.qualityLimitationReason) : null, g ||= i.get(String(v.codecId ?? "")) ?? null), v.type === "candidate-pair" && (v.selected || v.nominated) && v.state === "succeeded") {
2082
- k = Number.isFinite(v.currentRoundTripTime) ? Number(v.currentRoundTripTime) : k, b = Number.isFinite(v.availableOutgoingBitrate) ? Number(v.availableOutgoingBitrate) : b;
2083
- const N = n.get(v.localCandidateId);
2084
- M = N?.candidateType ? String(N.candidateType) : M, I = N?.protocol ? String(N.protocol) : I;
2104
+ let s = 0, o = 0, r = 0, c = 0, l = 0, d = 0, u = 0, S = 0, f = 0, v = 0, I = 0, y = 0, k = 0, p = null, C = null, P = null, L = null, E = null, A = null;
2105
+ t.forEach((g) => {
2106
+ n.set(g.id, g), g.type === "codec" && i.set(g.id, String(g.mimeType ?? ""));
2107
+ }), t.forEach((g) => {
2108
+ if (g.type === "inbound-rtp" && !g.isRemote && (s += Number(g.bytesReceived ?? 0), r += Math.max(0, Number(g.packetsLost ?? 0)), c += Math.max(0, Number(g.packetsReceived ?? 0)), Number.isFinite(g.jitter) && (l += Number(g.jitter), d += 1), u = Math.max(u, Number(g.framesPerSecond ?? 0)), S = Math.max(S, Number(g.frameWidth ?? 0)), f = Math.max(f, Number(g.frameHeight ?? 0)), v += Number(g.framesDropped ?? 0), I += Number(g.freezeCount ?? 0), y += Number(g.totalFreezesDuration ?? 0), k += Number(g.concealedSamples ?? 0), E ||= i.get(String(g.codecId ?? "")) ?? null), g.type === "outbound-rtp" && !g.isRemote && (o += Number(g.bytesSent ?? 0), A ||= g.qualityLimitationReason ? String(g.qualityLimitationReason) : null, E ||= i.get(String(g.codecId ?? "")) ?? null), g.type === "candidate-pair" && (g.selected || g.nominated) && g.state === "succeeded") {
2109
+ p = Number.isFinite(g.currentRoundTripTime) ? Number(g.currentRoundTripTime) : p, C = Number.isFinite(g.availableOutgoingBitrate) ? Number(g.availableOutgoingBitrate) : C;
2110
+ const q = n.get(g.localCandidateId);
2111
+ P = q?.candidateType ? String(q.candidateType) : P, L = q?.protocol ? String(q.protocol) : L;
2085
2112
  }
2086
2113
  });
2087
- const h = Date.now(), R = e ? Math.max(1e-3, (h - e.timestamp) / 1e3) : 0, L = e ? Math.max(0, Math.round((s - e.inboundBytes) * 8 / R)) : null, q = e ? Math.max(0, Math.round((o - e.outboundBytes) * 8 / R)) : null, E = r + c, P = e ? Math.max(0, r - e.packetsLost) : r, C = e ? Math.max(0, c - e.packetsReceived) : c, D = P + C;
2114
+ const w = Date.now(), M = e ? Math.max(1e-3, (w - e.timestamp) / 1e3) : 0, m = e ? Math.max(0, Math.round((s - e.inboundBytes) * 8 / M)) : null, h = e ? Math.max(0, Math.round((o - e.outboundBytes) * 8 / M)) : null, T = r + c, R = e ? Math.max(0, r - e.packetsLost) : r, b = e ? Math.max(0, c - e.packetsReceived) : c, O = R + b;
2088
2115
  return {
2089
- counters: { timestamp: h, inboundBytes: s, outboundBytes: o, packetsLost: r, packetsReceived: c },
2116
+ counters: { timestamp: w, inboundBytes: s, outboundBytes: o, packetsLost: r, packetsReceived: c },
2090
2117
  sample: {
2091
- rttMs: k === null ? null : k * 1e3,
2092
- jitterMs: l ? d / l * 1e3 : null,
2093
- packetLossPct: D ? P / D * 100 : null,
2094
- packetLossCumulativePct: E ? r / E * 100 : null,
2118
+ rttMs: p === null ? null : p * 1e3,
2119
+ jitterMs: d ? l / d * 1e3 : null,
2120
+ packetLossPct: O ? R / O * 100 : null,
2121
+ packetLossCumulativePct: T ? r / T * 100 : null,
2095
2122
  packetsLost: r,
2096
2123
  packetsReceived: c,
2097
- inboundBitrateBps: L,
2098
- outboundBitrateBps: q,
2099
- availableOutgoingBitrateBps: b,
2124
+ inboundBitrateBps: m,
2125
+ outboundBitrateBps: h,
2126
+ availableOutgoingBitrateBps: C,
2100
2127
  framesPerSecond: u || null,
2101
- frameWidth: y || null,
2128
+ frameWidth: S || null,
2102
2129
  frameHeight: f || null,
2103
- framesDropped: w,
2104
- freezeCount: m,
2105
- freezeDurationMs: Math.round(S * 1e3),
2106
- concealedSamples: T,
2107
- codec: g,
2108
- transportProtocol: I,
2109
- candidateType: M,
2110
- qualityLimitationReason: p
2130
+ framesDropped: v,
2131
+ freezeCount: I,
2132
+ freezeDurationMs: Math.round(y * 1e3),
2133
+ concealedSamples: k,
2134
+ codec: E,
2135
+ transportProtocol: L,
2136
+ candidateType: P,
2137
+ qualityLimitationReason: A
2111
2138
  }
2112
2139
  };
2113
2140
  }
2114
2141
  function Ae(a) {
2115
2142
  let e = a.mediaScore == null ? 5 : Math.round(se(Number(a.mediaScore), 0, 5));
2116
- const t = J(a.packetLossPct) ?? 0, i = J(a.rttMs) ?? 0, n = J(a.jitterMs) ?? 0, s = String(a.connectionState ?? "unknown").toLowerCase();
2143
+ const t = H(a.packetLossPct) ?? 0, i = H(a.rttMs) ?? 0, n = H(a.jitterMs) ?? 0, s = String(a.connectionState ?? "unknown").toLowerCase();
2117
2144
  ["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));
2118
2145
  const o = Number(se(4.5 - t * 0.09 - i * 11e-4 - n * 6e-3, 1, 4.5).toFixed(2));
2119
2146
  return { networkScore: e, estimatedMos: o };
@@ -2125,7 +2152,7 @@ function Le() {
2125
2152
  const a = Number(navigator.deviceMemory);
2126
2153
  return Number.isFinite(a) ? a : null;
2127
2154
  }
2128
- function J(a) {
2155
+ function H(a) {
2129
2156
  const e = Number(a);
2130
2157
  return Number.isFinite(e) ? e : null;
2131
2158
  }
@@ -2138,7 +2165,7 @@ function V(a) {
2138
2165
  function re(a, e) {
2139
2166
  return a instanceof Error ? a : new Error(e);
2140
2167
  }
2141
- const De = "1.3.16";
2168
+ const De = "1.3.18";
2142
2169
  export {
2143
2170
  Z as AVATAR_TUNING_DEFAULTS,
2144
2171
  Se as BACKGROUND_PRESETS,
@@ -2147,11 +2174,11 @@ export {
2147
2174
  Ee as RtcIncomingClient,
2148
2175
  qe as SPEAKER_NOISE_FLOOR,
2149
2176
  Oe as SPEAKER_TAKEOVER_RATIO,
2150
- Ue as createAvatarPipeline,
2177
+ xe as createAvatarPipeline,
2151
2178
  je as createCallRecorder,
2152
2179
  Ne as createPictureInPictureController,
2153
- Qe as createRtcClient,
2154
- xe as createRtcIncomingClient,
2180
+ Ue as createRtcClient,
2181
+ Qe as createRtcIncomingClient,
2155
2182
  Ve as createVideoEffectsPipeline,
2156
2183
  be as drawAvatar,
2157
2184
  we as headPoseFromMatrix,