优化视频对讲--添加网络质量评估和设备性能评估,根据网络和设备状况动态调整缓冲区大小

This commit is contained in:
sky_min 2025-11-11 15:14:09 +08:00
parent a6d53858f6
commit f51a3abcb0
2 changed files with 189 additions and 6 deletions

View File

@ -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-55
int _frameDropCount = 0;
int _totalFrameCount = 0;
//
int _devicePerformanceScore = 5; // 1-55
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;
}
// 160
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();
//

View File

@ -104,6 +104,10 @@ class TalkViewNativeDecodeState {
int lastPerformanceCheck = 0;
int lastFrameCount = 0;
//
final RxInt networkQualityScore = 1.obs; // 1-55
final RxString networkQualityMessage = ''.obs; //
// Mapkey为textureId_frameSeq
Map<String, Map<String, dynamic>> frameTracker = {};