From 797cb23cc7adb06111d4a3e3e1c8bdd7628aaa09 Mon Sep 17 00:00:00 2001 From: Bruno Windels <274386+bwindels@users.noreply.github.com> Date: Tue, 12 Apr 2022 14:02:13 +0200 Subject: [PATCH] implement receiving hangup, and retry on connection failure --- src/matrix/calls/PeerCall.ts | 16 +++++++++++++++- src/matrix/calls/group/Member.ts | 24 ++++++++++++++++++++++-- 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/src/matrix/calls/PeerCall.ts b/src/matrix/calls/PeerCall.ts index fc37807d..fa1063ec 100644 --- a/src/matrix/calls/PeerCall.ts +++ b/src/matrix/calls/PeerCall.ts @@ -86,6 +86,7 @@ export class PeerCall implements IDisposable { private iceDisconnectedTimeout?: Timeout; private _dataChannel?: any; + private _hangupReason?: CallErrorCode; constructor( private callId: string, @@ -138,6 +139,8 @@ export class PeerCall implements IDisposable { get state(): CallState { return this._state; } + get hangupReason(): CallErrorCode | undefined { return this._hangupReason; } + get remoteTracks(): Track[] { return this.peerConnection.remoteTracks; } @@ -374,6 +377,17 @@ export class PeerCall implements IDisposable { } } + private handleHangupReceived(content: MCallHangupReject, log: ILogItem) { + // party ID must match (our chosen partner hanging up the call) or be undefined (we haven't chosen + // a partner yet but we're treating the hangup as a reject as per VoIP v0) + // if (this.state === CallState.Ringing) { + // default reason is user_hangup + this.terminate(CallParty.Remote, content.reason || CallErrorCode.UserHangup, log); + // } else { + // log.set("ignored", true); + // } + }; + private async handleFirstInvite(content: MCallInvite, partyId: PartyId, log: ILogItem): Promise { if (this._state !== CallState.Fledgling || this.opponentPartyId !== undefined) { // TODO: hangup or ignore? @@ -789,7 +803,7 @@ export class PeerCall implements IDisposable { } this.hangupParty = hangupParty; - // this.hangupReason = hangupReason; + this._hangupReason = hangupReason; this.setState(CallState.Ended, log); //this.localMedia?.dispose(); //this.localMedia = undefined; diff --git a/src/matrix/calls/group/Member.ts b/src/matrix/calls/group/Member.ts index 3eb5f17f..0ac7df99 100644 --- a/src/matrix/calls/group/Member.ts +++ b/src/matrix/calls/group/Member.ts @@ -16,7 +16,7 @@ limitations under the License. import {PeerCall, CallState} from "../PeerCall"; import {makeTxnId, makeId} from "../../common"; -import {EventType} from "../callEventTypes"; +import {EventType, CallErrorCode} from "../callEventTypes"; import {formatToDeviceMessagesPayload} from "../../common"; import type {Options as PeerCallOptions} from "../PeerCall"; @@ -39,9 +39,19 @@ export type Options = Omit void, } +const errorCodesWithoutRetry = [ + CallErrorCode.UserHangup, + CallErrorCode.AnsweredElsewhere, + CallErrorCode.Replaced, + CallErrorCode.UserBusy, + CallErrorCode.Transfered, + CallErrorCode.NewSession +]; + export class Member { private peerCall?: PeerCall; private localMedia?: LocalMedia; + private retryCount: number = 0; constructor( public readonly member: RoomMember, @@ -109,6 +119,17 @@ export class Member { if (peerCall.state === CallState.Ringing) { peerCall.answer(this.localMedia!); } + else if (peerCall.state === CallState.Ended) { + const hangupReason = peerCall.hangupReason; + peerCall.dispose(); + this.peerCall = undefined; + if (hangupReason && !errorCodesWithoutRetry.includes(hangupReason)) { + this.retryCount += 1; + if (this.retryCount <= 3) { + this.connect(this.localMedia!); + } + } + } this.options.emitUpdate(this, params); } @@ -151,7 +172,6 @@ export class Member { this.peerCall = this._createPeerCall(message.content.call_id); } if (this.peerCall) { - const prevState = this.peerCall.state; this.peerCall.handleIncomingSignallingMessage(message, deviceId); } else { // TODO: need to buffer events until invite comes?