From c4aa1567d770a642d45ea961fef362d490b03226 Mon Sep 17 00:00:00 2001 From: Jared Vititoe Date: Sat, 12 Sep 2026 02:05:34 -0400 Subject: [PATCH] fix(call): answering an incoming call honours cameraOnJoin and mic/sound prefs handleAnswer hard-coded { microphone: true, video, sound: true }, so pressing Answer on a video call published the camera even with the "Join with Camera On" setting off (the default) and ignored a persisted muted/deafened preference. Build the answer prefs the same way every other join path does; PTT's forceAudioOff still applies downstream. Fixes #8 Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01PPmy3tPq869XDW4njjVaKA --- src/app/components/CallEmbedProvider.tsx | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/app/components/CallEmbedProvider.tsx b/src/app/components/CallEmbedProvider.tsx index c0621e123..56d73365b 100644 --- a/src/app/components/CallEmbedProvider.tsx +++ b/src/app/components/CallEmbedProvider.tsx @@ -58,6 +58,7 @@ import { ExitFullscreenIcon, FullscreenIcon } from '../features/call/Controls'; import { useTheme, ThemeKind } from '../hooks/useTheme'; import { useReducedMotion } from '../hooks/useReducedMotion'; import { useSetting } from '../state/hooks/settings'; +import { useCallPreferences } from '../state/hooks/callPreferences'; import { settingsAtom } from '../state/settings'; import { getStateEvent, getStateEvents, getMemberName } from '../utils/room'; import { StateEvent } from '../../types/matrix/room'; @@ -410,6 +411,8 @@ function IncomingCallListener({ callEmbed, joined }: IncomingCallListenerProps) const [callInfo, setCallInfo] = useState(); const dm = callInfo ? directs.has(callInfo.room.roomId) : false; const startCall = useCallStart(dm); + const { microphone, sound } = useCallPreferences(); + const [cameraOnJoin] = useSetting(settingsAtom, 'cameraOnJoin'); // C-L6: handleTimelineEvent awaits decryption before calling setState; guard // against the component unmounting during that await. @@ -566,11 +569,15 @@ function IncomingCallListener({ callEmbed, joined }: IncomingCallListenerProps) const handleAnswer = useCallback( (room: Room, video: boolean) => { - startCall(room, { microphone: true, video, sound: true }); + // Honour cameraOnJoin and the persisted mic/sound preferences instead of + // forcing camera+mic+sound on — every other join path does this, and + // Answer was skipping it, publishing the camera with no prescreen. + // (PTT's forceAudioOff is applied downstream inside useCallStart.) + startCall(room, { microphone, video: cameraOnJoin && video, sound }); setCallInfo(undefined); navigateRoom(room.roomId); }, - [startCall, navigateRoom], + [startCall, navigateRoom, microphone, sound, cameraOnJoin], ); if (!callInfo) return null;