diff --git a/CHANGELOG.md b/CHANGELOG.md index 1f174fc724..cacb17ba89 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,10 @@ # Changelog +[1.0.13] - 2025-10-28 +* Exposed `eventStream` in `MediaDevices`. +* [Android] Sends event when screen capture ends. + [1.0.12] - 2025-09-30 * [Android] Changed the configuration used when creating EGL rendering context to one that supports alpha channel to fix an issue with Impeller blending background with video texture on some devices. * [Android] Migrate from onSurfaceDestroyed to onSurfaceCleanup for SurfaceProducer.Callback. diff --git a/android/src/main/java/io/getstream/webrtc/flutter/GetUserMediaImpl.java b/android/src/main/java/io/getstream/webrtc/flutter/GetUserMediaImpl.java index a073bb00e4..a2f2bb4d4a 100755 --- a/android/src/main/java/io/getstream/webrtc/flutter/GetUserMediaImpl.java +++ b/android/src/main/java/io/getstream/webrtc/flutter/GetUserMediaImpl.java @@ -96,6 +96,7 @@ public class GetUserMediaImpl { private static final int DEFAULT_HEIGHT = 720; private static final int DEFAULT_FPS = 30; + private static final String EVENT_DISPLAY_MEDIA_STOPPED = "screenSharingStopped"; private static final String PERMISSION_AUDIO = Manifest.permission.RECORD_AUDIO; private static final String PERMISSION_VIDEO = Manifest.permission.CAMERA; private static final String PERMISSION_SCREEN = "android.permission.MediaProjection"; @@ -519,19 +520,24 @@ private void getDisplayMedia(final Result result, final MediaStream mediaStream, /* Create ScreenCapture */ VideoTrack displayTrack = null; VideoCapturer videoCapturer = null; - videoCapturer = - new OrientationAwareScreenCapturer( - applicationContext, - mediaProjectionData, - new MediaProjection.Callback() { - @Override - public void onStop() { - super.onStop(); - // After Huawei P30 and Android 10 version test, the onstop method is called, which will not affect the next process, - // and there is no need to call the resulterror method - //resultError("MediaProjection.Callback()", "User revoked permission to capture the screen.", result); - } - }); + String trackId = stateProvider.getNextTrackUUID(); + + videoCapturer = new OrientationAwareScreenCapturer( + applicationContext, + mediaProjectionData, + new MediaProjection.Callback() { + @Override + public void onStop() { + super.onStop(); + + ConstraintsMap params = new ConstraintsMap(); + params.putString("event", EVENT_DISPLAY_MEDIA_STOPPED); + params.putString("trackId", trackId); + FlutterWebRTCPlugin.sharedSingleton.sendEvent(params.toMap()); + } + } + ); + if (videoCapturer == null) { resultError("screenRequestPermissions", "GetDisplayMediaFailed, User revoked permission to capture the screen.", result); return; @@ -563,7 +569,6 @@ public void onStop() { videoCapturer.startCapture(info.width, info.height, info.fps); Log.d(TAG, "OrientationAwareScreenCapturer.startCapture: " + info.width + "x" + info.height + "@" + info.fps); - String trackId = stateProvider.getNextTrackUUID(); mVideoCapturers.put(trackId, info); mVideoSources.put(trackId, videoSource); diff --git a/common/darwin/Classes/FlutterWebRTCPlugin.h b/common/darwin/Classes/FlutterWebRTCPlugin.h index ef8ea50e37..1d021f25ce 100644 --- a/common/darwin/Classes/FlutterWebRTCPlugin.h +++ b/common/darwin/Classes/FlutterWebRTCPlugin.h @@ -97,6 +97,8 @@ typedef void (^CapturerStopHandler)(CompletionHandler _Nonnull handler); - (RTCRtpSender* _Nullable)getRtpSenderById:(RTCPeerConnection* _Nonnull)peerConnection Id:(NSString* _Nonnull)Id; +- (void)postEventWithName:(NSString* _Nonnull)eventName data:(NSDictionary* _Nullable)data; + + (FlutterWebRTCPlugin* _Nullable)sharedSingleton; @end diff --git a/common/darwin/Classes/FlutterWebRTCPlugin.m b/common/darwin/Classes/FlutterWebRTCPlugin.m index fa0122f5f8..76a7e82bf5 100644 --- a/common/darwin/Classes/FlutterWebRTCPlugin.m +++ b/common/darwin/Classes/FlutterWebRTCPlugin.m @@ -2503,4 +2503,19 @@ - (FlutterRTCVideoRenderer *)findRendererByTrackId:(NSString *)trackId { } return nil; } + +#pragma mark - Event Posting Helper + +- (void)postEventWithName:(NSString*)eventName data:(NSDictionary*)data { + if (!self.eventSink) { + return; + } + + NSMutableDictionary* eventData = [NSMutableDictionary dictionaryWithObject:eventName forKey:@"event"]; + if (data) { + [eventData addEntriesFromDictionary:data]; + } + + postEvent(self.eventSink, eventData); +} @end diff --git a/ios/stream_webrtc_flutter.podspec b/ios/stream_webrtc_flutter.podspec index c18cc1f36a..dba17447c3 100644 --- a/ios/stream_webrtc_flutter.podspec +++ b/ios/stream_webrtc_flutter.podspec @@ -3,7 +3,7 @@ # Pod::Spec.new do |s| s.name = 'stream_webrtc_flutter' - s.version = '1.0.12' + s.version = '1.0.13' s.summary = 'Flutter WebRTC plugin for iOS.' s.description = <<-DESC A new flutter plugin project. diff --git a/lib/src/native/factory_impl.dart b/lib/src/native/factory_impl.dart index 9da5f29339..65e8be3d0d 100644 --- a/lib/src/native/factory_impl.dart +++ b/lib/src/native/factory_impl.dart @@ -187,3 +187,6 @@ DesktopCapturer get desktopCapturer => DesktopCapturerNative.instance; MediaDevices get mediaDevices => MediaDeviceNative.instance; FrameCryptorFactory get frameCryptorFactory => FrameCryptorFactoryImpl.instance; + +Stream> get eventStream => + MediaDeviceNative.instance.eventStream; diff --git a/lib/src/native/mediadevices_impl.dart b/lib/src/native/mediadevices_impl.dart index d9599df252..f339da7e76 100644 --- a/lib/src/native/mediadevices_impl.dart +++ b/lib/src/native/mediadevices_impl.dart @@ -19,6 +19,9 @@ class MediaDeviceNative extends MediaDevices { static final MediaDeviceNative instance = MediaDeviceNative._internal(); + Stream> get eventStream => + FlutterWebRTCEventChannel.instance.handleEvents.stream; + void handleEvent(String event, final Map map) async { switch (map['event']) { case 'onDeviceChange': diff --git a/lib/src/web/factory_impl.dart b/lib/src/web/factory_impl.dart index 1dfd629425..f601622fd0 100644 --- a/lib/src/web/factory_impl.dart +++ b/lib/src/web/factory_impl.dart @@ -22,3 +22,5 @@ Future handleCallInterruptionCallbacks( throw UnimplementedError( 'handleCallInterruptionCallbacks() is not supported on web'); } + +Stream> get eventStream => Stream.empty(); diff --git a/macos/stream_webrtc_flutter.podspec b/macos/stream_webrtc_flutter.podspec index eb316380f3..7c154a04a2 100644 --- a/macos/stream_webrtc_flutter.podspec +++ b/macos/stream_webrtc_flutter.podspec @@ -3,7 +3,7 @@ # Pod::Spec.new do |s| s.name = 'stream_webrtc_flutter' - s.version = '1.0.12' + s.version = '1.0.13' s.summary = 'Flutter WebRTC plugin for macOS.' s.description = <<-DESC A new flutter plugin project. diff --git a/pubspec.yaml b/pubspec.yaml index 588c1a80cc..f81975b693 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: stream_webrtc_flutter description: Flutter WebRTC plugin for iOS/Android/Destkop/Web, based on GoogleWebRTC. -version: 1.0.12 +version: 1.0.13 homepage: https://github.com/GetStream/webrtc-flutter environment: sdk: ">=3.6.0 <4.0.0"