feat: 对讲中APP发送录音到锁声量增大
This commit is contained in:
parent
9aac85f20e
commit
6adc1b41d3
@ -46,6 +46,8 @@ class TalkViewLogic extends BaseGetXController {
|
|||||||
int audioFrameIntervalMs = 20; // 初始帧间隔设置为45毫秒(约22FPS)
|
int audioFrameIntervalMs = 20; // 初始帧间隔设置为45毫秒(约22FPS)
|
||||||
int minFrameIntervalMs = 30; // 最小帧间隔(约33 FPS)
|
int minFrameIntervalMs = 30; // 最小帧间隔(约33 FPS)
|
||||||
int maxFrameIntervalMs = 100; // 最大帧间隔(约1 FPS)
|
int maxFrameIntervalMs = 100; // 最大帧间隔(约1 FPS)
|
||||||
|
// 定义音频帧缓冲和发送函数
|
||||||
|
List<int> _bufferedAudioFrames = <int>[];
|
||||||
|
|
||||||
/// 初始化音频播放器
|
/// 初始化音频播放器
|
||||||
void _initFlutterPcmSound() {
|
void _initFlutterPcmSound() {
|
||||||
@ -533,15 +535,17 @@ class TalkViewLogic extends BaseGetXController {
|
|||||||
|
|
||||||
//开始录音
|
//开始录音
|
||||||
Future<void> startProcessingAudio() async {
|
Future<void> startProcessingAudio() async {
|
||||||
// 增加录音帧监听器和错误监听器
|
|
||||||
state.voiceProcessor?.addFrameListener(_onFrame);
|
|
||||||
state.voiceProcessor?.addErrorListener(_onError);
|
|
||||||
try {
|
try {
|
||||||
if (await state.voiceProcessor?.hasRecordAudioPermission() ?? false) {
|
if (await state.voiceProcessor?.hasRecordAudioPermission() ?? false) {
|
||||||
await state.voiceProcessor?.start(state.frameLength, state.sampleRate);
|
await state.voiceProcessor?.start(state.frameLength, state.sampleRate);
|
||||||
final bool? isRecording = await state.voiceProcessor?.isRecording();
|
final bool? isRecording = await state.voiceProcessor?.isRecording();
|
||||||
state.isRecordingAudio.value = isRecording!;
|
state.isRecordingAudio.value = isRecording!;
|
||||||
state.startRecordingAudioTime.value = DateTime.now();
|
state.startRecordingAudioTime.value = DateTime.now();
|
||||||
|
|
||||||
|
// 增加录音帧监听器和错误监听器
|
||||||
|
state.voiceProcessor
|
||||||
|
?.addFrameListeners(<VoiceProcessorFrameListener>[_onFrame]);
|
||||||
|
state.voiceProcessor?.addErrorListener(_onError);
|
||||||
} else {
|
} else {
|
||||||
// state.errorMessage.value = 'Recording permission not granted';
|
// state.errorMessage.value = 'Recording permission not granted';
|
||||||
}
|
}
|
||||||
@ -576,23 +580,23 @@ class TalkViewLogic extends BaseGetXController {
|
|||||||
|
|
||||||
// 音频帧处理
|
// 音频帧处理
|
||||||
Future<void> _onFrame(List<int> frame) async {
|
Future<void> _onFrame(List<int> frame) async {
|
||||||
// 预处理和转码操作放到异步计算线程
|
|
||||||
// final processedFrame = await compute(preprocessAudio, frame);
|
|
||||||
// final list = listLinearToALaw(processedFrame);
|
|
||||||
final List<int> processedFrame = preprocessAudio(frame);
|
final List<int> processedFrame = preprocessAudio(frame);
|
||||||
final List<int> list = listLinearToALaw(processedFrame);
|
final List<int> list = listLinearToALaw(processedFrame);
|
||||||
|
_bufferedAudioFrames.addAll(list);
|
||||||
|
|
||||||
final int ms = DateTime.now().millisecondsSinceEpoch -
|
final int ms = DateTime.now().millisecondsSinceEpoch -
|
||||||
state.startRecordingAudioTime.value.millisecondsSinceEpoch;
|
state.startRecordingAudioTime.value.millisecondsSinceEpoch;
|
||||||
|
|
||||||
// 发送音频数据到UDP
|
Future.delayed(const Duration(milliseconds: 1000)).whenComplete(() async {
|
||||||
await StartChartManage().sendTalkDataMessage(
|
// 发送音频数据到UDP
|
||||||
talkData: TalkData(
|
await StartChartManage().sendTalkDataMessage(
|
||||||
content: list,
|
talkData: TalkData(
|
||||||
contentType: TalkData_ContentTypeE.G711,
|
content: list,
|
||||||
durationMs: ms,
|
contentType: TalkData_ContentTypeE.G711,
|
||||||
),
|
durationMs: ms,
|
||||||
);
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// 错误监听
|
// 错误监听
|
||||||
@ -662,9 +666,31 @@ class TalkViewLogic extends BaseGetXController {
|
|||||||
// return processedList;
|
// return processedList;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
List<int> listLinearToALaw(List<int> pcmList) {
|
List<int> adjustVolume(List<int> pcmList, double volume) {
|
||||||
final List<int> aLawList = [];
|
final List<int> adjustedPcmList = [];
|
||||||
for (int pcmVal in pcmList) {
|
for (int pcmVal in pcmList) {
|
||||||
|
// 调整音量
|
||||||
|
int adjustedPcmVal = (pcmVal * volume).round();
|
||||||
|
|
||||||
|
// 裁剪到 16-bit PCM 范围
|
||||||
|
if (adjustedPcmVal > 32767) {
|
||||||
|
adjustedPcmVal = 32767;
|
||||||
|
} else if (adjustedPcmVal < -32768) {
|
||||||
|
adjustedPcmVal = -32768;
|
||||||
|
}
|
||||||
|
|
||||||
|
adjustedPcmList.add(adjustedPcmVal);
|
||||||
|
}
|
||||||
|
return adjustedPcmList;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<int> listLinearToALaw(List<int> pcmList) {
|
||||||
|
// 先调节音量
|
||||||
|
final List<int> adjustedPcmList = adjustVolume(pcmList, 5.0);
|
||||||
|
|
||||||
|
// 再进行 A-law 编码
|
||||||
|
final List<int> aLawList = [];
|
||||||
|
for (int pcmVal in adjustedPcmList) {
|
||||||
final int aLawVal = linearToALaw(pcmVal);
|
final int aLawVal = linearToALaw(pcmVal);
|
||||||
aLawList.add(aLawVal);
|
aLawList.add(aLawVal);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -37,7 +37,7 @@ class TalkViewState {
|
|||||||
RxList<int> listAudioData = <int>[].obs; //得到的音频流字节数据
|
RxList<int> listAudioData = <int>[].obs; //得到的音频流字节数据
|
||||||
GlobalKey globalKey = GlobalKey();
|
GlobalKey globalKey = GlobalKey();
|
||||||
|
|
||||||
Timer? oneMinuteTimeTimer; // 定时器超过60秒关闭当前界面
|
Timer? oneMinuteTimeTimer; // 定时器超过60秒关闭当前界面
|
||||||
RxInt oneMinuteTime = 0.obs; // 定时器秒数
|
RxInt oneMinuteTime = 0.obs; // 定时器秒数
|
||||||
|
|
||||||
// 定时器如果发送了接听的命令 而没收到回复就每秒重复发送10次
|
// 定时器如果发送了接听的命令 而没收到回复就每秒重复发送10次
|
||||||
@ -89,4 +89,4 @@ class TalkViewState {
|
|||||||
RxBool isLongPressing = false.obs; // 旋转角度(以弧度为单位)
|
RxBool isLongPressing = false.obs; // 旋转角度(以弧度为单位)
|
||||||
RxBool hasAudioData = false.obs; // 是否有音频数据
|
RxBool hasAudioData = false.obs; // 是否有音频数据
|
||||||
RxInt lastAudioTimestamp = 0.obs; // 最后接收到的音频数据的时间戳
|
RxInt lastAudioTimestamp = 0.obs; // 最后接收到的音频数据的时间戳
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user