LiveKit Flutter

Flutter plugin for real-time audio and video calls in Meeting Place SDK, using LiveKit for media transport, Matrix RTC for signalling, and per-participant end-to-end encryption.

The meeting_place_livekit_flutter plugin provides real-time audio and video call rendering for Flutter applications built on the Meeting Place SDK. It bridges the Matrix transport layer to LiveKit media transport with per-participant end-to-end encryption, and integrates with the meeting_place_matrix SDK to enable audio and video calls in Matrix-backed chat sessions.

Core Concepts

  • LiveKit: an open-source, scalable Selective Forwarding Unit (SFU) for real-time media transport of audio and video calls.
  • WebRTC: an open standard for peer-to-peer multimedia communication over IP networks, enabling audio and video streaming.
  • Matrix RTC: a Matrix extension for managing call signalling and end-to-end encryption of real-time media via Matrix rooms.
  • End-to-End Encryption (E2EE): per-participant encryption of call media streams using keys distributed by Matrix RTC, ensuring only authorised participants can decrypt media.

Requirements

  • Flutter >=3.24.0.
  • Dart SDK >=3.8.0.
  • meeting_place_matrix SDK with a MatrixConfig that includes livekitServiceUrl and livekitSfuUrl.
  • Vodozemac encryption runtime initialised once in main() before creating the SDK. See the meeting_place_matrix README for details.

Install Dependency

Package: meeting_place_livekit_flutter

flutter pub add meeting_place_livekit_flutter

Alternatively, add the package to your pubspec.yaml file manually:

dependencies:
  meeting_place_livekit_flutter: ^<version_number>

Then install it:

flutter pub get

Check the latest version on the pub.dev registry or view the source on GitHub.

Usage

Integrate the plugin into MeetingPlaceMatrixSDK.create() to handle audio and video calls. Set up in this order:

import 'package:flutter_vodozemac/flutter_vodozemac.dart' as fvod;

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await fvod.init();
  // Continue with app startup
}
config: MatrixConfig(
  // ... other settings ...
  livekitServiceUrl: Uri.parse('https://your-livekit-jwt-service'),
  livekitSfuUrl: Uri.parse('wss://your-livekit-sfu'),
)
import 'package:flutter/widgets.dart';
import 'package:meeting_place_livekit_flutter/meeting_place_livekit_flutter.dart';
import 'package:meeting_place_matrix/meeting_place_matrix.dart';

final matrixSDK = await MeetingPlaceMatrixSDK.create(
  wallet: wallet,
  repositoryConfig: repositoryConfig,
  config: matrixConfig,  // With livekitServiceUrl and livekitSfuUrl
  rtcDelegate: FlutterMatrixRTCDelegate(),
  roomFactory: (_) => FlutterLiveKitRoom(),
  options: MeetingPlaceMatrixSdkOptions(
    // ... options
  ),
);
final chatSDK = await MeetingPlaceMatrixChatSDK.initialiseFromChannel(
  channel,
  coreSDK: matrixSDK,
  chatRepository: chatRepository,
);

final chat = await chatSDK.startChatSession();

Once set up, audio and video calls within Matrix rooms use Matrix RTC for signalling and LiveKit for media transport, with per-participant end-to-end encryption handled automatically.

For additional usage examples, see the example folder on GitHub.

Classes and Methods

AudioVideoCallView

A StatelessWidget that renders the video track for a call participant. It returns SizedBox.shrink when hasVideo is false, the session is not LiveKit-backed, or the room has no renderable track for the given participantId.

hasVideo must reflect whether participantId currently has an active video track. Pass it from the controller state so the widget rebuilds only when the caller decides, not via an internal stream subscription.

AudioVideoCallView (constructor)

Creates an AudioVideoCallView widget.

Parameters

session AudioVideoCallSession? Required
The active call session. Pass null when there is no ongoing call.
participantId String Required
The unique identifier of the participant whose video track should be rendered.
hasVideo bool Required
Whether the participant currently has an active video track. Derive this from the controller state rather than an internal stream so that the widget rebuilds at the correct time.
key Key? Optional
An optional widget key.
mirror bool Optional
When true, mirrors the video view for the local camera preview. The view is mirrored only while the front camera is active. Peers are never mirrored. Defaults to false.

Example

import 'package:meeting_place_livekit_flutter/meeting_place_livekit_flutter.dart';

@override
Widget build(BuildContext context, WidgetRef ref) {
  final session = ref.watch(provider.select((s) => s.session));
  final hasVideo = ref.watch(
    provider.select(
      (s) =>
          s.participants
              .firstWhereOrNull((p) => p.participantId == participantId)
              ?.hasVideo ??
          false,
    ),
  );

  return AudioVideoCallView(
    session: session,
    participantId: participantId,
    hasVideo: hasVideo,
  );
}

FlutterLiveKitRoom

Concrete LiveKit implementation of LiveKitRoom. Owns all livekit_client types so they do not leak into the SDK layer. Converts LiveKit events and participants into domain objects before publishing them through the interface.

FlutterLiveKitRoom (constructor)

Creates an instance of FlutterLiveKitRoom.

Parameters

logger MeetingPlaceCoreSDKLogger? Optional
Optional logger for diagnostic output.
hardware Hardware? Optional
Optional hardware configuration for audio and video devices.

Example

import 'package:meeting_place_livekit_flutter/meeting_place_livekit_flutter.dart';
import 'package:meeting_place_matrix/meeting_place_matrix.dart';

final matrixSDK = await MeetingPlaceMatrixSDK.create(
  wallet: wallet,
  repositoryConfig: repositoryConfig,
  config: matrixConfig,
  rtcDelegate: FlutterMatrixRTCDelegate(),
  roomFactory: (_) => FlutterLiveKitRoom(),
);

Properties

ownParticipantId String? Optional
The identity of the local participant in the room, or null when not connected.
participants List<AudioVideoCallParticipant> Optional
A snapshot of all current call participants mapped to domain objects.

connect

Connects to the LiveKit SFU at the given URL using the provided access token.

Parameters

url String Required
The WebSocket URL of the LiveKit SFU (for example, wss://your-livekit-sfu).
token String Required
The LiveKit access token for this participant.
participantIdToDid Map<String, String> Optional
A map of LiveKit participant identities to their corresponding DIDs. Defaults to an empty map.
onE2EEStateChanged OnCallE2EEStateChanged? Optional
Callback invoked when the E2EE state changes for a participant.
onParticipantDisconnected OnParticipantDisconnected? Optional
Callback invoked when a participant disconnects from the room.
onParticipantsChanged void Function()? Optional
Callback invoked whenever the participant list changes.

Example

import 'package:meeting_place_livekit_flutter/meeting_place_livekit_flutter.dart';

final room = FlutterLiveKitRoom();

await room.connect(
  url: 'wss://your-livekit-sfu',
  token: livekitAccessToken,
  participantIdToDid: {'alice-livekit-id': 'did:example:alice'},
  onParticipantsChanged: () => setState(() {}),
  onE2EEStateChanged: (participantId, state) {
    debugPrint('E2EE state for $participantId: $state');
  },
);

disconnect

Disconnects from the room and releases all resources.

Parameters

No parameters required.

Example

await room.disconnect();

setCameraEnabled

Enables or disables the local camera.

Parameters

enabled bool Required
Pass true to enable the camera or false to disable it.

Example

// Disable the camera
await room.setCameraEnabled(false);

// Enable the camera
await room.setCameraEnabled(true);

setMicrophoneEnabled

Enables or disables the local microphone.

Parameters

enabled bool Required
Pass true to enable the microphone or false to mute it.

Example

// Mute the microphone
await room.setMicrophoneEnabled(false);

setSpeakerphoneEnabled

Routes audio through the loudspeaker (true) or the earpiece (false).

Parameters

enabled bool Required
Pass true to route audio through the loudspeaker or false for the earpiece.

Example

await room.setSpeakerphoneEnabled(true);

switchCamera

Switches between the front and rear camera.

Parameters

No parameters required.

Example

await room.switchCamera();

setSharedKey

Sets the shared E2EE key for the call session.

Parameters

key String Required
The shared encryption key for this call session.

Example

await room.setSharedKey('<SHARED-E2EE-KEY>');

ratchetKey

Ratchets the E2EE key for a specific participant, advancing the key material for forward secrecy.

Parameters

participantId String Required
The identifier of the participant whose key should be ratcheted.
keyIndex int Required
The index of the key to ratchet.

Example

await room.ratchetKey('alice-livekit-id', 0);

forceRemoteKeyframe

Forces the SFU to emit a fresh keyframe for a participant’s video stream. Useful when a video track becomes undecodable after an E2EE key rotation.

Parameters

participantId String Required
The identifier of the participant whose video keyframe should be forced.

Example

await room.forceRemoteKeyframe('alice-livekit-id');

renderableVideoTrackFor

Returns the renderable video track for a participant, or null when the room is not connected, the participant is not found, or they have no active video track.

Parameters

participantId String Required
The identifier of the participant whose video track should be retrieved.

Example

final track = room.renderableVideoTrackFor('alice-livekit-id');
if (track != null) {
  // Render the track
}

FlutterMatrixRTCDelegate

Concrete matrix.WebRTCDelegate that bridges Matrix RTC to flutter_webrtc. Lives in the plugin so that the SDK stays pure Dart. Created once per app session and injected into matrix.VoIP at startup via MeetingPlaceMatrixSDK.create().

The keyProvider is set by the call service before a call starts, allowing per-participant E2EE keys distributed by Matrix RTC to flow into the LiveKit FrameCryptor layer.

FlutterMatrixRTCDelegate (constructor)

Creates an instance of FlutterMatrixRTCDelegate. Takes no arguments.

Parameters

No parameters required.

Example

import 'package:meeting_place_livekit_flutter/meeting_place_livekit_flutter.dart';
import 'package:meeting_place_matrix/meeting_place_matrix.dart';

final matrixSDK = await MeetingPlaceMatrixSDK.create(
  wallet: wallet,
  repositoryConfig: repositoryConfig,
  config: matrixConfig,
  rtcDelegate: FlutterMatrixRTCDelegate(),
  roomFactory: (_) => FlutterLiveKitRoom(),
);

updateKeyProvider

Sets the LiveKit KeyProvider that should receive per-participant E2EE keys distributed by Matrix RTC.

Parameters

provider KeyProvider? Required
The LiveKit key provider to receive E2EE keys. Pass null to clear the current provider.

Example

import 'package:meeting_place_livekit_flutter/meeting_place_livekit_flutter.dart';

final delegate = FlutterMatrixRTCDelegate();

// Set the key provider before starting a call
delegate.updateKeyProvider(myKeyProvider);

// Clear the key provider after the call ends
delegate.updateKeyProvider(null);