This commit is contained in:
huxi
2025-12-03 11:12:34 +08:00
parent c23ae4f24c
commit bc195654bf
8163 changed files with 3799544 additions and 92 deletions
+443
View File
@@ -0,0 +1,443 @@
#ifdef SUPPORT_MS_EXTENSIONS
#pragma bss_seg(".jl_kws_platform.data.bss")
#pragma data_seg(".jl_kws_platform.data")
#pragma const_seg(".jl_kws_platform.text.const")
#pragma code_seg(".jl_kws_platform.text")
#endif
/*****************************************************************
>file name : jl_asr.c
>create time : Sat 16 Apr 2022 09:46:07 AM CST
*****************************************************************/
#define LOG_TAG "[Smart-Voice]"
#define LOG_INFO_ENABLE
#define LOG_DEBUG_ENABLE
#define LOG_DUMP_ENABLE
#define LOG_ERROR_ENABLE
#define LOG_WARN_ENABLE
#include "smart_voice.h"
#include "debug.h"
#include "includes.h"
#include "voice_mic_data.h"
#include "kws_event.h"
#include "nn_vad.h"
#include "asr/jl_kws.h"
#include "clock_manager/clock_manager.h"
#if CONFIG_VAD_PLATFORM_SUPPORT_EN
#include "vad_mic.h"
#endif /*CONFIG_VAD_PLATFORM_SUPPORT_EN*/
#if ((defined TCFG_SMART_VOICE_ENABLE) && TCFG_SMART_VOICE_ENABLE && !TCFG_AUDIO_ASR_DEVELOP)
#define SMART_VOICE_TEST_LISTEN_SOUND 0
#define SMART_VOICE_TEST_PRINT_PCM 0
#define SMART_VOICE_TEST_WRITE_FILE 0
#define SMART_VOICE_DEBUG_KWS_RESULT 0
#define AUDIO_NN_VAD_ENABLE 0
/*
* Audio语音识别
*/
struct smart_voice_context {
u8 kws_model;
void *kws;
void *mic;
void *nn_vad;
#if SMART_VOICE_TEST_WRITE_FILE
void *file;
#endif
#if SMART_VOICE_DEBUG_KWS_RESULT
void *dump_hdl;
#endif
};
extern const int config_jl_audio_kws_enable;
#define SMART_VOICE_SAMPLE_RATE 16000
#define SMART_VOICE_REC_MIC_SECS 8
#define SMART_VOICE_REC_DATA_LEN (SMART_VOICE_SAMPLE_RATE * SMART_VOICE_REC_MIC_SECS * 2)
#define SMART_VOICE_KWS_FRAME_LEN (320)
#if SMART_VOICE_TEST_WRITE_FILE
#define VOICE_DATA_BUFFER_SIZE 16 * 1024
#elif SMART_VOICE_TEST_PRINT_PCM
#define VOICE_DATA_BUFFER_SIZE SMART_VOICE_REC_DATA_LEN
#else
#define VOICE_DATA_BUFFER_SIZE 2 * 1024
#endif
#if ((defined TCFG_AUDIO_DATA_EXPORT_ENABLE && TCFG_AUDIO_DATA_EXPORT_ENABLE) || SMART_VOICE_TEST_WRITE_FILE)
#define CONFIG_VAD_KWS_DETECT_ENABLE 0
#else
#define CONFIG_VAD_KWS_DETECT_ENABLE 1
#endif
static struct smart_voice_context *this_sv = NULL;
static u8 volatile smart_voice_wakeup = 0;
#if SMART_VOICE_TEST_LISTEN_SOUND
#include "audio_config.h"
extern struct audio_dac_hdl dac_hdl;
#endif
static inline void smart_voice_data_listen_sound(void *data, int len)
{
#if SMART_VOICE_TEST_LISTEN_SOUND
if (audio_dac_is_working(&dac_hdl)) {
audio_dac_write(&dac_hdl, data, len);
}
#endif
}
static inline void smart_voice_data_write_file(struct smart_voice_context *sv, void *data, int len)
{
#if SMART_VOICE_TEST_WRITE_FILE
if (sv->file) {
fwrite(data, len, 1, sv->file);
}
#endif
}
static void voice_mic_data_debug_stop(struct smart_voice_context *sv)
{
#if SMART_VOICE_TEST_PRINT_PCM
if (sv->mic) {
voice_mic_data_dump(sv->mic);
}
#endif
#if SMART_VOICE_TEST_WRITE_FILE
if (sv->file) {
fclose(sv->file);
sv->file = NULL;
}
#endif
}
static void voice_mic_data_debug_start(struct smart_voice_context *sv)
{
#if SMART_VOICE_TEST_WRITE_FILE
sv->file = fopen("storage/sd0/C/AudioVAD/vad***.raw", "w+");
if (!sv->file) {
printf("Open file failed, can not test.\n");
}
#endif
}
static void smart_voice_kws_close(struct smart_voice_context *sv)
{
#if AUDIO_NN_VAD_ENABLE
if (sv->nn_vad) {
audio_nn_vad_close(sv->nn_vad);
sv->nn_vad = NULL;
}
#else
if (sv->kws) {
audio_kws_close(sv->kws);
sv->kws = NULL;
}
#endif
}
static void smart_voice_kws_open(struct smart_voice_context *sv, u8 model)
{
#if AUDIO_NN_VAD_ENABLE
if (sv->nn_vad) {
return;
}
sv->nn_vad = audio_nn_vad_open();
#else
if (sv->kws) {
if (sv->kws_model == model) {
return;
}
smart_voice_kws_close(sv);
}
sv->kws_model = model;
sv->kws = audio_kws_open(model, NULL);//kws_model_files[model]);
#endif
}
/*
* 语音识别的KWS处理
*/
static int smart_voice_data_handler(struct smart_voice_context *sv)
{
if (!config_jl_audio_kws_enable) {
return 0;
}
#if SMART_VOICE_TEST_PRINT_PCM
putchar('*');
return 1;
#endif
if (!sv->mic) {
return -EINVAL;
}
s16 data[SMART_VOICE_KWS_FRAME_LEN / 2];
int rlen = voice_mic_data_read(sv->mic, data, SMART_VOICE_KWS_FRAME_LEN);
if (rlen < SMART_VOICE_KWS_FRAME_LEN) {
return -EINVAL;
}
if (sv->nn_vad) {
#if AUDIO_NN_VAD_ENABLE
audio_nn_vad_data_handler(sv->nn_vad, data, sizeof(data));
#endif
}
if (sv->kws) {
/*putchar('*');*/
smart_voice_data_listen_sound(data, sizeof(data));
smart_voice_data_write_file(sv, data, sizeof(data));
#if (CONFIG_VAD_KWS_DETECT_ENABLE)
int result = audio_kws_detect_handler(sv->kws, (void *)data, sizeof(data));
if (result > 1) {
printf("result : %d\n", result);
}
smart_voice_kws_event_handler(sv->kws_model, result);
#endif
#if SMART_VOICE_DEBUG_KWS_RESULT
smart_voice_kws_dump_result_add(sv->dump_hdl, sv->kws_model, result);
#endif
}
return 0;
}
int smart_voice_core_handler(void *priv, int taskq_type, int *msg)
{
int err = ASR_CORE_STANDBY;
struct smart_voice_context *sv = (struct smart_voice_context *)priv;
if (taskq_type == OS_TASKQ) {
switch (msg[0]) {
case SMART_VOICE_MSG_MIC_OPEN:
sv->mic = voice_mic_data_open(msg[1], msg[2], msg[3]);
if (!sv->mic) {
printf("VAD mic open failed.\n");
}
smart_voice_kws_open(sv, msg[4]);
break;
case SMART_VOICE_MSG_SWITCH_SOURCE:
if (sv->mic) {
voice_mic_data_clear(sv->mic);
voice_mic_data_switch_source(sv->mic, msg[1], msg[2], msg[3]);
}
smart_voice_kws_open(sv, msg[4]);
break;
case SMART_VOICE_MSG_MIC_CLOSE:
smart_voice_kws_close(sv);
voice_mic_data_close(sv->mic);
sv->mic = NULL;
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);
smart_voice_wakeup = 1;
break;
case SMART_VOICE_MSG_STANDBY:
smart_voice_wakeup = 0;
voice_mic_data_debug_stop(sv);
if (sv->mic) {
voice_mic_data_clear(sv->mic);
}
break;
case SMART_VOICE_MSG_DMA:
err = ASR_CORE_WAKEUP;
smart_voice_wakeup = 1;
/* msg[0] = (int)audio_codec_clock_check; */
/* msg[1] = 0; */
/* os_taskq_post_type("app_core", Q_CALLBACK, 2, msg); */
/*audio_codec_clock_check();*/
break;
}
}
if (smart_voice_wakeup) {
err = smart_voice_data_handler(sv);
err = err ? ASR_CORE_STANDBY : ASR_CORE_WAKEUP;
}
return err;
}
int audio_smart_voice_detect_create(u8 model, u8 mic, int buffer_size)
{
int err = 0;
// printf("audio_smart_voice_detect_create");
if (!config_jl_audio_kws_enable) {
return 0;
}
if (this_sv) {
smart_voice_core_post_msg(5, SMART_VOICE_MSG_SWITCH_SOURCE, mic, buffer_size, SMART_VOICE_SAMPLE_RATE, model);
return 0;
}
struct smart_voice_context *sv = (struct smart_voice_context *)zalloc(sizeof(struct smart_voice_context));
if (!sv) {
goto __err;
}
smart_voice_wakeup = 0;
err = smart_voice_core_create(sv);
if (err) {
goto __err;
}
clock_alloc("jl_kws", 90 * 1000000L);
smart_voice_core_post_msg(5, SMART_VOICE_MSG_MIC_OPEN, mic, buffer_size, SMART_VOICE_SAMPLE_RATE, model);
#if SMART_VOICE_DEBUG_KWS_RESULT
if (!sv->dump_hdl) {
sv->dump_hdl = smart_voice_kws_dump_open(2000);
}
#endif
this_sv = sv;
return 0;
__err:
if (sv) {
free(sv);
}
return err;
}
void audio_smart_voice_detect_close(void)
{
// printf("audio_smart_voice_detect_close");
if (config_jl_audio_kws_enable && this_sv) {
#if SMART_VOICE_DEBUG_KWS_RESULT
smart_voice_kws_dump_close(this_sv->dump_hdl);
#endif
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_sv);
this_sv = NULL;
clock_free("jl_kws");
}
}
static void __audio_smart_voice_detect_open(u8 mic, u8 model)
{
#if SMART_VOICE_TEST_WRITE_FILE
extern void force_set_sd_online(char *sdx);
force_set_sd_online("sd0");
void *mnt = mount("sd0", "storage/sd0", "fat", 3, NULL);
if (!mnt) {
printf("sd0 mount fat failed.\n");
}
#endif
audio_smart_voice_detect_create(model, mic, VOICE_DATA_BUFFER_SIZE);
}
void audio_smart_voice_detect_open(u8 model)
{
// printf("audio_smart_voice_detect_open ");
#if CONFIG_VAD_PLATFORM_SUPPORT_EN
return __audio_smart_voice_detect_open(model == JL_KWS_COMMAND_KEYWORD ? VOICE_VAD_MIC : VOICE_MCU_MIC, model);
#else
return __audio_smart_voice_detect_open(VOICE_MCU_MIC, model);
#endif /*CONFIG_VAD_PLATFORM_SUPPORT_EN*/
}
int audio_smart_voice_detect_init(void *vad_mic_data)
{
#if CONFIG_VAD_PLATFORM_SUPPORT_EN
u8 mic_type = VOICE_VAD_MIC;
lp_vad_mic_data_init((struct vad_mic_platform_data *)vad_mic_data);
#else
u8 mic_type = VOICE_MCU_MIC;
#endif /*CONFIG_VAD_PLATFORM_SUPPORT_EN*/
__audio_smart_voice_detect_open(mic_type, JL_KWS_COMMAND_KEYWORD);
return 0;
}
/*
* 来电KWS关键词识别
*/
int audio_phone_call_kws_start(void)
{
// printf("audio_phone_call_kws_start");
if (this_sv) {
/*通话语音识别,由LP VAD的MIC切到系统主MIC进行识别*/
smart_voice_core_post_msg(5, SMART_VOICE_MSG_SWITCH_SOURCE, VOICE_MCU_MIC, VOICE_DATA_BUFFER_SIZE, SMART_VOICE_SAMPLE_RATE, JL_KWS_CALL_KEYWORD);
return 0;
}
__audio_smart_voice_detect_open(VOICE_MCU_MIC, JL_KWS_CALL_KEYWORD);
return 0;
}
/*
* 来电KWS关闭(接通或拒接)
*/
int audio_phone_call_kws_close(void)
{
// printf("audio_phone_call_kws_close");
if (!this_sv) {
return 0;
}
/*通话语音识别结束后,由系统的主MIC切换回LP VAD的MIC源*/
#if CONFIG_VAD_PLATFORM_SUPPORT_EN
u8 mic_type = VOICE_VAD_MIC;
#else
u8 mic_type = VOICE_MCU_MIC;
#endif /*CONFIG_VAD_PLATFORM_SUPPORT_EN*/
smart_voice_core_post_msg(5, SMART_VOICE_MSG_SWITCH_SOURCE, mic_type, VOICE_DATA_BUFFER_SIZE, SMART_VOICE_SAMPLE_RATE, JL_KWS_COMMAND_KEYWORD);
return 0;
}
int audio_smart_voice_kws_get_model(void)
{
if (this_sv) {
return this_sv->kws_model;
}
return -1;
}
#if !TCFG_VAD_LP_CLOSE
static u8 smart_voice_idle_query(void)
{
return !smart_voice_wakeup;
}
static enum LOW_POWER_LEVEL smart_voice_level_query(void)
{
return LOW_POWER_MODE_DEEP_SLEEP;
}
REGISTER_LP_TARGET(smart_voice_lp_target) = {
.name = "smart_voice",
.level = smart_voice_level_query,
.is_idle = smart_voice_idle_query,
};
#endif
void audio_vad_test(void)
{
#if SMART_VOICE_TEST_LISTEN_SOUND
app_audio_state_switch(APP_AUDIO_STATE_MUSIC, get_max_sys_vol());
audio_dac_set_sample_rate(&dac_hdl, SMART_VOICE_SAMPLE_RATE);
audio_dac_set_volume(&dac_hdl, 15);
audio_dac_start(&dac_hdl);
audio_vad_m2p_event_post(M2P_VAD_CMD_TEST);
while (1) {
os_time_dly(10);
}
#endif
}
#endif
+229
View File
@@ -0,0 +1,229 @@
#ifdef SUPPORT_MS_EXTENSIONS
#pragma bss_seg(".kws_event.data.bss")
#pragma data_seg(".kws_event.data")
#pragma const_seg(".kws_event.text.const")
#pragma code_seg(".kws_event.text")
#endif
/*****************************************************************
>file name : kws_event.c
>author : lichao
>create time : Mon 01 Nov 2021 11:34:00 AM CST
*****************************************************************/
#include "app_config.h"
#include "system/includes.h"
#include "kws_event.h"
#include "asr/jl_kws.h"
#include "key/key_driver.h"
#include "app_msg.h"
#if ((defined TCFG_SMART_VOICE_ENABLE) && TCFG_SMART_VOICE_ENABLE)
extern int config_audio_kws_event_enable;
static const int kws_wake_word_event[] = {
KWS_EVENT_NULL,
KWS_EVENT_HEY_KEYWORD,
};
static const int kws_multi_command_event[] = {
[ 0] = KWS_EVENT_NULL,
[ 1] = KWS_EVENT_NULL,
[ 2] = KWS_EVENT_PLAY_MUSIC,
[ 3] = KWS_EVENT_PAUSE_MUSIC,
[ 4] = KWS_EVENT_STOP_MUSIC,
[ 5] = KWS_EVENT_VOLUME_UP,
[ 6] = KWS_EVENT_VOLUME_DOWN,
[ 7] = KWS_EVENT_PREV_SONG,
[ 8] = KWS_EVENT_NEXT_SONG,
[ 9] = KWS_EVENT_DETECTION_HEART,
[10] = KWS_EVENT_DETECTION_OXYGEN,
[11] = KWS_EVENT_SEE_SPORT_RECORD,
[12] = KWS_EVENT_SEE_ACTION_RECORD,
[13] = KWS_EVENT_SEE_SLEEP_RECORD,
[14] = KWS_EVENT_SEE_CALL_REDORD,
[15] = KWS_EVENT_SEE_TRAIN_RECORD,
[16] = KWS_EVENT_SEE_HEAT,
[17] = KWS_EVENT_START_PHOTOS,
[18] = KWS_EVENT_SWITCH_DIAL,
[19] = KWS_EVENT_SWITCH_STYLE,
[20] = KWS_EVENT_FIND_PHONE,
[21] = KWS_EVENT_VOLUME_MUTE,
[22] = KWS_EVENT_VOLUME_UNMUTE,
[23] = KWS_EVENT_VOLUME_MAX,
[24] = KWS_EVENT_BRIGHTNESS_ALWAYS,
[25] = KWS_EVENT_BRIGHTNESS_UP,
[26] = KWS_EVENT_BRIGHTNESS_DOWN,
[27] = KWS_EVENT_BRIGHTNESS_AUTO,
[28] = KWS_EVENT_OPEN_SPORT,
[29] = KWS_EVENT_OPEN_TRAIN,
[30] = KWS_EVENT_OPEN_CALCULAGRAPH,
[31] = KWS_EVENT_OPEN_CALL_DIAL,
[32] = KWS_EVENT_OPEN_PHONEBOOK,
[33] = KWS_EVENT_OPEN_ALARM,
[34] = KWS_EVENT_OPEN_STOPWATCH,
[35] = KWS_EVENT_OPEN_WEATHER,
[36] = KWS_EVENT_OPEN_MESS,
[37] = KWS_EVENT_OPEN_SET,
[38] = KWS_EVENT_OPEN_APP_LIST,
[39] = KWS_EVENT_OPEN_BREATH_TRAIN,
[40] = KWS_EVENT_OPEN_BARO,
[41] = KWS_EVENT_OPEN_COMPASS,
[42] = KWS_EVENT_OPEN_CARD_BAG,
[43] = KWS_EVENT_OPEN_ALIPAY,
[44] = KWS_EVENT_OPEN_FLASHLIGHT,
[45] = KWS_EVENT_OPEN_CALENDAR,
[46] = KWS_EVENT_OPEN_CALCULATOR,
[47] = KWS_EVENT_OPEN_EDR,
[48] = KWS_EVENT_CALL_ACTIVE,
[49] = KWS_EVENT_CALL_HANGUP,
};
static const int kws_call_command_event[] = {
KWS_EVENT_NULL,
KWS_EVENT_NULL,
KWS_EVENT_CALL_ACTIVE,
KWS_EVENT_CALL_HANGUP,
};
static const int *kws_model_events[3] = {
kws_wake_word_event,
kws_multi_command_event,
kws_call_command_event,
};
int smart_voice_kws_event_handler(u8 model, int kws)
{
if (!config_audio_kws_event_enable || kws < 0) {
return 0;
}
int event = KWS_EVENT_NULL;
if (model >= sizeof(kws_model_events) / sizeof(kws_model_events[0])) {
return -EINVAL;
}
event = kws_model_events[model][kws];
if (event == KWS_EVENT_NULL) {
return -EINVAL;
}
int msg[2];
msg[0] = APP_MSG_SMART_VOICE_EVENT;
msg[1] = event;
os_taskq_post_type("app_core", MSG_FROM_APP, 2, msg);
return 0;
}
static const char *kws_dump_words[] = {
[ 0] = "no words",
[ 1] = "hey siri",
[ 2] = "bo fang",
[ 3] = "zan ting",
[ 4] = "ting zhi",
[ 5] = "zeng da",
[ 6] = "jian xiao",
[ 7] = "shangyishou",
[ 8] = "xiayishou",
[ 9] = "xin lv",
[10] = "xue yang",
[11] = "duan lian ji lu",
[12] = "huo dong ji lu",
[13] = "shui mian shuo ju",
[14] = "tong hua ji lu",
[15] = "xun lian ji lu",
[16] = "ya li zhi biao",
[17] = "pai zhao",
[18] = "geng huan biao pan",
[19] = "jie mian feng ge",
[20] = "zhao shou ji",
[21] = "jing yin mo shi",
[22] = "qu xiao jing yin",
[23] = "zui da yin liang",
[24] = "ping mu chang liang",
[25] = "zeng da liang du",
[26] = "jain xiao liang du",
[27] = "tiao zheng liang du",
[28] = "yun dong",
[29] = "duan lian",
[30] = "ji shi qi",
[31] = "dian hua",
[32] = "lian xi ren",
[33] = "nao zhong",
[34] = "miao biao",
[35] = "tian qi",
[36] = "xiao xi",
[37] = "she zhi",
[38] = "ying yong lie biao",
[39] = "hu xi xun lian",
[40] = "hai bo qi ya ji",
[41] = "zhi nan zhen",
[42] = "ka bao",
[43] = "zhi fu bao",
[44] = "shou dian tong",
[45] = "ri li",
[46] = "ji suan qi",
[47] = "lan ya",
[48] = "jie ting",
[49] = "gua duan",
};
struct kws_result_context {
u16 timer;
u32 result[0];
};
static void smart_voice_kws_dump_timer(void *arg)
{
struct kws_result_context *ctx = (struct kws_result_context *)arg;
int i = 0;
int kws_num = ARRAY_SIZE(kws_dump_words);
printf("\n===============================================\nResults:\n");
for (i = 1; i < kws_num; i++) {
printf("%s : %u\n", kws_dump_words[i], ctx->result[i]);
}
printf("\n===============================================\n");
}
void *smart_voice_kws_dump_open(int period_time)
{
if (!config_audio_kws_event_enable) {
return NULL;
}
struct kws_result_context *ctx = NULL;
ctx = zalloc(sizeof(struct kws_result_context) + (sizeof(u32) * ARRAY_SIZE(kws_dump_words)));
if (ctx) {
ctx->timer = sys_timer_add(ctx, smart_voice_kws_dump_timer, period_time);
}
return ctx;
}
void smart_voice_kws_dump_result_add(void *_ctx, u8 model, int kws)
{
if (!config_audio_kws_event_enable || kws < 0) {
return;
}
struct kws_result_context *ctx = (struct kws_result_context *)_ctx;
int event = kws_model_events[model][kws];
if (event >= ARRAY_SIZE(kws_dump_words)) {
return;
}
ctx->result[event]++;
}
void smart_voice_kws_dump_close(void *_ctx)
{
struct kws_result_context *ctx = (struct kws_result_context *)_ctx;
if (config_audio_kws_event_enable) {
if (ctx->timer) {
sys_timer_del(ctx->timer);
free(ctx);
}
}
}
#endif
+21
View File
@@ -0,0 +1,21 @@
/*****************************************************************
>file name : kws_event.h
>author : lichao
>create time : Mon 01 Nov 2021 05:08:48 PM CST
*****************************************************************/
#ifndef _SMART_VOICE_KWS_EVENT_H_
#define _SMART_VOICE_KWS_EVENT_H_
#include "asr/kws_event.h"
int smart_voice_kws_event_handler(u8 model, int kws);
void *smart_voice_kws_dump_open(int period_time);
void smart_voice_kws_dump_result_add(void *_ctx, u8 model, int kws);
void smart_voice_kws_dump_close(void *_ctx);
#endif
+78
View File
@@ -0,0 +1,78 @@
#ifdef SUPPORT_MS_EXTENSIONS
#pragma bss_seg(".nn_vad.data.bss")
#pragma data_seg(".nn_vad.data")
#pragma const_seg(".nn_vad.text.const")
#pragma code_seg(".nn_vad.text")
#endif
/*****************************************************************
>file name : nn_vad.c
>create time : Thu 16 Dec 2021 07:19:26 PM CST
*****************************************************************/
#include "app_config.h"
#include "typedef.h"
#include "media/tech_lib/jlsp_vad.h"
#if ((defined TCFG_SMART_VOICE_ENABLE) && TCFG_SMART_VOICE_ENABLE)
struct audio_nn_vad_context {
void *algo;
u8 *share_buffer;
u8 algo_mem[0];
};
void *audio_nn_vad_open(void)
{
struct audio_nn_vad_context *ctx;
int model_size = 0;
int share_size = 10 * 1024;
int lib_heap_size = JLSP_vad_get_heap_size(NULL, &model_size);
ctx = (struct audio_nn_vad_context *)zalloc(sizeof(struct audio_nn_vad_context) + lib_heap_size + share_size);
if (!ctx) {
return NULL;
}
ctx->share_buffer = ctx->algo_mem + lib_heap_size;
ctx->algo = (void *)JLSP_vad_init((char *)ctx->algo_mem,
lib_heap_size,
(char *)ctx->share_buffer,
share_size,
NULL,
model_size);
if (!ctx->algo) {
goto err;
}
JLSP_vad_reset(ctx->algo);
return ctx;
err:
if (ctx) {
free(ctx);
}
return NULL;
}
int audio_nn_vad_data_handler(void *vad, void *data, int len)
{
struct audio_nn_vad_context *ctx = (struct audio_nn_vad_context *)vad;
int out_flag;
if (ctx) {
return JLSP_vad_process(ctx->algo, data, &out_flag);
}
return 0;
}
void audio_nn_vad_close(void *vad)
{
struct audio_nn_vad_context *ctx = (struct audio_nn_vad_context *)vad;
if (ctx->algo) {
JLSP_vad_free(ctx->algo);
}
free(ctx);
}
#endif
+15
View File
@@ -0,0 +1,15 @@
/*****************************************************************
>file name : nn_vad.h
>create time : Fri 17 Dec 2021 02:36:53 PM CST
*****************************************************************/
#ifndef _AUDIO_NN_VAD_H_
#define _AUDIO_NN_VAD_H_
void *audio_nn_vad_open(void);
int audio_nn_vad_data_handler(void *vad, void *data, int len);
void audio_nn_vad_close(void *vad);
#endif
+137
View File
@@ -0,0 +1,137 @@
/*****************************************************************
>file name : smart_voice.h
>create time : Thu 17 Jun 2021 02:07:32 PM CST
*****************************************************************/
#ifndef _SMART_VOICE_H_
#define _SMART_VOICE_H_
#include "media/includes.h"
#include "app_config.h"
#include "asm/audio_adc.h"
/*是否支持VAD唤醒*/
#define CONFIG_VAD_PLATFORM_SUPPORT_EN 0
#define ASR_CORE "audio_vad"
#define ASR_CORE_WAKEUP 0
#define ASR_CORE_STANDBY 1
#if (TCFG_AUDIO_KWS_LANGUAGE_SEL == KWS_CH)
#include "tech_lib/jlsp_kws.h"
#define audio_kws_model_get_heap_size jl_kws_model_get_heap_size
#define audio_kws_model_init jl_kws_model_init
#define audio_kws_model_reset jl_kws_model_reset
#define audio_kws_model_process jl_kws_model_process
#define audio_kws_model_free jl_kws_model_free
#elif (TCFG_AUDIO_KWS_LANGUAGE_SEL == KWS_FAR_CH)
#include "tech_lib/jlsp_far_keyword.h"
#define audio_kws_model_get_heap_size jl_far_kws_model_get_heap_size
#define audio_kws_model_init jl_far_kws_model_init
#define audio_kws_model_reset jl_far_kws_model_reset
#define audio_kws_model_process jl_far_kws_model_process
#define audio_kws_model_free jl_far_kws_model_free
#else
#include "tech_lib/jlsp_india_english.h"
#define audio_kws_model_get_heap_size jl_india_english_model_get_heap_size
#define audio_kws_model_init jl_india_english_model_init
#define audio_kws_model_reset jl_india_english_model_reset
#define audio_kws_model_process jl_india_english_model_process
#define audio_kws_model_free jl_india_english_model_free
#endif /*TCFG_AUDIO_KWS_LANGUAGE_SEL*/
enum {
SMART_VOICE_MSG_WAKE = 0, /*唤醒*/
SMART_VOICE_MSG_STANDBY, /*待机*/
SMART_VOICE_MSG_DMA, /*语音数据DMA传输*/
SMART_VOICE_MSG_MIC_OPEN, /*MIC打开*/
SMART_VOICE_MSG_SWITCH_SOURCE, /*MIC切换*/
SMART_VOICE_MSG_MIC_CLOSE, /*MIC关闭*/
};
/*
*********************************************************************
* audio smart voice detect create
* Description: 创建智能语音检测引擎
* Arguments : model - KWS模型
* task_name - VAD引擎task
* mic - MIC的选择(低功耗MIC或主控MIC)
* buffer_size - MIC的DMA数据缓冲大小
* Return : 0 - 创建成功,非0 - 失败.
* Note(s) : None.
*********************************************************************
*/
int audio_smart_voice_detect_create(u8 model, u8 mic, int buffer_size);
/*
*********************************************************************
* audio smart voice detect open
* Description: 智能语音检测打开接口
* Arguments : mic - MIC的选择(低功耗MIC或主控MIC)
* Return : void.
* Note(s) : None.
*********************************************************************
*/
void audio_smart_voice_detect_open(u8 mic);
/*
*********************************************************************
* audio smart voice detect close
* Description: 智能语音检测关闭接口
* Arguments : void.
* Return : void.
* Note(s) : 关闭引擎的所有资源(无论使用哪个mic).
*********************************************************************
*/
void audio_smart_voice_detect_close(void);
/*
*********************************************************************
* audio smart voice detect init
* Description: 智能语音检测配置初始化
* Arguments : mic_data - P11 mic初始化配置.
* Return : void.
* Note(s) : None.
*********************************************************************
*/
int audio_smart_voice_detect_init(void *vad_mic_data);
/*
*********************************************************************
* audio phone call kws start
* Description: 启动通话来电关键词识别
* Arguments : void.
* Return : 0 - 成功,非0 - 失败.
* Note(s) : 接口会将VAD的低功耗mic切换至通话使用的主控mic.
*********************************************************************
*/
int audio_phone_call_kws_start(void);
/*
*********************************************************************
* audio phone call kws close
* Description: 关闭通话来电关键词识别
* Arguments : void.
* Return : 0 - 成功,非0 - 出错.
* Note(s) : 关闭来电关键词识别,通常用于接通后或挂断/拒接后.
*********************************************************************
*/
int audio_phone_call_kws_close(void);
#define smart_voice_core_post_msg(num, ...) os_taskq_post_msg(ASR_CORE, num, __VA_ARGS__)
int smart_voice_core_create(void *priv);
int smart_voice_core_free(void);
int audio_smart_voice_kws_get_model(void);
int audio_smart_voice_check_status(void);
/*语音识别回音消除相关函数*/
void audio_smart_voice_aec_cbuf_data_clear();
int audio_smart_voice_aec_open(void);
void audio_smart_voice_aec_close(void);
#endif
@@ -0,0 +1,64 @@
#ifdef SUPPORT_MS_EXTENSIONS
#pragma bss_seg(".smart_voice_config.data.bss")
#pragma data_seg(".smart_voice_config.data")
#pragma const_seg(".smart_voice_config.text.const")
#pragma code_seg(".smart_voice_config.text")
#endif
/*****************************************************************
>file name : smart_voice_config.c
>author : lichao
>create time : Mon 01 Nov 2021 11:18:03 AM CST
*****************************************************************/
#include "app_config.h"
#include "typedef.h"
#include "smart_voice.h"
#include "asr/jl_kws.h"
#if ((defined TCFG_AUDIO_ASR_DEVELOP) && (TCFG_AUDIO_ASR_DEVELOP == ASR_CFG_AIS))
const int config_lp_vad_enable = CONFIG_VAD_PLATFORM_SUPPORT_EN;
const int config_jl_audio_kws_enable = 0;
const int config_aispeech_asr_enable = 1;
const int config_user_asr_enable = 0;
const int config_audio_kws_event_enable = 1;
#elif ((defined TCFG_AUDIO_ASR_DEVELOP) && (TCFG_AUDIO_ASR_DEVELOP == ASR_CFG_USER_DEFINED))
const int config_lp_vad_enable = CONFIG_VAD_PLATFORM_SUPPORT_EN;
const int config_jl_audio_kws_enable = 0;
const int config_aispeech_asr_enable = 0;
const int config_user_asr_enable = 1;
const int config_audio_kws_event_enable = 1;
#elif (TCFG_SMART_VOICE_ENABLE)
const int config_lp_vad_enable = CONFIG_VAD_PLATFORM_SUPPORT_EN;
const int config_jl_audio_kws_enable = 1; /*KWS 使能*/
const int config_aispeech_asr_enable = 0;
const int config_user_asr_enable = 0;
const int config_audio_kws_event_enable = 1;
#else
const int config_lp_vad_enable = 0;
const int config_jl_audio_kws_enable = 0;
const int config_aispeech_asr_enable = 0;
const int config_user_asr_enable = 0;
const int config_audio_kws_event_enable = 0;
#endif
const int config_audio_nn_vad_enable = 0;
static struct kws_multi_keyword_model kws_model_api = {
.mem_dump = audio_kws_model_get_heap_size,
.init = audio_kws_model_init,
.reset = audio_kws_model_reset,
.process = audio_kws_model_process,
.free = audio_kws_model_free,
};
void get_kws_api(struct kws_multi_keyword_model *api)
{
memcpy(api, &kws_model_api, sizeof(struct kws_multi_keyword_model));
}
/*重新封装远场语音识别库使用的系统函数接口*/
u32 sys_cfg_read_otp(u32 id, u8 *buf, u32 len)
{
extern u32 syscfg_read_otp(u32 id, u8 * buf, u32 len);
return syscfg_read_otp(id, buf, len);
}
+106
View File
@@ -0,0 +1,106 @@
#ifdef SUPPORT_MS_EXTENSIONS
#pragma bss_seg(".smart_voice_core.data.bss")
#pragma data_seg(".smart_voice_core.data")
#pragma const_seg(".smart_voice_core.text.const")
#pragma code_seg(".smart_voice_core.text")
#endif
/*****************************************************************
>file name : smart_voice_core.c
>author : lichao
>create time : Mon 01 Nov 2021 11:35:15 AM CST
*****************************************************************/
#include "app_config.h"
#if ((defined TCFG_SMART_VOICE_ENABLE) && TCFG_SMART_VOICE_ENABLE)
#include "smart_voice.h"
#include "includes.h"
#include "os/os_api.h"
#if CONFIG_VAD_PLATFORM_SUPPORT_EN
#include "vad_mic.h"
#endif /*CONFIG_VAD_PLATFORM_SUPPORT_EN*/
/*#include "jl_kws_platform.h"*/
/*#include "aispeech_platform.h"*/
/*#include "user_platform.h"*/
/*****************************************************************
* **算法平台接入说明**
*
* 1、TCFG_SMART_VOICE_ENABLE 为内置VAD+KWS关键词识别算法,默认在
* 非通话的模式下使用低功耗VAD MIC作为语音数据MIC。
*
* 2、根据宏定义TCFG_AUDIO_ASR_DEVELOP 选择对应的算法开发平台,在开
* 发框架上实现算法接入。
*
* 3、使用系统内置低功耗VAD作为语音数据MIC唤醒以及数据源需要实现
* 以下三个步骤:
* 1) 配置TCFG_VAD_LOWPOWER_CLOCK 时钟选择为 VAD_CLOCK_USE_PMU_STD12M
* 2) 调用lp_vad_mic_data_init()初始化VAD MIC配置
* 3) 调用voice_mic_data_open()时的数据源选择为VOICE_VAD_MIC
*
*****************************************************************/
extern const int config_jl_audio_kws_enable; /*KWS 使能*/
extern const int config_aispeech_asr_enable;
extern const int config_user_asr_enable;
extern const int config_lp_vad_enable;
extern int smart_voice_core_handler(void *priv, int taskq_type, int *msg);
extern int aispeech_asr_core_handler(void *priv, int taskq_type, int *msg);
extern int user_asr_core_handler(void *priv, int taskq_type, int *msg);
/*
* 智能唤醒和语音识别处理任务
*/
static void smart_voice_core_task(void *arg)
{
int msg[16];
int res;
u8 pend_taskq = 1;
int err;
/*struct smart_voice_context *sv = (struct smart_voice_context *)arg;*/
#if CONFIG_VAD_PLATFORM_SUPPORT_EN
if (config_lp_vad_enable) {
audio_vad_clock_trim();
}
#endif /*CONFIG_VAD_PLATFORM_SUPPORT_EN*/
while (1) {
if (pend_taskq) {
res = os_taskq_pend("taskq", msg, ARRAY_SIZE(msg));
} else {
res = os_taskq_accept(ARRAY_SIZE(msg), msg);
}
err = ASR_CORE_STANDBY;
if (config_jl_audio_kws_enable) {
err = smart_voice_core_handler(arg, res, &msg[1]);
}
if (config_aispeech_asr_enable) {
err = aispeech_asr_core_handler(arg, res, &msg[1]);
}
if (config_user_asr_enable) {
err = user_asr_core_handler(arg, res, &msg[1]);
}
pend_taskq = err ? 1 : 0;
}
}
int smart_voice_core_create(void *priv)
{
int err = task_create(smart_voice_core_task, priv, ASR_CORE);
if (err != OS_NO_ERR) {
return -EINVAL;
}
return 0;
}
int smart_voice_core_free(void)
{
task_kill(ASR_CORE);
return 0;
}
#endif /*((defined TCFG_SMART_VOICE_ENABLE) && TCFG_SMART_VOICE_ENABLE)*/
+317
View File
@@ -0,0 +1,317 @@
#ifdef SUPPORT_MS_EXTENSIONS
#pragma bss_seg(".user_asr.data.bss")
#pragma data_seg(".user_asr.data")
#pragma const_seg(".user_asr.text.const")
#pragma code_seg(".user_asr.text")
#endif
/*****************************************************************
>file name : user_asr.c
>create time : Thu 23 Dec 2021 10:00:58 AM CST
>用户自定义语音识别算法平台接入
*****************************************************************/
#include "app_config.h"
#include "system/includes.h"
#include "user_asr.h"
#include "smart_voice.h"
#include "voice_mic_data.h"
#if ((defined TCFG_AUDIO_ASR_DEVELOP) && (TCFG_AUDIO_ASR_DEVELOP == ASR_CFG_USER_DEFINED))
#define ASR_FRAME_SAMPLES 160 /*语音识别帧长(采样点)*/
/*debug调试*/
#define SMART_VOICE_TEST_PRINT_PCM 0
#define SMART_VOICE_TEST_WRITE_FILE 0
#define SMART_VOICE_SAMPLE_RATE 16000
#define SMART_VOICE_REC_MIC_SECS 2 /*记录声音时长*/
#define SMART_VOICE_REC_DATA_LEN (SMART_VOICE_SAMPLE_RATE * SMART_VOICE_REC_MIC_SECS * 2)
#if SMART_VOICE_TEST_WRITE_FILE
#define VOICE_DATA_BUFFER_SIZE 16 * 1024
#elif SMART_VOICE_TEST_PRINT_PCM
#define VOICE_DATA_BUFFER_SIZE SMART_VOICE_REC_DATA_LEN
#else
#define VOICE_DATA_BUFFER_SIZE 2 * 1024
#endif
struct user_platform_asr_context {
void *mic;
void *core;
u8 data_enable;
#if SMART_VOICE_TEST_WRITE_FILE
void *file;
#endif
};
extern const int config_user_asr_enable;
static struct user_platform_asr_context *__this = NULL;
static void user_voice_mic_data_debug_stop_handler(struct user_platform_asr_context *sv);
static inline void user_voice_data_write_file(struct user_platform_asr_context *asr, void *data, int len);
static void user_voice_mic_data_debug_start(struct user_platform_asr_context *asr);
/*
* 算法引擎打开函数
*/
static void *user_asr_core_open(int sample_rate)
{
return NULL;
}
/*
* 算法引擎关闭函数
*/
static void user_asr_core_close(void *core)
{
}
/*
* 算法引擎数据处理
*/
static int user_asr_core_data_handler(void *core, void *data, int len)
{
return 0;
}
/*
*********************************************************************
* user asr data handler
* Description: 用户算法平台平台语音识别数据处理
* Arguments : asr - 语音识别数据管理结构
* Return : 0 - 处理成功, 非0 - 处理失败.
* Note(s) : 该函数通过读取mic数据送入算法引擎完成语音帧.
*********************************************************************
*/
static int user_asr_data_handler(struct user_platform_asr_context *asr)
{
if (!asr->mic) {
return -EINVAL;
}
#if SMART_VOICE_TEST_PRINT_PCM
putchar('*');
return 1;
#endif
s16 data[ASR_FRAME_SAMPLES];
int len = voice_mic_data_read(asr->mic, data, sizeof(data));
if (len < sizeof(data)) {
return -EINVAL;
}
#if SMART_VOICE_TEST_WRITE_FILE
user_voice_data_write_file(asr, data, sizeof(data));
#else
if (asr->core) {
user_asr_core_data_handler(asr->core, data, sizeof(data));
}
#endif
return 0;
}
/*
*********************************************************************
* user_asr core handler
* Description: 用户自定义语音识别处理
* Arguments : priv - 语音识别私有数据
* taskq_type - TASK消息类型
* msg - 消息存储指针(对应自身模块post的消息)
* Return : None.
* Note(s) : 音频平台资源控制以及ASR主要识别算法引擎.
*********************************************************************
*/
int user_asr_core_handler(void *priv, int taskq_type, int *msg)
{
struct user_platform_asr_context *asr = (struct user_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的数据总缓冲长度*/
asr->mic = voice_mic_data_open(msg[1], msg[2], msg[3]);
if (!asr->mic) {
printf("asr mic open failed.\n");
}
asr->core = user_asr_core_open(msg[2]);
asr->data_enable = 1;
err = ASR_CORE_WAKEUP;
break;
case SMART_VOICE_MSG_SWITCH_SOURCE:
/*这里进行MIC的数据源切换 (主系统MIC或VAD MIC*/
break;
case SMART_VOICE_MSG_WAKE:
err = ASR_CORE_WAKEUP;
putchar('W');
user_voice_mic_data_debug_start(asr);
asr->data_enable = 1;
break;
case SMART_VOICE_MSG_STANDBY:
asr->data_enable = 0;
user_voice_mic_data_debug_stop_handler(asr);
if (asr->mic) {
voice_mic_data_clear(asr->mic);
}
break;
case SMART_VOICE_MSG_MIC_CLOSE: /*语音识别关闭 - MIC关闭,算法引擎关闭*/
asr->data_enable = 0;
/* msg[2] - 信号量*/
voice_mic_data_close(asr->mic);
asr->mic = NULL;
user_asr_core_close(asr->core);
asr->core = NULL;
asr->data_enable = 0;
os_sem_post((OS_SEM *)msg[1]);
break;
case SMART_VOICE_MSG_DMA: /*MIC通路数据DMA消息*/
asr->data_enable = 1;
err = ASR_CORE_WAKEUP;
break;
default:
break;
}
if (asr->data_enable) {
err = user_asr_data_handler(asr);
err = err ? ASR_CORE_STANDBY : ASR_CORE_WAKEUP;
}
return err;
}
int user_platform_asr_open(void)
{
if (!config_user_asr_enable) {
return 0;
}
int err = 0;
struct user_platform_asr_context *asr = (struct user_platform_asr_context *)zalloc(sizeof(struct user_platform_asr_context));
if (!asr) {
return -ENOMEM;
}
err = smart_voice_core_create(asr);
if (err != OS_NO_ERR) {
goto __err;
}
#if SMART_VOICE_TEST_WRITE_FILE
extern void force_set_sd_online(char *sdx);
force_set_sd_online("sd0");
void *mnt = mount("sd0", "storage/sd0", "fat", 3, NULL);
if (!mnt) {
printf("sd0 mount fat failed.\n");
goto __err;
}
#endif
/*
* 推送MIC的资源打开到语音识别主任务
* V1.1.0版本支持了低功耗VAD MIC的使用,需要可以改为VAD MIC
*
*/
smart_voice_core_post_msg(4, SMART_VOICE_MSG_MIC_OPEN, VOICE_MCU_MIC, VOICE_DATA_BUFFER_SIZE, SMART_VOICE_SAMPLE_RATE);
__this = asr;
return 0;
__err:
if (asr) {
free(asr);
}
return err;
}
void user_platform_asr_close(void)
{
if (!config_user_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;
}
}
void user_voice_mic_data_debug_stop(void)
{
smart_voice_core_post_msg(1, SMART_VOICE_MSG_STANDBY);
}
static void user_voice_mic_data_debug_stop_handler(struct user_platform_asr_context *asr)
{
#if SMART_VOICE_TEST_PRINT_PCM
if (asr->mic) {
voice_mic_data_dump(asr->mic);
}
#endif
#if SMART_VOICE_TEST_WRITE_FILE
if (asr->file) {
fclose(asr->file);
asr->file = NULL;
}
#endif
}
static inline void user_voice_data_write_file(struct user_platform_asr_context *asr, void *data, int len)
{
#if SMART_VOICE_TEST_WRITE_FILE
if (asr->file) {
int ret = fwrite(data, len, 1, asr->file);
if (ret <= 0) {
printf("%s write error!!!", __func__);
}
}
#endif
}
static void user_voice_mic_data_debug_start(struct user_platform_asr_context *asr)
{
#if SMART_VOICE_TEST_WRITE_FILE
asr->file = fopen("storage/sd0/C/AudioVAD/vad***.raw", "w+");
if (!asr->file) {
printf("Open file failed, can not test.\n");
}
#endif
}
static u8 user_asr_idle_query(void)
{
if (__this) {
return !__this->data_enable;
} else {
return 1;
}
}
REGISTER_LP_TARGET(user_asr_lp_target) = {
.name = "smart_voice",
.is_idle = user_asr_idle_query,
};
int audio_smart_voice_check_status(void)
{
return (__this ? true : false);
}
#endif
+15
View File
@@ -0,0 +1,15 @@
/*****************************************************************
>file name : user_asr.h
>create time : Thu 23 Dec 2021 11:53:40 AM CST
*****************************************************************/
#ifndef _USER_ASR_H_
#define _USER_ASR_H_
int user_platform_asr_open(void);
void user_platform_asr_close(void);
int user_asr_core_handler(void *priv, int taskq_type, int *msg);
#endif
+678
View File
@@ -0,0 +1,678 @@
#ifdef SUPPORT_MS_EXTENSIONS
#pragma bss_seg(".voice_mic_data.data.bss")
#pragma data_seg(".voice_mic_data.data")
#pragma const_seg(".voice_mic_data.text.const")
#pragma code_seg(".voice_mic_data.text")
#endif
/*****************************************************************
>file name : voice_mic_data.c
>author : lichao
>create time : Mon 01 Nov 2021 11:33:32 AM CST
*****************************************************************/
#include "app_config.h"
#include "voice_mic_data.h"
#include "smart_voice.h"
#include "app_main.h"
#include "adc_file.h"
#include "aec_uart_debug.h"
#include "effects/convert_data.h"
#include "circular_buf.h"
#include "media/audio_general.h"
#include "audio_splicing.h"
#if TCFG_AUDIO_ANC_ENABLE
#include "audio_anc.h"
#endif /*TCFG_AUDIO_ANC_ENABLE*/
#if CONFIG_VAD_PLATFORM_SUPPORT_EN
#include "vad_mic.h"
#endif /*CONFIG_VAD_PLATFORM_SUPPORT_EN*/
#if TCFG_SMART_VOICE_USE_AEC
#include "audio_cvp.h"
#include "overlay_code.h"
#endif
#if ((defined TCFG_SMART_VOICE_ENABLE) && TCFG_SMART_VOICE_ENABLE)
extern struct audio_adc_hdl adc_hdl;
#define CONFIG_VOICE_MIC_DATA_DUMP 0
#define CONFIG_VOICE_MIC_DATA_EXPORT 0
#define MAIN_ADC_GAIN 8
#define MAIN_ADC_BUF_NUM 3
struct main_adc_context {
struct audio_adc_output_hdl dma_output;
struct adc_mic_ch mic_ch;
s16 *dma_buf;
s16 *mic_sample_data;
u8 adc_ch_num; //打开的adc ch数量
u8 adc_seq; //记录当前用的那个mic
u8 bit_width;
};
/*
* Mic 数据接收buffer(循环buffer,动态大小)
*/
struct voice_mic_data {
u8 open;
u8 source;
struct main_adc_context *main_adc;
void *vad_mic;
struct list_head head;
cbuffer_t cbuf;
u8 buf[0];
};
struct voice_mic_capture_channel {
void *priv;
void (*output)(void *priv, s16 *data, int len);
struct list_head entry;
};
static struct voice_mic_data *voice_handle = NULL;
extern const u8 const_adc_async_en;
#define __this (voice_handle)
#if CONFIG_VOICE_MIC_DATA_DUMP
static u8 mic_data_dump = 0;
#endif
int audio_smart_voice_aec_run(void *priv, s16 *data, int len);
#if TCFG_SMART_VOICE_USE_AEC
struct voice_aec_hdl_t {
cbuffer_t aec_cbuf;
u8 aec_data_buf[640 * 3];
u8 in_tmpbuf[3][512];
u8 *ref_tmpbuf;
int ref_tmpbuf_len;
int last_data_len;
u8 bit_width;
u8 ref_channel;
};
static struct voice_aec_hdl_t *voice_aec_hdl = NULL;
extern int audio_dac_read_reset(void);
extern int audio_dac_read(s16 points_offset, void *data, int len, u8 read_channel);
extern int a2dp_player_runing();
void audio_smart_voice_aec_cbuf_data_clear()
{
if (voice_aec_hdl) {
cbuf_clear(&voice_aec_hdl->aec_cbuf);
audio_dac_read_reset();
}
}
static int audio_smart_voice_aec_run(void *priv, s16 *data, int len)
{
if (a2dp_player_runing() && voice_aec_hdl) {
#if CONFIG_VAD_PLATFORM_SUPPORT_EN
/*vad 刚起来时,会把缓存的4包数据一起推出来,需要等数据稳定320byte后再做回音消除*/
if (len != voice_aec_hdl->last_data_len) {
audio_dac_read_reset();
voice_aec_hdl->last_data_len = len;
return 0;
}
voice_aec_hdl->last_data_len = len;
#endif
int wlen = 0;
wlen = cbuf_write(&voice_aec_hdl->aec_cbuf, data, len);
if (wlen != len) {
putchar('a');
}
int dac_read_len;
if (voice_aec_hdl->bit_width == ADC_BIT_WIDTH_16) {
dac_read_len = len * 1 * voice_aec_hdl->ref_channel * 3;
audio_dac_read(0, voice_aec_hdl->ref_tmpbuf, dac_read_len / voice_aec_hdl->ref_channel, voice_aec_hdl->ref_channel);
if (voice_aec_hdl->ref_channel == 2) {
pcm_dual_to_single(voice_aec_hdl->ref_tmpbuf, voice_aec_hdl->ref_tmpbuf, dac_read_len);
dac_read_len >>= 1;
}
audio_aec_refbuf((s16 *)voice_aec_hdl->ref_tmpbuf, NULL, dac_read_len);
} else {
dac_read_len = len * 2 * voice_aec_hdl->ref_channel * 3;
audio_dac_read(0, voice_aec_hdl->ref_tmpbuf, dac_read_len / voice_aec_hdl->ref_channel, voice_aec_hdl->ref_channel);
audio_convert_data_32bit_to_16bit_round((s32 *)voice_aec_hdl->ref_tmpbuf, (s16 *)voice_aec_hdl->ref_tmpbuf, dac_read_len / 4);
dac_read_len >>= 1;
if (voice_aec_hdl->ref_channel == 2) {
pcm_dual_to_single(voice_aec_hdl->ref_tmpbuf, voice_aec_hdl->ref_tmpbuf, dac_read_len);
dac_read_len >>= 1;
}
audio_aec_refbuf((s16 *)voice_aec_hdl->ref_tmpbuf, NULL, dac_read_len);
}
static u8 burk = 0;
if (cbuf_get_data_len(&voice_aec_hdl->aec_cbuf) >= 512) {
wlen = cbuf_read(&voice_aec_hdl->aec_cbuf, &(voice_aec_hdl->in_tmpbuf[burk][0]), 512);
audio_aec_inbuf((s16 *) & (voice_aec_hdl->in_tmpbuf[burk][0]), wlen);
burk++;
if (burk > 2) {
burk = 0;
}
/* printf("wlen : %d", wlen); */
} else {
//printf("data_len : %d", cbuf_get_data_len(&__this->aec_cbuf));
}
return len;
} else {
return 0;
}
}
/*清晰语音数据输出*/
static int cvp_output_hdl(s16 *data, u16 len)
{
struct voice_mic_data *voice = (struct voice_mic_data *)__this;
struct voice_mic_capture_channel *ch;
list_for_each_entry(ch, &voice->head, entry) {
if (ch->output) {
ch->output(ch->priv, data, len);
}
}
int wlen = cbuf_write(&voice->cbuf, data, len);
if (wlen < len) {
putchar('D');
}
return wlen;
}
int audio_smart_voice_aec_open(void)
{
if (voice_aec_hdl) {
printf("voice_aec_hdl is alreadly open !!!");
return -1;
}
struct voice_aec_hdl_t *hdl = zalloc(sizeof(struct voice_aec_hdl_t));
if (hdl == NULL) {
printf("hdl malloc fail !!!");
return -1;
}
#if (TCFG_DAC_NODE_ENABLE && (TCFG_AUDIO_DAC_CONNECT_MODE == DAC_OUTPUT_LR))
hdl->ref_channel = 2;
#else
hdl->ref_channel = 1;
#endif
hdl->bit_width = audio_general_out_dev_bit_width();
printf("hdl->bit_width %d", hdl->bit_width);
if (hdl->bit_width == DATA_BIT_WIDE_16BIT) {
hdl->ref_tmpbuf_len = VOICE_MIC_DATA_PERIOD_FRAMES * sizeof(short) * hdl->ref_channel * 3;
} else {
hdl->ref_tmpbuf_len = VOICE_MIC_DATA_PERIOD_FRAMES * sizeof(int) * hdl->ref_channel * 3;
}
hdl->ref_tmpbuf = zalloc(hdl->ref_tmpbuf_len);
cbuf_init(&hdl->aec_cbuf, hdl->aec_data_buf, sizeof(hdl->aec_data_buf));
struct audio_aec_init_param_t init_param = {
.sample_rate = VOICE_ADC_SAMPLE_RATE,
.ref_sr = TCFG_AUDIO_GLOBAL_SAMPLE_RATE,
};
audio_aec_open(&init_param, AEC_EN, cvp_output_hdl);
audio_dac_read_reset();
voice_aec_hdl = hdl;
return 0;
}
void audio_smart_voice_aec_close(void)
{
if (voice_aec_hdl) {
audio_aec_close();
free(voice_aec_hdl->ref_tmpbuf);
free(voice_aec_hdl);
voice_aec_hdl = NULL;
}
}
#endif // TCFG_SMART_VOICE_USE_AEC
static int voice_mic_data_output(void *priv, s16 *data, int len)
{
struct voice_mic_data *voice = (struct voice_mic_data *)priv;
int wlen = 0;
#if TCFG_SMART_VOICE_USE_AEC
wlen = audio_smart_voice_aec_run(priv, data, len);
if (wlen) {
return wlen;
} else
#endif // TCFG_SMART_VOICE_USE_AEC
{
struct voice_mic_capture_channel *ch;
list_for_each_entry(ch, &voice->head, entry) {
if (ch->output) {
ch->output(ch->priv, data, len);
}
}
wlen = cbuf_write(&voice->cbuf, data, len);
if (wlen < len) {
putchar('D');
}
}
return wlen;
}
static void audio_main_adc_dma_data_handler(void *priv, s16 *data, int len)
{
struct voice_mic_data *voice = (struct voice_mic_data *)priv;
if (!voice || voice->source != VOICE_MCU_MIC) {
return;
}
s16 *pcm_data = NULL;
if (voice->main_adc->bit_width != ADC_BIT_WIDTH_16) {
s32 *s32_src = (s32 *)data;
s32 *s32_dst = (s32 *)voice->main_adc->mic_sample_data;
if (voice->main_adc->adc_ch_num > 1) {
for (int i = 0; i < len / 4; i++) {
s32_dst[i] = s32_src[i * voice->main_adc->adc_ch_num + voice->main_adc->adc_seq];
}
audio_convert_data_32bit_to_16bit_round(s32_dst, (s16 *)s32_dst, len / 4);
} else {
audio_convert_data_32bit_to_16bit_round(s32_src, (s16 *)s32_dst, len / 4);
}
pcm_data = (s16 *)s32_dst;
len >>= 1;
} else {
s16 *s16_src = (s16 *)data;
s16 *s16_dst = (s16 *)voice->main_adc->mic_sample_data;
if (voice->main_adc->adc_ch_num > 1) {
for (int i = 0; i < len / 2; i++) {
s16_dst[i] = s16_src[i * voice->main_adc->adc_ch_num + voice->main_adc->adc_seq];
}
pcm_data = (s16 *)s16_dst;
} else {
pcm_data = (s16 *)data;
}
}
/* putchar('M'); */
voice_mic_data_output(voice, pcm_data, len);
smart_voice_core_post_msg(1, SMART_VOICE_MSG_DMA);
}
#if TCFG_CALL_KWS_SWITCH_ENABLE
static void audio_main_adc_mic_close(struct voice_mic_data *voice, u8 all_channel);
static void audio_main_adc_suspend_handler(int all_channel, int arg)
{
OS_SEM *sem = (OS_SEM *)arg;
if (__this) {
audio_main_adc_mic_close(__this, all_channel);
}
os_sem_post(sem);
}
void audio_main_adc_suspend_in_core_task(u8 all_channel)
{
if (!__this || !__this->main_adc) {
return;
}
int argv[5];
OS_SEM *sem = malloc(sizeof(OS_SEM));
os_sem_create(sem, 0);
argv[0] = (int)audio_main_adc_suspend_handler;
argv[1] = 2;
argv[2] = all_channel;
argv[3] = (int)sem;
do {
int err = os_taskq_post_type(ASR_CORE, Q_CALLBACK, 4, argv);
if (err == OS_ERR_NONE) {
break;
}
if (err != OS_Q_FULL) {
audio_main_adc_suspend_handler(all_channel, (int)sem);
goto exit;
}
os_time_dly(2);
} while (1);
os_sem_pend(sem, 100);
exit:
free(sem);
}
void kws_aec_data_output(void *priv, s16 *data, int len)
{
if (!__this || __this->source != VOICE_MCU_MIC) {
return;
}
audio_main_adc_suspend_in_core_task(0);
voice_mic_data_output(__this, data, len);
smart_voice_core_post_msg(1, SMART_VOICE_MSG_DMA);
}
u8 kws_get_state(void)
{
if (!__this || __this->source != VOICE_MCU_MIC) {
return 0;
}
return 1;
}
void smart_voice_mcu_mic_suspend(void)
{
if (!__this || __this->source != VOICE_MCU_MIC) {
return;
}
//打开adc前, 如果kws本身打开了mic,需要close
audio_main_adc_suspend_in_core_task(1);
}
#endif
#define audio_main_adc_mic_ch_setup(ch, mic_ch, ch_map, adc_handle) \
if (ch_map & BIT(ch)) { \
audio_adc_mic##ch##_open(mic_ch, ch_map, adc_handle); \
}
static int audio_main_adc_mic_open(struct voice_mic_data *voice)
{
int ret = 0;
if (voice->main_adc) {
printf("audio main adc mic already open !!!");
return 0;
}
voice->main_adc = zalloc(sizeof(struct main_adc_context));
if (!voice->main_adc) {
return -ENOMEM;
}
#if TCFG_AUDIO_ANC_ENABLE && (!TCFG_AUDIO_DYNAMIC_ADC_GAIN)
/* MAIN_ADC_GAIN = anc_mic_gain_get(); */
#elif TCFG_AUDIO_ANC_ENABLE && TCFG_AUDIO_DYNAMIC_ADC_GAIN
anc_dynamic_micgain_start(MAIN_ADC_GAIN);
#endif/*TCFG_AUDIO_ANC_ENABLE && (!TCFG_AUDIO_DYNAMIC_ADC_GAIN)*/
if (const_adc_async_en) {
/*是否4个adc通道都打开,音箱使用*/
voice->main_adc->adc_ch_num = 4;
} else {
/*默认打开一个adc通道做语音识别,耳机使用*/
voice->main_adc->adc_ch_num = 1;
}
voice->main_adc->bit_width = adc_hdl.bit_width;
/*设置adc buf大小*/
int dma_len = 0;
if (voice->main_adc->bit_width == ADC_BIT_WIDTH_16) {
dma_len = VOICE_MIC_DATA_PERIOD_FRAMES * sizeof(short) * MAIN_ADC_BUF_NUM * voice->main_adc->adc_ch_num;
} else {
dma_len = VOICE_MIC_DATA_PERIOD_FRAMES * sizeof(int) * MAIN_ADC_BUF_NUM * voice->main_adc->adc_ch_num;
}
voice->main_adc->dma_buf = zalloc(dma_len);
printf("adc dma_len %d ", dma_len);
/*设置缓存buf大小*/
int buf_len = 0;
if (voice->main_adc->bit_width == ADC_BIT_WIDTH_16) {
if (voice->main_adc->adc_ch_num > 1) {
buf_len = VOICE_MIC_DATA_PERIOD_FRAMES * sizeof(short);
}
} else {
if (voice->main_adc->adc_ch_num > 1) {
buf_len = VOICE_MIC_DATA_PERIOD_FRAMES * sizeof(int);
} else {
buf_len = VOICE_MIC_DATA_PERIOD_FRAMES * sizeof(short);
}
}
printf("mic sample data len %d", buf_len);
if (buf_len) {
voice->main_adc->mic_sample_data = zalloc(buf_len);
}
/*配置使用哪个mic做语音识别*/
#ifdef TCFG_SMART_VOICE_MIC_CH_SEL
u8 ch = TCFG_SMART_VOICE_MIC_CH_SEL;
#else
u8 ch = AUDIO_ADC_MIC_0;
#endif
printf("%s:%d", __func__, ch);
audio_adc_file_init();
if (ch & AUDIO_ADC_MIC_0) {
adc_file_mic_open(&voice->main_adc->mic_ch, AUDIO_ADC_MIC_0);
audio_adc_mic_set_gain(&voice->main_adc->mic_ch, AUDIO_ADC_MIC_0, MAIN_ADC_GAIN);
}
if (ch & AUDIO_ADC_MIC_1) {
adc_file_mic_open(&voice->main_adc->mic_ch, AUDIO_ADC_MIC_1);
audio_adc_mic_set_gain(&voice->main_adc->mic_ch, AUDIO_ADC_MIC_1, MAIN_ADC_GAIN);
}
if (ch & AUDIO_ADC_MIC_2) {
adc_file_mic_open(&voice->main_adc->mic_ch, AUDIO_ADC_MIC_2);
audio_adc_mic_set_gain(&voice->main_adc->mic_ch, AUDIO_ADC_MIC_2, MAIN_ADC_GAIN);
}
if (ch & AUDIO_ADC_MIC_3) {
adc_file_mic_open(&voice->main_adc->mic_ch, AUDIO_ADC_MIC_3);
audio_adc_mic_set_gain(&voice->main_adc->mic_ch, AUDIO_ADC_MIC_3, MAIN_ADC_GAIN);
}
audio_adc_mic_set_sample_rate(&voice->main_adc->mic_ch, VOICE_ADC_SAMPLE_RATE);
ret = audio_adc_mic_set_buffs(&voice->main_adc->mic_ch, voice->main_adc->dma_buf,
VOICE_MIC_DATA_PERIOD_FRAMES * 2, MAIN_ADC_BUF_NUM);
if (ret && voice->main_adc->dma_buf) {
/*已经设置过buf了,并不需要在set buf*/
free(voice->main_adc->dma_buf);
voice->main_adc->dma_buf = NULL;
}
voice->main_adc->dma_output.priv = voice;
voice->main_adc->dma_output.handler = audio_main_adc_dma_data_handler;
audio_adc_add_output_handler(&adc_hdl, &voice->main_adc->dma_output);
audio_adc_mic_start(&voice->main_adc->mic_ch);
voice->main_adc->adc_seq = get_adc_seq(&adc_hdl, ch); //查询模拟mic对应的ADC通道,打开4个adc通道时使用
printf("adc_seq %d", voice->main_adc->adc_seq);
return 0;
}
static void audio_main_adc_mic_close(struct voice_mic_data *voice, u8 all_channel)
{
if (voice->main_adc) {
#if TCFG_AUDIO_ANC_ENABLE && TCFG_AUDIO_DYNAMIC_ADC_GAIN
anc_dynamic_micgain_stop();
#endif/*TCFG_AUDIO_ANC_ENABLE && TCFG_AUDIO_DYNAMIC_ADC_GAIN*/
if (all_channel) {
audio_adc_mic_close(&voice->main_adc->mic_ch);
}
audio_adc_del_output_handler(&adc_hdl, &voice->main_adc->dma_output);
if (voice->main_adc->dma_buf) {
/*mic close时会自动释放内存*/
/* free(voice->main_adc->dma_buf); */
voice->main_adc->dma_buf = NULL;
}
if (voice->main_adc->mic_sample_data) {
free(voice->main_adc->mic_sample_data);
voice->main_adc->mic_sample_data = NULL;
}
free(voice->main_adc);
voice->main_adc = NULL;
}
}
void *voice_mic_data_open(u8 source, int buffer_size, int sample_rate)
{
if (!__this) {
__this = zalloc(sizeof(struct voice_mic_data) + buffer_size);
}
if (!__this) {
return NULL;
}
if (__this->open) {
return __this;
}
cbuf_init(&__this->cbuf, __this->buf, buffer_size);
__this->source = source;
INIT_LIST_HEAD(&__this->head);
#if CONFIG_VOICE_MIC_DATA_EXPORT
aec_uart_open(1, VOICE_MIC_DATA_PERIOD_FRAMES * 2);
#endif
#if CONFIG_VAD_PLATFORM_SUPPORT_EN
if (source == VOICE_VAD_MIC) {
__this->vad_mic = lp_vad_mic_open((void *)__this, voice_mic_data_output);
} else if (source == VOICE_MCU_MIC)
#endif /*CONFIG_VAD_PLATFORM_SUPPORT_EN*/
{
audio_main_adc_mic_open(__this);
smart_voice_core_post_msg(1, SMART_VOICE_MSG_WAKE);
}
__this->open = 1;
return __this;
}
void voice_mic_data_close(void *mic)
{
struct voice_mic_data *voice = (struct voice_mic_data *)mic;
#if CONFIG_VAD_PLATFORM_SUPPORT_EN
if (voice->source == VOICE_VAD_MIC) {
lp_vad_mic_close(voice->vad_mic);
voice->vad_mic = NULL;
} else if (voice->source == VOICE_MCU_MIC)
#endif /*CONFIG_VAD_PLATFORM_SUPPORT_EN*/
{
audio_main_adc_mic_close(voice, 1);
smart_voice_core_post_msg(1, SMART_VOICE_MSG_STANDBY);
}
#if CONFIG_VOICE_MIC_DATA_EXPORT
aec_uart_close();
#endif
if (voice) {
free(voice);
}
__this = NULL;
}
void voice_mic_data_switch_source(void *mic, u8 source, int buffer_size, int sample_rate)
{
struct voice_mic_data *voice = (struct voice_mic_data *)mic;
voice->source = source;
if (voice->source == VOICE_VAD_MIC) {
audio_main_adc_mic_close(voice, 1);
#if CONFIG_VAD_PLATFORM_SUPPORT_EN
if (!voice->vad_mic) {
voice->vad_mic = lp_vad_mic_open(voice, voice_mic_data_output);
}
#endif /*CONFIG_VAD_PLATFORM_SUPPORT_EN*/
} else if (voice->source == VOICE_MCU_MIC) {
#if CONFIG_VAD_PLATFORM_SUPPORT_EN
if (voice->vad_mic) {
lp_vad_mic_close(voice->vad_mic);
voice->vad_mic = NULL;
}
#endif /*CONFIG_VAD_PLATFORM_SUPPORT_EN*/
audio_main_adc_mic_open(voice);
smart_voice_core_post_msg(1, SMART_VOICE_MSG_WAKE);
}
}
void *voice_mic_data_capture(int sample_rate, void *priv, void (*output)(void *priv, s16 *data, int len))
{
struct voice_mic_capture_channel *ch = (struct voice_mic_capture_channel *)zalloc(sizeof(struct voice_mic_capture_channel));
if (!ch) {
return NULL;
}
voice_mic_data_open(VOICE_VAD_MIC, 2048, sample_rate);
if (!__this) {
free(ch);
return NULL;
}
ch->priv = priv;
ch->output = output;
list_add(&ch->entry, &__this->head);
#if CONFIG_VAD_PLATFORM_SUPPORT_EN
lp_vad_mic_test();
#endif /*CONFIG_VAD_PLATFORM_SUPPORT_EN*/
return ch;
}
void voice_mic_data_stop_capture(void *mic)
{
struct voice_mic_capture_channel *ch = (struct voice_mic_capture_channel *)mic;
if (ch) {
list_del(&ch->entry);
free(ch);
}
if (list_empty(&__this->head)) {
#if CONFIG_VAD_PLATFORM_SUPPORT_EN
lp_vad_mic_test();
#endif /*CONFIG_VAD_PLATFORM_SUPPORT_EN*/
}
}
int voice_mic_data_read(void *mic, void *data, int len)
{
struct voice_mic_data *fb = (struct voice_mic_data *)mic;
/* printf("%s. %d, %d", __func__, len, cbuf_get_data_len(&fb->cbuf)); */
if (cbuf_get_data_len(&fb->cbuf) < len) {
return 0;
} else {
int wlen = cbuf_read(&fb->cbuf, data, len);
#if CONFIG_VOICE_MIC_DATA_EXPORT
aec_uart_fill(0, data, len);
aec_uart_write();
#endif
return wlen;
}
}
int voice_mic_data_buffered_samples(void *mic)
{
struct voice_mic_data *fb = (struct voice_mic_data *)mic;
return cbuf_get_data_len(&fb->cbuf) >> 1;
}
void voice_mic_data_clear(void *mic)
{
struct voice_mic_data *fb = (struct voice_mic_data *)mic;
cbuf_clear(&fb->cbuf);
}
void voice_mic_data_dump(void *mic)
{
struct voice_mic_data *fb = (struct voice_mic_data *)mic;
if (fb == NULL) {
return;
}
#if CONFIG_VOICE_MIC_DATA_DUMP
mic_data_dump = 1;
int len = 0;
int i = 0;
s16 *data = (s16 *)cbuf_read_alloc(&fb->cbuf, &len);
len >>= 1;
if (data) {
#if 0
for (i = 0; i < len; i++) {
if ((i % 3000) == 0) {
wdt_clear();
}
printf("%d\n", data[i]);
}
#else
put_buf(data, len << 1);
#endif
}
cbuf_read_updata(&fb->cbuf, len << 1);
mic_data_dump = 0;
#endif
}
#endif
+39
View File
@@ -0,0 +1,39 @@
/*****************************************************************
>file name : voice_mic_data.h
>author : lichao
>create time : Mon 01 Nov 2021 05:08:11 PM CST
*****************************************************************/
#ifndef _VOICE_MIC_DATA_H_
#define _VOICE_MIC_DATA_H_
#include "asm/audio_adc.h"
#define VOICE_VAD_MIC 0
#define VOICE_MCU_MIC 1
#define VOICE_DEFULT_MIC VOICE_VAD_MIC
#define VOICE_ADC_SAMPLE_RATE 16000
#define VOICE_ADC_SAMPLE_CH 1
#define VOICE_MIC_DATA_SAMPLE_PREIOD 10
#define VOICE_MIC_DATA_PERIOD_FRAMES (VOICE_MIC_DATA_SAMPLE_PREIOD * VOICE_ADC_SAMPLE_RATE / 1000)
void *voice_mic_data_open(u8 source, int buffer_size, int sample_rate);
void voice_mic_data_close(void *mic);
int voice_mic_data_read(void *mic, void *data, int len);
int voice_mic_data_buffered_samples(void *mic);
void voice_mic_data_clear(void *mic);
void voice_mic_data_dump(void *mic);
void *voice_mic_data_capture(int sample_rate, void *priv, void (*output)(void *priv, s16 *data, int len));
void voice_mic_data_stop_capture(void *mic);
void voice_mic_data_switch_source(void *mic, u8 source, int buffer_size, int sample_rate);
#endif