From 9255683d8c1f73fea2ee7803f69f9440cd792823 Mon Sep 17 00:00:00 2001 From: Jannis Braun <151788261+TheZwiss@users.noreply.github.com> Date: Wed, 11 Mar 2026 00:34:52 +0100 Subject: [PATCH] fix: display real avatars and resolved names in PiP overlay Use useVoiceParticipantMeta hook to resolve avatar and display name from space/DM member stores, matching VoiceUser and StreamTile behavior. --- .../src/components/voice/PictureInPicture.tsx | 24 ++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/packages/web/src/components/voice/PictureInPicture.tsx b/packages/web/src/components/voice/PictureInPicture.tsx index 6c832f3b..316a7375 100644 --- a/packages/web/src/components/voice/PictureInPicture.tsx +++ b/packages/web/src/components/voice/PictureInPicture.tsx @@ -6,6 +6,15 @@ import { useUIStore } from '../../stores/uiStore'; import { useSpaceStore } from '../../stores/spaceStore'; import { Avatar } from '../ui/Avatar'; import type { ParticipantInfo } from '../../hooks/useLiveKit'; +import { useVoiceParticipantMeta } from '../../hooks/useVoiceParticipantMeta'; + +/** Stable fallback for useVoiceParticipantMeta when no participant exists */ +const EMPTY_PARTICIPANT: ParticipantInfo = { + identity: '', userId: '', username: '', homeUserId: null, + isMuted: false, isDeafened: false, isCameraOn: false, isScreenSharing: false, + isLocal: false, audioTrack: null, videoTrack: null, screenTrack: null, + screenAudioTrack: null, lkVideoTrack: null, lkScreenTrack: null, +}; const PIP_WIDTH = 320; const PIP_HEIGHT = 180; @@ -307,11 +316,19 @@ export function PictureInPicture() { setPipCollapsed(true); }, [setPipCollapsed]); + // Compute displayParticipant before early return so hook is called unconditionally + const displayParticipant = useMemo( + () => selectedStream?.participant ?? fallbackParticipant, + [selectedStream, fallbackParticipant], + ); + + const { displayName: resolvedName, avatar: resolvedAvatar } = + useVoiceParticipantMeta(displayParticipant ?? EMPTY_PARTICIPANT); + if (!shouldShow) return null; - const displayParticipant = selectedStream?.participant ?? fallbackParticipant; const displayName = displayParticipant - ? (displayParticipant.isLocal ? `${displayParticipant.username} (You)` : displayParticipant.username) + ? (displayParticipant.isLocal ? `${resolvedName} (You)` : resolvedName) : channelName; const hasVideo = selectedStream !== null; const isScreen = selectedStream?.type === 'screen'; @@ -349,7 +366,8 @@ export function PictureInPicture() { {displayParticipant ? (