1
0
mirror of https://github.com/matrix-org/matrix-js-sdk.git synced 2025-11-28 05:03:59 +03:00

Merge pull request #1503 from matrix-org/dbkr/call_state_machine

Fixes for call state machine
This commit is contained in:
David Baker
2020-10-13 10:39:10 +01:00
committed by GitHub

View File

@@ -85,6 +85,13 @@ export enum CallParty {
Remote = 'remote', Remote = 'remote',
} }
export enum CallEvent {
Hangup = 'hangup',
State = 'state',
Error = 'error',
Replaced = 'replaced',
}
enum MediaQueueId { enum MediaQueueId {
RemoteVideo = 'remote_video', RemoteVideo = 'remote_video',
RemoteAudio = 'remote_audio', RemoteAudio = 'remote_audio',
@@ -92,6 +99,9 @@ enum MediaQueueId {
} }
export enum CallErrorCode { export enum CallErrorCode {
/** The user chose to end the call */
UserHangup = 'user_hangup',
/** An error code when the local client failed to create an offer. */ /** An error code when the local client failed to create an offer. */
LocalOfferFailed = 'local_offer_failed', LocalOfferFailed = 'local_offer_failed',
/** /**
@@ -297,7 +307,7 @@ export class MatrixCall extends EventEmitter {
const audioConstraints = getUserMediaVideoContraints(CallType.Voice); const audioConstraints = getUserMediaVideoContraints(CallType.Voice);
this.placeCallWithConstraints(audioConstraints); this.placeCallWithConstraints(audioConstraints);
} catch (err) { } catch (err) {
this.emit("error", this.emit(CallEvent.Error,
new CallError( new CallError(
CallErrorCode.NoUserMedia, CallErrorCode.NoUserMedia,
"Failed to get screen-sharing stream: ", err, "Failed to get screen-sharing stream: ", err,
@@ -440,7 +450,7 @@ export class MatrixCall extends EventEmitter {
if (this.peerConn.signalingState != 'closed') { if (this.peerConn.signalingState != 'closed') {
this.peerConn.close(); this.peerConn.close();
} }
this.emit("hangup"); this.emit(CallEvent.Hangup);
} }
}, this.msg.lifetime - event.getLocalAge()); }, this.msg.lifetime - event.getLocalAge());
} }
@@ -511,7 +521,7 @@ export class MatrixCall extends EventEmitter {
newCall.remoteVideoElement = this.remoteVideoElement; newCall.remoteVideoElement = this.remoteVideoElement;
newCall.remoteAudioElement = this.remoteAudioElement; newCall.remoteAudioElement = this.remoteAudioElement;
this.successor = newCall; this.successor = newCall;
this.emit("replaced", newCall); this.emit(CallEvent.Replaced, newCall);
this.hangup(CallErrorCode.Replaced, true); this.hangup(CallErrorCode.Replaced, true);
} }
@@ -528,8 +538,10 @@ export class MatrixCall extends EventEmitter {
const content = { const content = {
version: 0, version: 0,
call_id: this.callId, call_id: this.callId,
reason: reason,
}; };
// Continue to send no reason for user hangups temporarily, until
// clients understand the user_hangup reason (voip v1)
if (reason !== CallErrorCode.UserHangup) content['reason'] = reason;
this.sendEvent('m.call.hangup', content); this.sendEvent('m.call.hangup', content);
} }
@@ -642,8 +654,8 @@ export class MatrixCall extends EventEmitter {
}; };
private sendAnswer() { private sendAnswer() {
this.setState(CallState.Connecting);
this.sendEvent('m.call.answer', this.answerContent).then(() => { this.sendEvent('m.call.answer', this.answerContent).then(() => {
this.setState(CallState.Connecting);
// If this isn't the first time we've tried to send the answer, // If this isn't the first time we've tried to send the answer,
// we may have candidates queued up, so send them now. // we may have candidates queued up, so send them now.
this.sendCandidateQueue(); this.sendCandidateQueue();
@@ -658,7 +670,7 @@ export class MatrixCall extends EventEmitter {
code = CallErrorCode.UnknownDevices; code = CallErrorCode.UnknownDevices;
message = "Unknown devices present in the room"; message = "Unknown devices present in the room";
} }
this.emit("error", new CallError(code, message, error)); this.emit(CallEvent.Error, new CallError(code, message, error));
throw error; throw error;
}); });
} }
@@ -854,7 +866,7 @@ export class MatrixCall extends EventEmitter {
this.client.cancelPendingEvent(error.event); this.client.cancelPendingEvent(error.event);
this.terminate(CallParty.Local, code, false); this.terminate(CallParty.Local, code, false);
this.emit("error", new CallError(code, message, error)); this.emit(CallEvent.Error, new CallError(code, message, error));
} }
}; };
@@ -863,7 +875,7 @@ export class MatrixCall extends EventEmitter {
this.terminate(CallParty.Local, CallErrorCode.LocalOfferFailed, false); this.terminate(CallParty.Local, CallErrorCode.LocalOfferFailed, false);
this.emit( this.emit(
"error", CallEvent.Error,
new CallError( new CallError(
CallErrorCode.LocalOfferFailed, CallErrorCode.LocalOfferFailed,
"Failed to get local offer!", err, "Failed to get local offer!", err,
@@ -879,7 +891,7 @@ export class MatrixCall extends EventEmitter {
this.terminate(CallParty.Local, CallErrorCode.NoUserMedia, false); this.terminate(CallParty.Local, CallErrorCode.NoUserMedia, false);
this.emit( this.emit(
"error", CallEvent.Error,
new CallError( new CallError(
CallErrorCode.NoUserMedia, CallErrorCode.NoUserMedia,
"Couldn't start capturing media! Is your microphone set up and " + "Couldn't start capturing media! Is your microphone set up and " +
@@ -893,12 +905,11 @@ export class MatrixCall extends EventEmitter {
return; // because ICE can still complete as we're ending the call return; // because ICE can still complete as we're ending the call
} }
logger.debug( logger.debug(
"Ice connection state changed to: " + this.peerConn.iceConnectionState, "ICE connection state changed to: " + this.peerConn.iceConnectionState,
); );
// ideally we'd consider the call to be connected when we get media but // ideally we'd consider the call to be connected when we get media but
// chrome doesn't implement any of the 'onstarted' events yet // chrome doesn't implement any of the 'onstarted' events yet
if (this.peerConn.iceConnectionState == 'completed' || if (this.peerConn.iceConnectionState == 'connected') {
this.peerConn.iceConnectionState == 'connected') {
this.setState(CallState.Connected); this.setState(CallState.Connected);
} else if (this.peerConn.iceConnectionState == 'failed') { } else if (this.peerConn.iceConnectionState == 'failed') {
this.hangup(CallErrorCode.IceFailed, false); this.hangup(CallErrorCode.IceFailed, false);
@@ -1004,7 +1015,7 @@ export class MatrixCall extends EventEmitter {
setState(state: CallState) { setState(state: CallState) {
const oldState = this.state; const oldState = this.state;
this.state = state; this.state = state;
this.emit("state", state, oldState); this.emit(CallEvent.State, state, oldState);
} }
/** /**
@@ -1075,7 +1086,7 @@ export class MatrixCall extends EventEmitter {
this.peerConn.close(); this.peerConn.close();
} }
if (shouldEmit) { if (shouldEmit) {
this.emit("hangup", self); this.emit(CallEvent.Hangup, self);
} }
} }
@@ -1092,8 +1103,10 @@ export class MatrixCall extends EventEmitter {
} }
} }
for (const track of this.remoteStream.getTracks()) { if (this.remoteStream) {
track.stop(); for (const track of this.remoteStream.getTracks()) {
track.stop();
}
} }
} }
@@ -1167,6 +1180,7 @@ export class MatrixCall extends EventEmitter {
iceServers: this.turnServers, iceServers: this.turnServers,
}); });
// 'connectionstatechange' would be better, but firefox doesn't implement that.
pc.addEventListener('iceconnectionstatechange', this.onIceConnectionStateChanged); pc.addEventListener('iceconnectionstatechange', this.onIceConnectionStateChanged);
pc.addEventListener('signalingstatechange', this.onSignallingStateChanged); pc.addEventListener('signalingstatechange', this.onSignallingStateChanged);
pc.addEventListener('icecandidate', this.gotLocalIceCandidate); pc.addEventListener('icecandidate', this.gotLocalIceCandidate);