fix:增加音视频数据的丢包率判断、调整udp发送和接收缓冲区大小
This commit is contained in:
parent
9f2c049147
commit
bf4c2b4750
@ -50,6 +50,10 @@ import 'package:star_lock/tools/deviceInfo_utils.dart';
|
|||||||
import 'package:star_lock/tools/storage.dart';
|
import 'package:star_lock/tools/storage.dart';
|
||||||
import 'package:uuid/uuid.dart';
|
import 'package:uuid/uuid.dart';
|
||||||
|
|
||||||
|
// Socket选项常量
|
||||||
|
const int SO_RCVBUF = 8; // 接收缓冲区
|
||||||
|
const int SO_SNDBUF = 7; // 发送缓冲区
|
||||||
|
|
||||||
class StartChartManage {
|
class StartChartManage {
|
||||||
// 私有构造函数,防止外部直接new对象
|
// 私有构造函数,防止外部直接new对象
|
||||||
StartChartManage._internal();
|
StartChartManage._internal();
|
||||||
@ -125,6 +129,17 @@ class StartChartManage {
|
|||||||
// 获取 StartChartTalkStatus 的唯一实例
|
// 获取 StartChartTalkStatus 的唯一实例
|
||||||
StartChartTalkStatus talkStatus = StartChartTalkStatus.instance;
|
StartChartTalkStatus talkStatus = StartChartTalkStatus.instance;
|
||||||
|
|
||||||
|
// 音视频帧级丢包统计变量
|
||||||
|
final Map<int, Set<int>> _avFrameParts = {};
|
||||||
|
int _avFrameTotal = 0;
|
||||||
|
int _avFrameLost = 0;
|
||||||
|
|
||||||
|
// 查询音视频帧丢包率
|
||||||
|
double getAvFrameLossRate() {
|
||||||
|
if (_avFrameTotal == 0) return 0.0;
|
||||||
|
return _avFrameLost / _avFrameTotal;
|
||||||
|
}
|
||||||
|
|
||||||
// 星图服务初始化
|
// 星图服务初始化
|
||||||
Future<void> init() async {
|
Future<void> init() async {
|
||||||
if (F.isXHJ) {
|
if (F.isXHJ) {
|
||||||
@ -225,6 +240,25 @@ class StartChartManage {
|
|||||||
var addressIListenFrom = InternetAddress.anyIPv4;
|
var addressIListenFrom = InternetAddress.anyIPv4;
|
||||||
RawDatagramSocket.bind(addressIListenFrom, localPort)
|
RawDatagramSocket.bind(addressIListenFrom, localPort)
|
||||||
.then((RawDatagramSocket socket) {
|
.then((RawDatagramSocket socket) {
|
||||||
|
|
||||||
|
// 设置接收缓冲区大小 (SO_RCVBUF = 8)
|
||||||
|
socket.setRawOption(
|
||||||
|
RawSocketOption.fromInt(
|
||||||
|
RawSocketOption.levelSocket,
|
||||||
|
8, // SO_RCVBUF for Android/iOS
|
||||||
|
2 * 1024 * 1024, // 2MB receive buffer
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// 设置发送缓冲区大小 (SO_SNDBUF = 7)
|
||||||
|
socket.setRawOption(
|
||||||
|
RawSocketOption.fromInt(
|
||||||
|
RawSocketOption.levelSocket,
|
||||||
|
7, // SO_SNDBUF for Android/iOS
|
||||||
|
2 * 1024 * 1024, // 2MB send buffer
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
_udpSocket = socket;
|
_udpSocket = socket;
|
||||||
|
|
||||||
/// 广播功能
|
/// 广播功能
|
||||||
@ -1017,35 +1051,54 @@ class StartChartManage {
|
|||||||
void _onReceiveData(RawDatagramSocket socket, BuildContext context) {
|
void _onReceiveData(RawDatagramSocket socket, BuildContext context) {
|
||||||
socket.listen((RawSocketEvent event) {
|
socket.listen((RawSocketEvent event) {
|
||||||
if (event == RawSocketEvent.read) {
|
if (event == RawSocketEvent.read) {
|
||||||
Datagram? dg = socket.receive();
|
Datagram? dg;
|
||||||
try {
|
while ((dg = socket.receive()) != null) {
|
||||||
if (dg?.data != null) {
|
try {
|
||||||
final deserialize = ScpMessage.deserialize(dg!.data);
|
if (dg?.data != null) {
|
||||||
|
final deserialize = ScpMessage.deserialize(dg!.data);
|
||||||
|
|
||||||
// //ToDo: 增加对讲调试、正式可删除
|
// 音视频帧丢包统计:只统计PayloadType==talkData的数据包,结合分包信息
|
||||||
// UdpTalkDataHandler().updateRecvDataRate(dg.data.length);
|
if (deserialize != null &&
|
||||||
|
deserialize.PayloadType == PayloadTypeConstant.talkData) {
|
||||||
// // 更新调试信息
|
int? msgId = deserialize.MessageId;
|
||||||
// Provider.of<DebugInfoModel>(context, listen: false).updateDebugInfo(
|
int spTotal = deserialize.SpTotal ?? 1;
|
||||||
// UdpTalkDataHandler().getLastRecvDataRate() ~/ 1024, // 转换为KB
|
int spIndex = deserialize.SpIndex ?? 1;
|
||||||
// UdpTalkDataHandler().getLastRecvPacketCount(),
|
if (msgId != null) {
|
||||||
// UdpTalkDataHandler().getLastSendDataRate() ~/ 1024, // 转换为KB
|
// 记录收到的分包
|
||||||
// UdpTalkDataHandler().getLastSendPacketCount(),
|
_avFrameParts.putIfAbsent(msgId, () => <int>{});
|
||||||
// );
|
_avFrameParts[msgId]!.add(spIndex);
|
||||||
|
// 如果收到最后一个分包,判断该帧是否完整
|
||||||
if (deserialize != null) {
|
if (spIndex == spTotal) {
|
||||||
// 处理返回数据
|
_avFrameTotal++;
|
||||||
_handleUdpResultData(deserialize);
|
if (_avFrameParts[msgId]!.length < spTotal) {
|
||||||
}
|
_avFrameLost++;
|
||||||
if (deserialize.PayloadType != PayloadTypeConstant.heartbeat) {
|
// _log(text: '音视频丢包,丢失的messageId: $msgId');
|
||||||
if (deserialize.Payload != null) {
|
}
|
||||||
// _log(text: 'Udp收到结构体数据---》$deserialize');
|
_avFrameParts.remove(msgId);
|
||||||
|
// 可选:每100帧打印一次丢包率
|
||||||
|
if (_avFrameTotal % 100 == 0) {
|
||||||
|
_log(
|
||||||
|
text:
|
||||||
|
'音视频帧丢包率: ${(getAvFrameLossRate() * 100).toStringAsFixed(2)}%');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (deserialize != null) {
|
||||||
|
// 处理返回数据
|
||||||
|
_handleUdpResultData(deserialize);
|
||||||
|
}
|
||||||
|
// if (deserialize.PayloadType != PayloadTypeConstant.heartbeat) {
|
||||||
|
// if (deserialize.Payload != null) {
|
||||||
|
// _log(text: 'Udp收到结构体数据---》$deserialize');
|
||||||
|
// }
|
||||||
// _log(text: 'text---》${utf8.decode(deserialize.Payload)}');
|
// _log(text: 'text---》${utf8.decode(deserialize.Payload)}');
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
} catch (e, stackTrace) {
|
||||||
|
throw StartChartMessageException('$e\n,$stackTrace');
|
||||||
}
|
}
|
||||||
} catch (e, stackTrace) {
|
|
||||||
throw StartChartMessageException('$e\n,$stackTrace');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user