From 139a046068cb9f7bed9592e64173bc99ce9317ab Mon Sep 17 00:00:00 2001 From: Oliver Lazoroski Date: Tue, 3 Oct 2023 17:06:52 +0200 Subject: [PATCH] chore: add screenshare support in ts-quickstart --- sample-apps/client/ts-quickstart/index.html | 1 + sample-apps/client/ts-quickstart/src/main.ts | 8 +- .../client/ts-quickstart/src/participant.ts | 86 ++++++++++++++++++- 3 files changed, 93 insertions(+), 2 deletions(-) diff --git a/sample-apps/client/ts-quickstart/index.html b/sample-apps/client/ts-quickstart/index.html index 78caf0e6bb..d9eec53e42 100644 --- a/sample-apps/client/ts-quickstart/index.html +++ b/sample-apps/client/ts-quickstart/index.html @@ -8,6 +8,7 @@
+
diff --git a/sample-apps/client/ts-quickstart/src/main.ts b/sample-apps/client/ts-quickstart/src/main.ts index 81f5a969ad..8a23d74f56 100644 --- a/sample-apps/client/ts-quickstart/src/main.ts +++ b/sample-apps/client/ts-quickstart/src/main.ts @@ -39,6 +39,11 @@ const client = new StreamVideoClient({ }); const call = client.call('default', callId); +// @ts-ignore +window.call = call; +// @ts-ignore +window.client = client; + call.screenShare.enableScreenShareAudio(); call.screenShare.setSettings({ maxFramerate: 10, @@ -74,13 +79,14 @@ window.addEventListener('beforeunload', () => { call.leave(); }); +const screenShareContainer = document.getElementById('screenshare')!; const parentContainer = document.getElementById('participants')!; call.setViewport(parentContainer); call.state.participants$.subscribe((participants) => { // render / update existing participants participants.forEach((participant) => { - renderParticipant(call, participant, parentContainer); + renderParticipant(call, participant, parentContainer, screenShareContainer); }); // Remove stale elements for stale participants diff --git a/sample-apps/client/ts-quickstart/src/participant.ts b/sample-apps/client/ts-quickstart/src/participant.ts index 9e986ecc89..1ddb7e3399 100644 --- a/sample-apps/client/ts-quickstart/src/participant.ts +++ b/sample-apps/client/ts-quickstart/src/participant.ts @@ -1,4 +1,8 @@ -import { Call, StreamVideoParticipant } from '@stream-io/video-client'; +import { + Call, + SfuModels, + StreamVideoParticipant, +} from '@stream-io/video-client'; // The quickstart uses fixed video dimensions for simplification const videoDimension = { @@ -73,13 +77,79 @@ const renderAudio = ( } }; +const renderScreenShare = ( + call: Call, + participant: StreamVideoParticipant, + screenShareContainer: HTMLElement, +) => { + const { publishedTracks } = participant; + + if (publishedTracks.includes(SfuModels.TrackType.SCREEN_SHARE)) { + const videoId = `screen-${participant.sessionId}`; + let screenEl = document.getElementById(videoId) as HTMLVideoElement | null; + if (!screenEl) { + screenEl = document.createElement('video'); + screenEl.style.setProperty('object-fit', 'contain'); + screenEl.id = videoId; + screenEl.width = videoDimension.width; + screenEl.height = videoDimension.height; + screenEl.dataset.sessionId = participant.sessionId; + + screenShareContainer.appendChild(screenEl); + + const untrack = call.trackElementVisibility( + screenEl, + participant.sessionId, + 'screenShareTrack', + ); + + // keep reference to untrack function to call it later + videoTrackingCache.set(videoId, untrack); + + // registers subscription updates and stream changes + const unbind = call.bindVideoElement( + screenEl, + participant.sessionId, + 'screenShareTrack', + ); + + // keep reference to unbind function to call it later + videoBindingsCache.set(videoId, unbind); + } + } + + if (publishedTracks.includes(SfuModels.TrackType.SCREEN_SHARE_AUDIO)) { + const audioId = `screen-audio-${participant.sessionId}`; + let audioEl = document.getElementById(audioId) as HTMLAudioElement | null; + if (!audioEl) { + audioEl = document.createElement('audio'); + audioEl.id = audioId; + audioEl.dataset.sessionId = participant.sessionId; + + screenShareContainer.appendChild(audioEl); + + // registers subscription updates and stream changes for audio + const unbind = call.bindAudioElement( + audioEl, + participant.sessionId, + 'screenShareAudioTrack', + ); + + // keep reference to unbind function to call it later + audioBindingsCache.set(audioId, unbind); + } + } +}; + export const renderParticipant = ( call: Call, participant: StreamVideoParticipant, parentContainer: HTMLElement, + screenShareContainer: HTMLElement, ) => { renderAudio(call, participant, parentContainer); renderVideo(call, participant, parentContainer); + renderScreenShare(call, participant, screenShareContainer); }; export const cleanupParticipant = (sessionId: string) => { @@ -100,4 +170,18 @@ export const cleanupParticipant = (sessionId: string) => { unbindAudio(); audioBindingsCache.delete(`audio-${sessionId}`); } + + const unbindScreenShareVideo = videoBindingsCache.get(`screen-${sessionId}`); + if (unbindScreenShareVideo) { + unbindScreenShareVideo(); + videoBindingsCache.delete(`screen-${sessionId}`); + } + + const unbundScreenShareAudio = audioBindingsCache.get( + `screen-audio-${sessionId}`, + ); + if (unbundScreenShareAudio) { + unbundScreenShareAudio(); + audioBindingsCache.delete(`screen-audio-${sessionId}`); + } };