From 1c7a55513eb8bdc6eed86994662b98f931e74a2b Mon Sep 17 00:00:00 2001 From: David Baker Date: Fri, 28 Jul 2023 22:31:46 +0100 Subject: [PATCH] Switch to new group call if the call in a room changes This PR comes with a lot of caveats currently: * It removes the leaveCall() from when the useGroupCall() hook is torn down. I can't see another way of maintaining the correct joined state (because switching group calls will cause the effects to re-run) but this does mean that if the user somehow navigates within the app without using the hangup button, they won't leave the call. * The state of the call will be reset on switch, including the state of the screenshare, what devices are being used and even the mute states. Unsure if it's better to try & fix these up by moving state around or whether to refactor more in js-sdk so the group call can be switched more transparently. --- src/room/useGroupCall.ts | 24 +++++++++++++++++------- src/room/useLoadGroupCall.ts | 14 +++++++++++++- 2 files changed, 30 insertions(+), 8 deletions(-) diff --git a/src/room/useGroupCall.ts b/src/room/useGroupCall.ts index b02e7113..75882cc0 100644 --- a/src/room/useGroupCall.ts +++ b/src/room/useGroupCall.ts @@ -94,6 +94,8 @@ interface State { requestingScreenshare: boolean; participants: Map>; hasLocalParticipant: boolean; + // whether we think we should be joined to the call (irrespective of whether or not we actually are) + joined: boolean; } // This is a bit of a hack, but we keep the opentelemetry tracker object at the file @@ -161,6 +163,7 @@ export function useGroupCall( participants, hasLocalParticipant, requestingScreenshare, + joined, }, setState, ] = useState({ @@ -173,6 +176,7 @@ export function useGroupCall( requestingScreenshare: false, participants: getParticipants(groupCall), hasLocalParticipant: false, + joined: false, }); if (groupCallOTelMembershipGroupCallId !== groupCall.groupCallId) { @@ -208,7 +212,8 @@ export function useGroupCall( const leaveCall = useCallback(() => { groupCallOTelMembership?.onLeaveCall(); groupCall.leave(); - }, [groupCall]); + updateState({ joined: false }); + }, [groupCall, updateState]); useEffect(() => { // disable the media action keys, otherwise audio elements get paused when @@ -238,6 +243,15 @@ export function useGroupCall( }, [doNothingMediaActionCallback]); useEffect(() => { + if (joined && groupCall.state !== GroupCallState.Entered) { + groupCall.enter().catch((error) => { + console.error(error); + updateState({ error }); + }); + } else if (!joined && groupCall.state === GroupCallState.Entered) { + groupCall.leave(); + } + function onGroupCallStateChanged() { updateState({ state: groupCall.state, @@ -462,9 +476,8 @@ export function useGroupCall( RoomStateEvent.Update, checkForParallelCalls ); - leaveCall(); }; - }, [groupCall, updateState, leaveCall]); + }, [groupCall, updateState, leaveCall, joined]); usePageUnload(() => { leaveCall(); @@ -490,10 +503,7 @@ export function useGroupCall( // have started tracking by the time calls start getting created. groupCallOTelMembership?.onJoinCall(); - await groupCall.enter().catch((error) => { - console.error(error); - updateState({ error }); - }); + updateState({ joined: true }); }, [groupCall, updateState]); const toggleLocalVideoMuted = useCallback(() => { diff --git a/src/room/useLoadGroupCall.ts b/src/room/useLoadGroupCall.ts index 4aa82f11..ee123fca 100644 --- a/src/room/useLoadGroupCall.ts +++ b/src/room/useLoadGroupCall.ts @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { useState, useEffect } from "react"; +import { useState, useEffect, useCallback } from "react"; import { EventType } from "matrix-js-sdk/src/@types/event"; import { GroupCallType, @@ -31,6 +31,7 @@ import type { GroupCall } from "matrix-js-sdk/src/webrtc/groupCall"; import { isLocalRoomId, createRoom, roomNameFromRoomId } from "../matrix-utils"; import { translatedError } from "../TranslatedError"; import { widget } from "../widget"; +import { useTypedEventEmitter } from "../useEvents"; const STATS_COLLECT_INTERVAL_TIME_MS = 10000; @@ -67,6 +68,17 @@ export const useLoadGroupCall = ( const { t } = useTranslation(); const [state, setState] = useState({ kind: "loading" }); + const onGroupCallIncoming = useCallback((groupCall: GroupCall) => { + // update if a new group call arrives for this room + setState({ kind: "loaded", groupCall }); + }, []); + + useTypedEventEmitter( + client, + GroupCallEventHandlerEvent.Incoming, + onGroupCallIncoming + ); + useEffect(() => { const fetchOrCreateRoom = async (): Promise => { try {