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.mediaPromises = {};
|
||||
|
||||
utils.inherits(MatrixCall, EventEmitter);
|
||||
|
||||
/**
|
||||
@@ -144,6 +146,64 @@ MatrixCall.prototype.placeScreenSharingCall =
|
||||
_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.
|
||||
* @return {Element} The dom element
|
||||
@@ -180,13 +240,15 @@ MatrixCall.prototype.setLocalVideoElement = function(element) {
|
||||
|
||||
if (element && this.localAVStream && this.type === 'video') {
|
||||
element.autoplay = true;
|
||||
element.src = this.URL.createObjectURL(this.localAVStream);
|
||||
this.assignElement(element,
|
||||
this.URL.createObjectURL(this.localAVStream),
|
||||
"localVideo");
|
||||
element.muted = true;
|
||||
var self = this;
|
||||
setTimeout(function() {
|
||||
var vel = self.getLocalVideoElement();
|
||||
if (vel.play) {
|
||||
vel.play();
|
||||
self.playElement(vel, "localVideo");
|
||||
}
|
||||
}, 0);
|
||||
}
|
||||
@@ -414,16 +476,20 @@ MatrixCall.prototype._gotUserMediaForInvite = function(stream) {
|
||||
videoEl.autoplay = true;
|
||||
if (this.screenSharingStream) {
|
||||
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 {
|
||||
videoEl.src = this.URL.createObjectURL(stream);
|
||||
this.assignElement(videoEl,
|
||||
this.URL.createObjectURL(stream),
|
||||
"localVideo");
|
||||
}
|
||||
videoEl.muted = true;
|
||||
setTimeout(function() {
|
||||
var vel = self.getLocalVideoElement();
|
||||
if (vel.play) {
|
||||
vel.play();
|
||||
self.playElement(vel, "localVideo");
|
||||
}
|
||||
}, 0);
|
||||
}
|
||||
@@ -460,12 +526,14 @@ MatrixCall.prototype._gotUserMediaForAnswer = function(stream) {
|
||||
|
||||
if (localVidEl && self.type == 'video') {
|
||||
localVidEl.autoplay = true;
|
||||
localVidEl.src = self.URL.createObjectURL(stream);
|
||||
this.assignElement(localVidEl,
|
||||
this.URL.createObjectURL(stream),
|
||||
"localVideo");
|
||||
localVidEl.muted = true;
|
||||
setTimeout(function() {
|
||||
var vel = self.getLocalVideoElement();
|
||||
if (vel.play) {
|
||||
vel.play();
|
||||
self.playElement(vel, "localVideo");
|
||||
}
|
||||
}, 0);
|
||||
}
|
||||
@@ -712,7 +780,7 @@ MatrixCall.prototype._onAddStream = function(event) {
|
||||
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
|
||||
event.stream.onstarted = hookCallback(self, self._onRemoteStreamStarted);
|
||||
|
||||
@@ -824,21 +892,21 @@ var sendCandidate = function(self, content) {
|
||||
var terminate = function(self, hangupParty, hangupReason, shouldEmit) {
|
||||
if (self.getRemoteVideoElement()) {
|
||||
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().pause) {
|
||||
self.getRemoteAudioElement().pause();
|
||||
self.pauseElement(self.getRemoteAudioElement(), "remoteAudio");
|
||||
}
|
||||
self.getRemoteAudioElement().src = "";
|
||||
self.assignElement(self.getRemoteAudioElement(), "", "remoteAudio");
|
||||
}
|
||||
if (self.getLocalVideoElement()) {
|
||||
if (self.getLocalVideoElement().pause) {
|
||||
self.getLocalVideoElement().pause();
|
||||
self.pauseElement(self.getLocalVideoElement(), "localVideo");
|
||||
}
|
||||
self.getLocalVideoElement().src = "";
|
||||
self.assignElement(self.getLocalVideoElement(), "", "localVideo");
|
||||
}
|
||||
self.hangupParty = hangupParty;
|
||||
self.hangupReason = hangupReason;
|
||||
@@ -896,11 +964,13 @@ var _tryPlayRemoteStream = function(self) {
|
||||
if (self.getRemoteVideoElement() && self.remoteAVStream) {
|
||||
var player = self.getRemoteVideoElement();
|
||||
player.autoplay = true;
|
||||
player.src = self.URL.createObjectURL(self.remoteAVStream);
|
||||
self.assignElement(player,
|
||||
self.URL.createObjectURL(self.remoteAVStream),
|
||||
"remoteVideo");
|
||||
setTimeout(function() {
|
||||
var vel = self.getRemoteVideoElement();
|
||||
if (vel.play) {
|
||||
vel.play();
|
||||
self.playElement(vel, "remoteVideo");
|
||||
}
|
||||
// OpenWebRTC does not support oniceconnectionstatechange yet
|
||||
if (self.webRtc.isOpenWebRTC()) {
|
||||
@@ -914,11 +984,13 @@ var _tryPlayRemoteAudioStream = function(self) {
|
||||
if (self.getRemoteAudioElement() && self.remoteAStream) {
|
||||
var player = self.getRemoteAudioElement();
|
||||
player.autoplay = true;
|
||||
player.src = self.URL.createObjectURL(self.remoteAStream);
|
||||
self.assignElement(player,
|
||||
self.URL.createObjectURL(self.remoteAStream),
|
||||
"remoteAudio");
|
||||
setTimeout(function() {
|
||||
var ael = self.getRemoteAudioElement();
|
||||
if (ael.play) {
|
||||
ael.play();
|
||||
self.playElement(vel, "remoteAudio");
|
||||
}
|
||||
// OpenWebRTC does not support oniceconnectionstatechange yet
|
||||
if (self.webRtc.isOpenWebRTC()) {
|
||||
@@ -1102,6 +1174,7 @@ var forAllTracksOnStream = function(s, f) {
|
||||
/** The MatrixCall class. */
|
||||
module.exports.MatrixCall = MatrixCall;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new Matrix call for the browser.
|
||||
* @param {MatrixClient} client The client instance to use.
|
||||
|
||||
Reference in New Issue
Block a user