diff --git a/lib/main/lockDetail/monitoring/star_chart_h264/star_chart_logic.dart b/lib/main/lockDetail/monitoring/star_chart_h264/star_chart_logic.dart index 88e37fea..a5f91c0a 100644 --- a/lib/main/lockDetail/monitoring/star_chart_h264/star_chart_logic.dart +++ b/lib/main/lockDetail/monitoring/star_chart_h264/star_chart_logic.dart @@ -24,7 +24,6 @@ class StarChartLogic extends BaseGetXController { int startTime = DateTime.now().millisecondsSinceEpoch; - @override void onReady() { super.onReady(); @@ -51,6 +50,8 @@ class StarChartLogic extends BaseGetXController { _cancelTimers(); stopProcessing(); state.listPhotoData.value = Uint8List(0); + // 停止播放音频 + _stopPlayG711Data(); // 状态错误,返回页面 Get.back(); @@ -72,6 +73,10 @@ class StarChartLogic extends BaseGetXController { case TalkData_ContentTypeE.G711: _playG711Data(talkData.content); break; + case TalkData_ContentTypeE.Image: + // 收到视频数据 + state.listPhotoData.value = Uint8List.fromList(talkData.content); + break; } }); } @@ -107,16 +112,18 @@ class StarChartLogic extends BaseGetXController { } void _startCallTimer() { + if (state.oneMinuteTimeTimer.isActive) return; + state.oneMinuteTimeTimer.cancel(); state.oneMinuteTimeTimer = Timer.periodic(const Duration(seconds: 1), (Timer t) { state.oneMinuteTime.value++; - if (state.oneMinuteTime.value >= 60) { - t.cancel(); - initiateHangUpCommand(); - AppLog.log('通话时间超过60秒,自动挂断'); - state.oneMinuteTime.value = 0; - } + // if (state.oneMinuteTime.value >= 60) { + // t.cancel(); + // initiateHangUpCommand(); + // AppLog.log('通话时间超过60秒,自动挂断'); + // state.oneMinuteTime.value = 0; + // } }); } diff --git a/lib/main/lockDetail/monitoring/star_chart_h264/star_chart_page.dart b/lib/main/lockDetail/monitoring/star_chart_h264/star_chart_page.dart index a7854c0c..1717c207 100644 --- a/lib/main/lockDetail/monitoring/star_chart_h264/star_chart_page.dart +++ b/lib/main/lockDetail/monitoring/star_chart_h264/star_chart_page.dart @@ -38,7 +38,6 @@ class _StarChartPageState extends State { super.initState(); initAsync(); - // _getTVDataRefreshUIAction(); } Future initAsync() async { @@ -265,52 +264,12 @@ class _StarChartPageState extends State { } } - // void _getTVDataRefreshUIAction() { - // // state.getTVDataRefreshUIEvent = eventBus - // // .on() - // // .listen((GetTVDataRefreshUI event) async { - // // if (event.tvList.isNotEmpty && event.tvList.length > 100) { - // // final Uint8List imageData = Uint8List.fromList(event.tvList); - // // if (!listEquals(state.listPhotoData.value, imageData)) { - // // state.listPhotoData.value = imageData; - // // state.shouldUpdateUI.value = true; - // // if (state.shouldUpdateUI.value) { - // // setState(() {}); - // // state.shouldUpdateUI.value = false; - // // } - // // } - // // } - // // }); - // state.talkDataRepository.talkDataStream.listen((talkData) { - // final contentType = talkData.contentType; - // // 判断数据类型,进行分发处理 - // switch (contentType) { - // case TalkData_ContentTypeE.Image: - // state.listPhotoData.value = Uint8List.fromList(talkData.content); - // if (talkData.content.isNotEmpty && talkData.content.length > 100) { - // // 比较新旧数据是否相同 - // final Uint8List imageData = Uint8List.fromList(talkData.content); - // if (!listEquals(state.listPhotoData.value, imageData)) { - // // 更新状态 - // state.listPhotoData.value = imageData; - // // 设置标志为true,表示需要更新UI - // state.shouldUpdateUI.value = true; - // // WidgetsBinding.instance.addPostFrameCallback((_) { - // // 调用setState方法之前检查标志,只有当标志为true时才更新UI - // if (state.shouldUpdateUI.value) { - // setState(() { - // // 更新UI - // }); - // // 更新完UI后将标志重新设置为false - // state.shouldUpdateUI.value = false; - // } - // // }); - // } - // } - // break; - // } - // }); - // } + String listToHexString(List intList) { + // 将整数列表转换为十六进制字符串列表 + List hexList = intList.map((num) => num.toRadixString(16)).toList(); + // 将十六进制字符串列表连接成一个字符串,没有空格 + return hexList.join(''); + } @override void dispose() { @@ -324,58 +283,67 @@ class _StarChartPageState extends State { } Widget _buildMpeg4TalkView() { - return Stack( - children: [ - Image.memory( - state.listPhotoData.value, - gaplessPlayback: true, - width: 1.sw, - height: 1.sh, - fit: BoxFit.cover, - filterQuality: FilterQuality.high, - errorBuilder: - (BuildContext context, Object error, StackTrace? stackTrace) { - return Container(color: Colors.transparent); - }, - ), - Positioned( - top: ScreenUtil().statusBarHeight + 30.h, - width: 1.sw, - child: Obx(() { - final String sec = - (state.oneMinuteTime.value % 60).toString().padLeft(2, '0'); - final String min = - (state.oneMinuteTime.value ~/ 60).toString().padLeft(2, '0'); - return Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text('$min:$sec', - style: TextStyle(fontSize: 26.sp, color: Colors.white)), - ], - ); - }), - ), - Positioned( - bottom: 10.w, - child: Container( - width: 1.sw - 30.w * 2, - margin: EdgeInsets.all(30.w), - decoration: BoxDecoration( - color: const Color(0xC83C3F41), - borderRadius: BorderRadius.circular(20.h), - ), - child: Column( - children: [ - SizedBox(height: 20.h), - buildTopButtons(), - SizedBox(height: 20.h), - buildBottomButtons(), - SizedBox(height: 20.h), - ], + return Obx( + () => Stack( + children: [ + state.listPhotoData.value.isNotEmpty + ? Image.memory( + state.listPhotoData.value, + gaplessPlayback: true, + width: 1.sw, + height: 1.sh, + fit: BoxFit.cover, + filterQuality: FilterQuality.high, + errorBuilder: (BuildContext context, Object error, + StackTrace? stackTrace) { + return Container(color: Colors.transparent); + }, + ) + : Image.asset( + 'images/main/monitorBg.png', + width: 1.sw, + height: 1.sh, + fit: BoxFit.cover, + ), + Positioned( + top: ScreenUtil().statusBarHeight + 30.h, + width: 1.sw, + child: Obx(() { + final String sec = + (state.oneMinuteTime.value % 60).toString().padLeft(2, '0'); + final String min = + (state.oneMinuteTime.value ~/ 60).toString().padLeft(2, '0'); + return Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text('$min:$sec', + style: TextStyle(fontSize: 26.sp, color: Colors.white)), + ], + ); + }), + ), + Positioned( + bottom: 10.w, + child: Container( + width: 1.sw - 30.w * 2, + margin: EdgeInsets.all(30.w), + decoration: BoxDecoration( + color: const Color(0xC83C3F41), + borderRadius: BorderRadius.circular(20.h), + ), + child: Column( + children: [ + SizedBox(height: 20.h), + buildTopButtons(), + SizedBox(height: 20.h), + buildBottomButtons(), + SizedBox(height: 20.h), + ], + ), ), ), - ), - ], + ], + ), ); } diff --git a/lib/main/lockDetail/monitoring/star_chart_h264/star_chart_state.dart b/lib/main/lockDetail/monitoring/star_chart_h264/star_chart_state.dart index 25512f62..68268c85 100644 --- a/lib/main/lockDetail/monitoring/star_chart_h264/star_chart_state.dart +++ b/lib/main/lockDetail/monitoring/star_chart_h264/star_chart_state.dart @@ -56,6 +56,9 @@ class StarChartState { RxInt talkStatus = 0.obs; //星图对讲状态 + // 获取 StartChartTalkStatus 的唯一实例 + StartChartTalkStatus talkStatusInstance = StartChartTalkStatus.instance; + // 通话数据流的单例流数据处理类 final TalkDataRepository talkDataRepository = TalkDataRepository.instance; diff --git a/lib/talk/startChart/constant/exception_constant.dart b/lib/talk/startChart/constant/exception_constant.dart new file mode 100644 index 00000000..e53fb85c --- /dev/null +++ b/lib/talk/startChart/constant/exception_constant.dart @@ -0,0 +1,3 @@ +class ExceptionConstant{ + static const String relay = 'relay'; +} \ No newline at end of file diff --git a/lib/talk/startChart/entity/scp_message.dart b/lib/talk/startChart/entity/scp_message.dart index c4f9ee07..f80db8a6 100644 --- a/lib/talk/startChart/entity/scp_message.dart +++ b/lib/talk/startChart/entity/scp_message.dart @@ -1,10 +1,10 @@ import 'dart:convert'; import 'dart:typed_data'; import 'package:star_lock/app_settings/app_settings.dart'; +import 'package:star_lock/talk/startChart/exception/start_chart_message_exception.dart'; import 'package:star_lock/talk/startChart/handle/scp_message_handle.dart'; import 'package:star_lock/talk/startChart/handle/scp_message_handler_factory.dart'; - class ScpMessage { ScpMessage({ this.ProtocolFlag, @@ -149,12 +149,13 @@ class ScpMessage { static ScpMessage deserialize(Uint8List bytes) { final message = ScpMessage(); int offset = 0; - // Convert byte array to hex string with zero padding and without spaces + // String hexString = // bytes.map((b) => b.toRadixString(16).padLeft(2, '0')).join(); - // - // // Log the hex string - // _log(text: '原始字节数组: $hexString'); + // // _log(text: 'result bytes hex: ${hexString}'); + // _log( + // text: + // '\n result bytes hex: ${hexString} \n payload hex: ${hexString.substring(194)}'); // ProtocolFlag (4 bytes) if (bytes.length - offset >= 4) { @@ -244,8 +245,7 @@ class ScpMessage { // 处理其他类型的Payload if (message.PayloadLength != null && bytes.length - offset >= message.PayloadLength!) { - final Uint8List sublist = - bytes.sublist(offset, offset + message.PayloadLength!); + final sublist = bytes.sublist(offset, offset + message.PayloadLength!); offset += message.PayloadLength!; message.Payload = _handlePayLoad( payloadType: message.PayloadType ?? 0, @@ -268,7 +268,7 @@ class ScpMessage { static dynamic _handlePayLoad({ required int payloadType, required int messageType, - required Uint8List byte, + required List byte, int? offset, int? PayloadLength, int? spTotal, @@ -280,7 +280,7 @@ class ScpMessage { final ScpMessageHandler handler = ScpMessageHandlerFactory.createHandler(payloadType); // 处理荷载信息并返回 - return handler.deserializePayload( + final payload = handler.deserializePayload( payloadType: payloadType, messageType: messageType, byte: byte, @@ -290,12 +290,9 @@ class ScpMessage { spIndex: spIndex, messageId: messageId, ); + return payload; } catch (e, stackTrace) { - // 打印异常信息 - _log(text: '❌反序列化udp数据时遇到错误----》$e'); - // 打印堆栈跟踪信息 - _log(text: '堆栈跟踪:\n$stackTrace'); - return ''; + throw StartChartMessageException('❌反序列化udp数据时遇到错误----》$e \n$stackTrace'); } } diff --git a/lib/talk/startChart/exception/start_chart_message_exception.dart b/lib/talk/startChart/exception/start_chart_message_exception.dart new file mode 100644 index 00000000..fa0065c2 --- /dev/null +++ b/lib/talk/startChart/exception/start_chart_message_exception.dart @@ -0,0 +1,10 @@ +class StartChartMessageException implements Exception { + final String message; + + StartChartMessageException(this.message); + + @override + String toString() { + return 'StartChartMessageException{message: $message}'; + } +} diff --git a/lib/talk/startChart/exception/start_chart_talk_status_exception.dart b/lib/talk/startChart/exception/start_chart_talk_status_exception.dart new file mode 100644 index 00000000..6620b177 --- /dev/null +++ b/lib/talk/startChart/exception/start_chart_talk_status_exception.dart @@ -0,0 +1,10 @@ +class StartChartTalkStatusException implements Exception { + final String message; + + StartChartTalkStatusException(this.message); + + @override + String toString() { + return 'StartChartTalkStatusException{message: $message}'; + } +} diff --git a/lib/talk/startChart/handle/impl/udp_ble_passthrough_handler.dart b/lib/talk/startChart/handle/impl/udp_ble_passthrough_handler.dart index a09f6aa2..de492782 100644 --- a/lib/talk/startChart/handle/impl/udp_ble_passthrough_handler.dart +++ b/lib/talk/startChart/handle/impl/udp_ble_passthrough_handler.dart @@ -35,7 +35,7 @@ class UdpBlePassThroughHandler extends ScpMessageBaseHandle deserializePayload( {required int payloadType, required int messageType, - required Uint8List byte, + required List byte, int? offset, int? PayloadLength, int? spTotal, diff --git a/lib/talk/startChart/handle/impl/udp_echo_test_handler.dart b/lib/talk/startChart/handle/impl/udp_echo_test_handler.dart index 75ecb89a..a814992c 100644 --- a/lib/talk/startChart/handle/impl/udp_echo_test_handler.dart +++ b/lib/talk/startChart/handle/impl/udp_echo_test_handler.dart @@ -36,7 +36,7 @@ class UdpEchoTestHandler extends ScpMessageBaseHandle deserializePayload( {required int payloadType, required int messageType, - required Uint8List byte, + required List byte, int? offset, int? PayloadLength, int? spTotal, diff --git a/lib/talk/startChart/handle/impl/udp_gateway_reset_handler.dart b/lib/talk/startChart/handle/impl/udp_gateway_reset_handler.dart index 1fcdd0c6..b0a54741 100644 --- a/lib/talk/startChart/handle/impl/udp_gateway_reset_handler.dart +++ b/lib/talk/startChart/handle/impl/udp_gateway_reset_handler.dart @@ -36,7 +36,7 @@ class UdpGateWayResetHandler extends ScpMessageBaseHandle deserializePayload( {required int payloadType, required int messageType, - required Uint8List byte, + required List byte, int? offset, int? PayloadLength, int? spTotal, diff --git a/lib/talk/startChart/handle/impl/udp_gateway_transfer_handler.dart b/lib/talk/startChart/handle/impl/udp_gateway_transfer_handler.dart index c5546e30..705c5ffe 100644 --- a/lib/talk/startChart/handle/impl/udp_gateway_transfer_handler.dart +++ b/lib/talk/startChart/handle/impl/udp_gateway_transfer_handler.dart @@ -39,7 +39,7 @@ class UdpGateWayTransferHandler extends ScpMessageBaseHandle deserializePayload( {required int payloadType, required int messageType, - required Uint8List byte, + required List byte, int? offset, int? PayloadLength, int? spTotal, diff --git a/lib/talk/startChart/handle/impl/udp_go_online_handler.dart b/lib/talk/startChart/handle/impl/udp_go_online_handler.dart index 830301ed..7899adc9 100644 --- a/lib/talk/startChart/handle/impl/udp_go_online_handler.dart +++ b/lib/talk/startChart/handle/impl/udp_go_online_handler.dart @@ -42,7 +42,7 @@ class UdpGoOnlineHandler extends ScpMessageBaseHandle deserializePayload( {required int payloadType, required int messageType, - required Uint8List byte, + required List byte, int? offset, int? PayloadLength, int? spTotal, diff --git a/lib/talk/startChart/handle/impl/udp_heart_beat_handler.dart b/lib/talk/startChart/handle/impl/udp_heart_beat_handler.dart index ed866f63..4e6caec1 100644 --- a/lib/talk/startChart/handle/impl/udp_heart_beat_handler.dart +++ b/lib/talk/startChart/handle/impl/udp_heart_beat_handler.dart @@ -43,7 +43,7 @@ class UdpHeartBeatHandler extends ScpMessageBaseHandle void handleRealTimeData(ScpMessage scpMessage) {} @override - deserializePayload({required int payloadType, required int messageType, required Uint8List byte, int? offset, int? PayloadLength, int? spTotal, int? spIndex, int? messageId}) { + deserializePayload({required int payloadType, required int messageType, required List byte, int? offset, int? PayloadLength, int? spTotal, int? spIndex, int? messageId}) { // 心跳 HeartbeatResponse heartbeatResponse = HeartbeatResponse.fromBytes(byte); return heartbeatResponse; diff --git a/lib/talk/startChart/handle/impl/udp_remote_un_lock_handler.dart b/lib/talk/startChart/handle/impl/udp_remote_un_lock_handler.dart index 03d24701..9e037284 100644 --- a/lib/talk/startChart/handle/impl/udp_remote_un_lock_handler.dart +++ b/lib/talk/startChart/handle/impl/udp_remote_un_lock_handler.dart @@ -38,7 +38,7 @@ class UdpRemoteUnLockHandler extends ScpMessageBaseHandle implements ScpMessageH } @override - deserializePayload({required int payloadType, required int messageType, required Uint8List byte, int? offset, int? PayloadLength, int? spTotal, int? spIndex, int? messageId}) { + deserializePayload({required int payloadType, required int messageType, required List byte, int? offset, int? PayloadLength, int? spTotal, int? spIndex, int? messageId}) { if (messageType == MessageTypeConstant.Resp) { final GenericResp genericResp = GenericResp(); genericResp.mergeFromBuffer(byte); diff --git a/lib/talk/startChart/handle/impl/udp_talk_accept_handler.dart b/lib/talk/startChart/handle/impl/udp_talk_accept_handler.dart index c29dbc84..a3c1fe8c 100644 --- a/lib/talk/startChart/handle/impl/udp_talk_accept_handler.dart +++ b/lib/talk/startChart/handle/impl/udp_talk_accept_handler.dart @@ -44,7 +44,7 @@ class UdpTalkAcceptHandler extends ScpMessageBaseHandle stopRingtone(); // 设置状态为接听中 talkStatus.setAnsweredSuccessfully(); - talkStatus.setDuringCall(); + talkStatus.setWaitingData(); } } @@ -58,7 +58,7 @@ class UdpTalkAcceptHandler extends ScpMessageBaseHandle deserializePayload( {required int payloadType, required int messageType, - required Uint8List byte, + required List byte, int? offset, int? PayloadLength, int? spTotal, diff --git a/lib/talk/startChart/handle/impl/udp_talk_data_handler.dart b/lib/talk/startChart/handle/impl/udp_talk_data_handler.dart index 20d6d1f0..8d94787d 100644 --- a/lib/talk/startChart/handle/impl/udp_talk_data_handler.dart +++ b/lib/talk/startChart/handle/impl/udp_talk_data_handler.dart @@ -30,10 +30,45 @@ class UdpTalkDataHandler extends ScpMessageBaseHandle talkDataOverTimeTimerManager.receiveMessage(); if (scpMessage.Payload != null) { final TalkData talkData = scpMessage.Payload; - print('talkData: ${listToHexString(talkData.content)}'); - // 处理音视频数据 _handleTalkData(talkData: talkData); + // 设置状态为接听中 + talkStatus.setDuringCall(); + } + } + + @override + deserializePayload( + {required int payloadType, + required int messageType, + required List byte, + int? offset, + int? PayloadLength, + int? spTotal, + int? spIndex, + int? messageId}) { + if (messageType == MessageTypeConstant.RealTimeData) { + print( + '收到音视频数据:${byte.length} messageId:$messageId spTotal:$spTotal spIndex:$spIndex PayloadLength:$PayloadLength'); + // 回声测试 + if (spTotal != null && + spTotal > 1 && + messageId != null && + spIndex != null) { + // 分包处理 + return handleFragmentedPayload( + messageId: messageId, + spTotal: spTotal, + spIndex: spIndex, + byte: byte, + payloadType: payloadType, + ); + } else { + // 没有分包直接解析 + final TalkData talkData = TalkData(); + talkData.mergeFromBuffer(byte); + return talkData; + } } } @@ -69,7 +104,15 @@ class UdpTalkDataHandler extends ScpMessageBaseHandle } /// 处理图片数据 - void _handleVideoImage(TalkData talkData) {} + void _handleVideoImage(TalkData talkData) { + final List processCompletePayload = + _processCompletePayload(Uint8List.fromList(talkData.content)); + // 循环发送每一帧的数据 + processCompletePayload.forEach((element) { + talkData.content = element; + talkDataRepository.addTalkData(talkData); + }); + } /// 处理g711音频数据 void _handleVideoG711(TalkData talkData) { @@ -84,36 +127,36 @@ class UdpTalkDataHandler extends ScpMessageBaseHandle } } - @override - deserializePayload( - {required int payloadType, - required int messageType, - required Uint8List byte, - int? offset, - int? PayloadLength, - int? spTotal, - int? spIndex, - int? messageId}) { - if (messageType == MessageTypeConstant.RealTimeData) { - // 回声测试 - if (spTotal != null && - spTotal > 1 && - messageId != null && - spIndex != null) { - // 分包处理 - return handleFragmentedPayload( - messageId: messageId, - spTotal: spTotal, - spIndex: spIndex, - byte: byte, - payloadType: payloadType, - ); + /// 查找完整的帧数据 + List _processCompletePayload(Uint8List payload) { + // 存储找到的所有完整帧 + List frames = []; + + // 寻找完整帧 (0xFFD8 开始, 0xFFD9 结束) + int startIdx = payload.indexOf(0xFF); + while (startIdx != -1 && startIdx + 1 < payload.length) { + if (payload[startIdx + 1] == 0xD8) { + // 找到帧的起始标志 0xFFD8 + int endIdx = startIdx + 2; + while (endIdx < payload.length - 1) { + endIdx = payload.indexOf(0xFF, endIdx); + if (endIdx == -1) break; + if (endIdx + 1 < payload.length && payload[endIdx + 1] == 0xD9) { + // 找到帧的结束标志 0xFFD9 + Uint8List frame = payload.sublist(startIdx, endIdx + 2); + frames.add(frame); + startIdx = endIdx + 2; // 继续寻找下一个帧 + break; + } else { + endIdx += 1; // 继续寻找结束标志 + } + } } else { - // 没有分包直接解析 - final TalkData talkData = TalkData(); - talkData.mergeFromBuffer(byte); - return talkData; + startIdx = payload.indexOf(0xFF, startIdx + 1); // 寻找下一个起始标志 } } + + // 返回找到的所有完整帧 + return frames; } } diff --git a/lib/talk/startChart/handle/impl/udp_talk_expect_handler.dart b/lib/talk/startChart/handle/impl/udp_talk_expect_handler.dart index 2dda6dab..6bdf44e7 100644 --- a/lib/talk/startChart/handle/impl/udp_talk_expect_handler.dart +++ b/lib/talk/startChart/handle/impl/udp_talk_expect_handler.dart @@ -49,7 +49,7 @@ class UdpTalkExpectHandler extends ScpMessageBaseHandle deserializePayload( {required int payloadType, required int messageType, - required Uint8List byte, + required List byte, int? offset, int? PayloadLength, int? spTotal, diff --git a/lib/talk/startChart/handle/impl/udp_talk_hangup_handler.dart b/lib/talk/startChart/handle/impl/udp_talk_hangup_handler.dart index 1bebcddc..dfe227ef 100644 --- a/lib/talk/startChart/handle/impl/udp_talk_hangup_handler.dart +++ b/lib/talk/startChart/handle/impl/udp_talk_hangup_handler.dart @@ -53,7 +53,7 @@ class UdpTalkHangUpHandler extends ScpMessageBaseHandle deserializePayload( {required int payloadType, required int messageType, - required Uint8List byte, + required List byte, int? offset, int? PayloadLength, int? spTotal, diff --git a/lib/talk/startChart/handle/impl/udp_talk_ping_handler.dart b/lib/talk/startChart/handle/impl/udp_talk_ping_handler.dart index 42b7021a..95c9f243 100644 --- a/lib/talk/startChart/handle/impl/udp_talk_ping_handler.dart +++ b/lib/talk/startChart/handle/impl/udp_talk_ping_handler.dart @@ -36,7 +36,7 @@ class UdpTalkPingHandler extends ScpMessageBaseHandle deserializePayload( {required int payloadType, required int messageType, - required Uint8List byte, + required List byte, int? offset, int? PayloadLength, int? spTotal, diff --git a/lib/talk/startChart/handle/impl/udp_talk_push_handler.dart b/lib/talk/startChart/handle/impl/udp_talk_push_handler.dart index 15ecf86e..addcedbc 100644 --- a/lib/talk/startChart/handle/impl/udp_talk_push_handler.dart +++ b/lib/talk/startChart/handle/impl/udp_talk_push_handler.dart @@ -37,7 +37,7 @@ class UdpTalkPushHandler extends ScpMessageBaseHandle deserializePayload( {required int payloadType, required int messageType, - required Uint8List byte, + required List byte, int? offset, int? PayloadLength, int? spTotal, diff --git a/lib/talk/startChart/handle/impl/udp_talk_receiver_transfer_handler.dart b/lib/talk/startChart/handle/impl/udp_talk_receiver_transfer_handler.dart index 168fde66..154afbac 100644 --- a/lib/talk/startChart/handle/impl/udp_talk_receiver_transfer_handler.dart +++ b/lib/talk/startChart/handle/impl/udp_talk_receiver_transfer_handler.dart @@ -35,7 +35,7 @@ class UdpTalkReceiverTransferHandler extends ScpMessageBaseHandle deserializePayload( {required int payloadType, required int messageType, - required Uint8List byte, + required List byte, int? offset, int? PayloadLength, int? spTotal, diff --git a/lib/talk/startChart/handle/impl/udp_talk_reject_handler.dart b/lib/talk/startChart/handle/impl/udp_talk_reject_handler.dart index ffcf75da..96e722ac 100644 --- a/lib/talk/startChart/handle/impl/udp_talk_reject_handler.dart +++ b/lib/talk/startChart/handle/impl/udp_talk_reject_handler.dart @@ -50,7 +50,7 @@ class UdpTalkRejectHandler extends ScpMessageBaseHandle deserializePayload( {required int payloadType, required int messageType, - required Uint8List byte, + required List byte, int? offset, int? PayloadLength, int? spTotal, diff --git a/lib/talk/startChart/handle/impl/udp_talk_request_handler.dart b/lib/talk/startChart/handle/impl/udp_talk_request_handler.dart index eb6a0cdd..af67d4b6 100644 --- a/lib/talk/startChart/handle/impl/udp_talk_request_handler.dart +++ b/lib/talk/startChart/handle/impl/udp_talk_request_handler.dart @@ -95,7 +95,7 @@ class UdpTalkRequestHandler extends ScpMessageBaseHandle deserializePayload( {required int payloadType, required int messageType, - required Uint8List byte, + required List byte, int? offset, int? PayloadLength, int? spTotal, diff --git a/lib/talk/startChart/handle/impl/unknow_payload_type_handler.dart b/lib/talk/startChart/handle/impl/unknow_payload_type_handler.dart index 4aee3b03..29665244 100644 --- a/lib/talk/startChart/handle/impl/unknow_payload_type_handler.dart +++ b/lib/talk/startChart/handle/impl/unknow_payload_type_handler.dart @@ -34,7 +34,7 @@ class UnKnowPayloadTypeHandler extends ScpMessageBaseHandle deserializePayload( {required int payloadType, required int messageType, - required Uint8List byte, + required List byte, int? offset, int? PayloadLength, int? spTotal, diff --git a/lib/talk/startChart/handle/scp_message_base_handle.dart b/lib/talk/startChart/handle/scp_message_base_handle.dart index a54fb927..de51229b 100644 --- a/lib/talk/startChart/handle/scp_message_base_handle.dart +++ b/lib/talk/startChart/handle/scp_message_base_handle.dart @@ -1,5 +1,6 @@ import 'dart:async'; import 'dart:convert'; +import 'dart:typed_data'; import 'package:audioplayers/audioplayers.dart'; import 'package:flutter_local_notifications/flutter_local_notifications.dart'; @@ -19,6 +20,7 @@ import 'package:star_lock/talk/startChart/start_chart_talk_status.dart'; class ScpMessageBaseHandle { final startChartManage = StartChartManage(); + final List _buffer = []; /// 分包缓冲区 // 存储每个 messageId 对应的分包数据 @@ -33,12 +35,12 @@ class ScpMessageBaseHandle { // 通话保持超时监听定时器管理 final talkePingOverTimeTimerManager = OverTimeTimerManager( - timeoutInSeconds: 15, + timeoutInSeconds: 55, ); // 通话数据超时定时器 final talkDataOverTimeTimerManager = OverTimeTimerManager( - timeoutInSeconds: 13, + timeoutInSeconds: 53, ); // 回复成功消息 @@ -86,7 +88,7 @@ class ScpMessageBaseHandle { }) { // 初始化分包列表 String key = '$messageId-$payloadType'; - if (!_packetBuffer.containsKey(messageId)) { + if (!_packetBuffer.containsKey(key)) { _packetBuffer[key] = List.filled(spTotal, []); _startTimer(key); } @@ -104,24 +106,17 @@ class ScpMessageBaseHandle { // 检查是否接收到所有分包 if (_packetBuffer[key]!.every((packet) => packet.isNotEmpty)) { // 重组所有分包 - List completePayload = - _packetBuffer[key]!.expand((packet) => packet).toList(); - + Uint8List completePayload = Uint8List.fromList( + _packetBuffer[key]!.expand((packet) => packet).toList()); // 清除已重组和超时的分包数据 _clearPacketData(key); - // 解析完整的 payload + // 使用重组的包构造成TalkData if (payloadType == PayloadTypeConstant.talkData) { - final TalkData talkData = TalkData(); + final talkData = TalkData(); talkData.mergeFromBuffer(completePayload); return talkData; } - // if (payloadType == PayloadTypeConstant.echoTest) { - // return completePayload; - // } else { - // String payload = utf8.decode(completePayload); - // return payload; - // } } else { // 如果分包尚未接收完全,返回 null 或其他指示符 return null; diff --git a/lib/talk/startChart/handle/scp_message_handle.dart b/lib/talk/startChart/handle/scp_message_handle.dart index e43ac425..352b5f3f 100644 --- a/lib/talk/startChart/handle/scp_message_handle.dart +++ b/lib/talk/startChart/handle/scp_message_handle.dart @@ -19,7 +19,7 @@ abstract class ScpMessageHandler { dynamic deserializePayload({ required int payloadType, required int messageType, - required Uint8List byte, + required List byte, int? offset, int? PayloadLength, int? spTotal, diff --git a/lib/talk/startChart/proto/talk_data.pb.dart b/lib/talk/startChart/proto/talk_data.pb.dart index d39cd33e..8fd25269 100644 --- a/lib/talk/startChart/proto/talk_data.pb.dart +++ b/lib/talk/startChart/proto/talk_data.pb.dart @@ -17,7 +17,7 @@ import 'talk_data.pbenum.dart'; export 'talk_data.pbenum.dart'; -/// 注意这个包不应该使用Req,而应该只用单向发送类型,不等待响应。 +/// 注意这个包不应该使用请求响应(Req/Resp),应该用单向发送类型(RealTimeData),不等待响应。 /// 在未收到对方的Ping,或者其他情况,即停止发送。 class TalkData extends $pb.GeneratedMessage { factory TalkData({ @@ -78,6 +78,7 @@ class TalkData extends $pb.GeneratedMessage { @$pb.TagNumber(1) void clearContentType() => clearField(1); + /// 音视频数据,例如PCM的字节,或者H264的字节,或者图片的字节 @$pb.TagNumber(2) $core.List<$core.int> get content => $_getN(1); @$pb.TagNumber(2) diff --git a/lib/talk/startChart/proto/talk_data.proto b/lib/talk/startChart/proto/talk_data.proto index 5dcb93a0..9c47ac05 100644 --- a/lib/talk/startChart/proto/talk_data.proto +++ b/lib/talk/startChart/proto/talk_data.proto @@ -3,7 +3,7 @@ syntax = "proto3"; package main; option go_package = "./spb/talk"; -// 注意这个包不应该使用Req,而应该只用单向发送类型,不等待响应。 +// 注意这个包不应该使用请求响应(Req/Resp),应该用单向发送类型(RealTimeData),不等待响应。 // 在未收到对方的Ping,或者其他情况,即停止发送。 message TalkData { // 内容类型枚举: 一张图传;一帧H264;一段G711 @@ -13,10 +13,10 @@ message TalkData { G711 = 2; }; ContentTypeE ContentType = 1; + // 音视频数据,例如PCM的字节,或者H264的字节,或者图片的字节 bytes Content = 2; // 时间 毫秒,例如第一帧视频,就是0ms,第2秒的第一帧,就是1000ms - // 该字段仅用于协调音视频同步,而不是用于影响音视频播放时机 - // 对于对讲场景,应该根据网络延迟和设备性能自行决定缓冲时长,在满足播放条件时立即进行渲染。 - uint32 DurationMs = 3; - + // 该字段仅用于协调音视频同步,而不是用于影响音视频播放时机 + // 对于对讲场景,应该根据网络延迟和设备性能自行决定缓冲时长,在满足播放条件时立即进行渲染。 + uint32 DurationMs = 3; } diff --git a/lib/talk/startChart/start_chart_manage.dart b/lib/talk/startChart/start_chart_manage.dart index d146a42a..e7de70a6 100644 --- a/lib/talk/startChart/start_chart_manage.dart +++ b/lib/talk/startChart/start_chart_manage.dart @@ -21,6 +21,7 @@ import 'package:star_lock/talk/startChart/entity/relay_info_entity.dart'; import 'package:star_lock/talk/startChart/entity/report_information_data.dart'; import 'package:star_lock/talk/startChart/entity/scp_message.dart'; import 'package:star_lock/talk/startChart/entity/star_chart_register_node_entity.dart'; +import 'package:star_lock/talk/startChart/exception/start_chart_message_exception.dart'; import 'package:star_lock/talk/startChart/handle/scp_message_handle.dart'; import 'package:star_lock/talk/startChart/handle/scp_message_handler_factory.dart'; import 'package:star_lock/talk/startChart/proto/talk_data.pb.dart'; @@ -363,10 +364,6 @@ class StartChartManage { // 发送期望接受消息 void sendTalkExpectMessage({required TalkExpect talkExpect}) async { - if (talkStatus.status != TalkStatus.duringCall) { - _log(text: '当前未处于接听状态, 无法发送期望接受数据消息'); - return; - } final message = MessageCommand.talkExpectMessage( ToPeerId: ToPeerId, FromPeerId: FromPeerId, @@ -407,10 +404,6 @@ class StartChartManage { // 发送通话保持消息 Future sendTalkPingMessage( {required String ToPeerId, required String FromPeerId}) async { - if (talkStatus.status != TalkStatus.duringCall) { - _log(text: '当前未处于接听状态, 无法发送通话保持消息'); - return; - } final message = MessageCommand.talkPingMessage( ToPeerId: ToPeerId, FromPeerId: FromPeerId, @@ -474,7 +467,8 @@ class StartChartManage { var result = await _udpSocket?.send( message, InternetAddress(remoteHost), remotePort); if (result != message.length) { - AppLog.log('❌Udp send data error----> $result ${message.length}'); + throw StartChartMessageException( + '❌Udp send data error----> $result ${message.length}'); // _udpSocket = null; } } @@ -663,7 +657,7 @@ class StartChartManage { .signPKCS1v15Bytes(signData, fastRsa.Hash.SHA256, pemPrivateKey); resultSign = hex.encode(result); } catch (e) { - _log(text: '❌--->上报信息生成签名时出现错误: $e'); + throw StartChartMessageException('❌--->上报信息生成签名时出现错误: $e'); e.printError(); } return resultSign ?? ''; @@ -785,14 +779,14 @@ class StartChartManage { } if (deserialize.PayloadType != PayloadTypeConstant.heartbeat) { if (deserialize.Payload != null) { - _log(text: 'Udp收到结构体数据---》$deserialize'); + // _log(text: 'Udp收到结构体数据---》$deserialize'); } // _log(text: 'text---》${utf8.decode(deserialize.Payload)}'); } } } catch (e, stackTrace) { - _log(text: '❌ Udp result data error ----> $e'); - _log(text: '堆栈跟踪:\n$stackTrace'); + throw StartChartMessageException( + '❌ Udp result data error ----> $e\n,$stackTrace'); } } }); @@ -815,7 +809,7 @@ class StartChartManage { handler.handleInvalidReq(scpMessage); } } catch (e, stackTrace) { - _log(text: '❌ 处理udp返回数据时遇到错误---> $e\n,$stackTrace'); + throw StartChartMessageException('❌ 处理udp返回数据时遇到错误---> $e\n,$stackTrace'); } } diff --git a/lib/talk/startChart/start_chart_talk_status.dart b/lib/talk/startChart/start_chart_talk_status.dart index 4fd0a363..6c8b5f11 100644 --- a/lib/talk/startChart/start_chart_talk_status.dart +++ b/lib/talk/startChart/start_chart_talk_status.dart @@ -64,6 +64,13 @@ class StartChartTalkStatus { // 可以在这里添加特定于 "waitingAnswer" 状态的逻辑 } + /// 设置状态为等待数据 + void setWaitingData() { + _setStatus(TalkStatus.waitingData); + // 可以在这里添加特定于 "waitingAnswer" 状态的逻辑 + } + + /// 设置状态为通话中 void setDuringCall() { _setStatus(TalkStatus.duringCall);