AC63_BT_SDK/apps/common/jl_kws/jl_kws_audio.c
2025-02-18 15:40:42 +08:00

305 lines
8.2 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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 */