diff --git a/lib/talk/starChart/views/native/talk_view_native_decode_logic.dart b/lib/talk/starChart/views/native/talk_view_native_decode_logic.dart index 72d9f6cf..5ecd4db9 100644 --- a/lib/talk/starChart/views/native/talk_view_native_decode_logic.dart +++ b/lib/talk/starChart/views/native/talk_view_native_decode_logic.dart @@ -5,6 +5,7 @@ import 'dart:math'; // Import the math package to use sqrt import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; import 'package:flutter_pcm_sound/flutter_pcm_sound.dart'; @@ -40,7 +41,14 @@ class TalkViewNativeDecodeLogic extends BaseGetXController { final LockDetailState lockDetailState = Get.put(LockDetailLogic()).state; - int bufferSize = 25; // 初始化为默认大小 + // 添加网络质量评估变量 + int _networkQualityScore = 5; // 1-5分,5为最佳 + int _frameDropCount = 0; + int _totalFrameCount = 0; + // 设备性能评估 + int _devicePerformanceScore = 5; // 1-5分,5为最佳 + + int bufferSize = 5; // 初始化为默认大小 int audioBufferSize = 20; // 音频默认缓冲2帧 @@ -92,6 +100,111 @@ class TalkViewNativeDecodeLogic extends BaseGetXController { }// 注意:避免过于积极地提高帧率,这可能导致卡顿 } + /// 根据网络和设备状况动态调整缓冲区大小 + void _adjustBufferSizeDynamically() { + // 计算网络质量得分 + final double dropRate = _totalFrameCount > 0 + ? _frameDropCount / _totalFrameCount + : 0.0; + + // 根据丢包率评估网络质量 + if (dropRate > 0.3) { + _networkQualityScore = 1; // 很差 + } else if (dropRate > 0.2) { + _networkQualityScore = 2; // 较差 + } else if (dropRate > 0.1) { + _networkQualityScore = 3; // 一般 + } else if (dropRate > 0.05) { + _networkQualityScore = 4; // 良好 + } else { + _networkQualityScore = 5; // 优秀 + } + + // 结合设备性能和网络质量计算缓冲区大小 + final int calculatedBufferSize = _calculateOptimalBufferSize( + networkQuality: _networkQualityScore, + devicePerformance: _devicePerformanceScore + ); + + // 只有当缓冲区大小变化较大时才调整 + if ((state.maxFrameBufferSize - calculatedBufferSize).abs() > 3) { + bufferSize = calculatedBufferSize; + AppLog.log('动态调整缓冲区大小至: $calculatedBufferSize (网络质量: $_networkQualityScore, 设备性能: $_devicePerformanceScore)'); + } + } + + /// 监测网络状况 + void _monitorNetworkCondition() { + // 可以通过帧处理时间来间接评估网络状况 + // 如果帧处理时间过长,可能表示网络延迟高或数据包丢失 + + // 也可以通过缓冲区长度来判断网络状况 + final int bufferLength = state.h264FrameBuffer.length; + + // 如果缓冲区经常接近最大值,说明消费速度跟不上生产速度,网络可能较差 + if (bufferLength > state.maxFrameBufferSize * 0.8) { + // 网络状况可能变差 + if (_networkQualityScore > 1) { + _networkQualityScore--; + } + } else if (bufferLength < state.maxFrameBufferSize * 0.3) { + // 网络状况良好 + if (_networkQualityScore < 5) { + _networkQualityScore++; + } + } + } + + /// 计算最优缓冲区大小 + int _calculateOptimalBufferSize({required int networkQuality, required int devicePerformance}) { + // 基础缓冲区大小基于网络质量 + int baseBufferSize; + switch (networkQuality) { + case 1: // 网络很差 + baseBufferSize = 20; + break; + case 2: // 网络较差 + baseBufferSize = 15; + break; + case 3: // 网络一般 + baseBufferSize = 10; + break; + case 4: // 网络良好 + baseBufferSize = 5; + break; + case 5: // 网络优秀 + baseBufferSize = 3; + break; + default: + baseBufferSize = 10; + } + + // 根据设备性能调整 + double performanceFactor; + switch (devicePerformance) { + case 1: // 设备性能很差 + performanceFactor = 1.5; + break; + case 2: // 设备性能较差 + performanceFactor = 1.2; + break; + case 3: // 设备性能一般 + performanceFactor = 1.0; + break; + case 4: // 设备性能良好 + performanceFactor = 0.8; + break; + case 5: // 设备性能优秀 + performanceFactor = 0.6; + break; + default: + performanceFactor = 1.0; + } + + // 计算最终缓冲区大小,最小为1,最大不超过60 + return (baseBufferSize * performanceFactor).round().clamp(1, 60); + } + // 回绕阈值,动态调整,frameSeq较小时阈值也小 int _getFrameSeqRolloverThreshold(int lastSeq) { if (lastSeq > 2000) { @@ -152,17 +265,25 @@ class TalkViewNativeDecodeLogic extends BaseGetXController { codecType: 'h264', ); + // 添加开始时间记录 + final startTime = DateTime.now().millisecondsSinceEpoch; + // 使用超时控制避免长时间等待 // iOS平台使用更短的超时时间 - final timeoutSeconds = Platform.isIOS ? 2 : 3; + final timeoutSeconds = Platform.isIOS ? 1 : 1; final timeoutFuture = Future.delayed(Duration(seconds: timeoutSeconds), () => null); final decoderFuture = VideoDecodePlugin.initDecoder(config); // 初始化解码器并获取textureId final textureId = await Future.any([decoderFuture, timeoutFuture]); + + // 计算耗时 + final endTime = DateTime.now().millisecondsSinceEpoch; + final duration = endTime - startTime; + if (textureId != null) { Future.microtask(() => state.textureId.value = textureId); - AppLog.log('视频解码器初始化成功:textureId=$textureId'); + AppLog.log('视频解码器初始化成功:textureId=$textureId, 耗时: ${duration}ms'); // 异步设置帧渲染监听器 VideoDecodePlugin.setOnFrameRenderedListener((textureId) { AppLog.log('已经开始渲染======='); @@ -170,11 +291,14 @@ class TalkViewNativeDecodeLogic extends BaseGetXController { Future.microtask(() => state.isLoading.value = false); }); } else { - AppLog.log('视频解码器初始化失败或超时'); + AppLog.log('视频解码器初始化失败或超时, 耗时: ${duration}ms'); state.isLoading.value = false; } // 启动定时器发送帧数据 - _startFrameProcessTimer(); + // 延迟启动帧处理定时器,让用户感觉更快 + Future.delayed(Duration(milliseconds: 100), () { + _startFrameProcessTimer(); + }); } catch (e) { AppLog.log('初始化视频解码器错误: $e'); state.isLoading.value = false; @@ -372,6 +496,12 @@ class TalkViewNativeDecodeLogic extends BaseGetXController { _monitorFrameProcessingPerformance(); final startTime = DateTime.now().microsecondsSinceEpoch; + // 定期动态调整缓冲区大小 + _totalFrameCount++; + if (_totalFrameCount % 30 == 0) { // 每处理30帧检查一次 + _adjustBufferSizeDynamically(); + } + // 避免重复处理 if (state.isProcessingFrame) { return; @@ -489,6 +619,9 @@ class TalkViewNativeDecodeLogic extends BaseGetXController { } } } + } catch (e) { + _frameDropCount++; + AppLog.log('帧处理失败: $e'); } finally { state.isProcessingFrame = false; final endTime = DateTime.now().microsecondsSinceEpoch; @@ -547,7 +680,7 @@ class TalkViewNativeDecodeLogic extends BaseGetXController { return; } - AppLog.log("==== 启动新的数据流监听 ===="); + AppLog.log("==== 启动新的数据流监听1 ===="); _isListening = true; _streamSubscription = state.talkDataRepository.talkDataStream.listen((TalkDataModel talkDataModel) async { @@ -681,6 +814,47 @@ class TalkViewNativeDecodeLogic extends BaseGetXController { Future stopRecording() async {} + /// 评估设备性能 + Future _evaluateDevicePerformance() async { + final stopwatch = Stopwatch()..start(); + + // 执行一些计算密集型任务来评估性能 + for (int i = 0; i < 100000; i++) { + sqrt(i); + } + + stopwatch.stop(); + final int elapsedMs = stopwatch.elapsedMilliseconds; + + // 根据计算时间评估设备性能 + if (elapsedMs < 50) { + _devicePerformanceScore = 5; // 优秀 + } else if (elapsedMs < 100) { + _devicePerformanceScore = 4; // 良好 + } else if (elapsedMs < 200) { + _devicePerformanceScore = 3; // 一般 + } else if (elapsedMs < 400) { + _devicePerformanceScore = 2; // 较差 + } else { + _devicePerformanceScore = 1; // 很差 + } + + AppLog.log('设备性能评估完成: $_devicePerformanceScore (耗时: ${elapsedMs}ms)'); + } + + Future _checkRequiredPermissions() async { + // 检查是否已获得必要权限 + var storageStatus = await Permission.storage.status; + var microphoneStatus = await Permission.microphone.status; + + if (!storageStatus.isGranted || !microphoneStatus.isGranted) { + // 延迟请求权限,让用户理解为什么需要这些权限 + Future.delayed(Duration(seconds: 1), () { + requestPermissions(); + }); + } + } + @override void onReady() { super.onReady(); @@ -690,6 +864,11 @@ class TalkViewNativeDecodeLogic extends BaseGetXController { void onInit() { super.onInit(); + // 异步评估设备性能 + WidgetsBinding.instance.addPostFrameCallback((_) { + _evaluateDevicePerformance(); + }); + // 启动监听对讲状态 _startListenTalkStatus(); // 在没有监听成功之前赋值一遍状态 diff --git a/lib/talk/starChart/views/native/talk_view_native_decode_state.dart b/lib/talk/starChart/views/native/talk_view_native_decode_state.dart index ed63b493..f3f09c16 100644 --- a/lib/talk/starChart/views/native/talk_view_native_decode_state.dart +++ b/lib/talk/starChart/views/native/talk_view_native_decode_state.dart @@ -104,6 +104,10 @@ class TalkViewNativeDecodeState { int lastPerformanceCheck = 0; int lastFrameCount = 0; + // 添加网络质量状态变量 + final RxInt networkQualityScore = 1.obs; // 1-5分,5为最佳 + final RxString networkQualityMessage = ''.obs; // 网络质量提示信息 + // 帧跟踪Map,记录每个提交的帧,key为textureId_frameSeq Map> frameTracker = {};