| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158 | 
							- // @flow
 - 
 - import {
 -     CLEAR_INTERVAL,
 -     INTERVAL_TIMEOUT,
 -     SET_INTERVAL,
 -     timerWorkerScript
 - } from './TimeWorker';
 - 
 - /**
 -  * Represents a modified MediaStream that adds video as pip on a desktop stream.
 -  * <tt>JitsiStreamPresenterEffect</tt> does the processing of the original
 -  * desktop stream.
 -  */
 - export default class JitsiStreamPresenterEffect {
 -     _canvas: HTMLCanvasElement;
 -     _ctx: CanvasRenderingContext2D;
 -     _desktopElement: HTMLVideoElement;
 -     _desktopStream: MediaStream;
 -     _frameRate: number;
 -     _onVideoFrameTimer: Function;
 -     _onVideoFrameTimerWorker: Function;
 -     _renderVideo: Function;
 -     _videoFrameTimerWorker: Worker;
 -     _videoElement: HTMLVideoElement;
 -     isEnabled: Function;
 -     startEffect: Function;
 -     stopEffect: Function;
 - 
 -     /**
 -      * Represents a modified MediaStream that adds a camera track at the
 -      * bottom right corner of the desktop track using a HTML canvas.
 -      * <tt>JitsiStreamPresenterEffect</tt> does the processing of the original
 -      * video stream.
 -      *
 -      * @param {MediaStream} videoStream - The video stream which is user for
 -      * creating the canvas.
 -      */
 -     constructor(videoStream: MediaStream) {
 -         const videoDiv = document.createElement('div');
 -         const firstVideoTrack = videoStream.getVideoTracks()[0];
 -         const { height, width, frameRate } = firstVideoTrack.getSettings() ?? firstVideoTrack.getConstraints();
 - 
 -         this._canvas = document.createElement('canvas');
 -         this._ctx = this._canvas.getContext('2d');
 - 
 -         this._desktopElement = document.createElement('video');
 -         this._videoElement = document.createElement('video');
 -         videoDiv.appendChild(this._videoElement);
 -         videoDiv.appendChild(this._desktopElement);
 -         if (document.body !== null) {
 -             document.body.appendChild(videoDiv);
 -         }
 - 
 -         // Set the video element properties
 -         this._frameRate = parseInt(frameRate, 10);
 -         this._videoElement.width = parseInt(width, 10);
 -         this._videoElement.height = parseInt(height, 10);
 -         this._videoElement.autoplay = true;
 -         this._videoElement.srcObject = videoStream;
 - 
 -         // set the style attribute of the div to make it invisible
 -         videoDiv.style.display = 'none';
 - 
 -         // Bind event handler so it is only bound once for every instance.
 -         this._onVideoFrameTimer = this._onVideoFrameTimer.bind(this);
 -         this._videoFrameTimerWorker = new Worker(timerWorkerScript);
 -         this._videoFrameTimerWorker.onmessage = this._onVideoFrameTimer;
 -     }
 - 
 -     /**
 -      * EventHandler onmessage for the videoFrameTimerWorker WebWorker.
 -      *
 -      * @private
 -      * @param {EventHandler} response - The onmessage EventHandler parameter.
 -      * @returns {void}
 -      */
 -     _onVideoFrameTimer(response) {
 -         if (response.data.id === INTERVAL_TIMEOUT) {
 -             this._renderVideo();
 -         }
 -     }
 - 
 -     /**
 -      * Loop function to render the video frame input and draw presenter effect.
 -      *
 -      * @private
 -      * @returns {void}
 -      */
 -     _renderVideo() {
 -         // adjust the canvas width/height on every frame incase the window has been resized.
 -         const [ track ] = this._desktopStream.getVideoTracks();
 -         const { height, width } = track.getSettings() ?? track.getConstraints();
 - 
 -         this._canvas.width = parseInt(width, 10);
 -         this._canvas.height = parseInt(height, 10);
 -         this._ctx.drawImage(this._desktopElement, 0, 0, this._canvas.width, this._canvas.height);
 -         this._ctx.drawImage(this._videoElement, this._canvas.width - this._videoElement.width, this._canvas.height
 -             - this._videoElement.height, this._videoElement.width, this._videoElement.height);
 - 
 -         // draw a border around the video element.
 -         this._ctx.beginPath();
 -         this._ctx.lineWidth = 2;
 -         this._ctx.strokeStyle = '#A9A9A9'; // dark grey
 -         this._ctx.rect(this._canvas.width - this._videoElement.width, this._canvas.height - this._videoElement.height,
 -             this._videoElement.width, this._videoElement.height);
 -         this._ctx.stroke();
 -     }
 - 
 -     /**
 -      * Checks if the local track supports this effect.
 -      *
 -      * @param {JitsiLocalTrack} jitsiLocalTrack - Track to apply effect.
 -      * @returns {boolean} - Returns true if this effect can run on the
 -      * specified track, false otherwise.
 -      */
 -     isEnabled(jitsiLocalTrack: Object) {
 -         return jitsiLocalTrack.isVideoTrack() && jitsiLocalTrack.videoType === 'desktop';
 -     }
 - 
 -     /**
 -      * Starts loop to capture video frame and render presenter effect.
 -      *
 -      * @param {MediaStream} desktopStream - Stream to be used for processing.
 -      * @returns {MediaStream} - The stream with the applied effect.
 -      */
 -     startEffect(desktopStream: MediaStream) {
 -         const firstVideoTrack = desktopStream.getVideoTracks()[0];
 -         const { height, width } = firstVideoTrack.getSettings() ?? firstVideoTrack.getConstraints();
 - 
 -         // set the desktop element properties.
 -         this._desktopStream = desktopStream;
 -         this._desktopElement.width = parseInt(width, 10);
 -         this._desktopElement.height = parseInt(height, 10);
 -         this._desktopElement.autoplay = true;
 -         this._desktopElement.srcObject = desktopStream;
 -         this._canvas.width = parseInt(width, 10);
 -         this._canvas.height = parseInt(height, 10);
 -         this._videoFrameTimerWorker.postMessage({
 -             id: SET_INTERVAL,
 -             timeMs: 1000 / this._frameRate
 -         });
 - 
 -         return this._canvas.captureStream(this._frameRate);
 -     }
 - 
 -     /**
 -      * Stops the capture and render loop.
 -      *
 -      * @returns {void}
 -      */
 -     stopEffect() {
 -         this._videoFrameTimerWorker.postMessage({
 -             id: CLEAR_INTERVAL
 -         });
 -     }
 - 
 - }
 
 
  |