From c55bd324785772785bcb040b4a1176d54dea99c6 Mon Sep 17 00:00:00 2001 From: Jolie <412895109@qq.com> Date: Sun, 4 Jan 2026 01:27:24 +0800 Subject: [PATCH] =?UTF-8?q?fix(call):=20=E8=A7=A3=E5=86=B3=E9=80=9A?= =?UTF-8?q?=E8=AF=9D=E4=B8=8E=E7=9B=B4=E6=92=AD=E5=8A=9F=E8=83=BD=E5=86=B2?= =?UTF-8?q?=E7=AA=81=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在CallController单例获取逻辑中添加GetX注册检查,确保实例正确获取 - 添加直播间状态检查,防止在直播间内发起或接听通话 - 修改通话状态为waitCalling,优化通话流程状态管理 - 在通话结束逻辑中添加异常处理,确保RTC频道正确清理 - 在RoomController中添加通话状态检查,防止通话期间开始直播或加入直播间 - 修复VideoCallPage挂断通话后页面重复退出问题 - 优化RTCManager中直播频道详情获取逻辑的缩进格式 --- lib/controller/discover/room_controller.dart | 36 +++++++++ lib/controller/message/call_controller.dart | 85 ++++++++++++++++---- lib/pages/message/video_call_page.dart | 4 +- lib/rtc/rtc_manager.dart | 58 ++++++------- 4 files changed, 135 insertions(+), 48 deletions(-) diff --git a/lib/controller/discover/room_controller.dart b/lib/controller/discover/room_controller.dart index 1cd07c1..84cb51d 100644 --- a/lib/controller/discover/room_controller.dart +++ b/lib/controller/discover/room_controller.dart @@ -22,6 +22,7 @@ import '../../pages/discover/live_end_page.dart'; import '../../pages/mine/real_name_page.dart'; import '../../pages/setting/match_spread_page.dart'; import '../../widget/live/live_recharge_popup.dart'; +import '../message/call_controller.dart'; import 'svga_player_manager.dart'; // 当前角色 @@ -135,6 +136,27 @@ class RoomController extends GetxController with WidgetsBindingObserver { if (isLive.value) { return; } + + // 检查是否正在通话中(包括呼叫中) + try { + // 先尝试使用 Get.find 获取已注册的实例,如果不存在再使用 instance + CallController callController; + if (Get.isRegistered()) { + callController = Get.find(); + } else { + callController = CallController.instance; + } + print('⚠️ [RoomController] 检查通话状态: currentCall=${callController.currentCall.value}, hashCode=${callController.hashCode}'); + if (callController.currentCall.value != null) { + SmartDialog.showToast('请先结束通话'); + print('⚠️ [RoomController] 当前正在通话中,无法开始直播'); + return; + } + } catch (e) { + // 如果获取失败,说明没有正在进行的通话,继续执行 + print('⚠️ [RoomController] 获取CallController失败(可能没有通话): $e'); + } + final granted = await _ensureRtcPermissions(); if (!granted) return; @@ -161,6 +183,20 @@ class RoomController extends GetxController with WidgetsBindingObserver { } Future joinChannel(String channelName) async { + // 检查是否正在通话中(包括呼叫中) + try { + // 直接使用 CallController.instance,因为它使用单例模式会自动注册 + final callController = CallController.instance; + if (callController.currentCall.value != null) { + SmartDialog.showToast('请先结束通话'); + print('⚠️ [RoomController] 当前正在通话中,无法加入直播间'); + return; + } + } catch (e) { + // 忽略错误,继续处理加入频道逻辑 + print('⚠️ [RoomController] 检查通话状态失败: $e'); + } + final response = await _networkService.rtcApi.getSwRtcToken(channelName); final base = response.data; if (base.isSuccess && base.data != null) { diff --git a/lib/controller/message/call_controller.dart b/lib/controller/message/call_controller.dart index d5dcdd8..a2c9364 100644 --- a/lib/controller/message/call_controller.dart +++ b/lib/controller/message/call_controller.dart @@ -58,7 +58,16 @@ class CallSession { class CallController extends GetxController { static CallController? _instance; static CallController get instance { - _instance ??= Get.put(CallController()); + if (_instance != null) { + return _instance!; + } + // 如果 GetX 中已注册,使用 Get.find 获取 + if (Get.isRegistered()) { + _instance = Get.find(); + return _instance!; + } + // 否则创建新实例并注册 + _instance = Get.put(CallController(), permanent: true); return _instance!; } @@ -178,6 +187,21 @@ class CallController extends GetxController { return false; } + // 检查是否在直播间 + try { + if (Get.isRegistered()) { + final roomController = Get.find(); + if (roomController.isLive.value) { + SmartDialog.showToast('请先退出直播间'); + print('⚠️ [CallController] 当前在直播间,无法发起通话'); + return false; + } + } + } catch (e) { + // 忽略错误,继续处理发起通话逻辑 + print('⚠️ [CallController] 检查直播间状态失败: $e'); + } + // 清空之前的远端用户UID和通话信息 remoteUid.value = null; @@ -202,7 +226,7 @@ class CallController extends GetxController { final session = CallSession( targetUserId: targetUserId, callType: callType, - status: CallStatus.calling, + status: CallStatus.waitCalling, isInitiator: true, startTime: DateTime.now(), ); @@ -255,6 +279,21 @@ class CallController extends GetxController { required EMMessage message, ChatController? chatController, }) async { + // 检查是否在直播间 + try { + if (Get.isRegistered()) { + final roomController = Get.find(); + if (roomController.isLive.value) { + SmartDialog.showToast('请先退出直播间再接听'); + print('⚠️ [CallController] 当前在直播间,无法接听通话'); + return false; + } + } + } catch (e) { + // 忽略错误,继续处理接听逻辑 + print('⚠️ [CallController] 检查直播间状态失败: $e'); + } + final callInfo = _parseCallInfo(message); if (callInfo == null) { return false; @@ -620,31 +659,43 @@ class CallController extends GetxController { callDurationSeconds.value == 0 && _callChannelId != null && _callChannelId!.isNotEmpty) { - final response = await _networkService.rtcApi.cancelOneOnOneRtcChannel({ - 'channelId': _callChannelId!, - }); - if (!response.data.isSuccess) { - SmartDialog.showToast(response.data.message); - return; + try { + final response = await _networkService.rtcApi.cancelOneOnOneRtcChannel({ + 'channelId': _callChannelId!, + }); + if (response.data.isSuccess) { + print('✅ [CallController] 已调用取消一对一RTC频道接口,channelId: $_callChannelId'); + } else { + print('⚠️ [CallController] 取消一对一RTC频道接口失败: ${response.data.message}'); + } + } catch (e) { + print('⚠️ [CallController] 调用取消接口异常: $e'); } - print('✅ [CallController] 已调用取消一对一RTC频道接口,channelId: $_callChannelId'); } else if (callSession != null && callDurationSeconds.value > 0 && _callChannelId != null && _callChannelId!.isNotEmpty) { // 如果通话已接通(无论是发起方还是接收方),调用终止接口 - final response = await _networkService.rtcApi.terminateOneOnOneRtcChannel( - {'channelId': _callChannelId!}, - ); - if (!response.data.isSuccess) { - SmartDialog.showToast(response.data.message); - return; + try { + final response = await _networkService.rtcApi.terminateOneOnOneRtcChannel( + {'channelId': _callChannelId!}, + ); + if (response.data.isSuccess) { + print('✅ [CallController] 已调用终止一对一RTC频道接口,channelId: $_callChannelId'); + } else { + print('⚠️ [CallController] 终止一对一RTC频道接口失败: ${response.data.message}'); + } + } catch (e) { + print('⚠️ [CallController] 调用终止接口异常: $e'); } - print('✅ [CallController] 已调用终止一对一RTC频道接口,channelId: $_callChannelId'); } // 离开RTC频道 - await RTCManager.instance.leaveChannel(); + try { + await RTCManager.instance.leaveChannel(); + } catch (e) { + print('⚠️ [CallController] 离开RTC频道异常: $e'); + } // 服务端会自动修改消息callStatus为'cancelled'或'terminated',客户端通过onMessageContentChanged收到通知 diff --git a/lib/pages/message/video_call_page.dart b/lib/pages/message/video_call_page.dart index b4a7b62..dde7e37 100644 --- a/lib/pages/message/video_call_page.dart +++ b/lib/pages/message/video_call_page.dart @@ -234,8 +234,8 @@ class _VideoCallPageState extends State { /// 挂断通话 void _hangUp() async { await _callController.hangUpCall(); - // 返回上一页 - Get.back(); + // hangUpCall() 方法内部已经调用了 Get.back() 来退出 VideoCallPage + // 所以这里不需要再次调用 Get.back(),避免退出两次导致回到MessagePage } @override diff --git a/lib/rtc/rtc_manager.dart b/lib/rtc/rtc_manager.dart index 4638121..b6091e4 100644 --- a/lib/rtc/rtc_manager.dart +++ b/lib/rtc/rtc_manager.dart @@ -133,22 +133,22 @@ class RTCManager { // 根据RTC类型判断是否执行 RoomController 的逻辑 // 只有直播类型才执行 RoomController 的逻辑 if (type == RTCType.live) { - // 调用 RoomController 的 fetchRtcChannelDetail 方法 - final channelId = connection.channelId; - if (Get.isRegistered() && - channelId != null && - channelId.isNotEmpty) { - final roomController = Get.find(); - await roomController.fetchRtcChannelDetail(channelId); - } + // 调用 RoomController 的 fetchRtcChannelDetail 方法 + final channelId = connection.channelId; + if (Get.isRegistered() && + channelId != null && + channelId.isNotEmpty) { + final roomController = Get.find(); + await roomController.fetchRtcChannelDetail(channelId); + } - if (connection.localUid == _currentUid) { - await RTMManager.instance.subscribe(_currentChannelId ?? ''); - await RTMManager.instance.publishChannelMessage( - channelName: _currentChannelId ?? '', - message: json.encode({'type': 'join_room', 'uid': _currentUid}), - ); - Get.to(() => const LiveRoomPage(id: 0)); + if (connection.localUid == _currentUid) { + await RTMManager.instance.subscribe(_currentChannelId ?? ''); + await RTMManager.instance.publishChannelMessage( + channelName: _currentChannelId ?? '', + message: json.encode({'type': 'join_room', 'uid': _currentUid}), + ); + Get.to(() => const LiveRoomPage(id: 0)); } } if (onJoinChannelSuccess != null) { @@ -163,13 +163,13 @@ class RTCManager { // 根据RTC类型判断是否执行 RoomController 的逻辑 // 只有直播类型才执行 RoomController 的逻辑 if (type == RTCType.live) { - // 调用 RoomController 的 fetchRtcChannelDetail 方法 - final channelId = connection.channelId; - if (Get.isRegistered() && - channelId != null && - channelId.isNotEmpty) { - final roomController = Get.find(); - await roomController.fetchRtcChannelDetail(channelId); + // 调用 RoomController 的 fetchRtcChannelDetail 方法 + final channelId = connection.channelId; + if (Get.isRegistered() && + channelId != null && + channelId.isNotEmpty) { + final roomController = Get.find(); + await roomController.fetchRtcChannelDetail(channelId); } } else if (type == RTCType.call) { // 通话场景:通知 CallController 远端用户已加入 @@ -202,13 +202,13 @@ class RTCManager { // 根据RTC类型判断是否执行 RoomController 的逻辑 // 只有直播类型才执行 RoomController 的逻辑 if (type == RTCType.live) { - // 调用 RoomController 的 fetchRtcChannelDetail 方法 - final channelId = connection.channelId; - if (Get.isRegistered() && - channelId != null && - channelId.isNotEmpty) { - final roomController = Get.find(); - await roomController.fetchRtcChannelDetail(channelId); + // 调用 RoomController 的 fetchRtcChannelDetail 方法 + final channelId = connection.channelId; + if (Get.isRegistered() && + channelId != null && + channelId.isNotEmpty) { + final roomController = Get.find(); + await roomController.fetchRtcChannelDetail(channelId); } }