flutter-webrtc / flutter-webrtc

WebRTC plugin for Flutter Mobile/Desktop/Web
MIT License
4.15k stars 1.13k forks source link

Android Screen Share: getDisplayMedia not build for SDKVersion 34 #1521

Open ipainchaud opened 9 months ago

ipainchaud commented 9 months ago

Describe the bug

It has been a while that we had to start a foreground service of type mediaProjection to be able to start a screen share using MediaDevices.getDisplayMedia(constraints) to avoid the following error:

Media projections require a foreground service of type ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION

With SDK Version 34 (targetSdkVersion 34) though the requirements have changed around the creation of mediaProjection services. There is now a runtime requisite:

Call the createScreenCaptureIntent() method before starting the foreground service. Doing so shows a permission notification to the user; the user must grant the permission before you can create the service.

After you have created the foreground service, you can call MediaProjectionManager.getMediaProjection()

Meeting this requisite doesn't seem possible using getDisplayMedia because of how it is implemented (see here where the Receiver starts the media capture straight after receiving the permission).

If you attempt to create the service before calling getDisplayMedia on an app targeting SDK Version 34 on an android 14 phone, you will now get:

java.lang.SecurityException: Starting FGS with type mediaProjection callerApp=ProcessRecord{d73055a 22200:io.aira.explorer/u0a714} targetSDK=34 requires permissions: all of the permissions allOf=true [android.permission.FOREGROUND_SERVICE_MEDIA_PROJECTION] any of the permissions allOf=false [android.permission.CAPTURE_VIDEO_OUTPUT, android:project_media] 

Not only we now have to add the FOREGROUND_SERVICE_MEDIA_PROJECTION and one of the CAPTURE_VIDEO_OUTPUT or android:project_media permission to AndroidManifest.xml, but you also have to get the User's permission for the media projection before you start the mediaProjection foreground service and then start acquiring the media projection.

To Reproduce

Android Only: Create a project targeting SDK Version 34 where you create a foreground service of type "mediaProjection" before calling getDisplayMedia.

Expected behavior

We should be able to provide a callback function to getDisplayMedia to create the "mediaProjection" service at the right time

OR have the plugin taking care of creating that service.

Platform information

[✓] Android toolchain - develop for Android devices (Android SDK version 33.0.0) • Android SDK at /Users/israelpainchaud/Library/Android/sdk • Platform android-34, build-tools 33.0.0 • Java binary at: /Applications/Android Studio.app/Contents/jbr/Contents/Home/bin/java • Java version OpenJDK Runtime Environment (build 17.0.7+0-17.0.7b1000.6-10550314) • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 15.2) • Xcode at /Applications/Xcode.app/Contents/Developer • Build 15C500b • CocoaPods version 1.14.3

[✓] Chrome - develop for the web • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Android Studio (version 2021.2) • Android Studio at /Applications/Android Studio Chipmonk.app/Contents • Flutter plugin can be installed from: 🔨 https://plugins.jetbrains.com/plugin/9212-flutter • Dart plugin can be installed from: 🔨 https://plugins.jetbrains.com/plugin/6351-dart • Java version OpenJDK Runtime Environment (build 11.0.12+0-b1504.28-7817840)

[✓] Android Studio (version 2023.1) • Android Studio at /Applications/Android Studio.app/Contents • Flutter plugin can be installed from: 🔨 https://plugins.jetbrains.com/plugin/9212-flutter • Dart plugin can be installed from: 🔨 https://plugins.jetbrains.com/plugin/6351-dart • Java version OpenJDK Runtime Environment (build 17.0.7+0-17.0.7b1000.6-10550314)

[✓] IntelliJ IDEA Community Edition (version 2022.2.1) • IntelliJ at /Applications/IntelliJ IDEA CE.app • Flutter plugin can be installed from: 🔨 https://plugins.jetbrains.com/plugin/9212-flutter • Dart plugin version 222.4560

[✓] Connected device (4 available)
• SM G991U1 (mobile) • R3CNC0JE7KR • android-arm64 • Android 14 (API 34) • Israel’s iPhone (mobile) • 00008110-001E19E80E62401E • ios • iOS 17.4 21E5184k • macOS (desktop) • macos • darwin-x64 • macOS 14.1.2 23B92 darwin-x64 • Chrome (web) • chrome • web-javascript • Google Chrome 121.0.6167.139

[✓] Network resources • All expected network resources are available.



* **Plugin version**: 
flutter_webrtc: ^0.9.48+hotfix.1

* **OS**: <!-- Android / iOS/Desktop -->
Android

* **OS version**:
Android 14  (One UI version 6.0)
ipainchaud commented 9 months ago

I attempted to create a PR which would create the "mediaProjection" foreground service just after a successful call to mediaProjectionManager.createScreenCaptureIntent() to solve this problem. I based myself on the flutter_foreground_service plugin which does something fairly similar. To ensure my logic was sound, I first wrote the logic on my native project and ensured it was working, then copied it to a fork of flutter_webrtc. This was to no avail though. My lack of understanding of Android is most probably at fault here. It would seem that calling context.startForegroundService(myMediaProjectionServiceIntent), although returning the right ComponentName, would never execute either of my Service's onCreate or onStartCommand functions. I suspect there might be something related with the context used to create the foreground service (context rights or scope?).

I did try to understand this further by looking into adb logcat and found this warning every time I attempted to start the foreground service: "ForegroundServiceTypeLoggerModule: API event end called before start!".

Jaemin-VIRNECT commented 8 months ago

@ipainchaud

1552 might be able to solve your problem!