From fd57f34a559fd9c15e9d0179f494e1142df1886d Mon Sep 17 00:00:00 2001 From: Xin Wang Date: Mon, 13 Jul 2026 07:05:06 +0800 Subject: [PATCH] Refactor camera handling and video stream management in Assistant and MobileCall pages - Remove direct camera start/stop calls and replace them with streamlined video stream handling. - Update DebugVideoPanel to accept a streamOverride for better flexibility in video source management. - Adjust MobileCallPage to utilize the new videoStream state, enhancing the call experience. - Introduce videoStream state management in useVoicePreview for improved media handling during voice interactions. --- .../src/components/pages/AssistantPage.tsx | 40 ++++++++----------- .../src/components/pages/MobileCallPage.tsx | 33 +++++---------- frontend/src/hooks/use-voice-preview.ts | 15 +++++++ 3 files changed, 43 insertions(+), 45 deletions(-) diff --git a/frontend/src/components/pages/AssistantPage.tsx b/frontend/src/components/pages/AssistantPage.tsx index a13ff37..b46fcb5 100644 --- a/frontend/src/components/pages/AssistantPage.tsx +++ b/frontend/src/components/pages/AssistantPage.tsx @@ -2155,11 +2155,8 @@ function DebugDrawer({ const [dynamicVariableValues, setDynamicVariableValues] = useState< Record >({}); - const stopCamera = camera.stop; - const startCamera = camera.start; const recording = preview.status === "connecting" || preview.status === "connected"; - const shouldKeepCamera = vision && recording; const dynamicVariableEntries = Object.entries(dynamicVariableDefinitions); const resolvedDynamicVariables: Record = {}; let dynamicVariablesError = ""; @@ -2174,18 +2171,10 @@ function DebugDrawer({ resolvedDynamicVariables[name] = value; } - useEffect(() => { - if (shouldKeepCamera) { - void startCamera(); - } else { - stopCamera(); - } - }, [shouldKeepCamera, startCamera, stopCamera]); - const selectCamera = useCallback( async (deviceId: string) => { - const nextStream = await camera.selectCamera(deviceId); - await preview.replaceVideoStream(nextStream); + await camera.selectCamera(deviceId); + preview.selectCamera(deviceId); }, [camera, preview], ); @@ -2666,15 +2655,12 @@ function DebugVoicePanel({ const startConversation = useCallback(async () => { if (!assistantId || hasUnsavedChanges) return; if (dynamicVariablesError) return; - const videoStream = vision ? await camera.start() : null; await connect({ visionEnabled: vision, - videoStream, dynamicVariables, }); }, [ assistantId, - camera, connect, dynamicVariables, dynamicVariablesError, @@ -2695,7 +2681,7 @@ function DebugVoicePanel({ connect={startConversation} /> ) : ( - + ) ) : !SHOW_VOICE_VIZ || showTranscript ? ( showIdleHub ? ( @@ -2955,19 +2941,27 @@ function DebugIdleHub({ ); } -function DebugVideoPanel({ camera }: { camera: CameraPreview }) { +function DebugVideoPanel({ + camera, + streamOverride, +}: { + camera: CameraPreview; + streamOverride?: MediaStream | null; +}) { const { stream, error, starting, active } = camera; + const effectiveStream = streamOverride ?? stream; + const effectiveActive = Boolean(effectiveStream) || active; const videoRef = useRef(null); useEffect(() => { - if (videoRef.current) videoRef.current.srcObject = stream; - }, [stream]); + if (videoRef.current) videoRef.current.srcObject = effectiveStream; + }, [effectiveStream]); return (