diff --git a/src/room/PTTCallView.tsx b/src/room/PTTCallView.tsx index 4b395f8..12157d2 100644 --- a/src/room/PTTCallView.tsx +++ b/src/room/PTTCallView.tsx @@ -44,8 +44,11 @@ function getPromptText( activeSpeakerIsLocalUser: boolean, talkOverEnabled: boolean, activeSpeakerUserId: string, - activeSpeakerDisplayName: string + activeSpeakerDisplayName: string, + connected: boolean ): string { + if (!connected) return "Connection Lost"; + const isTouchScreen = Boolean(window.ontouchstart !== undefined); if (showTalkOverError) { @@ -127,6 +130,7 @@ export const PTTCallView: React.FC = ({ startTalking, stopTalking, transmitBlocked, + connected, } = usePTT( client, groupCall, @@ -234,7 +238,8 @@ export const PTTCallView: React.FC = ({ activeSpeakerIsLocalUser, talkOverEnabled, activeSpeakerUserId, - activeSpeakerDisplayName + activeSpeakerDisplayName, + connected )}

{userMediaFeeds.map((callFeed) => ( diff --git a/src/room/usePTT.ts b/src/room/usePTT.ts index 3446ff6..e677e9a 100644 --- a/src/room/usePTT.ts +++ b/src/room/usePTT.ts @@ -15,10 +15,11 @@ limitations under the License. */ import { useCallback, useEffect, useState } from "react"; -import { MatrixClient } from "matrix-js-sdk/src/client"; +import { MatrixClient, ClientEvent } from "matrix-js-sdk/src/client"; import { GroupCall } from "matrix-js-sdk/src/webrtc/groupCall"; import { CallFeed, CallFeedEvent } from "matrix-js-sdk/src/webrtc/callFeed"; import { logger } from "matrix-js-sdk/src/logger"; +import { SyncState } from "matrix-js-sdk/src/sync"; import { PlayClipFunction, PTTClipID } from "../sound/usePttSounds"; @@ -67,6 +68,11 @@ export interface PTTState { startTalking: () => void; stopTalking: () => void; transmitBlocked: boolean; + // connected is actually an indication of whether we're connected to the HS + // (ie. the client's syncing state) rather than media connection, since + // it's peer to peer so we can't really say which peer is 'disconnected' if + // there's only one other person in the call and they've lost Internet. + connected: boolean; } export const usePTT = ( @@ -226,6 +232,17 @@ export const usePTT = ( setMicMuteWrapper(true); }, [setMicMuteWrapper]); + // separate state for connected: we set it separately from other things + // in the client sync callback + const [connected, setConnected] = useState(true); + + const onClientSync = useCallback( + (syncState: SyncState) => { + setConnected(syncState !== SyncState.Error); + }, + [setConnected] + ); + useEffect(() => { function onKeyDown(event: KeyboardEvent): void { if (event.code === "Space") { @@ -275,8 +292,18 @@ export const usePTT = ( pttButtonHeld, enablePTTButton, setMicMuteWrapper, + client, + onClientSync, ]); + useEffect(() => { + client.on(ClientEvent.Sync, onClientSync); + + return () => { + client.removeListener(ClientEvent.Sync, onClientSync); + }; + }, [client, onClientSync]); + const setTalkOverEnabled = useCallback((talkOverEnabled) => { setState((prevState) => ({ ...prevState, @@ -293,5 +320,6 @@ export const usePTT = ( startTalking, stopTalking, transmitBlocked, + connected, }; };