207 lines
6.6 KiB
Dart
207 lines
6.6 KiB
Dart
import 'dart:async';
|
|
import 'dart:convert';
|
|
import 'dart:io';
|
|
import 'dart:typed_data';
|
|
|
|
import 'package:audioplayers/audioplayers.dart';
|
|
import 'package:flutter_easyloading/flutter_easyloading.dart';
|
|
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
|
|
import 'package:get/get.dart';
|
|
|
|
import 'package:star_lock/app_settings/app_settings.dart';
|
|
import 'package:star_lock/talk/other/audio_player_manager.dart';
|
|
import 'package:star_lock/talk/starChart/constant/payload_type_constant.dart';
|
|
|
|
import 'package:star_lock/talk/starChart/constant/udp_constant.dart';
|
|
import 'package:star_lock/talk/starChart/entity/scp_message.dart';
|
|
import 'package:star_lock/talk/starChart/handle/other/h264_frame_handler.dart';
|
|
import 'package:star_lock/talk/starChart/handle/other/talk_data_model.dart';
|
|
|
|
import 'package:star_lock/talk/starChart/handle/other/talk_data_repository.dart';
|
|
import 'package:star_lock/talk/starChart/handle/other/talke_data_over_time_timer_manager.dart';
|
|
import 'package:star_lock/talk/starChart/handle/other/talke_ping_over_time_timer_manager.dart';
|
|
import 'package:star_lock/talk/starChart/handle/other/talke_request_over_time_timer_manager.dart';
|
|
|
|
import 'package:star_lock/talk/starChart/proto/generic.pb.dart';
|
|
import 'package:star_lock/talk/starChart/proto/talk_data.pb.dart';
|
|
import 'package:star_lock/talk/starChart/star_chart_manage.dart';
|
|
|
|
import 'package:star_lock/talk/starChart/status/star_chart_talk_status.dart';
|
|
|
|
class ScpMessageBaseHandle {
|
|
/// 使用单例 TimerManager
|
|
/// 超时处理
|
|
final TalkeRequestOverTimeTimerManager talkeRequestOverTimeTimerManager =
|
|
TalkeRequestOverTimeTimerManager();
|
|
final TalkePingOverTimeTimerManager talkePingOverTimeTimerManager =
|
|
TalkePingOverTimeTimerManager();
|
|
final TalkDataOverTimeTimerManager talkDataOverTimeTimerManager =
|
|
TalkDataOverTimeTimerManager();
|
|
|
|
final startChartManage = StartChartManage();
|
|
|
|
/// 分包缓冲区
|
|
// 存储每个 messageId 对应的分包数据
|
|
static Map<String, List<List<int>>> _packetBuffer = {};
|
|
final Map<String, Timer> _packetTimers = {};
|
|
final Duration _timeoutDuration = Duration(seconds: 3); // 分包组包最大超时时间
|
|
|
|
// 通话数据流的单例流数据处理类
|
|
final TalkDataRepository talkDataRepository = TalkDataRepository.instance;
|
|
|
|
// 获取 StartChartTalkStatus 的唯一实例
|
|
final StartChartTalkStatus talkStatus = StartChartTalkStatus.instance;
|
|
|
|
final audioManager = AudioPlayerManager();
|
|
|
|
// 处理出完整帧数据后的回调
|
|
final H264FrameHandler frameHandler =
|
|
H264FrameHandler(onCompleteFrame: (TalkDataModel talkDataModel) {
|
|
// 处理完整的帧数据
|
|
TalkDataRepository.instance.addTalkData(
|
|
talkDataModel,
|
|
);
|
|
});
|
|
|
|
// 回复成功消息
|
|
void replySuccessMessage(ScpMessage scpMessage) {
|
|
startChartManage.sendGenericRespSuccessMessage(
|
|
ToPeerId: scpMessage.FromPeerId!,
|
|
FromPeerId: scpMessage.ToPeerId!,
|
|
PayloadType: scpMessage.PayloadType!,
|
|
messageId: scpMessage.MessageId!,
|
|
);
|
|
}
|
|
|
|
// 回复失败消息
|
|
void replyErrorMessage(ScpMessage scpMessage) {
|
|
startChartManage.sendGenericRespErrorMessage(
|
|
ToPeerId: scpMessage.FromPeerId!,
|
|
FromPeerId: scpMessage.ToPeerId!,
|
|
PayloadType: scpMessage.PayloadType!,
|
|
messageId: scpMessage.MessageId!,
|
|
);
|
|
}
|
|
|
|
bool checkGenericRespSuccess(GenericResp genericResp) {
|
|
if (genericResp == null) return false;
|
|
final code = genericResp.code;
|
|
final message = genericResp.message;
|
|
return (code == UdpConstant.genericRespSuccessCode || code == null) &&
|
|
message.toLowerCase() ==
|
|
UdpConstant.genericRespSuccessMsg.toLowerCase();
|
|
}
|
|
|
|
void log({required String text}) {
|
|
AppLog.log('==========${text}');
|
|
}
|
|
|
|
// 播放铃声
|
|
void playRingtone() async {
|
|
//test:使用自定义铃声
|
|
await audioManager.playRingtone();
|
|
}
|
|
|
|
// 停止播放铃声
|
|
void stopRingtone() async {
|
|
await audioManager.stopRingtone();
|
|
}
|
|
|
|
/// 处理分包逻辑
|
|
/// 如果没有收到所有包则返回null
|
|
dynamic handleFragmentedPayload({
|
|
required int messageId,
|
|
required int spTotal,
|
|
required int spIndex,
|
|
required List<int> byte,
|
|
required int payloadType,
|
|
}) {
|
|
// 初始化分包列表
|
|
// 使用更高效的key生成方式
|
|
final key = '${messageId}_$payloadType';
|
|
|
|
// 打印每个包的信息
|
|
// AppLog.log(
|
|
// '📦 收到分包 - MessageId: $messageId, 总包数: $spTotal, 当前包序号: $spIndex');
|
|
|
|
// 检查分包索引是否在合法范围内
|
|
if (spIndex < 1 || spIndex > spTotal) {
|
|
AppLog.log(
|
|
'❌ 分包序号异常 - MessageId: $messageId, 总包数: $spTotal, 无效包序号: $spIndex');
|
|
return null;
|
|
}
|
|
|
|
// 检查分包索引是否在合法范围内(提前检查可以避免后续无效操作)
|
|
if (spIndex < 1 || spIndex > spTotal) return null;
|
|
|
|
// 初始化分包列表(使用固定长度列表提高性能)
|
|
var packets = _packetBuffer[key];
|
|
if (packets == null) {
|
|
// 预分配固定大小的列表,避免动态扩容
|
|
packets = List<List<int>>.filled(spTotal, const [], growable: false);
|
|
_packetBuffer[key] = packets;
|
|
_startTimer(key);
|
|
// AppLog.log('📝 新建分包缓存 - MessageId: $messageId, 预期总包数: $spTotal');
|
|
}
|
|
|
|
// 存储当前分包
|
|
packets[spIndex - 1] = byte;
|
|
|
|
// 优化检查逻辑,使用循环替代every
|
|
var isComplete = true;
|
|
var totalLength = 0;
|
|
for (var i = 0; i < packets.length; i++) {
|
|
if (packets[i].isEmpty) {
|
|
isComplete = false;
|
|
} else {
|
|
totalLength += packets[i].length;
|
|
}
|
|
}
|
|
|
|
if (isComplete) {
|
|
// 预分配确切大小的buffer,避免扩容
|
|
final buffer = Uint8List(totalLength);
|
|
var offset = 0;
|
|
|
|
// 直接复制数据,避免使用expand
|
|
for (var packet in packets) {
|
|
buffer.setRange(offset, offset + packet.length, packet);
|
|
offset += packet.length;
|
|
}
|
|
|
|
// 清理资源
|
|
_clearPacketData(key);
|
|
|
|
// 构造TalkData
|
|
if (payloadType == PayloadTypeConstant.talkData) {
|
|
final talkData = TalkData();
|
|
talkData.mergeFromBuffer(buffer);
|
|
return talkData;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
// 启动定时器
|
|
void _startTimer(String key) {
|
|
_packetTimers[key]?.cancel();
|
|
_packetTimers[key] = Timer(_timeoutDuration, () {
|
|
_clearPacketData(key);
|
|
});
|
|
}
|
|
|
|
// 清除分包数据和定时器
|
|
void _clearPacketData(String key) {
|
|
_packetBuffer.remove(key);
|
|
_packetTimers.remove(key)?.cancel();
|
|
}
|
|
|
|
// 处理通话请求未处理超时
|
|
void _handleTalkeRequestOverTime() {}
|
|
|
|
void _handleTalkePingOverTime() {}
|
|
|
|
void _handleTalkDataOverTime() {}
|
|
}
|