fix:调整发送g711音频数据
This commit is contained in:
parent
6df3783f90
commit
1fb9a5a188
@ -11,6 +11,7 @@ import 'package:star_lock/talk/startChart/proto/gateway_reset.pb.dart';
|
||||
import 'package:star_lock/talk/startChart/proto/generic.pb.dart';
|
||||
import 'package:star_lock/talk/startChart/proto/rbcu.pb.dart';
|
||||
import 'package:star_lock/talk/startChart/proto/talk_accept.pb.dart';
|
||||
import 'package:star_lock/talk/startChart/proto/talk_data.pb.dart';
|
||||
import 'package:star_lock/talk/startChart/proto/talk_expect.pb.dart';
|
||||
import 'package:star_lock/talk/startChart/proto/talk_hangup.pb.dart';
|
||||
import 'package:star_lock/talk/startChart/proto/talk_ping.pb.dart';
|
||||
@ -272,16 +273,12 @@ class MessageCommand {
|
||||
required String FromPeerId,
|
||||
required String ToPeerId,
|
||||
int? MessageId,
|
||||
List<int>? payload,
|
||||
required TalkData talkData,
|
||||
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();
|
||||
|
||||
final payload = talkData.writeToBuffer();
|
||||
ScpMessage message = ScpMessage(
|
||||
ProtocolFlag: ProtocolFlagConstant.scp01,
|
||||
MessageType: MessageTypeConstant.RealTimeData,
|
||||
@ -291,7 +288,7 @@ class MessageCommand {
|
||||
FromPeerId: FromPeerId,
|
||||
ToPeerId: ToPeerId,
|
||||
Payload: payload,
|
||||
PayloadCRC: calculationCrcFromIntList(payload!),
|
||||
PayloadCRC: calculationCrcFromIntList(payload),
|
||||
PayloadLength: payload.length,
|
||||
PayloadType: PayloadTypeConstant.talkData,
|
||||
);
|
||||
|
||||
@ -438,7 +438,7 @@ class StartChartManage {
|
||||
end = payload.length;
|
||||
}
|
||||
// 取到分包数据
|
||||
List<int> packet = payload.sublist(start, end);
|
||||
List<int> packetTalkData = payload.sublist(start, end);
|
||||
|
||||
// 分包数据不递增messageID
|
||||
final messageId =
|
||||
@ -447,12 +447,15 @@ class StartChartManage {
|
||||
final message = MessageCommand.talkDataMessage(
|
||||
ToPeerId: toPeerId,
|
||||
FromPeerId: FromPeerId,
|
||||
payload: packet,
|
||||
talkData: TalkData(
|
||||
contentType: talkData.contentType,
|
||||
content: packetTalkData,
|
||||
durationMs: talkData.durationMs,
|
||||
),
|
||||
SpTotal: totalPackets,
|
||||
SpIndex: i + 1,
|
||||
MessageId: messageId,
|
||||
);
|
||||
|
||||
// 发送消息
|
||||
await _sendMessage(message: message);
|
||||
}
|
||||
|
||||
@ -8,10 +8,8 @@ import 'package:flutter/services.dart';
|
||||
import 'package:flutter_easyloading/flutter_easyloading.dart';
|
||||
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:gallery_saver/gallery_saver.dart';
|
||||
|
||||
import 'package:get/get.dart';
|
||||
import 'package:image_gallery_saver/image_gallery_saver.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
@ -560,6 +558,7 @@ class TalkViewLogic extends BaseGetXController {
|
||||
} on PlatformException catch (ex) {
|
||||
// state.errorMessage.value = 'Failed to start recorder: $ex';
|
||||
}
|
||||
state.isOpenVoice.value = false;
|
||||
}
|
||||
|
||||
/// 停止录音
|
||||
@ -581,34 +580,20 @@ class TalkViewLogic extends BaseGetXController {
|
||||
} finally {
|
||||
final bool? isRecording = await state.voiceProcessor?.isRecording();
|
||||
state.isRecordingAudio.value = isRecording!;
|
||||
state.isOpenVoice.value = true;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _onFrame(List<int> frame) async {
|
||||
// state.recordingAudioAllFrames.add(frame); // 将帧添加到状态变量中
|
||||
// final List<int> concatenatedFrames =
|
||||
// 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);
|
||||
|
||||
AppLog.log('msg');
|
||||
|
||||
// AppLog.log('录制的音频数据(A-law):$aLawFrame, size:${aLawFrame.length}');
|
||||
|
||||
final list = listLinearToALaw(frame);
|
||||
final ms = DateTime.now().millisecondsSinceEpoch -
|
||||
state.startRecordingAudioTime.value.millisecondsSinceEpoch;
|
||||
// 发送音频数据
|
||||
await StartChartManage().sendTalkDataMessage(
|
||||
talkData: TalkData(
|
||||
content: aLawSamples,
|
||||
content: list,
|
||||
contentType: TalkData_ContentTypeE.G711,
|
||||
durationMs: DateTime.now().millisecondsSinceEpoch -
|
||||
state.startRecordingAudioTime.value.millisecondsSinceEpoch,
|
||||
durationMs: ms,
|
||||
),
|
||||
);
|
||||
}
|
||||
@ -618,77 +603,69 @@ class TalkViewLogic extends BaseGetXController {
|
||||
AppLog.log(error.message!);
|
||||
}
|
||||
|
||||
int linearToALaw(int pcmVal) {
|
||||
const int ALAW_MAX = 0x7FFF; // 16 位 PCM 的最大值
|
||||
const int ALAW_BIAS = 0x84; // A-law 偏置值
|
||||
List<int> listLinearToALaw(List<int> pcmList) {
|
||||
final List<int> aLawList = [];
|
||||
for (int pcmVal in pcmList) {
|
||||
final int aLawVal = linearToALaw(pcmVal);
|
||||
aLawList.add(aLawVal);
|
||||
}
|
||||
return aLawList;
|
||||
}
|
||||
|
||||
// 处理符号位
|
||||
int sign = (pcmVal & 0x8000) != 0 ? 0x00 : 0x80; // A-law 符号位
|
||||
if (sign == 0x80) {
|
||||
pcmVal = -pcmVal; // 取绝对值
|
||||
int linearToALaw(int pcmVal) {
|
||||
const int ALAW_MAX = 0x7FFF; // 32767
|
||||
const int ALAW_BIAS = 0x84; // 132
|
||||
|
||||
int mask;
|
||||
int seg;
|
||||
int aLawVal;
|
||||
|
||||
// Handle sign
|
||||
if (pcmVal < 0) {
|
||||
pcmVal = -pcmVal;
|
||||
mask = 0x7F; // 127 (sign bit is 1)
|
||||
} else {
|
||||
mask = 0xFF; // 255 (sign bit is 0)
|
||||
}
|
||||
|
||||
// 限制 PCM 值在有效范围内
|
||||
// Add bias and clamp to ALAW_MAX
|
||||
pcmVal += ALAW_BIAS;
|
||||
if (pcmVal > ALAW_MAX) {
|
||||
pcmVal = ALAW_MAX;
|
||||
}
|
||||
|
||||
// 添加偏置
|
||||
pcmVal += ALAW_BIAS;
|
||||
// Determine segment
|
||||
seg = search(pcmVal);
|
||||
|
||||
// 查找段和量化值
|
||||
int seg = searchALawSegment(pcmVal);
|
||||
int quantizedValue = (pcmVal >> (seg + 3)) & 0x0F;
|
||||
// Calculate A-law value
|
||||
if (seg >= 8) {
|
||||
aLawVal = 0x7F ^ mask; // Clamp to maximum value
|
||||
} else {
|
||||
int quantized = (pcmVal >> (seg + 3)) & 0xF;
|
||||
aLawVal = (seg << 4) | quantized;
|
||||
aLawVal ^= 0xD5; // XOR with 0xD5 to match standard A-law table
|
||||
}
|
||||
|
||||
// 生成 A-law 编码
|
||||
int aLawVal = sign | (seg << 4) | quantizedValue;
|
||||
return aLawVal;
|
||||
}
|
||||
|
||||
int searchALawSegment(int val) {
|
||||
const List<int> ALAW_SEGMENT_TABLE = [
|
||||
0x1F,
|
||||
0x3F,
|
||||
0x7F,
|
||||
0xFF,
|
||||
0x1FF,
|
||||
0x3FF,
|
||||
0x7FF,
|
||||
0xFFF
|
||||
int search(int val) {
|
||||
final List<int> table = [
|
||||
0xFF, // Segment 0
|
||||
0x1FF, // Segment 1
|
||||
0x3FF, // Segment 2
|
||||
0x7FF, // Segment 3
|
||||
0xFFF, // Segment 4
|
||||
0x1FFF, // Segment 5
|
||||
0x3FFF, // Segment 6
|
||||
0x7FFF // Segment 7
|
||||
];
|
||||
const int size = 8;
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
if (val <= ALAW_SEGMENT_TABLE[i]) {
|
||||
if (val <= 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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -82,7 +82,7 @@ class TalkViewState {
|
||||
RxInt recordingAudioTime = 0.obs; // 录音时间持续时间
|
||||
RxDouble fps = 0.0.obs; // 添加 FPS 计数
|
||||
late VoiceProcessor? voiceProcessor; // 音频处理器、录音
|
||||
final int frameLength = 640; //录音视频帧长度为640
|
||||
final int frameLength = 320; //录音视频帧长度为640
|
||||
final int sampleRate = 8000; //录音频采样率为8000
|
||||
List<List<int>> recordingAudioAllFrames = <List<int>>[]; // 录制音频的所有帧
|
||||
RxInt rotateAngle = 0.obs; // 旋转角度(以弧度为单位)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user