diff --git a/openvidu-browser/src/OpenVidu/Publisher.ts b/openvidu-browser/src/OpenVidu/Publisher.ts index 3e679b1c..6a93a2eb 100644 --- a/openvidu-browser/src/OpenVidu/Publisher.ts +++ b/openvidu-browser/src/OpenVidu/Publisher.ts @@ -168,68 +168,88 @@ export class Publisher extends StreamManager { * useful if the Publisher was unpublished freeing the hardware resource, and openvidu-browser is not able to successfully re-create the video track as it was before unpublishing. In this way previous track settings will be ignored and this MediaStreamTrack * will be used instead. */ - publishVideo(enabled: T, resource?: T extends false ? boolean : MediaStreamTrack): void { + publishVideo(enabled: T, resource?: T extends false ? boolean : MediaStreamTrack): Promise { - if (this.stream.videoActive !== enabled) { + return new Promise(async (resolve, reject) => { - const affectedMediaStream: MediaStream = this.stream.displayMyRemote() ? this.stream.localMediaStreamWhenSubscribedToRemote! : this.stream.getMediaStream(); - let mustRestartMediaStream = false; - affectedMediaStream.getVideoTracks().forEach((track) => { - track.enabled = enabled; - if (!enabled && resource === true) { - track.stop(); - } else if (enabled && track.readyState === 'ended') { - // Resource was freed - mustRestartMediaStream = true; + if (this.stream.videoActive !== enabled) { + + const affectedMediaStream: MediaStream = this.stream.displayMyRemote() ? this.stream.localMediaStreamWhenSubscribedToRemote! : this.stream.getMediaStream(); + let mustRestartMediaStream = false; + affectedMediaStream.getVideoTracks().forEach((track) => { + track.enabled = enabled; + if (!enabled && resource === true) { + track.stop(); + } else if (enabled && track.readyState === 'ended') { + // Resource was freed + mustRestartMediaStream = true; + } + }); + + // There is a Virtual Background filter applied that must be removed in case the hardware must be freed + if (!enabled && resource === true && !!this.stream.filter && this.stream.filter.type.startsWith('VB:')) { + this.stream.lastVBFilter = this.stream.filter; // Save the filter to be re-applied in case of unmute + await this.stream.removeFilterAux(true); } - }); - if (mustRestartMediaStream) { - const oldVideoTrack = affectedMediaStream.getVideoTracks()[0]; - affectedMediaStream.removeTrack(oldVideoTrack); + if (mustRestartMediaStream) { + const oldVideoTrack = affectedMediaStream.getVideoTracks()[0]; + affectedMediaStream.removeTrack(oldVideoTrack); - const replaceVideoTrack = (tr: MediaStreamTrack) => { - affectedMediaStream.addTrack(tr); - if (this.stream.isLocalStreamPublished) { - this.replaceTrackInRtcRtpSender(tr); + const replaceVideoTrack = async (tr: MediaStreamTrack) => { + affectedMediaStream.addTrack(tr); + if (this.stream.isLocalStreamPublished) { + await this.replaceTrackInRtcRtpSender(tr); + } + if (!!this.stream.lastVBFilter) { + setTimeout(async () => { + let options = this.stream.lastVBFilter!.options; + const lastExecMethod = this.stream.lastVBFilter!.lastExecMethod; + if (!!lastExecMethod && lastExecMethod.method === 'update') { + options = Object.assign({}, options, lastExecMethod.params); + } + await this.stream.applyFilter(this.stream.lastVBFilter!.type, options); + delete this.stream.lastVBFilter; + }, 1); + } + } + + if (!!resource && resource instanceof MediaStreamTrack) { + await replaceVideoTrack(resource); + } else { + try { + const mediaStream = await navigator.mediaDevices.getUserMedia({ audio: false, video: this.stream.lastVideoTrackConstraints }); + await replaceVideoTrack(mediaStream.getVideoTracks()[0]); + } catch (error) { + return reject(error); + } } } - if (!!resource && resource instanceof MediaStreamTrack) { - replaceVideoTrack(resource); - } else { - navigator.mediaDevices.getUserMedia({ audio: false, video: this.stream.lastVideoTrackConstraints }) - .then(mediaStream => { - replaceVideoTrack(mediaStream.getVideoTracks()[0]); - }) - .catch(error => { - console.error(error); + if (!!this.session && !!this.stream.streamId) { + this.session.openvidu.sendRequest( + 'streamPropertyChanged', + { + streamId: this.stream.streamId, + property: 'videoActive', + newValue: enabled, + reason: 'publishVideo' + }, + (error, response) => { + if (error) { + logger.error("Error sending 'streamPropertyChanged' event", error); + } else { + this.session.emitEvent('streamPropertyChanged', [new StreamPropertyChangedEvent(this.session, this.stream, 'videoActive', enabled, !enabled, 'publishVideo')]); + this.emitEvent('streamPropertyChanged', [new StreamPropertyChangedEvent(this, this.stream, 'videoActive', enabled, !enabled, 'publishVideo')]); + this.session.sendVideoData(this.stream.streamManager); + } }); } + this.stream.videoActive = enabled; + logger.info("'Publisher' has " + (enabled ? 'published' : 'unpublished') + ' its video stream'); + return resolve(); } - - if (!!this.session && !!this.stream.streamId) { - this.session.openvidu.sendRequest( - 'streamPropertyChanged', - { - streamId: this.stream.streamId, - property: 'videoActive', - newValue: enabled, - reason: 'publishVideo' - }, - (error, response) => { - if (error) { - logger.error("Error sending 'streamPropertyChanged' event", error); - } else { - this.session.emitEvent('streamPropertyChanged', [new StreamPropertyChangedEvent(this.session, this.stream, 'videoActive', enabled, !enabled, 'publishVideo')]); - this.emitEvent('streamPropertyChanged', [new StreamPropertyChangedEvent(this, this.stream, 'videoActive', enabled, !enabled, 'publishVideo')]); - this.session.sendVideoData(this.stream.streamManager); - } - }); - } - this.stream.videoActive = enabled; - logger.info("'Publisher' has " + (enabled ? 'published' : 'unpublished') + ' its video stream'); - } + }); } diff --git a/openvidu-browser/src/OpenVidu/Stream.ts b/openvidu-browser/src/OpenVidu/Stream.ts index 464052f3..73575f37 100644 --- a/openvidu-browser/src/OpenVidu/Stream.ts +++ b/openvidu-browser/src/OpenVidu/Stream.ts @@ -232,6 +232,10 @@ export class Stream { * @hidden */ lastVideoTrackConstraints: MediaTrackConstraints | boolean | undefined; + /** + * @hidden + */ + lastVBFilter?: Filter; /**