# Use Nosmai Effects with LiveKit in Flutter

> Publish the processed Flutter camera feed to LiveKit on Android and iOS through the official Nosmai LiveKit bridge.

> For AI agents: the complete documentation index is at https://nosmai.com/llms/effects.txt

Product: Nosmai Effects
Group: integrations
Source: https://nosmai.com/docs/effects/integrations/livekit/flutter/

## Streaming path

![Nosmai processes camera frames before LiveKit publishes them](/images/docs/livekit-streaming-flow-v1.svg)

Nosmai owns the camera and preview. The bridge creates a LiveKit video track
from the processed native output, while LiveKit manages the room and transport.

## Prerequisites

- A working [Flutter quickstart](/docs/effects/quickstart/flutter/)
- A LiveKit server URL and participant token
- iOS 15 or later, or Android API 24 or later
- A physical arm64 device

## Install the packages

```yaml
dependencies:
  nosmai_effects_sdk: ^1.0.2
  nosmai_livekit_bridge:
    git:
      url: https://github.com/nosmai/nosmai_livekit_bridge.git
  livekit_client: ^2.6.4
```

The Android host application must still package the verified Nosmai AAR. The
iOS host resolves the native SDK through CocoaPods.

## Register the shared context first

Call `registerShareContext` before Nosmai initialization. This order lets the
Android encoder read the textures produced by Nosmai. The call is a no-op on
iOS.

```dart
await NosmaiLiveKitBridge.registerShareContext();

final initialized = await NosmaiFlutter.initialize(nosmaiLicenseKey);
if (!initialized) {
  throw StateError('Nosmai initialization was not accepted');
}
```

Keep one `NosmaiCameraPreview` mounted for the full session. Do not create a
LiveKit camera track.

```dart
const NosmaiCameraPreview()
```

## Publish the processed track

```dart
final room = Room(
  roomOptions: const RoomOptions(
    stopLocalTrackOnUnpublish: false,
    defaultVideoPublishOptions: VideoPublishOptions(simulcast: false),
  ),
);

await room.connect(liveKitUrl, liveKitToken);

final track = await NosmaiLiveKitBridge.createVideoTrack();
await room.localParticipant!.publishVideoTrack(track);
```

Apply and switch effects through `NosmaiFlutter`. Switch the camera through
Nosmai as well, because LiveKit does not own capture on this path.

## Stop in the correct order

```dart
await NosmaiLiveKitBridge.stopStreaming();
await room.disconnect();
```

Stop the bridge before disconnecting the room so it can release its native
track and graphics resources safely.

## Common errors

| Symptom | Cause | Fix |
| --- | --- | --- |
| Local preview works but remote video is black | The shared context was registered after Nosmai initialization | Await `registerShareContext` before `NosmaiFlutter.initialize` |
| No frames are published | `NosmaiCameraPreview` is not mounted | Keep one preview mounted throughout the session |
| Remote video is raw or the camera is busy | LiveKit also created a camera track | Publish only the track returned by `createVideoTrack` |
| A second session freezes | The first bridge session was not stopped | Pair each successful start with `stopStreaming` |

## Verify it worked

Apply a visible effect and join the room from a second participant. Confirm the
remote video is filtered and remains stable after camera switch, stop, and
rejoin.

## Complete example

Use the maintained [Nosmai LiveKit bridge example](https://github.com/nosmai/nosmai_livekit_bridge/tree/main/example)
for the full screen, token configuration, filter picker, and teardown flow.

## Next steps

- [Compare live-streaming routes](/docs/effects/integrations/live-streaming/)
- [Review the Flutter platform guide](/docs/effects/platforms/flutter/)
- [Understand off-screen rendering](/docs/effects/concepts/off-screen-rendering/)

## References

- [Nosmai LiveKit bridge](https://github.com/nosmai/nosmai_livekit_bridge)
- [LiveKit Flutter SDK](https://github.com/livekit/client-sdk-flutter)
