fix(audio): ignore playback tail before VAD
This commit is contained in:
@@ -29,6 +29,9 @@
|
||||
// 在文件顶部添加状态变量
|
||||
static uint8_t speech_detect_count = 0; // 连续语音帧计数器
|
||||
#define SPEECH_DETECT_THRESHOLD 20 // 连续检测到语音的阈值
|
||||
#define PLAYBACK_VAD_GUARD_MS 800 // 屏蔽播放结束后的尾音和音频通路切换噪声
|
||||
#define VAD_FRAME_BYTES 640 // 20ms @ 16kHz, 16-bit mono
|
||||
#define VAD_PREROLL_FRAMES 25 // 保留500ms预录音,避免吞掉用户首字
|
||||
uint8_t no_speech_timeout = 0;
|
||||
extern int g_mic_working;
|
||||
|
||||
@@ -57,6 +60,9 @@ static int64_t no_sound_start_time = 0;
|
||||
static int64_t cmd_wait_start_time = 0;
|
||||
static bool first_sound_detected = false;
|
||||
static int64_t recording_start_time = 0; // 记录录音开始时间(首次检测到声音时)
|
||||
static uint8_t vad_preroll[VAD_PREROLL_FRAMES][VAD_FRAME_BYTES];
|
||||
static size_t vad_preroll_next = 0;
|
||||
static size_t vad_preroll_count = 0;
|
||||
|
||||
static int vad_tts_playback_finished_status = 0;
|
||||
// 统计
|
||||
@@ -101,6 +107,9 @@ void set_state(system_state_t new_state) {
|
||||
no_sound_start_time = now;
|
||||
first_sound_detected = false;
|
||||
speech_frame_count = 0;
|
||||
speech_detect_count = 0;
|
||||
vad_preroll_next = 0;
|
||||
vad_preroll_count = 0;
|
||||
g_mic_working = 0;
|
||||
break;
|
||||
case STATE_RECORDING_ACTIVE:
|
||||
@@ -299,8 +308,8 @@ void vad_audio_process(void) {
|
||||
int64_t now = hal_os_up_time_ms();
|
||||
|
||||
static size_t buffer_offset = 0;
|
||||
uint8_t mic_buf[640]={0};
|
||||
int record_len = 640;
|
||||
uint8_t mic_buf[VAD_FRAME_BYTES]={0};
|
||||
int record_len = VAD_FRAME_BYTES;
|
||||
uint16 frame[320];
|
||||
int index = 0, i = 0;
|
||||
|
||||
@@ -326,15 +335,19 @@ void vad_audio_process(void) {
|
||||
//每次读取640字节音频数据
|
||||
ql_audio_record_read(record_hd, mic_buf, &record_len);
|
||||
|
||||
//如果检测到声音再去传输
|
||||
// if(first_sound_detected){
|
||||
//实际上每次编码需要输入1152字节的PCM数据
|
||||
if(hal_os_rb_write(ring_sender, (uint8*)mic_buf, record_len, 25)>0){
|
||||
|
||||
//quec_usbcdc_write((uint8*)mic_buf, record_len);
|
||||
ql_rtos_semaphore_release(sender_sem); //告诉线程去获取录音数据
|
||||
if (g_state == STATE_RECORDING_WAIT_SOUND) {
|
||||
/* 首次开口确认前不向服务端发送静音。只在本地保留最近500ms,
|
||||
* 确认开口时再回填,防止截掉用户首字。 */
|
||||
memcpy(vad_preroll[vad_preroll_next], mic_buf, VAD_FRAME_BYTES);
|
||||
vad_preroll_next = (vad_preroll_next + 1) % VAD_PREROLL_FRAMES;
|
||||
if (vad_preroll_count < VAD_PREROLL_FRAMES) {
|
||||
vad_preroll_count++;
|
||||
}
|
||||
} else {
|
||||
if(hal_os_rb_write(ring_sender, (uint8*)mic_buf, record_len, 25)>0){
|
||||
ql_rtos_semaphore_release(sender_sem);
|
||||
}
|
||||
}
|
||||
// }
|
||||
#if 1
|
||||
for(index=0; index<320; index++)
|
||||
{
|
||||
@@ -347,6 +360,12 @@ void vad_audio_process(void) {
|
||||
|
||||
// 首次声音检测
|
||||
if (!first_sound_detected) {
|
||||
/* 播放刚结束时扬声器尾音和PA切换噪声容易被FVAD认为用户开口。 */
|
||||
if ((now - no_sound_start_time) < PLAYBACK_VAD_GUARD_MS) {
|
||||
speech_detect_count = 0;
|
||||
buffer_offset = 0;
|
||||
break;
|
||||
}
|
||||
if (current_vad == VAD_STATE_ACTIVE) {
|
||||
speech_detect_count++;
|
||||
printf("Speech frame count: %d\r\n", speech_detect_count);
|
||||
@@ -363,8 +382,19 @@ void vad_audio_process(void) {
|
||||
}
|
||||
#endif
|
||||
|
||||
first_sound_detected = true;
|
||||
set_state(STATE_RECORDING_ACTIVE);
|
||||
first_sound_detected = true;
|
||||
{
|
||||
size_t first = (vad_preroll_next + VAD_PREROLL_FRAMES - vad_preroll_count) % VAD_PREROLL_FRAMES;
|
||||
size_t n;
|
||||
for (n = 0; n < vad_preroll_count; n++) {
|
||||
size_t frame_index = (first + n) % VAD_PREROLL_FRAMES;
|
||||
if (hal_os_rb_write(ring_sender, vad_preroll[frame_index], VAD_FRAME_BYTES, 25) > 0) {
|
||||
ql_rtos_semaphore_release(sender_sem);
|
||||
}
|
||||
}
|
||||
vad_preroll_count = 0;
|
||||
}
|
||||
set_state(STATE_RECORDING_ACTIVE);
|
||||
printf("First speech confirmed by FVAD (continuous %d frames)", SPEECH_DETECT_THRESHOLD);
|
||||
}
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user