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
kill unhandled exceptions where loads and plays race by queuing them as promises
This commit is contained in:
@@ -74,6 +74,8 @@ MatrixCall.ERR_LOCAL_OFFER_FAILED = "local_offer_failed";
|
|||||||
*/
|
*/
|
||||||
MatrixCall.ERR_NO_USER_MEDIA = "no_user_media";
|
MatrixCall.ERR_NO_USER_MEDIA = "no_user_media";
|
||||||
|
|
||||||
|
MatrixCall.mediaPromises = {};
|
||||||
|
|
||||||
utils.inherits(MatrixCall, EventEmitter);
|
utils.inherits(MatrixCall, EventEmitter);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -144,6 +146,64 @@ MatrixCall.prototype.placeScreenSharingCall =
|
|||||||
_tryPlayRemoteStream(this);
|
_tryPlayRemoteStream(this);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Play the given HTMLMediaElement, serialising the operation into a chain
|
||||||
|
* of promises to avoid racing access to the element
|
||||||
|
* @param {Element} HTMLMediaElement to play
|
||||||
|
* @param {string} Arbitrary ID to track the chain of promises to be used
|
||||||
|
*/
|
||||||
|
MatrixCall.prototype.playElement = function(element, queueId) {
|
||||||
|
if (MatrixCall.mediaPromises[queueId]) {
|
||||||
|
MatrixCall.mediaPromises[queueId] =
|
||||||
|
MatrixCall.mediaPromises[queueId].then(function() {
|
||||||
|
return element.play();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
MatrixCall.mediaPromises[queueId] = element.play();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pause the given HTMLMediaElement, serialising the operation into a chain
|
||||||
|
* of promises to avoid racing access to the element
|
||||||
|
* @param {Element} HTMLMediaElement to pause
|
||||||
|
* @param {string} Arbitrary ID to track the chain of promises to be used
|
||||||
|
*/
|
||||||
|
MatrixCall.prototype.pauseElement = function(element, queueId) {
|
||||||
|
if (MatrixCall.mediaPromises[queueId]) {
|
||||||
|
MatrixCall.mediaPromises[queueId] =
|
||||||
|
MatrixCall.mediaPromises[queueId].then(function() {
|
||||||
|
return element.pause();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// pause doesn't actually return a promise, but do this for symmetry
|
||||||
|
// and just in case it does in future.
|
||||||
|
MatrixCall.mediaPromises[queueId] = element.pause();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assign the given HTMLMediaElement by setting the .src attribute on it,
|
||||||
|
* serialising the operation into a chain of promises to avoid racing access
|
||||||
|
* to the element
|
||||||
|
* @param {Element} HTMLMediaElement to pause
|
||||||
|
* @param {string} the src attribute value to assign to the element
|
||||||
|
* @param {string} Arbitrary ID to track the chain of promises to be used
|
||||||
|
*/
|
||||||
|
MatrixCall.prototype.assignElement = function(element, src, queueId) {
|
||||||
|
if (MatrixCall.mediaPromises[queueId]) {
|
||||||
|
MatrixCall.mediaPromises[queueId] =
|
||||||
|
MatrixCall.mediaPromises[queueId].then(function() {
|
||||||
|
element.src = src;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
element.src = src;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the local <code><video></code> DOM element.
|
* Retrieve the local <code><video></code> DOM element.
|
||||||
* @return {Element} The dom element
|
* @return {Element} The dom element
|
||||||
@@ -180,13 +240,15 @@ MatrixCall.prototype.setLocalVideoElement = function(element) {
|
|||||||
|
|
||||||
if (element && this.localAVStream && this.type === 'video') {
|
if (element && this.localAVStream && this.type === 'video') {
|
||||||
element.autoplay = true;
|
element.autoplay = true;
|
||||||
element.src = this.URL.createObjectURL(this.localAVStream);
|
this.assignElement(element,
|
||||||
|
this.URL.createObjectURL(this.localAVStream),
|
||||||
|
"localVideo");
|
||||||
element.muted = true;
|
element.muted = true;
|
||||||
var self = this;
|
var self = this;
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
var vel = self.getLocalVideoElement();
|
var vel = self.getLocalVideoElement();
|
||||||
if (vel.play) {
|
if (vel.play) {
|
||||||
vel.play();
|
self.playElement(vel, "localVideo");
|
||||||
}
|
}
|
||||||
}, 0);
|
}, 0);
|
||||||
}
|
}
|
||||||
@@ -414,16 +476,20 @@ MatrixCall.prototype._gotUserMediaForInvite = function(stream) {
|
|||||||
videoEl.autoplay = true;
|
videoEl.autoplay = true;
|
||||||
if (this.screenSharingStream) {
|
if (this.screenSharingStream) {
|
||||||
debuglog("Setting screen sharing stream to the local video element");
|
debuglog("Setting screen sharing stream to the local video element");
|
||||||
videoEl.src = this.URL.createObjectURL(this.screenSharingStream);
|
this.assignElement(videoEl,
|
||||||
|
this.URL.createObjectURL(this.screenSharingStream),
|
||||||
|
"localVideo");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
videoEl.src = this.URL.createObjectURL(stream);
|
this.assignElement(videoEl,
|
||||||
|
this.URL.createObjectURL(stream),
|
||||||
|
"localVideo");
|
||||||
}
|
}
|
||||||
videoEl.muted = true;
|
videoEl.muted = true;
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
var vel = self.getLocalVideoElement();
|
var vel = self.getLocalVideoElement();
|
||||||
if (vel.play) {
|
if (vel.play) {
|
||||||
vel.play();
|
self.playElement(vel, "localVideo");
|
||||||
}
|
}
|
||||||
}, 0);
|
}, 0);
|
||||||
}
|
}
|
||||||
@@ -460,12 +526,14 @@ MatrixCall.prototype._gotUserMediaForAnswer = function(stream) {
|
|||||||
|
|
||||||
if (localVidEl && self.type == 'video') {
|
if (localVidEl && self.type == 'video') {
|
||||||
localVidEl.autoplay = true;
|
localVidEl.autoplay = true;
|
||||||
localVidEl.src = self.URL.createObjectURL(stream);
|
this.assignElement(localVidEl,
|
||||||
|
this.URL.createObjectURL(stream),
|
||||||
|
"localVideo");
|
||||||
localVidEl.muted = true;
|
localVidEl.muted = true;
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
var vel = self.getLocalVideoElement();
|
var vel = self.getLocalVideoElement();
|
||||||
if (vel.play) {
|
if (vel.play) {
|
||||||
vel.play();
|
self.playElement(vel, "localVideo");
|
||||||
}
|
}
|
||||||
}, 0);
|
}, 0);
|
||||||
}
|
}
|
||||||
@@ -712,7 +780,7 @@ MatrixCall.prototype._onAddStream = function(event) {
|
|||||||
t.onstarted = hookCallback(self, self._onRemoteStreamTrackStarted);
|
t.onstarted = hookCallback(self, self._onRemoteStreamTrackStarted);
|
||||||
});
|
});
|
||||||
|
|
||||||
event.stream.onended = hookCallback(self, self._onRemoteStreamEnded);
|
event.stream.oninactive = hookCallback(self, self._onRemoteStreamEnded);
|
||||||
// not currently implemented in chrome
|
// not currently implemented in chrome
|
||||||
event.stream.onstarted = hookCallback(self, self._onRemoteStreamStarted);
|
event.stream.onstarted = hookCallback(self, self._onRemoteStreamStarted);
|
||||||
|
|
||||||
@@ -824,21 +892,21 @@ var sendCandidate = function(self, content) {
|
|||||||
var terminate = function(self, hangupParty, hangupReason, shouldEmit) {
|
var terminate = function(self, hangupParty, hangupReason, shouldEmit) {
|
||||||
if (self.getRemoteVideoElement()) {
|
if (self.getRemoteVideoElement()) {
|
||||||
if (self.getRemoteVideoElement().pause) {
|
if (self.getRemoteVideoElement().pause) {
|
||||||
self.getRemoteVideoElement().pause();
|
self.pauseElement(self.getRemoteVideoElement(), "remoteVideo");
|
||||||
}
|
}
|
||||||
self.getRemoteVideoElement().src = "";
|
self.assignElement(self.getRemoteVideoElement(), "", "remoteVideo");
|
||||||
}
|
}
|
||||||
if (self.getRemoteAudioElement()) {
|
if (self.getRemoteAudioElement()) {
|
||||||
if (self.getRemoteAudioElement().pause) {
|
if (self.getRemoteAudioElement().pause) {
|
||||||
self.getRemoteAudioElement().pause();
|
self.pauseElement(self.getRemoteAudioElement(), "remoteAudio");
|
||||||
}
|
}
|
||||||
self.getRemoteAudioElement().src = "";
|
self.assignElement(self.getRemoteAudioElement(), "", "remoteAudio");
|
||||||
}
|
}
|
||||||
if (self.getLocalVideoElement()) {
|
if (self.getLocalVideoElement()) {
|
||||||
if (self.getLocalVideoElement().pause) {
|
if (self.getLocalVideoElement().pause) {
|
||||||
self.getLocalVideoElement().pause();
|
self.pauseElement(self.getLocalVideoElement(), "localVideo");
|
||||||
}
|
}
|
||||||
self.getLocalVideoElement().src = "";
|
self.assignElement(self.getLocalVideoElement(), "", "localVideo");
|
||||||
}
|
}
|
||||||
self.hangupParty = hangupParty;
|
self.hangupParty = hangupParty;
|
||||||
self.hangupReason = hangupReason;
|
self.hangupReason = hangupReason;
|
||||||
@@ -896,11 +964,13 @@ var _tryPlayRemoteStream = function(self) {
|
|||||||
if (self.getRemoteVideoElement() && self.remoteAVStream) {
|
if (self.getRemoteVideoElement() && self.remoteAVStream) {
|
||||||
var player = self.getRemoteVideoElement();
|
var player = self.getRemoteVideoElement();
|
||||||
player.autoplay = true;
|
player.autoplay = true;
|
||||||
player.src = self.URL.createObjectURL(self.remoteAVStream);
|
self.assignElement(player,
|
||||||
|
self.URL.createObjectURL(self.remoteAVStream),
|
||||||
|
"remoteVideo");
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
var vel = self.getRemoteVideoElement();
|
var vel = self.getRemoteVideoElement();
|
||||||
if (vel.play) {
|
if (vel.play) {
|
||||||
vel.play();
|
self.playElement(vel, "remoteVideo");
|
||||||
}
|
}
|
||||||
// OpenWebRTC does not support oniceconnectionstatechange yet
|
// OpenWebRTC does not support oniceconnectionstatechange yet
|
||||||
if (self.webRtc.isOpenWebRTC()) {
|
if (self.webRtc.isOpenWebRTC()) {
|
||||||
@@ -914,11 +984,13 @@ var _tryPlayRemoteAudioStream = function(self) {
|
|||||||
if (self.getRemoteAudioElement() && self.remoteAStream) {
|
if (self.getRemoteAudioElement() && self.remoteAStream) {
|
||||||
var player = self.getRemoteAudioElement();
|
var player = self.getRemoteAudioElement();
|
||||||
player.autoplay = true;
|
player.autoplay = true;
|
||||||
player.src = self.URL.createObjectURL(self.remoteAStream);
|
self.assignElement(player,
|
||||||
|
self.URL.createObjectURL(self.remoteAStream),
|
||||||
|
"remoteAudio");
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
var ael = self.getRemoteAudioElement();
|
var ael = self.getRemoteAudioElement();
|
||||||
if (ael.play) {
|
if (ael.play) {
|
||||||
ael.play();
|
self.playElement(vel, "remoteAudio");
|
||||||
}
|
}
|
||||||
// OpenWebRTC does not support oniceconnectionstatechange yet
|
// OpenWebRTC does not support oniceconnectionstatechange yet
|
||||||
if (self.webRtc.isOpenWebRTC()) {
|
if (self.webRtc.isOpenWebRTC()) {
|
||||||
@@ -1102,6 +1174,7 @@ var forAllTracksOnStream = function(s, f) {
|
|||||||
/** The MatrixCall class. */
|
/** The MatrixCall class. */
|
||||||
module.exports.MatrixCall = MatrixCall;
|
module.exports.MatrixCall = MatrixCall;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new Matrix call for the browser.
|
* Create a new Matrix call for the browser.
|
||||||
* @param {MatrixClient} client The client instance to use.
|
* @param {MatrixClient} client The client instance to use.
|
||||||
|
|||||||
Reference in New Issue
Block a user