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 dd5f1a89..5b41c798 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 @@ -1,5 +1,7 @@ import 'dart:async'; +import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; +import 'package:flutter_pcm_sound/flutter_pcm_sound.dart'; import 'package:flutter_voice_processor/flutter_voice_processor.dart'; import 'package:get/get.dart'; import 'package:permission_handler/permission_handler.dart'; @@ -7,6 +9,8 @@ import 'package:star_lock/app_settings/app_settings.dart'; import 'package:star_lock/blue/io_tool/manager_event_bus.dart'; import 'package:star_lock/main/lockDetail/monitoring/star_chart_h264/star_chart_state.dart'; import 'package:star_lock/talk/startChart/events/talk_status_change_event.dart'; +import 'package:star_lock/talk/startChart/handle/other/talk_data_repository.dart'; +import 'package:star_lock/talk/startChart/proto/talk_data.pbenum.dart'; import 'package:star_lock/talk/startChart/start_chart_manage.dart'; import 'package:star_lock/talk/startChart/start_chart_talk_status.dart'; import 'package:star_lock/tools/baseGetXController.dart'; @@ -21,7 +25,14 @@ class StarChartLogic extends BaseGetXController { @override void onReady() { super.onReady(); + // 初始化音频播放设备,采样率为 44100 Hz,单声道 + FlutterPcmSound.setup(sampleRate: 44100, channelCount: 1, ); + + // 设置音频数据的供给阈值,假设我们使用一秒钟的供给阈值 + int feedThreshold = 44100 * 1; // 44100 个样本,相当于一秒钟的数据量 + FlutterPcmSound.setFeedThreshold(feedThreshold); _getTalkStatusRefreshUIAction(); + _startListenTalkData(); } void _getTalkStatusRefreshUIAction() { @@ -36,8 +47,11 @@ class StarChartLogic extends BaseGetXController { state.talkStatus.value == TalkStatus.notTalkPing.index || state.talkStatus.value == TalkStatus.end.index) { _cancelTimers(); + stopProcessing(); + state.listPhotoData.value = Uint8List(0); // 状态错误,返回页面 Get.back(); + return; } @@ -47,6 +61,33 @@ class StarChartLogic extends BaseGetXController { }); } + // 监听音视频数据流 + void _startListenTalkData() { + state.talkDataRepository.talkDataStream.listen((talkData) { + final contentType = talkData.contentType; + // 判断数据类型,进行分发处理 + switch (contentType) { + case TalkData_ContentTypeE.G711: + _playG711Data(talkData.content); + break; + } + }); + } + + /// 播放音频数据 + Future _playG711Data(List audioData) async { + final PcmArrayInt16 fromList = PcmArrayInt16.fromList(audioData); + + await FlutterPcmSound.feed(fromList); + FlutterPcmSound.play(); + } + + void _stopPlayG711Data() { + FlutterPcmSound.pause(); + FlutterPcmSound.clear(); + FlutterPcmSound.stop(); + } + void _startCallTimer() { state.oneMinuteTimeTimer.cancel(); state.oneMinuteTimeTimer = 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 8508c58e..b0678082 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 @@ -15,6 +15,7 @@ import 'package:star_lock/app_settings/app_colors.dart'; import 'package:star_lock/app_settings/app_settings.dart'; import 'package:star_lock/main/lockDetail/monitoring/star_chart_h264/star_chart_logic.dart'; import 'package:star_lock/main/lockDetail/monitoring/star_chart_h264/star_chart_state.dart'; +import 'package:star_lock/talk/startChart/proto/talk_data.pbenum.dart'; import 'package:star_lock/talk/startChart/start_chart_talk_status.dart'; import 'package:star_lock/talk/startChart/webView/h264_web_view.dart'; import 'package:star_lock/talk/udp/udp_manage.dart'; @@ -265,19 +266,48 @@ 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.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; } }); } 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 4a8ddfc4..c0aa5e69 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 @@ -5,6 +5,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_voice_processor/flutter_voice_processor.dart'; import 'package:get/get.dart'; import 'package:network_info_plus/network_info_plus.dart'; +import 'package:star_lock/talk/startChart/handle/other/talk_data_repository.dart'; import 'package:star_lock/talk/startChart/start_chart_talk_status.dart'; import '../../../../tools/storage.dart'; @@ -54,4 +55,8 @@ class StarChartState { RxInt openDoorSeconds = 0.obs; RxInt talkStatus = 0.obs; //星图对讲状态 + + // 通话数据流的单例流数据处理类 + final TalkDataRepository talkDataRepository = TalkDataRepository.instance; + } 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 d16f80fd..295e2c02 100644 --- a/lib/talk/startChart/handle/impl/udp_talk_accept_handler.dart +++ b/lib/talk/startChart/handle/impl/udp_talk_accept_handler.dart @@ -31,8 +31,8 @@ class UdpTalkAcceptHandler extends ScpMessageBaseHandle // 收到同意接听回复 final GenericResp genericResp = scpMessage.Payload; if (checkGenericRespSuccess(genericResp)) { - // 延迟2秒后启动监听 - Future.delayed(Duration(seconds: 5), () { + // 延迟一秒启动定时器判断 + Future.delayed(Duration(seconds: 1), () { // 启动通话保持定时器 _handleStartTalkPing(); // 启动发送预期数据请求 @@ -57,13 +57,13 @@ class UdpTalkAcceptHandler extends ScpMessageBaseHandle @override deserializePayload( {required int payloadType, - required int messageType, - required Uint8List byte, - int? offset, - int? PayloadLength, - int? spTotal, - int? spIndex, - int? messageId}) { + required int messageType, + required Uint8List byte, + int? offset, + int? PayloadLength, + int? spTotal, + int? spIndex, + int? messageId}) { if (messageType == MessageTypeConstant.Resp) { final GenericResp genericResp = GenericResp(); genericResp.mergeFromBuffer(byte); @@ -114,6 +114,4 @@ class UdpTalkAcceptHandler extends ScpMessageBaseHandle // 启动发送预期数据定时器 startChartManage.startTalkExpectTimer(); } - - } 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 9649533e..98767822 100644 --- a/lib/talk/startChart/handle/impl/udp_talk_data_handler.dart +++ b/lib/talk/startChart/handle/impl/udp_talk_data_handler.dart @@ -3,6 +3,7 @@ import 'dart:typed_data'; import 'package:flutter_easyloading/flutter_easyloading.dart'; import 'package:get/get.dart'; +import 'package:star_lock/talk/call/g711.dart'; import 'package:star_lock/talk/startChart/constant/message_type_constant.dart'; import 'package:star_lock/talk/startChart/entity/scp_message.dart'; import 'package:star_lock/talk/startChart/handle/scp_message_base_handle.dart'; @@ -25,13 +26,12 @@ class UdpTalkDataHandler extends ScpMessageBaseHandle @override void handleRealTimeData(ScpMessage scpMessage) { + // 收到数据后调用更新,防止定时器超时 + talkDataOverTimeTimerManager.receiveMessage(); if (scpMessage.Payload != null) { final TalkData talkData = scpMessage.Payload; // 处理音视频数据 _handleTalkData(talkData: talkData); - print('talkData:$talkData'); - // 收到数据后调用更新,防止定时器超时 - talkDataOverTimeTimerManager.receiveMessage(); } } @@ -64,7 +64,15 @@ class UdpTalkDataHandler extends ScpMessageBaseHandle /// 处理g711音频数据 void _handleVideoG711(TalkData talkData) { - talkDataRepository.addTalkData(talkData); + try { + final g711Data = talkData.content; + // 转pcm数据 + List pcmBytes = G711().convertList(g711Data); + talkData.content = pcmBytes; + talkDataRepository.addTalkData(talkData); + } catch (e) { + print('Error decoding G.711 to PCM: $e'); + } } @override diff --git a/lib/talk/startChart/start_chart_manage.dart b/lib/talk/startChart/start_chart_manage.dart index 080bf818..0b3d22d4 100644 --- a/lib/talk/startChart/start_chart_manage.dart +++ b/lib/talk/startChart/start_chart_manage.dart @@ -126,7 +126,6 @@ class StartChartManage { FromPeerId = requestStarChartRegisterNode.peer!.id ?? ''; bindUserStarchart(); } - } //绑定星图配置 @@ -158,7 +157,6 @@ class StartChartManage { if (relayInfoEntity.client_addr != null) { localPublicHost = relayInfoEntity.client_addr!; } - if (relayInfoEntity.relay_list != null && relayInfoEntity.relay_list!.length > 0) { for (int i = 0; i <= relayInfoEntity.relay_list!.length; i++) { @@ -220,7 +218,6 @@ class StartChartManage { // 发送上线消息 Future _sendOnlineMessage() async { - _log(text: '发送上线消息,是否已经上线:$isOnlineStartChartServer'); if (isOnlineStartChartServer) { _log(text: '星图已上线,请勿重复发送上线消息'); return; @@ -285,8 +282,8 @@ class StartChartManage { } // 发送回声测试消息 - void sendEchoMessage({required List payload,required String toPeerId}) async { - + void sendEchoMessage( + {required List payload, required String toPeerId}) async { // 计算需要分多少个包发送 final int totalPackets = (payload.length / _maxPayloadSize).ceil(); // 循环遍历 @@ -763,7 +760,10 @@ class StartChartManage { _handleUdpResultData(deserialize); } if (deserialize.PayloadType != PayloadTypeConstant.heartbeat) { - // _log(text: 'Udp收到结构体数据---》$deserialize'); + if (deserialize.Payload != null) { + _log(text: 'Udp收到结构体数据---》$deserialize'); + } + // _log(text: 'text---》${utf8.decode(deserialize.Payload)}'); } } @@ -791,8 +791,8 @@ class StartChartManage { } else { handler.handleInvalidReq(scpMessage); } - } catch (e) { - // _log(text: '❌ 处理udp返回数据时遇到错误---> $e'); + } catch (e, stackTrace) { + _log(text: '❌ 处理udp返回数据时遇到错误---> $e\n,$stackTrace'); } }