Add VoIP user mapper

The accompanying element-web PR with the config documentation should
explain what this is & why. Internally, this breaks the assumption
that call.roomId is the room that the call appears in for the user.
call.roomId may now be a 'virtual' room while the react SDK actually
displays it in a different room. React SDK always stores the calls
under the user-facing rooms, and provides a function to get the
user-facing room for a given call.
This commit is contained in:
David Baker
2021-01-21 19:20:35 +00:00
parent 604b9378ce
commit 0a90c982c7
8 changed files with 173 additions and 32 deletions
+33 -10
View File
@@ -83,6 +83,7 @@ import {UIFeature} from "./settings/UIFeature";
import { CallError } from "matrix-js-sdk/src/webrtc/call";
import { logger } from 'matrix-js-sdk/src/logger';
import { Action } from './dispatcher/actions';
import { roomForVirtualRoom, getOrCreateVirtualRoomForRoom } from './VoipUserMapper';
const CHECK_PSTN_SUPPORT_ATTEMPTS = 3;
@@ -133,6 +134,15 @@ export default class CallHandler {
return window.mxCallHandler;
}
/*
* Gets the user-facing room associated with a call (call.roomId may be the call "virtual room"
* if a voip_mxid_translate_pattern is set in the config)
*/
public static roomIdForCall(call: MatrixCall) {
if (!call) return null;
return roomForVirtualRoom(call.roomId) || call.roomId;
}
start() {
this.dispatcherRef = dis.register(this.onAction);
// add empty handlers for media actions, otherwise the media keys
@@ -284,11 +294,15 @@ export default class CallHandler {
// We don't allow placing more than one call per room, but that doesn't mean there
// can't be more than one, eg. in a glare situation. This checks that the given call
// is the call we consider 'the' call for its room.
const callForThisRoom = this.getCallForRoom(call.roomId);
const mappedRoomId = CallHandler.roomIdForCall(call);
const callForThisRoom = this.getCallForRoom(mappedRoomId);
return callForThisRoom && call.callId === callForThisRoom.callId;
}
private setCallListeners(call: MatrixCall) {
const mappedRoomId = CallHandler.roomIdForCall(call);
call.on(CallEvent.Error, (err: CallError) => {
if (!this.matchesCallForThisRoom(call)) return;
@@ -318,7 +332,7 @@ export default class CallHandler {
Analytics.trackEvent('voip', 'callHangup');
this.removeCallForRoom(call.roomId);
this.removeCallForRoom(mappedRoomId);
});
call.on(CallEvent.State, (newState: CallState, oldState: CallState) => {
if (!this.matchesCallForThisRoom(call)) return;
@@ -343,7 +357,7 @@ export default class CallHandler {
break;
case CallState.Ended:
Analytics.trackEvent('voip', 'callEnded', 'hangupReason', call.hangupReason);
this.removeCallForRoom(call.roomId);
this.removeCallForRoom(mappedRoomId);
if (oldState === CallState.InviteSent && (
call.hangupParty === CallParty.Remote ||
(call.hangupParty === CallParty.Local && call.hangupReason === CallErrorCode.InviteTimeout)
@@ -392,7 +406,7 @@ export default class CallHandler {
this.pause(AudioID.Ringback);
}
this.calls.set(newCall.roomId, newCall);
this.calls.set(mappedRoomId, newCall);
this.setCallListeners(newCall);
this.setCallState(newCall, newCall.state);
});
@@ -404,13 +418,15 @@ export default class CallHandler {
}
private setCallState(call: MatrixCall, status: CallState) {
const mappedRoomId = CallHandler.roomIdForCall(call);
console.log(
`Call state in ${call.roomId} changed to ${status}`,
`Call state in ${mappedRoomId} changed to ${status}`,
);
dis.dispatch({
action: 'call_state',
room_id: call.roomId,
room_id: mappedRoomId,
state: status,
});
}
@@ -477,14 +493,20 @@ export default class CallHandler {
}, null, true);
}
private placeCall(
private async placeCall(
roomId: string, type: PlaceCallType,
localElement: HTMLVideoElement, remoteElement: HTMLVideoElement,
) {
Analytics.trackEvent('voip', 'placeCall', 'type', type);
CountlyAnalytics.instance.trackStartCall(roomId, type === PlaceCallType.Video, false);
const call = createNewMatrixCall(MatrixClientPeg.get(), roomId);
const mappedRoomId = (await getOrCreateVirtualRoomForRoom(roomId)) || roomId;
logger.debug("Mapped real room " + roomId + " to room ID " + mappedRoomId);
const call = createNewMatrixCall(MatrixClientPeg.get(), mappedRoomId);
this.calls.set(roomId, call);
this.setCallListeners(call);
this.setCallAudioElement(call);
@@ -586,13 +608,14 @@ export default class CallHandler {
const call = payload.call as MatrixCall;
if (this.getCallForRoom(call.roomId)) {
const mappedRoomId = CallHandler.roomIdForCall(call);
if (this.getCallForRoom(mappedRoomId)) {
// ignore multiple incoming calls to the same room
return;
}
Analytics.trackEvent('voip', 'receiveCall', 'type', call.type);
this.calls.set(call.roomId, call)
this.calls.set(mappedRoomId, call)
this.setCallListeners(call);
}
break;