You've already forked matrix-js-sdk
mirror of
https://github.com/matrix-org/matrix-js-sdk.git
synced 2025-07-31 15:24:23 +03:00
Refactor the way group calls hang up (#3234)
* Refactor how group call end calls We previously used disposeCall to terminate the call which meant that sometimes a call would never get a hangup event. This changes it so that we always end a call by calling hangup, then do the cleanup when the hangup event arrives, so the cleanup is the same whether we hang up or the other side does. * Some fixes for failing & hanging tests * Add type for the call map
This commit is contained in:
@ -511,6 +511,8 @@ export class MockMatrixCall extends TypedEventEmitter<CallEvent, CallEventHandle
|
|||||||
public callId = "1";
|
public callId = "1";
|
||||||
public localUsermediaFeed = {
|
public localUsermediaFeed = {
|
||||||
setAudioVideoMuted: jest.fn<void, [boolean, boolean]>(),
|
setAudioVideoMuted: jest.fn<void, [boolean, boolean]>(),
|
||||||
|
isAudioMuted: jest.fn().mockReturnValue(false),
|
||||||
|
isVideoMuted: jest.fn().mockReturnValue(false),
|
||||||
stream: new MockMediaStream("stream"),
|
stream: new MockMediaStream("stream"),
|
||||||
} as unknown as CallFeed;
|
} as unknown as CallFeed;
|
||||||
public remoteUsermediaFeed?: CallFeed;
|
public remoteUsermediaFeed?: CallFeed;
|
||||||
|
@ -144,6 +144,10 @@ describe("Group Call", function () {
|
|||||||
} as unknown as RoomMember;
|
} as unknown as RoomMember;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
groupCall.leave();
|
||||||
|
});
|
||||||
|
|
||||||
it.each(Object.values(GroupCallState).filter((v) => v !== GroupCallState.LocalCallFeedUninitialized))(
|
it.each(Object.values(GroupCallState).filter((v) => v !== GroupCallState.LocalCallFeedUninitialized))(
|
||||||
"throws when initializing local call feed in %s state",
|
"throws when initializing local call feed in %s state",
|
||||||
async (state: GroupCallState) => {
|
async (state: GroupCallState) => {
|
||||||
|
@ -42,6 +42,8 @@ export enum GroupCallTerminationReason {
|
|||||||
CallEnded = "call_ended",
|
CallEnded = "call_ended",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type CallsByUserAndDevice = Map<string, Map<string, MatrixCall>>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Because event names are just strings, they do need
|
* Because event names are just strings, they do need
|
||||||
* to be unique over all event types of event emitter.
|
* to be unique over all event types of event emitter.
|
||||||
@ -62,7 +64,7 @@ export enum GroupCallEvent {
|
|||||||
export type GroupCallEventHandlerMap = {
|
export type GroupCallEventHandlerMap = {
|
||||||
[GroupCallEvent.GroupCallStateChanged]: (newState: GroupCallState, oldState: GroupCallState) => void;
|
[GroupCallEvent.GroupCallStateChanged]: (newState: GroupCallState, oldState: GroupCallState) => void;
|
||||||
[GroupCallEvent.ActiveSpeakerChanged]: (activeSpeaker: CallFeed | undefined) => void;
|
[GroupCallEvent.ActiveSpeakerChanged]: (activeSpeaker: CallFeed | undefined) => void;
|
||||||
[GroupCallEvent.CallsChanged]: (calls: Map<string, Map<string, MatrixCall>>) => void;
|
[GroupCallEvent.CallsChanged]: (calls: CallsByUserAndDevice) => void;
|
||||||
[GroupCallEvent.UserMediaFeedsChanged]: (feeds: CallFeed[]) => void;
|
[GroupCallEvent.UserMediaFeedsChanged]: (feeds: CallFeed[]) => void;
|
||||||
[GroupCallEvent.ScreenshareFeedsChanged]: (feeds: CallFeed[]) => void;
|
[GroupCallEvent.ScreenshareFeedsChanged]: (feeds: CallFeed[]) => void;
|
||||||
[GroupCallEvent.LocalScreenshareStateChanged]: (
|
[GroupCallEvent.LocalScreenshareStateChanged]: (
|
||||||
@ -528,12 +530,16 @@ export class GroupCall extends TypedEventEmitter<
|
|||||||
this.retryCallLoopInterval = undefined;
|
this.retryCallLoopInterval = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.participantsExpirationTimer !== null) {
|
||||||
|
clearTimeout(this.participantsExpirationTimer);
|
||||||
|
this.participantsExpirationTimer = null;
|
||||||
|
}
|
||||||
|
|
||||||
if (this.state !== GroupCallState.Entered) {
|
if (this.state !== GroupCallState.Entered) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.forEachCall((call) => this.disposeCall(call, CallErrorCode.UserHangup));
|
this.forEachCall((call) => call.hangup(CallErrorCode.UserHangup, false));
|
||||||
this.calls.clear();
|
|
||||||
|
|
||||||
this.activeSpeaker = undefined;
|
this.activeSpeaker = undefined;
|
||||||
clearInterval(this.activeSpeakerLoopInterval);
|
clearInterval(this.activeSpeakerLoopInterval);
|
||||||
@ -869,7 +875,8 @@ export class GroupCall extends TypedEventEmitter<
|
|||||||
`GroupCall ${this.groupCallId} onIncomingCall() incoming call (userId=${opponentUserId}, callId=${newCall.callId})`,
|
`GroupCall ${this.groupCallId} onIncomingCall() incoming call (userId=${opponentUserId}, callId=${newCall.callId})`,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (prevCall) this.disposeCall(prevCall, CallErrorCode.Replaced);
|
if (prevCall) prevCall.hangup(CallErrorCode.Replaced, false);
|
||||||
|
|
||||||
this.initCall(newCall);
|
this.initCall(newCall);
|
||||||
|
|
||||||
const feeds = this.getLocalFeeds().map((feed) => feed.clone());
|
const feeds = this.getLocalFeeds().map((feed) => feed.clone());
|
||||||
@ -928,7 +935,7 @@ export class GroupCall extends TypedEventEmitter<
|
|||||||
logger.debug(
|
logger.debug(
|
||||||
`GroupCall ${this.groupCallId} placeOutgoingCalls() replacing call (userId=${userId}, deviceId=${deviceId}, callId=${prevCall.callId})`,
|
`GroupCall ${this.groupCallId} placeOutgoingCalls() replacing call (userId=${userId}, deviceId=${deviceId}, callId=${prevCall.callId})`,
|
||||||
);
|
);
|
||||||
this.disposeCall(prevCall, CallErrorCode.NewSession);
|
prevCall.hangup(CallErrorCode.NewSession, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
const newCall = createNewMatrixCall(this.client, this.room.roomId, {
|
const newCall = createNewMatrixCall(this.client, this.room.roomId, {
|
||||||
@ -979,7 +986,7 @@ export class GroupCall extends TypedEventEmitter<
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.disposeCall(newCall, CallErrorCode.SignallingFailed);
|
newCall.hangup(CallErrorCode.SignallingFailed, false);
|
||||||
if (callMap.get(deviceId) === newCall) callMap.delete(deviceId);
|
if (callMap.get(deviceId) === newCall) callMap.delete(deviceId);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -1101,10 +1108,6 @@ export class GroupCall extends TypedEventEmitter<
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (call.state !== CallState.Ended) {
|
|
||||||
call.hangup(hangupReason, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
const usermediaFeed = this.getUserMediaFeed(opponentMemberId, opponentDeviceId);
|
const usermediaFeed = this.getUserMediaFeed(opponentMemberId, opponentDeviceId);
|
||||||
|
|
||||||
if (usermediaFeed) {
|
if (usermediaFeed) {
|
||||||
@ -1156,6 +1159,8 @@ export class GroupCall extends TypedEventEmitter<
|
|||||||
};
|
};
|
||||||
|
|
||||||
private onCallStateChanged = (call: MatrixCall, state: CallState, _oldState: CallState | undefined): void => {
|
private onCallStateChanged = (call: MatrixCall, state: CallState, _oldState: CallState | undefined): void => {
|
||||||
|
if (state === CallState.Ended) return;
|
||||||
|
|
||||||
const audioMuted = this.localCallFeed!.isAudioMuted();
|
const audioMuted = this.localCallFeed!.isAudioMuted();
|
||||||
|
|
||||||
if (call.localUsermediaStream && call.isMicrophoneMuted() !== audioMuted) {
|
if (call.localUsermediaStream && call.isMicrophoneMuted() !== audioMuted) {
|
||||||
@ -1200,7 +1205,7 @@ export class GroupCall extends TypedEventEmitter<
|
|||||||
this.calls.set(opponentUserId, deviceMap);
|
this.calls.set(opponentUserId, deviceMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.disposeCall(prevCall, CallErrorCode.Replaced);
|
prevCall.hangup(CallErrorCode.Replaced, false);
|
||||||
this.initCall(newCall);
|
this.initCall(newCall);
|
||||||
deviceMap.set(prevCall.getOpponentDeviceId()!, newCall);
|
deviceMap.set(prevCall.getOpponentDeviceId()!, newCall);
|
||||||
this.emit(GroupCallEvent.CallsChanged, this.calls);
|
this.emit(GroupCallEvent.CallsChanged, this.calls);
|
||||||
|
Reference in New Issue
Block a user