Files
99_7018_lmx/cpu/br28/smart_voice/voice_mic_data.c
2025-10-29 13:10:02 +08:00

396 lines
10 KiB
C
Raw 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.

/*****************************************************************
>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 "vad_mic.h"
#include "app_main.h"
#include "audio_anc.h"
#if TCFG_AUDIO_ANC_ENABLE
#include "audio_anc.h"
#endif/*TCFG_AUDIO_ANC_ENABLE*/
extern struct audio_adc_hdl adc_hdl;
#define CONFIG_VOICE_MIC_DATA_DUMP 0
#define CONFIG_VOICE_MIC_DATA_EXPORT 0
#if CONFIG_VOICE_MIC_DATA_EXPORT
#include "aec_uart_debug.h"
#endif
#define MAIN_ADC_GAIN app_var.aec_mic_gain
#if TCFG_AUDIO_TRIPLE_MIC_ENABLE
#define MAIN_ADC_CH_NUM 3
#elif TCFG_AUDIO_DUAL_MIC_ENABLE
#define MAIN_ADC_CH_NUM 2
#else
#define MAIN_ADC_CH_NUM 1
#endif
extern s16 esco_adc_buf[];
struct main_adc_context {
struct audio_adc_output_hdl dma_output;
struct adc_mic_ch mic_ch;
/*s16 dma_buf[VOICE_MIC_DATA_PERIOD_FRAMES * 2 * MAIN_ADC_CH_NUM];*/
s16 *dma_buf;
#if (MAIN_ADC_CH_NUM > 1)
s16 mic0_sample_data[VOICE_MIC_DATA_PERIOD_FRAMES];
#endif /*MAIN_ADC_CH_NUM*/
};
/*
* 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;
#define __this (voice_handle)
#if CONFIG_VOICE_MIC_DATA_DUMP
static u8 mic_data_dump = 0;
#endif
static int voice_mic_data_output(void *priv, s16 *data, int len)
{
struct voice_mic_data *voice = (struct voice_mic_data *)priv;
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;
}
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 = data;
#if (MAIN_ADC_CH_NUM > 1)
pcm_data = voice->main_adc->mic0_sample_data;
int frames = len >> 1;
int i = 0;
for (i = 0; i < frames; i++) {
pcm_data[i] = data[i * MAIN_ADC_CH_NUM];
}
#endif
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);
}
static 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;
}
//aec初始化, 查询是否进入kws模式, 这时有可能需要kws本身打开了mic需要close
audio_main_adc_suspend_in_core_task(1);
return 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)
{
if (!voice->main_adc) {
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 = audio_anc_ffmic_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)*/
voice->main_adc->dma_buf = esco_adc_buf;
audio_adc_mic_open(&voice->main_adc->mic_ch, AUDIO_ADC_MIC_0, &adc_hdl);
audio_adc_mic_set_gain(&voice->main_adc->mic_ch, MAIN_ADC_GAIN);
#ifdef TCFG_AUDIO_ADC_MIC_CHA
audio_main_adc_mic_ch_setup(1, &voice->main_adc->mic_ch, TCFG_AUDIO_ADC_MIC_CHA, &adc_hdl);
audio_main_adc_mic_ch_setup(2, &voice->main_adc->mic_ch, TCFG_AUDIO_ADC_MIC_CHA, &adc_hdl);
audio_main_adc_mic_ch_setup(3, &voice->main_adc->mic_ch, TCFG_AUDIO_ADC_MIC_CHA, &adc_hdl);
#endif
audio_adc_mic_set_sample_rate(&voice->main_adc->mic_ch, 16000);
audio_adc_mic_set_buffs(&voice->main_adc->mic_ch, voice->main_adc->dma_buf,
VOICE_MIC_DATA_PERIOD_FRAMES * 2, 2);
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);
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);
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 (source == VOICE_VAD_MIC) {
__this->vad_mic = lp_vad_mic_open((void *)__this, voice_mic_data_output);
} else if (source == VOICE_MCU_MIC) {
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 (voice->source == VOICE_VAD_MIC) {
lp_vad_mic_close(voice->vad_mic);
voice->vad_mic = NULL;
} else if (voice->source == VOICE_MCU_MIC) {
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;
if (voice->source == source) {
return;
}
voice->source = source;
if (voice->source == VOICE_VAD_MIC) {
audio_main_adc_mic_close(voice, 1);
voice->vad_mic = lp_vad_mic_open(voice, voice_mic_data_output);
} else if (voice->source == VOICE_MCU_MIC) {
lp_vad_mic_close(voice->vad_mic);
voice->vad_mic = NULL;
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);
lp_vad_mic_test();
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)) {
lp_vad_mic_test();
}
}
int voice_mic_data_read(void *mic, void *data, int len)
{
struct voice_mic_data *fb = (struct voice_mic_data *)mic;
int wlen = 0;
if (cbuf_get_data_len(&fb->cbuf) < len) {
return 0;
} else {
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 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
}