@livo-tv/sdk 1.2.3 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/studio/index.cjs +241 -80
- package/dist/studio/index.cjs.map +1 -1
- package/dist/studio/index.d.cts +7 -0
- package/dist/studio/index.d.ts +7 -0
- package/dist/studio/index.js +241 -80
- package/dist/studio/index.js.map +1 -1
- package/package.json +1 -1
package/dist/studio/index.cjs
CHANGED
|
@@ -1899,6 +1899,7 @@ function StudioGuestWaiting({
|
|
|
1899
1899
|
muted,
|
|
1900
1900
|
labels,
|
|
1901
1901
|
settingsOpen,
|
|
1902
|
+
statusLabel,
|
|
1902
1903
|
onToggleCamera,
|
|
1903
1904
|
onToggleMute,
|
|
1904
1905
|
onOpenSettings,
|
|
@@ -1930,7 +1931,7 @@ function StudioGuestWaiting({
|
|
|
1930
1931
|
reducedMotion
|
|
1931
1932
|
}
|
|
1932
1933
|
),
|
|
1933
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-muted-foreground text-center text-sm", role: "status", children: labels.waitingHost }),
|
|
1934
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-muted-foreground text-center text-sm", role: "status", children: statusLabel ?? labels.waitingHost }),
|
|
1934
1935
|
/* @__PURE__ */ jsxRuntime.jsx(TooltipProvider, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-center gap-2", children: [
|
|
1935
1936
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1936
1937
|
ControlIcon,
|
|
@@ -2703,11 +2704,15 @@ function StudioSidePanel({
|
|
|
2703
2704
|
onGrantStage,
|
|
2704
2705
|
onDenyStage,
|
|
2705
2706
|
onTakeOffAir,
|
|
2707
|
+
onKick,
|
|
2706
2708
|
guestUrl,
|
|
2707
2709
|
onShareGuestLink
|
|
2708
2710
|
}) {
|
|
2709
2711
|
const panelists = participants.filter((row) => isOnStage(row.stageStatus));
|
|
2710
2712
|
const audience = participants.filter((row) => !isOnStage(row.stageStatus));
|
|
2713
|
+
const [pendingKick, setPendingKick] = react.useState(
|
|
2714
|
+
null
|
|
2715
|
+
);
|
|
2711
2716
|
return /* @__PURE__ */ jsxRuntime.jsxs("aside", { className: "bg-background flex min-h-0 w-full flex-1 flex-col border-t md:w-80 md:flex-none md:border-l md:border-t-0", children: [
|
|
2712
2717
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex", children: [
|
|
2713
2718
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
@@ -2824,23 +2829,37 @@ function StudioSidePanel({
|
|
|
2824
2829
|
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium", children: labels.panelists }),
|
|
2825
2830
|
panelists.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-muted-foreground text-sm", children: labels.noPanelists }) : /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "space-y-2", children: panelists.map((row) => {
|
|
2826
2831
|
const userId = row.userId;
|
|
2832
|
+
const showKick = isModerator2 && !row.isSelf && Boolean(row.id);
|
|
2827
2833
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2828
2834
|
"li",
|
|
2829
2835
|
{
|
|
2830
2836
|
className: "space-y-2 rounded-md border p-2",
|
|
2831
2837
|
children: [
|
|
2832
2838
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "block truncate text-sm", children: row.name }),
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
|
|
2839
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-2", children: [
|
|
2840
|
+
!row.isSelf && userId ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
2841
|
+
Button,
|
|
2842
|
+
{
|
|
2843
|
+
type: "button",
|
|
2844
|
+
size: "xs",
|
|
2845
|
+
variant: "outline",
|
|
2846
|
+
className: "w-full",
|
|
2847
|
+
onClick: () => onTakeOffAir(userId),
|
|
2848
|
+
children: labels.offAir
|
|
2849
|
+
}
|
|
2850
|
+
) : null,
|
|
2851
|
+
showKick ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
2852
|
+
Button,
|
|
2853
|
+
{
|
|
2854
|
+
type: "button",
|
|
2855
|
+
size: "xs",
|
|
2856
|
+
variant: "ghost",
|
|
2857
|
+
className: "w-full",
|
|
2858
|
+
onClick: () => setPendingKick(row),
|
|
2859
|
+
children: labels.kick
|
|
2860
|
+
}
|
|
2861
|
+
) : null
|
|
2862
|
+
] })
|
|
2844
2863
|
]
|
|
2845
2864
|
},
|
|
2846
2865
|
row.id
|
|
@@ -2851,29 +2870,61 @@ function StudioSidePanel({
|
|
|
2851
2870
|
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium", children: labels.audience }),
|
|
2852
2871
|
audience.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-muted-foreground text-sm", children: labels.noAudience }) : /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "space-y-2", children: audience.map((row) => {
|
|
2853
2872
|
const userId = row.userId;
|
|
2873
|
+
const showKick = isModerator2 && !row.isSelf && Boolean(row.id);
|
|
2854
2874
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2855
2875
|
"li",
|
|
2856
2876
|
{
|
|
2857
2877
|
className: "space-y-2 rounded-md border p-2",
|
|
2858
2878
|
children: [
|
|
2859
2879
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "block truncate text-sm", children: row.name }),
|
|
2860
|
-
|
|
2861
|
-
|
|
2862
|
-
|
|
2863
|
-
|
|
2864
|
-
|
|
2865
|
-
|
|
2866
|
-
|
|
2867
|
-
|
|
2868
|
-
|
|
2869
|
-
|
|
2870
|
-
|
|
2880
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-2", children: [
|
|
2881
|
+
!row.isSelf && userId ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
2882
|
+
Button,
|
|
2883
|
+
{
|
|
2884
|
+
type: "button",
|
|
2885
|
+
size: "xs",
|
|
2886
|
+
variant: "outline",
|
|
2887
|
+
className: "w-full",
|
|
2888
|
+
onClick: () => onGrantStage(userId),
|
|
2889
|
+
children: labels.bringOnAir
|
|
2890
|
+
}
|
|
2891
|
+
) : null,
|
|
2892
|
+
showKick ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
2893
|
+
Button,
|
|
2894
|
+
{
|
|
2895
|
+
type: "button",
|
|
2896
|
+
size: "xs",
|
|
2897
|
+
variant: "ghost",
|
|
2898
|
+
className: "w-full",
|
|
2899
|
+
onClick: () => setPendingKick(row),
|
|
2900
|
+
children: labels.kick
|
|
2901
|
+
}
|
|
2902
|
+
) : null
|
|
2903
|
+
] })
|
|
2871
2904
|
]
|
|
2872
2905
|
},
|
|
2873
2906
|
row.id
|
|
2874
2907
|
);
|
|
2875
2908
|
}) })
|
|
2876
|
-
] })
|
|
2909
|
+
] }),
|
|
2910
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2911
|
+
ConfirmAction,
|
|
2912
|
+
{
|
|
2913
|
+
open: pendingKick !== null,
|
|
2914
|
+
onOpenChange: (open) => {
|
|
2915
|
+
if (!open) setPendingKick(null);
|
|
2916
|
+
},
|
|
2917
|
+
triggerLabel: labels.kick,
|
|
2918
|
+
title: pendingKick ? labels.kickTitleNamed.replace("{name}", pendingKick.name) : labels.kickTitle,
|
|
2919
|
+
description: labels.kickDescription,
|
|
2920
|
+
confirmLabel: labels.kickConfirm,
|
|
2921
|
+
onConfirm: () => {
|
|
2922
|
+
const target = pendingKick;
|
|
2923
|
+
setPendingKick(null);
|
|
2924
|
+
if (target) onKick(target.id);
|
|
2925
|
+
}
|
|
2926
|
+
}
|
|
2927
|
+
)
|
|
2877
2928
|
] })
|
|
2878
2929
|
] });
|
|
2879
2930
|
}
|
|
@@ -3514,6 +3565,7 @@ function StudioToolbar({
|
|
|
3514
3565
|
] }) });
|
|
3515
3566
|
}
|
|
3516
3567
|
var STAGE_GRANT_VERIFY_MS = 4e3;
|
|
3568
|
+
var STUDIO_CONNECT_WATCHDOG_MS = 12e3;
|
|
3517
3569
|
function StudioRoom({
|
|
3518
3570
|
session,
|
|
3519
3571
|
meeting,
|
|
@@ -3549,6 +3601,7 @@ function StudioRoom({
|
|
|
3549
3601
|
);
|
|
3550
3602
|
const [egressError, setEgressError] = react.useState(null);
|
|
3551
3603
|
const [shareGrant, setShareGrant] = react.useState("idle");
|
|
3604
|
+
const [connectTimedOut, setConnectTimedOut] = react.useState(false);
|
|
3552
3605
|
const [screenPermission, setScreenPermission] = react.useState(
|
|
3553
3606
|
() => meeting.screenSharePermission()
|
|
3554
3607
|
);
|
|
@@ -3795,6 +3848,14 @@ function StudioRoom({
|
|
|
3795
3848
|
[participants]
|
|
3796
3849
|
);
|
|
3797
3850
|
const waitlisted = react.useMemo(() => meeting.waitlisted(), [meeting, tick]);
|
|
3851
|
+
const connectionState = react.useMemo(
|
|
3852
|
+
() => meeting.connectionState(),
|
|
3853
|
+
[meeting, tick]
|
|
3854
|
+
);
|
|
3855
|
+
const lastMeetingError = react.useMemo(
|
|
3856
|
+
() => meeting.lastMeetingError(),
|
|
3857
|
+
[meeting, tick]
|
|
3858
|
+
);
|
|
3798
3859
|
const canManageStage = meeting.canManageStage();
|
|
3799
3860
|
const stageEnabled = meeting.stageEnabled();
|
|
3800
3861
|
const stageRequests = react.useMemo(
|
|
@@ -3892,6 +3953,16 @@ function StudioRoom({
|
|
|
3892
3953
|
}
|
|
3893
3954
|
}
|
|
3894
3955
|
}, [labels.knock, session.role, waitlisted]);
|
|
3956
|
+
react.useEffect(() => {
|
|
3957
|
+
if (session.role !== "guest" || connectionState !== "connecting") {
|
|
3958
|
+
setConnectTimedOut(false);
|
|
3959
|
+
return;
|
|
3960
|
+
}
|
|
3961
|
+
const id = window.setTimeout(() => {
|
|
3962
|
+
setConnectTimedOut(true);
|
|
3963
|
+
}, STUDIO_CONNECT_WATCHDOG_MS);
|
|
3964
|
+
return () => window.clearTimeout(id);
|
|
3965
|
+
}, [connectionState, session.role]);
|
|
3895
3966
|
react.useEffect(() => {
|
|
3896
3967
|
if (inWaitingRoom || screenNoticePrimed.current) return;
|
|
3897
3968
|
if (!durableScreenBlock) return;
|
|
@@ -4207,7 +4278,20 @@ function StudioRoom({
|
|
|
4207
4278
|
}
|
|
4208
4279
|
) });
|
|
4209
4280
|
}
|
|
4210
|
-
|
|
4281
|
+
const guestConnectFailed = session.role === "guest" && (connectionState === "failed" || connectionState === "connecting" && connectTimedOut);
|
|
4282
|
+
if (guestConnectFailed) {
|
|
4283
|
+
const detail = [meeting.roomState(), lastMeetingError].filter((value) => Boolean(value)).join(" \u2014 ");
|
|
4284
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex h-dvh flex-col items-center justify-center p-6", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4285
|
+
EmptyState,
|
|
4286
|
+
{
|
|
4287
|
+
title: labels.connectFailed,
|
|
4288
|
+
description: detail || labels.connectFailed,
|
|
4289
|
+
actionLabel: onRejoin ? labels.retry : void 0,
|
|
4290
|
+
onAction: onRejoin
|
|
4291
|
+
}
|
|
4292
|
+
) });
|
|
4293
|
+
}
|
|
4294
|
+
if (session.role === "guest" && (connectionState === "waitlisted" || connectionState === "connecting")) {
|
|
4211
4295
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
4212
4296
|
StudioGuestWaiting,
|
|
4213
4297
|
{
|
|
@@ -4217,6 +4301,7 @@ function StudioRoom({
|
|
|
4217
4301
|
muted,
|
|
4218
4302
|
labels,
|
|
4219
4303
|
settingsOpen,
|
|
4304
|
+
statusLabel: connectionState === "connecting" ? labels.connecting : labels.waitingHost,
|
|
4220
4305
|
onToggleCamera,
|
|
4221
4306
|
onToggleMute: () => void onToggleMute(),
|
|
4222
4307
|
onOpenSettings: () => setSettingsOpen(true),
|
|
@@ -4401,6 +4486,7 @@ function StudioRoom({
|
|
|
4401
4486
|
const tile = participants.find((row) => row.userId === userId);
|
|
4402
4487
|
if (tile) void onSetStage(tile, false);
|
|
4403
4488
|
},
|
|
4489
|
+
onKick: (id) => void onKick(id),
|
|
4404
4490
|
guestUrl: session.guestUrl,
|
|
4405
4491
|
onShareGuestLink: () => {
|
|
4406
4492
|
const url = session.guestUrl;
|
|
@@ -4742,8 +4828,8 @@ function StudioGuestLobby({
|
|
|
4742
4828
|
}
|
|
4743
4829
|
}
|
|
4744
4830
|
async function onTestSpeaker() {
|
|
4745
|
-
|
|
4746
|
-
|
|
4831
|
+
if (testingSpeaker) return;
|
|
4832
|
+
const speakerId = effective.speaker || devices.speaker[0]?.deviceId || void 0;
|
|
4747
4833
|
setTestingSpeaker(true);
|
|
4748
4834
|
try {
|
|
4749
4835
|
await playSpeakerTest(speakerId);
|
|
@@ -4811,7 +4897,7 @@ function StudioGuestLobby({
|
|
|
4811
4897
|
type: "button",
|
|
4812
4898
|
size: "sm",
|
|
4813
4899
|
variant: "outline",
|
|
4814
|
-
disabled:
|
|
4900
|
+
disabled: testingSpeaker,
|
|
4815
4901
|
onClick: () => void onTestSpeaker(),
|
|
4816
4902
|
children: deviceLabels.testSpeaker
|
|
4817
4903
|
}
|
|
@@ -5053,6 +5139,38 @@ function isStageDisabledError(error) {
|
|
|
5053
5139
|
const message = typeof row.message === "string" ? row.message : "";
|
|
5054
5140
|
return message.includes("ERR2003") || message.toLowerCase().includes("stage is disabled");
|
|
5055
5141
|
}
|
|
5142
|
+
function isStageBusyError(error) {
|
|
5143
|
+
if (!error || typeof error !== "object") return false;
|
|
5144
|
+
const row = error;
|
|
5145
|
+
if (row.name === "UnsupportedConcurrentMethodExecution") return true;
|
|
5146
|
+
if (row.code === "2006" || row.code === 2006) return true;
|
|
5147
|
+
const message = typeof row.message === "string" ? row.message : "";
|
|
5148
|
+
return message.includes("ERR2006") || message.includes("Unsupported concurrent calls") || message.includes("Action not permitted in current stage status");
|
|
5149
|
+
}
|
|
5150
|
+
function isRtkMeetingError(error) {
|
|
5151
|
+
if (!error || typeof error !== "object") return false;
|
|
5152
|
+
const row = error;
|
|
5153
|
+
const name = typeof row.name === "string" ? row.name : "";
|
|
5154
|
+
const message = typeof row.message === "string" ? row.message : "";
|
|
5155
|
+
return name === "ClientError" || name === "TransportConnectionError" || message.includes("ERR1608") || message.includes("No speaker found") || message.includes("Socket is not connected");
|
|
5156
|
+
}
|
|
5157
|
+
function meetingErrorText(error) {
|
|
5158
|
+
if (error instanceof Error && error.message.trim()) return error.message;
|
|
5159
|
+
if (error && typeof error === "object") {
|
|
5160
|
+
const message = error.message;
|
|
5161
|
+
if (typeof message === "string" && message.trim()) return message;
|
|
5162
|
+
}
|
|
5163
|
+
return "Studio failed";
|
|
5164
|
+
}
|
|
5165
|
+
async function settledDeviceList(load) {
|
|
5166
|
+
if (!load) return [];
|
|
5167
|
+
try {
|
|
5168
|
+
const [result] = await Promise.allSettled([load()]);
|
|
5169
|
+
return result?.status === "fulfilled" ? result.value : [];
|
|
5170
|
+
} catch {
|
|
5171
|
+
return [];
|
|
5172
|
+
}
|
|
5173
|
+
}
|
|
5056
5174
|
function waitMs(ms) {
|
|
5057
5175
|
return new Promise((resolve) => {
|
|
5058
5176
|
setTimeout(resolve, ms);
|
|
@@ -5090,8 +5208,9 @@ function studioMeetingFromRtk(raw) {
|
|
|
5090
5208
|
const pendingPanelists = /* @__PURE__ */ new Set();
|
|
5091
5209
|
const chatSend = /* @__PURE__ */ new Map();
|
|
5092
5210
|
const nameOverrides = /* @__PURE__ */ new Map();
|
|
5093
|
-
let
|
|
5211
|
+
let joinStageInFlight = null;
|
|
5094
5212
|
let joinedStageLocally = false;
|
|
5213
|
+
let lastMeetingError = null;
|
|
5095
5214
|
const historyMessages = [];
|
|
5096
5215
|
let speakerSinkId = null;
|
|
5097
5216
|
let lastSpeakerId = typeof meeting.participants?.lastActiveSpeaker === "string" ? meeting.participants.lastActiveSpeaker : null;
|
|
@@ -5187,47 +5306,75 @@ function studioMeetingFromRtk(raw) {
|
|
|
5187
5306
|
return [...byId.values()].sort((a, b) => a.time - b.time);
|
|
5188
5307
|
}
|
|
5189
5308
|
function currentStageStatus() {
|
|
5190
|
-
return meeting.
|
|
5309
|
+
return meeting.self?.stageStatus ?? meeting.stage?.status;
|
|
5310
|
+
}
|
|
5311
|
+
function resolveConnectionState() {
|
|
5312
|
+
const self = meeting.self;
|
|
5313
|
+
const roomState = self?.roomState ?? null;
|
|
5314
|
+
if (roomState === "waitlisted") return "waitlisted";
|
|
5315
|
+
if (roomState === "joined" || self?.roomJoined === true) return "joined";
|
|
5316
|
+
if (lastMeetingError) return "failed";
|
|
5317
|
+
return "connecting";
|
|
5318
|
+
}
|
|
5319
|
+
function recordMeetingError(error) {
|
|
5320
|
+
if (!isRtkMeetingError(error)) return;
|
|
5321
|
+
lastMeetingError = meetingErrorText(error);
|
|
5322
|
+
notifyParticipants();
|
|
5323
|
+
}
|
|
5324
|
+
function onUnhandledRejection(event) {
|
|
5325
|
+
recordMeetingError(event.reason);
|
|
5326
|
+
}
|
|
5327
|
+
if (typeof window !== "undefined") {
|
|
5328
|
+
window.addEventListener("unhandledrejection", onUnhandledRejection);
|
|
5191
5329
|
}
|
|
5192
5330
|
async function republishCameraIfOn() {
|
|
5193
5331
|
if (meeting.self?.videoEnabled !== true) return;
|
|
5194
5332
|
await meeting.self.disableVideo?.();
|
|
5195
5333
|
await meeting.self.enableVideo?.();
|
|
5196
5334
|
}
|
|
5197
|
-
async function
|
|
5198
|
-
|
|
5199
|
-
|
|
5200
|
-
|
|
5201
|
-
|
|
5202
|
-
|
|
5335
|
+
async function runJoinStageAttempts() {
|
|
5336
|
+
let lastError;
|
|
5337
|
+
for (let attempt = 0; attempt < STAGE_JOIN_MAX_ATTEMPTS; attempt++) {
|
|
5338
|
+
if (currentStageStatus() === "ON_STAGE") {
|
|
5339
|
+
notifyStage();
|
|
5340
|
+
return;
|
|
5341
|
+
}
|
|
5342
|
+
try {
|
|
5343
|
+
await meeting.stage?.join?.();
|
|
5344
|
+
joinedStageLocally = true;
|
|
5345
|
+
await republishCameraIfOn();
|
|
5346
|
+
notifyStage();
|
|
5347
|
+
return;
|
|
5348
|
+
} catch (error) {
|
|
5349
|
+
lastError = error;
|
|
5350
|
+
if (isStageDisabledError(error)) {
|
|
5203
5351
|
notifyStage();
|
|
5204
5352
|
return;
|
|
5205
5353
|
}
|
|
5206
|
-
|
|
5207
|
-
await meeting.stage?.join?.();
|
|
5208
|
-
joinedStageLocally = true;
|
|
5209
|
-
await republishCameraIfOn();
|
|
5210
|
-
notifyStage();
|
|
5211
|
-
return;
|
|
5212
|
-
} catch (error) {
|
|
5213
|
-
if (isStageDisabledError(error)) {
|
|
5214
|
-
notifyStage();
|
|
5215
|
-
return;
|
|
5216
|
-
}
|
|
5217
|
-
console.warn("studio: stage join failed", error);
|
|
5218
|
-
if (attempt === STAGE_JOIN_MAX_ATTEMPTS - 1) {
|
|
5219
|
-
notifyStage();
|
|
5220
|
-
return;
|
|
5221
|
-
}
|
|
5354
|
+
if (isStageBusyError(error)) {
|
|
5222
5355
|
await waitMs(STAGE_JOIN_RETRY_MS);
|
|
5223
|
-
|
|
5224
|
-
notifyStage();
|
|
5225
|
-
return;
|
|
5226
|
-
}
|
|
5356
|
+
continue;
|
|
5227
5357
|
}
|
|
5358
|
+
console.warn("studio: stage join failed", error);
|
|
5359
|
+
if (attempt === STAGE_JOIN_MAX_ATTEMPTS - 1) break;
|
|
5360
|
+
await waitMs(STAGE_JOIN_RETRY_MS);
|
|
5228
5361
|
}
|
|
5362
|
+
}
|
|
5363
|
+
notifyStage();
|
|
5364
|
+
if (currentStageStatus() !== "ON_STAGE") {
|
|
5365
|
+
throw lastError instanceof Error ? lastError : new Error("stage join failed");
|
|
5366
|
+
}
|
|
5367
|
+
}
|
|
5368
|
+
async function joinStageWithRetry() {
|
|
5369
|
+
if (joinStageInFlight) {
|
|
5370
|
+
await joinStageInFlight;
|
|
5371
|
+
return;
|
|
5372
|
+
}
|
|
5373
|
+
joinStageInFlight = runJoinStageAttempts();
|
|
5374
|
+
try {
|
|
5375
|
+
await joinStageInFlight;
|
|
5229
5376
|
} finally {
|
|
5230
|
-
|
|
5377
|
+
joinStageInFlight = null;
|
|
5231
5378
|
}
|
|
5232
5379
|
}
|
|
5233
5380
|
async function autoJoinStage() {
|
|
@@ -5235,18 +5382,27 @@ function studioMeetingFromRtk(raw) {
|
|
|
5235
5382
|
notifyStage();
|
|
5236
5383
|
return;
|
|
5237
5384
|
}
|
|
5238
|
-
|
|
5385
|
+
try {
|
|
5386
|
+
await joinStageWithRetry();
|
|
5387
|
+
} catch {
|
|
5388
|
+
notifyStage();
|
|
5389
|
+
}
|
|
5239
5390
|
}
|
|
5240
5391
|
async function ensureStageJoined() {
|
|
5241
5392
|
if (currentStageStatus() !== "ACCEPTED_TO_JOIN_STAGE") return;
|
|
5242
|
-
|
|
5393
|
+
try {
|
|
5394
|
+
await joinStageWithRetry();
|
|
5395
|
+
} catch {
|
|
5396
|
+
notifyStage();
|
|
5397
|
+
}
|
|
5243
5398
|
}
|
|
5244
5399
|
async function joinStageIfAllowed() {
|
|
5245
5400
|
if (meeting.self?.permissions?.stageAccess !== "ALLOWED") return;
|
|
5246
5401
|
if (currentStageStatus() === "ON_STAGE") return;
|
|
5247
5402
|
try {
|
|
5248
|
-
await
|
|
5403
|
+
await joinStageWithRetry();
|
|
5249
5404
|
} catch {
|
|
5405
|
+
notifyStage();
|
|
5250
5406
|
}
|
|
5251
5407
|
}
|
|
5252
5408
|
function queuePanelist(guest, fallbackId) {
|
|
@@ -5282,6 +5438,8 @@ function studioMeetingFromRtk(raw) {
|
|
|
5282
5438
|
listen(meeting.self, "audioUpdate", rebindMedia);
|
|
5283
5439
|
listen(meeting.self, "pinned", notifyPinned);
|
|
5284
5440
|
listen(meeting.self, "unpinned", notifyPinned);
|
|
5441
|
+
listen(meeting.self, "waitlisted", notifyParticipants);
|
|
5442
|
+
listen(meeting.self, "roomJoined", notifyParticipants);
|
|
5285
5443
|
const joined = meeting.participants?.joined;
|
|
5286
5444
|
listen(joined, "participantJoined", (payload) => {
|
|
5287
5445
|
void grantIfPending(payload);
|
|
@@ -5349,6 +5507,9 @@ function studioMeetingFromRtk(raw) {
|
|
|
5349
5507
|
await joinStageIfAllowed();
|
|
5350
5508
|
},
|
|
5351
5509
|
async leave() {
|
|
5510
|
+
if (typeof window !== "undefined") {
|
|
5511
|
+
window.removeEventListener("unhandledrejection", onUnhandledRejection);
|
|
5512
|
+
}
|
|
5352
5513
|
await meeting.leave?.();
|
|
5353
5514
|
},
|
|
5354
5515
|
async setAudioEnabled(enabled) {
|
|
@@ -5458,19 +5619,7 @@ function studioMeetingFromRtk(raw) {
|
|
|
5458
5619
|
notifyStage();
|
|
5459
5620
|
return;
|
|
5460
5621
|
}
|
|
5461
|
-
|
|
5462
|
-
if (userId) {
|
|
5463
|
-
await meeting.stage?.grantAccess?.([userId]);
|
|
5464
|
-
}
|
|
5465
|
-
try {
|
|
5466
|
-
await meeting.stage?.join?.();
|
|
5467
|
-
} catch (error) {
|
|
5468
|
-
notifyStage();
|
|
5469
|
-
throw error;
|
|
5470
|
-
}
|
|
5471
|
-
joinedStageLocally = true;
|
|
5472
|
-
await republishCameraIfOn();
|
|
5473
|
-
notifyStage();
|
|
5622
|
+
await joinStageWithRetry();
|
|
5474
5623
|
},
|
|
5475
5624
|
async leaveStage() {
|
|
5476
5625
|
await meeting.stage?.leave?.();
|
|
@@ -5478,7 +5627,7 @@ function studioMeetingFromRtk(raw) {
|
|
|
5478
5627
|
notifyStage();
|
|
5479
5628
|
},
|
|
5480
5629
|
stageStatus() {
|
|
5481
|
-
return meeting.
|
|
5630
|
+
return meeting.self?.stageStatus ?? meeting.stage?.status ?? "OFF_STAGE";
|
|
5482
5631
|
},
|
|
5483
5632
|
stageRequests() {
|
|
5484
5633
|
if (meeting.self?.permissions?.acceptStageRequests !== true) {
|
|
@@ -5590,9 +5739,13 @@ function studioMeetingFromRtk(raw) {
|
|
|
5590
5739
|
}));
|
|
5591
5740
|
},
|
|
5592
5741
|
inWaitingRoom() {
|
|
5593
|
-
|
|
5594
|
-
|
|
5595
|
-
|
|
5742
|
+
return meeting.self?.roomState === "waitlisted";
|
|
5743
|
+
},
|
|
5744
|
+
connectionState() {
|
|
5745
|
+
return resolveConnectionState();
|
|
5746
|
+
},
|
|
5747
|
+
lastMeetingError() {
|
|
5748
|
+
return lastMeetingError;
|
|
5596
5749
|
},
|
|
5597
5750
|
moderatorIds() {
|
|
5598
5751
|
const ids = [];
|
|
@@ -5712,9 +5865,9 @@ function studioMeetingFromRtk(raw) {
|
|
|
5712
5865
|
async listDevices() {
|
|
5713
5866
|
const self = meeting.self;
|
|
5714
5867
|
const [audio, video, speaker] = await Promise.all([
|
|
5715
|
-
self?.getAudioDevices?.()
|
|
5716
|
-
self?.getVideoDevices?.()
|
|
5717
|
-
self?.getSpeakerDevices?.()
|
|
5868
|
+
settledDeviceList(self?.getAudioDevices?.bind(self)),
|
|
5869
|
+
settledDeviceList(self?.getVideoDevices?.bind(self)),
|
|
5870
|
+
settledDeviceList(self?.getSpeakerDevices?.bind(self))
|
|
5718
5871
|
]);
|
|
5719
5872
|
return {
|
|
5720
5873
|
audio: asOptions(audio),
|
|
@@ -5727,6 +5880,10 @@ function studioMeetingFromRtk(raw) {
|
|
|
5727
5880
|
if (kind === "speaker") {
|
|
5728
5881
|
speakerSinkId = deviceId;
|
|
5729
5882
|
for (const el of audioEls.values()) applySink(el, speakerSinkId);
|
|
5883
|
+
const speakers = await settledDeviceList(
|
|
5884
|
+
meeting.self?.getSpeakerDevices?.bind(meeting.self)
|
|
5885
|
+
);
|
|
5886
|
+
if (speakers.length === 0) return;
|
|
5730
5887
|
}
|
|
5731
5888
|
await meeting.self?.setDevice?.({
|
|
5732
5889
|
deviceId,
|
|
@@ -6269,6 +6426,9 @@ function studioRoomLabels(t) {
|
|
|
6269
6426
|
preview: t("preview"),
|
|
6270
6427
|
waiting: t("waiting"),
|
|
6271
6428
|
waitingHost: t("waitingHost"),
|
|
6429
|
+
connecting: t("connecting"),
|
|
6430
|
+
connectFailed: t("connectFailed"),
|
|
6431
|
+
retry: t("retry"),
|
|
6272
6432
|
admit: t("admit"),
|
|
6273
6433
|
deny: t("deny"),
|
|
6274
6434
|
denied: t("denied"),
|
|
@@ -6409,6 +6569,7 @@ function studioRoomLabels(t) {
|
|
|
6409
6569
|
unpinnedToast: t("unpinnedToast"),
|
|
6410
6570
|
pinError: t("pinError"),
|
|
6411
6571
|
kickTitle: t("kickTitle"),
|
|
6572
|
+
kickTitleNamed: t("kickTitleNamed", { name: "{name}" }),
|
|
6412
6573
|
kickDescription: t("kickDescription"),
|
|
6413
6574
|
kickConfirm: t("kickConfirm"),
|
|
6414
6575
|
kickError: t("kickError"),
|