简体   繁体   中英

Flutter Web-RTC getDisplayMedia results in app crash

I want to create an app for Video-calling between 2 devices, with the possibility to share their own screen with the Flutter WebRTC plugin. I already made the video-calling part, but I ran into a problem with switching the UserMedia stream to DisplayMedia stream:

When I call the function getDisplayMedia() on android, sometimes it's working but when it's not, my app will crash with the following error:

E/AndroidRuntime(28052): FATAL EXCEPTION: main
E/AndroidRuntime(28052): Process: com.robin.screenshare_sample, PID: 28052
E/AndroidRuntime(28052): java.lang.RuntimeException: Unable to resume activity {com.robin.screenshare_sample/com.robin.screenshare_sample.MainActivity}: java.lang.IllegalStateException: MediaStreamTrack has been disposed.
E/AndroidRuntime(28052):    at android.app.ActivityThread.performResumeActivity(ActivityThread.java:4657)
E/AndroidRuntime(28052):    at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:4690)
E/AndroidRuntime(28052):    at android.app.servertransaction.ResumeActivityItem.execute(ResumeActivityItem.java:52)
E/AndroidRuntime(28052):    at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:176)
E/AndroidRuntime(28052):    at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:97)
E/AndroidRuntime(28052):    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2267)
E/AndroidRuntime(28052):    at android.os.Handler.dispatchMessage(Handler.java:107)
E/AndroidRuntime(28052):    at android.os.Looper.loop(Looper.java:237)
E/AndroidRuntime(28052):    at android.app.ActivityThread.main(ActivityThread.java:8167)
E/AndroidRuntime(28052):    at java.lang.reflect.Method.invoke(Native Method)
E/AndroidRuntime(28052):    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:496)
E/AndroidRuntime(28052):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1100)
E/AndroidRuntime(28052): Caused by: java.lang.IllegalStateException: MediaStreamTrack has been disposed.
E/AndroidRuntime(28052):    at org.webrtc.MediaStreamTrack.checkMediaStreamTrackExists(MediaStreamTrack.java:120)
E/AndroidRuntime(28052):    at org.webrtc.MediaStreamTrack.enabled(MediaStreamTrack.java:93)
E/AndroidRuntime(28052):    at com.cloudwebrtc.webrtc.MethodCallHandlerImpl$5.isEnabled(MethodCallHandlerImpl.java:1710)
E/AndroidRuntime(28052):    at com.cloudwebrtc.webrtc.GetUserMediaImpl.reStartCamera(GetUserMediaImpl.java:1044)
E/AndroidRuntime(28052):    at com.cloudwebrtc.webrtc.MethodCallHandlerImpl.reStartCamera(MethodCallHandlerImpl.java:1704)
E/AndroidRuntime(28052):    at com.cloudwebrtc.webrtc.FlutterWebRTCPlugin$LifeCycleObserver.onResume(FlutterWebRTCPlugin.java:186)
E/AndroidRuntime(28052):    at androidx.lifecycle.FullLifecycleObserverAdapter.onStateChanged(FullLifecycleObserverAdapter.java:42)
E/AndroidRuntime(28052):    at androidx.lifecycle.LifecycleRegistry$ObserverWithState.dispatchEvent(LifecycleRegistry.java:361)
E/AndroidRuntime(28052):    at androidx.lifecycle.LifecycleRegistry.forwardPass(LifecycleRegistry.java:300)
E/AndroidRuntime(28052):    at androidx.lifecycle.LifecycleRegistry.sync(LifecycleRegistry.java:339)
E/AndroidRuntime(28052):    at androidx.lifecycle.LifecycleRegistry.moveToState(LifecycleRegistry.java:145)
E/AndroidRuntime(28052):    at androidx.lifecycle.LifecycleRegistry.handleLifecycleEvent(LifecycleRegistry.java:131)
E/AndroidRuntime(28052):    at io.flutter.embedding.android.FlutterActivity.onResume(FlutterActivity.java:599)
E/AndroidRuntime(28052):    at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1454)
E/AndroidRuntime(28052):    at android.app.Activity.performResume(Activity.java:8111)
E/AndroidRuntime(28052):    at android.app.ActivityThread.performResumeActivity(ActivityThread.java:4647)
E/AndroidRuntime(28052):    ... 11 more

My code:

if (Platform.isAndroid) {
    await startForegroundService();
    MediaStream stream = await navigator.mediaDevices.getDisplayMedia({'video':true,'audio':true});
    var connections = await peerConnection!.getSenders();
    connections.forEach((rtpSender) {
      if (rtpSender.track!.kind == 'video') {
        rtpSender.replaceTrack(stream.getVideoTracks()[0]);
      }
    });
    localVideo.srcObject = stream;
    localStream = stream;
}

To start a foreground service I use the plugin flutter_foreground_plugin .

If anyone has a suggestion, it will be a pleasure. Thanks in advance.

Mine works. I am using flutter_foreground_task: ^3.5.5

Just wrap scaffold body with WithForegroundTask widget provided by package.

just add things described in the package description but add one more thing( media projection attribute should be added for it).

<service android:name="com.pravera.flutter_foreground_task.service.ForegroundService" android:foregroundServiceType="mediaProjection"/>
  Future<bool> _startForegroundTask() async {
    // You can save data using the saveData function.
    //await FlutterForegroundTask.saveData(key: 'customData', value: 'hello');

    ReceivePort? receivePort;
    if (await FlutterForegroundTask.isRunningService) {
      receivePort = await FlutterForegroundTask.restartService();
    } else {
      receivePort = await FlutterForegroundTask.startService(
        notificationTitle: 'Ongoing call',
        notificationText: 'Tap to return to the app',
        callback: () {
          //FlutterForegroundTask.setTaskHandler(FirstTaskHandler());
        },
      );
    }

/*     if (receivePort != null) {
      _receivePort = receivePort;
      _receivePort?.listen((message) {
        if (message is DateTime) {
          print('receive timestamp: $message');
        }
      });

      return true;
    } */

    return false;
  }

  Future<void> _initForegroundTask() async {
    await FlutterForegroundTask.init(
      androidNotificationOptions: AndroidNotificationOptions(
        channelId: 'ongoing_call_notification_channel_id',
        channelName: 'Ongoing call Notification',
        channelDescription:
            'This notification appears when the foreground service is running.',
        channelImportance: NotificationChannelImportance.LOW,
        priority: NotificationPriority.LOW,
        iconData: const NotificationIconData(
          resType: ResourceType.mipmap,
          resPrefix: ResourcePrefix.ic,
          name: 'launcher',
        ),
/*         buttons: [
          const NotificationButton(id: 'returnToCall', text: 'Return'),
          const NotificationButton(id: 'endCall', text: 'End Call'),
        ], */
      ),
      foregroundTaskOptions: const ForegroundTaskOptions(
        interval: 5000,
        autoRunOnBoot: false,
        allowWifiLock: true,
      ),
      printDevLog: true,
    );
    await _startForegroundTask();
  }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM