From f7488a0474d1c0e963971dba5256fd8787e5c9fa Mon Sep 17 00:00:00 2001 From: Robin Date: Wed, 1 Apr 2026 13:16:39 +0200 Subject: [PATCH] Avoid redundantly showing the local user in the PiP tile If you are the only participant in the call, the expanded spotlight layout would redundantly show your media in both the spotlight and PiP tiles. This is a regression; in versions 0.16.1 and earlier we would avoid showing the same user twice. --- src/state/CallViewModel/CallViewModel.test.ts | 47 +++++++++++++++++++ src/state/CallViewModel/CallViewModel.ts | 7 ++- 2 files changed, 52 insertions(+), 2 deletions(-) diff --git a/src/state/CallViewModel/CallViewModel.test.ts b/src/state/CallViewModel/CallViewModel.test.ts index aca3ee7b..1fecd112 100644 --- a/src/state/CallViewModel/CallViewModel.test.ts +++ b/src/state/CallViewModel/CallViewModel.test.ts @@ -750,6 +750,53 @@ describe.each([ }); }); + test("PiP tile in expanded spotlight layout avoids redundantly showing local user", () => { + withTestScheduler(({ behavior, schedule, expectObservable }) => { + // Switch to spotlight immediately + const modeInputMarbles = " s"; + // And expand the spotlight immediately + const expandInputMarbles = " a"; + // First no one else is in the call, then Alice joins + const participantInputMarbles = "ab"; + // First local user should be in the spotlight, then they appear in PiP + // only once Alice has joined + const expectedLayoutMarbles = " ab"; + + withCallViewModel( + { + rtcMembers$: behavior(participantInputMarbles, { + a: [localRtcMember], + b: [localRtcMember, aliceRtcMember], + }), + }, + (vm) => { + schedule(modeInputMarbles, { + s: () => vm.setGridMode("spotlight"), + }); + schedule(expandInputMarbles, { + a: () => vm.toggleSpotlightExpanded$.value!(), + }); + + expectObservable(summarizeLayout$(vm.layout$)).toBe( + expectedLayoutMarbles, + { + a: { + type: "spotlight-expanded", + spotlight: [`${localId}:0`], + pip: undefined, + }, + b: { + type: "spotlight-expanded", + spotlight: [`${aliceId}:0`], + pip: `${localId}:0`, + }, + }, + ); + }, + ); + }); + }); + test("spotlight remembers whether it's expanded", () => { withTestScheduler(({ schedule, expectObservable }) => { // Start in spotlight mode, then switch to grid and back to spotlight a diff --git a/src/state/CallViewModel/CallViewModel.ts b/src/state/CallViewModel/CallViewModel.ts index 8b4d19fb..6dca08dc 100644 --- a/src/state/CallViewModel/CallViewModel.ts +++ b/src/state/CallViewModel/CallViewModel.ts @@ -951,7 +951,7 @@ export function createCallViewModel$( const spotlightAndPip$ = scope.behavior<{ spotlight: MediaViewModel[]; - pip$: Behavior; + pip$: Observable; }>( ringingMedia$.pipe( switchMap((ringingMedia) => { @@ -966,7 +966,10 @@ export function createCallViewModel$( return spotlightSpeaker$.pipe( map((speaker) => ({ spotlight: speaker ? [speaker] : [], - pip$: localUserMediaForPip$, + // Hide PiP if redundant (i.e. if local user is already in spotlight) + pip$: localUserMediaForPip$.pipe( + map((m) => (m === speaker ? undefined : m)), + ), })), ); }),