Files
99_7018_lmx/apps/earphone/linein/linein.c

446 lines
14 KiB
C
Raw Normal View History

2025-10-29 13:10:02 +08:00
#include "system/includes.h"
#include "app_action.h"
#include "key_event_deal.h"
#include "bt_background.h"
#include "default_event_handler.h"
#include "tone_player.h"
#include "user_cfg.h"
#include "app_task.h"
#include "earphone.h"
#include "app_charge.h"
#include "app_power_manage.h"
#include "app_main.h"
#include "media/includes.h"
#include "audio_config.h"
#include "asm/audio_adc.h"
#include "circular_buf.h"
#include "audio_dec_pcm.h"
#define LOG_TAG_CONST AUX
#define LOG_TAG "[AUX]"
#define LOG_ERROR_ENABLE
#define LOG_DEBUG_ENABLE
#define LOG_INFO_ENABLE
/* #define LOG_DUMP_ENABLE */
#define LOG_CLI_ENABLE
#include "debug.h"
#include "log.h"
#if TCFG_APP_AUX_EN
#define POWER_OFF_CNT 6
extern void sys_enter_soft_poweroff(void *priv);
extern int app_power_event_handler(struct device_event *dev);
extern void app_task_switch_next(void);
extern struct audio_dac_hdl dac_hdl;
extern struct audio_adc_hdl adc_hdl;
#define AUX_CH_NUM 4 /*支持的最大采样通道(max = 2)*/
#define AUX_BUF_NUM 2 /*采样buf数*/
#define AUX_IRQ_POINTS 64 /*采样中断点数*/
#define AUX_BUFS_SIZE (AUX_CH_NUM * AUX_BUF_NUM * AUX_IRQ_POINTS)
#define AUX_CBUF_SIZE (AUX_BUFS_SIZE / 2)
struct linein_hdl {
u8 adc_2_dac;
u8 linein_idx;
struct audio_adc_output_hdl adc_output;
struct adc_mic_ch mic_ch;
struct adc_linein_ch linein_ch;
cbuffer_t linein_cbuf;
s16 adc_buf[AUX_BUFS_SIZE];
u8 *cbuf;
u8 linein_ch_num;
u8 linein_ch_sel;
u8 need_resume;
u8 start;
};
struct app_aux_var {
struct linein_hdl *linein_demo;
u8 inited;
u8 idle;
};
static u8 goto_poweroff_cnt = 0;
static u8 goto_poweroff_flag = 0;
static struct app_aux_var g_aux = {0};
static const u8 aux_key_table[][KEY_EVENT_MAX] = {
// SHORT LONG HOLD
// UP DOUBLE TRIPLE
{
KEY_MODE_SWITCH, KEY_POWEROFF, KEY_POWEROFF_HOLD,
KEY_NULL, KEY_NULL, KEY_NULL
},
{
KEY_NULL, KEY_NULL, KEY_NULL,
KEY_NULL, KEY_NULL, KEY_NULL
},
{
KEY_NULL, KEY_NULL, KEY_NULL,
KEY_NULL, KEY_NULL, KEY_NULL
},
};
static u8 aux_idle_query()
{
return !g_aux.idle;
}
REGISTER_LP_TARGET(aux_lp_target) = {
.name = "aux",
.is_idle = aux_idle_query,
};
// linein adc 回调函数
static void adc_linein_output_hdl(void *priv, s16 *data, int len)
{
int wlen = 0;
if (g_aux.linein_demo && g_aux.linein_demo->cbuf && g_aux.linein_demo->start == 1) {
if (g_aux.linein_demo->linein_ch_num >= 2) {
#if (TCFG_AUDIO_DAC_CONNECT_MODE == DAC_OUTPUT_LR)
/*输出两个linein的数据到DAC两个通道,默认输出第一个和第二个采样通道的数据*/
s16 temp[len * 2];
for (int i = 0; i < len / 2; i++) {
temp[2 * i] = data[g_aux.linein_demo->linein_ch_num * i];
temp[2 * i + 1] = data[g_aux.linein_demo->linein_ch_num * i + 1];
}
/* wlen = audio_dac_write(&dac_hdl, temp, len * 2); */
wlen = cbuf_write(&g_aux.linein_demo->linein_cbuf, temp, len * 2);
#else
/*输出其中一个linein的数据到DAC一个通道*/
s16 *mono_data = data;
for (int i = 0; i < (len / 2); i++) {
switch (g_aux.linein_demo->linein_ch_sel) {
case 0:
mono_data[i] = data[i * g_aux.linein_demo->linein_ch_num]; /*第一路 linein采样的数据*/
break;
case 1:
mono_data[i] = data[i * g_aux.linein_demo->linein_ch_num + 1]; /*第一路 linein采样的数据*/
break;
case 2:
mono_data[i] = data[i * g_aux.linein_demo->linein_ch_num + 2]; /*第三路 linein采样的数据*/
break;
case 3:
mono_data[i] = data[i * g_aux.linein_demo->linein_ch_num + 3]; /*第四路 linein采样的数据*/
break;
default:
break;
}
}
/* wlen = audio_dac_write(&dac_hdl, mono_data, len); */
wlen = cbuf_write(&g_aux.linein_demo->linein_cbuf, mono_data, len);
#endif/*TCFG_AUDIO_DAC_CONNECT_MODE*/
} else {
/*输出一个linein的数据到DAC一个通道*/
/* wlen = audio_dac_write(&dac_hdl, data, len); */
wlen = cbuf_write(&g_aux.linein_demo->linein_cbuf, data, len);
}
/* pcm_dec_resume(); */
if (g_aux.linein_demo->need_resume == 1) {
//激活解码
pcm_dec_resume();
}
}
}
int linein_data_read(void *priv, void *data, int len)
{
int rlen = 0;
if (g_aux.linein_demo && g_aux.linein_demo->start == 1) {
int read_len = cbuf_get_data_size(&g_aux.linein_demo->linein_cbuf);
read_len = read_len > len ? len : read_len;
rlen = cbuf_read(&g_aux.linein_demo->linein_cbuf, data, read_len);
if (!rlen) {
g_aux.linein_demo->need_resume = 1;
}
}
return rlen;
}
/*
*********************************************************************
* AUDIO ADC linein OPEN
* Description: linein通道
* Arguments : linein_idx linein通道
* gain linein增益
* sr linein采样率
* linein_2_dac linein数据DAC
* Return : None.
* Note(s) : (1)linein通道示例
* audio_linein_open(AUDIO_ADC_LINE0,10,16000,1);
*
* audio_linein_open(AUDIO_ADC_LINE1,10,16000,1);
* (2)linein通道示例
* audio_linein_open(AUDIO_ADC_LINE1|AUDIO_ADC_LINE0,10,16000,1);
* (3)linein通道示例
* audio_linein_open(AUDIO_ADC_LINE3|AUDIO_ADC_LINE2|AUDIO_ADC_LINE1|AUDIO_ADC_LINE0,10,16000,1);
*********************************************************************
*/
void audio_linein_open(u8 linein_idx, u8 gain, u16 sr, u8 linein_2_dac)
{
if (g_aux.linein_demo) {
printf("Func:%s,Line:%d, audio linein is opened!\n", __func__, __LINE__);
}
printf("\naudio_adc_linein_demo open:%d,gain:%d,sr:%d,linein_2_dac:%d\n", linein_idx, gain, sr, linein_2_dac);
g_aux.linein_demo = zalloc(sizeof(struct linein_hdl));
if (g_aux.linein_demo) {
//step0:打开linein通道并设置增益
if (linein_idx & AUDIO_ADC_LINE0) {
audio_adc_linein_open(&g_aux.linein_demo->linein_ch, AUDIO_ADC_LINE0, &adc_hdl);
audio_adc_linein_set_gain(&g_aux.linein_demo->linein_ch, gain);
audio_adc_linein_0dB_en(1);
g_aux.linein_demo->linein_ch_num += 1;
}
if (linein_idx & AUDIO_ADC_LINE1) {
audio_adc_linein1_open(&g_aux.linein_demo->linein_ch, AUDIO_ADC_LINE1, &adc_hdl);
audio_adc_linein1_set_gain(&g_aux.linein_demo->linein_ch, gain);
audio_adc_linein1_0dB_en(1);
g_aux.linein_demo->linein_ch_num += 1;
}
if (linein_idx & AUDIO_ADC_LINE2) {
audio_adc_linein2_open(&g_aux.linein_demo->linein_ch, AUDIO_ADC_LINE2, &adc_hdl);
audio_adc_linein2_set_gain(&g_aux.linein_demo->linein_ch, gain);
audio_adc_linein2_0dB_en(1);
g_aux.linein_demo->linein_ch_num += 1;
}
if (linein_idx & AUDIO_ADC_LINE3) {
audio_adc_linein3_open(&g_aux.linein_demo->linein_ch, AUDIO_ADC_LINE3, &adc_hdl);
audio_adc_linein3_set_gain(&g_aux.linein_demo->linein_ch, gain);
audio_adc_linein3_0dB_en(1);
g_aux.linein_demo->linein_ch_num += 1;
}
//初始化cbuffer
if (!g_aux.linein_demo->cbuf) {
g_aux.linein_demo->cbuf = malloc(AUX_CBUF_SIZE);
if (g_aux.linein_demo->cbuf) {
cbuf_init(&g_aux.linein_demo->linein_cbuf, g_aux.linein_demo->cbuf, AUX_CBUF_SIZE);
} else {
r_printf("Error, Func:%s, Line:%d\n", __func__, __LINE__);
return;
}
}
//step1:设置linein通道采样率
audio_adc_linein_set_sample_rate(&g_aux.linein_demo->linein_ch, sr);
//step2:设置linein采样buf
audio_adc_linein_set_buffs(&g_aux.linein_demo->linein_ch, g_aux.linein_demo->adc_buf, AUX_IRQ_POINTS * 2, AUX_BUF_NUM);
//step3:设置linein采样输出回调函数
g_aux.linein_demo->adc_output.handler = adc_linein_output_hdl;
audio_adc_add_output_handler(&adc_hdl, &g_aux.linein_demo->adc_output);
//step4:启动linein通道采样
audio_adc_linein_start(&g_aux.linein_demo->linein_ch);
/*监听配置(可选)*/
g_aux.linein_demo->adc_2_dac = linein_2_dac;
g_aux.linein_demo->linein_idx = linein_idx;
#if 0
if (linein_2_dac) {
printf("max_sys_vol:%d\n", get_max_sys_vol());
app_audio_state_switch(APP_AUDIO_STATE_MUSIC, get_max_sys_vol());
printf("cur_vol:%d\n", app_audio_get_volume(APP_AUDIO_STATE_MUSIC));
audio_dac_set_volume(&dac_hdl, app_audio_get_volume(APP_AUDIO_STATE_MUSIC));
audio_dac_set_sample_rate(&dac_hdl, sr);
audio_dac_start(&dac_hdl);
}
#endif
g_aux.linein_demo->start = 1;
}
printf("audio_adc_linein_demo start succ\n");
}
/*
*********************************************************************
* AUDIO ADC linein CLOSE
* Description: linein采样模块
* Arguments : None.
* Return : None.
* Note(s) : None.
*********************************************************************
*/
void audio_linein_close(void)
{
printf("\naudio_adc_linein_close\n");
if (g_aux.linein_demo) {
g_aux.linein_demo->start = 0;
audio_adc_del_output_handler(&adc_hdl, &g_aux.linein_demo->adc_output);
audio_adc_linein_close(&g_aux.linein_demo->linein_ch);
local_irq_disable();
if (g_aux.linein_demo->cbuf) {
free(g_aux.linein_demo->cbuf);
g_aux.linein_demo->cbuf = NULL;
}
free(g_aux.linein_demo);
g_aux.linein_demo = NULL;
local_irq_enable();
}
}
static void app_aux_init()
{
log_info("app_aux_init");
audio_linein_open(AUDIO_ADC_LINE1 | AUDIO_ADC_LINE0, 10, 44100, 1);
pcm_audio_play_open(44100, g_aux.linein_demo->linein_ch_num);
pcm_dec_set_read_cb(linein_data_read);
}
static void app_aux_exit()
{
log_info("app_aux_exit");
audio_linein_close();
pcm_audio_play_close();
g_aux.idle = 0;
}
static int app_aux_key_event_handler(struct sys_event *event)
{
struct key_event *key = &event->u.key;
int key_event = aux_key_table[key->value][key->event];
log_info("key_event:%d %d %d\n", key_event, key->value, key->event);
switch (key_event) {
case KEY_MODE_SWITCH:
log_info("KEY_MODE_SWITCH");
app_task_switch_next();
break;
case KEY_POWEROFF:
goto_poweroff_cnt = 0;
goto_poweroff_flag = 1;
break;
case KEY_POWEROFF_HOLD:
log_info("poweroff flag:%d cnt:%d\n", goto_poweroff_flag, goto_poweroff_cnt);
if (goto_poweroff_flag) {
goto_poweroff_cnt++;
if (goto_poweroff_cnt >= POWER_OFF_CNT) {
goto_poweroff_cnt = 0;
sys_enter_soft_poweroff(NULL);
}
}
break;
case KEY_ANC_SWITCH:
#if TCFG_AUDIO_ANC_ENABLE
extern void anc_mode_next(void);
anc_mode_next();
#endif
break;
default:
break;
}
return false;
}
/*
*
*/
static int event_handler(struct application *app, struct sys_event *event)
{
switch (event->type) {
case SYS_KEY_EVENT:
/*
*
*/
return app_aux_key_event_handler(event);
case SYS_BT_EVENT:
/*
*
*/
break;
case SYS_DEVICE_EVENT:
/*
*
*/
if ((u32)event->arg == DEVICE_EVENT_FROM_OTG) {
if (event->u.dev.event == DEVICE_EVENT_OUT) {
/* app_task_switch_next(); */
return true;
}
} else if ((u32)event->arg == DEVICE_EVENT_FROM_POWER) {
/* app_power_event_handler(&event->u.dev); */
return true;
} else if ((u32)event->arg == DEVICE_EVENT_FROM_CHARGE) {
#if TCFG_CHARGE_ENABLE
/* app_charge_event_handler(&event->u.dev); */
#endif
return true;
}
break;
default:
return false;
}
return false;
}
static int state_machine(struct application *app, enum app_state state,
struct intent *it)
{
switch (state) {
case APP_STA_CREATE:
log_info("APP_STA_CREATE");
break;
case APP_STA_START:
log_info("APP_STA_START");
if (!it) {
break;
}
switch (it->action) {
case ACTION_AUX_MAIN:
y_printf("\n>>>>>>> Enter Linein Mode!\n");
log_info("ACTION_AUX_MAIN");
///按键使能
sys_key_event_enable();
//关闭自动关机
sys_auto_shut_down_disable();
app_aux_init();
g_aux.idle = 1; //防止进入低功耗
break;
}
break;
case APP_STA_PAUSE:
log_info("APP_STA_PAUSE");
app_aux_exit();
break;
case APP_STA_RESUME:
log_info("APP_STA_RESUME");
app_aux_init();
break;
case APP_STA_STOP:
log_info("APP_STA_STOP");
app_aux_exit();
break;
case APP_STA_DESTROY:
log_info("APP_STA_DESTROY");
break;
}
return 0;
}
static const struct application_operation app_aux_ops = {
.state_machine = state_machine,
.event_handler = event_handler,
};
/*
* aux模式
*/
REGISTER_APPLICATION(app_aux) = {
.name = "aux",
.action = ACTION_AUX_MAIN,
.ops = &app_aux_ops,
.state = APP_STA_DESTROY,
};
#endif