Technical Documentation: flutter-webrtc/flutter-webrtc
โน๏ธ Provenance: Multi-Tier Ingestion ยท CodeWiki Reference
Overview (`README.md`)
Flutter-WebRTC
WebRTC plugin for Flutter Mobile/Desktop/Web
LiveKit - Open source WebRTC and realtime AI infrastructure
Functionality
| Feature | Android | iOS | Web | macOS | Windows | Linux | Embedded | Fuchsia |
|---|---|---|---|---|---|---|---|---|
| Audio/Video | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | |
| Data Channel | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | |
| Screen Capture | :heavy_check_mark: | :heavy_check_mark:(*) | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | |
| Unified-Plan | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | |
| Simulcast | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | |
| MediaRecorder | :warning: | :warning: | :heavy_check_mark: | |||||
| End to End Encryption | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | |
| Insertable Streams |
Additional platform/OS support from the other community
- flutter-tizen: https://github.com/flutter-tizen/plugins/tree/master/packages/flutter_webrtc
- flutter-elinux(WIP): https://github.com/sony/flutter-elinux-plugins/issues/7
Add flutter_webrtc as a dependency in your pubspec.yaml file.
iOS/macOS: Swift Package Manager
The plugin supports both Swift Package Manager and CocoaPods on iOS and macOS. With Flutter 3.44 or later, Swift Package Manager is enabled by default and the plugin is consumed as a Swift package automatically. No project changes are needed.
CocoaPods remains fully supported and is used when Swift Package Manager is disabled or on older Flutter versions. The Podfile notes below apply to CocoaPods projects only.
iOS
Add the following entry to your Info.plist file, located in /ios/Runner/Info.plist:
<key>NSCameraUsageDescription</key>
<string>$(PRODUCT_NAME) Camera Usage!</string>
<key>NSMicrophoneUsageDescription</key>
<string>$(PRODUCT_NAME) Microphone Usage!</string>This entry allows your app to access camera and microphone.
Note for iOS
The WebRTC.xframework compiled after the m104 release no longer supports iOS arm devices, so need to add the config.build_settings['ONLY_ACTIVE_ARCH'] = 'YES' to your ios/Podfile in your project
ios/Podfile
post_install do |installer|
installer.pods_project.targets.each do |target|
flutter_additional_ios_build_settings(target)
target.build_configurations.each do |config|
# Workaround for https://github.com/flutter/flutter/issues/64502
config.build_settings['ONLY_ACTIVE_ARCH'] = 'YES' # <= this line
end
end
endAndroid
Ensure the following permission is present in your Android Manifest file, located in /android/app/src/main/AndroidManifest.xml:
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />If you need to use a Bluetooth device, please add:
<uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30" />The Flutter project template adds it, so it may already be there.
Also you will need to set your build settings to Java 8, because official WebRTC jar now uses static methods in EglBase interface. Just add this to your app level build.gradle:
android {
//...
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}If necessary, in the same build.gradle you will need to increase minSdkVersion of defaultConfig up to 23 (currently default Flutter generator set it to 16).
Important reminder
When you compile the release apk, you need to add the following operations,
Setup Proguard Rules
Contributing
The project is inseparable from the contributors of the community.
- CloudWebRTC - Original Author
- RainwayApp - Sponsor
- ไบขๅฐๅ - Sponsor
- ION - Sponsor
- reSipWebRTC - Sponsor
- ๆฒๅพท็ฑณ็งๆ-36่ฎฐๆๅๆฟ - Sponsor
- ้ฟๆฏ็น็ฝ็ป็งๆๆ้ๅ ฌๅธ - Sponsor
Example
For more examples, please refer to flutter-webrtc-demo.
Contributors
Code Contributors
This project exists thanks to all the people who contribute. [Contribute].
Financial Contributors
Become a financial contributor and help us sustain our community. [Contribute]
Individuals
Organizations
Support this project with your organization. Your logo will show up here with a link to your website. [Contribute]
Overview (`example/README.md`)
webrtc_example
Demonstrates how to use the webrtc plugin.
Getting Started
Make sure your flutter is using the dev channel.
flutter channel dev
./scripts/project_tools.sh createAndroid/iOS
flutter runmacOS
flutter run -d macosWeb
dart compile js ../web/e2ee.worker.dart -o web/e2ee.worker.dart.js
flutter run -d webWindows
flutter channel master
flutter create --platforms windows .
flutter run -d windowsOverview (`example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md`)
Launch Screen Assets
You can customize the launch screen with your own desired assets by replacing the image files in this directory.
You can also do it by opening your Flutter project's Xcode project with open ios/Runner.xcworkspace, selecting Runner/Assets.xcassets in the Project Navigator and dropping in the desired images.
Documentation E2EE (`Documentation/E2EE.md`)
End to End Encryption
E2EE is an AES-GCM encryption interface injected before sending the packaged RTP packet and after receiving the RTP packet, ensuring that the data is not eavesdropped when passing through SFU or any public transmission network. It coexists with DTLS-SRTP as two layers of encryption. You can control the key, ratchet and other operations of FrameCryptor yourself to ensure that no third party will monitor your tracks.
Process of enabling E2EE
1, Prepare the key provider
ratchetSalt is used to add to the mixture when ratcheting or deriving AES passwordsaesKey aesKey is the plaintext password you entered, which will be used to derive the actual password
final aesKey = 'you-private-key-here'.codeUnits;
final ratchetSalt = 'flutter-webrtc-ratchet-salt';
var keyProviderOptions = KeyProviderOptions(
sharedKey: true,
ratchetSalt: Uint8List.fromList(ratchetSalt.codeUnits),
ratchetWindowSize: 16,
failureTolerance: -1,
);
var keyProvider = await frameCyrptorFactory.createDefaultKeyProvider(keyProviderOptions);
/// set shared key for all track, default index is 0
/// also you can set multiple keys by different indexes
await keyProvider.setSharedKey(key: aesKey);2, create PeerConnectioin
when you use E2EE on the web, please add encodedInsertableStreams,
var pc = await createPeerConnection( {
'encodedInsertableStreams': true,
});3, Enable FrameCryptor for RTPSender.
var stream = await navigator.mediaDevices
.getUserMedia({'audio': true, 'video': false });
var audioTrack = stream.getAudioTracks();
var sender = await pc.addTrack(audioTrack, stream);
var trackId = audioTrack?.id;
var id = 'audio_' + trackId! + '_sender';
var frameCyrptor =
await frameCyrptorFactory.createFrameCryptorForRtpSender(
participantId: id,
sender: sender,
algorithm: Algorithm.kAesGcm,
keyProvider: keyProvider!);
/// print framecyrptor state
frameCyrptor.onFrameCryptorStateChanged = (participantId, state) =>
print('EN onFrameCryptorStateChanged $participantId $state');
/// set currently shared key index
await frameCyrptor.setKeyIndex(0);
/// enable encryption now.
await frameCyrptor.setEnabled(true);4, Enable FrameCryptor for RTPReceiver
pc.onTrack((RTCTrackEvent event) async {
var receiver = event.receiver;
var trackId = event.track?.id;
var id = event.track.kind + '_' + trackId! + '_receiver';
var frameCyrptor =
await frameCyrptorFactory.createFrameCryptorForRtpReceiver(
participantId: id,
receiver: receiver,
algorithm: Algorithm.kAesGcm,
keyProvider: keyProvider);
frameCyrptor.onFrameCryptorStateChanged = (participantId, state) =>
print('DE onFrameCryptorStateChanged $participantId $state');
/// set currently shared key index
await frameCyrptor.setKeyIndex(0);
/// enable encryption now.
await frameCyrptor.setEnabled(true);
});Documentation Desktop Peerconnection Disposal (`Documentation/desktop-peerconnection-disposal.md`)
Desktop PeerConnection disposal regression check
example/lib/peer_connection_dispose_smoke.dart exercises native observer
teardown on Windows and Linux. It creates a remote audio stream from a synthetic
SDP offer, waits for onAddStream, then calls dispose() followed by close().
It repeats this sequence ten times. No account, microphone capture, ICE server,
or media connection is needed.
Run this with a desktop runner. flutter test uses mocked platform channels and
cannot exercise the native observer lifetime. From the repository root:
cd example
flutter pub get
flutter run -d linux -t lib/peer_connection_dispose_smoke.dartOn Windows, replace -d linux with -d windows. Success prints:
PASS: 10 native PeerConnections disposed with remote audioTo check the native process exit code on Windows (PowerShell, from example):
flutter build windows --debug -t lib/peer_connection_dispose_smoke.dart
$process = Start-Process -FilePath .\build\windows\x64\runner\Debug\flutter_webrtc_example.exe -WindowStyle Hidden -Wait -PassThru
$process.ExitCodeThe expected exit code is zero. A Dart failure exits with code 1. A native
access violation can terminate the process before Dart can report a failure.
Failure being exercised
In common/cpp/src/flutter_peerconnection.cc, RTCPeerConnectionDispose
previously erased peerconnection_observers_[uuid] while the native connection
still had that observer registered. A later RTCPeerConnectionClose called
libwebrtc Close(), which can deliver OnRemoveStream for remaining remote
streams. That callback could access the deleted observer.
Disposal now closes the native connection while its observer is still alive,
unregisters the observer, then erases it. The connection map entry remains for
the subsequent peerConnectionClose call, preserving that cleanup sequence.
Restore the regular example entry point after the check:
flutter run -d windows -t lib/main.dartUse -d linux for the Linux example.
--- METRICS ---
- Files Extracted: 5
- Estimated Token Budget: ~3978 tokens
- Canonical Reference: https://codewiki.google/github.com/flutter-webrtc/flutter-webrtc