AC63_BT_SDK/apps/common/jl_kws/jl_kws_audio.c

305 lines
8.2 KiB
C
Raw Normal View History

2025-02-18 15:40:42 +08:00
#include "jl_kws_common.h"
#if TCFG_KWS_VOICE_RECOGNITION_ENABLE
#include "audio_enc.h"
#include "asm/audio_adc.h"
#include "audio_codec_clock.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;
u8 mic_gain = 10;
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);
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;
#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)
{
int ret = 0;
u32 data_len = 0;
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
ret = os_sem_pend(&(__kws_audio->rx_sem), 100);
if (ret == OS_TIMEOUT) {
kws_speech_recognition_local_mic_open();
}
#else
os_sem_pend(&(__kws_audio->rx_sem), portMAX_DELAY);
#endif /* #if TCFG_JL_KWS_AUDIO_DATA_FROM_EXTERN */
}
return rlen;
}
int jl_kws_audio_start(void)
{
int ret = JL_KWS_ERR_NONE;
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_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);
}
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 */