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

webrtc/call: Fall back to recvonly if camera/mic access is denied

Users of MatrixCall will need to present some sensible UX for this.
This commit is contained in:
Robert Swain
2017-04-05 15:24:54 +02:00
parent 2c15bdae04
commit b33dcfe6ff

View File

@@ -409,12 +409,12 @@ MatrixCall.prototype.answer = function() {
if (!this.localAVStream && !this.waitForLocalAVStream) { if (!this.localAVStream && !this.waitForLocalAVStream) {
this.webRtc.getUserMedia( this.webRtc.getUserMedia(
_getUserMediaVideoContraints(this.type), _getUserMediaVideoContraints(this.type),
hookCallback(self, self._gotUserMediaForAnswer), hookCallback(self, self._maybeGotUserMediaForAnswer),
hookCallback(self, self._getUserMediaFailed), hookCallback(self, self._maybeGotUserMediaForAnswer),
); );
setState(this, 'wait_local_media'); setState(this, 'wait_local_media');
} else if (this.localAVStream) { } else if (this.localAVStream) {
this._gotUserMediaForAnswer(this.localAVStream); this._maybeGotUserMediaForAnswer(this.localAVStream);
} else if (this.waitForLocalAVStream) { } else if (this.waitForLocalAVStream) {
setState(this, 'wait_local_media'); setState(this, 'wait_local_media');
} }
@@ -433,11 +433,11 @@ MatrixCall.prototype._replacedBy = function(newCall) {
newCall.waitForLocalAVStream = true; newCall.waitForLocalAVStream = true;
} else if (this.state == 'create_offer') { } else if (this.state == 'create_offer') {
debuglog("Handing local stream to new call"); debuglog("Handing local stream to new call");
newCall._gotUserMediaForAnswer(this.localAVStream); newCall._maybeGotUserMediaForAnswer(this.localAVStream);
delete(this.localAVStream); delete(this.localAVStream);
} else if (this.state == 'invite_sent') { } else if (this.state == 'invite_sent') {
debuglog("Handing local stream to new call"); debuglog("Handing local stream to new call");
newCall._gotUserMediaForAnswer(this.localAVStream); newCall._maybeGotUserMediaForAnswer(this.localAVStream);
delete(this.localAVStream); delete(this.localAVStream);
} }
newCall.localVideoElement = this.localVideoElement; newCall.localVideoElement = this.localVideoElement;
@@ -523,48 +523,70 @@ MatrixCall.prototype.isMicrophoneMuted = function() {
* @private * @private
* @param {Object} stream * @param {Object} stream
*/ */
MatrixCall.prototype._gotUserMediaForInvite = function(stream) { MatrixCall.prototype._maybeGotUserMediaForInvite = function(stream) {
if (this.successor) { if (this.successor) {
this.successor._gotUserMediaForAnswer(stream); this.successor._maybeGotUserMediaForAnswer(stream);
return; return;
} }
if (this.state == 'ended') { if (this.state == 'ended') {
return; return;
} }
debuglog("_gotUserMediaForInvite -> " + this.type); debuglog("_maybeGotUserMediaForInvite -> " + this.type);
const self = this; const self = this;
const videoEl = this.getLocalVideoElement();
if (videoEl && this.type == 'video') { const error = stream;
videoEl.autoplay = true; let constraints = null;
if (this.screenSharingStream) { if (stream instanceof MediaStream) {
debuglog("Setting screen sharing stream to the local video element"); const videoEl = this.getLocalVideoElement();
this.assignElement(videoEl, this.screenSharingStream, "localVideo");
} else { if (videoEl && this.type == 'video') {
this.assignElement(videoEl, stream, "localVideo"); videoEl.autoplay = true;
} if (this.screenSharingStream) {
videoEl.muted = true; debuglog("Setting screen sharing stream to the local video" +
setTimeout(function() { " element");
const vel = self.getLocalVideoElement(); this.assignElement(videoEl, this.screenSharingStream, "localVideo");
if (vel.play) { } else {
self.playElement(vel, "localVideo"); this.assignElement(videoEl, stream, "localVideo");
} }
}, 0); videoEl.muted = true;
setTimeout(function() {
const vel = self.getLocalVideoElement();
if (vel.play) {
self.playElement(vel, "localVideo");
}
}, 0);
}
if (this.screenSharingStream) {
this.screenSharingStream.addTrack(stream.getAudioTracks()[0]);
stream = this.screenSharingStream;
}
this.localAVStream = stream;
// why do we enable audio (and only audio) tracks here? -- matthew
setTracksEnabled(stream.getAudioTracks(), true);
this.peerConn = _createPeerConnection(this);
this.peerConn.addStream(stream);
} else if (error.name === 'PermissionDeniedError') {
debuglog('User denied access to camera/microphone.' +
' Or possibly you are using an insecure domain. Receiving only.');
constraints = {
'mandatory': {
'OfferToReceiveAudio': true,
'OfferToReceiveVideo': self.type == 'video',
},
};
this.peerConn = _createPeerConnection(this);
} else {
debuglog('Failed to getUserMedia.');
this._getUserMediaFailed(error);
return;
} }
if (this.screenSharingStream) {
this.screenSharingStream.addTrack(stream.getAudioTracks()[0]);
stream = this.screenSharingStream;
}
this.localAVStream = stream;
// why do we enable audio (and only audio) tracks here? -- matthew
setTracksEnabled(stream.getAudioTracks(), true);
this.peerConn = _createPeerConnection(this);
this.peerConn.addStream(stream);
this.peerConn.createOffer( this.peerConn.createOffer(
hookCallback(self, self._gotLocalOffer), hookCallback(self, self._gotLocalOffer),
hookCallback(self, self._getLocalOfferFailed), hookCallback(self, self._getLocalOfferFailed),
constraints,
); );
setState(self, 'create_offer'); setState(self, 'create_offer');
}; };
@@ -574,29 +596,40 @@ MatrixCall.prototype._gotUserMediaForInvite = function(stream) {
* @private * @private
* @param {Object} stream * @param {Object} stream
*/ */
MatrixCall.prototype._gotUserMediaForAnswer = function(stream) { MatrixCall.prototype._maybeGotUserMediaForAnswer = function(stream) {
const self = this; const self = this;
if (self.state == 'ended') { if (self.state == 'ended') {
return; return;
} }
const localVidEl = self.getLocalVideoElement();
if (localVidEl && self.type == 'video') { const error = stream;
localVidEl.autoplay = true; if (stream instanceof MediaStream) {
this.assignElement(localVidEl, stream, "localVideo"); const localVidEl = self.getLocalVideoElement();
localVidEl.muted = true;
setTimeout(function() { if (localVidEl && self.type == 'video') {
const vel = self.getLocalVideoElement(); localVidEl.autoplay = true;
if (vel.play) { this.assignElement(localVidEl, stream, "localVideo");
self.playElement(vel, "localVideo"); localVidEl.muted = true;
} setTimeout(function() {
}, 0); const vel = self.getLocalVideoElement();
if (vel.play) {
self.playElement(vel, "localVideo");
}
}, 0);
}
self.localAVStream = stream;
setTracksEnabled(stream.getAudioTracks(), true);
self.peerConn.addStream(stream);
} else if (error.name === 'PermissionDeniedError') {
debuglog('User denied access to camera/microphone.' +
' Or possibly you are using an insecure domain. Receiving only.');
} else {
debuglog('Failed to getUserMedia.');
this._getUserMediaFailed(error);
return;
} }
self.localAVStream = stream;
setTracksEnabled(stream.getAudioTracks(), true);
self.peerConn.addStream(stream);
const constraints = { const constraints = {
'mandatory': { 'mandatory': {
'OfferToReceiveAudio': true, 'OfferToReceiveAudio': true,
@@ -1126,8 +1159,8 @@ const _placeCallWithConstraints = function(self, constraints) {
self.client.callList[self.callId] = self; self.client.callList[self.callId] = self;
self.webRtc.getUserMedia( self.webRtc.getUserMedia(
constraints, constraints,
hookCallback(self, self._gotUserMediaForInvite), hookCallback(self, self._maybeGotUserMediaForInvite),
hookCallback(self, self._getUserMediaFailed), hookCallback(self, self._maybeGotUserMediaForInvite),
); );
setState(self, 'wait_local_media'); setState(self, 'wait_local_media');
self.direction = 'outbound'; self.direction = 'outbound';