fix:调整发送g711音频数据

This commit is contained in:
liyi 2025-01-14 17:57:33 +08:00
parent 7a0e8f9e28
commit df71e2ceb7
6 changed files with 168 additions and 58 deletions

View File

@ -3,12 +3,54 @@ import 'dart:math';
import 'package:flutter/services.dart';
class G711 {
List<int> _aLawTable = [
1, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
];
Future<List<int>> readAssetFile(String assetPath) async {
final ByteData data = await rootBundle.load(assetPath);
final List<int> bytes = data.buffer.asUint8List();
return bytes;
}
List<int> encodeALaw(List<int> pcmSamples) {
final List<int> aLawSamples = [];
for (final sample in pcmSamples) {
// 16 PCM 13
int normalizedSample = sample >> 3;
//
int sign = (normalizedSample & 0x8000) != 0 ? 0x80 : 0x00;
//
normalizedSample = normalizedSample.abs();
//
int segment = _aLawTable[normalizedSample >> 8];
//
int quantizedValue = (normalizedSample >> (segment + 3)) & 0x0F;
// A-law
int aLawSample = sign | (segment << 4) | quantizedValue;
//
aLawSamples.add(aLawSample);
}
return aLawSamples;
}
int ALawToLinear(int aVal) {
//
aVal = ~aVal;

View File

@ -276,6 +276,11 @@ class MessageCommand {
int? SpTotal,
int? SpIndex,
}) {
// payload 4
// final payloadBytes = ByteData(payload!.length * 4);
// for (int i = 0; i < payload.length; i++) {
// payloadBytes.setInt32(i * 4, payload[i], Endian.big); // 使
// }
// final payload = talkData.writeToBuffer();
ScpMessage message = ScpMessage(
ProtocolFlag: ProtocolFlagConstant.scp01,
@ -286,7 +291,7 @@ class MessageCommand {
FromPeerId: FromPeerId,
ToPeerId: ToPeerId,
Payload: payload,
PayloadCRC: calculationCrc(Uint8List.fromList(payload!)),
PayloadCRC: calculationCrcFromIntList(payload!),
PayloadLength: payload.length,
PayloadType: PayloadTypeConstant.talkData,
);
@ -428,7 +433,7 @@ class MessageCommand {
FromPeerId: FromPeerId,
ToPeerId: ToPeerId,
Payload: payload,
PayloadCRC: calculationCrc(Uint8List.fromList(payload)),
PayloadCRC: calculationCrcFromIntList(payload),
PayloadLength: payload.length,
PayloadType: PayloadTypeConstant.blePassthrough,
);
@ -438,10 +443,30 @@ class MessageCommand {
// 16
static List<int> _hexToBytes(String hex) {
final bytes = <int>[];
for (int i = 0; i < hex.length; i += 2) {
bytes.add(int.parse(hex.substring(i, i + 2), radix: 16));
//
hex = hex.replaceAll(RegExp(r'[^0-9a-fA-F]'), '');
// 0
if (hex.length % 2 != 0) {
hex = '0$hex';
}
final bytes = <int>[];
for (int i = 0; i < hex.length; i += 2) {
// i + 2 hex
final end = i + 2 <= hex.length ? i + 2 : hex.length;
final hexByte = hex.substring(i, end);
//
try {
bytes.add(int.parse(hexByte, radix: 16));
} catch (e) {
//
throw FormatException('Invalid hex byte: $hexByte');
}
}
return bytes;
}

View File

@ -426,7 +426,7 @@ class StartChartManage {
//
//
Future<void> sendTalkDataMessage({required TalkData talkData}) async {
String toPeerId = lockPeerId;
String toPeerId = ToPeerId;
final List<int> payload = talkData.content;
//
final int totalPackets = (payload.length / _maxPayloadSize).ceil();
@ -452,6 +452,7 @@ class StartChartManage {
SpIndex: i + 1,
MessageId: messageId,
);
//
await _sendMessage(message: message);
}

View File

@ -10,6 +10,7 @@ import 'package:flutter_pcm_sound/flutter_pcm_sound.dart';
import 'package:flutter_screen_recording/flutter_screen_recording.dart';
import 'package:flutter_voice_processor/flutter_voice_processor.dart';
import 'package:g711_flutter/g711_flutter.dart';
import 'package:gallery_saver/gallery_saver.dart';
import 'package:get/get.dart';
@ -128,9 +129,10 @@ class TalkViewLogic extends BaseGetXController {
///
void _playAudioData(TalkData talkData) async {
final list = G711().decodeAndDenoise(talkData.content, true, 8000, 100, 50);
// PCM PcmArrayInt16
// final list = G711().convertList(talkData.content);
final list = G711().decodeAndDenoise(talkData.content, true, 8000, 300, 50);
//
// // PCM PcmArrayInt16
final PcmArrayInt16 fromList = PcmArrayInt16.fromList(list);
FlutterPcmSound.feed(fromList);
if (!state.isPlaying.value) {
@ -459,14 +461,22 @@ class TalkViewLogic extends BaseGetXController {
state.videoBuffer.clear(); //
_syncTimer?.cancel(); //
_syncTimer = null; //
stopProcessingAudio();
super.onClose();
}
@override
void dispose() {
stopProcessingAudio();
super.dispose();
}
///
void _handleInvalidTalkStatus() {
state.listData.value = Uint8List(0);
//
_stopPlayG711Data();
stopProcessingAudio();
//
Get.back();
}
@ -576,20 +586,33 @@ class TalkViewLogic extends BaseGetXController {
}
Future<void> _onFrame(List<int> frame) async {
state.recordingAudioAllFrames.add(frame); //
// state.recordingAudioAllFrames.add(frame); //
// final List<int> concatenatedFrames =
// _concatenateFrames(state.recordingAudioAllFrames); //
final List<int> pcmBytes = _listLinearToULaw(frame);
// concatenateFrames(state.recordingAudioAllFrames); //
// final List<int> pcmBytes = _listLinearToULaw(frame);
// final aLaw = G711().encodeALaw(frame);
// final aLawFrame = listLinearToALaw(frame);
// 640 0 PCM
// 640 0 8 PCM
final pcmSamples = List<int>.filled(640, 0); // 128 8 PCM 0
// A-law
final aLawSamples = listLinearToALaw(pcmSamples, isUnsigned: true);
final encode = DartG711Codec().encode(Uint8List.fromList(pcmSamples));
AppLog.log('msg');
// AppLog.log('录制的音频数据A-law$aLawFrame, size${aLawFrame.length}');
//
await StartChartManage().sendTalkDataMessage(
talkData: TalkData(
content: pcmBytes,
content: aLawSamples,
contentType: TalkData_ContentTypeE.G711,
durationMs: DateTime.now().millisecondsSinceEpoch -
state.startRecordingAudioTime.value.millisecondsSinceEpoch,
),
);
AppLog.log('发送音频数据');
}
void _onError(VoiceProcessorException error) {
@ -597,57 +620,77 @@ class TalkViewLogic extends BaseGetXController {
AppLog.log(error.message!);
}
// pcm
List<int> _listLinearToULaw(List<int> pcmList) {
final List<int> uLawList = [];
for (int pcmVal in pcmList) {
final int uLawVal = _linearToULaw(pcmVal);
uLawList.add(uLawVal);
int linearToALaw(int pcmVal) {
const int ALAW_MAX = 0x7FFF; // 16 PCM
const int ALAW_BIAS = 0x84; // A-law
//
int sign = (pcmVal & 0x8000) != 0 ? 0x00 : 0x80; // A-law
if (sign == 0x80) {
pcmVal = -pcmVal; //
}
return uLawList;
// PCM
if (pcmVal > ALAW_MAX) {
pcmVal = ALAW_MAX;
}
//
pcmVal += ALAW_BIAS;
//
int seg = searchALawSegment(pcmVal);
int quantizedValue = (pcmVal >> (seg + 3)) & 0x0F;
// A-law
int aLawVal = sign | (seg << 4) | quantizedValue;
return aLawVal;
}
// pcm
int _linearToULaw(int pcmVal) {
int mask;
int seg;
int uval;
if (pcmVal < 0) {
pcmVal = 0x84 - pcmVal;
mask = 0x7F;
} else {
pcmVal += 0x84;
mask = 0xFF;
}
seg = search(pcmVal);
if (seg >= 8) {
return 0x7F ^ mask;
} else {
uval = seg << 4;
uval |= (pcmVal >> (seg + 3)) & 0xF;
return uval ^ mask;
}
}
int search(int val) {
final List<int> table = [
int searchALawSegment(int val) {
const List<int> ALAW_SEGMENT_TABLE = [
0x1F,
0x3F,
0x7F,
0xFF,
0x1FF,
0x3FF,
0x7FF,
0xFFF,
0x1FFF,
0x3FFF,
0x7FFF
0xFFF
];
const int size = 8;
for (int i = 0; i < size; i++) {
if (val <= table[i]) {
if (val <= ALAW_SEGMENT_TABLE[i]) {
return i;
}
}
return size;
}
List<int> listLinearToALaw(List<int> pcmList, {bool isUnsigned = true}) {
final List<int> aLawList = [];
// 8 PCM 16 PCM
for (int i = 0; i < pcmList.length; i += 2) {
int pcm8High = pcmList[i];
int pcm8Low = (i + 1 < pcmList.length) ? pcmList[i + 1] : 0; // 0
// 8 PCM 16 PCM
int pcm16;
if (isUnsigned) {
// 8 PCM 16 PCM
pcm16 = ((pcm8High - 128) << 8) | (pcm8Low - 128);
} else {
// 8 PCM 16 PCM
pcm16 = (pcm8High << 8) | pcm8Low;
}
// 16 PCM A-law
final int aLawVal = linearToALaw(pcm16);
aLawList.add(aLawVal);
}
return aLawList;
}
}

View File

@ -56,9 +56,8 @@ class TalkViewState {
//
List<TalkData> audioBuffer = <TalkData>[].obs;
List<TalkData> audioBuffer2 = <TalkData>[].obs;
List<TalkData> activeAudioBuffer =<TalkData>[].obs;
List<TalkData> activeVideoBuffer =<TalkData>[].obs;
List<TalkData> activeAudioBuffer = <TalkData>[].obs;
List<TalkData> activeVideoBuffer = <TalkData>[].obs;
List<TalkData> videoBuffer = <TalkData>[].obs;
List<TalkData> videoBuffer2 = <TalkData>[].obs;
@ -83,9 +82,9 @@ class TalkViewState {
RxInt recordingAudioTime = 0.obs; //
RxDouble fps = 0.0.obs; // FPS
late VoiceProcessor? voiceProcessor; //
final int frameLength = 320; //320
final int frameLength = 640; //640
final int sampleRate = 8000; //8000
List<List<int>> recordingAudioAllFrames = <List<int>>[]; //
RxInt rotateAngle = 0.obs; //
RxBool isLongPressing = false.obs; //
RxBool isLongPressing = false.obs; //
}

View File

@ -263,7 +263,7 @@ dependencies:
fixnum: ^1.1.1
# 图片预览
photo_view: ^0.15.0
g711_flutter: ^2.1.1