优化视频对讲--添加网络质量评估和设备性能评估,根据网络和设备状况动态调整缓冲区大小
This commit is contained in:
parent
a6d53858f6
commit
f51a3abcb0
@ -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<void> stopRecording() async {}
|
||||
|
||||
/// 评估设备性能
|
||||
Future<void> _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<void> _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();
|
||||
// 在没有监听成功之前赋值一遍状态
|
||||
|
||||
@ -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<String, Map<String, dynamic>> frameTracker = {};
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user