Files
banban/ql-application/threadx/interface/custom_app/net_diag_voice.c
T

100 lines
4.6 KiB
C

#include <stdio.h>
#include <string.h>
#include "ql_rtos.h"
#include "hal_api.h"
#include "net_diag.h"
#include "net_diag_voice.h"
static struct {
unsigned int round, seen;
unsigned long started, stamp[VOICE_STAGE_COUNT];
char first_url[128];
} voice;
static const char *stages[] = {
"确认用户语音", "录音结束", "结束包已入发送队列(不代表服务端收到)",
"收到END_ACK", "收到TTS_START", "收到首段音频URL", "首段开始下载",
"首段下载完成", "首PCM提交播放接口(不等于实际出声)"
};
void net_diag_voice_begin(unsigned int round)
{
if (!net_diag_is_enabled()) return;
ql_rtos_task_sched_lock();
memset(&voice, 0, sizeof(voice));
voice.round = round; voice.started = (unsigned long)hal_os_up_time_ms();
ql_rtos_task_sched_unlock();
printf("[现场诊断][%lu ms][对话#%u] 开始录音;分段计时起点\r\n", voice.started, round);
}
void net_diag_voice_mark(unsigned int round, int stage)
{
unsigned long now, since_start, total = 0, tail = 0, server = 0, wait_url = 0, queue = 0, download = 0, pcm = 0;
unsigned int bit, seen;
if (!net_diag_is_enabled() || stage < 0 || stage >= VOICE_STAGE_COUNT) return;
now = (unsigned long)hal_os_up_time_ms(); bit = 1U << stage;
ql_rtos_task_sched_lock();
if (!voice.round || (round && round != voice.round) || (voice.seen & bit)) {
ql_rtos_task_sched_unlock(); return;
}
round = voice.round; voice.seen |= bit; voice.stamp[stage] = now;
since_start = now - voice.started; seen = voice.seen;
#define HAVE(s) ((seen & (1U << (s))) != 0)
if (stage == VOICE_FIRST_PCM && HAVE(VOICE_RECORD_STOP) && HAVE(VOICE_END_QUEUED) &&
HAVE(VOICE_TTS_START) && HAVE(VOICE_FIRST_URL) && HAVE(VOICE_DOWNLOAD_BEGIN) && HAVE(VOICE_DOWNLOAD_DONE)) {
total = now - voice.stamp[VOICE_RECORD_STOP];
tail = voice.stamp[VOICE_END_QUEUED] - voice.stamp[VOICE_RECORD_STOP];
server = voice.stamp[VOICE_TTS_START] - voice.stamp[VOICE_END_QUEUED];
wait_url = voice.stamp[VOICE_FIRST_URL] - voice.stamp[VOICE_TTS_START];
queue = voice.stamp[VOICE_DOWNLOAD_BEGIN] - voice.stamp[VOICE_FIRST_URL];
download = voice.stamp[VOICE_DOWNLOAD_DONE] - voice.stamp[VOICE_DOWNLOAD_BEGIN];
pcm = now - voice.stamp[VOICE_DOWNLOAD_DONE];
}
ql_rtos_task_sched_unlock();
printf("[现场诊断][%lu ms][对话#%u] %s;距录音开始=%lu ms\r\n", now, round, stages[stage], since_start);
/* Nonstandard server ordering is printed as events, never unsigned deltas. */
if (total && tail <= total && server <= total && wait_url <= total && queue <= total && download <= total && pcm <= total)
printf("[现场诊断][%lu ms][对话#%u][耗时汇总] 录音结束到首PCM=%lu ms;收尾入队=%lu 等TTS通知=%lu 等首URL=%lu 播放队列=%lu 下载=%lu 解码提交=%lu(均ms;含网络与服务端处理,尚未分离)\r\n",
now, round, total, tail, server, wait_url, queue, download, pcm);
#undef HAVE
}
void net_diag_voice_url(unsigned int round, const char *url)
{
int accepted = 0;
if (!net_diag_is_enabled() || !url) return;
ql_rtos_task_sched_lock();
if (round == voice.round && !voice.first_url[0] && strlen(url) < sizeof(voice.first_url)) {
strcpy(voice.first_url, url); accepted = 1;
}
ql_rtos_task_sched_unlock();
if (accepted) net_diag_voice_mark(round, VOICE_FIRST_URL);
}
unsigned int net_diag_audio_begin(const char *url)
{
unsigned int round = 0;
if (!net_diag_is_enabled() || !url) return 0;
ql_rtos_task_sched_lock();
if (voice.first_url[0] && strcmp(url, voice.first_url) == 0) round = voice.round;
ql_rtos_task_sched_unlock();
if (round) net_diag_voice_mark(round, VOICE_DOWNLOAD_BEGIN);
return round;
}
void net_diag_audio_done(unsigned int round, int bytes, int result)
{
if (!round || !net_diag_is_enabled()) return;
printf("[现场诊断][%lu ms][对话#%u][首段下载] 字节=%d 返回=%d\r\n",
(unsigned long)hal_os_up_time_ms(), round, bytes, result);
if (result >= 0 && bytes > 0) net_diag_voice_mark(round, VOICE_DOWNLOAD_DONE);
}
void net_diag_vad_stats(unsigned int frames, unsigned int speech, unsigned int peak)
{
unsigned int round;
if (!net_diag_is_enabled()) return;
ql_rtos_task_sched_lock(); round = voice.round; ql_rtos_task_sched_unlock();
printf("[现场诊断][%lu ms][对话#%u][语音检测] 总帧=%u 活跃录音帧=%u 首次确认前连续语音峰值=%u/20;帧长20ms\r\n",
(unsigned long)hal_os_up_time_ms(), round, frames, speech, peak);
}