# Technical Documentation: flutter-webrtc/flutter-webrtc

> ℹ️ **Provenance:** Multi-Tier Ingestion · [CodeWiki Reference](https://codewiki.google/github.com/flutter-webrtc/flutter-webrtc)

### Overview (`README.md`)

# Flutter-WebRTC

[](https://opencollective.com/flutter-webrtc) [](https://pub.dartlang.org/packages/flutter_webrtc) [](https://gitter.im/flutter-webrtc/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) [](https://join.slack.com/t/flutterwebrtc/shared_invite/zt-q83o7y1s-FExGLWEvtkPKM8ku_F8cEQ)

WebRTC plugin for Flutter Mobile/Desktop/Web

</br>
<p align="center">
<strong>Sponsored with 💖 &nbsp by</strong><br />
<a href="https://getstream.io/chat/flutter/tutorial/?utm_source=https://github.com/flutter-webrtc/flutter-webrtc&utm_medium=github&utm_content=developer&utm_term=flutter" target="_blank">
<img src="assets/sponsors/stream-logo.png" alt="Stream Chat" style="margin: 8px; width: 350px" />
</a>
<br />
Enterprise Grade APIs for Feeds, Chat, & Video. <a href="https://getstream.io/video/docs/flutter/?utm_source=https://github.com/flutter-webrtc/flutter-webrtc&utm_medium=sponsorship&utm_content=&utm_campaign=webrtcFlutterRepo_July2023_video_klmh22" target="_blank">Try the Flutter Video tutorial</a> 💬
</p>

</br>
<p align="center">
<a href="https://livekit.io/?utm_source=opencollective&utm_medium=github&utm_campaign=flutter-webrtc" target="_blank">
<img src="https://avatars.githubusercontent.com/u/69438833?s=200&v=4" alt="LiveKit" style="margin: 8px; width: 100px" />
</a>
<br />
   <a href="https://livekit.io/?utm_source=opencollective&utm_medium=github&utm_campaign=flutter-webrtc" target="_blank">LiveKit</a> - Open source WebRTC and realtime AI infrastructure
<p>

## Functionality

| Feature | Android | iOS | [Web](https://flutter.dev/web) | macOS | Windows | Linux | [Embedded](https://github.com/sony/flutter-elinux) | [Fuchsia](https://fuchsia.dev/) |
| :-------------: | :-------------:| :-----: | :-----: | :-----: | :-----: | :-----: | :-----: | :-----: |
| 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:(*)](https://github.com/flutter-webrtc/flutter-webrtc/wiki/iOS-Screen-Sharing) | :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](https://flutter.io/using-packages/).

### iOS/macOS: Swift Package Manager

The plugin supports both [Swift Package Manager](https://docs.flutter.dev/packages-and-plugins/swift-package-manager/for-app-developers) 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 `<project root>/ios/Runner/Info.plist`:

```xml
<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

```ruby
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
end
```

### Android

Ensure the following permission is present in your Android Manifest file, located in `<project root>/android/app/src/main/AndroidManifest.xml`:

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

```xml
<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`:

```groovy
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](https://github.com/flutter-webrtc/flutter-webrtc/blob/main/android/proguard-rules.pro)

## Contributing

The project is inseparable from the contributors of the community.

- [CloudWebRTC](https://github.com/cloudwebrtc) - Original Author
- [RainwayApp](https://github.com/rainwayapp) - Sponsor
- [亢少军](https://github.com/kangshaojun) - Sponsor
- [ION](https://github.com/pion/ion) - Sponsor
- [reSipWebRTC](https://github.com/reSipWebRTC) - Sponsor
- [沃德米科技](https://github.com/woodemi)-[36记手写板](https://www.36notes.com) - Sponsor
- [阿斯特网络科技有限公司](https://www.astgo.net/) - Sponsor

### Example

For more examples, please refer to [flutter-webrtc-demo](https://github.com/cloudwebrtc/flutter-webrtc-demo/).

## Contributors

### Code Contributors

This project exists thanks to all the people who contribute. [[Contribute](CONTRIBUTING.md)].
<a href="https://github.com/cloudwebrtc/flutter-webrtc/graphs/contributors"><img src="https://opencollective.com/flutter-webrtc/contributors.svg?width=890&button=false" /></a>

### Financial Contributors

Become a financial contributor and help us sustain our community. [[Contribute](https://opencollective.com/flutter-webrtc/contribute)]

#### Individuals

<a href="https://opencollective.com/flutter-webrtc"><img src="https://opencollective.com/flutter-webrtc/individuals.svg?width=890"></a>

#### Organizations

Support this project with your organization. Your logo will show up here with a link to your website. [[Contribute](https://opencollective.com/flutter-webrtc/contribute)]

<a href="https://opencollective.com/flutter-webrtc/organization/0/website"><img src="https://opencollective.com/flutter-webrtc/organization/0/avatar.svg"></a>
<a href="https://opencollective.com/flutter-webrtc/organization/1/website"><img src="https://opencollective.com/flutter-webrtc/organization/1/avatar.svg"></a>
<a href="https://opencollective.com/flutter-webrtc/organization/2/website"><img src="https://opencollective.com/flutter-webrtc/organization/2/avatar.svg"></a>
<a href="https://opencollective.com/flutter-webrtc/organization/3/website"><img src="https://opencollective.com/flutter-webrtc/organization/3/avatar.svg"></a>
<a href="https://opencollective.com/flutter-webrtc/organization/4/website"><img src="https://opencollective.com/flutter-webrtc/organization/4/avatar.svg"></a>
<a href="https://opencollective.com/flutter-webrtc/organization/5/website"><img src="https://opencollective.com/flutter-webrtc/organization/5/avatar.svg"></a>
<a href="https://opencollective.com/flutter-webrtc/organization/6/website"><img src="https://opencollective.com/flutter-webrtc/organization/6/avatar.svg"></a>
<a href="https://opencollective.com/flutter-webrtc/organization/7/website"><img src="https://opencollective.com/flutter-webrtc/organization/7/avatar.svg"></a>
<a href="https://opencollective.com/flutter-webrtc/organization/8/website"><img src="https://opencollective.com/flutter-webrtc/organization/8/avatar.svg"></a>
<a href="https://opencollective.com/flutter-webrtc/organization/9/website"><img src="https://opencollective.com/flutter-webrtc/organization/9/avatar.svg"></a>

---

### Overview (`example/README.md`)

# webrtc_example

Demonstrates how to use the webrtc plugin.

## Getting Started

Make sure your flutter is using the `dev` channel.

```bash
flutter channel dev
./scripts/project_tools.sh create
```

Android/iOS

```bash
flutter run
```

macOS

```bash
flutter run -d macos
```

Web

```bash
dart compile js ../web/e2ee.worker.dart -o web/e2ee.worker.dart.js
flutter run -d web
```

Windows

```bash
flutter channel master
flutter create --platforms windows .
flutter run -d windows
```

---

### Overview (`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 passwords
`aesKey` aesKey is the plaintext password you entered, which will be used to derive the actual password

```dart
    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`,

``` dart
var pc = await createPeerConnection( {
        'encodedInsertableStreams': true,
        });
```

3, Enable FrameCryptor for RTPSender.

```dart
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

```dart

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:

```sh
cd example
flutter pub get
flutter run -d linux -t lib/peer_connection_dispose_smoke.dart
```

On Windows, replace `-d linux` with `-d windows`. Success prints:

```text
PASS: 10 native PeerConnections disposed with remote audio
```

To check the native process exit code on Windows (PowerShell, from `example`):

```powershell
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.ExitCode
```

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

```sh
flutter run -d windows -t lib/main.dart
```

Use `-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
