diff --git a/src/state/CallViewModel/CallViewModel.test.ts b/src/state/CallViewModel/CallViewModel.test.ts index f14f487f5..8c7ef4415 100644 --- a/src/state/CallViewModel/CallViewModel.test.ts +++ b/src/state/CallViewModel/CallViewModel.test.ts @@ -22,6 +22,7 @@ import { SyncState } from "matrix-js-sdk"; import { ConnectionState, type LocalTrackPublication, + type Participant, type RemoteParticipant, } from "livekit-client"; import * as ComponentsCore from "@livekit/components-core"; @@ -1031,6 +1032,10 @@ describe.each([ a: [localRtcMember], b: [localRtcMember, aliceRtcMember], }), + videoEnabled: new Map>([ + [localParticipant, constant(true)], + [aliceParticipant, constant(true)], + ]), }, (vm) => { schedule(modeInputMarbles, { @@ -1060,6 +1065,33 @@ describe.each([ }); }); + test("expanded spotlight layout hides PiP tile in one-on-one voice call", () => { + withTestScheduler(({ behavior, schedule, expectObservable }) => { + withCallViewModel( + { + remoteParticipants$: constant([aliceParticipant]), + roomMembers: [local, alice], + rtcMembers$: constant([localRtcMember, aliceRtcMember]), + videoEnabled: new Map>([ + [localParticipant, constant(false)], + [aliceParticipant, constant(false)], + ]), + windowSize$: constant({ width: 700, height: 380 }), // Mobile phone in landscape + }, + (vm) => { + // Layout should show remote tile only + expectObservable(summarizeLayout$(vm.layout$)).toBe("a", { + a: { + type: "spotlight-expanded", + spotlight: [`${aliceId}:0`], + pip: undefined, + }, + }); + }, + ); + }); + }); + test("spotlight remembers whether it's expanded", () => { withTestScheduler(({ schedule, expectObservable }) => { // Start in spotlight mode, then switch to grid and back to spotlight a @@ -1096,7 +1128,7 @@ describe.each([ b: { type: "spotlight-expanded", spotlight: [`${aliceId}:0`], - pip: `${localId}:0`, + pip: undefined, }, c: { type: "grid", diff --git a/src/state/CallViewModel/CallViewModel.ts b/src/state/CallViewModel/CallViewModel.ts index e39014e4b..27676cb50 100644 --- a/src/state/CallViewModel/CallViewModel.ts +++ b/src/state/CallViewModel/CallViewModel.ts @@ -942,8 +942,8 @@ export function createCallViewModel$( ); /** - * Local user media suitable for displaying in a PiP (undefined if not found - * or if user prefers to not see themselves). + * Local user media suitable for displaying in a PiP (undefined if not found, + * video is muted, or if user prefers to not see themselves). */ const localUserMediaForPip$ = scope.behavior< LocalUserMediaViewModel | undefined @@ -955,8 +955,10 @@ export function createCallViewModel$( m.type === "user" && m.local, ); if (!localUserMedia) return of(undefined); - return localUserMedia.alwaysShow$.pipe( - map((alwaysShow) => (alwaysShow ? localUserMedia : undefined)), + return combineLatest( + [localUserMedia.videoEnabled$, localUserMedia.alwaysShow$], + (videoEnabled, alwaysShow) => + videoEnabled && alwaysShow ? localUserMedia : undefined, ); }), ),