Files
AC707N/SDK/audio/jl_kws/jl_kws_audio.c
T
2025-12-03 11:12:34 +08:00

328 lines
9.0 KiB
C

#ifdef SUPPORT_MS_EXTENSIONS
#pragma bss_seg(".jl_kws_audio.data.bss")
#pragma data_seg(".jl_kws_audio.data")
#pragma const_seg(".jl_kws_audio.text.const")
#pragma code_seg(".jl_kws_audio.text")
#endif
#include "jl_kws_common.h"
#if TCFG_KWS_VOICE_RECOGNITION_ENABLE
#include "asm/audio_adc.h"
#include "circular_buf.h"
//===================================================//
// ADC buf配置 //
//===================================================//
#define ADC_DEMO_BUF_NUM 2
#define ADC_DEMO_IRQ_POINTS 256
#define ADC_DEMO_BUFS_SIZE (ADC_DEMO_BUF_NUM * ADC_DEMO_IRQ_POINTS)
#define KWS_CBUF_SIZE (ADC_DEMO_BUFS_SIZE * sizeof(s16))
//==============================================//
// KWS 数据来自外部输入(AEC)配置 //
//==============================================//
#ifdef CONFIG_EARPHONE_CASE_ENABLE
#define TCFG_JL_KWS_AUDIO_DATA_FROM_EXTERN 1 //配置为1, 不需要本地开MIC, 由AEC外部输入
#else
#define TCFG_JL_KWS_AUDIO_DATA_FROM_EXTERN 0 //配置为0, 需要本地开MIC
#endif /* #ifdef CONFIG_EARPHONE_CASE_ENABLE */
//==============================================//
// KWS RAM使用OVERLAY配置 //
//==============================================//
#define KWS_USE_OVERLAY_RAM_ENABLE 0
#define KWS_USE_OVERLAY_RAM_SIZE (35 * 1024)
#if KWS_USE_OVERLAY_RAM_ENABLE
static int kws_ram[KWS_USE_OVERLAY_RAM_SIZE / sizeof(int)] sec(.jl_kws_ram);
#endif /* #if KWS_USE_OVERLAY_RAM_ENABLE */
enum KWS_AUDIO_STATE {
KWS_AUDIO_STATE_IDLE = 0,
KWS_AUDIO_STATE_RUN,
KWS_AUDIO_STATE_STOP,
KWS_AUDIO_STATE_CLOSE,
};
struct kws_adc_mic {
struct audio_adc_output_hdl adc_output;
struct adc_mic_ch mic_ch;
s16 adc_buf[ADC_DEMO_BUFS_SIZE]; //align 4Bytes
};
struct jl_kws_audio {
u8 kws_audio_state;
OS_SEM rx_sem;
struct kws_adc_mic *kws_adc;
cbuffer_t kws_cbuf;
u32 cbuf[KWS_CBUF_SIZE / 4];
};
static struct jl_kws_audio *__kws_audio = NULL;
extern struct audio_adc_hdl adc_hdl;
static void kws_adc_mic_output(void *priv, s16 *data, int len)
{
int wlen = 0;
local_irq_disable();/*防止关闭kws时,kws任务和aec任务互相打断导致释放信号量错误死机的问题*/
if (__kws_audio == NULL) {
local_irq_enable();
return;
}
if (__kws_audio->kws_audio_state != KWS_AUDIO_STATE_RUN) {
local_irq_enable();
return;
}
/* kws_putchar('w'); */
wlen = cbuf_write(&(__kws_audio->kws_cbuf), data, len);
if (wlen < len) {
kws_info("kws cbuf full");
} else {
//kws_debug("wlen: %d", wlen);
}
os_sem_post(&(__kws_audio->rx_sem));
local_irq_enable();
}
static int jl_kws_adc_mic_open(void)
{
u16 mic_sr = 16000;
if (__kws_audio->kws_adc != NULL) {
return JL_KWS_ERR_AUDIO_MIC_STATE_ERR;
}
__kws_audio->kws_adc = zalloc(sizeof(struct kws_adc_mic));
kws_debug("struct kws_adc_mic = 0x%x", (u32)sizeof(struct kws_adc_mic));
if (__kws_audio->kws_adc == NULL) {
return JL_KWS_ERR_AUDIO_MIC_NO_BUF;
}
kws_debug("kws local open mic");
//audio_mic_pwr_ctl(MIC_PWR_ON);
#if 1 // use config file
extern void audio_adc_file_init(void);
extern int adc_file_mic_open(struct adc_mic_ch * mic, int ch);
audio_adc_file_init();
adc_file_mic_open(&(__kws_audio->kws_adc->mic_ch), TCFG_KWS_MIC_CHA_SELECT);
#else
u8 mic_gain = 10;
struct mic_open_param mic_param = {0};
mic_param.mic_mode = AUDIO_MIC_CAP_MODE;
mic_param.mic_ain_sel = AUDIO_MIC0_CH0;
mic_param.mic_bias_sel = AUDIO_MIC_BIAS_CH0;
mic_param.mic_bias_rsel = 4;
mic_param.mic_dcc = 8;
audio_adc_mic_open(&(__kws_audio->kws_adc->mic_ch), TCFG_KWS_MIC_CHA_SELECT, &adc_hdl, &mic_param);
audio_adc_mic_set_gain(&(__kws_audio->kws_adc->mic_ch), TCFG_KWS_MIC_CHA_SELECT, mic_gain);
/* audio_adc_mic_0dB_en(TCFG_KWS_MIC_CHA_SELECT, 1); */
#endif
/* audio_adc_mic_open(&(__kws_audio->kws_adc->mic_ch), AUDIO_ADC_MIC_CH, &adc_hdl); */
audio_adc_mic_set_sample_rate(&(__kws_audio->kws_adc->mic_ch), mic_sr);
/* audio_adc_mic_set_gain(&(__kws_audio->kws_adc->mic_ch), mic_gain); */
audio_adc_mic_set_buffs(&(__kws_audio->kws_adc->mic_ch), __kws_audio->kws_adc->adc_buf, ADC_DEMO_IRQ_POINTS * 2, ADC_DEMO_BUF_NUM);
__kws_audio->kws_adc->adc_output.handler = kws_adc_mic_output;
audio_adc_add_output_handler(&adc_hdl, &(__kws_audio->kws_adc->adc_output));
return JL_KWS_ERR_NONE;
}
static int kws_speech_recognition_local_mic_open(void)
{
jl_kws_adc_mic_open();
jl_kws_audio_start();
return 0;
}
//==========================================================//
// JL_KWS AUDIO API //
//==========================================================//
int jl_kws_audio_init(void)
{
int ret = JL_KWS_ERR_NONE;
if (__kws_audio != NULL) {
return JL_KWS_ERR_AUDIO_INIT_STATE_ERR;
}
__kws_audio = zalloc(sizeof(struct jl_kws_audio));
kws_debug("struct jl_kws_audio = 0x%x", (u32)sizeof(struct jl_kws_audio));
if (__kws_audio == NULL) {
return JL_KWS_ERR_AUDIO_MIC_NO_BUF;
}
os_sem_create(&(__kws_audio->rx_sem), 0);
cbuf_init(&(__kws_audio->kws_cbuf), __kws_audio->cbuf, KWS_CBUF_SIZE);
/* audio_codec_clock_set(AUDIO_KWS_MODE, AUDIO_CODING_MSBC, 0); */
return ret;
}
u8 kws_aec_get_state(void)
{
#if TCFG_JL_KWS_AUDIO_DATA_FROM_EXTERN
if (__kws_audio) {
//aec初始化, 查询是否进入kws模式, 这时有可能需要kws本身打开了mic,需要close
if (__kws_audio->kws_adc) {
kws_debug("kws free adc buf");
audio_adc_mic_close(&__kws_audio->kws_adc->mic_ch);
audio_adc_del_output_handler(&adc_hdl, &(__kws_audio->kws_adc->adc_output));
free(__kws_audio->kws_adc);
__kws_audio->kws_adc = NULL;
cbuf_clear(&(__kws_audio->kws_cbuf));
os_sem_set(&(__kws_audio->rx_sem), 0);
}
return 1;
} else {
return 0;
}
#else
return 0;
#endif /* #if TCFG_JL_KWS_AUDIO_DATA_FROM_EXTERN */
}
u8 kws_get_state(void)
{
return kws_aec_get_state();
}
u8 kws_is_running(void)
{
return (__kws_audio != NULL);
}
__attribute__((weak))
int audio_aec_update(u8 EnableBit)
{
return 0;
}
void kws_aec_data_output(void *priv, s16 *data, int len)
{
if (__kws_audio == NULL) {
return ;
}
if (__kws_audio->kws_adc) {
audio_adc_del_output_handler(&adc_hdl, &__kws_audio->kws_adc->adc_output);
kws_debug("kws free adc buf");
free(__kws_audio->kws_adc);
__kws_audio->kws_adc = NULL;
}
kws_adc_mic_output(priv, data, len);
}
int jl_kws_audio_get_data(void *buf, u32 len)
{
u32 data_len;
u32 rlen = 0;
if (__kws_audio == NULL) {
return 0;
}
data_len = cbuf_get_data_len(&(__kws_audio->kws_cbuf));
if (data_len >= len) {
cbuf_read(&(__kws_audio->kws_cbuf), buf, len);
rlen = len;
} else {
os_sem_set(&(__kws_audio->rx_sem), 0);
#if TCFG_JL_KWS_AUDIO_DATA_FROM_EXTERN
int ret = os_sem_pend(&(__kws_audio->rx_sem), 500);
if (ret == OS_TIMEOUT) {
kws_speech_recognition_local_mic_open();
}
#else
os_sem_pend(&(__kws_audio->rx_sem), 0);
#endif /* #if TCFG_JL_KWS_AUDIO_DATA_FROM_EXTERN */
}
return rlen;
}
int jl_kws_audio_start(void)
{
int ret = JL_KWS_ERR_NONE;
if (__kws_audio == NULL) {
return JL_KWS_ERR_AUDIO_MIC_STATE_ERR;
}
kws_debug("%s", __func__);
__kws_audio->kws_audio_state = KWS_AUDIO_STATE_RUN;
#if (TCFG_JL_KWS_AUDIO_DATA_FROM_EXTERN == 0)
ret = jl_kws_adc_mic_open();
if (ret != JL_KWS_ERR_NONE) {
return ret;
}
#endif /* #if TCFG_JL_KWS_AUDIO_DATA_FROM_EXTERN */
if (__kws_audio->kws_adc) {
audio_adc_mic_start(&(__kws_audio->kws_adc->mic_ch));
}
return ret;
}
void jl_kws_audio_stop(void)
{
if (__kws_audio) {
__kws_audio->kws_audio_state = KWS_AUDIO_STATE_STOP;
if (__kws_audio->kws_adc) {
audio_adc_mic_close(&__kws_audio->kws_adc->mic_ch);
audio_adc_del_output_handler(&adc_hdl, &(__kws_audio->kws_adc->adc_output));
free(__kws_audio->kws_adc);
__kws_audio->kws_adc = NULL;
}
cbuf_clear(&(__kws_audio->kws_cbuf));
os_sem_set(&(__kws_audio->rx_sem), 0);
}
}
void jl_kws_audio_close(void)
{
kws_debug("%s", __func__);
if (__kws_audio) {
__kws_audio->kws_audio_state = KWS_AUDIO_STATE_CLOSE;
if (__kws_audio->kws_adc) {
audio_adc_mic_close(&__kws_audio->kws_adc->mic_ch);
audio_adc_del_output_handler(&adc_hdl, &(__kws_audio->kws_adc->adc_output));
free(__kws_audio->kws_adc);
__kws_audio->kws_adc = NULL;
}
/* audio_codec_clock_del(AUDIO_KWS_MODE); */
extern u8 audio_aec_status(void);
if (audio_aec_status()) {
audio_aec_update(0);
}
free(__kws_audio);
__kws_audio = NULL;
}
}
#endif /* #if TCFG_KWS_VOICE_RECOGNITION_ENABLE */