优化视频对讲 优化
This commit is contained in:
parent
f51a3abcb0
commit
705ba72e31
@ -804,6 +804,8 @@ class LockDetailLogic extends BaseGetXController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 添加网络质量评估变量
|
||||||
|
int _networkQualityScore = 5; // 1-5分,5为最佳
|
||||||
/// 发送监控消息
|
/// 发送监控消息
|
||||||
void sendMonitorMessage() async {
|
void sendMonitorMessage() async {
|
||||||
final catEyeConfig = state.keyInfos.value.lockSetting?.catEyeConfig ?? [];
|
final catEyeConfig = state.keyInfos.value.lockSetting?.catEyeConfig ?? [];
|
||||||
@ -817,6 +819,30 @@ class LockDetailLogic extends BaseGetXController {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// 根据网络质量设置提示信息
|
||||||
|
switch (_networkQualityScore) {
|
||||||
|
case 1:
|
||||||
|
state.networkQualityMessage.value = '很差';
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
state.networkQualityMessage.value = '较差';
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
state.networkQualityMessage.value = '一般';
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
state.networkQualityMessage.value = '良好';
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
state.networkQualityMessage.value = '优秀';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
state.networkQualityMessage.value = '';
|
||||||
|
}
|
||||||
|
// 根据网络质量设置提示信息
|
||||||
|
if (_networkQualityScore < 4) {
|
||||||
|
showToast('网络质量'.tr + ':${state.networkQualityMessage.value}');
|
||||||
|
}
|
||||||
if (catEyeConfig.isNotEmpty && catEyeConfig.length > 0 && catEyeConfig[0].catEyeMode != 0) {
|
if (catEyeConfig.isNotEmpty && catEyeConfig.length > 0 && catEyeConfig[0].catEyeMode != 0) {
|
||||||
if (network == null || network?.peerId == null || network?.peerId == '') {
|
if (network == null || network?.peerId == null || network?.peerId == '') {
|
||||||
showToast('设备未配网'.tr);
|
showToast('设备未配网'.tr);
|
||||||
|
|||||||
@ -17,6 +17,9 @@ class LockDetailState {
|
|||||||
StreamSubscription? DetailLockInfo;
|
StreamSubscription? DetailLockInfo;
|
||||||
StreamSubscription? SuccessfulDistributionNetworkEvent;
|
StreamSubscription? SuccessfulDistributionNetworkEvent;
|
||||||
|
|
||||||
|
// 添加网络质量状态变量
|
||||||
|
final RxInt networkQualityScore = 1.obs; // 1-5分,5为最佳
|
||||||
|
final RxString networkQualityMessage = ''.obs; // 网络质量提示信息
|
||||||
String lockNetToken = '0';
|
String lockNetToken = '0';
|
||||||
int differentialTime = 0; // 服务器时间与本地时间差值
|
int differentialTime = 0; // 服务器时间与本地时间差值
|
||||||
bool isHaveNetwork = true;
|
bool isHaveNetwork = true;
|
||||||
|
|||||||
@ -68,6 +68,15 @@ class TalkViewNativeDecodeLogic extends BaseGetXController {
|
|||||||
final targetFps = state.targetFps.toDouble();
|
final targetFps = state.targetFps.toDouble();
|
||||||
final actualRatio = _actualFps / targetFps;
|
final actualRatio = _actualFps / targetFps;
|
||||||
|
|
||||||
|
// 增加中间档位的调整,避免帧率波动过大
|
||||||
|
if (actualRatio < 0.3) {
|
||||||
|
state.targetFps = (targetFps * 0.5).round().clamp(15, 60);
|
||||||
|
_startFrameProcessTimer();
|
||||||
|
} else if (actualRatio < 0.5) {
|
||||||
|
state.targetFps = (targetFps * 0.7).round().clamp(15, 60);
|
||||||
|
_startFrameProcessTimer();
|
||||||
|
}
|
||||||
|
|
||||||
// 更加保守和稳定的调整策略
|
// 更加保守和稳定的调整策略
|
||||||
// iOS平台使用更保守的调整策略
|
// iOS平台使用更保守的调整策略
|
||||||
if (Platform.isIOS) {
|
if (Platform.isIOS) {
|
||||||
@ -85,7 +94,7 @@ class TalkViewNativeDecodeLogic extends BaseGetXController {
|
|||||||
_startFrameProcessTimer();
|
_startFrameProcessTimer();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Android平台原有逻辑
|
// Android平台
|
||||||
if (actualRatio < 0.4) {
|
if (actualRatio < 0.4) {
|
||||||
state.targetFps = (targetFps * 0.6).round().clamp(15, 60);
|
state.targetFps = (targetFps * 0.6).round().clamp(15, 60);
|
||||||
_startFrameProcessTimer();
|
_startFrameProcessTimer();
|
||||||
@ -108,13 +117,13 @@ class TalkViewNativeDecodeLogic extends BaseGetXController {
|
|||||||
: 0.0;
|
: 0.0;
|
||||||
|
|
||||||
// 根据丢包率评估网络质量
|
// 根据丢包率评估网络质量
|
||||||
if (dropRate > 0.3) {
|
if (dropRate > 0.25) {
|
||||||
_networkQualityScore = 1; // 很差
|
_networkQualityScore = 1; // 很差
|
||||||
} else if (dropRate > 0.2) {
|
} else if (dropRate > 0.15) {
|
||||||
_networkQualityScore = 2; // 较差
|
_networkQualityScore = 2; // 较差
|
||||||
} else if (dropRate > 0.1) {
|
} else if (dropRate > 0.08) {
|
||||||
_networkQualityScore = 3; // 一般
|
_networkQualityScore = 3; // 一般
|
||||||
} else if (dropRate > 0.05) {
|
} else if (dropRate > 0.03) {
|
||||||
_networkQualityScore = 4; // 良好
|
_networkQualityScore = 4; // 良好
|
||||||
} else {
|
} else {
|
||||||
_networkQualityScore = 5; // 优秀
|
_networkQualityScore = 5; // 优秀
|
||||||
@ -269,9 +278,8 @@ class TalkViewNativeDecodeLogic extends BaseGetXController {
|
|||||||
final startTime = DateTime.now().millisecondsSinceEpoch;
|
final startTime = DateTime.now().millisecondsSinceEpoch;
|
||||||
|
|
||||||
// 使用超时控制避免长时间等待
|
// 使用超时控制避免长时间等待
|
||||||
// iOS平台使用更短的超时时间
|
// 设置超时时间为500ms,避免过长等待
|
||||||
final timeoutSeconds = Platform.isIOS ? 1 : 1;
|
final timeoutFuture = Future.delayed(Duration(milliseconds: 500), () => null);
|
||||||
final timeoutFuture = Future.delayed(Duration(seconds: timeoutSeconds), () => null);
|
|
||||||
final decoderFuture = VideoDecodePlugin.initDecoder(config);
|
final decoderFuture = VideoDecodePlugin.initDecoder(config);
|
||||||
|
|
||||||
// 初始化解码器并获取textureId
|
// 初始化解码器并获取textureId
|
||||||
@ -296,16 +304,14 @@ class TalkViewNativeDecodeLogic extends BaseGetXController {
|
|||||||
}
|
}
|
||||||
// 启动定时器发送帧数据
|
// 启动定时器发送帧数据
|
||||||
// 延迟启动帧处理定时器,让用户感觉更快
|
// 延迟启动帧处理定时器,让用户感觉更快
|
||||||
Future.delayed(Duration(milliseconds: 100), () {
|
Future.delayed(Duration(milliseconds: 50), () {
|
||||||
_startFrameProcessTimer();
|
_startFrameProcessTimer();
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
AppLog.log('初始化视频解码器错误: $e');
|
AppLog.log('初始化视频解码器错误: $e');
|
||||||
state.isLoading.value = false;
|
state.isLoading.value = false;
|
||||||
// 如果初始化失败,延迟后重试
|
// 如果初始化失败,延迟后重试 --缩短重试延迟
|
||||||
// iOS平台使用更短的重试延迟
|
await Future.delayed(Duration(milliseconds: 300));
|
||||||
final delaySeconds = Platform.isIOS ? 0.5 : 1;
|
|
||||||
await Future.delayed(Duration(milliseconds: (delaySeconds * 1000).toInt()));
|
|
||||||
if (!Get.isRegistered<TalkViewNativeDecodeLogic>()) {
|
if (!Get.isRegistered<TalkViewNativeDecodeLogic>()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -537,8 +543,25 @@ class TalkViewNativeDecodeLogic extends BaseGetXController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 查找最适合处理的帧
|
// 查找最适合处理的帧 -- 优先处理I帧以加速首帧显示
|
||||||
int frameIndex = -1;
|
int frameIndex = -1;
|
||||||
|
// 首先查找最早的I帧
|
||||||
|
final iFrames = state.h264FrameBuffer
|
||||||
|
.where((f) => f['frameType'] == TalkDataH264Frame_FrameTypeE.I)
|
||||||
|
.toList()
|
||||||
|
..sort((a, b) => (a['frameSeq'] as int).compareTo(b['frameSeq'] as int));
|
||||||
|
|
||||||
|
if (iFrames.isNotEmpty) {
|
||||||
|
final minIFrame = iFrames.first;
|
||||||
|
frameIndex = state.h264FrameBuffer.indexWhere(
|
||||||
|
(f) =>
|
||||||
|
f['frameType'] == TalkDataH264Frame_FrameTypeE.I &&
|
||||||
|
f['frameSeq'] == minIFrame['frameSeq'],
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// 如果没有I帧,处理最早的帧
|
||||||
|
frameIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
// 优先处理与最近解码的I帧相关的P帧
|
// 优先处理与最近解码的I帧相关的P帧
|
||||||
if (lastDecodedIFrameSeq != null) {
|
if (lastDecodedIFrameSeq != null) {
|
||||||
@ -897,44 +920,103 @@ class TalkViewNativeDecodeLogic extends BaseGetXController {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
void onClose() {
|
void onClose() {
|
||||||
|
try {
|
||||||
|
// 先停止所有处理流程
|
||||||
|
_stopAllProcessing();
|
||||||
|
|
||||||
|
// 释放视频相关资源
|
||||||
|
_releaseVideoResources();
|
||||||
|
|
||||||
|
// 释放音频相关资源
|
||||||
|
_releaseAudioResources();
|
||||||
|
|
||||||
|
// 释放网络和状态相关资源
|
||||||
|
_releaseNetworkAndStateResources();
|
||||||
|
|
||||||
|
// 清理定时器和订阅
|
||||||
|
_cancelAllTimersAndSubscriptions();
|
||||||
|
|
||||||
|
} catch (e, stackTrace) {
|
||||||
|
AppLog.log('资源释放过程中出现错误: $e\n$stackTrace');
|
||||||
|
} finally {
|
||||||
|
super.onClose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 停止所有处理流程
|
||||||
|
void _stopAllProcessing() {
|
||||||
// 停止帧处理定时器
|
// 停止帧处理定时器
|
||||||
_stopFrameProcessTimer();
|
_stopFrameProcessTimer();
|
||||||
|
|
||||||
_stopPlayG711Data(); // 停止播放音频
|
// 停止音频处理
|
||||||
|
|
||||||
state.audioBuffer.clear(); // 清空音频缓冲区
|
|
||||||
|
|
||||||
state.oneMinuteTimeTimer?.cancel();
|
|
||||||
state.oneMinuteTimeTimer = null;
|
|
||||||
|
|
||||||
// 停止播放音频
|
|
||||||
stopProcessingAudio();
|
stopProcessingAudio();
|
||||||
|
|
||||||
state.oneMinuteTimeTimer?.cancel(); // 取消旧定时器
|
// 停止播放音频
|
||||||
state.oneMinuteTimeTimer = null; // 取消旧定时器
|
_stopPlayG711Data();
|
||||||
state.oneMinuteTime.value = 0;
|
}
|
||||||
|
|
||||||
// 异步释放视频解码器资源
|
/// 释放视频相关资源
|
||||||
_releaseVideoDecoderAsync();
|
void _releaseVideoResources() {
|
||||||
|
try {
|
||||||
|
// 异步释放视频解码器资源
|
||||||
|
_releaseVideoDecoderAsync();
|
||||||
|
} catch (e) {
|
||||||
|
AppLog.log('释放视频解码器资源失败: $e');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 取消数据流监听
|
/// 释放音频相关资源
|
||||||
_streamSubscription?.cancel();
|
void _releaseAudioResources() {
|
||||||
_isListening = false;
|
try {
|
||||||
|
// 停止播放音频
|
||||||
|
_stopPlayG711Data();
|
||||||
|
|
||||||
// 重置期望数据
|
// 清空音频缓冲区
|
||||||
StartChartManage().reSetDefaultTalkExpect();
|
state.audioBuffer.clear();
|
||||||
StartChartManage().stopTalkExpectMessageTimer();
|
|
||||||
|
|
||||||
// 取消批处理定时器
|
// 清空音频帧缓冲
|
||||||
_batchProcessTimer?.cancel();
|
_bufferedAudioFrames.clear();
|
||||||
_batchProcessTimer = null;
|
} catch (e) {
|
||||||
|
AppLog.log('释放音频资源失败: $e');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 清空已解码I帧集合
|
/// 释放网络和状态相关资源
|
||||||
_decodedIFrames.clear();
|
void _releaseNetworkAndStateResources() {
|
||||||
_startProcessingAudioTimer?.cancel();
|
try {
|
||||||
_startProcessingAudioTimer = null;
|
// 重置期望数据
|
||||||
_bufferedAudioFrames.clear();
|
StartChartManage().reSetDefaultTalkExpect();
|
||||||
super.onClose();
|
StartChartManage().stopTalkExpectMessageTimer();
|
||||||
|
|
||||||
|
// 清空已解码I帧集合
|
||||||
|
_decodedIFrames.clear();
|
||||||
|
|
||||||
|
// 重置状态
|
||||||
|
state.oneMinuteTimeTimer?.cancel();
|
||||||
|
state.oneMinuteTimeTimer = null;
|
||||||
|
state.oneMinuteTime.value = 0;
|
||||||
|
} catch (e) {
|
||||||
|
AppLog.log('释放网络和状态资源失败: $e');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 取消所有定时器和订阅
|
||||||
|
void _cancelAllTimersAndSubscriptions() {
|
||||||
|
try {
|
||||||
|
// 取消数据流监听
|
||||||
|
_streamSubscription?.cancel();
|
||||||
|
_isListening = false;
|
||||||
|
|
||||||
|
// 取消批处理定时器
|
||||||
|
_batchProcessTimer?.cancel();
|
||||||
|
_batchProcessTimer = null;
|
||||||
|
|
||||||
|
// 取消音频处理定时器
|
||||||
|
_startProcessingAudioTimer?.cancel();
|
||||||
|
_startProcessingAudioTimer = null;
|
||||||
|
} catch (e) {
|
||||||
|
AppLog.log('取消定时器和订阅失败: $e');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/// 异步释放视频解码器
|
/// 异步释放视频解码器
|
||||||
Future<void> _releaseVideoDecoderAsync() async {
|
Future<void> _releaseVideoDecoderAsync() async {
|
||||||
@ -1191,14 +1273,14 @@ class TalkViewNativeDecodeLogic extends BaseGetXController {
|
|||||||
_pendingResetWidth = width;
|
_pendingResetWidth = width;
|
||||||
_pendingResetHeight = height;
|
_pendingResetHeight = height;
|
||||||
|
|
||||||
// 并行执行两个操作以提高效率
|
// 并行执行两个操作以提高效率---使用更短的总超时时间
|
||||||
await Future.wait([
|
await Future.wait([
|
||||||
// 立即重置解码器
|
// 立即重置解码器
|
||||||
_resetDecoderForNewStream(width, height),
|
_resetDecoderForNewStream(width, height),
|
||||||
// 修改发送预期数据
|
// 修改发送预期数据
|
||||||
Future.microtask(() =>
|
Future.microtask(() =>
|
||||||
StartChartManage().changeTalkExpectDataTypeAndReStartTalkExpectMessageTimer(talkExpect: talkExpectReq))
|
StartChartManage().changeTalkExpectDataTypeAndReStartTalkExpectMessageTimer(talkExpect: talkExpectReq))
|
||||||
]).timeout(const Duration(seconds: 2)); // 设置总超时时间
|
]).timeout(const Duration(milliseconds: 1500)); // 设置总超时时间
|
||||||
}
|
}
|
||||||
|
|
||||||
void _initHdOptions() {
|
void _initHdOptions() {
|
||||||
@ -1222,13 +1304,11 @@ class TalkViewNativeDecodeLogic extends BaseGetXController {
|
|||||||
// 快速清理缓冲区以加快响应
|
// 快速清理缓冲区以加快响应
|
||||||
_clearFrameBufferQuickly();
|
_clearFrameBufferQuickly();
|
||||||
|
|
||||||
// 释放旧解码器 - 使用最短超时时间
|
// 释放旧解码器 - 使用最短超时时间 - 减少不必要的延时
|
||||||
if (state.textureId.value != null) {
|
if (state.textureId.value != null) {
|
||||||
try {
|
try {
|
||||||
// 极短超时时间,避免阻塞
|
// 极短超时时间,避免阻塞
|
||||||
// iOS平台使用更短的超时时间
|
await VideoDecodePlugin.releaseDecoder().timeout(Duration(milliseconds: 100));
|
||||||
final timeoutMs = Platform.isIOS ? 200 : 300;
|
|
||||||
await VideoDecodePlugin.releaseDecoder().timeout(Duration(milliseconds: timeoutMs));
|
|
||||||
state.textureId.value = null;
|
state.textureId.value = null;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
AppLog.log('释放解码器超时或失败: $e');
|
AppLog.log('释放解码器超时或失败: $e');
|
||||||
@ -1238,9 +1318,7 @@ class TalkViewNativeDecodeLogic extends BaseGetXController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 最小化等待时间
|
// 最小化等待时间
|
||||||
// iOS平台使用更短的等待时间
|
await Future.delayed(Duration(milliseconds: 0));
|
||||||
final delayMs = Platform.isIOS ? 0 : 1;
|
|
||||||
await Future.delayed(Duration(milliseconds: delayMs));
|
|
||||||
|
|
||||||
// 创建新的解码器配置
|
// 创建新的解码器配置
|
||||||
final config = VideoDecoderConfig(
|
final config = VideoDecoderConfig(
|
||||||
@ -1252,10 +1330,8 @@ class TalkViewNativeDecodeLogic extends BaseGetXController {
|
|||||||
// 初始化新解码器
|
// 初始化新解码器
|
||||||
try {
|
try {
|
||||||
// 使用较短超时时间
|
// 使用较短超时时间
|
||||||
// iOS平台使用更短的超时时间
|
|
||||||
final timeoutMs = Platform.isIOS ? 1000 : 1500;
|
|
||||||
final textureId = await VideoDecodePlugin.initDecoder(config)
|
final textureId = await VideoDecodePlugin.initDecoder(config)
|
||||||
.timeout(Duration(milliseconds: timeoutMs));
|
.timeout(Duration(milliseconds: 800));
|
||||||
|
|
||||||
if (textureId != null) {
|
if (textureId != null) {
|
||||||
state.textureId.value = textureId;
|
state.textureId.value = textureId;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user