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)), + ), })), ); }),