# 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:

```tsx label="Before"
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;
};
```

After:

```tsx label="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.

```tsx label="Before"
const { isMute: cameraMuted } = useCameraState();
const { isMute: microphoneMuted } = useMicrophoneState();
```

```tsx label="After"
const { optimisticIsMute: cameraMuted } = useCameraState();
const { optimisticIsMute: microphoneMuted } = useMicrophoneState();
```

See the [Lobby Preview cookbook](https://getstream.io/video/docs/react-native/ui-cookbook/lobby-preview/) for the full updated recipe.

### If you built a pre-call self-test screen

The [Pre-Call Self-Test cookbook](https://getstream.io/video/docs/react-native/ui-cookbook/pre-call-self-test/) 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:

```tsx label="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:

```tsx label="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`.


---

This page was last updated at 2026-08-19T08:17:22.228Z.

For the most recent version of this documentation, visit [https://getstream.io/video/docs/react-native/migration-guides/1.44.0/](https://getstream.io/video/docs/react-native/migration-guides/1.44.0/).