Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,20 @@

# Changelog

--------------------------------------------
[0.12.12] - 2025-03-09

* [Android] feat: Migrate to the new Surface API. (#1726)
* [Chore] chore: fix sponsors logo and links.

[0.12.11] - 2025-02-23

* [web] bump version for dart_webrtc.
* [web] fix: compile error for web with --wasm.

[0.12.10] - 2025-02-18

* [web] bump version for dart_webrtc.
* [web] fix: compile error for web with --wasm.

[0.12.9+1] - 2025-02-17

Expand Down
14 changes: 8 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ WebRTC plugin for Flutter Mobile/Desktop/Web
<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="https://stream-blog-v2.imgix.net/blog/wp-content/uploads/f7401112f41742c4e173c30d4f318cb8/stream_logo_white.png?w=350" alt="Stream Chat" style="margin: 8px" />
<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> 💬
Expand All @@ -17,10 +17,10 @@ Enterprise Grade APIs for Feeds, Chat, & Video. <a href="https://getstream.io/vi
</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=92&v=4" alt="LiveKit" style="margin: 8px" />
<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 infrastructure
<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
Expand All @@ -38,8 +38,8 @@ Enterprise Grade APIs for Feeds, Chat, & Video. <a href="https://getstream.io/vi

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
- 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/).

Expand All @@ -56,7 +56,8 @@ Add the following entry to your _Info.plist_ file, located in `<project root>/io

This entry allows your app to access camera and microphone.

### Note for iOS.
### 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
Expand Down Expand Up @@ -111,6 +112,7 @@ android {
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)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import android.util.Log;
import android.graphics.SurfaceTexture;
import android.view.Surface;

import io.getstream.webrtc.flutter.utils.AnyThreadSink;
import io.getstream.webrtc.flutter.utils.ConstraintsMap;
Expand All @@ -20,8 +21,7 @@
public class FlutterRTCVideoRenderer implements EventChannel.StreamHandler {

private static final String TAG = FlutterWebRTCPlugin.TAG;
private final SurfaceTexture texture;
private final TextureRegistry.SurfaceTextureEntry entry;
private final TextureRegistry.SurfaceProducer producer;
private int id = -1;
private MediaStream mediaStream;

Expand All @@ -36,7 +36,7 @@ public void Dispose() {
eventChannel.setStreamHandler(null);

eventSink = null;
entry.release();
producer.release();
}

/**
Expand Down Expand Up @@ -100,15 +100,14 @@ public void onFrameResolutionChanged(
EventChannel eventChannel;
EventChannel.EventSink eventSink;

public FlutterRTCVideoRenderer(SurfaceTexture texture, TextureRegistry.SurfaceTextureEntry entry) {
public FlutterRTCVideoRenderer(TextureRegistry.SurfaceProducer producer) {
this.surfaceTextureRenderer = new SurfaceTextureRenderer("");
listenRendererEvents();
surfaceTextureRenderer.init(EglUtils.getRootEglBaseContext(), rendererEvents);
surfaceTextureRenderer.surfaceCreated(texture);
surfaceTextureRenderer.surfaceCreated(producer);

this.texture = texture;
this.eventSink = null;
this.entry = entry;
this.producer = producer;
this.ownerTag = null;
}

Expand Down Expand Up @@ -238,7 +237,7 @@ private void tryAddRendererToVideoTrack() throws Exception {
surfaceTextureRenderer.release();
listenRendererEvents();
surfaceTextureRenderer.init(sharedContext, rendererEvents);
surfaceTextureRenderer.surfaceCreated(texture);
surfaceTextureRenderer.surfaceCreated(producer);

videoTrack.addSink(surfaceTextureRenderer);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@ public MediaStreamTrack getRemoteTrack(String trackId) {
return methodCallHandler.getRemoteTrack(trackId);
}


@Override
public void onAttachedToEngine(@NonNull FlutterPluginBinding binding) {
startListening(binding.getApplicationContext(), binding.getBinaryMessenger(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import android.os.Build;
import android.util.Log;
import android.util.LongSparseArray;
import android.view.Surface;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
Expand Down Expand Up @@ -583,22 +584,21 @@ public void onMethodCall(MethodCall call, @NonNull Result notSafeResult) {
break;
}
case "createVideoRenderer": {
SurfaceTextureEntry entry = textures.createSurfaceTexture();
SurfaceTexture surfaceTexture = entry.surfaceTexture();
FlutterRTCVideoRenderer render = new FlutterRTCVideoRenderer(surfaceTexture, entry);
renders.put(entry.id(), render);
TextureRegistry.SurfaceProducer producer = textures.createSurfaceProducer();
FlutterRTCVideoRenderer render = new FlutterRTCVideoRenderer(producer);
renders.put(producer.id(), render);

EventChannel eventChannel =
new EventChannel(
messenger,
"FlutterWebRTC/Texture" + entry.id());
"FlutterWebRTC/Texture" + producer.id());

eventChannel.setStreamHandler(render);
render.setEventChannel(eventChannel);
render.setId((int) entry.id());
render.setId((int) producer.id());

ConstraintsMap params = new ConstraintsMap();
params.putInt("textureId", (int) entry.id());
params.putInt("textureId", (int) producer.id());
result.success(params.toMap());
break;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.getstream.webrtc.flutter;

import android.graphics.SurfaceTexture;
import android.view.Surface;

import org.webrtc.EglBase;
import org.webrtc.EglRenderer;
Expand All @@ -11,6 +12,8 @@

import java.util.concurrent.CountDownLatch;

import io.flutter.view.TextureRegistry;

/**
* Display the video stream on a Surface.
* renderFrame() is asynchronous to avoid blocking the calling thread.
Expand Down Expand Up @@ -95,19 +98,35 @@ public void pauseVideo() {
// VideoSink interface.
@Override
public void onFrame(VideoFrame frame) {
if(!isFirstFrameRendered) {
texture.setDefaultBufferSize(frame.getRotatedWidth(), frame.getRotatedHeight());
createEglSurface(texture);
if(surface == null) {
producer.setSize(frame.getRotatedWidth(),frame.getRotatedHeight());
surface = producer.getSurface();
createEglSurface(surface);
}
updateFrameDimensionsAndReportEvents(frame);
super.onFrame(frame);
}

private SurfaceTexture texture;
private Surface surface = null;

private TextureRegistry.SurfaceProducer producer;

public void surfaceCreated(final SurfaceTexture texture) {
public void surfaceCreated(final TextureRegistry.SurfaceProducer producer) {
ThreadUtils.checkIsOnMainThread();
this.texture = texture;
this.producer = producer;
this.producer.setCallback(
new TextureRegistry.SurfaceProducer.Callback() {
@Override
public void onSurfaceAvailable() {
// Do surface initialization here, and draw the current frame.
}

@Override
public void onSurfaceDestroyed() {
surfaceDestroyed();
}
}
);
}

public void surfaceDestroyed() {
Expand Down Expand Up @@ -138,7 +157,7 @@ private void updateFrameDimensionsAndReportEvents(VideoFrame frame) {
}
rotatedFrameWidth = frame.getRotatedWidth();
rotatedFrameHeight = frame.getRotatedHeight();
texture.setDefaultBufferSize(rotatedFrameWidth, rotatedFrameHeight);
producer.setSize(rotatedFrameWidth, rotatedFrameHeight);
frameRotation = frame.getRotation();
}
}
Expand Down
Binary file added assets/sponsors/stream-logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import 'package:stream_webrtc_flutter/stream_webrtc_flutter.dart';
import 'src/device_enumeration_sample.dart';
import 'src/get_display_media_sample.dart';
import 'src/get_user_media_sample.dart'
if (dart.library.html) 'src/get_user_media_sample_web.dart';
if (dart.library.js_interop) 'src/get_user_media_sample_web.dart';
import 'src/loopback_data_channel_sample.dart';
import 'src/loopback_sample_unified_tracks.dart';
import 'src/route_item.dart';
Expand Down
1 change: 1 addition & 0 deletions example/lib/src/get_user_media_sample.dart
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ class _GetUserMediaSampleState extends State<GetUserMediaSample> {
print('Recording is not available on iOS');
return;
}

// TODO(rostopira): request write storage permission
final storagePath = await getExternalStorageDirectory();
if (storagePath == null) throw Exception('Can\'t find storagePath');
Expand Down
8 changes: 6 additions & 2 deletions example/lib/src/loopback_sample_unified_tracks.dart
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,9 @@ class _MyAppState extends State<LoopBackSampleUnifiedTracks> {
}

void _selectAudioInput(String deviceId) async {
await Helper.selectAudioInput(deviceId);
if (!WebRTC.platformIsWeb) {
await Helper.selectAudioInput(deviceId);
}
}

void _cleanUp() async {
Expand Down Expand Up @@ -539,7 +541,9 @@ class _MyAppState extends State<LoopBackSampleUnifiedTracks> {
void _switchSpeaker() async {
setState(() {
_speakerOn = !_speakerOn;
Helper.setSpeakerphoneOn(_speakerOn);
if (!WebRTC.platformIsWeb) {
Helper.setSpeakerphoneOn(_speakerOn);
}
});
}

Expand Down
1 change: 0 additions & 1 deletion example/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ dependencies:
stream_webrtc_flutter:
path: ../


dev_dependencies:
flutter_test:
sdk: flutter
Expand Down
Loading