diff --git a/src/UrlParams.ts b/src/UrlParams.ts index 498d7cc5..321af424 100644 --- a/src/UrlParams.ts +++ b/src/UrlParams.ts @@ -111,6 +111,12 @@ interface UrlParams { * E2EE password */ password: string | null; + /** + * Setting this flag skips the lobby and brings you in the call directly. + * In the widget this can be combined with preload to pass the device settings + * with the join widget action. + */ + skipLobby: boolean; } // This is here as a stopgap, but what would be far nicer is a function that @@ -206,6 +212,7 @@ export const getUrlParams = ( fontScale: Number.isNaN(fontScale) ? null : fontScale, analyticsID: parser.getParam("analyticsID"), allowIceFallback: parser.getFlagParam("allowIceFallback"), + skipLobby: parser.getFlagParam("skipLobby"), }; }; diff --git a/src/room/GroupCallView.tsx b/src/room/GroupCallView.tsx index 4b2f4cfa..202f8f6e 100644 --- a/src/room/GroupCallView.tsx +++ b/src/room/GroupCallView.tsx @@ -56,6 +56,7 @@ interface Props { isPasswordlessUser: boolean; confineToRoom: boolean; preload: boolean; + skipLobby: boolean; hideHeader: boolean; rtcSession: MatrixRTCSession; } @@ -65,6 +66,7 @@ export const GroupCallView: FC = ({ isPasswordlessUser, confineToRoom, preload, + skipLobby, hideHeader, rtcSession, }) => { @@ -122,80 +124,80 @@ export const GroupCallView: FC = ({ latestMuteStates.current = muteStates; useEffect(() => { + // this effect is only if we don't want to show the lobby (skipLobby = true) + if (!skipLobby) return; + + const defaultDeviceSetup = async ( + requestedDeviceData: JoinCallData, + ): Promise => { + // XXX: I think this is broken currently - LiveKit *won't* request + // permissions and give you device names unless you specify a kind, but + // here we want all kinds of devices. This needs a fix in livekit-client + // for the following name-matching logic to do anything useful. + const devices = await Room.getLocalDevices(undefined, true); + const { audioInput, videoInput } = requestedDeviceData; + if (audioInput === null) { + latestMuteStates.current!.audio.setEnabled?.(false); + } else { + const deviceId = await findDeviceByName( + audioInput, + "audioinput", + devices, + ); + if (!deviceId) { + logger.warn("Unknown audio input: " + audioInput); + latestMuteStates.current!.audio.setEnabled?.(false); + } else { + logger.debug( + `Found audio input ID ${deviceId} for name ${audioInput}`, + ); + latestDevices.current!.audioInput.select(deviceId); + latestMuteStates.current!.audio.setEnabled?.(true); + } + } + + if (videoInput === null) { + latestMuteStates.current!.video.setEnabled?.(false); + } else { + const deviceId = await findDeviceByName( + videoInput, + "videoinput", + devices, + ); + if (!deviceId) { + logger.warn("Unknown video input: " + videoInput); + latestMuteStates.current!.video.setEnabled?.(false); + } else { + logger.debug( + `Found video input ID ${deviceId} for name ${videoInput}`, + ); + latestDevices.current!.videoInput.select(deviceId); + latestMuteStates.current!.video.setEnabled?.(true); + } + } + }; if (widget && preload) { // In preload mode, wait for a join action before entering const onJoin = async ( ev: CustomEvent, ): Promise => { - // XXX: I think this is broken currently - LiveKit *won't* request - // permissions and give you device names unless you specify a kind, but - // here we want all kinds of devices. This needs a fix in livekit-client - // for the following name-matching logic to do anything useful. - const devices = await Room.getLocalDevices(undefined, true); - - const { audioInput, videoInput } = ev.detail - .data as unknown as JoinCallData; - - if (audioInput === null) { - latestMuteStates.current!.audio.setEnabled?.(false); - } else { - const deviceId = await findDeviceByName( - audioInput, - "audioinput", - devices, - ); - if (!deviceId) { - logger.warn("Unknown audio input: " + audioInput); - latestMuteStates.current!.audio.setEnabled?.(false); - } else { - logger.debug( - `Found audio input ID ${deviceId} for name ${audioInput}`, - ); - latestDevices.current!.audioInput.select(deviceId); - latestMuteStates.current!.audio.setEnabled?.(true); - } - } - - if (videoInput === null) { - latestMuteStates.current!.video.setEnabled?.(false); - } else { - const deviceId = await findDeviceByName( - videoInput, - "videoinput", - devices, - ); - if (!deviceId) { - logger.warn("Unknown video input: " + videoInput); - latestMuteStates.current!.video.setEnabled?.(false); - } else { - logger.debug( - `Found video input ID ${deviceId} for name ${videoInput}`, - ); - latestDevices.current!.videoInput.select(deviceId); - latestMuteStates.current!.video.setEnabled?.(true); - } - } - + defaultDeviceSetup(ev.detail.data as unknown as JoinCallData); enterRTCSession(rtcSession); - - PosthogAnalytics.instance.eventCallEnded.cacheStartCall(new Date()); - // we only have room sessions right now, so call ID is the emprty string - we use the room ID - PosthogAnalytics.instance.eventCallStarted.track( - rtcSession.room.roomId, - ); - await Promise.all([ widget!.api.setAlwaysOnScreen(true), widget!.api.transport.reply(ev.detail, {}), ]); }; - widget.lazyActions.on(ElementWidgetActions.JoinCall, onJoin); return () => { widget!.lazyActions.off(ElementWidgetActions.JoinCall, onJoin); }; + } else { + // if we don't use preload and only skipLobby we enter the rtc session right away + defaultDeviceSetup({ audioInput: null, videoInput: null }); + enterRTCSession(rtcSession); } - }, [rtcSession, preload]); + }, [rtcSession, preload, skipLobby]); const [left, setLeft] = useState(false); const [leaveError, setLeaveError] = useState(undefined); diff --git a/src/room/RoomPage.tsx b/src/room/RoomPage.tsx index 9bcb8a81..3ae11b50 100644 --- a/src/room/RoomPage.tsx +++ b/src/room/RoomPage.tsx @@ -31,8 +31,14 @@ import { platform } from "../Platform"; import { AppSelectionModal } from "./AppSelectionModal"; export const RoomPage: FC = () => { - const { confineToRoom, appPrompt, preload, hideHeader, displayName } = - useUrlParams(); + const { + confineToRoom, + appPrompt, + preload, + hideHeader, + displayName, + skipLobby, + } = useUrlParams(); const { roomAlias, roomId, viaServers } = useRoomIdentifier(); @@ -78,10 +84,11 @@ export const RoomPage: FC = () => { isPasswordlessUser={passwordlessUser} confineToRoom={confineToRoom} preload={preload} + skipLobby={skipLobby} hideHeader={hideHeader} /> ), - [client, passwordlessUser, confineToRoom, preload, hideHeader], + [client, passwordlessUser, confineToRoom, preload, hideHeader, skipLobby], ); let content: ReactNode;