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 {