app-starlock/lib/talk/starChart/handle/impl/udp_talk_data_handler.dart

286 lines
8.7 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import 'dart:typed_data';
import 'package:star_lock/app_settings/app_settings.dart';
import 'package:star_lock/talk/call/g711.dart';
import 'package:star_lock/talk/starChart/constant/message_type_constant.dart';
import 'package:star_lock/talk/starChart/entity/scp_message.dart';
import 'package:star_lock/talk/starChart/handle/other/h264_frame_handler.dart';
import 'package:star_lock/talk/starChart/handle/scp_message_base_handle.dart';
import 'package:star_lock/talk/starChart/handle/scp_message_handle.dart';
import 'package:star_lock/talk/starChart/proto/talk_data.pb.dart';
import 'package:star_lock/talk/starChart/proto/talk_data.pbserver.dart';
import 'package:star_lock/talk/starChart/proto/talk_data_h264_frame.pb.dart';
// class UdpTalkDataHandler extends ScpMessageBaseHandle
// implements ScpMessageHandler {
class UdpTalkDataHandler extends ScpMessageBaseHandle
implements ScpMessageHandler {
factory UdpTalkDataHandler() {
return _instance;
}
UdpTalkDataHandler._internal();
static final UdpTalkDataHandler _instance = UdpTalkDataHandler._internal();
int _recentRecvDataRate = 0;
int _recentRecvPacketCount = 0;
int _recentSendDataRate = 0;
int _recentSendPacketCount = 0;
int _lastRecvDataRate = 0;
int _lastRecvPacketCount = 0;
int _lastSendDataRate = 0;
int _lastSendPacketCount = 0;
void updateRecvDataRate(int dataSize) {
_recentRecvDataRate += dataSize;
_recentRecvPacketCount++;
}
void updateSendDataRate(int dataSize) {
_recentSendDataRate += dataSize;
_recentSendPacketCount++;
}
void resetDataRates() {
_lastRecvDataRate = _recentRecvDataRate;
_lastRecvPacketCount = _recentRecvPacketCount;
_lastSendDataRate = _recentSendDataRate;
_lastSendPacketCount = _recentSendPacketCount;
_recentRecvDataRate = 0;
_recentRecvPacketCount = 0;
_recentSendDataRate = 0;
_recentSendPacketCount = 0;
}
int getLastRecvDataRate() {
return _lastRecvDataRate;
}
int getLastRecvPacketCount() {
return _lastRecvPacketCount;
}
int getLastSendDataRate() {
return _lastSendDataRate;
}
int getLastSendPacketCount() {
return _lastSendPacketCount;
}
@override
void handleReq(ScpMessage scpMessage) {}
@override
void handleResp(ScpMessage scpMessage) {}
@override
void handleInvalidReq(ScpMessage scpMessage) {}
@override
void handleRealTimeData(ScpMessage scpMessage) {
// 收到数据后调用更新,防止定时器超时
talkDataOverTimeTimerManager.renew();
if (scpMessage.Payload != null) {
final TalkData talkData = scpMessage.Payload;
// 处理音视频数据
_handleTalkData(talkData: talkData);
}
}
String bufferToHexString(List<int> buffer) {
return buffer.map((byte) => byte.toRadixString(16).padLeft(2, '0')).join();
}
@override
deserializePayload(
{required int payloadType,
required int messageType,
required List<int> byte,
int? offset,
int? PayloadLength,
int? spTotal,
int? spIndex,
int? messageId}) {
// AppLog.log(
// '没有组包之前的每一个包的数据:${byte.length} messageId:$messageId spTotal:$spTotal spIndex:$spIndex PayloadLength:$PayloadLength,byte:${bufferToHexString(byte)}');
if (messageType == MessageTypeConstant.RealTimeData) {
// 回声测试
if (spTotal != null &&
spTotal > 1 &&
messageId != null &&
spIndex != null) {
// 分包处理
return handleFragmentedPayload(
messageId: messageId,
spTotal: spTotal,
spIndex: spIndex,
byte: byte,
payloadType: payloadType,
);
} else {
// 没有分包直接解析
final TalkData talkData = TalkData();
talkData.mergeFromBuffer(byte);
return talkData;
}
}
}
String listToHexString(List<int> intList) {
// 将整数列表转换为十六进制字符串列表
List<String> hexList = intList.map((num) => num.toRadixString(16)).toList();
// 将十六进制字符串列表连接成一个字符串,没有空格
return hexList.join('');
}
void _handleTalkData({required TalkData talkData}) {
if (talkData == null) return;
final contentType = talkData.contentType;
switch (contentType) {
case TalkData_ContentTypeE.H264:
_handleVideoH264(talkData);
break;
case TalkData_ContentTypeE.Image:
_handleVideoImage(talkData);
break;
case TalkData_ContentTypeE.G711:
_handleVideoG711(talkData);
break;
default:
print('❌未知的TalkData--->contentType类型');
break;
}
}
/// 处理h264协议的数据
void _handleVideoH264(TalkData talkData) {
final TalkDataH264Frame talkDataH264Frame = TalkDataH264Frame();
talkDataH264Frame.mergeFromBuffer(talkData.content);
frameHandler.handleFrame(talkDataH264Frame);
AppLog.log(
"帧:${talkDataH264Frame.frameType},帧序号:${talkDataH264Frame.frameSeq},对应I帧序号${talkDataH264Frame.frameSeqI}");
}
/// 处理图片数据
void _handleVideoImage(TalkData talkData) async {
final List<Uint8List> processCompletePayload =
await _processCompletePayload(Uint8List.fromList(talkData.content));
processCompletePayload.forEach((element) {
talkData.content = element;
talkDataRepository.addTalkData(talkData);
});
}
/// 处理g711音频数据
void _handleVideoG711(TalkData talkData) {
try {
// final g711Data = talkData.content;
// // 转pcm数据
// List<int> pcmBytes = G711().convertList(g711Data);
// talkData.content = pcmBytes;
talkDataRepository.addTalkData(talkData);
} catch (e) {
print('Error decoding G.711 to PCM: $e');
}
}
Future<List<Uint8List>> _processCompletePayload(Uint8List payload) async {
List<Uint8List> frames = [];
int startIdx = -1;
final length = payload.length - 1;
for (int i = 0; i < length; i++) {
final currentByte = payload[i];
final nextByte = payload[i + 1];
if (currentByte == 0xFF) {
if (nextByte == 0xD8) {
startIdx = i;
i++; // Skip the next byte
} else if (nextByte == 0xD9 && startIdx != -1) {
frames
.add(Uint8List.view(payload.buffer, startIdx, i + 2 - startIdx));
startIdx = -1;
i++; // Skip the next byte
}
}
}
return frames;
}
// Future<List<Uint8List>> _processCompletePayload(Uint8List payload) async {
// // 存储找到的所有完整帧
// List<Uint8List> frames = [];
//
// // 手动遍历 payload
// int i = 0;
// while (i < payload.length - 1) {
// // 寻找起始标志 0xFFD8
// if (payload[i] == 0xFF && payload[i + 1] == 0xD8) {
// int startIdx = i;
// i += 2; // 跳过起始标志
//
// // 寻找结束标志 0xFFD9
// while (i < payload.length - 1) {
// if (payload[i] == 0xFF && payload[i + 1] == 0xD9) {
// // 找到结束标志 0xFFD9
// int endIdx = i + 2;
// // 使用 Uint8List.view 创建视图,避免内存分配
// frames.add(
// Uint8List.view(payload.buffer, startIdx, endIdx - startIdx));
// i = endIdx; // 继续寻找下一个帧
// break;
// } else {
// i += 1; // 继续寻找结束标志
// }
// }
// } else {
// i += 1; // 继续寻找起始标志
// }
// }
//
// // 返回找到的所有完整帧
// return frames;
// }
// Future<List<Uint8List>> _processCompletePayload(Uint8List payload) async {
// // 存储找到的所有完整帧
// List<Uint8List> frames = [];
//
// // 寻找完整帧 (0xFFD8 开始, 0xFFD9 结束)
// int startIdx = 0;
// while (startIdx < payload.length - 1) {
// // 找到帧的起始标志 0xFFD8
// startIdx = payload.indexOf(0xFF, startIdx);
// if (startIdx == -1 || startIdx + 1 >= payload.length) break;
// if (payload[startIdx + 1] == 0xD8) {
// // 找到帧的起始标志 0xFFD8
// int endIdx = startIdx + 2;
// while (endIdx < payload.length - 1) {
// endIdx = payload.indexOf(0xFF, endIdx);
// if (endIdx == -1 || endIdx + 1 >= payload.length) break;
// if (payload[endIdx + 1] == 0xD9) {
// // 找到帧的结束标志 0xFFD9
// Uint8List frame = payload.sublist(startIdx, endIdx + 2);
// frames.add(frame);
// startIdx = endIdx + 2; // 继续寻找下一个帧
// break;
// } else {
// endIdx += 1; // 继续寻找结束标志
// }
// }
// } else {
// startIdx += 1; // 继续寻找下一个起始标志
// }
// }
//
// // 返回找到的所有完整帧
// return frames;
// }
}