From c05ea63dae222eae57c2c2c03bf229d26a1b0212 Mon Sep 17 00:00:00 2001 From: Ben Cherry Date: Wed, 7 May 2025 09:05:41 -0700 Subject: [PATCH] Add screenshare support (#138) --- .../config/ConfigurationPanelItem.tsx | 19 +++++----- src/components/playground/Playground.tsx | 35 +++++++++++++++---- .../playground/SettingsDropdown.tsx | 9 +++-- src/hooks/useConfig.tsx | 4 +++ 4 files changed, 50 insertions(+), 17 deletions(-) diff --git a/src/components/config/ConfigurationPanelItem.tsx b/src/components/config/ConfigurationPanelItem.tsx index ba2c33f..6b2abf1 100644 --- a/src/components/config/ConfigurationPanelItem.tsx +++ b/src/components/config/ConfigurationPanelItem.tsx @@ -6,29 +6,30 @@ import { Track } from "livekit-client"; type ConfigurationPanelItemProps = { title: string; children?: ReactNode; - deviceSelectorKind?: MediaDeviceKind; + source?: Track.Source; }; export const ConfigurationPanelItem: React.FC = ({ children, title, - deviceSelectorKind, + source, }) => { return (

{title}

- {deviceSelectorKind && ( + {source && ( - + {source === Track.Source.Camera && ( + + )} + {source === Track.Source.Microphone && ( + + )} )}
diff --git a/src/components/playground/Playground.tsx b/src/components/playground/Playground.tsx index 888fc34..ec1db3d 100644 --- a/src/components/playground/Playground.tsx +++ b/src/components/playground/Playground.tsx @@ -79,9 +79,12 @@ export default function Playground({ const localTracks = tracks.filter( ({ participant }) => participant instanceof LocalParticipant ); - const localVideoTrack = localTracks.find( + const localCameraTrack = localTracks.find( ({ source }) => source === Track.Source.Camera ); + const localScreenTrack = localTracks.find( + ({ source }) => source === Track.Source.ScreenShare + ); const localMicTrack = localTracks.find( ({ source }) => source === Track.Source.Microphone ); @@ -339,15 +342,34 @@ export default function Playground({ />
- {localVideoTrack && ( + {roomState === ConnectionState.Connected && config.settings.inputs.screen && ( + + {localScreenTrack ? ( +
+ +
+ ) : ( +
+ Press the button above to share your screen. +
+ )} +
+ )} + {localCameraTrack && (
@@ -355,7 +377,7 @@ export default function Playground({ {localMicTrack && ( @@ -389,7 +411,8 @@ export default function Playground({ localParticipant, name, roomState, - localVideoTrack, + localCameraTrack, + localScreenTrack, localMicTrack, themeColors, setUserSettings, diff --git a/src/components/playground/SettingsDropdown.tsx b/src/components/playground/SettingsDropdown.tsx index 6f3e2cc..3fcb943 100644 --- a/src/components/playground/SettingsDropdown.tsx +++ b/src/components/playground/SettingsDropdown.tsx @@ -47,6 +47,11 @@ const settingsDropdown: SettingValue[] = [ type: "inputs", key: "mic", }, + { + title: "Allow screenshare", + type: "inputs", + key: "screen", + }, ]; export const SettingsDropdown = () => { @@ -59,7 +64,7 @@ export const SettingsDropdown = () => { } if(setting.type === "inputs") { - const key = setting.key as "camera" | "mic"; + const key = setting.key as "camera" | "mic" | "screen"; return config.settings.inputs[key]; } else if(setting.type === "outputs") { const key = setting.key as "video" | "audio"; @@ -77,7 +82,7 @@ export const SettingsDropdown = () => { if(setting.type === "chat") { newSettings.chat = newValue; } else if(setting.type === "inputs") { - newSettings.inputs[setting.key as "camera" | "mic"] = newValue; + newSettings.inputs[setting.key as "camera" | "mic" | "screen"] = newValue; } else if(setting.type === "outputs") { newSettings.outputs[setting.key as "video" | "audio"] = newValue; } diff --git a/src/hooks/useConfig.tsx b/src/hooks/useConfig.tsx index fe4e6e5..16dd556 100644 --- a/src/hooks/useConfig.tsx +++ b/src/hooks/useConfig.tsx @@ -26,6 +26,7 @@ export type UserSettings = { chat: boolean; inputs: { camera: boolean; + screen: boolean; mic: boolean; }; outputs: { @@ -49,6 +50,7 @@ const defaultConfig: AppConfig = { chat: true, inputs: { camera: true, + screen: true, mic: true, }, outputs: { @@ -117,6 +119,7 @@ export const ConfigProvider = ({ children }: { children: React.ReactNode }) => { theme_color: params.get("theme_color"), inputs: { camera: params.get("cam") === "1", + screen: params.get("screen") === "1", mic: params.get("mic") === "1", }, outputs: { @@ -148,6 +151,7 @@ export const ConfigProvider = ({ children }: { children: React.ReactNode }) => { const obj = new URLSearchParams({ cam: boolToString(us.inputs.camera), mic: boolToString(us.inputs.mic), + screen: boolToString(us.inputs.screen), video: boolToString(us.outputs.video), audio: boolToString(us.outputs.audio), chat: boolToString(us.chat),