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.
This commit is contained in:
David Baker
2023-07-28 22:31:46 +01:00
parent f0c22c429d
commit 1c7a55513e
2 changed files with 30 additions and 8 deletions

View File

@@ -94,6 +94,8 @@ interface State {
requestingScreenshare: boolean;
participants: Map<RoomMember, Map<string, ParticipantInfo>>;
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<State>({
@@ -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(() => {

View File

@@ -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<GroupCallStatus>({ 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<Room> => {
try {