@streaming-cdn/rtc-web 1.3.14 → 1.3.16

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,25 +1,25 @@
1
- const fe = 0.02, ge = 1.4;
2
- function H(c, e, t = 0.02, i = 1.4) {
3
- const n = c.filter((r) => r.level >= t);
1
+ const qe = 0.02, Oe = 1.4;
2
+ function oe(a, e, t = 0.02, i = 1.4) {
3
+ const n = a.filter((r) => r.level >= t);
4
4
  if (n.length === 0) return null;
5
- const s = n.reduce((r, o) => o.level > r.level ? o : r), a = n.find((r) => r.participantId === e);
6
- return a ? s.participantId === e ? e : s.level >= a.level * i ? s.participantId : e : s.participantId;
5
+ const s = n.reduce((r, c) => c.level > r.level ? c : r), o = n.find((r) => r.participantId === e);
6
+ return o ? s.participantId === e ? e : s.level >= o.level * i ? s.participantId : e : s.participantId;
7
7
  }
8
- function _(c) {
8
+ function ce(a) {
9
9
  const e = [];
10
- for (const t of c) {
10
+ for (const t of a) {
11
11
  if (String(t.type ?? "") !== "inbound-rtp" || String(t.kind ?? t.mediaType ?? "") !== "audio") continue;
12
12
  const i = Number(t.audioLevel ?? NaN);
13
13
  Number.isFinite(i) && e.push({ mid: typeof t.mid == "string" ? t.mid : null, level: i });
14
14
  }
15
15
  return e;
16
16
  }
17
- const f = {
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
- }, X = {
22
+ }, he = {
23
23
  warmupSamples: 3,
24
24
  poorSamplesToStepDown: 2,
25
25
  goodSamplesToStepUp: 6,
@@ -31,46 +31,46 @@ const f = {
31
31
  goodRttMs: 250,
32
32
  sustainRatio: 0.8
33
33
  };
34
- function Z(c) {
35
- const e = String(c ?? "").trim().toLowerCase();
34
+ function ue(a) {
35
+ const e = String(a ?? "").trim().toLowerCase();
36
36
  return !e || e === "none" ? "" : e === "cpu" || e === "bandwidth" ? e : "other";
37
37
  }
38
- function ee(c, e, t, i, n = {}) {
39
- const s = { ...X, ...n.thresholds }, a = ["low", "medium", "high"], r = n.ceiling && n.ceiling !== "audio" ? n.ceiling : "high", o = a.indexOf(r), l = a.indexOf(c), d = (n.samplesSeen ?? s.warmupSamples) + 1, u = d <= s.warmupSamples, m = Z(e.qualityLimitationReason), p = e.packetLossPct ?? 0, v = e.rttMs ?? 0, T = e.availableOutgoingBitrateBps, E = f[c].maxBitrate, w = p >= s.criticalLossPct || v >= s.criticalRttMs || m === "cpu", y = w || p >= s.poorLossPct || v >= s.poorRttMs || m === "bandwidth", b = T == null || T >= E * s.sustainRatio, C = p < s.goodLossPct && v < s.goodRttMs && !m && b, S = y ? t + 1 : 0, k = C ? i + 1 : 0, I = { quality: c, poorSamples: S, goodSamples: k, samplesSeen: d, changed: !1 };
40
- return l > o ? { quality: a[o], poorSamples: 0, goodSamples: 0, samplesSeen: d, changed: !0 } : u ? I : w && l > 0 ? { quality: a[l - 1], poorSamples: 0, goodSamples: 0, samplesSeen: d, changed: !0 } : S >= s.poorSamplesToStepDown && l > 0 ? { quality: a[l - 1], poorSamples: 0, goodSamples: 0, samplesSeen: d, changed: !0 } : k >= s.goodSamplesToStepUp && l < o ? { quality: a[l + 1], poorSamples: 0, goodSamples: 0, samplesSeen: d, changed: !0 } : I;
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;
41
41
  }
42
- function te(c, e) {
43
- const t = c instanceof Map ? c : new Map(c);
44
- let i = 0, n = 0, s = null, a = null, r = null;
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 m = Number(d.roundTripTime ?? NaN);
50
- Number.isFinite(m) && (a = m * 1e3);
42
+ function pe(a, e) {
43
+ const t = a instanceof Map ? a : new Map(a);
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);
51
51
  }
52
- if (u === "candidate-pair" && (d.nominated === !0 || String(d.state ?? "") === "succeeded")) {
53
- const m = Number(d.currentRoundTripTime ?? NaN);
54
- a == null && Number.isFinite(m) && (a = m * 1e3);
55
- const p = Number(d.availableOutgoingBitrate ?? NaN);
56
- Number.isFinite(p) && (r = p);
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);
56
+ Number.isFinite(f) && (r = f);
57
57
  }
58
58
  }
59
- const o = { packetsSent: i, packetsLost: n, timestamp: Date.now() };
60
- let l = null;
59
+ const c = { packetsSent: i, packetsLost: n, timestamp: Date.now() };
60
+ let d = null;
61
61
  if (e) {
62
- const d = i - e.packetsSent, u = n - e.packetsLost;
63
- d > 0 && u >= 0 && (l = u / (d + u) * 100);
62
+ const l = i - e.packetsSent, u = n - e.packetsLost;
63
+ l > 0 && u >= 0 && (d = u / (l + u) * 100);
64
64
  }
65
65
  return {
66
- sample: { packetLossPct: l, rttMs: a, availableOutgoingBitrateBps: r, qualityLimitationReason: s },
67
- counters: o
66
+ sample: { packetLossPct: d, rttMs: o, availableOutgoingBitrateBps: r, qualityLimitationReason: s },
67
+ counters: c
68
68
  };
69
69
  }
70
- const ie = {
70
+ const fe = {
71
71
  audio: { active: !1, maxBitrate: 0, maxFramerate: 0, scaleResolutionDownBy: 4 }
72
- }, ne = { active: !0, maxBitrate: 4e6, maxFramerate: 30, scaleResolutionDownBy: 1 };
73
- class A {
72
+ }, ge = { active: !0, maxBitrate: 4e6, maxFramerate: 30, scaleResolutionDownBy: 1 };
73
+ class x {
74
74
  options;
75
75
  socket = null;
76
76
  localStream = null;
@@ -153,14 +153,14 @@ class A {
153
153
  async setDevice(e) {
154
154
  const t = { deviceId: { exact: e.deviceId } }, i = await navigator.mediaDevices.getUserMedia(e.kind === "audioinput" ? { audio: t } : { video: { ...t, width: { ideal: 1920 }, height: { ideal: 1080 }, frameRate: { ideal: 30, max: 30 } } }), n = e.kind === "audioinput" ? i.getAudioTracks()[0] : i.getVideoTracks()[0];
155
155
  if (!n) throw new Error("Selected media device is unavailable");
156
- const s = e.kind === "audioinput" ? "audio" : "video", a = this.localStream?.getTracks().find((r) => r.kind === s);
157
- if (this.localStream || (this.localStream = new MediaStream()), a && (this.localStream.removeTrack(a), a.stop()), this.localStream.addTrack(n), s === "video") {
156
+ const s = e.kind === "audioinput" ? "audio" : "video", o = this.localStream?.getTracks().find((r) => r.kind === s);
157
+ if (this.localStream || (this.localStream = new MediaStream()), o && (this.localStream.removeTrack(o), o.stop()), this.localStream.addTrack(n), s === "video") {
158
158
  this.screenStream?.getVideoTracks().some((r) => r.readyState === "live") || await this.replaceVideoTrack(n);
159
159
  return;
160
160
  }
161
161
  for (const r of this.peers.values()) {
162
- const o = r.connection.getSenders().find((l) => l.track?.kind === s);
163
- o ? await o.replaceTrack(n) : r.connection.addTrack(n, this.localStream);
162
+ const c = r.connection.getSenders().find((d) => d.track?.kind === s);
163
+ c ? await c.replaceTrack(n) : r.connection.addTrack(n, this.localStream);
164
164
  }
165
165
  await this.applyVideoQuality();
166
166
  }
@@ -168,7 +168,7 @@ class A {
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 = A.clampToCeiling(t.quality, e), t.poorSamples = 0, t.goodSamples = 0;
171
+ t.quality = x.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 A {
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((o, l) => {
218
- this.resolveJoin = o, this.rejectJoin = l;
219
- }), s = new WebSocket(i, ["rtc-client", t.signalingToken]), a = ++this.socketGeneration;
217
+ const n = new Promise((c, d) => {
218
+ this.resolveJoin = c, this.rejectJoin = d;
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
- }), s.addEventListener("message", (o) => {
225
- const l = String(o.data);
224
+ }), s.addEventListener("message", (c) => {
225
+ const d = String(c.data);
226
226
  this.signalQueue = this.signalQueue.then(async () => {
227
- this.socket !== s || this.socketGeneration !== a || await this.handleSignal(l);
228
- }).catch((d) => {
229
- const u = d instanceof Error ? d.message : "RTC signaling processing failed";
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";
230
230
  this.options.onEvent("signalingerror", { message: u }), this.joined || this.rejectJoin?.(new Error(u));
231
231
  });
232
- }), s.addEventListener("error", () => this.rejectJoin?.(new Error("RTC signaling connection failed"))), s.addEventListener("close", (o) => {
232
+ }), s.addEventListener("error", () => this.rejectJoin?.(new Error("RTC signaling connection failed"))), s.addEventListener("close", (c) => {
233
233
  if (this.socket !== s) return;
234
- this.socket = null, this.stopHeartbeat(), this.stopQualitySampling(), !this.joined && !e && this.rejectJoin?.(new Error(o.reason || "RTC signaling connection closed"));
235
- const l = !this.stopped && (this.joined || e);
236
- this.joined = !1, l ? (this.resetPeers(), this.options.onEvent("reconnecting", { reason: o.reason, code: o.code, attempt: this.reconnectAttempt + 1 }), this.scheduleReconnect()) : this.stopped || this.options.onEvent("disconnected", { reason: o.reason, code: o.code });
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 });
237
237
  });
238
238
  try {
239
239
  await n, this.joined = !0, this.options.onEvent("connected", { participantId: t.participantId, resumed: e });
@@ -270,8 +270,8 @@ class A {
270
270
  if (i === "rtc.offer" && t.sender && t.description) {
271
271
  const n = this.ensurePeer(t.sender);
272
272
  n.offerTask && await n.offerTask;
273
- const s = n.connection.signalingState !== "stable", a = !this.shouldInitiateOffer(t.sender);
274
- if (s && !a) return;
273
+ const s = n.connection.signalingState !== "stable", o = !this.shouldInitiateOffer(t.sender);
274
+ if (s && !o) return;
275
275
  s && await n.connection.setLocalDescription({ type: "rollback" }), await n.connection.setRemoteDescription(t.description);
276
276
  const r = await n.connection.createAnswer();
277
277
  await n.connection.setLocalDescription(r), this.send({
@@ -313,19 +313,19 @@ class A {
313
313
  makingOffer: !1,
314
314
  offerTask: null,
315
315
  activeNegotiationId: null,
316
- quality: A.startingQuality(this.quality),
316
+ quality: x.startingQuality(this.quality),
317
317
  poorSamples: 0,
318
318
  goodSamples: 0,
319
319
  samplesSeen: 0,
320
320
  counters: null
321
321
  };
322
322
  this.peers.set(e.participantId, s);
323
- for (const o of this.localStream?.getAudioTracks() ?? []) i.addTrack(o, this.localStream);
324
- const a = this.screenStream?.getVideoTracks().some((o) => o.readyState === "live") ? this.screenStream : this.localStream, r = a?.getVideoTracks()[0];
325
- return r && a && (s.videoSender = i.addTrack(r, a)), !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", (o) => {
326
- o.candidate && this.send({ type: "rtc.ice", targetParticipantId: e.participantId, candidate: o.candidate.toJSON() });
327
- }), i.addEventListener("track", (o) => {
328
- n.getTracks().some((l) => l.id === o.track.id) || n.addTrack(o.track), this.options.onEvent("remotestream", { participant: e, stream: n, track: o.track });
323
+ for (const c of this.localStream?.getAudioTracks() ?? []) i.addTrack(c, this.localStream);
324
+ const o = this.screenStream?.getVideoTracks().some((c) => c.readyState === "live") ? this.screenStream : this.localStream, r = o?.getVideoTracks()[0];
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
+ c.candidate && this.send({ type: "rtc.ice", targetParticipantId: e.participantId, candidate: c.candidate.toJSON() });
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 });
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 A {
351
351
  });
352
352
  if (e.connection.signalingState !== "stable") return;
353
353
  await e.connection.setLocalDescription(t);
354
- const i = L();
354
+ const i = W();
355
355
  e.activeNegotiationId = i, this.send({
356
356
  type: "rtc.offer",
357
357
  targetParticipantId: e.identity.participantId,
@@ -371,10 +371,10 @@ class A {
371
371
  async replaceVideoTrack(e) {
372
372
  let t = !1;
373
373
  for (const i of this.peers.values()) {
374
- const n = i.videoSender ?? i.connection.getSenders().find((a) => a.track?.kind === "video") ?? i.connection.getTransceivers().find((a) => a.receiver.track.kind === "video")?.sender, s = i.videoTransceiver ?? i.connection.getTransceivers().find((a) => a.sender === n);
374
+ const n = i.videoSender ?? i.connection.getSenders().find((o) => o.track?.kind === "video") ?? i.connection.getTransceivers().find((o) => o.receiver.track.kind === "video")?.sender, s = i.videoTransceiver ?? i.connection.getTransceivers().find((o) => o.sender === n);
375
375
  if (n) {
376
- const a = e ? this.options.receiveVideo ? "sendrecv" : "sendonly" : this.options.receiveVideo ? "recvonly" : "inactive";
377
- s && s.direction !== a && (s.direction = a, t = !0), await n.replaceTrack(e), i.videoSender = n, s && (i.videoTransceiver = s);
376
+ const o = e ? this.options.receiveVideo ? "sendrecv" : "sendonly" : this.options.receiveVideo ? "recvonly" : "inactive";
377
+ s && s.direction !== o && (s.direction = o, t = !0), await n.replaceTrack(e), i.videoSender = n, s && (i.videoTransceiver = s);
378
378
  } else e && (i.videoSender = i.connection.addTrack(e, this.screenStream ?? this.localStream ?? new MediaStream([e])), t = !0);
379
379
  }
380
380
  t && await this.renegotiateAll(), await this.applyVideoQuality();
@@ -391,8 +391,8 @@ class A {
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 ? ne : this.quality === "audio" ? ie.audio : f[e.quality], a = i.getParameters(), r = a.encodings?.length ? a.encodings : [{}];
395
- a.encodings = r.map((o) => ({ ...o, ...s })), a.degradationPreference = n ? "maintain-resolution" : "maintain-framerate", await i.setParameters(a);
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 : [{}];
395
+ o.encodings = r.map((c) => ({ ...c, ...s })), o.degradationPreference = n ? "maintain-resolution" : "maintain-framerate", await i.setParameters(o);
396
396
  }
397
397
  }
398
398
  startQualitySampling() {
@@ -411,11 +411,11 @@ class A {
411
411
  if (i.connection.connectionState === "connected")
412
412
  try {
413
413
  const n = await i.connection.getStats();
414
- for (const s of _(n.values()))
414
+ for (const s of ce(n.values()))
415
415
  e.push({ participantId: i.identity.participantId, level: s.level });
416
416
  } catch {
417
417
  }
418
- const t = H(e, this.activeSpeaker);
418
+ const t = oe(e, this.activeSpeaker);
419
419
  t !== this.activeSpeaker && (this.activeSpeaker = t, this.options.onEvent("activespeaker", { participantId: t }));
420
420
  }
421
421
  async samplePeerQuality() {
@@ -428,9 +428,9 @@ class A {
428
428
  } catch {
429
429
  continue;
430
430
  }
431
- const { sample: i, counters: n } = te(t, e.counters);
431
+ const { sample: i, counters: n } = pe(t, e.counters);
432
432
  e.counters = n;
433
- const s = ee(e.quality, i, e.poorSamples, e.goodSamples, {
433
+ const s = me(e.quality, i, e.poorSamples, e.goodSamples, {
434
434
  samplesSeen: e.samplesSeen,
435
435
  ceiling: this.quality
436
436
  });
@@ -487,7 +487,7 @@ class A {
487
487
  }
488
488
  send(e) {
489
489
  this.socket?.readyState === WebSocket.OPEN && this.socket.send(JSON.stringify({
490
- clientMessageId: e.clientMessageId ?? L(),
490
+ clientMessageId: e.clientMessageId ?? W(),
491
491
  ...e
492
492
  }));
493
493
  }
@@ -495,15 +495,15 @@ class A {
495
495
  for (const t of e?.getTracks() ?? []) t.stop();
496
496
  }
497
497
  }
498
- function L() {
498
+ function W() {
499
499
  return globalThis.crypto?.randomUUID?.() ?? `${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`;
500
500
  }
501
- const M = { active: !0, maxBitrate: 4e6, maxFramerate: 30, scaleResolutionDownBy: 1 }, j = [
502
- { rid: "a", maxBitrate: f.high.maxBitrate, maxFramerate: f.high.maxFramerate },
503
- { rid: "b", maxBitrate: f.medium.maxBitrate, maxFramerate: f.medium.maxFramerate, scaleResolutionDownBy: 2 },
504
- { rid: "c", maxBitrate: f.low.maxBitrate, maxFramerate: f.low.maxFramerate, scaleResolutionDownBy: 4 }
505
- ], O = { high: "a", medium: "b", low: "c" };
506
- class se {
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 }
505
+ ], G = { high: "a", medium: "b", low: "c" };
506
+ class ye {
507
507
  options;
508
508
  apiBase;
509
509
  socket = null;
@@ -594,12 +594,12 @@ class se {
594
594
  async setDevice(e) {
595
595
  const t = { deviceId: { exact: e.deviceId } }, i = await navigator.mediaDevices.getUserMedia(e.kind === "audioinput" ? { audio: t } : { video: { ...t, width: { ideal: 1920 }, height: { ideal: 1080 }, frameRate: { ideal: 30, max: 30 } } }), n = e.kind === "audioinput" ? i.getAudioTracks()[0] : i.getVideoTracks()[0];
596
596
  if (!n) throw new Error("Selected media device is unavailable");
597
- const s = e.kind === "audioinput" ? "audio" : "video", a = this.localStream?.getTracks().find((o) => o.kind === s);
598
- if (this.localStream || (this.localStream = new MediaStream()), a && (this.localStream.removeTrack(a), a.stop()), this.localStream.addTrack(n), s === "video") {
599
- this.screenStream?.getVideoTracks().some((o) => o.readyState === "live") || await this.replaceVideoTrack(n);
597
+ const s = e.kind === "audioinput" ? "audio" : "video", o = this.localStream?.getTracks().find((c) => c.kind === s);
598
+ if (this.localStream || (this.localStream = new MediaStream()), o && (this.localStream.removeTrack(o), o.stop()), this.localStream.addTrack(n), s === "video") {
599
+ this.screenStream?.getVideoTracks().some((c) => c.readyState === "live") || await this.replaceVideoTrack(n);
600
600
  return;
601
601
  }
602
- const r = this.connection?.getSenders().find((o) => o.track?.kind === "audio");
602
+ const r = this.connection?.getSenders().find((c) => c.track?.kind === "audio");
603
603
  r && await r.replaceTrack(n);
604
604
  }
605
605
  /** One uplink serves everyone, so the requested quality applies directly. */
@@ -638,26 +638,26 @@ class se {
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((o, l) => {
642
- this.resolveJoin = o, this.rejectJoin = l;
643
- }), s = new WebSocket(i, ["rtc-client", t.signalingToken]), a = ++this.socketGeneration;
641
+ const n = new Promise((c, d) => {
642
+ this.resolveJoin = c, this.rejectJoin = d;
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
- }), s.addEventListener("message", (o) => {
649
- const l = String(o.data);
648
+ }), s.addEventListener("message", (c) => {
649
+ const d = String(c.data);
650
650
  this.signalQueue = this.signalQueue.then(async () => {
651
- this.socket !== s || this.socketGeneration !== a || await this.handleSignal(l);
652
- }).catch((d) => {
653
- const u = d instanceof Error ? d.message : "RTC signaling processing failed";
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";
654
654
  this.options.onEvent("signalingerror", { message: u }), this.joined || this.rejectJoin?.(new Error(u));
655
655
  });
656
- }), s.addEventListener("error", () => this.rejectJoin?.(new Error("RTC signaling connection failed"))), s.addEventListener("close", (o) => {
656
+ }), s.addEventListener("error", () => this.rejectJoin?.(new Error("RTC signaling connection failed"))), s.addEventListener("close", (c) => {
657
657
  if (this.socket !== s) return;
658
- this.socket = null, this.stopHeartbeat(), !this.joined && !e && this.rejectJoin?.(new Error(o.reason || "RTC signaling connection closed"));
659
- const l = !this.stopped && (this.joined || e);
660
- this.joined = !1, l ? (this.options.onEvent("reconnecting", { reason: o.reason, code: o.code, attempt: this.reconnectAttempt + 1 }), this.scheduleReconnect()) : this.stopped || this.options.onEvent("disconnected", { reason: o.reason, code: o.code });
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 });
661
661
  });
662
662
  try {
663
663
  await n, this.joined = !0, this.options.onEvent("connected", { participantId: t.participantId, resumed: e });
@@ -718,10 +718,10 @@ class se {
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: j.map((o) => ({ ...o })) } : {}
721
+ ...r.kind === "video" ? { sendEncodings: Y.map((c) => ({ ...c })) } : {}
722
722
  })), s = await t.createOffer();
723
723
  await t.setLocalDescription(s);
724
- const a = await this.sfuFetch(
724
+ const o = await this.sfuFetch(
725
725
  "POST",
726
726
  `/v1/rtc/sfu/sessions/${encodeURIComponent(i.sessionId)}/tracks`,
727
727
  {
@@ -733,7 +733,7 @@ class se {
733
733
  }))
734
734
  }
735
735
  );
736
- a.sessionDescription && await t.setRemoteDescription(a.sessionDescription), this.videoSender = t.getSenders().find((r) => r.track?.kind === "video") ?? null, await this.applyVideoQuality();
736
+ o.sessionDescription && await t.setRemoteDescription(o.sessionDescription), this.videoSender = t.getSenders().find((r) => r.track?.kind === "video") ?? null, await this.applyVideoQuality();
737
737
  }
738
738
  trackName(e) {
739
739
  return `${this.options.credential.participantId}/${e.kind}`;
@@ -753,7 +753,7 @@ class se {
753
753
  this.pendingAnnouncements.set(e.participantId, { sender: e, detail: t ?? {} });
754
754
  return;
755
755
  }
756
- const a = this.remotes.get(e.participantId) ?? {
756
+ const o = this.remotes.get(e.participantId) ?? {
757
757
  identity: e,
758
758
  stream: new MediaStream(),
759
759
  sessionId: i,
@@ -761,12 +761,12 @@ class se {
761
761
  simulcastNames: /* @__PURE__ */ new Set(),
762
762
  mids: /* @__PURE__ */ new Map()
763
763
  };
764
- a.sessionId = i;
764
+ o.sessionId = i;
765
765
  for (const r of n)
766
- r.simulcast && a.simulcastNames.add(r.trackName);
767
- this.remotes.set(e.participantId, a), this.negotiationQueue = this.negotiationQueue.then(async () => {
768
- const r = s.filter((o) => !a.trackNames.includes(o));
769
- r.length !== 0 && await this.subscribe(a, r);
766
+ r.simulcast && o.simulcastNames.add(r.trackName);
767
+ this.remotes.set(e.participantId, o), this.negotiationQueue = this.negotiationQueue.then(async () => {
768
+ const r = s.filter((c) => !o.trackNames.includes(c));
769
+ r.length !== 0 && await this.subscribe(o, r);
770
770
  }).catch((r) => {
771
771
  this.options.onEvent("signalingerror", { message: r instanceof Error ? r.message : "SFU subscribe failed" });
772
772
  }), await this.negotiationQueue;
@@ -818,7 +818,7 @@ class se {
818
818
  n && await this.sfuFetch("PUT", `/v1/rtc/sfu/sessions/${encodeURIComponent(this.sessionId)}/tracks/update`, {
819
819
  tracks: [{
820
820
  mid: n,
821
- simulcast: { preferredRid: O[t], priorityOrdering: "asciibetical", ridNotAvailable: "asciibetical" }
821
+ simulcast: { preferredRid: G[t], priorityOrdering: "asciibetical", ridNotAvailable: "asciibetical" }
822
822
  }]
823
823
  });
824
824
  }
@@ -830,16 +830,16 @@ class se {
830
830
  if (!e) return;
831
831
  const t = this.screenStream?.getVideoTracks()[0]?.id, i = !!(t && e.track?.id === t), n = e.getParameters(), s = n.encodings?.length ? n.encodings : [{}];
832
832
  if (s.length > 1) {
833
- const a = this.quality === "audio" ? null : O[this.quality];
833
+ const o = this.quality === "audio" ? null : G[this.quality];
834
834
  n.encodings = s.map((r) => {
835
835
  if (i)
836
- return { ...r, active: r.rid === "a", ...r.rid === "a" ? { maxBitrate: M.maxBitrate, maxFramerate: M.maxFramerate } : {} };
837
- const o = j.find((d) => d.rid === r.rid), l = a != null && String(r.rid ?? "") >= a;
838
- return { ...r, ...o ?? {}, active: l };
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 };
839
839
  });
840
840
  } else {
841
- const a = this.quality === "audio" ? f.audio : f[this.quality], r = i ? M : a;
842
- n.encodings = s.map((o) => ({ ...o, ...r }));
841
+ const o = this.quality === "audio" ? O.audio : O[this.quality], r = i ? $ : o;
842
+ n.encodings = s.map((c) => ({ ...c, ...r }));
843
843
  }
844
844
  n.degradationPreference = i ? "maintain-resolution" : "maintain-framerate", await e.setParameters(n);
845
845
  }
@@ -905,11 +905,11 @@ class se {
905
905
  return;
906
906
  }
907
907
  const i = [];
908
- for (const s of _(t.values())) {
909
- const a = s.mid ? this.midToParticipant.get(s.mid) : void 0;
910
- a && i.push({ participantId: a, level: s.level });
908
+ for (const s of ce(t.values())) {
909
+ const o = s.mid ? this.midToParticipant.get(s.mid) : void 0;
910
+ o && i.push({ participantId: o, level: s.level });
911
911
  }
912
- const n = H(i, this.activeSpeaker);
912
+ const n = oe(i, this.activeSpeaker);
913
913
  n !== this.activeSpeaker && (this.activeSpeaker = n, this.options.onEvent("activespeaker", { participantId: n }));
914
914
  }
915
915
  clearTimers() {
@@ -926,7 +926,7 @@ class se {
926
926
  }
927
927
  send(e) {
928
928
  this.socket?.readyState === WebSocket.OPEN && this.socket.send(JSON.stringify({
929
- clientMessageId: e.clientMessageId ?? ae(),
929
+ clientMessageId: e.clientMessageId ?? ve(),
930
930
  ...e
931
931
  }));
932
932
  }
@@ -934,28 +934,28 @@ class se {
934
934
  for (const t of e?.getTracks() ?? []) t.stop();
935
935
  }
936
936
  }
937
- function ae() {
937
+ function ve() {
938
938
  return globalThis.crypto?.randomUUID?.() ?? `${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`;
939
939
  }
940
- function ve(c, e = {}) {
940
+ function Ne(a, e = {}) {
941
941
  const t = e.document ?? globalThis.document, i = !!(t && t.pictureInPictureEnabled);
942
942
  let n = null;
943
943
  function s() {
944
944
  return n || (n = t.createElement("video"), n.muted = !0, n.playsInline = !0, n.style.position = "fixed", n.style.width = "1px", n.style.height = "1px", n.style.opacity = "0", n.style.pointerEvents = "none", n.addEventListener("leavepictureinpicture", () => e.onLeave?.()), t.body.appendChild(n), n);
945
945
  }
946
- function a(r) {
947
- const o = c.getRemoteStreams();
948
- return r ? o.find((l) => l.participant.participantId === r)?.stream ?? null : o[0]?.stream ?? c.getLocalStream();
946
+ function o(r) {
947
+ const c = a.getRemoteStreams();
948
+ return r ? c.find((d) => d.participant.participantId === r)?.stream ?? null : c[0]?.stream ?? a.getLocalStream();
949
949
  }
950
950
  return {
951
951
  supported: i,
952
952
  async enter(r) {
953
953
  if (!i) throw new Error("This browser does not support picture-in-picture");
954
- const o = a(r);
955
- if (!o) throw new Error("No video stream is available for picture-in-picture");
956
- const l = s();
957
- l.srcObject !== o && (l.srcObject = o), await l.play().catch(() => {
958
- }), await l.requestPictureInPicture();
954
+ const c = o(r);
955
+ 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();
959
959
  },
960
960
  async exit() {
961
961
  t.pictureInPictureElement && typeof t.exitPictureInPicture == "function" && await t.exitPictureInPicture();
@@ -965,7 +965,358 @@ function ve(c, e = {}) {
965
965
  }
966
966
  };
967
967
  }
968
- class re extends EventTarget {
968
+ function je(a, e) {
969
+ 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,
974
+ headers: {
975
+ authorization: `Bearer ${e.credential.signalingToken}`,
976
+ "content-type": b
977
+ },
978
+ body: k === void 0 ? void 0 : b === "application/json" ? JSON.stringify(k) : k
979
+ });
980
+ if (!M.ok) throw new Error(`Recording request failed with HTTP ${M.status}`);
981
+ return M.json();
982
+ }
983
+ return {
984
+ get recording() {
985
+ return w;
986
+ },
987
+ 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;
996
+ };
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" }] : []
1001
+ ];
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);
1007
+ });
1008
+ }, 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),
1014
+ ...a.getLocalStream() ? [a.getLocalStream()] : []
1015
+ ];
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));
1019
+ };
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
+ },
1027
+ 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
+ f = [];
1035
+ const b = Math.max(1, Math.round((Date.now() - y) / 1e3)), M = await m(
1036
+ "PUT",
1037
+ `/v1/rtc/recordings/${encodeURIComponent(u)}/media`,
1038
+ k,
1039
+ s
1040
+ );
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;
1044
+ },
1045
+ dispose() {
1046
+ d && clearInterval(d), d = null;
1047
+ try {
1048
+ c?.stop();
1049
+ } catch {
1050
+ }
1051
+ c = null, l?.close().catch(() => {
1052
+ }), l = null, w = !1;
1053
+ }
1054
+ };
1055
+ }
1056
+ const Se = ["none", "blur", "aurora", "cybergrid", "bokeh", "sunset", "image"], ke = ["none", "snow", "confetti", "vignette"], K = {
1057
+ aurora(a, e, t, i) {
1058
+ const n = a.createLinearGradient(0, 0, 0, t);
1059
+ n.addColorStop(0, "#050b1e"), n.addColorStop(1, "#0b2540"), a.fillStyle = n, a.fillRect(0, 0, e, t);
1060
+ for (let s = 0; s < 3; s += 1) {
1061
+ a.beginPath();
1062
+ for (let o = 0; o <= e; o += 16) {
1063
+ const r = t * 0.35 + s * 40 + Math.sin(o / 140 + i / 900 + s) * 60;
1064
+ o === 0 ? a.moveTo(o, r) : a.lineTo(o, r);
1065
+ }
1066
+ a.lineTo(e, 0), a.lineTo(0, 0), a.closePath(), a.fillStyle = `hsla(${140 + s * 40 + Math.sin(i / 1300) * 20}, 80%, 55%, 0.14)`, a.fill();
1067
+ }
1068
+ },
1069
+ cybergrid(a, e, t, i) {
1070
+ a.fillStyle = "#0a0118", a.fillRect(0, 0, e, t), a.strokeStyle = "rgba(255,0,180,0.5)", a.lineWidth = 1.5;
1071
+ const n = t * 0.45;
1072
+ for (let o = 0; o < 12; o += 1) {
1073
+ const r = n + (o * 34 + i / 18) % (t - n);
1074
+ a.beginPath(), a.moveTo(0, r), a.lineTo(e, r), a.stroke();
1075
+ }
1076
+ for (let o = -8; o <= 8; o += 1)
1077
+ a.beginPath(), a.moveTo(e / 2 + o * 24, n), a.lineTo(e / 2 + o * e * 0.12, t), a.stroke();
1078
+ const s = a.createLinearGradient(0, t * 0.1, 0, n);
1079
+ s.addColorStop(0, "#ffd34d"), s.addColorStop(1, "#ff2d78"), a.fillStyle = s, a.beginPath(), a.arc(e / 2, n, t * 0.22, Math.PI, 0), a.fill();
1080
+ },
1081
+ bokeh(a, e, t, i) {
1082
+ a.fillStyle = "#14100c", a.fillRect(0, 0, e, t);
1083
+ for (let n = 0; n < 26; n += 1) {
1084
+ const s = (Math.sin(n * 12.9898) * 0.5 + 0.5) * e, o = (Math.sin(n * 78.233) * 0.5 + 0.5) * t + Math.sin(i / 1500 + n) * 12, r = 14 + n % 5 * 12;
1085
+ a.fillStyle = `hsla(${35 + n % 4 * 12}, 90%, 60%, ${0.1 + n % 3 * 0.05})`, a.beginPath(), a.arc(s, o, r, 0, Math.PI * 2), a.fill();
1086
+ }
1087
+ },
1088
+ sunset(a, e, t, i) {
1089
+ const n = a.createLinearGradient(0, 0, 0, t);
1090
+ 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);
1091
+ }
1092
+ };
1093
+ 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(() => {
1099
+ });
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) => ({
1105
+ x: (Math.sin(h * 12.9898) * 0.5 + 0.5) * i,
1106
+ y: (Math.sin(h * 78.233) * 0.5 + 0.5) * n,
1107
+ speed: 0.6 + h % 5 * 0.5,
1108
+ drift: Math.sin(h) * 0.6,
1109
+ size: 2 + h % 4,
1110
+ hue: h * 47 % 360
1111
+ }));
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);
1115
+ return;
1116
+ }
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);
1127
+ }
1128
+ }
1129
+ const I = setInterval(() => {
1130
+ M(Date.now()), l && !y && r !== "none" && (y = !0, l.segment(f).then((p) => {
1131
+ u = p;
1132
+ }).catch(() => {
1133
+ u = null;
1134
+ }).finally(() => {
1135
+ y = !1;
1136
+ }));
1137
+ }, Math.round(1e3 / s)), g = w.captureStream(s);
1138
+ 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);
1143
+ },
1144
+ setOverlay(p) {
1145
+ c = ke.includes(p) ? p : "none";
1146
+ },
1147
+ setSegmenter(p) {
1148
+ l = p, p || (u = null);
1149
+ },
1150
+ dispose() {
1151
+ clearInterval(I), l?.close?.();
1152
+ for (const p of g.getTracks()) p.stop();
1153
+ f.srcObject = null;
1154
+ }
1155
+ };
1156
+ }
1157
+ function le() {
1158
+ return {
1159
+ blinkLeft: 0,
1160
+ blinkRight: 0,
1161
+ jawOpen: 0,
1162
+ smile: 0,
1163
+ browUp: 0,
1164
+ pupilX: 0,
1165
+ pupilY: 0,
1166
+ headYaw: 0,
1167
+ headPitch: 0,
1168
+ headRoll: 0,
1169
+ tracked: !1
1170
+ };
1171
+ }
1172
+ function A(a, e) {
1173
+ const t = a.find((i) => i.categoryName === e);
1174
+ return t ? Math.max(0, Math.min(1, t.score)) : 0;
1175
+ }
1176
+ function we(a) {
1177
+ if (!a || a.length < 16) return { yaw: 0, pitch: 0, roll: 0 };
1178
+ a[0], a[4];
1179
+ 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);
1180
+ return { yaw: o, pitch: r, roll: c };
1181
+ }
1182
+ function Te(a, e, t = 1) {
1183
+ 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;
1185
+ 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,
1191
+ pupilX: n - s,
1192
+ pupilY: r - o,
1193
+ headYaw: i.yaw,
1194
+ headPitch: i.pitch,
1195
+ headRoll: i.roll,
1196
+ tracked: !0
1197
+ };
1198
+ }
1199
+ function X(a, e, t = 0.4) {
1200
+ const i = (n, s) => n + (s - n) * t;
1201
+ return {
1202
+ blinkLeft: i(a.blinkLeft, e.blinkLeft),
1203
+ blinkRight: i(a.blinkRight, e.blinkRight),
1204
+ jawOpen: i(a.jawOpen, e.jawOpen),
1205
+ smile: i(a.smile, e.smile),
1206
+ browUp: i(a.browUp, e.browUp),
1207
+ pupilX: i(a.pupilX, e.pupilX),
1208
+ pupilY: i(a.pupilY, e.pupilY),
1209
+ headYaw: i(a.headYaw, e.headYaw),
1210
+ headPitch: i(a.headPitch, e.headPitch),
1211
+ headRoll: i(a.headRoll, e.headRoll),
1212
+ tracked: e.tracked
1213
+ };
1214
+ }
1215
+ function be(a, e, t, i, n) {
1216
+ n || (a.fillStyle = "#101822", a.fillRect(0, 0, t, i));
1217
+ 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
+ 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;
1222
+ 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,
1236
+ 0,
1237
+ 0,
1238
+ Math.PI * 2
1239
+ ), a.fill();
1240
+ }
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");
1243
+ }
1244
+ const Z = {
1245
+ mouthGain: 1.7,
1246
+ blinkGain: 1,
1247
+ eyeSync: 1,
1248
+ smoothing: 0.4,
1249
+ avatarScale: 1,
1250
+ avatarLift: 0,
1251
+ lostHoldMs: 400
1252
+ };
1253
+ function ee() {
1254
+ return {
1255
+ render(a, e, t, i, n) {
1256
+ be(a, e, t, i, n ?? void 0);
1257
+ }
1258
+ };
1259
+ }
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(() => {
1267
+ });
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;
1280
+ try {
1281
+ h = r.detect(y, g);
1282
+ } catch {
1283
+ }
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));
1286
+ }
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);
1290
+ }
1291
+ const M = setInterval(() => b(Date.now()), Math.round(1e3 / s)), I = f.captureStream(s);
1292
+ return {
1293
+ track: I.getVideoTracks()[0],
1294
+ stream: I,
1295
+ getRig: () => ({ ...m }),
1296
+ setMode(g) {
1297
+ d = g === "overlay" ? "overlay" : "replace";
1298
+ },
1299
+ setTracker(g) {
1300
+ r?.close?.(), r = g;
1301
+ },
1302
+ setRenderer(g) {
1303
+ c?.dispose?.(), c = g ?? ee();
1304
+ },
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);
1309
+ }
1310
+ },
1311
+ getTuning: () => ({ ...l }),
1312
+ dispose() {
1313
+ clearInterval(M), r?.close?.(), c?.dispose?.();
1314
+ for (const g of I.getTracks()) g.stop();
1315
+ y.srcObject = null;
1316
+ }
1317
+ };
1318
+ }
1319
+ class Ce extends EventTarget {
969
1320
  mode;
970
1321
  options;
971
1322
  client = null;
@@ -999,7 +1350,7 @@ class re extends EventTarget {
999
1350
  async initialize() {
1000
1351
  if (this.client) return this;
1001
1352
  try {
1002
- const t = (this.options.transport === "auto" ? this.mode === "meeting" ? "sfu" : "mesh" : this.options.transport ?? "mesh") === "sfu" ? se : A;
1353
+ const t = (this.options.transport === "auto" ? this.mode === "meeting" ? "sfu" : "mesh" : this.options.transport ?? "mesh") === "sfu" ? ye : x;
1003
1354
  return this.client = new t({
1004
1355
  credential: {
1005
1356
  signalingToken: this.options.credential.signalingToken,
@@ -1018,19 +1369,19 @@ class re extends EventTarget {
1018
1369
  iceTransportPolicy: this.options.iceTransportPolicy ?? "all",
1019
1370
  localStream: this.options.localStream,
1020
1371
  onEvent: (i, n) => this.handleNativeEvent(i, n)
1021
- }), await this.client.initialize(), this.startStats(), this.emit("initialized", { mode: this.mode, sdkVersion: pe }), this.options.autoJoin && await this.join(), this;
1372
+ }), await this.client.initialize(), this.startStats(), this.emit("initialized", { mode: this.mode, sdkVersion: De }), this.options.autoJoin && await this.join(), this;
1022
1373
  } catch (e) {
1023
1374
  this.state = "failed";
1024
- const t = z(e, "RTC initialization failed");
1025
- throw this.emit("error", g(t)), t;
1375
+ const t = re(e, "RTC initialization failed");
1376
+ throw this.emit("error", V(t)), t;
1026
1377
  }
1027
1378
  }
1028
1379
  async join() {
1029
1380
  const e = this.requireClient();
1030
1381
  return this.joinPromise ? this.joinPromise : (this.state = "joining", this.emit("joining", {}), this.joinPromise = e.join().catch((t) => {
1031
1382
  this.state = "failed";
1032
- const i = z(t, "RTC connection failed");
1033
- throw this.emit("error", g(i)), i;
1383
+ const i = re(t, "RTC connection failed");
1384
+ throw this.emit("error", V(i)), i;
1034
1385
  }).finally(() => {
1035
1386
  this.joinPromise = null;
1036
1387
  }), this.joinPromise);
@@ -1068,14 +1419,14 @@ class re extends EventTarget {
1068
1419
  return navigator.mediaDevices?.enumerateDevices ? navigator.mediaDevices.enumerateDevices() : [];
1069
1420
  }
1070
1421
  getParticipants() {
1071
- return this.requireClient().getParticipants().map(F);
1422
+ return this.requireClient().getParticipants().map(ne);
1072
1423
  }
1073
1424
  getLocalStream() {
1074
1425
  return this.client?.getLocalStream() ?? null;
1075
1426
  }
1076
1427
  getRemoteStreams() {
1077
1428
  return (this.client?.getRemoteStreams() ?? []).map((e) => ({
1078
- participant: F(e.participant),
1429
+ participant: ne(e.participant),
1079
1430
  stream: e.stream
1080
1431
  }));
1081
1432
  }
@@ -1144,45 +1495,45 @@ class re extends EventTarget {
1144
1495
  let n = "unavailable";
1145
1496
  if (e.requestMedia !== !1 && navigator.mediaDevices?.getUserMedia)
1146
1497
  try {
1147
- (await navigator.mediaDevices.getUserMedia({ audio: this.options.audio, video: this.options.video })).getTracks().forEach((m) => m.stop()), n = "granted";
1498
+ (await navigator.mediaDevices.getUserMedia({ audio: this.options.audio, video: this.options.video })).getTracks().forEach((y) => y.stop()), n = "granted";
1148
1499
  } catch {
1149
1500
  n = "denied", t.push("media_permission_denied");
1150
1501
  }
1151
- const s = navigator.mediaDevices?.enumerateDevices ? await navigator.mediaDevices.enumerateDevices().catch(() => []) : [], a = s.filter((u) => u.kind === "audioinput").length, r = s.filter((u) => u.kind === "videoinput").length;
1152
- this.options.audio && a === 0 && t.push("microphone_unavailable"), this.options.video && r === 0 && t.push("camera_unavailable");
1153
- const o = e.probeUrl ?? this.options.preflightProbeUrl;
1154
- let l = null;
1155
- if (o) {
1502
+ 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
+ this.options.audio && o === 0 && t.push("microphone_unavailable"), this.options.video && r === 0 && t.push("camera_unavailable");
1504
+ const c = e.probeUrl ?? this.options.preflightProbeUrl;
1505
+ let d = null;
1506
+ if (c) {
1156
1507
  const u = performance.now();
1157
1508
  try {
1158
- const m = await fetch(o, { method: "HEAD", cache: "no-store", credentials: "omit" });
1159
- l = Math.round(performance.now() - u), m.ok || t.push("network_probe_failed");
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");
1160
1511
  } catch {
1161
1512
  t.push("network_probe_failed");
1162
1513
  }
1163
1514
  }
1164
- const d = {
1515
+ const l = {
1165
1516
  passed: t.length === 0,
1166
1517
  sampledAt: (/* @__PURE__ */ new Date()).toISOString(),
1167
1518
  secureContext: i,
1168
1519
  mediaPermission: n,
1169
- microphoneCount: a,
1520
+ microphoneCount: o,
1170
1521
  cameraCount: r,
1171
- probeLatencyMs: l,
1172
- effectiveConnectionType: J()?.effectiveType ?? null,
1522
+ probeLatencyMs: d,
1523
+ effectiveConnectionType: ae()?.effectiveType ?? null,
1173
1524
  issues: t
1174
1525
  };
1175
- return this.emit("preflight", d), this.options.autoReportStats && await this.reportQuality({
1526
+ return this.emit("preflight", l), this.options.autoReportStats && await this.reportQuality({
1176
1527
  sampleType: "preflight",
1177
- sampledAt: d.sampledAt,
1178
- connectionState: d.passed ? "ready" : "failed",
1179
- rttMs: d.probeLatencyMs,
1180
- effectiveConnectionType: d.effectiveConnectionType
1528
+ sampledAt: l.sampledAt,
1529
+ connectionState: l.passed ? "ready" : "failed",
1530
+ rttMs: l.probeLatencyMs,
1531
+ effectiveConnectionType: l.effectiveConnectionType
1181
1532
  }).catch(() => {
1182
- }), d;
1533
+ }), l;
1183
1534
  }
1184
1535
  async collectQualitySample(e = "runtime") {
1185
- const t = this.options.statsProvider ? await this.options.statsProvider() : {}, i = this.peerConnection ? await he(this.peerConnection, this.previousCounters) : null;
1536
+ const t = this.options.statsProvider ? await this.options.statsProvider() : {}, i = this.peerConnection ? await Pe(this.peerConnection, this.previousCounters) : null;
1186
1537
  i?.counters && (this.previousCounters = i.counters);
1187
1538
  const s = { ...{
1188
1539
  sampleType: e,
@@ -1211,10 +1562,10 @@ class re extends EventTarget {
1211
1562
  transportProtocol: null,
1212
1563
  candidateType: null,
1213
1564
  qualityLimitationReason: null,
1214
- deviceMemoryGb: me(),
1215
- effectiveConnectionType: J()?.effectiveType ?? null
1216
- }, ...i?.sample ?? {}, ...t, sampleType: e, sampledAt: (/* @__PURE__ */ new Date()).toISOString() }, a = ue(s);
1217
- return s.networkScore = a.networkScore, s.estimatedMos = a.estimatedMos, this.latestQuality = s, s;
1565
+ deviceMemoryGb: Le(),
1566
+ effectiveConnectionType: ae()?.effectiveType ?? null
1567
+ }, ...i?.sample ?? {}, ...t, sampleType: e, sampledAt: (/* @__PURE__ */ new Date()).toISOString() }, o = Ae(s);
1568
+ return s.networkScore = o.networkScore, s.estimatedMos = o.estimatedMos, this.latestQuality = s, s;
1218
1569
  }
1219
1570
  async reportQuality(e) {
1220
1571
  const t = this.options.credential.telemetryToken, i = this.options.telemetryEndpoint ?? this.options.credential.telemetryEndpoint;
@@ -1264,7 +1615,7 @@ class re extends EventTarget {
1264
1615
  const i = Date.now(), n = e !== "runtime" || i - this.lastTelemetryAt >= this.options.telemetryInterval;
1265
1616
  this.options.autoReportStats && n && (await this.reportQuality(t), this.lastTelemetryAt = i);
1266
1617
  } catch (t) {
1267
- this.emit("telemetryerror", g(t));
1618
+ this.emit("telemetryerror", V(t));
1268
1619
  } finally {
1269
1620
  this.statsRunning = !1;
1270
1621
  }
@@ -1281,8 +1632,8 @@ class re extends EventTarget {
1281
1632
  }
1282
1633
  const t = String(e.qualityLimitationReason ?? "").toLowerCase(), i = (e.packetLossPct ?? 0) >= 8 || (e.rttMs ?? 0) >= 800 || t === "cpu" || t === "bandwidth", n = i || (e.packetLossPct ?? 0) >= 3 || (e.rttMs ?? 0) >= 350 || e.availableOutgoingBitrateBps != null && e.availableOutgoingBitrateBps < 35e4, s = (e.packetLossPct ?? 100) < 1 && (e.rttMs ?? 1e3) < 180 && !t && (e.availableOutgoingBitrateBps == null || e.availableOutgoingBitrateBps > 1e6);
1283
1634
  this.poorQualitySamples = n ? this.poorQualitySamples + 1 : 0, this.goodQualitySamples = s ? this.goodQualitySamples + 1 : 0;
1284
- const a = ["low", "medium", "high"], r = a.indexOf(this.effectiveQuality);
1285
- i && r > 0 ? (this.poorQualitySamples = 0, await this.applyEffectiveQuality("low", "network")) : this.poorQualitySamples >= 2 && r > 0 ? (this.poorQualitySamples = 0, await this.applyEffectiveQuality(a[r - 1], "network")) : this.goodQualitySamples >= 6 && r >= 0 && r < a.length - 1 && (this.goodQualitySamples = 0, await this.applyEffectiveQuality(a[r + 1], "network"));
1635
+ const o = ["low", "medium", "high"], r = o.indexOf(this.effectiveQuality);
1636
+ i && r > 0 ? (this.poorQualitySamples = 0, await this.applyEffectiveQuality("low", "network")) : this.poorQualitySamples >= 2 && r > 0 ? (this.poorQualitySamples = 0, await this.applyEffectiveQuality(o[r - 1], "network")) : this.goodQualitySamples >= 6 && r >= 0 && r < o.length - 1 && (this.goodQualitySamples = 0, await this.applyEffectiveQuality(o[r + 1], "network"));
1286
1637
  }
1287
1638
  async applyEffectiveQuality(e, t) {
1288
1639
  if (this.effectiveQuality === e && this.client) return;
@@ -1298,21 +1649,21 @@ class re extends EventTarget {
1298
1649
  this.dispatchEvent(new CustomEvent(e, { detail: i })), this.options.onEvent?.(i);
1299
1650
  }
1300
1651
  }
1301
- async function ye(c) {
1302
- return new re(c).initialize();
1652
+ async function Qe(a) {
1653
+ return new Ce(a).initialize();
1303
1654
  }
1304
- let P = null;
1305
- function W() {
1306
- if (P) return P;
1307
- const c = globalThis, e = c.AudioContext ?? c.webkitAudioContext;
1308
- return e ? (P = new e(), P) : null;
1655
+ let Q = null;
1656
+ function de() {
1657
+ if (Q) return Q;
1658
+ const a = globalThis, e = a.AudioContext ?? a.webkitAudioContext;
1659
+ return e ? (Q = new e(), Q) : null;
1309
1660
  }
1310
- async function oe() {
1311
- const c = W();
1312
- return c ? (c.state === "suspended" && await c.resume().catch(() => {
1313
- }), c.state === "running") : !1;
1661
+ async function Re() {
1662
+ const a = de();
1663
+ return a ? (a.state === "suspended" && await a.resume().catch(() => {
1664
+ }), a.state === "running") : !1;
1314
1665
  }
1315
- class ce {
1666
+ class Ie {
1316
1667
  options;
1317
1668
  media = null;
1318
1669
  cadenceTimer = null;
@@ -1321,7 +1672,7 @@ class ce {
1321
1672
  this.options = e;
1322
1673
  }
1323
1674
  unlock() {
1324
- return oe();
1675
+ return Re();
1325
1676
  }
1326
1677
  startIncoming() {
1327
1678
  this.start("incoming", this.options.ringtoneUrl);
@@ -1349,17 +1700,17 @@ class ce {
1349
1700
  i(), this.cadenceTimer = setInterval(i, e === "incoming" ? 3e3 : 3500);
1350
1701
  }
1351
1702
  playBuiltInTone(e) {
1352
- const t = W();
1703
+ const t = de();
1353
1704
  if (!t || t.state !== "running") return;
1354
- const i = e === "incoming" ? 1.25 : 1, n = e === "incoming" ? [440, 480] : [425], s = t.createGain(), a = t.currentTime;
1355
- s.gain.setValueAtTime(1e-4, a), s.gain.exponentialRampToValueAtTime(0.045, a + 0.025), s.gain.setValueAtTime(0.045, a + i - 0.06), s.gain.exponentialRampToValueAtTime(1e-4, a + i), s.connect(t.destination);
1705
+ const i = e === "incoming" ? 1.25 : 1, n = e === "incoming" ? [440, 480] : [425], s = t.createGain(), o = t.currentTime;
1706
+ 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);
1356
1707
  for (const r of n) {
1357
- const o = t.createOscillator();
1358
- o.type = "sine", o.frequency.value = r, o.connect(s), this.oscillators.add(o), o.onended = () => this.oscillators.delete(o), o.start(a), o.stop(a + i + 0.02);
1708
+ const c = t.createOscillator();
1709
+ c.type = "sine", c.frequency.value = r, c.connect(s), this.oscillators.add(c), c.onended = () => this.oscillators.delete(c), c.start(o), c.stop(o + i + 0.02);
1359
1710
  }
1360
1711
  }
1361
1712
  }
1362
- class le extends EventTarget {
1713
+ class Ee extends EventTarget {
1363
1714
  options;
1364
1715
  socket = null;
1365
1716
  stopped = !1;
@@ -1386,14 +1737,14 @@ class le extends EventTarget {
1386
1737
  if (e.token && !e.token.startsWith("rtcc_")) throw new Error("A valid RTC client token is required");
1387
1738
  if (!e.signalingUrl && !e.apiBaseUrl && !globalThis.location?.origin)
1388
1739
  throw new Error("signalingUrl or apiBaseUrl is required outside a browser");
1389
- this.options = e, this.currentToken = e.token ?? null, this.currentTokenExpiresAt = e.tokenExpiresAt, this.callAudio = new ce(e), this.mount = B(e.mount), this.scheduleTokenRefresh();
1740
+ this.options = e, this.currentToken = e.token ?? null, this.currentTokenExpiresAt = e.tokenExpiresAt, this.callAudio = new Ie(e), this.mount = te(e.mount), this.scheduleTokenRefresh();
1390
1741
  }
1391
1742
  connect() {
1392
1743
  if (!this.options.signalingUrl) throw new Error("signalingUrl is required to connect signaling");
1393
1744
  return this.stopped = !1, this.scheduleTokenRefresh(), this.openSocket("initial"), this;
1394
1745
  }
1395
1746
  setMount(e) {
1396
- this.clearUi(), this.mount = B(e), this.currentCall && this.renderIncoming(this.currentCall);
1747
+ this.clearUi(), this.mount = te(e), this.currentCall && this.renderIncoming(this.currentCall);
1397
1748
  }
1398
1749
  /** Binds media lifetime to a call. Terminal call states automatically leave and destroy it. */
1399
1750
  attachMediaClient(e, t) {
@@ -1421,8 +1772,8 @@ class le extends EventTarget {
1421
1772
  headers: e.idempotencyKey ? { "idempotency-key": e.idempotencyKey } : void 0,
1422
1773
  body: JSON.stringify(i)
1423
1774
  });
1424
- } catch (a) {
1425
- throw this.callAudio.stop(), a;
1775
+ } catch (o) {
1776
+ throw this.callAudio.stop(), o;
1426
1777
  }
1427
1778
  return !s.credential && s.callerCredential && (s.credential = s.callerCredential), this.outgoingCallId = String(s.call?.id ?? "") || null, this.outgoingCallId && this.activeCallIds.add(this.outgoingCallId), this.emit("outgoingcall", s), s;
1428
1779
  })();
@@ -1479,7 +1830,7 @@ class le extends EventTarget {
1479
1830
  /** Applies a call state received through the application's own push or signaling channel. */
1480
1831
  handleCallUpdate(e) {
1481
1832
  const t = e.id === this.currentCall?.id || e.id === this.outgoingCallId;
1482
- 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, de(e.status)), ["rejected", "busy", "cancelled", "ended", "failed", "missed"].includes(e.status) && this.releaseMedia(e.id), this.emit("callupdated", e);
1833
+ 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);
1483
1834
  }
1484
1835
  disconnect() {
1485
1836
  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();
@@ -1495,7 +1846,7 @@ class le extends EventTarget {
1495
1846
  try {
1496
1847
  t = await this.resolveToken(e, e === "reconnect");
1497
1848
  } catch (s) {
1498
- this.emit("tokenerror", g(s)), !this.stopped && this.options.reconnect !== !1 && this.scheduleReconnect();
1849
+ this.emit("tokenerror", V(s)), !this.stopped && this.options.reconnect !== !1 && this.scheduleReconnect();
1499
1850
  return;
1500
1851
  }
1501
1852
  if (this.stopped || this.socket) return;
@@ -1503,8 +1854,8 @@ class le extends EventTarget {
1503
1854
  i.protocol = i.protocol === "https:" ? "wss:" : "ws:";
1504
1855
  const n = new WebSocket(i, ["rtc-client", t]);
1505
1856
  this.socket = n, n.addEventListener("open", () => {
1506
- const s = this.reconnectAttempt > 0, a = this.lastDisconnect;
1507
- this.reconnectAttempt = 0, this.heartbeatDeadline = Date.now() + 45e3, this.emit("signalingconnected", { resumed: s }), a && (this.reportSignalingDiagnostic({ event: "recovered", code: a.code, reason: a.reason, wasClean: a.wasClean, outageMs: Date.now() - a.at }), this.lastDisconnect = null), this.heartbeatTimer && clearInterval(this.heartbeatTimer), this.heartbeatTimer = setInterval(() => {
1857
+ const s = this.reconnectAttempt > 0, o = this.lastDisconnect;
1858
+ 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(() => {
1508
1859
  if (n.readyState === WebSocket.OPEN) {
1509
1860
  if (Date.now() > this.heartbeatDeadline) {
1510
1861
  n.close(4e3, "Signaling heartbeat timed out");
@@ -1518,14 +1869,14 @@ class le extends EventTarget {
1518
1869
  }), n.addEventListener("close", (s) => {
1519
1870
  if (this.socket !== n) return;
1520
1871
  this.socket = null, this.heartbeatTimer && clearInterval(this.heartbeatTimer), this.heartbeatTimer = null;
1521
- const a = !this.stopped && this.options.reconnect !== !1, r = {
1872
+ const o = !this.stopped && this.options.reconnect !== !1, r = {
1522
1873
  code: s.code,
1523
1874
  reason: s.reason,
1524
1875
  wasClean: s.wasClean,
1525
- willReconnect: a,
1876
+ willReconnect: o,
1526
1877
  attempt: this.reconnectAttempt + 1
1527
1878
  };
1528
- a && (this.lastDisconnect = { code: s.code, reason: s.reason, wasClean: s.wasClean, at: Date.now() }), this.emit("signalingdisconnected", r), this.reportSignalingDiagnostic({ event: a ? "reconnecting" : "disconnected", ...r }), a && this.scheduleReconnect();
1879
+ o && (this.lastDisconnect = { code: s.code, reason: s.reason, wasClean: s.wasClean, at: Date.now() }), this.emit("signalingdisconnected", r), this.reportSignalingDiagnostic({ event: o ? "reconnecting" : "disconnected", ...r }), o && this.scheduleReconnect();
1529
1880
  }), n.addEventListener("error", () => {
1530
1881
  const s = { message: "RTC signaling connection failed", reconnecting: !this.stopped && this.options.reconnect !== !1, attempt: this.reconnectAttempt + 1 };
1531
1882
  this.emit("signalingerror", s), this.reportSignalingDiagnostic({ event: "error", attempt: s.attempt });
@@ -1559,16 +1910,16 @@ class le extends EventTarget {
1559
1910
  async request(e, t, i = !1) {
1560
1911
  const n = this.options.apiBaseUrl ?? this.options.signalingUrl ?? globalThis.location?.origin;
1561
1912
  if (!n) throw new Error("apiBaseUrl is required for call actions");
1562
- const s = new URL(n, globalThis.location?.href), a = await this.resolveToken("initial"), r = new Headers(t.headers);
1563
- r.set("authorization", `Bearer ${a}`), r.set("content-type", "application/json");
1564
- const o = await fetch(new URL(e, s.origin), { ...t, headers: r }), l = await o.json().catch(() => ({}));
1565
- if (o.status === 401 && this.options.tokenProvider && !i)
1913
+ const s = new URL(n, globalThis.location?.href), o = await this.resolveToken("initial"), r = new Headers(t.headers);
1914
+ 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(() => ({}));
1916
+ if (c.status === 401 && this.options.tokenProvider && !i)
1566
1917
  return await this.resolveToken("unauthorized", !0), this.request(e, t, !0);
1567
- if (!o.ok) {
1568
- const d = l.error;
1569
- throw new Error(typeof d == "string" ? d : d?.message || `RTC API failed with HTTP ${o.status}`);
1918
+ 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}`);
1570
1921
  }
1571
- return l;
1922
+ return d;
1572
1923
  }
1573
1924
  renderIncoming(e) {
1574
1925
  if (!this.mount) return;
@@ -1591,12 +1942,12 @@ class le extends EventTarget {
1591
1942
  n.textContent = e.caller.name, n.style.fontSize = "20px";
1592
1943
  const s = document.createElement("div");
1593
1944
  Object.assign(s.style, { display: "grid", gridTemplateColumns: "1fr 1fr", gap: "10px" });
1594
- const a = U("Decline", "#fff", "#a32920", "#d9a09b"), r = U("Answer", "#fff", "#08745f", "#08745f");
1595
- a.addEventListener("click", () => {
1596
- this.reject(e.id).catch((o) => this.emit("error", g(o)));
1945
+ const o = ie("Decline", "#fff", "#a32920", "#d9a09b"), r = ie("Answer", "#fff", "#08745f", "#08745f");
1946
+ o.addEventListener("click", () => {
1947
+ this.reject(e.id).catch((c) => this.emit("error", V(c)));
1597
1948
  }), r.addEventListener("click", () => {
1598
- this.accept(e.id).catch((o) => this.emit("error", g(o)));
1599
- }), s.appendChild(a), s.appendChild(r), t.appendChild(i), t.appendChild(n), t.appendChild(s), this.mount.replaceChildren(t);
1949
+ this.accept(e.id).catch((c) => this.emit("error", V(c)));
1950
+ }), s.appendChild(o), s.appendChild(r), t.appendChild(i), t.appendChild(n), t.appendChild(s), this.mount.replaceChildren(t);
1600
1951
  }
1601
1952
  dismiss(e) {
1602
1953
  e && this.currentCall?.id !== e && this.outgoingCallId !== e || (this.currentCall = null, (!e || this.outgoingCallId === e) && (this.outgoingCallId = null), this.callAudio.stop(), this.clearUi());
@@ -1663,7 +2014,7 @@ class le extends EventTarget {
1663
2014
  const t = Math.max(0, e - this.refreshSkew(e));
1664
2015
  this.tokenRefreshTimer = setTimeout(() => {
1665
2016
  this.tokenRefreshTimer = null, this.resolveToken("expiring", !0).catch((i) => {
1666
- this.emit("tokenerror", g(i)), this.stopped || (this.tokenRefreshTimer = setTimeout(() => this.scheduleTokenRefresh(), 3e4));
2017
+ this.emit("tokenerror", V(i)), this.stopped || (this.tokenRefreshTimer = setTimeout(() => this.scheduleTokenRefresh(), 3e4));
1667
2018
  });
1668
2019
  }, Math.min(t, 2147e6));
1669
2020
  }
@@ -1677,23 +2028,23 @@ class le extends EventTarget {
1677
2028
  this.options.reportSignalingDiagnostics === !1 || this.stopped || this.request("/v1/rtc/client/signaling-events", {
1678
2029
  method: "POST",
1679
2030
  body: JSON.stringify({ ...e, occurredAt: (/* @__PURE__ */ new Date()).toISOString() })
1680
- }).catch((t) => this.emit("diagnosticserror", g(t)));
2031
+ }).catch((t) => this.emit("diagnosticserror", V(t)));
1681
2032
  }
1682
2033
  emit(e, t) {
1683
2034
  const i = { type: e, detail: t, timestamp: (/* @__PURE__ */ new Date()).toISOString() };
1684
2035
  this.dispatchEvent(new CustomEvent(e, { detail: i })), this.options.onEvent?.(i);
1685
2036
  }
1686
2037
  }
1687
- function Se(c) {
1688
- const e = new le(c);
1689
- return c.autoConnect !== !1 && c.signalingUrl && e.connect(), e;
2038
+ function xe(a) {
2039
+ const e = new Ee(a);
2040
+ return a.autoConnect !== !1 && a.signalingUrl && e.connect(), e;
1690
2041
  }
1691
- function B(c) {
1692
- return c ? typeof c == "string" ? document.querySelector(c) : c : null;
2042
+ function te(a) {
2043
+ return a ? typeof a == "string" ? document.querySelector(a) : a : null;
1693
2044
  }
1694
- function U(c, e, t, i) {
2045
+ function ie(a, e, t, i) {
1695
2046
  const n = document.createElement("button");
1696
- return n.type = "button", n.textContent = c, Object.assign(n.style, {
2047
+ return n.type = "button", n.textContent = a, Object.assign(n.style, {
1697
2048
  minHeight: "44px",
1698
2049
  border: `1px solid ${i}`,
1699
2050
  borderRadius: "6px",
@@ -1704,7 +2055,7 @@ function U(c, e, t, i) {
1704
2055
  fontWeight: "700"
1705
2056
  }), n;
1706
2057
  }
1707
- function de(c) {
2058
+ function Me(a) {
1708
2059
  return {
1709
2060
  rejected: "Call declined",
1710
2061
  busy: "Line busy",
@@ -1712,91 +2063,104 @@ function de(c) {
1712
2063
  ended: "Call ended",
1713
2064
  failed: "Call failed",
1714
2065
  missed: "No answer"
1715
- }[c] ?? "Call ended";
2066
+ }[a] ?? "Call ended";
1716
2067
  }
1717
- function F(c) {
2068
+ function ne(a) {
1718
2069
  return {
1719
- id: c.participantId,
1720
- name: c.displayName,
2070
+ id: a.participantId,
2071
+ name: a.displayName,
1721
2072
  role: "participant"
1722
2073
  };
1723
2074
  }
1724
- async function he(c, e) {
1725
- const t = await c.getStats(), i = /* @__PURE__ */ new Map(), n = /* @__PURE__ */ new Map();
1726
- let s = 0, a = 0, r = 0, o = 0, l = 0, d = 0, u = 0, m = 0, p = 0, v = 0, T = 0, E = 0, w = 0, y = null, b = null, C = null, S = null, k = null, I = null;
1727
- t.forEach((h) => {
1728
- n.set(h.id, h), h.type === "codec" && i.set(h.id, String(h.mimeType ?? ""));
1729
- }), t.forEach((h) => {
1730
- if (h.type === "inbound-rtp" && !h.isRemote && (s += Number(h.bytesReceived ?? 0), r += Math.max(0, Number(h.packetsLost ?? 0)), o += Math.max(0, Number(h.packetsReceived ?? 0)), Number.isFinite(h.jitter) && (l += Number(h.jitter), d += 1), u = Math.max(u, Number(h.framesPerSecond ?? 0)), m = Math.max(m, Number(h.frameWidth ?? 0)), p = Math.max(p, Number(h.frameHeight ?? 0)), v += Number(h.framesDropped ?? 0), T += Number(h.freezeCount ?? 0), E += Number(h.totalFreezesDuration ?? 0), w += Number(h.concealedSamples ?? 0), k ||= i.get(String(h.codecId ?? "")) ?? null), h.type === "outbound-rtp" && !h.isRemote && (a += Number(h.bytesSent ?? 0), I ||= h.qualityLimitationReason ? String(h.qualityLimitationReason) : null, k ||= i.get(String(h.codecId ?? "")) ?? null), h.type === "candidate-pair" && (h.selected || h.nominated) && h.state === "succeeded") {
1731
- y = Number.isFinite(h.currentRoundTripTime) ? Number(h.currentRoundTripTime) : y, b = Number.isFinite(h.availableOutgoingBitrate) ? Number(h.availableOutgoingBitrate) : b;
1732
- const R = n.get(h.localCandidateId);
1733
- C = R?.candidateType ? String(R.candidateType) : C, S = R?.protocol ? String(R.protocol) : S;
2075
+ async function Pe(a, e) {
2076
+ 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;
1734
2085
  }
1735
2086
  });
1736
- const D = Date.now(), q = e ? Math.max(1e-3, (D - e.timestamp) / 1e3) : 0, G = e ? Math.max(0, Math.round((s - e.inboundBytes) * 8 / q)) : null, K = e ? Math.max(0, Math.round((a - e.outboundBytes) * 8 / q)) : null, N = r + o, Q = e ? Math.max(0, r - e.packetsLost) : r, Y = e ? Math.max(0, o - e.packetsReceived) : o, V = Q + Y;
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;
1737
2088
  return {
1738
- counters: { timestamp: D, inboundBytes: s, outboundBytes: a, packetsLost: r, packetsReceived: o },
2089
+ counters: { timestamp: h, inboundBytes: s, outboundBytes: o, packetsLost: r, packetsReceived: c },
1739
2090
  sample: {
1740
- rttMs: y === null ? null : y * 1e3,
1741
- jitterMs: d ? l / d * 1e3 : null,
1742
- packetLossPct: V ? Q / V * 100 : null,
1743
- packetLossCumulativePct: N ? r / N * 100 : null,
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,
1744
2095
  packetsLost: r,
1745
- packetsReceived: o,
1746
- inboundBitrateBps: G,
1747
- outboundBitrateBps: K,
2096
+ packetsReceived: c,
2097
+ inboundBitrateBps: L,
2098
+ outboundBitrateBps: q,
1748
2099
  availableOutgoingBitrateBps: b,
1749
2100
  framesPerSecond: u || null,
1750
- frameWidth: m || null,
1751
- frameHeight: p || null,
1752
- framesDropped: v,
1753
- freezeCount: T,
1754
- freezeDurationMs: Math.round(E * 1e3),
1755
- concealedSamples: w,
1756
- codec: k,
1757
- transportProtocol: S,
1758
- candidateType: C,
1759
- qualityLimitationReason: I
2101
+ frameWidth: y || null,
2102
+ 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
1760
2111
  }
1761
2112
  };
1762
2113
  }
1763
- function ue(c) {
1764
- let e = c.mediaScore == null ? 5 : Math.round($(Number(c.mediaScore), 0, 5));
1765
- const t = x(c.packetLossPct) ?? 0, i = x(c.rttMs) ?? 0, n = x(c.jitterMs) ?? 0, s = String(c.connectionState ?? "unknown").toLowerCase();
2114
+ function Ae(a) {
2115
+ 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();
1766
2117
  ["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));
1767
- const a = Number($(4.5 - t * 0.09 - i * 11e-4 - n * 6e-3, 1, 4.5).toFixed(2));
1768
- return { networkScore: e, estimatedMos: a };
2118
+ const o = Number(se(4.5 - t * 0.09 - i * 11e-4 - n * 6e-3, 1, 4.5).toFixed(2));
2119
+ return { networkScore: e, estimatedMos: o };
1769
2120
  }
1770
- function J() {
2121
+ function ae() {
1771
2122
  return navigator.connection ?? null;
1772
2123
  }
1773
- function me() {
1774
- const c = Number(navigator.deviceMemory);
1775
- return Number.isFinite(c) ? c : null;
2124
+ function Le() {
2125
+ const a = Number(navigator.deviceMemory);
2126
+ return Number.isFinite(a) ? a : null;
1776
2127
  }
1777
- function x(c) {
1778
- const e = Number(c);
2128
+ function J(a) {
2129
+ const e = Number(a);
1779
2130
  return Number.isFinite(e) ? e : null;
1780
2131
  }
1781
- function $(c, e, t) {
1782
- return Math.min(t, Math.max(e, c));
2132
+ function se(a, e, t) {
2133
+ return Math.min(t, Math.max(e, a));
1783
2134
  }
1784
- function g(c) {
1785
- return c instanceof Error ? { name: c.name, message: c.message } : { name: "ServiceError", message: String(c ?? "Service request failed") };
2135
+ function V(a) {
2136
+ return a instanceof Error ? { name: a.name, message: a.message } : { name: "ServiceError", message: String(a ?? "Service request failed") };
1786
2137
  }
1787
- function z(c, e) {
1788
- return c instanceof Error ? c : new Error(e);
2138
+ function re(a, e) {
2139
+ return a instanceof Error ? a : new Error(e);
1789
2140
  }
1790
- const pe = "1.3.14";
2141
+ const De = "1.3.16";
1791
2142
  export {
1792
- re as RtcClient,
1793
- le as RtcIncomingClient,
1794
- fe as SPEAKER_NOISE_FLOOR,
1795
- ge as SPEAKER_TAKEOVER_RATIO,
1796
- ve as createPictureInPictureController,
1797
- ye as createRtcClient,
1798
- Se as createRtcIncomingClient,
1799
- H as pickActiveSpeaker,
1800
- oe as unlockRtcCallAudio,
1801
- pe as version
2143
+ Z as AVATAR_TUNING_DEFAULTS,
2144
+ Se as BACKGROUND_PRESETS,
2145
+ ke as OVERLAY_EFFECTS,
2146
+ Ce as RtcClient,
2147
+ Ee as RtcIncomingClient,
2148
+ qe as SPEAKER_NOISE_FLOOR,
2149
+ Oe as SPEAKER_TAKEOVER_RATIO,
2150
+ Ue as createAvatarPipeline,
2151
+ je as createCallRecorder,
2152
+ Ne as createPictureInPictureController,
2153
+ Qe as createRtcClient,
2154
+ xe as createRtcIncomingClient,
2155
+ Ve as createVideoEffectsPipeline,
2156
+ be as drawAvatar,
2157
+ we as headPoseFromMatrix,
2158
+ le as neutralRig,
2159
+ oe as pickActiveSpeaker,
2160
+ Te as rigFromBlendshapes,
2161
+ K as scenePainters,
2162
+ X as smoothRig,
2163
+ ee as stylizedAvatarRenderer,
2164
+ Re as unlockRtcCallAudio,
2165
+ De as version
1802
2166
  };