Browse Source

refactor(call): 移除RTM消息处理改为使用onMessageContentChanged

- 移除RTMManager相关依赖和消息监听器注册
- 移除RTM频道订阅和取消订阅逻辑
- 移除RTM消息发送(accept、reject、hangup)相关代码
- 添加handleCallStatusChange方法处理通话状态变化
- 修改接听通话逻辑改为通过onMessageContentChanged接收通知
- 更新RTCManager中CallController实例获取方式
- 优化代码结构和错误处理机制
master
Jolie 2 months ago
parent
commit
0a7d02adc3
5 changed files with 812 additions and 580 deletions
  1. 348
      lib/controller/message/call_controller.dart
  2. 910
      lib/im/im_manager.dart
  3. 52
      lib/pages/discover/live_room_page.dart
  4. 24
      lib/rtc/rtc_manager.dart
  5. 58
      lib/widget/live/live_room_anchor_showcase.dart

348
lib/controller/message/call_controller.dart

@ -1,19 +1,16 @@
import 'dart:async';
import 'dart:convert';
import 'dart:typed_data';
import 'package:agora_rtc_engine/agora_rtc_engine.dart';
import 'package:agora_rtm/agora_rtm.dart';
import 'package:audioplayers/audioplayers.dart';
import 'package:dating_touchme_app/generated/assets.dart';
import 'package:dating_touchme_app/model/rtc/rtc_channel_data.dart';
import 'package:dating_touchme_app/network/network_service.dart';
import 'package:dating_touchme_app/rtc/rtc_manager.dart';
import 'package:dating_touchme_app/rtc/rtm_manager.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:get/get.dart';
import 'package:im_flutter_sdk/im_flutter_sdk.dart';
import 'package:permission_handler/permission_handler.dart';
import '../discover/room_controller.dart';
import '../overlay_controller.dart';
import 'chat_controller.dart';
@ -118,88 +115,7 @@ class CallController extends GetxController {
}
});
// RTM RTM
_registerRtmMessageListener();
}
/// RTM
void _registerRtmMessageListener() {
RTMManager.instance.onMessageEvent = (MessageEvent event) {
_handleRtmMessage(event);
};
print('✅ [CallController] RTM 消息监听器已注册');
}
/// RTM
Future<void> _handleRtmMessage(MessageEvent event) async {
try {
//
String messageText;
if (event.message is String) {
messageText = event.message as String;
} else if (event.message is Uint8List) {
messageText = utf8.decode(event.message as Uint8List);
} else {
messageText = event.message.toString();
}
final messageData = json.decode(messageText) as Map<String, dynamic>;
print('📥 [CallController] 收到 RTM 消息: $messageData');
//
if (messageData['type'] == 'call_message') {
final event = messageData['event'] as String?;
if (event == 'accept') {
// accept UID
final uid = messageData['uid'];
if (uid != null) {
remoteUid.value = uid is int ? uid : int.tryParse(uid.toString());
print(
'📞 [CallController] 收到 accept 消息,设置 remoteUid: ${remoteUid.value}',
);
}
//
_stopCallTimeoutTimer();
// accept
_startCallTimer();
print('📞 [CallController] 收到 accept 消息,已启动通话计时器');
} else if (event == 'hangup') {
// 退
print('📞 [CallController] 收到 hangup 消息,执行退出逻辑');
final channelId = messageData['channelId'] as String?;
if (channelId != null && channelId.isNotEmpty) {
RTMManager.instance.unsubscribe(channelId);
}
SmartDialog.dismiss(tag: 'video_call_invite_dialog');
_handleHangupMessage();
} else if (event == 'reject') {
// reject 退
print('📞 [CallController] 收到 reject 消息,执行退出逻辑');
//
_stopCallTimeoutTimer();
final channelId = messageData['channelId'] as String?;
if (channelId != null && channelId.isNotEmpty) {
RTMManager.instance.unsubscribe(channelId);
print('✅ [CallController] 已取消订阅 RTM 频道: $channelId');
}
//
if (Get.isRegistered<OverlayController>()) {
final overlayController = Get.find<OverlayController>();
overlayController.hideVideoCall();
print('✅ [CallController] 已关闭通话小窗口');
}
// 退 VideoCallPage VideoCallPage
if (Get.currentRoute.contains('VideoCallPage')) {
Get.back();
print('✅ [CallController] 已退出 VideoCallPage');
}
//
await endCall(callDuration: callDurationSeconds.value);
}
}
} catch (e) {
print('❌ [CallController] 处理 RTM 消息失败: $e');
}
// RTM onMessageContentChanged处理
}
/// RTC频道
@ -326,10 +242,6 @@ class CallController extends GetxController {
);
print('✅ [CallController] 已加入 RTC 频道: ${channelData.channelId}');
// RTC RTM
await RTMManager.instance.subscribe(channelData.channelId);
print('✅ [CallController] 已订阅 RTM 频道: ${channelData.channelId}');
// 3030
_startCallTimeoutTimer();
@ -408,15 +320,33 @@ class CallController extends GetxController {
print('📞 [CallController] 视频通话,已打开摄像头');
}
// RTC
await joinChannel(channelId);
print('✅ [CallController] 已加入 RTC 频道: $channelId');
// RTC token
final response = await _networkService.rtcApi.getSwRtcToken(channelId);
final base = response.data;
if (base.isSuccess && base.data != null) {
rtcChannel.value = base.data;
// UID
_callUid = base.data!.uid;
await _joinRtcChannel(
base.data!.token,
channelId,
base.data!.uid,
ClientRoleType.clientRoleBroadcaster,
);
// RTC uid UID
final initiatorUid = callInfo['uid'] as int?;
if (initiatorUid != null) {
remoteUid.value = initiatorUid;
print('📞 [CallController] 从消息中获取到发起方 UID: $initiatorUid,已设置 remoteUid');
// uid UID
final initiatorUid = callInfo['uid'] as int?;
if (initiatorUid != null) {
remoteUid.value = initiatorUid;
print(
'📞 [CallController] 从消息中获取到发起方 UID: $initiatorUid,已设置 remoteUid',
);
}
} else {
SmartDialog.showToast('获取RTC token失败');
return false;
}
return true;
@ -454,22 +384,7 @@ class CallController extends GetxController {
return false;
}
print('✅ [CallController] 已调用拒绝一对一RTC频道接口,channelId: $channelId');
await RTMManager.instance.unsubscribe(channelId);
final callInfo = _parseCallInfo(message);
final callTypeStr = callInfo?['callType'] as String?;
final callType = callTypeStr == 'video' ? 'video' : 'voice';
// RTM
await RTMManager.instance.publishChannelMessage(
channelName: channelId,
message: json.encode({
'type': 'call_message',
'uid': 0,
'channelId': channelId,
'callType': callType,
'event': 'reject',
}),
);
// callStatus为'rejected'onMessageContentChanged收到通知
}
//
@ -631,32 +546,13 @@ class CallController extends GetxController {
// UID
_callUid = base.data!.uid;
// RTM
await RTMManager.instance.subscribe(channelName);
//
final callSession = currentCall.value;
final callType = callSession?.callType == CallType.video
? 'video'
: 'voice';
// RTM UID
await RTMManager.instance.publishChannelMessage(
channelName: channelName,
message: json.encode({
'type': 'call_message',
'uid': base.data!.uid,
'callType': callType,
'event': 'accept',
}),
);
await _joinRtcChannel(
base.data!.token,
channelName,
base.data!.uid,
ClientRoleType.clientRoleBroadcaster,
);
// callStatus为'calling'onMessageContentChanged收到通知
}
}
@ -675,19 +571,7 @@ class CallController extends GetxController {
role: roleType,
rtcType: RTCType.call,
);
final data = {
'channelId': channelName,
'seatNumber': 1,
'isMicrophoneOn': true,
'isVideoOn': true,
};
final response = await _networkService.rtcApi.connectRtcChannel(data);
if (!response.data.isSuccess) {
SmartDialog.showToast(response.data.message);
return;
}
SmartDialog.showToast('加入通话成功');
print('✅ [CallController] 已加入 RTC 频道: $channelName');
}
Future<bool> _ensureRtcPermissions() async {
@ -759,36 +643,10 @@ class CallController extends GetxController {
print('✅ [CallController] 已调用终止一对一RTC频道接口,channelId: $_callChannelId');
}
if (_callChannelId != null &&
_callChannelId!.isNotEmpty &&
_callUid != null) {
final callType = callSession?.callType == CallType.video
? 'video'
: 'voice';
await RTMManager.instance.publishChannelMessage(
channelName: _callChannelId!,
message: json.encode({
'type': 'call_message',
'uid': _callUid!,
'channelId': _callChannelId,
'callType': callType,
'event': 'hangup',
}),
);
print(
'✅ [CallController] 已发送 RTM 挂断消息,channelId: $_callChannelId, uid: $_callUid',
);
}
// RTC频道
await RTCManager.instance.leaveChannel();
// RTM
if (_callChannelId != null && _callChannelId!.isNotEmpty) {
await RTMManager.instance.unsubscribe(_callChannelId!);
print('✅ [CallController] 已取消订阅 RTM 频道: $_callChannelId');
}
// callStatus为'cancelled''terminated'onMessageContentChanged收到通知
//
await endCall(callDuration: callDurationSeconds.value);
@ -812,41 +670,127 @@ class CallController extends GetxController {
print('✅ [CallController] 通话已挂断');
}
///
Future<void> _handleHangupMessage() async {
//
SmartDialog.dismiss();
print('✅ [CallController] 已关闭视频通话邀请弹框');
/// callStatus变化onMessageContentChanged调用
Future<void> handleCallStatusChange({
required EMMessage message,
required String callStatus,
String? channelId,
int? uid,
int? callDuration,
}) async {
print(
'📞 [CallController] 处理callStatus变化: callStatus=$callStatus, channelId=$channelId',
);
//
_stopCallTimeoutTimer();
final callSession = currentCall.value;
if (callSession == null) {
print('⚠️ [CallController] 当前没有进行中的通话,忽略callStatus变化');
return;
}
//
stopCallAudio();
// channelId
if (channelId != null &&
channelId.isNotEmpty &&
_callChannelId != channelId) {
print(
'⚠️ [CallController] channelId不匹配,忽略callStatus变化: 当前=$_callChannelId, 消息=$channelId',
);
return;
}
// RTC频道
await RTCManager.instance.leaveChannel();
try {
if (callStatus == 'calling') {
//
print('📞 [CallController] 通话已接通,callStatus=$callStatus');
// UID并启动计时器
if (callSession.isInitiator) {
//
stopCallAudio();
//
_stopCallTimeoutTimer();
//
_startCallTimer();
print('📞 [CallController] 已启动通话计时器');
// remoteUid RTCManager onUserJoined
// RTCManager remoteUsersNotifier
if (remoteUid.value == null) {
final rtcManager = RTCManager.instance;
final remoteUsers = rtcManager.remoteUsersNotifier.value;
if (remoteUsers.isNotEmpty) {
remoteUid.value = remoteUsers.first;
print(
'📞 [CallController] 从 RTCManager.remoteUsersNotifier 获取到 remoteUid: ${remoteUsers.first}',
);
} else if (uid != null) {
// RTCManager 使 uid
remoteUid.value = uid;
print('📞 [CallController] 使用消息中的 uid 设置 remoteUid: $uid');
}
}
}
} else if (callStatus == 'rejected') {
//
print('📞 [CallController] 通话被拒绝,callStatus=$callStatus');
// RTM
if (_callChannelId != null && _callChannelId!.isNotEmpty) {
await RTMManager.instance.unsubscribe(_callChannelId!);
print('✅ [CallController] 已取消订阅 RTM 频道: $_callChannelId');
}
// 退
if (callSession.isInitiator) {
//
_stopCallTimeoutTimer();
//
if (Get.isRegistered<OverlayController>()) {
final overlayController = Get.find<OverlayController>();
overlayController.hideVideoCall();
print('✅ [CallController] 已关闭通话小窗口');
}
// 退 VideoCallPage VideoCallPage
if (Get.currentRoute.contains('VideoCallPage')) {
Get.back();
print('✅ [CallController] 已退出 VideoCallPage');
}
//
await endCall(callDuration: callDurationSeconds.value);
}
} else if (callStatus == 'cancelled' || callStatus == 'terminated') {
//
print(
'📞 [CallController] 通话被取消/终止,callStatus=$callStatus, isInitiator=${callSession.isInitiator}',
);
//
await endCall(callDuration: callDurationSeconds.value);
//
SmartDialog.dismiss();
print('✅ [CallController] 已关闭视频通话邀请弹框');
//
if (Get.isRegistered<OverlayController>()) {
final overlayController = Get.find<OverlayController>();
overlayController.hideVideoCall();
print('✅ [CallController] 已关闭通话小窗口');
}
//
_stopCallTimeoutTimer();
// 退 VideoCallPage VideoCallPage
if (Get.currentRoute.contains('VideoCallPage')) {
Get.back();
print('✅ [CallController] 已退出 VideoCallPage');
//
stopCallAudio();
//
_stopCallTimer();
// RTC频道
await RTCManager.instance.leaveChannel();
//
await endCall(callDuration: callDuration ?? callDurationSeconds.value);
//
if (Get.isRegistered<OverlayController>()) {
final overlayController = Get.find<OverlayController>();
overlayController.hideVideoCall();
print('✅ [CallController] 已关闭通话小窗口');
}
// 退 VideoCallPage VideoCallPage
if (Get.currentRoute.contains('VideoCallPage')) {
Get.back();
print('✅ [CallController] 已退出 VideoCallPage');
}
}
} catch (e) {
print('❌ [CallController] 处理callStatus变化失败: $e');
}
}

910
lib/im/im_manager.dart
File diff suppressed because it is too large
View File

52
lib/pages/discover/live_room_page.dart

@ -248,7 +248,7 @@ class _LiveRoomPageState extends State<LiveRoomPage> {
}
//
Future.delayed(const Duration(milliseconds: 200), () {
_overlayController.show();
_overlayController.show();
});
},
child: Scaffold(
@ -281,41 +281,41 @@ class _LiveRoomPageState extends State<LiveRoomPage> {
),
Container(
padding: EdgeInsets.only(top: MediaQuery.of(context).padding.top),
child: Column(
children: [
SizedBox(height: 10.w),
Obx(() {
child: Column(
children: [
SizedBox(height: 10.w),
Obx(() {
final detail = _roomController.rtcChannelDetail.value;
final anchorInfo = detail?.anchorInfo;
final anchorInfo = detail?.anchorInfo;
final userName = anchorInfo?.nickName ?? '用户';
final avatarAsset = anchorInfo?.profilePhoto ?? Assets.imagesUserAvatar;
const popularityText = '0'; // TODO: 使
const popularityText = '0'; // TODO: 使
return LiveRoomUserHeader(
userName: userName,
popularityText: popularityText,
avatarAsset: avatarAsset,
onCloseTap: () {
SmartDialog.dismiss();
// 退RTM消息
if (Get.isRegistered<RoomController>()) {
return LiveRoomUserHeader(
userName: userName,
popularityText: popularityText,
avatarAsset: avatarAsset,
onCloseTap: () {
SmartDialog.dismiss();
// 退RTM消息
if (Get.isRegistered<RoomController>()) {
final roomController = Get.find<RoomController>();
roomController.chatMessages.clear();
}
roomController.chatMessages.clear();
}
Get.back();
//
Future.delayed(const Duration(milliseconds: 200), () {
_overlayController.show();
_overlayController.show();
});
},
);
}),
SizedBox(height: 7.w),
LiveRoomAnchorShowcase(),
SizedBox(height: 5.w),
const LiveRoomActiveSpeaker(),
SizedBox(height: 9.w),
},
);
}),
SizedBox(height: 7.w),
LiveRoomAnchorShowcase(),
SizedBox(height: 5.w),
const LiveRoomActiveSpeaker(),
SizedBox(height: 9.w),
Expanded(child: const LiveRoomNoticeChatPanel()),
// / LiveRoomActionBar
if (MediaQuery.of(context).viewInsets.bottom == 0)

24
lib/rtc/rtc_manager.dart

@ -174,12 +174,13 @@ class RTCManager {
} else if (type == RTCType.call) {
// CallController
print('📞 [RTCManager] 通话场景:检测到用户加入,UID:$remoteUid');
if (Get.isRegistered<CallController>()) {
final callController = Get.find<CallController>();
try {
// 使 CallController.instance使
final callController = CallController.instance;
callController.remoteUid.value = remoteUid;
print('✅ [RTCManager] 通话场景:已设置 CallController.remoteUid = $remoteUid');
} else {
print('⚠️ [RTCManager] CallController 未注册,无法设置 remoteUid');
} catch (e) {
print('⚠️ [RTCManager] 设置 CallController.remoteUid 失败: $e');
}
} else {
print('⚠️ [RTCManager] 未知的 RTC 类型:$type');
@ -565,11 +566,16 @@ class RTCManager {
remoteUsersNotifier.value = List<int>.unmodifiable(_remoteUserIds);
// CallController remoteUid
if (type == RTCType.call && Get.isRegistered<CallController>()) {
final callController = Get.find<CallController>();
if (callController.remoteUid.value == null) {
callController.remoteUid.value = remoteUid;
print('📞 [RTCManager] _handleRemoteUserJoined: 已同步 remoteUid 到 CallController: $remoteUid');
if (type == RTCType.call) {
try {
// 使 CallController.instance使
final callController = CallController.instance;
if (callController.remoteUid.value == null) {
callController.remoteUid.value = remoteUid;
print('📞 [RTCManager] _handleRemoteUserJoined: 已同步 remoteUid 到 CallController: $remoteUid');
}
} catch (e) {
print('⚠️ [RTCManager] _handleRemoteUserJoined 设置 CallController.remoteUid 失败: $e');
}
}
}

58
lib/widget/live/live_room_anchor_showcase.dart

@ -106,24 +106,24 @@ class _LiveRoomAnchorShowcaseState extends State<LiveRoomAnchorShowcase> {
_showGiftPopupForUser(anchorInfo, 2);
}
},
child: Container(
width: 47.w,
height: 20.w,
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(20.w)),
color: Colors.white,
),
child: Center(
child: Text(
anchorInfo?.isFriend == true ? '好友' : "加好友",
style: TextStyle(
fontSize: 11.w,
color: const Color.fromRGBO(117, 98, 249, 1),
),
child: Container(
width: 47.w,
height: 20.w,
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(20.w)),
color: Colors.white,
),
child: Center(
child: Text(
anchorInfo?.isFriend == true ? '好友' : "加好友",
style: TextStyle(
fontSize: 11.w,
color: const Color.fromRGBO(117, 98, 249, 1),
),
),
),
),
),
);
}),
],
@ -290,25 +290,25 @@ class _LiveRoomAnchorShowcaseState extends State<LiveRoomAnchorShowcase> {
}
_showGiftPopupForUser(userInfo, 2);
},
child: Container(
width: 47.w,
height: 20.w,
decoration: BoxDecoration(
borderRadius: BorderRadius.all(
Radius.circular(20.w),
),
color: Colors.white,
child: Container(
width: 47.w,
height: 20.w,
decoration: BoxDecoration(
borderRadius: BorderRadius.all(
Radius.circular(20.w),
),
child: Center(
child: Text(
userInfo.isFriend != true ? "加好友" : '好友',
style: TextStyle(
fontSize: 11.w,
color: const Color.fromRGBO(117, 98, 249, 1),
),
color: Colors.white,
),
child: Center(
child: Text(
userInfo.isFriend != true ? "加好友" : '好友',
style: TextStyle(
fontSize: 11.w,
color: const Color.fromRGBO(117, 98, 249, 1),
),
),
),
),
),
),
Positioned(

Loading…
Cancel
Save