This commit is contained in:
sky.min 2026-01-20 14:31:13 +08:00
parent 197320dfbf
commit c3750ff5a3
2 changed files with 25 additions and 150 deletions

View File

@ -956,8 +956,6 @@ class LockDetailLogic extends BaseGetXController {
showToast('设备未配网'.tr); showToast('设备未配网'.tr);
return; return;
} }
//
TalkViewNativeDecodeLogic.setMonitorStartTime(DateTime.now());
// //
// PacketLossStatistics().reset(); // PacketLossStatistics().reset();
// id - // id -

View File

@ -1,8 +1,9 @@
import 'dart:async'; import 'dart:async';
import 'dart:io'; import 'dart:io';
import 'dart:math'; // Random类支持
import 'dart:ui' as ui; import 'dart:ui' as ui;
import 'dart:math'; // Import the math package to use sqrt
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
@ -27,20 +28,21 @@ import 'package:star_lock/talk/starChart/proto/talk_expect.pb.dart';
import 'package:star_lock/talk/starChart/star_chart_manage.dart'; import 'package:star_lock/talk/starChart/star_chart_manage.dart';
import 'package:star_lock/talk/starChart/views/native/talk_view_native_decode_state.dart'; import 'package:star_lock/talk/starChart/views/native/talk_view_native_decode_state.dart';
import 'package:star_lock/tools/G711Tool.dart'; import 'package:star_lock/tools/G711Tool.dart';
import 'package:star_lock/tools/baseGetXController.dart';
import 'package:star_lock/tools/callkit_handler.dart'; import 'package:star_lock/tools/callkit_handler.dart';
import 'package:star_lock/tools/commonDataManage.dart'; import 'package:star_lock/tools/commonDataManage.dart';
import 'package:star_lock/tools/storage.dart'; import 'package:star_lock/tools/storage.dart';
import 'package:video_decode_plugin/video_decode_plugin.dart'; import 'package:video_decode_plugin/video_decode_plugin.dart';
import '../../../../tools/baseGetXController.dart';
class TalkViewNativeDecodeLogic extends BaseGetXController { class TalkViewNativeDecodeLogic extends BaseGetXController {
final TalkViewNativeDecodeState state = TalkViewNativeDecodeState(); final TalkViewNativeDecodeState state = TalkViewNativeDecodeState();
final LockDetailState lockDetailState = Get.put(LockDetailLogic()).state; final LockDetailState lockDetailState = Get.put(LockDetailLogic()).state;
int bufferSize = 2; // int bufferSize = 25; //
int audioBufferSize = 3; // 3 int audioBufferSize = 20; // 2
// frameSeq较小时阈值也小 // frameSeq较小时阈值也小
int _getFrameSeqRolloverThreshold(int lastSeq) { int _getFrameSeqRolloverThreshold(int lastSeq) {
@ -90,75 +92,15 @@ class TalkViewNativeDecodeLogic extends BaseGetXController {
int? lastDecodedIFrameSeq; int? lastDecodedIFrameSeq;
// I帧的时间戳
DateTime? _lastIFrameTime;
// H264帧
bool _isFirstH264FrameReceived = true;
//
DateTime? _firstFrameReceivedTime;
//
static DateTime? _monitorStartTime;
//
static void setMonitorStartTime(DateTime startTime) {
_monitorStartTime = startTime;
AppLog.log('监控启动时间已记录: $startTime');
}
//
static void printH264ReceiveTime() {
if (_monitorStartTime != null) {
final Duration duration = DateTime.now().difference(_monitorStartTime!);
AppLog.log('从点击监控到接收H264数据耗时: ${duration.inMilliseconds} 毫秒 (${duration.inSeconds}.${duration.inMilliseconds % 1000} 秒)');
//
_monitorStartTime = null;
}
}
// //
Future<void> _initVideoDecoder() async { Future<void> _initVideoDecoder() async {
try { try {
state.isLoading.value = true; state.isLoading.value = true;
int width = StartChartManage().videoWidth;
int height = StartChartManage().videoHeight;
// ios第一次点击监控没画面
if (Platform.isIOS && (width == 0 || height == 0)) {
// 使Future.microtask代替延时等待
int attempts = 0;
const maxAttempts = 10; //
while ((width == 0 || height == 0) && attempts < maxAttempts) {
await Future.microtask(() async {
await Future.delayed(const Duration(milliseconds: 50)); //
width = StartChartManage().videoWidth;
height = StartChartManage().videoHeight;
});
attempts++;
}
// 使
if (width == 0 || height == 0) {
width = 864;
height = 480;
AppLog.log('使用默认视频参数: ${width}x$height');
} else {
AppLog.log('获取到视频参数: ${width}x$height');
}
}
// H264标准
width = (width / 2).floor() * 2;
height = (height / 2).floor() * 2;
// //
final config = VideoDecoderConfig( final config = VideoDecoderConfig(
width: width, width: StartChartManage().videoWidth,
height: height, //
height: StartChartManage().videoHeight,
codecType: 'h264', codecType: 'h264',
); );
// textureId // textureId
@ -168,16 +110,6 @@ class TalkViewNativeDecodeLogic extends BaseGetXController {
AppLog.log('视频解码器初始化成功textureId=$textureId'); AppLog.log('视频解码器初始化成功textureId=$textureId');
VideoDecodePlugin.setOnFrameRenderedListener((textureId) { VideoDecodePlugin.setOnFrameRenderedListener((textureId) {
AppLog.log('已经开始渲染======='); AppLog.log('已经开始渲染=======');
// loading的耗时
if (_firstFrameReceivedTime != null) {
final Duration renderToLoadingDuration = DateTime.now().difference(_firstFrameReceivedTime!);
AppLog.log('从接收第一帧到关闭loading耗时: ${renderToLoadingDuration.inMilliseconds} 毫秒 (${renderToLoadingDuration.inSeconds}.${renderToLoadingDuration.inMilliseconds % 1000} 秒)');
//
_firstFrameReceivedTime = null;
}
// loading // loading
Future.microtask(() => state.isLoading.value = false); Future.microtask(() => state.isLoading.value = false);
}); });
@ -189,7 +121,7 @@ class TalkViewNativeDecodeLogic extends BaseGetXController {
} catch (e) { } catch (e) {
AppLog.log('初始化视频解码器错误: $e'); AppLog.log('初始化视频解码器错误: $e');
// //
await Future.delayed(const Duration(milliseconds: 500)); // await Future.delayed(const Duration(seconds: 2));
if (!Get.isRegistered<TalkViewNativeDecodeLogic>()) { if (!Get.isRegistered<TalkViewNativeDecodeLogic>()) {
return; // return; //
} }
@ -315,8 +247,7 @@ class TalkViewNativeDecodeLogic extends BaseGetXController {
state.frameProcessTimer?.cancel(); state.frameProcessTimer?.cancel();
// //
// final int intervalMs = (1000 / state.targetFps).round(); final int intervalMs = (1000 / state.targetFps).round();
final int intervalMs = state.frameProcessIntervalMs;
// //
state.frameProcessTimer = Timer.periodic(Duration(milliseconds: intervalMs), (timer) { state.frameProcessTimer = Timer.periodic(Duration(milliseconds: intervalMs), (timer) {
@ -325,6 +256,7 @@ class TalkViewNativeDecodeLogic extends BaseGetXController {
AppLog.log('启动帧处理定时器,目标帧率: ${state.targetFps}fps间隔: ${intervalMs}ms'); AppLog.log('启动帧处理定时器,目标帧率: ${state.targetFps}fps间隔: ${intervalMs}ms');
} }
///
/// ///
void _processNextFrameFromBuffer() async { void _processNextFrameFromBuffer() async {
final startTime = DateTime.now().microsecondsSinceEpoch; final startTime = DateTime.now().microsecondsSinceEpoch;
@ -530,21 +462,8 @@ class TalkViewNativeDecodeLogic extends BaseGetXController {
/// ///
void _playAudioData(TalkData talkData) async { void _playAudioData(TalkData talkData) async {
if (state.isOpenVoice.value && state.isLoading.isFalse) { if (state.isOpenVoice.value && state.isLoading.isFalse && state.isRecordingAudio.value == false) {
//
List<int> encodedData = G711Tool.decode(talkData.content, 0); // 0A-law List<int> encodedData = G711Tool.decode(talkData.content, 0); // 0A-law
//
if (Platform.isIOS) {
if (state.isRecordingAudio.value) {
//
encodedData = _applyGain(encodedData, 1.5);
} else {
// 使
encodedData = _applyGain(encodedData, 1.2);
}
}
// PCM PcmArrayInt16 // PCM PcmArrayInt16
final PcmArrayInt16 fromList = PcmArrayInt16.fromList(encodedData); final PcmArrayInt16 fromList = PcmArrayInt16.fromList(encodedData);
FlutterPcmSound.feed(fromList); FlutterPcmSound.feed(fromList);
@ -691,8 +610,6 @@ class TalkViewNativeDecodeLogic extends BaseGetXController {
_startProcessingAudioTimer?.cancel(); _startProcessingAudioTimer?.cancel();
_startProcessingAudioTimer = null; _startProcessingAudioTimer = null;
_bufferedAudioFrames.clear(); _bufferedAudioFrames.clear();
//
StartChartManage().stopCallRequestMessageTimer();
super.onClose(); super.onClose();
} }
@ -884,14 +801,10 @@ class TalkViewNativeDecodeLogic extends BaseGetXController {
// //
Future<void> _onFrame(List<int> frame) async { Future<void> _onFrame(List<int> frame) async {
// iOS使用较低增益避免影响接收端灵敏度 final applyGain = _applyGain(frame, 1.6);
double gainFactor = Platform.isIOS ? 0.6 : 1.2;
//
final gainApplied = _applyGain(frame, gainFactor);
// G711数据 // G711数据
List<int> encodedData = G711Tool.encode(gainApplied, 0); // 0A-law List<int> encodedData = G711Tool.encode(applyGain, 0); // 0A-law
_bufferedAudioFrames.addAll(encodedData); _bufferedAudioFrames.addAll(encodedData);
// //
@ -963,8 +876,8 @@ class TalkViewNativeDecodeLogic extends BaseGetXController {
state.textureId.value = null; state.textureId.value = null;
} }
// //
await Future.delayed(Duration(milliseconds: 50)); await Future.delayed(Duration(milliseconds: 100));
// //
final config = VideoDecoderConfig( final config = VideoDecoderConfig(
@ -1031,50 +944,14 @@ class TalkViewNativeDecodeLogic extends BaseGetXController {
// H264帧 // H264帧
if (state.textureId.value != null) { if (state.textureId.value != null) {
if (talkDataH264Frame != null) { if (talkDataH264Frame != null) {
// H264帧接收时间并计算耗时 _addFrameToBuffer(
if (_isFirstH264FrameReceived) { talkData.content,
AppLog.log('第一个H264帧接收时间: ${DateTime.now()}'); talkDataH264Frame.frameType,
talkData.durationMs,
// H264数据的耗时 talkDataH264Frame.frameSeq,
TalkViewNativeDecodeLogic.printH264ReceiveTime(); talkDataH264Frame.frameSeqI,
scpMessage!,
// loading的耗时 );
_firstFrameReceivedTime = DateTime.now();
_isFirstH264FrameReceived = false;
}
// Map
final Map<String, dynamic> frameMap = {
'frameData': talkData.content,
'frameType': talkDataH264Frame.frameType,
'frameSeq': talkDataH264Frame.frameSeq,
'frameSeqI': talkDataH264Frame.frameSeqI,
'pts': talkData.durationMs,
'scpMessage': scpMessage!,
};
// P/B帧
if (state.h264FrameBuffer.length >= state.maxFrameBufferSize) {
// P帧
int pbIndex = -1;
for (int i = 0; i < state.h264FrameBuffer.length; i++) {
if (state.h264FrameBuffer[i]['frameType'] == TalkDataH264Frame_FrameTypeE.P) {
pbIndex = i;
break;
}
}
if (pbIndex != -1) {
state.h264FrameBuffer.removeAt(pbIndex);
} else {
// P帧
state.h264FrameBuffer.removeAt(0);
}
}
//
state.h264FrameBuffer.add(frameMap);
} }
} else { } else {
AppLog.log('无法处理H264帧textureId为空'); AppLog.log('无法处理H264帧textureId为空');