初版
This commit is contained in:
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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)*/
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user