diff --git a/src/app/components/VideoCallContent.svelte b/src/app/components/VideoCallContent.svelte index 1da29813..45f82737 100644 --- a/src/app/components/VideoCallContent.svelte +++ b/src/app/components/VideoCallContent.svelte @@ -27,6 +27,7 @@ isLocal: boolean trackSid: string attachable: Track | undefined + source: Track.Source.Camera | Track.Source.ScreenShare } const {variant, url, h, visible = true, class: className = ""}: Props = $props() @@ -60,17 +61,40 @@ isLocal: true, trackSid: localPub?.trackSid ?? "local-camera", attachable: localPub?.track, + source: Track.Source.Camera, + }) + } + + if (session.screenShareOn) { + const localPub = lp.getTrackPublication(Track.Source.ScreenShare) + out.push({ + identity: lp.identity, + isLocal: true, + trackSid: localPub?.trackSid ?? "local-screen", + attachable: localPub?.track, + source: Track.Source.ScreenShare, }) } for (const rp of room.remoteParticipants.values()) { - const pub = rp.getTrackPublication(Track.Source.Camera) - if (pub?.isSubscribed && pub.track) { + const camPub = rp.getTrackPublication(Track.Source.Camera) + if (camPub?.isSubscribed && camPub.track) { out.push({ identity: rp.identity, isLocal: false, - trackSid: pub.trackSid, - attachable: pub.track, + trackSid: camPub.trackSid, + attachable: camPub.track, + source: Track.Source.Camera, + }) + } + const screenPub = rp.getTrackPublication(Track.Source.ScreenShare) + if (screenPub?.isSubscribed && screenPub.track) { + out.push({ + identity: rp.identity, + isLocal: false, + trackSid: screenPub.trackSid, + attachable: screenPub.track, + source: Track.Source.ScreenShare, }) } } @@ -85,9 +109,10 @@ } }) - const labelFor = (identity: string) => { + const labelFor = (identity: string, source: Tile["source"]) => { const pk = pubkeyFromLiveKitIdentity(identity) - return pk ? displayProfileByPubkey(pk) : "Unknown" + const name = pk ? displayProfileByPubkey(pk) : "Unknown" + return source === Track.Source.ScreenShare ? `${name} ยท screen` : name } const showTileGrid = $derived(tiles.length > 0) @@ -106,9 +131,17 @@ )}> {#if showTileGrid} {#each tiles as tile (tile.trackSid + tile.identity)} -
+
{#if tile.attachable} - + {:else}
@@ -116,15 +149,17 @@ {/if} - {labelFor(tile.identity)}{tile.isLocal ? " (you)" : ""} + {labelFor(tile.identity, tile.source)}{tile.isLocal ? " (you)" : ""}
{/each} {:else}
-

No camera video yet.

-

Use the camera control in the voice widget to share video.

+

No camera or screen share yet.

+

+ Use the camera or screen share control in the voice widget to share video. +

{/if}
diff --git a/src/app/components/VideoCallVideo.svelte b/src/app/components/VideoCallVideo.svelte index fbc3af89..ec42547e 100644 --- a/src/app/components/VideoCallVideo.svelte +++ b/src/app/components/VideoCallVideo.svelte @@ -5,10 +5,11 @@ type Props = { track: Track muted?: boolean + fit?: "cover" | "contain" class?: string } - const {track, muted = true, class: className = ""}: Props = $props() + const {track, muted = true, fit = "cover", class: className = ""}: Props = $props() let el = $state() @@ -23,5 +24,8 @@ }) - + diff --git a/src/app/components/VoiceWidget.svelte b/src/app/components/VoiceWidget.svelte index 64375bc9..8877ad48 100644 --- a/src/app/components/VoiceWidget.svelte +++ b/src/app/components/VoiceWidget.svelte @@ -8,6 +8,8 @@ import MicrophoneOff from "@assets/icons/microphone-off.svg?dataurl" import Videocamera from "@assets/icons/videocamera.svg?dataurl" import VideocameraRecord from "@assets/icons/videocamera-record.svg?dataurl" + import ScreenShare from "@assets/icons/screen-share.svg?dataurl" + import Screencast from "@assets/icons/screencast.svg?dataurl" import PhoneRounded from "@assets/icons/phone-rounded.svg?dataurl" import PhoneCallingRounded from "@assets/icons/phone-calling-rounded.svg?dataurl" import CloseCircle from "@assets/icons/close-circle.svg?dataurl" @@ -34,6 +36,7 @@ leaveVoiceRoom, toggleMute, toggleCamera, + toggleScreenShare, cancelJoinVoiceRoom, } from "@app/voice" @@ -122,6 +125,14 @@ btn-ghost" onclick={openAudioSettings}> +