1
0
mirror of https://github.com/matrix-org/matrix-js-sdk.git synced 2025-11-26 17:03:12 +03:00

Merge pull request #575 from matrix-org/dbkr/udd_no_auto_show

Supporting fixes For making UnknownDeviceDialog not pop up automatically
This commit is contained in:
David Baker
2017-12-08 16:33:18 +00:00
committed by GitHub
2 changed files with 87 additions and 41 deletions

View File

@@ -1137,6 +1137,9 @@ function _sendEvent(client, room, event, callback) {
try {
_updatePendingEventStatus(room, event, EventStatus.NOT_SENT);
event.error = err;
// also put the event object on the error: the caller will need this
// to resend or cancel the event
err.event = event;
if (callback) {
callback(err);

View File

@@ -1,5 +1,6 @@
/*
Copyright 2015, 2016 OpenMarket Ltd
Copyright 2017 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -24,31 +25,6 @@ const DEBUG = true; // set true to enable console logging.
// events: hangup, error(err), replaced(call), state(state, oldState)
/**
* Fires when the MatrixCall encounters an error when sending a Matrix event.
* <p>
* This is required to allow errors, which occur during sending of events, to bubble up.
* (This is because call.js does a hangup when it encounters a normal `error`, which in
* turn could lead to an UnknownDeviceError.)
* <p>
* To deal with an UnknownDeviceError when trying to send events, the application should let
* users know that there are new devices in the encrypted room (into which the event was
* sent) and give the user the options to resend unsent events or cancel them. Resending
* is done using {@link module:client~MatrixClient#resendEvent} and cancelling can be done by using
* {@link module:client~MatrixClient#cancelPendingEvent}.
* <p>
* MatrixCall will not do anything in response to an error that causes `send_event_error`
* to be emitted with the exception of sending `m.call.candidates`, which is retried upon
* failure when ICE candidates are being sent. This happens during call setup.
*
* @event module:webrtc/call~MatrixCall#"send_event_error"
* @param {Error} err The error caught from calling client.sendEvent in call.js.
* @example
* matrixCall.on("send_event_error", function(err){
* console.error(err);
* });
*/
/**
* Fires whenever an error occurs when call.js encounters an issue with setting up the call.
* <p>
@@ -110,6 +86,8 @@ function MatrixCall(opts) {
this.mediaPromises = Object.create(null);
this.screenSharingStream = null;
this._answerContent = null;
}
/** The length of time a call can be ringing for. */
MatrixCall.CALL_TIMEOUT_MS = 60000;
@@ -123,6 +101,24 @@ MatrixCall.ERR_LOCAL_OFFER_FAILED = "local_offer_failed";
*/
MatrixCall.ERR_NO_USER_MEDIA = "no_user_media";
/*
* Error code used when a call event failed to send
* because unknown devices were present in the room
*/
MatrixCall.ERR_UNKNOWN_DEVICES = "unknown_devices";
/*
* Error code usewd when we fail to send the invite
* for some reason other than there being unknown devices
*/
MatrixCall.ERR_SEND_INVITE = "send_invite";
/*
* Error code usewd when we fail to send the answer
* for some reason other than there being unknown devices
*/
MatrixCall.ERR_SEND_ANSWER = "send_answer";
utils.inherits(MatrixCall, EventEmitter);
/**
@@ -409,6 +405,11 @@ MatrixCall.prototype.answer = function() {
debuglog("Answering call %s of type %s", this.callId, this.type);
const self = this;
if (self._answerContent) {
self._sendAnswer();
return;
}
if (!this.localAVStream && !this.waitForLocalAVStream) {
this.webRtc.getUserMedia(
_getUserMediaVideoContraints(this.type),
@@ -457,6 +458,8 @@ MatrixCall.prototype._replacedBy = function(newCall) {
* @param {boolean} suppressEvent True to suppress emitting an event.
*/
MatrixCall.prototype.hangup = function(reason, suppressEvent) {
if (this.state == 'ended') return;
debuglog("Ending call " + this.callId);
terminate(this, "local", reason, !suppressEvent);
const content = {
@@ -593,6 +596,28 @@ MatrixCall.prototype._maybeGotUserMediaForInvite = function(stream) {
setState(self, 'create_offer');
};
MatrixCall.prototype._sendAnswer = function(stream) {
sendEvent(this, 'm.call.answer', this._answerContent).then(() => {
setState(this, 'connecting');
// If this isn't the first time we've tried to send the answer,
// we may have candidates queued up, so send them now.
_sendCandidateQueue(this);
}).catch((error) => {
// We've failed to answer: back to the ringing state
setState(this, 'ringing');
this.client.cancelPendingEvent(error.event);
let code = MatrixCall.ERR_SEND_ANSWER;
let message = "Failed to send answer";
if (error.name == 'UnknownDeviceError') {
code = MatrixCall.ERR_UNKNOWN_DEVICES;
message = "Unknown devices present in the room";
}
this.emit("error", callError(code, message));
throw error;
});
};
/**
* Internal
* @private
@@ -641,7 +666,7 @@ MatrixCall.prototype._maybeGotUserMediaForAnswer = function(stream) {
self.peerConn.createAnswer(function(description) {
debuglog("Created answer: " + description);
self.peerConn.setLocalDescription(description, function() {
const content = {
self._answerContent = {
version: 0,
call_id: self.callId,
answer: {
@@ -649,8 +674,7 @@ MatrixCall.prototype._maybeGotUserMediaForAnswer = function(stream) {
type: self.peerConn.localDescription.type,
},
};
sendEvent(self, 'm.call.answer', content);
setState(self, 'connecting');
self._sendAnswer();
}, function() {
debuglog("Error setting local description!");
}, constraints);
@@ -671,6 +695,9 @@ MatrixCall.prototype._gotLocalIceCandidate = function(event) {
"Got local ICE " + event.candidate.sdpMid + " candidate: " +
event.candidate.candidate,
);
if (this.state == 'ended') return;
// As with the offer, note we need to make a copy of this object, not
// pass the original: that broke in Chrome ~m43.
const c = {
@@ -753,14 +780,27 @@ MatrixCall.prototype._gotLocalOffer = function(description) {
},
lifetime: MatrixCall.CALL_TIMEOUT_MS,
};
sendEvent(self, 'm.call.invite', content);
setTimeout(function() {
if (self.state == 'invite_sent') {
self.hangup('invite_timeout');
sendEvent(self, 'm.call.invite', content).then(() => {
setState(self, 'invite_sent');
setTimeout(function() {
if (self.state == 'invite_sent') {
self.hangup('invite_timeout');
}
}, MatrixCall.CALL_TIMEOUT_MS);
}).catch((error) => {
let code = MatrixCall.ERR_SEND_INVITE;
let message = "Failed to send invite";
if (error.name == 'UnknownDeviceError') {
code = MatrixCall.ERR_UNKNOWN_DEVICES;
message = "Unknown devices present in the room";
}
}, MatrixCall.CALL_TIMEOUT_MS);
setState(self, 'invite_sent');
self.client.cancelPendingEvent(error.event);
terminate(self, "local", code, false);
self.emit("error", callError(code, message));
throw error;
});
}, function() {
debuglog("Error setting local description!");
});
@@ -784,6 +824,7 @@ MatrixCall.prototype._getLocalOfferFailed = function(error) {
* @param {Object} error
*/
MatrixCall.prototype._getUserMediaFailed = function(error) {
terminate(this, "local", 'user_media_failed', false);
this.emit(
"error",
callError(
@@ -792,7 +833,6 @@ MatrixCall.prototype._getUserMediaFailed = function(error) {
"does this app have permission?",
),
);
this.hangup("user_media_failed");
};
/**
@@ -972,17 +1012,20 @@ const setState = function(self, state) {
* @return {Promise}
*/
const sendEvent = function(self, eventType, content) {
return self.client.sendEvent(self.roomId, eventType, content).catch(
(err) => {
self.emit('send_event_error', err);
},
);
return self.client.sendEvent(self.roomId, eventType, content);
};
const sendCandidate = function(self, content) {
// Sends candidates with are sent in a special way because we try to amalgamate
// them into one message
self.candidateSendQueue.push(content);
// Don't send the ICE candidates yet if the call is in the ringing state: this
// means we tried to pick (ie. started generating candidates) and then failed to
// send the answer and went back to the ringing state. Queue up the candidates
// to send if we sucessfully send the answer.
if (self.state == 'ringing') return;
if (self.candidateSendTries === 0) {
setTimeout(function() {
_sendCandidateQueue(self);