1
0
mirror of https://github.com/matrix-org/matrix-react-sdk.git synced 2025-11-05 23:10:41 +03:00

Line 1 / 2 Support

Support one active call plus one call on hold
This commit is contained in:
David Baker
2020-12-03 17:45:49 +00:00
parent 31044b68d1
commit 1ce63f0fa7
8 changed files with 468 additions and 234 deletions

View File

@@ -81,6 +81,7 @@ import Analytics from './Analytics';
import CountlyAnalytics from "./CountlyAnalytics";
import {UIFeature} from "./settings/UIFeature";
import { CallError } from "matrix-js-sdk/src/webrtc/call";
import { logger } from 'matrix-js-sdk/src/logger';
enum AudioID {
Ring = 'ringAudio',
@@ -115,7 +116,7 @@ function getRemoteAudioElement(): HTMLAudioElement {
}
export default class CallHandler {
private calls = new Map<string, MatrixCall>();
private calls = new Map<string, MatrixCall>(); // roomId -> call
private audioPromises = new Map<AudioID, Promise<void>>();
static sharedInstance() {
@@ -175,6 +176,28 @@ export default class CallHandler {
return null;
}
getAllActiveCalls() {
const activeCalls = [];
for (const call of this.calls.values()) {
if (call.state !== CallState.Ended && call.state !== CallState.Ringing) {
activeCalls.push(call);
}
}
return activeCalls;
}
getAllActiveCallsNotInRoom(notInThisRoomId) {
const callsNotInThatRoom = [];
for (const [roomId, call] of this.calls.entries()) {
if (roomId !== notInThisRoomId && call.state !== CallState.Ended) {
callsNotInThatRoom.push(call);
}
}
return callsNotInThatRoom;
}
play(audioId: AudioID) {
// TODO: Attach an invisible element for this instead
// which listens?
@@ -425,6 +448,8 @@ export default class CallHandler {
this.setCallListeners(call);
this.setCallAudioElement(call);
this.setActiveCallRoomId(roomId);
if (type === PlaceCallType.Voice) {
call.placeVoiceCall();
} else if (type === 'video') {
@@ -453,14 +478,6 @@ export default class CallHandler {
switch (payload.action) {
case 'place_call':
{
if (this.getAnyActiveCall()) {
Modal.createTrackedDialog('Call Handler', 'Existing Call', ErrorDialog, {
title: _t('Existing Call'),
description: _t('You are already in a call.'),
});
return; // don't allow >1 call to be placed.
}
// if the runtime env doesn't do VoIP, whine.
if (!MatrixClientPeg.get().supportsVoip()) {
Modal.createTrackedDialog('Call Handler', 'VoIP is unsupported', ErrorDialog, {
@@ -470,6 +487,15 @@ export default class CallHandler {
return;
}
// don't allow > 2 calls to be placed.
if (this.getAllActiveCalls().length > 1) {
Modal.createTrackedDialog('Call Handler', 'Existing Call', ErrorDialog, {
title: _t('Too Many Calls'),
description: _t("You've reached the maximum number of simultaneous calls."),
});
return;
}
const room = MatrixClientPeg.get().getRoom(payload.room_id);
if (!room) {
console.error("Room %s does not exist.", payload.room_id);
@@ -513,24 +539,21 @@ export default class CallHandler {
break;
case 'incoming_call':
{
if (this.getAnyActiveCall()) {
// ignore multiple incoming calls. in future, we may want a line-1/line-2 setup.
// we avoid rejecting with "busy" in case the user wants to answer it on a different device.
// in future we could signal a "local busy" as a warning to the caller.
// see https://github.com/vector-im/vector-web/issues/1964
return;
}
// if the runtime env doesn't do VoIP, stop here.
if (!MatrixClientPeg.get().supportsVoip()) {
return;
}
const call = payload.call as MatrixCall;
if (this.getCallForRoom(call.roomId)) {
// ignore multiple incoming calls to the same room
return;
}
Analytics.trackEvent('voip', 'receiveCall', 'type', call.type);
this.calls.set(call.roomId, call)
this.setCallListeners(call);
this.setCallAudioElement(call);
}
break;
case 'hangup':
@@ -549,8 +572,19 @@ export default class CallHandler {
if (!this.calls.has(payload.room_id)) {
return; // no call to answer
}
if (this.getAllActiveCalls().length > 1) {
Modal.createTrackedDialog('Call Handler', 'Existing Call', ErrorDialog, {
title: _t('Too Many Calls'),
description: _t("You've reached the maximum number of simultaneous calls."),
});
return;
}
const call = this.calls.get(payload.room_id);
call.answer();
this.setCallAudioElement(call);
this.setActiveCallRoomId(payload.room_id);
CountlyAnalytics.instance.trackJoinCall(payload.room_id, call.type === CallType.Video, false);
dis.dispatch({
action: "view_room",
@@ -561,6 +595,21 @@ export default class CallHandler {
}
}
setActiveCallRoomId(activeCallRoomId: string) {
logger.info("Setting call in room " + activeCallRoomId + " active");
for (const [roomId, call] of this.calls.entries()) {
if (call.state === CallState.Ended) continue;
if (roomId === activeCallRoomId) {
call.setRemoteOnHold(false);
} else {
logger.info("Holding call in room " + roomId + " because another call is being set active");
call.setRemoteOnHold(true);
}
}
}
private async startCallApp(roomId: string, type: string) {
dis.dispatch({
action: 'appsDrawer',