diff --git a/lib/controller/message/call_controller.dart b/lib/controller/message/call_controller.dart new file mode 100644 index 0000000..4370c6a --- /dev/null +++ b/lib/controller/message/call_controller.dart @@ -0,0 +1,68 @@ +import 'package:dating_touchme_app/model/rtc/rtc_channel_data.dart'; +import 'package:dating_touchme_app/network/network_service.dart'; +import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; +import 'package:get/get.dart'; + +/// 通话相关控制器 +class CallController extends GetxController { + CallController({NetworkService? networkService}) + : _networkService = networkService ?? Get.find(); + + final NetworkService _networkService; + + /// 当前频道信息 + final Rxn rtcChannel = Rxn(); + + /// 是否正在创建频道 + final RxBool isCreatingChannel = false.obs; + + /// 创建一对一RTC频道 + /// [type] 1为音频,2为视频 + Future createOneOnOneRtcChannel({required int type}) async { + if (isCreatingChannel.value) { + print('⚠️ 正在创建频道,请稍候'); + return null; + } + + // 验证 type 参数 + if (type != 1 && type != 2) { + SmartDialog.showToast('类型参数错误:1为音频,2为视频'); + return null; + } + + isCreatingChannel.value = true; + + try { + final response = await _networkService.rtcApi.createOneOnOneRtcChannel({ + 'type': type, + }); + + if (response.data.isSuccess && response.data.data != null) { + rtcChannel.value = response.data.data; + print('✅ 创建一对一RTC频道成功: ${response.data.data?.channelId}'); + return response.data.data; + } else { + final message = response.data.message.isNotEmpty + ? response.data.message + : '创建频道失败'; + SmartDialog.showToast(message); + print('❌ 创建一对一RTC频道失败: $message'); + return null; + } + } catch (e) { + final errorMessage = '创建频道异常:$e'; + SmartDialog.showToast(errorMessage); + print('❌ $errorMessage'); + return null; + } finally { + isCreatingChannel.value = false; + } + } + + @override + void onClose() { + super.onClose(); + rtcChannel.value = null; + } +} + diff --git a/lib/controller/message/chat_controller.dart b/lib/controller/message/chat_controller.dart index b1342c4..9144ff7 100644 --- a/lib/controller/message/chat_controller.dart +++ b/lib/controller/message/chat_controller.dart @@ -1053,10 +1053,12 @@ class ChatController extends GetxController { /// [callType] 通话类型:'voice' 语音通话,'video' 视频通话 /// [callStatus] 通话状态:'calling' 通话中,'missed' 未接听,'cancelled' 已取消,'rejected' 已拒绝 /// [callDuration] 通话时长(秒),仅在 callStatus 为 'calling' 时有效 + /// [channelId] RTC频道ID Future sendCallMessage({ required String callType, // 'voice' 或 'video' required String callStatus, // 'calling', 'missed', 'cancelled', 'rejected' int? callDuration, // 通话时长(秒) + String? channelId, // RTC频道ID }) async { try { // 构建通话消息参数(需要转换为 Map) @@ -1067,6 +1069,9 @@ class ChatController extends GetxController { if (callDuration != null) { callParams['callDuration'] = callDuration.toString(); } + if (channelId != null && channelId.isNotEmpty) { + callParams['channelId'] = channelId; + } // 先创建自定义消息对象(即使发送失败也要显示在列表中) final tempMessage = EMMessage.createCustomSendMessage( diff --git a/lib/im/im_manager.dart b/lib/im/im_manager.dart index e310849..7e0079b 100644 --- a/lib/im/im_manager.dart +++ b/lib/im/im_manager.dart @@ -18,7 +18,7 @@ import '../network/user_api.dart'; import '../widget/message/message_notification_dialog.dart'; import '../widget/message/video_call_invite_dialog.dart'; import '../pages/message/video_call_page.dart'; -import '../controller/message/call_manager.dart'; +import '../rtc/call_manager.dart'; import '../service/local_notification_service.dart'; // 消息通知数据结构 diff --git a/lib/network/api_urls.dart b/lib/network/api_urls.dart index 2c18e43..599da59 100644 --- a/lib/network/api_urls.dart +++ b/lib/network/api_urls.dart @@ -42,6 +42,8 @@ class ApiUrls { 'dating-agency-chat-audio/user/get/sw/rtc/token'; static const String createRtcChannel = 'dating-agency-chat-audio/user/create/rtc-channel'; + static const String createOneOnOneRtcChannel = + 'dating-agency-chat-audio/user/create/one-on-one/rtc-channel'; static const String editOwnMarriageInformation = 'dating-agency-service/user/edit/own-marriage-information'; static const String getSwRtmToken = diff --git a/lib/network/rtc_api.dart b/lib/network/rtc_api.dart index e3dc9a6..e46519e 100644 --- a/lib/network/rtc_api.dart +++ b/lib/network/rtc_api.dart @@ -29,6 +29,12 @@ abstract class RtcApi { @POST(ApiUrls.createRtcChannel) Future>> createRtcChannel(); + /// 创建一对一RTC频道(type: 1为音频,2为视频) + @POST(ApiUrls.createOneOnOneRtcChannel) + Future>> createOneOnOneRtcChannel( + @Body() Map data, + ); + /// 获取 RTC 频道详情 @GET(ApiUrls.getRtcChannelDetail) Future>> getRtcChannelDetail( diff --git a/lib/network/rtc_api.g.dart b/lib/network/rtc_api.g.dart index fa855f3..5e0170f 100644 --- a/lib/network/rtc_api.g.dart +++ b/lib/network/rtc_api.g.dart @@ -114,6 +114,40 @@ class _RtcApi implements RtcApi { return httpResponse; } + @override + Future>> createOneOnOneRtcChannel( + Map data, + ) async { + final _extra = {}; + final queryParameters = {}; + final _headers = {}; + final _data = {}; + _data.addAll(data); + final _options = _setStreamType>>( + Options(method: 'POST', headers: _headers, extra: _extra) + .compose( + _dio.options, + 'dating-agency-chat-audio/user/create/one-on-one/rtc-channel', + queryParameters: queryParameters, + data: _data, + ) + .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)), + ); + final _result = await _dio.fetch>(_options); + late BaseResponse _value; + try { + _value = BaseResponse.fromJson( + _result.data!, + (json) => RtcChannelData.fromJson(json as Map), + ); + } on Object catch (e, s) { + errorLogger?.logError(e, s, _options); + rethrow; + } + final httpResponse = HttpResponse(_value, _result); + return httpResponse; + } + @override Future>> getRtcChannelDetail( String channelId, diff --git a/lib/network/user_api.g.dart b/lib/network/user_api.g.dart index 743d037..095ff32 100644 --- a/lib/network/user_api.g.dart +++ b/lib/network/user_api.g.dart @@ -1651,7 +1651,7 @@ class _UserApi implements UserApi { Options(method: 'GET', headers: _headers, extra: _extra) .compose( _dio.options, - '/dating-agency-uec/user/get/app-version/update', + 'dating-agency-uec/user/get/app-version/update', queryParameters: queryParameters, data: _data, ) diff --git a/lib/pages/message/chat_page.dart b/lib/pages/message/chat_page.dart index f2ee51d..f79fad5 100644 --- a/lib/pages/message/chat_page.dart +++ b/lib/pages/message/chat_page.dart @@ -4,7 +4,7 @@ import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; import 'package:im_flutter_sdk/im_flutter_sdk.dart'; -import '../../controller/message/call_manager.dart'; +import '../../rtc/call_manager.dart'; import '../../controller/message/chat_controller.dart'; import '../../controller/message/voice_player_manager.dart'; // import '../../controller/message/call_manager.dart'; // 暂时隐藏 diff --git a/lib/pages/message/video_call_page.dart b/lib/pages/message/video_call_page.dart index 6489454..46f2f94 100644 --- a/lib/pages/message/video_call_page.dart +++ b/lib/pages/message/video_call_page.dart @@ -6,7 +6,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; -import '../../controller/message/call_manager.dart'; +import '../../rtc/call_manager.dart'; import '../../controller/message/conversation_controller.dart'; import '../../controller/overlay_controller.dart'; import '../../model/home/marriage_data.dart'; diff --git a/lib/controller/message/call_manager.dart b/lib/rtc/call_manager.dart similarity index 93% rename from lib/controller/message/call_manager.dart rename to lib/rtc/call_manager.dart index ed03185..304e8ce 100644 --- a/lib/controller/message/call_manager.dart +++ b/lib/rtc/call_manager.dart @@ -4,9 +4,10 @@ import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; import 'package:im_flutter_sdk/im_flutter_sdk.dart'; -import '../../generated/assets.dart'; -import '../../im/im_manager.dart'; -import 'chat_controller.dart'; +import '../generated/assets.dart'; +import '../im/im_manager.dart'; +import '../controller/message/chat_controller.dart'; +import '../controller/message/call_controller.dart'; /// 通话类型 enum CallType { @@ -76,6 +77,19 @@ class CallManager extends GetxController { print('📞 [CallManager] 发起${callType == CallType.video ? "视频" : "语音"}通话,目标用户: $targetUserId'); + // 发起通话前,先调用 CallController 创建一对一 RTC 频道 + final callController = Get.put(CallController()); + final type = callType == CallType.video ? 2 : 1; // 1为音频,2为视频 + final channelData = await callController.createOneOnOneRtcChannel(type: type); + + if (channelData == null) { + print('❌ [CallManager] 创建RTC频道失败,无法发起通话'); + SmartDialog.showToast('创建通话频道失败'); + return false; + } + + print('✅ [CallManager] RTC频道创建成功: ${channelData.channelId}'); + // 创建通话会话 final session = CallSession( targetUserId: targetUserId, @@ -92,6 +106,7 @@ class CallManager extends GetxController { targetUserId: targetUserId, callType: callTypeStr, callStatus: 'missed', // 初始状态为未接听,等待对方响应 + channelId: channelData.channelId, // 传递频道ID chatController: chatController, ); @@ -305,6 +320,7 @@ class CallManager extends GetxController { required String callType, required String callStatus, int? callDuration, + String? channelId, ChatController? chatController, }) async { try { @@ -314,6 +330,7 @@ class CallManager extends GetxController { callType: callType, callStatus: callStatus, callDuration: callDuration, + channelId: channelId, ); } @@ -325,6 +342,9 @@ class CallManager extends GetxController { if (callDuration != null) { callParams['callDuration'] = callDuration.toString(); } + if (channelId != null && channelId.isNotEmpty) { + callParams['channelId'] = channelId; + } final message = await IMManager.instance.sendCustomMessage( targetUserId, diff --git a/lib/widget/message/video_call_overlay_widget.dart b/lib/widget/message/video_call_overlay_widget.dart index db82ade..c965073 100644 --- a/lib/widget/message/video_call_overlay_widget.dart +++ b/lib/widget/message/video_call_overlay_widget.dart @@ -1,5 +1,5 @@ import 'package:cached_network_image/cached_network_image.dart'; -import 'package:dating_touchme_app/controller/message/call_manager.dart'; +import 'package:dating_touchme_app/rtc/call_manager.dart'; import 'package:dating_touchme_app/extension/ex_widget.dart'; import 'package:dating_touchme_app/generated/assets.dart'; import 'package:dating_touchme_app/pages/message/video_call_page.dart';