You've already forked matrix-js-sdk
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:
@@ -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';
|
||||||
|
|||||||
Reference in New Issue
Block a user