From 208b91e52a476869e6dca7b917ae976f6152f4d6 Mon Sep 17 00:00:00 2001 From: Gregoire Parant Date: Sat, 6 Jun 2020 17:03:10 +0200 Subject: [PATCH] Feature screen sharing - Send stream of screen sharing in peer connexion - Add button for share your screen --- front/dist/index.html | 11 +++ front/dist/resources/logos/monitor-close.svg | 44 ++++++++++++ front/dist/resources/logos/monitor.svg | 15 ++++ front/dist/resources/style/style.css | 4 ++ front/src/WebRtc/MediaManager.ts | 73 ++++++++++++++++++++ front/src/WebRtc/SimplePeer.ts | 58 ++++++++-------- 6 files changed, 174 insertions(+), 31 deletions(-) create mode 100644 front/dist/resources/logos/monitor-close.svg create mode 100644 front/dist/resources/logos/monitor.svg diff --git a/front/dist/index.html b/front/dist/index.html index 92a7bf3c..360d5a9a 100644 --- a/front/dist/index.html +++ b/front/dist/index.html @@ -77,6 +77,10 @@ +
+ + +
@@ -100,6 +104,13 @@ +
+ + +
+ --> diff --git a/front/dist/resources/logos/monitor-close.svg b/front/dist/resources/logos/monitor-close.svg new file mode 100644 index 00000000..80056e2d --- /dev/null +++ b/front/dist/resources/logos/monitor-close.svg @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/front/dist/resources/logos/monitor.svg b/front/dist/resources/logos/monitor.svg new file mode 100644 index 00000000..d4b586c6 --- /dev/null +++ b/front/dist/resources/logos/monitor.svg @@ -0,0 +1,15 @@ + + + + + + diff --git a/front/dist/resources/style/style.css b/front/dist/resources/style/style.css index 30e099ef..413bce71 100644 --- a/front/dist/resources/style/style.css +++ b/front/dist/resources/style/style.css @@ -109,6 +109,10 @@ video#myCamVideo{ transition: all .2s; right: 134px; } +.btn-monitor{ + transition: all .2s; + right: 224px; +} /*.btn-call{ transition: all .1s; left: 0px; diff --git a/front/src/WebRtc/MediaManager.ts b/front/src/WebRtc/MediaManager.ts index 39a61738..a11532ac 100644 --- a/front/src/WebRtc/MediaManager.ts +++ b/front/src/WebRtc/MediaManager.ts @@ -5,6 +5,9 @@ const videoConstraint: boolean|MediaTrackConstraints = { height: { ideal: 720 }, facingMode: "user" }; +interface MediaServiceInterface extends MediaDevices{ + getDisplayMedia(constrain: any) : Promise; +} type UpdatedLocalStreamCallback = (media: MediaStream) => void; @@ -12,10 +15,13 @@ type UpdatedLocalStreamCallback = (media: MediaStream) => void; // TODO: verify that microphone event listeners are not triggered plenty of time NOW (since MediaManager is created many times!!!!) export class MediaManager { localStream: MediaStream|null = null; + localScreenCapture: MediaStream|null = null; private remoteVideo: Map = new Map(); myCamVideo: HTMLVideoElement; cinemaClose: HTMLImageElement; cinema: HTMLImageElement; + monitorClose: HTMLImageElement; + monitor: HTMLImageElement; microphoneClose: HTMLImageElement; microphone: HTMLImageElement; webrtcInAudio: HTMLAudioElement; @@ -57,6 +63,21 @@ export class MediaManager { this.disabledCamera(); //update tracking }); + + this.monitorClose = document.getElementById('monitor-close'); + this.monitorClose.style.display = "block"; + this.monitorClose.addEventListener('click', (e: any) => { + e.preventDefault(); + this.enabledMonitor(); + //update tracking + }); + this.monitor = document.getElementById('monitor'); + this.monitor.style.display = "none"; + this.monitor.addEventListener('click', (e: any) => { + e.preventDefault(); + this.disabledMonitor(); + //update tracking + }); } onUpdateLocalStream(callback: UpdatedLocalStreamCallback): void { @@ -126,6 +147,58 @@ export class MediaManager { }); } + enabledMonitor() { + this.monitorClose.style.display = "none"; + this.monitor.style.display = "block"; + this.getScreenMedia().then((stream) => { + this.updatedLocalStreamCallBack(stream); + }); + } + + disabledMonitor() { + this.monitorClose.style.display = "block"; + this.monitor.style.display = "none"; + this.localScreenCapture?.getTracks().forEach((track: MediaStreamTrack) => { + track.stop(); + }); + this.localScreenCapture = null; + this.getCamera().then((stream) => { + this.updatedLocalStreamCallBack(stream); + }); + } + + //get screen + getScreenMedia() : Promise{ + try { + return this._startScreenCapture() + .then((stream: MediaStream) => { + this.localScreenCapture = stream; + return stream; + }) + .catch((err: any) => { + console.error("Error => getScreenMedia => " + err); + throw err; + }); + }catch (err) { + return new Promise((resolve, reject) => { // eslint-disable-line no-unused-vars + reject(err); + }); + } + } + + private _startScreenCapture() { + if ((navigator as any).getDisplayMedia) { + return (navigator as any).getDisplayMedia({video: true}); + } else if ((navigator.mediaDevices as any).getDisplayMedia) { + return (navigator.mediaDevices as any).getDisplayMedia({video: true}); + } else { + //return navigator.mediaDevices.getUserMedia(({video: {mediaSource: 'screen'}} as any)); + return new Promise((resolve, reject) => { // eslint-disable-line no-unused-vars + reject("error sharing screen"); + }); + } + } + //get camera async getCamera(): Promise { if (navigator.mediaDevices === undefined) { diff --git a/front/src/WebRtc/SimplePeer.ts b/front/src/WebRtc/SimplePeer.ts index fdc2d0c2..96f047b7 100644 --- a/front/src/WebRtc/SimplePeer.ts +++ b/front/src/WebRtc/SimplePeer.ts @@ -156,22 +156,11 @@ export class SimplePeer { videoActive = true; } }); - if(microphoneActive){ - mediaManager.enabledMicrophoneByUserId(user.userId); - }else{ - mediaManager.disabledMicrophoneByUserId(user.userId); - } - if(videoActive){ - mediaManager.enabledVideoByUserId(user.userId); - }else{ - mediaManager.disabledVideoByUserId(user.userId); - } this.stream(user.userId, stream); }); /*peer.on('track', (track: MediaStreamTrack, stream: MediaStream) => { - this.stream(user.userId, stream); });*/ peer.on('close', () => { @@ -190,9 +179,19 @@ export class SimplePeer { }); peer.on('data', (chunk: Buffer) => { - const data = JSON.parse(chunk.toString('utf8')); - if(data.type === "stream"){ - this.stream(user.userId, data.stream); + let constraint = JSON.parse(chunk.toString('utf8')); + + if (constraint.audio) { + mediaManager.enabledMicrophoneByUserId(user.userId); + } else { + mediaManager.disabledMicrophoneByUserId(user.userId); + } + + if (constraint.video) { + mediaManager.enabledVideoByUserId(user.userId); + } else { + this.stream(user.userId); + mediaManager.disabledVideoByUserId(user.userId); } }); @@ -279,7 +278,7 @@ export class SimplePeer { * @param userId * @param stream */ - private stream(userId : string, stream: MediaStream) { + private stream(userId : string, stream?: MediaStream) { if(!stream){ mediaManager.disabledVideoByUserId(userId); mediaManager.disabledMicrophoneByUserId(userId); @@ -294,24 +293,21 @@ export class SimplePeer { */ private addMedia (userId : string) { try { - const localStream: MediaStream|null = mediaManager.localStream; - const peer = this.PeerConnectionArray.get(userId); - if(localStream === null) { - //send fake signal - if(peer === undefined){ - return; - } - peer.write(new Buffer(JSON.stringify({ - type: "stream", - stream: null - }))); - return; - } + let localStream: MediaStream | null = mediaManager.localStream; + let localScreenCapture: MediaStream | null = mediaManager.localScreenCapture; + let peer = this.PeerConnectionArray.get(userId); if (peer === undefined) { - throw new Error('While adding media, cannot find user with ID '+userId); + throw new Error('While adding media, cannot find user with ID ' + userId); } - for (const track of localStream.getTracks()) { - peer.addTrack(track, localStream); + peer.write(new Buffer(JSON.stringify(mediaManager.constraintsMedia))); + if (localScreenCapture !== null) { + for (const track of localScreenCapture.getTracks()) { + peer.addTrack(track, localScreenCapture); + } + } else if (localStream) { + for (const track of localStream.getTracks()) { + peer.addTrack(track, localStream); + } } }catch (e) { console.error(`addMedia => addMedia => ${userId}`, e);