import { RTCView } from "@stream-io/react-native-webrtc";
import { useCall, useCallStateHooks } from "@stream-io/video-react-native-sdk";
export const LocalVideoRenderer = () => {
const call = useCall();
const localVideoStream = call?.camera.state.mediaStream;
const { useCameraState } = useCallStateHooks();
const { status: cameraStatus } = useCameraState();
return cameraStatus === "enabled" ? (
<RTCView
streamURL={localVideoStream?.toURL()}
objectFit="cover"
style={StyleSheet.absoluteFill}
/>
) : null;
};1.44.0
The lobby camera preview is now driven by a native capturer directly — no WebRTC track is created before the call is joined. If you built a custom lobby using the old cookbook recipe, your preview will render blank after upgrading. The built-in <Lobby> component is unaffected.
🔨 What changed?
Everything continues to work at and after join — the change only affects the pre-join (lobby) window.
💡 How to migrate?
If you use the built-in <Lobby> component
No changes required. The SDK's <Lobby> uses the new LobbyCameraPreview internally.
If you built a custom lobby
Two things to update.
1. Replace the video preview
Drop RTCView + call.camera.state.mediaStream and use LobbyCameraPreview from the SDK — it renders the platform camera preview and handles permission, direction, target resolution, and mirror mode for you.
Before:
After:
import {
LobbyCameraPreview,
useCallStateHooks,
} from "@stream-io/video-react-native-sdk";
export const LocalVideoRenderer = () => {
const { useCameraState } = useCallStateHooks();
const { optimisticIsMute: cameraIsMuted } = useCameraState();
return !cameraIsMuted ? <LobbyCameraPreview objectFit="cover" /> : null;
};2. Read optimisticIsMute, not isMute or status
Toggle-button UIs and any conditional rendering that depends on the intended camera / microphone state must use optimisticIsMute from useCameraState() / useMicrophoneState(). isMute and status remain undefined until the call is joined.
const { isMute: cameraMuted } = useCameraState();
const { isMute: microphoneMuted } = useMicrophoneState();const { optimisticIsMute: cameraMuted } = useCameraState();
const { optimisticIsMute: microphoneMuted } = useMicrophoneState();See the Lobby Preview cookbook for the full updated recipe.
If you built a pre-call self-test screen
The Pre-Call Self-Test cookbook previously rendered nothing in the video area before recording started (loopbackVideoStream ? <RTCView /> : null). Swap the fallback branch for LobbyCameraPreview so users can verify their camera setup before hitting Start recording.
Before:
return (
<View style={{ flex: 1 }}>
{loopbackVideoStream ? (
<RTCView
streamURL={loopbackVideoStream.toURL()}
objectFit="cover"
style={{ flex: 1 }}
/>
) : null}
<Button title={label} onPress={onPress} disabled={isConnecting} />
</View>
);After:
return (
<View style={{ flex: 1 }}>
{loopbackVideoStream ? (
<RTCView
streamURL={loopbackVideoStream.toURL()}
objectFit="cover"
style={{ flex: 1 }}
/>
) : (
<LobbyCameraPreview objectFit="cover" />
)}
<Button title={label} onPress={onPress} disabled={isConnecting} />
</View>
);Remember to add LobbyCameraPreview to your imports from @stream-io/video-react-native-sdk.