diff options
author | Daniel Calviño Sánchez <danxuliu@gmail.com> | 2021-05-25 06:50:33 +0200 |
---|---|---|
committer | Daniel Calviño Sánchez <danxuliu@gmail.com> | 2021-06-21 20:44:44 +0200 |
commit | abe5633824b06ddfd97869dab6cb12ebbc8407ef (patch) | |
tree | 7329d9da21779089943b1f19d75fed48e80ada79 | |
parent | 661d5fd1e897983700f9aa2fb69c3a6673112a80 (diff) |
Stop sent streams when media is disabled
In order to stop the sent streams the track can be replaced in the
sender by a null track. To differentiate between a null track due to no
device being selected or the original track being stopped an additional
attribute, "trackDisabled", is attached now to each sender.
Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
-rw-r--r-- | src/utils/webrtc/simplewebrtc/localmedia.js | 8 | ||||
-rw-r--r-- | src/utils/webrtc/simplewebrtc/peer.js | 59 |
2 files changed, 66 insertions, 1 deletions
diff --git a/src/utils/webrtc/simplewebrtc/localmedia.js b/src/utils/webrtc/simplewebrtc/localmedia.js index ad7e84903..a7a008923 100644 --- a/src/utils/webrtc/simplewebrtc/localmedia.js +++ b/src/utils/webrtc/simplewebrtc/localmedia.js @@ -637,6 +637,10 @@ LocalMedia.prototype._setAudioEnabled = function(bool) { this.localStreams.forEach(stream => { stream.getAudioTracks().forEach(track => { track.enabled = !!bool + + // MediaStreamTrack does not emit an event when the enabled property + // changes, so it needs to be explicitly notified. + this.emit('localTrackEnabledChanged', track, stream) }) }) } @@ -646,6 +650,10 @@ LocalMedia.prototype._setVideoEnabled = function(bool) { this.localStreams.forEach(stream => { stream.getVideoTracks().forEach(track => { track.enabled = !!bool + + // MediaStreamTrack does not emit an event when the enabled property + // changes, so it needs to be explicitly notified. + this.emit('localTrackEnabledChanged', track, stream) }) }) } diff --git a/src/utils/webrtc/simplewebrtc/peer.js b/src/utils/webrtc/simplewebrtc/peer.js index 4f81eac75..44feb991d 100644 --- a/src/utils/webrtc/simplewebrtc/peer.js +++ b/src/utils/webrtc/simplewebrtc/peer.js @@ -88,6 +88,9 @@ function Peer(options) { // TODO What would happen if the track is replaced while the peer is // still negotiating the offer and answer? this.parent.on('localTrackReplaced', this.handleLocalTrackReplacedBound) + + this.handleLocalTrackEnabledChangedBound = this.handleLocalTrackEnabledChanged.bind(this) + this.parent.on('localTrackEnabledChanged', this.handleLocalTrackEnabledChangedBound) } } @@ -378,6 +381,7 @@ Peer.prototype.end = function() { this.pc.close() this.handleStreamRemoved() this.parent.off('localTrackReplaced', this.handleLocalTrackReplacedBound) + this.parent.off('localTrackEnabledChanged', this.handleLocalTrackEnabledChangedBound) } Peer.prototype.handleLocalTrackReplaced = function(newTrack, oldTrack, stream) { @@ -445,6 +449,12 @@ Peer.prototype._processPendingReplaceTracksAsync = async function() { /** * Replaces the old track with the new track in the appropriate sender. * + * If the new track is disabled the old track will be replaced by a null track + * instead, which stops the sent data. The old and new tracks can be the same + * track, which can be used to start or stop sending the track data depending on + * whether the track is enabled or disabled (at the time of being passed to this + * method). + * * If a new track is provided but no sender was found the new track is added * instead of replaced (which will require a renegotiation). * @@ -465,16 +475,29 @@ Peer.prototype._replaceTrack = async function(newTrack, oldTrack, stream) { const replaceTrackPromises = [] this.pc.getSenders().forEach(sender => { - if (sender.track !== oldTrack) { + if (sender.track !== oldTrack && sender.trackDisabled !== oldTrack) { + return + } + + if ((sender.track || sender.trackDisabled) && !oldTrack) { return } if (!sender.track && !newTrack) { + // The old track was disabled and thus already stopped, so it does + // not need to be replaced, but the null track needs to be set as + // the disabled track. + if (sender.trackDisabled === oldTrack) { + sender.trackDisabled = newTrack + } + return } if (!sender.kind && sender.track) { sender.kind = sender.track.kind + } else if (!sender.kind && sender.trackDisabled) { + sender.kind = sender.trackDisabled.kind } else if (!sender.kind) { this.pc.getTransceivers().forEach(transceiver => { if (transceiver.sender === sender) { @@ -496,9 +519,32 @@ Peer.prototype._replaceTrack = async function(newTrack, oldTrack, stream) { senderFound = true + // Save reference to trackDisabled to be able to restore it if the track + // can not be replaced. + const oldTrackDisabled = sender.trackDisabled + + if (newTrack && !newTrack.enabled) { + sender.trackDisabled = newTrack + } else { + sender.trackDisabled = null + } + + if (!sender.track && !newTrack.enabled) { + // Nothing to replace now, it will be done once the track is + // enabled. + return + } + + if (sender.track && newTrack && !newTrack.enabled) { + // Replace with a null track to stop the sender. + newTrack = null + } + const replaceTrackPromise = sender.replaceTrack(newTrack) replaceTrackPromise.catch(error => { + sender.trackDisabled = oldTrackDisabled + if (error.name === 'InvalidModificationError') { console.debug('Track could not be replaced, negotiation needed') } else { @@ -521,6 +567,17 @@ Peer.prototype._replaceTrack = async function(newTrack, oldTrack, stream) { return Promise.allSettled(replaceTrackPromises) } +Peer.prototype.handleLocalTrackEnabledChanged = function(track, stream) { + const sender = this.pc.getSenders().find(sender => sender.track === track) + const stoppedSender = this.pc.getSenders().find(sender => sender.trackDisabled === track) + + if (track.enabled && stoppedSender) { + this.handleLocalTrackReplacedBound(track, track, stream) + } else if (!track.enabled && sender) { + this.handleLocalTrackReplacedBound(track, track, stream) + } +} + Peer.prototype.handleRemoteStreamAdded = function(event) { const self = this if (this.stream) { |