Files
99_7018_lmx/cpu/br28/smart_voice/aispeech_asr.c

639 lines
19 KiB
C
Raw Normal View History

2025-10-29 13:10:02 +08:00
/*****************************************************************
>file name : aispeech_asr.c
>create time : Thu 23 Dec 2021 10:00:58 AM CST
>
*****************************************************************/
#include "system/includes.h"
#include "aispeech_asr.h"
#include "smart_voice.h"
#include "voice_mic_data.h"
#include "key_event_deal.h"
#include "vad_mic.h"
#define ASR_FRAME_SAMPLES 160 /*语音识别帧长(采样点)*/
#define AISPEECH_ASR_SAMPLE_RATE 16000
struct ais_platform_asr_context {
void *mic;
void *core;
u8 data_enable;
};
extern const int config_aispeech_asr_enable;
static struct ais_platform_asr_context *__this = NULL;
#define ASR_CLK (160 * 1000000L) /*模块运行时钟(MaxFre:160MHz)*/
#ifdef AUDIO_PCM_DEBUG
//#define AISPEECH_ASR_AUDIO_DUMP
#endif /*AUDIO_PCM_DEBUG*/
#define AISPEECH_VAD_ASR_MODULE
#ifdef AISPEECH_VAD_ASR_MODULE
#include "vad_asr_demo.h"
#endif /*AISPEECH_VAD_ASR_MODULE*/
#if 1
#include "btstack/avctp_user.h"
#include "audio_anc.h"
#include "anc.h"
#endif
#define MIC_CAPTURE_BUF_SIZE (1024*10)
/*--------------------audio dump--------------------------------*/
#ifdef AISPEECH_ASR_AUDIO_DUMP
#include "cqueue.h"
OS_MUTEX catch_queue_amutex;
CQueue aec_uart_catch_queue;
u8 aec_uart_catch_buf[MIC_CAPTURE_BUF_SIZE];
extern int aec_uart_init();
extern int aec_uart_fill(u8 ch, void *buf, u16 size);
extern void aec_uart_write(void);
extern int aec_uart_close(void);
s16 gasr_exportbuf[256];
void audio_asr_export_demo_task(void *param)
{
int ret = 0;
int msg[16];
while (1) {
ret = os_taskq_pend(NULL, msg, ARRAY_SIZE(msg));
if (ret == OS_TASKQ) {
switch (msg[1]) {
case 0x01:
int rlen = 512;
while (LengthOfCQueue(&aec_uart_catch_queue) >= rlen) {
os_mutex_pend(&catch_queue_amutex, 0);
DeCQueue(&aec_uart_catch_queue, gasr_exportbuf, rlen);
os_mutex_post(&catch_queue_amutex);
/* for (int i = 0; i < 256; i++)
{
gasr_exportbuf[i] = i * 110 + 1;
} */
aec_uart_fill(0, gasr_exportbuf, rlen);
aec_uart_fill(1, gasr_exportbuf, rlen);
aec_uart_fill(2, gasr_exportbuf, rlen);
aec_uart_fill(3, gasr_exportbuf, rlen);
aec_uart_fill(4, gasr_exportbuf, rlen);
// putchar('W');
aec_uart_write();
}
break;
}
}
}
}
int audio_asr_export_demo_init()
{
int err = 0;
os_mutex_create(&catch_queue_amutex);
InitCQueue(&aec_uart_catch_queue, sizeof(aec_uart_catch_buf), (CQItemType *)aec_uart_catch_buf);
aec_uart_init();
task_create(audio_asr_export_demo_task, NULL, "audio_asr_export_task");
return err;
}
void audio_asr_export_demo_deinit()
{
aec_uart_close();
os_mutex_del(&catch_queue_amutex, 0);
task_kill("audio_asr_export_task");
}
#endif /*AISPEECH_ASR_AUDIO_DUMP*/
/*--------------------audio dump end-------------------------------*/
#ifdef AISPEECH_VAD_ASR_MODULE
#if 1
enum ais_asr_cmdid {
AIS_ASR_CMDID_NULL = 0,
/*Hey xxx系列关键词*/
AIS_ASR_CMDID_KEYWORD,
AIS_ASR_CMDID_PLAY_MUSIC, /*播放音乐*/
AIS_ASR_CMDID_STOP_MUSIC, /*停止播放*/
AIS_ASR_CMDID_PAUSE_MUSIC, /*暂停播放*/
AIS_ASR_CMDID_VOLUME_UP, /*增大音量*/
AIS_ASR_CMDID_VOLUME_DOWN, /*减小音量*/
AIS_ASR_CMDID_PREV_SONG, /*上一首*/
AIS_ASR_CMDID_NEXT_SONG, /*下一首*/
AIS_ASR_CMDID_CALL_ACTIVE, /*接听电话*/
AIS_ASR_CMDID_CALL_HANGUP, /*挂断电话*/
AIS_ASR_CMDID_ANC_OFF, /*关闭模式*/
AIS_ASR_CMDID_ANC_ON, /*降噪模式*/
AIS_ASR_CMDID_ANC_TRANSPARENCY, /*通透模式*/
/*TODO*/
AIS_ASR_CMDID_MAX,
};
typedef struct Input_CMD {
enum ais_asr_cmdid cmdid;
const char *cmd_str;
const char *at_cmd;
} Input_CMD_ST;
Input_CMD_ST global_asr_cmd[] = {
{ AIS_ASR_CMDID_KEYWORD, "xiao ting xiao ting", "AT+XEVENT=MAJORWAKEUP\r"},
{ AIS_ASR_CMDID_KEYWORD, "xiao jie tong xue", "AT+XEVENT=BIXINBIXIN\r"},
{ AIS_ASR_CMDID_STOP_MUSIC, "zan ting bo fang", "AT+XEVENT=ZANTINGBOFANG\r"},
{ AIS_ASR_CMDID_PLAY_MUSIC, "bo fang yin yue", "AT+XEVENT=BOFANGYINYUE\r"},
{ AIS_ASR_CMDID_PLAY_MUSIC, "ji xv bo fang", "AT+XEVENT=BOFANGYINYUE\r"},
{ AIS_ASR_CMDID_NEXT_SONG, "xia yi shou", "AT+XEVENT=XIAYISHOU\r"},
{ AIS_ASR_CMDID_PREV_SONG, "shang yi shou", "AT+XEVENT=SHANGYISHOU\r"},
{ AIS_ASR_CMDID_VOLUME_UP, "zeng da yin liang", "AT+XEVENT=ZENGDAYINLIANG\r"},
{ AIS_ASR_CMDID_VOLUME_UP, "yin liang da yi dian", "AT+XEVENT=ZENGDAYINLIANG\r"},
{ AIS_ASR_CMDID_VOLUME_DOWN, "jian xiao yin liang", "AT+XEVENT=JIANXIAOYINLIANG\r"},
{ AIS_ASR_CMDID_VOLUME_DOWN, "yin liang xiao yi dian", "AT+XEVENT=JIANXIAOYINLIANG\r"},
{ AIS_ASR_CMDID_CALL_ACTIVE, "jie ting dian hua", "AT+XEVENT=JIETINGDIANHUA\r"},
{ AIS_ASR_CMDID_CALL_HANGUP, "gua duan dian hua", "AT+XEVENT=GUADUANDIANHUA\r"},
{ AIS_ASR_CMDID_ANC_ON, "jiang zao mo shi", "AT+XEVENT=QUEDINGQUEDING\r"},
{ AIS_ASR_CMDID_ANC_TRANSPARENCY, "tong tou mo shi", "AT+XEVENT=QUEDINGQUEDING\r"},
{ AIS_ASR_CMDID_ANC_OFF, "guan bi jiang zao", "AT+XEVENT=QUXIAOQUXIAO\r"},
};
#endif
/*
*
*/
int aispeech_asr_output_handler(int status, const char *json, int bytes)
{
#if 1
u8 a2dp_state;
u8 call_state;
enum ais_asr_cmdid cmdid = AIS_ASR_CMDID_NULL;
char *cmdstr = strstr(json, "rec");
if (cmdstr != NULL) {
//printf("cmdstr: %s. \n", cmdstr+6);
cmdstr = cmdstr + 6;
for (int i = 0; i < (sizeof(global_asr_cmd) / sizeof(global_asr_cmd[0])); i++) {
if (memcmp(global_asr_cmd[i].cmd_str, cmdstr, strlen(global_asr_cmd[i].cmd_str)) == 0) {
cmdid = global_asr_cmd[i].cmdid;
int ret = user_send_at_cmd_prepare(global_asr_cmd[i].at_cmd, strlen(global_asr_cmd[i].at_cmd));
//printf("user_send_at_cmd_prepare :%s %d \n", global_asr_cmd[i].at_cmd, ret);
break;
}
}
}
printf("asr_post: %s. bytes:%d\n", json, bytes);
os_time_dly(1);
switch (cmdid) {
case AIS_ASR_CMDID_KEYWORD:
//主唤醒词:
printf("send SIRI cmd");
user_send_cmd_prepare(USER_CTRL_HFP_GET_SIRI_OPEN, 0, NULL);
break;
case AIS_ASR_CMDID_PLAY_MUSIC:
case AIS_ASR_CMDID_STOP_MUSIC:
case AIS_ASR_CMDID_PAUSE_MUSIC:
call_state = get_call_status();
if ((call_state == BT_CALL_OUTGOING) ||
(call_state == BT_CALL_ALERT)) {
//user_send_cmd_prepare(USER_CTRL_HFP_CALL_HANGUP, 0, NULL);
} else if (call_state == BT_CALL_INCOMING) {
//user_send_cmd_prepare(USER_CTRL_HFP_CALL_ANSWER, 0, NULL);
} else if (call_state == BT_CALL_ACTIVE) {
//user_send_cmd_prepare(USER_CTRL_HFP_CALL_HANGUP, 0, NULL);
} else {
a2dp_state = a2dp_get_status();
if (a2dp_state == BT_MUSIC_STATUS_STARTING) {
if (cmdid == AIS_ASR_CMDID_PAUSE_MUSIC) {
printf("send PAUSE cmd");
user_send_cmd_prepare(USER_CTRL_AVCTP_OPID_PAUSE, 0, NULL);
} else if (cmdid == AIS_ASR_CMDID_STOP_MUSIC) {
printf("send PLAY cmd to STOP");
user_send_cmd_prepare(USER_CTRL_AVCTP_OPID_PLAY, 0, NULL);
}
} else {
if (cmdid == AIS_ASR_CMDID_PLAY_MUSIC) {
printf("send PLAY cmd");
user_send_cmd_prepare(USER_CTRL_AVCTP_OPID_PLAY, 0, NULL);
}
}
}
break;
case AIS_ASR_CMDID_VOLUME_UP:
printf("volume up");
volume_up(4); //music: 0 ~ 16, call: 0 ~ 15, step: 25%
break;
case AIS_ASR_CMDID_VOLUME_DOWN:
printf("volume down");
volume_down(4); //music: 0 ~ 16, call: 0 ~ 15, step: 25%
break;
case AIS_ASR_CMDID_PREV_SONG:
printf("Send PREV cmd");
user_send_cmd_prepare(USER_CTRL_AVCTP_OPID_PREV, 0, NULL);
break;
case AIS_ASR_CMDID_NEXT_SONG:
printf("Send NEXT cmd");
user_send_cmd_prepare(USER_CTRL_AVCTP_OPID_NEXT, 0, NULL);
break;
case AIS_ASR_CMDID_CALL_ACTIVE:
if (get_call_status() == BT_CALL_INCOMING) {
printf("Send ANSWER cmd");
user_send_cmd_prepare(USER_CTRL_HFP_CALL_ANSWER, 0, NULL);
}
break;
case AIS_ASR_CMDID_CALL_HANGUP:
printf("Send HANG UP cmd");
if ((get_call_status() >= BT_CALL_INCOMING) && (get_call_status() <= BT_CALL_ALERT)) {
user_send_cmd_prepare(USER_CTRL_HFP_CALL_HANGUP, 0, NULL);
}
break;
case AIS_ASR_CMDID_ANC_OFF:
printf("Send ANC_OFF cmd");
#if TCFG_AUDIO_ANC_ENABLE
anc_mode_switch(ANC_OFF, 1);
#endif
break;
case AIS_ASR_CMDID_ANC_ON:
printf("Send ANC_ON cmd");
#if TCFG_AUDIO_ANC_ENABLE
anc_mode_switch(ANC_ON, 1);
#endif
break;
case AIS_ASR_CMDID_ANC_TRANSPARENCY:
printf("Send ANC_TRANSPARENCY cmd 11");
#if TCFG_AUDIO_ANC_ENABLE
anc_mode_switch(ANC_TRANSPARENCY, 1);
#endif
break;
case AIS_ASR_CMDID_NULL:
printf("KWS_EVENT_NULL");
break;
default:
break;
}
#endif
}
#endif
/*
*
*/
static void *aispeech_asr_core_open(int sample_rate)
{
printf("[%s-%d]-----start\n", __func__, __LINE__);
clk_set("sys", ASR_CLK);
printf("aip_asr----clk %d \n", ASR_CLK / 1000000);
mem_stats();
void *core = NULL;
#ifdef AISPEECH_VAD_ASR_MODULE
core = aispeech_vad_asr_init();
aispeech_asr_register_handler(aispeech_asr_output_handler);
#endif /*AISPEECH_VAD_ASR_MODULE*/
#ifdef AISPEECH_ASR_AUDIO_DUMP
audio_asr_export_demo_init();
#endif /*AISPEECH_ASR_AUDIO_DUMP*/
printf("[%s-%d]-----end\n", __func__, __LINE__);
return core;
}
/*
*
*/
static void aispeech_asr_core_close(void *core)
{
printf("[%s-%d]-----start\n", __func__, __LINE__);
#ifdef AISPEECH_VAD_ASR_MODULE
aispeech_vad_asr_deinit();
#endif /*AISPEECH_VAD_ASR_MODULE*/
#ifdef AISPEECH_ASR_AUDIO_DUMP
audio_asr_export_demo_deinit();
#endif /*AISPEECH_ASR_AUDIO_DUMP*/
printf("[%s-%d]-----end\n", __func__, __LINE__);
}
/*
*
*/
static u8 asr_maxcosttime = 0;
static u32 asr_meantime = 0;
static u8 asr_printcnt = 0;
static int aispeech_asr_core_data_handler(void *core, void *data, int len)
{
//printf("[%s-%d]-------len %d \n", __func__, __LINE__, len);
printf(".");
int cur_sys_clk = clk_get("sys");
if (cur_sys_clk < ASR_CLK) {
//printf("[%s-%d]------- %d M\n", __func__, __LINE__, cur_sys_clk/1000000);
clk_set("sys", ASR_CLK);
}
#ifdef AISPEECH_VAD_ASR_MODULE
unsigned long start = jiffies_msec();
aispeech_vad_asr_feed((char *)data, len);
unsigned long end = jiffies_msec();
u8 costtim = end - start;
if (costtim > asr_maxcosttime) {
asr_maxcosttime = costtim;
}
asr_meantime += costtim;
if ((++asr_printcnt) >= 200) {
printf("200 ais asr cost %d ms MAX %d \r\n", asr_meantime / asr_printcnt, asr_maxcosttime);
asr_printcnt = 0;
asr_meantime = 0;
}
#endif /*AISPEECH_VAD_ASR_MODULE*/
return 0;
}
/*
*********************************************************************
* aispeech asr data handler
* Description:
* Arguments : asr -
* Return : 0 - 0 - .
* Note(s) : mic数据送入算法引擎完成语音帧.
*********************************************************************
*/
static int aispeech_asr_data_handler(struct ais_platform_asr_context *asr)
{
int result = 0;
if (!asr->mic) {
return -EINVAL;
}
s16 data[ASR_FRAME_SAMPLES];
int len = voice_mic_data_read(asr->mic, data, sizeof(data));
if (len < sizeof(data)) {
return -EINVAL;
}
if (asr->core) {
result = aispeech_asr_core_data_handler(asr->core, data, sizeof(data));
} else {
printf("[%s-%d]---len %d \n", __func__, __LINE__, len);
}
#ifdef AISPEECH_ASR_AUDIO_DUMP
os_mutex_pend(&catch_queue_amutex, 0);
EnCQueue(&aec_uart_catch_queue, gasr_datatempbuf, rlen);
os_mutex_post(&catch_queue_amutex);
os_taskq_post_msg("audio_asr_export_task", 1, 0x01);
#endif /*AISPEECH_ASR_AUDIO_DUMP*/
#if 0 //def AISPEECH_ASR_AUDIO_DUMP
EnCQueue(&aec_uart_catch_queue, gasr_datatempbuf, rlen);
rlen = 512;
while (LengthOfCQueue(&aec_uart_catch_queue) >= rlen) {
DeCQueue(&aec_uart_catch_queue, gasr_datatempbuf, rlen);
/* for (int i = 0; i < 256; i++)
{
gasr_datatempbuf[i] = i * 110 + 1;
} */
aec_uart_fill(0, gasr_datatempbuf, rlen);
aec_uart_fill(1, gasr_datatempbuf, rlen);
aec_uart_fill(2, gasr_datatempbuf, rlen);
aec_uart_fill(3, gasr_datatempbuf, rlen);
aec_uart_fill(4, gasr_datatempbuf, rlen);
putchar('W');
aec_uart_write();
}
#endif
return 0;
}
/*
*********************************************************************
* aispeech_asr core handler
* Description:
* Arguments : priv -
* taskq_type - TASK消息类型
* msg - (post的消息)
* Return : None.
* Note(s) : ASR主要识别算法引擎.
*********************************************************************
*/
int aispeech_asr_core_handler(void *priv, int taskq_type, int *msg)
{
struct ais_platform_asr_context *asr = (struct ais_platform_asr_context *)priv;
int err = ASR_CORE_STANDBY;
if (taskq_type != OS_TASKQ) {
return err;
}
switch (msg[0]) {
case SMART_VOICE_MSG_MIC_OPEN: /*语音识别打开 - MIC打开算法引擎打开*/
/* msg[1] - MIC数据源msg[2] - 音频采样率msg[3] - mic的数据总缓冲长度*/
if (asr->data_enable == 0) {
asr->mic = voice_mic_data_open(msg[1], msg[2], msg[3]);
asr->core = aispeech_asr_core_open(msg[2]);
asr->data_enable = 1;
}
err = ASR_CORE_WAKEUP;
break;
case SMART_VOICE_MSG_SWITCH_SOURCE:
/*这里进行MIC的数据源切换 主系统MIC或VAD MIC*/
if (asr->mic) {
voice_mic_data_clear(asr->mic);
voice_mic_data_switch_source(asr->mic, msg[1], msg[2], msg[3]);
}
/* smart_voice_kws_open(sv, msg[4]); */
break;
case SMART_VOICE_MSG_MIC_CLOSE: /*语音识别关闭 - MIC关闭算法引擎关闭*/
/* msg[2] - 信号量*/
if (asr->data_enable == 1) {
voice_mic_data_close(asr->mic);
asr->mic = NULL;
aispeech_asr_core_close(asr->core);
asr->core = NULL;
asr->data_enable = 0;
}
os_sem_post((OS_SEM *)msg[1]);
break;
case SMART_VOICE_MSG_WAKE:
err = ASR_CORE_WAKEUP;
/*putchar('W');*/
/* voice_mic_data_debug_start(sv); */
asr->data_enable = 1;
break;
case SMART_VOICE_MSG_STANDBY:
asr->data_enable = 0;
if (asr->mic) {
voice_mic_data_clear(asr->mic);
}
/* voice_mic_data_debug_stop(sv); */
break;
case SMART_VOICE_MSG_DMA: /*MIC通路数据DMA消息*/
err = ASR_CORE_WAKEUP;
break;
default:
break;
}
if (asr->data_enable) {
err = aispeech_asr_data_handler(asr);
err = err ? ASR_CORE_STANDBY : ASR_CORE_WAKEUP;
}
return err;
}
int __ais_platform_asr_open(u8 mic)
{
if (!config_aispeech_asr_enable) {
return 0;
}
int err = 0;
if (__this) {
smart_voice_core_post_msg(4, SMART_VOICE_MSG_SWITCH_SOURCE, MIC_CAPTURE_BUF_SIZE, AISPEECH_ASR_SAMPLE_RATE, mic);
return 0;
}
struct ais_platform_asr_context *asr = (struct ais_platform_asr_context *)zalloc(sizeof(struct ais_platform_asr_context));
if (!asr) {
return -ENOMEM;
}
err = smart_voice_core_create(asr);
if (err != OS_NO_ERR) {
goto __err;
}
/*
* MIC的资源打开到语音识别主任务
* V1.1.0VAD MIC的使用VAD MIC
*
*/
smart_voice_core_post_msg(4, SMART_VOICE_MSG_MIC_OPEN, mic, AISPEECH_ASR_SAMPLE_RATE, MIC_CAPTURE_BUF_SIZE);
__this = asr;
return 0;
__err:
if (asr) {
free(asr);
}
return err;
}
int ais_platform_asr_open(void)
{
/* return __ais_platform_asr_open(VOICE_MCU_MIC); */
return __ais_platform_asr_open(VOICE_VAD_MIC);
}
void ais_platform_asr_close(void)
{
if (!config_aispeech_asr_enable) {
return;
}
if (__this) {
OS_SEM *sem = (OS_SEM *)malloc(sizeof(OS_SEM));
os_sem_create(sem, 0);
smart_voice_core_post_msg(2, SMART_VOICE_MSG_MIC_CLOSE, (int)sem);
os_sem_pend(sem, 0);
free(sem);
smart_voice_core_free();
free(__this);
__this = NULL;
}
}
int audio_ais_platform_asr_init(struct vad_mic_platform_data *mic_data)
{
lp_vad_mic_data_init(mic_data);
/* __ais_platform_asr_open(VOICE_MCU_MIC); */
__ais_platform_asr_open(VOICE_VAD_MIC);
return 0;
}
/*
* KWS关键词识别
*/
int audio_phone_call_aispeech_asr_start(void)
{
if (__this) {
/*通话语音识别由LP VAD的MIC切到系统主MIC进行识别*/
smart_voice_core_post_msg(4, SMART_VOICE_MSG_SWITCH_SOURCE, MIC_CAPTURE_BUF_SIZE, AISPEECH_ASR_SAMPLE_RATE, VOICE_MCU_MIC);
return 0;
}
__ais_platform_asr_open(VOICE_MCU_MIC);
return 0;
}
/*
* KWS关闭
*/
int audio_phone_call_aispeech_asr_close(void)
{
if (!__this) {
return 0;
}
/*通话语音识别结束后由系统的主MIC切换回LP VAD的MIC源*/
smart_voice_core_post_msg(4, SMART_VOICE_MSG_SWITCH_SOURCE, MIC_CAPTURE_BUF_SIZE, AISPEECH_ASR_SAMPLE_RATE, VOICE_VAD_MIC);
return 0;
}
static u8 aispeech_asr_core_idle_query()
{
if (__this) {
return !(__this->data_enable);
} else {
return 1;
}
}
REGISTER_LP_TARGET(aispeech_asr_core_lp_target) = {
.name = "aispeech_asr_core",
.is_idle = aispeech_asr_core_idle_query,
};