@ai-matrx/meet 0.11.43 → 0.11.44
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/CHANGELOG.md +6 -0
- package/dist/core.cjs +148 -13
- package/dist/core.cjs.map +1 -1
- package/dist/core.d.cts +96 -1
- package/dist/core.d.ts +96 -1
- package/dist/core.js +148 -13
- package/dist/core.js.map +1 -1
- package/dist/index.cjs +148 -13
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +148 -13
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +385 -25
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +1 -1
- package/dist/react.d.ts +1 -1
- package/dist/react.js +791 -431
- package/dist/react.js.map +1 -1
- package/dist/skins/meet.cjs +262 -15
- package/dist/skins/meet.cjs.map +1 -1
- package/dist/skins/meet.d.cts +2 -1
- package/dist/skins/meet.d.ts +2 -1
- package/dist/skins/meet.js +609 -362
- package/dist/skins/meet.js.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +5 -5
package/dist/react.cjs
CHANGED
|
@@ -158,6 +158,7 @@ __export(react_exports, {
|
|
|
158
158
|
createReconnectPolicy: () => createReconnectPolicy,
|
|
159
159
|
createRecordingController: () => createRecordingController,
|
|
160
160
|
createRoomEngine: () => createRoomEngine,
|
|
161
|
+
createSpeakingWhileMutedDetector: () => createSpeakingWhileMutedDetector,
|
|
161
162
|
createTokenClient: () => createTokenClient,
|
|
162
163
|
createWebDeviceStorage: () => createWebDeviceStorage,
|
|
163
164
|
createWebEffectsStorage: () => createWebEffectsStorage,
|
|
@@ -166,6 +167,7 @@ __export(react_exports, {
|
|
|
166
167
|
createWebRoomTokenStorage: () => createWebRoomTokenStorage,
|
|
167
168
|
defaultCaptionLanguage: () => defaultCaptionLanguage,
|
|
168
169
|
detectBrowser: () => detectBrowser,
|
|
170
|
+
detectCapabilities: () => detectCapabilities,
|
|
169
171
|
detectOs: () => detectOs,
|
|
170
172
|
deviceChipLabel: () => deviceChipLabel,
|
|
171
173
|
deviceFixSteps: () => deviceFixSteps,
|
|
@@ -190,6 +192,7 @@ __export(react_exports, {
|
|
|
190
192
|
isLinkFollower: () => isLinkFollower,
|
|
191
193
|
isListenOnly: () => isListenOnly,
|
|
192
194
|
isLivePhase: () => isLivePhase,
|
|
195
|
+
isMobileUserAgent: () => isMobileUserAgent,
|
|
193
196
|
isNoteTaker: () => isNoteTaker,
|
|
194
197
|
isObserverRole: () => isObserverRole,
|
|
195
198
|
isRealName: () => isRealName,
|
|
@@ -282,6 +285,7 @@ __export(react_exports, {
|
|
|
282
285
|
transcriptDocument: () => transcriptDocument,
|
|
283
286
|
unavailableFrom: () => unavailableFrom,
|
|
284
287
|
uniqueAttendees: () => uniqueAttendees,
|
|
288
|
+
unsupportedWords: () => unsupportedWords,
|
|
285
289
|
untranslatedLines: () => untranslatedLines,
|
|
286
290
|
useActivityAttention: () => useActivityAttention,
|
|
287
291
|
useAudioLevel: () => useAudioLevel,
|
|
@@ -2792,11 +2796,13 @@ function minutesLeft(policy, startedAtMs, nowMs) {
|
|
|
2792
2796
|
}
|
|
2793
2797
|
|
|
2794
2798
|
// src/core/attendance.ts
|
|
2799
|
+
var IDLE_PREVIEW = { state: "idle", unavailable: null };
|
|
2795
2800
|
var IDLE_MEDIA_REGION = {
|
|
2796
2801
|
permission: { microphone: "unknown", camera: "unknown" },
|
|
2797
2802
|
audioOutput: "ok",
|
|
2798
2803
|
notice: null,
|
|
2799
|
-
offer: null
|
|
2804
|
+
offer: null,
|
|
2805
|
+
preview: { microphone: IDLE_PREVIEW, camera: IDLE_PREVIEW }
|
|
2800
2806
|
};
|
|
2801
2807
|
var IDLE_TRACK = { enabled: false, unavailable: null };
|
|
2802
2808
|
var IDLE_MEDIA = {
|
|
@@ -5151,6 +5157,47 @@ function createMeetSessionIdentity(options) {
|
|
|
5151
5157
|
});
|
|
5152
5158
|
}
|
|
5153
5159
|
|
|
5160
|
+
// src/core/capabilities.ts
|
|
5161
|
+
var IN_APP = [
|
|
5162
|
+
[/Instagram/i, "Instagram"],
|
|
5163
|
+
[/FBAN|FBAV|FB_IAB/i, "Facebook"],
|
|
5164
|
+
[/LinkedInApp/i, "LinkedIn"],
|
|
5165
|
+
[/MicroMessenger/i, "WeChat"],
|
|
5166
|
+
[/Snapchat/i, "Snapchat"],
|
|
5167
|
+
[/\bLine\//i, "LINE"],
|
|
5168
|
+
[/Twitter|TwitterAndroid/i, "X"],
|
|
5169
|
+
[/TikTok|musical_ly|BytedanceWebview/i, "TikTok"]
|
|
5170
|
+
];
|
|
5171
|
+
function isMobileUserAgent(userAgent, maxTouchPoints = 0) {
|
|
5172
|
+
if (/iPhone|iPod|Android|Mobile|iPad/i.test(userAgent)) return true;
|
|
5173
|
+
return /Macintosh/.test(userAgent) && maxTouchPoints > 1;
|
|
5174
|
+
}
|
|
5175
|
+
function detectCapabilities(scope = typeof globalThis === "undefined" ? null : globalThis) {
|
|
5176
|
+
if (scope === null || scope.navigator === void 0) {
|
|
5177
|
+
return { canJoin: true, reason: null, inAppBrowser: null, mobile: false, canShareScreen: false };
|
|
5178
|
+
}
|
|
5179
|
+
const ua = scope.navigator.userAgent ?? "";
|
|
5180
|
+
const webrtc = typeof scope.RTCPeerConnection === "function" || typeof scope.webkitRTCPeerConnection === "function";
|
|
5181
|
+
const mobile = isMobileUserAgent(ua, scope.navigator.maxTouchPoints ?? 0);
|
|
5182
|
+
const inAppBrowser = IN_APP.find(([pattern]) => pattern.test(ua))?.[1] ?? null;
|
|
5183
|
+
return {
|
|
5184
|
+
canJoin: webrtc,
|
|
5185
|
+
reason: webrtc ? null : "no_webrtc",
|
|
5186
|
+
inAppBrowser,
|
|
5187
|
+
mobile,
|
|
5188
|
+
canShareScreen: !mobile && typeof scope.navigator.mediaDevices?.getDisplayMedia === "function"
|
|
5189
|
+
};
|
|
5190
|
+
}
|
|
5191
|
+
function unsupportedWords(capabilities) {
|
|
5192
|
+
if (capabilities.inAppBrowser !== null) {
|
|
5193
|
+
return {
|
|
5194
|
+
title: `${capabilities.inAppBrowser}'s browser can't join calls`,
|
|
5195
|
+
body: "Open this link in Chrome, Safari, Edge or Firefox"
|
|
5196
|
+
};
|
|
5197
|
+
}
|
|
5198
|
+
return { title: "This browser can't join calls", body: "Open this link in Chrome, Safari, Edge or Firefox" };
|
|
5199
|
+
}
|
|
5200
|
+
|
|
5154
5201
|
// src/core/media-supervisor.ts
|
|
5155
5202
|
function classifyDeviceFailure(error, permission) {
|
|
5156
5203
|
if (permission === "denied") return "denied";
|
|
@@ -5211,7 +5258,7 @@ function deviceFixSteps(kind, reason, where) {
|
|
|
5211
5258
|
case "safari":
|
|
5212
5259
|
return where.os === "ios" ? [`Settings \u203A Apps \u203A Safari \u203A ${device}`, "Choose Allow", "Return here and press Try again"] : ["Safari \u203A Settings for This Website", `Set ${device} to Allow`, "Press Try again"];
|
|
5213
5260
|
default:
|
|
5214
|
-
return ["Click the icon
|
|
5261
|
+
return ["Click the site settings icon in the address bar", `Set ${device} to Allow`, "Press Try again"];
|
|
5215
5262
|
}
|
|
5216
5263
|
case "blocked_os": {
|
|
5217
5264
|
const app = where.browser === "chrome" ? "Google Chrome" : where.browser === "edge" ? "Microsoft Edge" : where.browser === "firefox" ? "Firefox" : "your browser";
|
|
@@ -5309,7 +5356,7 @@ function createMediaSupervisor(options) {
|
|
|
5309
5356
|
function setRegion(next) {
|
|
5310
5357
|
const current = region();
|
|
5311
5358
|
const merged = { ...current, ...next };
|
|
5312
|
-
if (merged.audioOutput === current.audioOutput && merged.notice === current.notice && merged.offer === current.offer && merged.permission.microphone === current.permission.microphone && merged.permission.camera === current.permission.camera) {
|
|
5359
|
+
if (merged.audioOutput === current.audioOutput && merged.notice === current.notice && merged.offer === current.offer && merged.preview === current.preview && merged.permission.microphone === current.permission.microphone && merged.permission.camera === current.permission.camera) {
|
|
5313
5360
|
return;
|
|
5314
5361
|
}
|
|
5315
5362
|
store.patch({ mediaRegion: merged });
|
|
@@ -5405,7 +5452,7 @@ function createMediaSupervisor(options) {
|
|
|
5405
5452
|
if (permission !== "unknown") setPermission(kind, permission);
|
|
5406
5453
|
return unavailableFrom(normalized, classifyDeviceFailure(normalized, permission));
|
|
5407
5454
|
}
|
|
5408
|
-
|
|
5455
|
+
const api = {
|
|
5409
5456
|
start() {
|
|
5410
5457
|
if (started || platform === null) return;
|
|
5411
5458
|
started = true;
|
|
@@ -5427,6 +5474,16 @@ function createMediaSupervisor(options) {
|
|
|
5427
5474
|
started = false;
|
|
5428
5475
|
},
|
|
5429
5476
|
unavailable,
|
|
5477
|
+
async preview(kind, outcome) {
|
|
5478
|
+
api.start();
|
|
5479
|
+
let next;
|
|
5480
|
+
if (typeof outcome === "string") next = { state: outcome, unavailable: null };
|
|
5481
|
+
else next = { state: "unavailable", unavailable: await unavailable(outcome.error, kind, `meet.${kind}Preview`) };
|
|
5482
|
+
const current = region().preview;
|
|
5483
|
+
const was = current[kind];
|
|
5484
|
+
if (was.state === next.state && was.unavailable?.reason === next.unavailable?.reason && was.unavailable?.message === next.unavailable?.message) return;
|
|
5485
|
+
setRegion({ preview: { ...region().preview, [kind]: next } });
|
|
5486
|
+
},
|
|
5430
5487
|
onAudioPlayback(canPlay) {
|
|
5431
5488
|
setRegion({ audioOutput: canPlay ? "ok" : "blocked" });
|
|
5432
5489
|
},
|
|
@@ -5485,6 +5542,7 @@ function createMediaSupervisor(options) {
|
|
|
5485
5542
|
setRegion({ notice: null });
|
|
5486
5543
|
}
|
|
5487
5544
|
};
|
|
5545
|
+
return api;
|
|
5488
5546
|
}
|
|
5489
5547
|
|
|
5490
5548
|
// src/core/room-events.ts
|
|
@@ -5996,7 +6054,8 @@ function createRoomEngine(options) {
|
|
|
5996
6054
|
message: normalized.message,
|
|
5997
6055
|
remedy: normalized.remedy,
|
|
5998
6056
|
reason: normalized.reason,
|
|
5999
|
-
retryAt: normalized.retryAfterSeconds === null ? null : now() + normalized.retryAfterSeconds * 1e3
|
|
6057
|
+
retryAt: normalized.retryAfterSeconds === null ? null : now() + normalized.retryAfterSeconds * 1e3,
|
|
6058
|
+
stage: "join"
|
|
6000
6059
|
}
|
|
6001
6060
|
});
|
|
6002
6061
|
store.dispatch({ type: "join_failed", reason: normalized.reason ?? null });
|
|
@@ -6387,6 +6446,10 @@ function createRoomEngine(options) {
|
|
|
6387
6446
|
}
|
|
6388
6447
|
departures.clear();
|
|
6389
6448
|
liveRoster = list;
|
|
6449
|
+
const localNow = list.find((p) => p.isLocal);
|
|
6450
|
+
if (localNow !== void 0 && !localNow.screenSharing && store.snapshot().share.state === "presenting") {
|
|
6451
|
+
store.patch({ share: NO_SHARE });
|
|
6452
|
+
}
|
|
6390
6453
|
const merged = mergeGhosts(list, ghosts, at);
|
|
6391
6454
|
ghosts = merged.kept;
|
|
6392
6455
|
const people = /* @__PURE__ */ new Map();
|
|
@@ -6606,7 +6669,10 @@ function createRoomEngine(options) {
|
|
|
6606
6669
|
try {
|
|
6607
6670
|
await driver.setScreenShareEnabled(enabled);
|
|
6608
6671
|
ambiguousShareDenials = 0;
|
|
6609
|
-
|
|
6672
|
+
const audio = enabled ? driver?.screenShareHasAudio?.() : void 0;
|
|
6673
|
+
store.patch({
|
|
6674
|
+
share: { state: enabled ? "presenting" : "none", reason: null, remedy: null, at: now(), ...audio !== void 0 ? { audio } : {} }
|
|
6675
|
+
});
|
|
6610
6676
|
} catch (error) {
|
|
6611
6677
|
const kind = classifyScreenShareError(error);
|
|
6612
6678
|
if (kind === "ambiguous") {
|
|
@@ -6673,13 +6739,14 @@ function createRoomEngine(options) {
|
|
|
6673
6739
|
return driver?.supportsVideoEffects?.() ?? false;
|
|
6674
6740
|
},
|
|
6675
6741
|
supportsScreenShare() {
|
|
6676
|
-
return driver?.supportsScreenShare?.() ??
|
|
6742
|
+
return driver?.supportsScreenShare?.() ?? detectCapabilities().canShareScreen;
|
|
6677
6743
|
},
|
|
6678
6744
|
async switchDevice(kind, deviceId2) {
|
|
6679
6745
|
if (driver === null) return;
|
|
6680
6746
|
await driver.switchDevice(kind, deviceId2);
|
|
6681
6747
|
},
|
|
6682
6748
|
enableAudio: () => media.enableAudio(),
|
|
6749
|
+
previewDevice: (kind, outcome) => media.preview(kind, outcome),
|
|
6683
6750
|
acceptDeviceOffer: () => media.acceptOffer(),
|
|
6684
6751
|
dismissDeviceOffer: () => media.dismissOffer(),
|
|
6685
6752
|
dismissDeviceNotice: () => media.dismissNotice(),
|
|
@@ -7151,7 +7218,15 @@ function createLiveKitDriver(handlers, options = {}) {
|
|
|
7151
7218
|
created.on(RoomEvent.ParticipantConnected, roster).on(RoomEvent.ParticipantDisconnected, (participant, reason) => {
|
|
7152
7219
|
handlers.participantLeft?.(participant.identity, reasonName(reason));
|
|
7153
7220
|
roster();
|
|
7154
|
-
}).on(RoomEvent.TrackSubscribed, roster).on(RoomEvent.TrackUnsubscribed, roster).on(RoomEvent.TrackMuted, roster).on(RoomEvent.TrackUnmuted, roster).on(RoomEvent.LocalTrackPublished,
|
|
7221
|
+
}).on(RoomEvent.TrackSubscribed, roster).on(RoomEvent.TrackUnsubscribed, roster).on(RoomEvent.TrackMuted, roster).on(RoomEvent.TrackUnmuted, roster).on(RoomEvent.LocalTrackPublished, (publication) => {
|
|
7222
|
+
if (publication.source === Track.Source.ScreenShare) {
|
|
7223
|
+
const ended = () => {
|
|
7224
|
+
void created.localParticipant.setScreenShareEnabled(false).catch(() => void 0);
|
|
7225
|
+
};
|
|
7226
|
+
publication.track?.mediaStreamTrack.addEventListener("ended", ended, { once: true });
|
|
7227
|
+
}
|
|
7228
|
+
roster();
|
|
7229
|
+
}).on(RoomEvent.LocalTrackUnpublished, roster).on(RoomEvent.ParticipantNameChanged, roster).on(RoomEvent.ParticipantAttributesChanged, roster).on(RoomEvent.ParticipantMetadataChanged, roster).on(RoomEvent.RoomMetadataChanged, (metadata) => {
|
|
7155
7230
|
handlers.roomMetadata?.(metadata ?? "");
|
|
7156
7231
|
}).on(RoomEvent.AudioPlaybackStatusChanged, (canPlay) => {
|
|
7157
7232
|
handlers.audioPlayback?.(canPlay);
|
|
@@ -7292,7 +7367,10 @@ function createLiveKitDriver(handlers, options = {}) {
|
|
|
7292
7367
|
},
|
|
7293
7368
|
async setScreenShareEnabled(enabled) {
|
|
7294
7369
|
try {
|
|
7295
|
-
await requireRoom("setScreenShareEnabled").localParticipant.setScreenShareEnabled(
|
|
7370
|
+
await requireRoom("setScreenShareEnabled").localParticipant.setScreenShareEnabled(
|
|
7371
|
+
enabled,
|
|
7372
|
+
enabled ? { audio: true, systemAudio: "include" } : void 0
|
|
7373
|
+
);
|
|
7296
7374
|
} catch (error) {
|
|
7297
7375
|
throw normalizeScreenShareError(error, "meet.setScreenShareEnabled");
|
|
7298
7376
|
}
|
|
@@ -7331,8 +7409,13 @@ function createLiveKitDriver(handlers, options = {}) {
|
|
|
7331
7409
|
supportsVideoEffects() {
|
|
7332
7410
|
return videoEffectsSupported();
|
|
7333
7411
|
},
|
|
7412
|
+
screenShareHasAudio() {
|
|
7413
|
+
const target = room;
|
|
7414
|
+
if (target === null) return false;
|
|
7415
|
+
return target.localParticipant.getTrackPublications().some((p) => String(p.source) === "screen_share_audio" && p.track !== void 0);
|
|
7416
|
+
},
|
|
7334
7417
|
supportsScreenShare() {
|
|
7335
|
-
return
|
|
7418
|
+
return detectCapabilities().canShareScreen;
|
|
7336
7419
|
},
|
|
7337
7420
|
attach(identity, kind, element) {
|
|
7338
7421
|
const target = requireRoom("attach");
|
|
@@ -7818,6 +7901,21 @@ function observedDevice(track, permission = "unknown", held = null) {
|
|
|
7818
7901
|
const reason = deviceUnavailableReason(track, permission);
|
|
7819
7902
|
return reason === null ? "muted_by_me" : `unavailable:${reason}`;
|
|
7820
7903
|
}
|
|
7904
|
+
function observedPreview(preview, permission = "unknown") {
|
|
7905
|
+
if (permission === "denied") return "unavailable:denied";
|
|
7906
|
+
switch (preview.state) {
|
|
7907
|
+
case "on":
|
|
7908
|
+
return "on";
|
|
7909
|
+
case "off":
|
|
7910
|
+
return "muted_by_me";
|
|
7911
|
+
case "prompting":
|
|
7912
|
+
return "prompting";
|
|
7913
|
+
case "unavailable":
|
|
7914
|
+
return `unavailable:${preview.unavailable?.reason ?? "failed"}`;
|
|
7915
|
+
default:
|
|
7916
|
+
return null;
|
|
7917
|
+
}
|
|
7918
|
+
}
|
|
7821
7919
|
function endedRecord(snapshot, given) {
|
|
7822
7920
|
const record = snapshot?.meeting ?? given;
|
|
7823
7921
|
return record !== null && record.endedAt !== null;
|
|
@@ -7841,18 +7939,22 @@ function observe(input) {
|
|
|
7841
7939
|
const canAdmit = actual !== "none" && ADMITTER_ROLES.has(actual);
|
|
7842
7940
|
const role = actual === "none" || snapshot === null ? "none" : observedRole(actual, effectiveStanding(snapshot));
|
|
7843
7941
|
const deviceInPlay = phase === "joining" || inCall;
|
|
7942
|
+
const region = snapshot?.mediaRegion;
|
|
7943
|
+
const atPrejoin = phase === "prejoin" && region !== void 0;
|
|
7844
7944
|
return {
|
|
7845
7945
|
phase,
|
|
7846
7946
|
reason: phase === "ended" ? snapshot?.reason ?? null : snapshot?.reason ?? reasonOf(phase),
|
|
7847
7947
|
role,
|
|
7848
|
-
|
|
7948
|
+
// `net-blip`: in the call, a drop shorter than `reconnect_banner_delay_ms` is not something the
|
|
7949
|
+
// person sees — the contract says what is on screen, so it reads `stable` until the banner shows.
|
|
7950
|
+
connection: snapshot === null ? "stable" : inCall && snapshot.connection !== "stable" && !snapshot.connectionBanner ? "stable" : snapshot.connection,
|
|
7849
7951
|
hostPresent: inCall && snapshot !== null ? snapshot.participants.some((p) => ADMITTER_ROLES.has(p.role)) : snapshot !== null && isWaitingPhase(snapshot.phase) ? snapshot.waiting?.admittersPresent ?? null : null,
|
|
7850
7952
|
lobbyCount: canAdmit && snapshot !== null ? snapshot.lobby.filter((entry) => entry.state === "knocking").length : 0,
|
|
7851
7953
|
recording: snapshot?.recording === "recording" || snapshot?.recording === "stopping",
|
|
7852
7954
|
// S6c: the autoplay region is known only inside the room (no remote audio exists elsewhere).
|
|
7853
7955
|
audioBlocked: inCall && snapshot !== null ? snapshot.mediaRegion.audioOutput === "blocked" : null,
|
|
7854
|
-
camera: deviceInPlay && snapshot !== null ? observedDevice(snapshot.media.camera, snapshot.mediaRegion.permission.camera, lockedFor(snapshot, "camera", inCall)) : null,
|
|
7855
|
-
microphone: deviceInPlay && snapshot !== null ? observedDevice(snapshot.media.microphone, snapshot.mediaRegion.permission.microphone, lockedFor(snapshot, "microphone", inCall)) : null
|
|
7956
|
+
camera: deviceInPlay && snapshot !== null ? observedDevice(snapshot.media.camera, snapshot.mediaRegion.permission.camera, lockedFor(snapshot, "camera", inCall)) : atPrejoin ? observedPreview(region.preview.camera, region.permission.camera) : null,
|
|
7957
|
+
microphone: deviceInPlay && snapshot !== null ? observedDevice(snapshot.media.microphone, snapshot.mediaRegion.permission.microphone, lockedFor(snapshot, "microphone", inCall)) : atPrejoin ? observedPreview(region.preview.microphone, region.permission.microphone) : null
|
|
7856
7958
|
};
|
|
7857
7959
|
}
|
|
7858
7960
|
function lockedFor(snapshot, kind, inCall) {
|
|
@@ -7952,7 +8054,13 @@ function MeetRoot({
|
|
|
7952
8054
|
...options
|
|
7953
8055
|
}) {
|
|
7954
8056
|
const snapshot = useMeetSnapshot();
|
|
7955
|
-
const
|
|
8057
|
+
const probed = useCapabilities();
|
|
8058
|
+
const base = useCoreObservation(options);
|
|
8059
|
+
const unsupported = probed !== null && !probed.canJoin;
|
|
8060
|
+
const observation = (0, import_react3.useMemo)(
|
|
8061
|
+
() => unsupported ? { ...staticObservation("unsupported", probed?.reason ?? null) } : base,
|
|
8062
|
+
[unsupported, probed, base]
|
|
8063
|
+
);
|
|
7956
8064
|
const attrs = (0, import_react3.useMemo)(() => rootAttributes(observation), [observation]);
|
|
7957
8065
|
const latest = (0, import_react3.useRef)({ observation, storePhase: snapshot?.phase ?? null });
|
|
7958
8066
|
latest.current = { observation, storePhase: snapshot?.phase ?? null };
|
|
@@ -7970,7 +8078,34 @@ function MeetRoot({
|
|
|
7970
8078
|
if (target.__matrxMeet === diagnostics) delete target.__matrxMeet;
|
|
7971
8079
|
};
|
|
7972
8080
|
}, []);
|
|
7973
|
-
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { ...attrs, style: { display: "contents" }, children });
|
|
8081
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { ...attrs, style: { display: "contents" }, children: unsupported && probed !== null ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(UnsupportedBrowser, { capabilities: probed }) : children });
|
|
8082
|
+
}
|
|
8083
|
+
function useCapabilities() {
|
|
8084
|
+
const [found, setFound] = (0, import_react3.useState)(null);
|
|
8085
|
+
(0, import_react3.useEffect)(() => {
|
|
8086
|
+
setFound(detectCapabilities());
|
|
8087
|
+
}, []);
|
|
8088
|
+
return found;
|
|
8089
|
+
}
|
|
8090
|
+
function UnsupportedBrowser({ capabilities }) {
|
|
8091
|
+
const words = unsupportedWords(capabilities);
|
|
8092
|
+
const [copied, setCopied] = (0, import_react3.useState)(false);
|
|
8093
|
+
const href = typeof window === "undefined" ? "" : window.location.href;
|
|
8094
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "mx-meet", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "mx-meet__waiting", "data-meet-exit": "unsupported", children: [
|
|
8095
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h1", { className: "mx-meet__prejoin-title", children: words.title }),
|
|
8096
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "mx-meet__hint", role: "status", "data-meet-notice": "browser-unsupported", children: words.body }),
|
|
8097
|
+
href.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
8098
|
+
"button",
|
|
8099
|
+
{
|
|
8100
|
+
type: "button",
|
|
8101
|
+
className: "mx-meet__primary",
|
|
8102
|
+
onClick: () => {
|
|
8103
|
+
void navigator.clipboard?.writeText(href).then(() => setCopied(true), () => void 0);
|
|
8104
|
+
},
|
|
8105
|
+
children: copied ? "Link copied" : "Copy link"
|
|
8106
|
+
}
|
|
8107
|
+
) : null
|
|
8108
|
+
] }) });
|
|
7974
8109
|
}
|
|
7975
8110
|
|
|
7976
8111
|
// src/react/hooks.ts
|
|
@@ -8670,7 +8805,8 @@ function useRoom() {
|
|
|
8670
8805
|
failure: snapshot?.failure ?? null,
|
|
8671
8806
|
secondDevice: snapshot?.secondDevice ?? null,
|
|
8672
8807
|
local,
|
|
8673
|
-
|
|
8808
|
+
// An observer (role `viewer`) publishes nothing: no Share screen to press and be refused (MD-16).
|
|
8809
|
+
canShareScreen: (engine?.supportsScreenShare() ?? true) && !isObserverRole(snapshot?.grants.role ?? null),
|
|
8674
8810
|
join: (0, import_react4.useCallback)(
|
|
8675
8811
|
async (request) => requireEngine(engine, "join").join(request),
|
|
8676
8812
|
[engine]
|
|
@@ -9149,6 +9285,12 @@ function useMediaSupervisor() {
|
|
|
9149
9285
|
retry: (0, import_react4.useCallback)(
|
|
9150
9286
|
async (kind) => kind === "microphone" ? engine?.setMicrophoneEnabled(true) : engine?.setCameraEnabled(true),
|
|
9151
9287
|
[engine]
|
|
9288
|
+
),
|
|
9289
|
+
reportPreview: (0, import_react4.useCallback)(
|
|
9290
|
+
(kind, outcome) => {
|
|
9291
|
+
void engine?.previewDevice(kind, outcome);
|
|
9292
|
+
},
|
|
9293
|
+
[engine]
|
|
9152
9294
|
)
|
|
9153
9295
|
};
|
|
9154
9296
|
}
|
|
@@ -10244,6 +10386,39 @@ function useCollabPanelRequest(onRequest) {
|
|
|
10244
10386
|
// src/core/reactions.ts
|
|
10245
10387
|
var MEET_REACTIONS = ["\u{1F496}", "\u{1F44D}", "\u{1F389}", "\u{1F44F}", "\u{1F602}", "\u{1F62E}", "\u{1F622}", "\u{1F914}", "\u{1F44E}"];
|
|
10246
10388
|
|
|
10389
|
+
// src/core/speaking-detector.ts
|
|
10390
|
+
function createSpeakingWhileMutedDetector(options = {}) {
|
|
10391
|
+
const threshold = options.threshold ?? 0.06;
|
|
10392
|
+
const holdMs = options.holdMs ?? 600;
|
|
10393
|
+
const gapMs = options.gapMs ?? 400;
|
|
10394
|
+
const cooldownMs = options.cooldownMs ?? 2e4;
|
|
10395
|
+
let speechStart = null;
|
|
10396
|
+
let lastLoud = null;
|
|
10397
|
+
let firedAt = null;
|
|
10398
|
+
return {
|
|
10399
|
+
feed(level, at) {
|
|
10400
|
+
if (level >= threshold) {
|
|
10401
|
+
if (speechStart === null || lastLoud === null || at - lastLoud > gapMs) speechStart = at;
|
|
10402
|
+
lastLoud = at;
|
|
10403
|
+
} else if (lastLoud !== null && at - lastLoud > gapMs) {
|
|
10404
|
+
speechStart = null;
|
|
10405
|
+
lastLoud = null;
|
|
10406
|
+
}
|
|
10407
|
+
if (speechStart === null || at - speechStart < holdMs) return false;
|
|
10408
|
+
if (firedAt !== null && at - firedAt < cooldownMs) return false;
|
|
10409
|
+
firedAt = at;
|
|
10410
|
+
speechStart = null;
|
|
10411
|
+
lastLoud = null;
|
|
10412
|
+
return true;
|
|
10413
|
+
},
|
|
10414
|
+
reset() {
|
|
10415
|
+
speechStart = null;
|
|
10416
|
+
lastLoud = null;
|
|
10417
|
+
firedAt = null;
|
|
10418
|
+
}
|
|
10419
|
+
};
|
|
10420
|
+
}
|
|
10421
|
+
|
|
10247
10422
|
// src/react/facade.ts
|
|
10248
10423
|
var NO_ACTIONS = {
|
|
10249
10424
|
join: async () => void 0,
|
|
@@ -10547,6 +10722,9 @@ function UndoIcon(props) {
|
|
|
10547
10722
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M4 9h10.5a5.5 5.5 0 0 1 5.5 5.5a5.5 5.5 0 0 1-5.5 5.5H11" })
|
|
10548
10723
|
] });
|
|
10549
10724
|
}
|
|
10725
|
+
function ChevronUpIcon(props) {
|
|
10726
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Icon, { ...props, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "m6 15 6-6 6 6" }) });
|
|
10727
|
+
}
|
|
10550
10728
|
|
|
10551
10729
|
// src/skins/meet/collab.tsx
|
|
10552
10730
|
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
@@ -11800,6 +11978,7 @@ function ControlBar({ onLeave }) {
|
|
|
11800
11978
|
) }) }) : null,
|
|
11801
11979
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(BreakoutBanner, {}),
|
|
11802
11980
|
panel !== "people" ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(KnockNotice, { onView: () => setPanel("people") }) : null,
|
|
11981
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(SpeakingWhileMutedNudge, {}),
|
|
11803
11982
|
controls.notice !== null && panel !== "people" ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Toast, { text: controls.notice.text, failed: controls.notice.failed, onDone: controls.clearNotice }) : null,
|
|
11804
11983
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "mx-meet__controls", children: [
|
|
11805
11984
|
live.micLocked ? null : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
@@ -11811,6 +11990,7 @@ function ControlBar({ onLeave }) {
|
|
|
11811
11990
|
children: room.local?.micEnabled === true ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(MicIcon, {}) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(MicOffIcon, {})
|
|
11812
11991
|
}
|
|
11813
11992
|
),
|
|
11993
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(AudioSettingsControl, {}),
|
|
11814
11994
|
live.cameraLocked ? null : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
11815
11995
|
ControlButton,
|
|
11816
11996
|
{
|
|
@@ -11926,6 +12106,13 @@ function ControlBar({ onLeave }) {
|
|
|
11926
12106
|
]
|
|
11927
12107
|
}
|
|
11928
12108
|
),
|
|
12109
|
+
!room.canShareScreen && room.local?.screenSharing !== true ? (
|
|
12110
|
+
// `share-unsupported-mobile`: the control is absent; the menu says where it lives.
|
|
12111
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("p", { className: "mx-meet__menu-note", role: "note", "data-meet-notice": "share-unsupported", children: [
|
|
12112
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ScreenShareIcon, { width: 16, height: 16 }),
|
|
12113
|
+
" Present from a computer"
|
|
12114
|
+
] })
|
|
12115
|
+
) : null,
|
|
11929
12116
|
controls.isHost ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
11930
12117
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "mx-meet__menu-sep", role: "separator" }),
|
|
11931
12118
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
@@ -12200,6 +12387,94 @@ function Toast({ text: text3, failed, onDone }) {
|
|
|
12200
12387
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", className: "mx-meet__toast-close", "aria-label": "Dismiss", onClick: onDone, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(CloseIcon, { width: 14, height: 14 }) })
|
|
12201
12388
|
] });
|
|
12202
12389
|
}
|
|
12390
|
+
function AudioSettingsControl() {
|
|
12391
|
+
const host = useMeetHost();
|
|
12392
|
+
const devices = useDeviceSnapshot();
|
|
12393
|
+
const [open, setOpen] = (0, import_react10.useState)(false);
|
|
12394
|
+
const list = (devices?.devices.audioinput ?? []).filter((device) => device.deviceId.length > 0);
|
|
12395
|
+
if (host === null || list.length < 2) return null;
|
|
12396
|
+
const current = devices?.selected.audioinput ?? host.devices.resolve("audioinput");
|
|
12397
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "mx-meet__anchor", children: [
|
|
12398
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
12399
|
+
ControlButton,
|
|
12400
|
+
{
|
|
12401
|
+
label: "Audio settings",
|
|
12402
|
+
active: open,
|
|
12403
|
+
onClick: () => {
|
|
12404
|
+
if (!open) void host.devices.refresh();
|
|
12405
|
+
setOpen(!open);
|
|
12406
|
+
},
|
|
12407
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ChevronUpIcon, {})
|
|
12408
|
+
}
|
|
12409
|
+
),
|
|
12410
|
+
open ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Popover, { label: "Microphone", onClose: () => setOpen(false), children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "mx-meet__menu", role: "menu", "aria-label": "Microphone", children: list.map((device) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
12411
|
+
"button",
|
|
12412
|
+
{
|
|
12413
|
+
type: "button",
|
|
12414
|
+
role: "menuitemradio",
|
|
12415
|
+
"aria-checked": device.deviceId === current,
|
|
12416
|
+
className: "mx-meet__menu-item",
|
|
12417
|
+
onClick: () => {
|
|
12418
|
+
setOpen(false);
|
|
12419
|
+
host.devices.select("audioinput", device.deviceId);
|
|
12420
|
+
void host.engine.switchDevice("audioinput", device.deviceId).catch(() => void 0);
|
|
12421
|
+
},
|
|
12422
|
+
children: [
|
|
12423
|
+
device.deviceId === current ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(CheckIcon, { width: 16, height: 16 }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "mx-meet__menu-gap" }),
|
|
12424
|
+
device.label.length > 0 ? device.label : "Microphone"
|
|
12425
|
+
]
|
|
12426
|
+
},
|
|
12427
|
+
device.deviceId
|
|
12428
|
+
)) }) }) : null
|
|
12429
|
+
] });
|
|
12430
|
+
}
|
|
12431
|
+
function SpeakingWhileMutedNudge() {
|
|
12432
|
+
const room = useRoom();
|
|
12433
|
+
const host = useMeetHost();
|
|
12434
|
+
const devices = useDeviceSnapshot();
|
|
12435
|
+
const microphone = useLocalMedia().microphone;
|
|
12436
|
+
const mutedByMe = host !== null && room.local != null && room.local.micEnabled !== true && microphone.unavailable === null;
|
|
12437
|
+
const mic = devices?.selected.audioinput ?? host?.devices.resolve("audioinput") ?? null;
|
|
12438
|
+
const stream = useMicrophoneStream(mutedByMe ? mic : "off");
|
|
12439
|
+
const level = useAudioLevel(stream);
|
|
12440
|
+
const latest = (0, import_react10.useRef)(0);
|
|
12441
|
+
latest.current = level;
|
|
12442
|
+
const [shown, setShown] = (0, import_react10.useState)(false);
|
|
12443
|
+
const [detector] = (0, import_react10.useState)(() => createSpeakingWhileMutedDetector());
|
|
12444
|
+
(0, import_react10.useEffect)(() => {
|
|
12445
|
+
if (!mutedByMe) {
|
|
12446
|
+
detector.reset();
|
|
12447
|
+
setShown(false);
|
|
12448
|
+
return void 0;
|
|
12449
|
+
}
|
|
12450
|
+
const timer = setInterval(() => {
|
|
12451
|
+
if (detector.feed(latest.current, Date.now())) setShown(true);
|
|
12452
|
+
}, 150);
|
|
12453
|
+
return () => clearInterval(timer);
|
|
12454
|
+
}, [mutedByMe, detector]);
|
|
12455
|
+
(0, import_react10.useEffect)(() => {
|
|
12456
|
+
if (!shown) return void 0;
|
|
12457
|
+
const timer = setTimeout(() => setShown(false), 8e3);
|
|
12458
|
+
return () => clearTimeout(timer);
|
|
12459
|
+
}, [shown]);
|
|
12460
|
+
if (!shown || !mutedByMe) return null;
|
|
12461
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "mx-meet__notice-bar", role: "status", "data-meet-notice": "speaking-while-muted", children: [
|
|
12462
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(MicOffIcon, { width: 16, height: 16 }),
|
|
12463
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { children: "You're muted" }),
|
|
12464
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
12465
|
+
"button",
|
|
12466
|
+
{
|
|
12467
|
+
type: "button",
|
|
12468
|
+
className: "mx-meet__primary mx-meet__primary--small",
|
|
12469
|
+
onClick: () => {
|
|
12470
|
+
setShown(false);
|
|
12471
|
+
void room.toggleMicrophone();
|
|
12472
|
+
},
|
|
12473
|
+
children: "Unmute"
|
|
12474
|
+
}
|
|
12475
|
+
)
|
|
12476
|
+
] });
|
|
12477
|
+
}
|
|
12203
12478
|
function MediaNotices() {
|
|
12204
12479
|
const media = useLocalMedia();
|
|
12205
12480
|
const { region, where, enableAudio, acceptOffer, dismissOffer, dismissNotice, retry } = useMediaSupervisor();
|
|
@@ -13049,14 +13324,20 @@ async function playTestSound(sinkId) {
|
|
|
13049
13324
|
audio.pause();
|
|
13050
13325
|
await context.close();
|
|
13051
13326
|
}
|
|
13052
|
-
function useMicrophoneStream(deviceId2) {
|
|
13327
|
+
function useMicrophoneStream(deviceId2, report, attempt = 0) {
|
|
13053
13328
|
const [stream, setStream] = (0, import_react10.useState)(null);
|
|
13329
|
+
const reportRef = (0, import_react10.useRef)(report);
|
|
13330
|
+
reportRef.current = report;
|
|
13054
13331
|
(0, import_react10.useEffect)(() => {
|
|
13055
|
-
if (deviceId2 === "off")
|
|
13332
|
+
if (deviceId2 === "off") {
|
|
13333
|
+
reportRef.current?.("off");
|
|
13334
|
+
return void 0;
|
|
13335
|
+
}
|
|
13056
13336
|
let live = true;
|
|
13057
13337
|
let opened = null;
|
|
13058
13338
|
const media = globalThis.navigator?.mediaDevices;
|
|
13059
13339
|
if (media === void 0) return void 0;
|
|
13340
|
+
reportRef.current?.("prompting");
|
|
13060
13341
|
void media.getUserMedia({ audio: deviceId2 === null ? true : { deviceId: { exact: deviceId2 } } }).then((next) => {
|
|
13061
13342
|
if (!live) {
|
|
13062
13343
|
next.getTracks().forEach((track) => track.stop());
|
|
@@ -13064,15 +13345,49 @@ function useMicrophoneStream(deviceId2) {
|
|
|
13064
13345
|
}
|
|
13065
13346
|
opened = next;
|
|
13066
13347
|
setStream(next);
|
|
13067
|
-
|
|
13348
|
+
reportRef.current?.("on");
|
|
13349
|
+
}).catch((thrown) => {
|
|
13350
|
+
setStream(null);
|
|
13351
|
+
if (live) reportRef.current?.({ error: thrown });
|
|
13352
|
+
});
|
|
13068
13353
|
return () => {
|
|
13069
13354
|
live = false;
|
|
13070
13355
|
opened?.getTracks().forEach((track) => track.stop());
|
|
13071
13356
|
setStream(null);
|
|
13072
13357
|
};
|
|
13073
|
-
}, [deviceId2]);
|
|
13358
|
+
}, [deviceId2, attempt]);
|
|
13074
13359
|
return stream;
|
|
13075
13360
|
}
|
|
13361
|
+
function PreviewStatus({ onRetry }) {
|
|
13362
|
+
const { region, where } = useMediaSupervisor();
|
|
13363
|
+
const [waited, setWaited] = (0, import_react10.useState)(false);
|
|
13364
|
+
const prompting = region.preview.microphone.state === "prompting" || region.preview.camera.state === "prompting";
|
|
13365
|
+
(0, import_react10.useEffect)(() => {
|
|
13366
|
+
if (!prompting) {
|
|
13367
|
+
setWaited(false);
|
|
13368
|
+
return void 0;
|
|
13369
|
+
}
|
|
13370
|
+
const timer = setTimeout(() => setWaited(true), 800);
|
|
13371
|
+
return () => clearTimeout(timer);
|
|
13372
|
+
}, [prompting]);
|
|
13373
|
+
const refused = ["microphone", "camera"].flatMap((kind) => {
|
|
13374
|
+
const preview = region.preview[kind];
|
|
13375
|
+
const reason = region.permission[kind] === "denied" ? "denied" : preview.state === "unavailable" ? preview.unavailable?.reason ?? "failed" : null;
|
|
13376
|
+
return reason === null ? [] : [{ kind, reason }];
|
|
13377
|
+
});
|
|
13378
|
+
if (refused.length === 0) {
|
|
13379
|
+
if (!prompting || !waited) return null;
|
|
13380
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "mx-meet__panel-note", role: "status", "data-meet-notice": "permission-prompt", children: "Allow camera and microphone when your browser asks" });
|
|
13381
|
+
}
|
|
13382
|
+
const first = refused[0];
|
|
13383
|
+
const both = refused.length === 2 && refused[0].reason === refused[1].reason;
|
|
13384
|
+
const label = both ? deviceChipLabel("camera", first.reason).replace(/^Camera/, "Camera and mic") : refused.map((r) => deviceChipLabel(r.kind, r.reason)).join(" \xB7 ");
|
|
13385
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "mx-meet__warning", role: "status", "data-meet-notice": deviceNoticeCode(first.kind, first.reason), children: [
|
|
13386
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("strong", { children: label }),
|
|
13387
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("ol", { className: "mx-meet__fix-steps", children: deviceFixSteps(first.kind, first.reason, where).map((step) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("li", { children: step }, step)) }),
|
|
13388
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system.Button, { type: "button", variant: "outline", size: "sm", onClick: onRetry, children: "Try again" })
|
|
13389
|
+
] });
|
|
13390
|
+
}
|
|
13076
13391
|
function KnockNotice({ onView }) {
|
|
13077
13392
|
const { knocker, others, admit, dismiss } = useKnockNotice();
|
|
13078
13393
|
if (knocker === null) return null;
|
|
@@ -13402,8 +13717,15 @@ function PreJoinBody({
|
|
|
13402
13717
|
const [joining, setJoining] = (0, import_react10.useState)(false);
|
|
13403
13718
|
const camera = devices?.selected.videoinput ?? host.devices.resolve("videoinput");
|
|
13404
13719
|
const mic = devices?.selected.audioinput ?? host.devices.resolve("audioinput");
|
|
13405
|
-
const
|
|
13406
|
-
const
|
|
13720
|
+
const { reportPreview } = useMediaSupervisor();
|
|
13721
|
+
const [attempt, setAttempt] = (0, import_react10.useState)(0);
|
|
13722
|
+
const preview = useCameraPreview(
|
|
13723
|
+
mode === "video" ? camera : void 0,
|
|
13724
|
+
effects.effects,
|
|
13725
|
+
(outcome) => reportPreview("camera", outcome),
|
|
13726
|
+
attempt
|
|
13727
|
+
);
|
|
13728
|
+
const micStream = useMicrophoneStream(microphone ? mic : "off", (outcome) => reportPreview("microphone", outcome), attempt);
|
|
13407
13729
|
const level = useAudioLevel(micStream);
|
|
13408
13730
|
const [speakerTesting, setSpeakerTesting] = (0, import_react10.useState)(false);
|
|
13409
13731
|
(0, import_react10.useEffect)(() => {
|
|
@@ -13447,6 +13769,7 @@ function PreJoinBody({
|
|
|
13447
13769
|
] }),
|
|
13448
13770
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "mx-meet__prejoin-panel", children: [
|
|
13449
13771
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h1", { className: "mx-meet__prejoin-title", children: "Ready to join?" }),
|
|
13772
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PreviewStatus, { onRetry: () => setAttempt((n) => n + 1) }),
|
|
13450
13773
|
notice?.kind === "removed" ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "mx-meet__warning", children: notice.text }) : null,
|
|
13451
13774
|
devices?.labelsHidden === true ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("p", { className: "mx-meet__panel-note", children: [
|
|
13452
13775
|
"Your browser is hiding device names until you allow camera and microphone access.",
|
|
@@ -13549,16 +13872,22 @@ function PreJoinBody({
|
|
|
13549
13872
|
] })
|
|
13550
13873
|
] });
|
|
13551
13874
|
}
|
|
13552
|
-
function useCameraPreview(deviceId2, effects) {
|
|
13875
|
+
function useCameraPreview(deviceId2, effects, report, attempt = 0) {
|
|
13876
|
+
const reportRef = (0, import_react10.useRef)(report);
|
|
13877
|
+
reportRef.current = report;
|
|
13553
13878
|
const [preview, setPreview] = (0, import_react10.useState)(null);
|
|
13554
13879
|
const [error, setError] = (0, import_react10.useState)(null);
|
|
13555
13880
|
const current = (0, import_react10.useRef)(null);
|
|
13556
13881
|
const initialEffect = (0, import_react10.useRef)(toVideoEffect(effects));
|
|
13557
13882
|
initialEffect.current = toVideoEffect(effects);
|
|
13558
13883
|
(0, import_react10.useEffect)(() => {
|
|
13559
|
-
if (deviceId2 === void 0)
|
|
13884
|
+
if (deviceId2 === void 0) {
|
|
13885
|
+
reportRef.current?.("off");
|
|
13886
|
+
return void 0;
|
|
13887
|
+
}
|
|
13560
13888
|
let live = true;
|
|
13561
13889
|
setError(null);
|
|
13890
|
+
reportRef.current?.("prompting");
|
|
13562
13891
|
void createCameraPreview(deviceId2, initialEffect.current).then((created) => {
|
|
13563
13892
|
if (!live) {
|
|
13564
13893
|
created.stop();
|
|
@@ -13566,8 +13895,10 @@ function useCameraPreview(deviceId2, effects) {
|
|
|
13566
13895
|
}
|
|
13567
13896
|
current.current = created;
|
|
13568
13897
|
setPreview(created);
|
|
13898
|
+
reportRef.current?.("on");
|
|
13569
13899
|
}).catch((thrown) => {
|
|
13570
13900
|
if (!live) return;
|
|
13901
|
+
reportRef.current?.({ error: thrown });
|
|
13571
13902
|
const failure = thrown;
|
|
13572
13903
|
const message = (failure.message ?? "").replace(/^meet\.[A-Za-z.()]+:\s*/, "");
|
|
13573
13904
|
const sentence = message.length > 0 ? message.charAt(0).toUpperCase() + message.slice(1) : "";
|
|
@@ -13579,7 +13910,7 @@ function useCameraPreview(deviceId2, effects) {
|
|
|
13579
13910
|
current.current = null;
|
|
13580
13911
|
setPreview(null);
|
|
13581
13912
|
};
|
|
13582
|
-
}, [deviceId2]);
|
|
13913
|
+
}, [deviceId2, attempt]);
|
|
13583
13914
|
return {
|
|
13584
13915
|
preview,
|
|
13585
13916
|
error,
|
|
@@ -13719,6 +14050,14 @@ function MeetSkinRoom({
|
|
|
13719
14050
|
}
|
|
13720
14051
|
function ShareNotice() {
|
|
13721
14052
|
const { share, actions } = useMeetCore();
|
|
14053
|
+
const [soundHintClosed, setSoundHintClosed] = (0, import_react10.useState)(null);
|
|
14054
|
+
if (share.state === "presenting" && share.audio === false && soundHintClosed !== share.at) {
|
|
14055
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("p", { className: "mx-meet__banner", role: "status", "data-meet-notice": "share-audio-missing", children: [
|
|
14056
|
+
"Sound not shared",
|
|
14057
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "mx-meet__remedy", children: "To include sound, share a tab and turn on Also share tab audio" }),
|
|
14058
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", className: "mx-meet__link", onClick: () => setSoundHintClosed(share.at), children: "Dismiss" })
|
|
14059
|
+
] });
|
|
14060
|
+
}
|
|
13722
14061
|
if (share.state !== "refused") return null;
|
|
13723
14062
|
const text3 = share.reason === "unsupported" ? "You can't share your screen from this browser" : share.reason === "blocked" ? "Screen sharing is blocked" : "Couldn't start sharing your screen";
|
|
13724
14063
|
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("p", { className: "mx-meet__banner", role: "status", "data-meet-notice": "share-unavailable", children: [
|
|
@@ -13831,6 +14170,27 @@ function ExitScreen({ onLeave }) {
|
|
|
13831
14170
|
] });
|
|
13832
14171
|
break;
|
|
13833
14172
|
case "disconnected":
|
|
14173
|
+
if (failure?.stage === "join" && (failure.reason ?? null) === null) {
|
|
14174
|
+
title = "Can't connect to the meeting";
|
|
14175
|
+
line = connection === "offline" ? "You're offline. Check your internet connection." : "Check your network. A VPN, firewall or proxy may be blocking the call.";
|
|
14176
|
+
notice = "cannot-connect";
|
|
14177
|
+
actionsNode = /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
14178
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
14179
|
+
import_design_system.Button,
|
|
14180
|
+
{
|
|
14181
|
+
type: "button",
|
|
14182
|
+
disabled: busy,
|
|
14183
|
+
onClick: () => {
|
|
14184
|
+
setBusy(true);
|
|
14185
|
+
void actions.rejoin().catch(() => void 0).finally(() => setBusy(false));
|
|
14186
|
+
},
|
|
14187
|
+
children: "Try again"
|
|
14188
|
+
}
|
|
14189
|
+
),
|
|
14190
|
+
home
|
|
14191
|
+
] });
|
|
14192
|
+
break;
|
|
14193
|
+
}
|
|
13834
14194
|
title = "You lost your connection to the meeting";
|
|
13835
14195
|
line = connection === "offline" ? "You're offline. You'll rejoin automatically when your internet is back." : connection === "server_unreachable" ? "Can't reach the meeting server. You'll rejoin automatically when it answers." : failure?.remedy ?? "Check your internet connection, then rejoin.";
|
|
13836
14196
|
notice = "disconnected";
|