MediaSFU mediasoup client for Flutter
A maintained, low-level mediasoup client for building custom real-time media experiences on Flutter.
Use mediasoup primitives such as Device, Transport, Producer, Consumer, DataProducer, and DataConsumer while keeping full control of your signaling and application UI. Version 0.1.4 is aligned with flutter_webrtc ^1.5.2 and supports Unified Plan, simulcast, data channels, and Opus/PCMU/PCMA audio negotiation.
Choose the right Flutter path
| You need | Start with |
|---|---|
| Custom signaling, custom UI, and direct control of mediasoup transports | This package |
| Complete rooms, signaling, participant state, and ready-to-use Flutter components | mediasfu_sdk |
| A self-hosted MediaSFU backend | MediaSFU Open |
| Managed recording, SIP/telephony, translation, AI notes, and production infrastructure | MediaSFU |
Install
flutter pub add mediasfu_mediasoup_client
import 'package:mediasfu_mediasoup_client/mediasfu_mediasoup_client.dart';
Compatibility
| Component | Supported baseline |
|---|---|
| Dart | >=3.3.3 <4.0.0 |
| Flutter WebRTC | ^1.5.2 |
| Platforms | Android, iOS, Linux, macOS, Windows |
This package currently targets native Flutter platforms. For browser applications, use a MediaSFU web SDK or the JavaScript mediasoup client.
How it fits together
This library owns the client-side WebRTC and mediasoup negotiation. Your application still provides the signaling channel and a mediasoup-compatible server.
- Request the router RTP capabilities from your server.
- Load a
Devicewith those capabilities. - Ask your server to create send and receive WebRTC transports.
- Create local transports from the server response.
- Exchange DTLS and producer parameters through your signaling channel.
- Produce local tracks and consume remote producers.
Integration skeleton
The example below shows the key client flow. The signaling calls represent your WebSocket or HTTP implementation.
import 'package:mediasfu_mediasoup_client/mediasfu_mediasoup_client.dart';
final device = Device();
Future<Transport> createSendTransport(SignalingClient signaling) async {
final routerCapabilities = await signaling.getRouterRtpCapabilities();
await device.load(
routerRtpCapabilities: RtpCapabilities.fromMap(routerCapabilities),
);
final transportOptions = await signaling.createWebRtcTransport(
direction: 'send',
sctpCapabilities: device.sctpCapabilities.toMap(),
);
final transport = device.createSendTransportFromMap(transportOptions);
transport.on('connect', (data) async {
try {
await signaling.connectWebRtcTransport(
transportId: transport.id,
dtlsParameters: data['dtlsParameters'].toMap(),
);
data['callback']();
} catch (error) {
data['errback'](error);
}
});
transport.on('produce', (data) async {
try {
final producerId = await signaling.produce(
transportId: transport.id,
kind: data['kind'],
rtpParameters: data['rtpParameters'].toMap(),
appData: data['appData'],
);
data['callback'](producerId);
} catch (error) {
data['errback'](error);
}
});
return transport;
}
After acquiring media with navigator.mediaDevices.getUserMedia, publish a track through the send transport:
final stream = await navigator.mediaDevices.getUserMedia({
'audio': true,
'video': true,
});
final videoTrack = stream.getVideoTracks().first;
sendTransport.produce(
track: videoTrack,
stream: stream,
source: 'webcam',
appData: {'mediaTag': 'camera'},
);
Use producerCallback when creating the send transport, or listen to transport.observer, to retain the resulting Producer in your application state.
The signaling method names above are illustrative. Your server contract determines endpoint names and response shapes. Transport data must include mediasoup
id,iceParameters,iceCandidates, anddtlsParameters; SCTP parameters are optional.
Why this package
- Maintained WebRTC alignment: tracks current
flutter_webrtcAPIs instead of leaving applications pinned to an old native WebRTC layer. - Low-level control: design your own signaling, state model, media controls, and interface.
- Media and data: supports producers, consumers, SCTP data producers, and data consumers.
- Codec coverage: includes Opus and G.711 PCMU/PCMA handling for real-time and telephony-oriented media flows.
- Clear growth path: move to the full MediaSFU Flutter SDK when you no longer want to maintain room orchestration yourself.
From primitives to a complete product
Building directly on mediasoup is ideal when the transport layer is part of your product differentiation. It also means your team owns signaling reliability, room lifecycle, reconnection, permissions, recording orchestration, and production operations.
When you want those pieces already integrated, add the MediaSFU Flutter SDK:
flutter pub add mediasfu_sdk
The full SDK adds higher-level room workflows and components while connecting to the broader MediaSFU platform for recording, streaming, SIP/telephony, translation, AI features, and managed or self-hosted deployment options.
Upgrading flutter_webrtc
WebRTC dependency updates can change native binaries and RTP types even when your Dart code is unchanged. When upgrading this package:
- Run
flutter cleanif an older native WebRTC artifact remains cached. - Run
flutter pub get. - Rebuild each platform you ship; do not rely on hot reload for native dependency changes.
- Exercise camera, microphone, screen sharing, reconnect, and Bluetooth/audio-route flows on real devices.
- Verify server codec and RTP capability negotiation before rollout.
Contributing
Issues and focused pull requests are welcome at MediaSFU/mediasfu_mediasoup_client. Include the Flutter version, platform, device and OS version, flutter_webrtc version, and a minimal reproduction for media negotiation issues.
Credits
This package is based on mediasoup-client-flutter and is maintained by MediaSFU.
License
MIT. See LICENSE.