AgoraIO-Extensions / Agora-Flutter-SDK

Flutter plugin of Agora RTC SDK for Android/iOS/macOS/Windows

Home Page:https://pub.dev/packages/agora_rtc_engine

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

[windows] agora in secondary window crashes app if window is closed

develocode777 opened this issue · comments

Hello,

I use desktop_multi_window to run agora in a secondary window, if I close the window by pressing the x in the upper right the whole flutter app crashes without giving an error message, this happens only if I call _engine.release() before closing. On macos there is no problem.

When I run the app in Visual studio it shows me this error:

Screenshot 2024-02-16 080828

I have found a workaround, if I set _localUserJoined = false before calling engine.release() then it does not crash anymore:

_localUserJoined ? SizedBox( width: 180, height: 120, child: AgoraVideoView( controller: VideoViewController( rtcEngine: _engine, canvas: VideoCanvas(uid: 0), ), ), ) : const CircularProgressIndicator(),

Thanks for your reporting, can you provide a reproducible demo for this case so that we can investigate this issue more easily?

flutter_window.cpp:

#include "flutter_window.h"

#include <optional>

#include "flutter/generated_plugin_registrant.h"

#include "desktop_multi_window/desktop_multi_window_plugin.h"

#include <agora_rtc_engine/agora_rtc_engine_plugin.h>
#include <iris_method_channel/iris_method_channel_plugin_c_api.h>

FlutterWindow::FlutterWindow(const flutter::DartProject &project)
    : project_(project) {}

FlutterWindow::~FlutterWindow() {}

bool FlutterWindow::OnCreate()
{
  if (!Win32Window::OnCreate())
  {
    return false;
  }

  RECT frame = GetClientArea();


  flutter_controller_ = std::make_unique<flutter::FlutterViewController>(
      frame.right - frame.left, frame.bottom - frame.top, project_);

  if (!flutter_controller_->engine() || !flutter_controller_->view())
  {
    return false;
  }
  RegisterPlugins(flutter_controller_->engine());
  DesktopMultiWindowSetWindowCreatedCallback([](void *controller)
                                             {
                                               auto *flutter_view_controller =
                                                   reinterpret_cast<flutter::FlutterViewController *>(controller);
                                               auto *registry = flutter_view_controller->engine();

                                               AgoraRtcEnginePluginRegisterWithRegistrar(
                                                   registry->GetRegistrarForPlugin("AgoraRtcEnginePlugin"));
                                               IrisMethodChannelPluginCApiRegisterWithRegistrar(
                                                   registry->GetRegistrarForPlugin("IrisMethodChannelPluginCApi")); });
  SetChildContent(flutter_controller_->view()->GetNativeWindow());

  flutter_controller_->engine()->SetNextFrameCallback([&]()
                                                      { this->Show(); });

  flutter_controller_->ForceRedraw();

  return true;
}

void FlutterWindow::OnDestroy()
{
  if (flutter_controller_)
  {
    flutter_controller_ = nullptr;
  }

  Win32Window::OnDestroy();
}

LRESULT
FlutterWindow::MessageHandler(HWND hwnd, UINT const message,
                              WPARAM const wparam,
                              LPARAM const lparam) noexcept
{

  if (flutter_controller_)
  {
    std::optional<LRESULT> result =
        flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam,
                                                      lparam);
    if (result)
    {
      return *result;
    }
  }

  switch (message)
  {
  case WM_FONTCHANGE:
    flutter_controller_->engine()->ReloadSystemFonts();
    break;
  }

  return Win32Window::MessageHandler(hwnd, message, wparam, lparam);
}

main.dart:


import 'package:agora_rtc_engine/agora_rtc_engine.dart';
import 'package:desktop_multi_window/desktop_multi_window.dart';
import 'package:flutter/material.dart';

void main(List<String> args) {
  if (args.firstOrNull == 'multi_window') {
    runApp(AgoraApp());
  } else {
    runApp(const MainApp());
  }
}

class MainApp extends StatelessWidget {
  const MainApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: Center(
          child: ElevatedButton(
              onPressed: () async {
                final window =
                    await DesktopMultiWindow.createWindow(jsonEncode({
                  'args1': 'Sub window',
                  'args2': 100,
                  'args3': true,
                  'bussiness': 'bussiness_test',
                }));
                window
                  ..setFrame(const Offset(0, 0) & const Size(1280, 720))
                  ..center()
                  ..setTitle('Another window')
                  ..show();
              },
              child: Text('open window')),
        ),
      ),
    );
  }
}

class AgoraApp extends StatefulWidget {
  const AgoraApp({super.key});

  @override
  State<AgoraApp> createState() => _AgoraAppState();
}

class _AgoraAppState extends State<AgoraApp> {
  final String channel = 'test';
  bool _localUserJoined = false;
  late RtcEngine _engine;

  @override
  void initState() {
    super.initState();
    initAgora();
  }

  Future<void> initAgora() async {

    _engine = createAgoraRtcEngine();
    await _engine.initialize(RtcEngineContext(
      appId: '',
      channelProfile: ChannelProfileType.channelProfileLiveBroadcasting,
    ));

    _engine.registerEventHandler(RtcEngineEventHandler(
      onError: (err, msg) {
        print(err);
        print(msg);
      },
      onJoinChannelSuccess: (RtcConnection connection, int elapsed) {
        debugPrint("local user ${connection.localUid} joined");
        setState(() {
          _localUserJoined = true;
        });
      },
      onUserJoined: (RtcConnection connection, int rUid, int elapsed) {
        debugPrint("remote user $rUid joined");
      },
      onUserOffline:
          (RtcConnection connection, int rUid, UserOfflineReasonType reason) {
        debugPrint("remote user $rUid left channel");
      },
      onTokenPrivilegeWillExpire: (RtcConnection connection, String token) {
        debugPrint(
            '[onTokenPrivilegeWillExpire] connection: ${connection.toJson()}, token: $token');
      },
    ));

    await _engine.setClientRole(role: ClientRoleType.clientRoleBroadcaster);
    await _engine.enableVideo();
    await _engine.startPreview();

    await _engine.joinChannel(
      token:
          '',
      channelId: channel,
      uid: 0,
      options: const ChannelMediaOptions(),
    );
    _localUserJoined = true;
    setState(() {});
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            _localUserJoined
                ? SizedBox(
                    width: 180,
                    height: 120,
                    child: AgoraVideoView(
                      controller: VideoViewController(
                        rtcEngine: _engine,
                        canvas: VideoCanvas(uid: 0),
                      ),
                    ),
                  )
                : const CircularProgressIndicator(),
            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                ElevatedButton(
                    onPressed: () async {
                      await _engine.leaveChannel();
                      await _engine.release();
                    },
                    child: Text('leave channel and release engine'))
              ],
            ),
          ],
        ),
      ),
    );
  }
}

if I close the window by pressing the x in the upper right the whole flutter app crashes without giving an error message, this happens only if I call _engine.release() before closing.

Based on your code, does it mean you click the "leave channel and release engine" button, and then click the x of the window?

This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please raise a new issue.