
Linein模式执行流程详解
概述
本文档详细描述linein模式从系统启动到正常工作的完整执行流程,包括关键函数调用链、接口跳转关系和代码位置。
完整执行流程图

#mermaid-svg-dwVmHQRgbaITdaFj{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-dwVmHQRgbaITdaFj .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-dwVmHQRgbaITdaFj .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-dwVmHQRgbaITdaFj .error-icon{fill:#552222;}#mermaid-svg-dwVmHQRgbaITdaFj .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-dwVmHQRgbaITdaFj .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-dwVmHQRgbaITdaFj .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-dwVmHQRgbaITdaFj .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-dwVmHQRgbaITdaFj .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-dwVmHQRgbaITdaFj .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-dwVmHQRgbaITdaFj .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-dwVmHQRgbaITdaFj .marker{fill:#333333;stroke:#333333;}#mermaid-svg-dwVmHQRgbaITdaFj .marker.cross{stroke:#333333;}#mermaid-svg-dwVmHQRgbaITdaFj svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-dwVmHQRgbaITdaFj p{margin:0;}#mermaid-svg-dwVmHQRgbaITdaFj .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-dwVmHQRgbaITdaFj .cluster-label text{fill:#333;}#mermaid-svg-dwVmHQRgbaITdaFj .cluster-label span{color:#333;}#mermaid-svg-dwVmHQRgbaITdaFj .cluster-label span p{background-color:transparent;}#mermaid-svg-dwVmHQRgbaITdaFj .label text,#mermaid-svg-dwVmHQRgbaITdaFj span{fill:#333;color:#333;}#mermaid-svg-dwVmHQRgbaITdaFj .node rect,#mermaid-svg-dwVmHQRgbaITdaFj .node circle,#mermaid-svg-dwVmHQRgbaITdaFj .node ellipse,#mermaid-svg-dwVmHQRgbaITdaFj .node polygon,#mermaid-svg-dwVmHQRgbaITdaFj .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-dwVmHQRgbaITdaFj .rough-node .label text,#mermaid-svg-dwVmHQRgbaITdaFj .node .label text,#mermaid-svg-dwVmHQRgbaITdaFj .image-shape .label,#mermaid-svg-dwVmHQRgbaITdaFj .icon-shape .label{text-anchor:middle;}#mermaid-svg-dwVmHQRgbaITdaFj .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-dwVmHQRgbaITdaFj .rough-node .label,#mermaid-svg-dwVmHQRgbaITdaFj .node .label,#mermaid-svg-dwVmHQRgbaITdaFj .image-shape .label,#mermaid-svg-dwVmHQRgbaITdaFj .icon-shape .label{text-align:center;}#mermaid-svg-dwVmHQRgbaITdaFj .node.clickable{cursor:pointer;}#mermaid-svg-dwVmHQRgbaITdaFj .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-dwVmHQRgbaITdaFj .arrowheadPath{fill:#333333;}#mermaid-svg-dwVmHQRgbaITdaFj .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-dwVmHQRgbaITdaFj .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-dwVmHQRgbaITdaFj .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-dwVmHQRgbaITdaFj .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-dwVmHQRgbaITdaFj .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-dwVmHQRgbaITdaFj .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-dwVmHQRgbaITdaFj .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-dwVmHQRgbaITdaFj .cluster text{fill:#333;}#mermaid-svg-dwVmHQRgbaITdaFj .cluster span{color:#333;}#mermaid-svg-dwVmHQRgbaITdaFj div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-dwVmHQRgbaITdaFj .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-dwVmHQRgbaITdaFj rect.text{fill:none;stroke-width:0;}#mermaid-svg-dwVmHQRgbaITdaFj .icon-shape,#mermaid-svg-dwVmHQRgbaITdaFj .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-dwVmHQRgbaITdaFj .icon-shape p,#mermaid-svg-dwVmHQRgbaITdaFj .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-dwVmHQRgbaITdaFj .icon-shape .label rect,#mermaid-svg-dwVmHQRgbaITdaFj .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-dwVmHQRgbaITdaFj .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-dwVmHQRgbaITdaFj .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-dwVmHQRgbaITdaFj :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 是
否
通过
失败
ADC采样
模拟直通
DAC输入
按键事件
设备事件
其他事件
设备拔出
系统启动
app_task_loop主循环
检测到linein设备?
app_task_switch_to
APP_LINEIN_TASK
其他任务模式
linein_app_check
设备在线检查
app_linein_task
linein主任务
切换失败
linein_app_init
应用初始化
UI_SHOW_WINDOW
显示linein界面
sys_key_event_enable
开启按键响应
clock_idle
时钟配置
tone_play_with_callback_by_name
播放linein提示音
line_tone_play_end_callback
提示音结束回调
app_task_put_key_msg
KEY_LINEIN_START
linein_key_msg_deal
按键消息处理
linein_start
启动linein音频
输入方式选择
__linein_way_adc_start
ADC输入方式
__linein_way_analog_start
模拟输入方式
__linein_way_dac_analog_start
DAC输入方式
linein_dec_open
打开解码器
audio_linein0/1/2_open
打开模拟通道
audio_linein_via_dac_open
打开DAC通道
消息循环处理
linein_sys_event_handler
系统事件处理
事件类型
linein_key_msg_deal
按键处理
设备插拔处理
app_default_event_deal
通用事件处理
音量调节/播放控制
app_task_switch_next
切换到下一模式
linein_task_close
任务退出清理
UI_HIDE_CURR_WINDOW
隐藏界面
linein_stop
停止音频
tone_play_stop_by_path
停止提示音
任务结束
关键执行阶段详解
1. 系统启动和任务调度
文件 : apps/soundbox/app_main.c
c
void app_task_loop()
{
while (1) {
switch (app_curr_task) {
case APP_LINEIN_TASK:
log_info("APP_LINEIN_TASK \n");
app_linein_task(); // 🔥调用linein主任务
break;
// ... 其他任务
}
app_task_clear_key_msg();//清理按键消息,防止消息堆积
vm_check_all(0); //检查整理VM
}
}
2. 任务切换和设备检测
文件 : apps/soundbox/task_manager/app_task_switch.c
c
// 任务列表配置
static const u8 app_task_list[] = {
#if TCFG_APP_BT_EN
APP_BT_TASK,
#endif
#if TCFG_APP_MUSIC_EN
APP_MUSIC_TASK,
#endif
#if TCFG_APP_LINEIN_EN
APP_LINEIN_TASK, // 🔥第7号任务
#endif
// ... 其他任务
};
// 任务切换检查
static int app_task_switch_check(u8 app_task)
{
switch (app_task) {
#if TCFG_APP_LINEIN_EN
case APP_LINEIN_TASK:
ret = linein_app_check(); // 🔥检查linein设备是否在线
break;
#endif
}
return ret;
}
// 任务切换函数
int app_task_switch_to(u8 app_task)
{
if (app_curr_task == app_task) {
return false;
}
if (!app_task_switch_check(app_task)) { // 🔥设备检查
return false;
}
app_prev_task = app_curr_task;
app_next_task = app_task;
app_task_put_usr_msg(APP_MSG_SWITCH_TASK, 0); // 🔥发送切换消息
return TRUE;
}
3. Linein设备在线检测
文件 : apps/soundbox/task_manager/linein/linein.c
c
int linein_app_check(void)
{
if (linein_is_online()) { // 🔥检查设备是否在线
return true;
}
return false;
}
文件 : apps/soundbox/task_manager/linein/linein_dev.c
c
// 设备检测定时器回调
static void linein_detect(void *arg)
{
u8 cur_stu = linein_sample_detect(arg); // 🔥采样检测
if (cur_stu != __this->stu) {
__this->stu = cur_stu;
__this->cnt = 0;
__this->active = 1;
} else {
__this->cnt++;
}
if (__this->cnt < LINEIN_DETECT_CNT) {//滤波计算
return;
}
// 🔥设备状态变化处理
if ((linein_is_online()) && (!__this->stu)) {
linein_set_online(false);
linein_event_notify(DEVICE_EVENT_OUT);//发布下线消息
} else if ((!linein_is_online()) && (__this->stu)) {
linein_set_online(true);
linein_event_notify(DEVICE_EVENT_IN);//发布上线消息
}
}
4. Linein主任务执行
文件 : apps/soundbox/task_manager/linein/linein.c
c
void app_linein_task()
{
int msg[32];
#if TCFG_APP_BT_EN
linein_bt_back_flag = get_bt_back_flag();//从蓝牙后台返回标志
set_bt_back_flag(0);
#endif
// 🔥1. 初始化linein应用
linein_app_init();
// 🔥2. 播放linein模式提示音
#if TCFG_DEC2TWS_ENABLE
if (get_tws_background_connected_flag()) { //不播放提示音
app_task_put_key_msg(KEY_LINEIN_START, 0);
set_tws_background_connected_flag(0);
} else
#endif
{
err = tone_play_with_callback_by_name(tone_table[IDEX_TONE_LINEIN], 1,
line_tone_play_end_callback, (void *)IDEX_TONE_LINEIN);
}
// 🔥3. 进入消息循环
while (1) {
app_task_get_msg(msg, ARRAY_SIZE(msg), 1);
switch (msg[0]) {
case APP_MSG_SYS_EVENT:
if (linein_sys_event_handler((struct sys_event *)(&msg[1])) == false) {
app_default_event_deal((struct sys_event *)(&msg[1]));
}
break;
}
// 🔥4. 检查是否需要退出任务
if (app_task_exitting()) {
linein_task_close();
return;
}
}
}
5. Linein应用初始化
文件 : apps/soundbox/task_manager/linein/linein.c
c
static void linein_app_init(void)
{
linein_idle_flag = 0;
UI_SHOW_WINDOW(ID_WINDOW_LINEIN); // 🔥打开ui主页
UI_SHOW_MENU(MENU_AUX, 0, 0, NULL); // 🔥显示AUX菜单
sys_key_event_enable(); // 🔥开启按键
ui_update_status(STATUS_LINEIN_MODE); // 🔥更新状态
clock_idle(LINEIN_IDLE_CLOCK); // 🔥时钟配置
}
6. 提示音播放完毕回调
文件 : apps/soundbox/task_manager/linein/linein.c
c
static void line_tone_play_end_callback(void *priv, int flag)
{
u32 index = (u32)priv;
if (APP_LINEIN_TASK != app_get_curr_task()) {
log_error("tone callback task out \n");
return;
}
switch (index) {
case IDEX_TONE_LINEIN:
// 🔥提示音播放结束,启动播放器播放
app_task_put_key_msg(KEY_LINEIN_START, 0);
break;
}
}
7. 按键消息处理和音频启动
文件 : apps/soundbox/task_manager/linein/linein.c
c
static int linein_key_msg_deal(struct sys_event *event)
{
struct key_event *key = &event->u.key;
int key_event = key->event;
int key_value = key->value;
switch (key_event) {
case KEY_LINEIN_START:
linein_start(); // 🔥启动linein音频
linein_last_onoff = 1;
UI_REFLASH_WINDOW(true);//刷新主页并且支持打断显示
break;
case KEY_MUSIC_PP:
linein_last_onoff = linein_volume_pp(); // 🔥播放/暂停控制
linein_last_onoff ? ui_update_status(STATUS_LINEIN_PLAY)
: ui_update_status(STATUS_LINEIN_PAUSE);
break;
case KEY_VOL_UP:
linein_key_vol_up(); // 🔥音量增加
break;
case KEY_VOL_DOWN:
linein_key_vol_down(); // 🔥音量减少
break;
}
return TRUE;
}
8. Linein音频启动流程
文件 : apps/soundbox/task_manager/linein/linein_api.c
c
int linein_start(void)
{
if (__this->onoff == 1) {
log_info("linein is aleady start\n");
return true;
}
// 🔥根据配置选择不同的输入方式
#if (TCFG_LINEIN_INPUT_WAY == LINEIN_INPUT_WAY_ADC)
set_dac_start_delay_time(1, 1); //设置dac 通道的启动延时
__linein_way_adc_start(); // 🔥ADC采样方式
__this->audio_state = APP_AUDIO_STATE_MUSIC;
#elif (TCFG_LINEIN_INPUT_WAY == LINEIN_INPUT_WAY_ANALOG)
__this->volume = app_audio_get_volume(__this->audio_state);
__this->audio_state = APP_AUDIO_STATE_LINEIN;
__linein_way_analog_start(); // 🔥模拟直通方式
audio_dac_vol_mute_lock(1);
#elif (TCFG_LINEIN_INPUT_WAY == LINEIN_INPUT_WAY_DAC)
__this->volume = app_audio_get_volume(__this->audio_state);
__this->audio_state = APP_AUDIO_STATE_LINEIN;
__linein_way_dac_analog_start(); // 🔥DAC输入方式
audio_dac_vol_mute_lock(1);
#endif
__this->volume = app_audio_get_volume(__this->audio_state);
__this->onoff = 1;
UI_REFLASH_WINDOW(false);//刷新主页并且支持打断显示
return true;
}
9. 三种输入方式详解

9.1 ADC采样方式
文件 : apps/soundbox/task_manager/linein/linein_api.c
c
static inline void __linein_way_adc_start()
{
#if (TCFG_LINEIN_MULTIPLEX_WITH_FM && (defined(CONFIG_CPU_BR25)))
linein_dec_open(AUDIO_LIN1R_CH, 44100); // 🔥696X系列FM与LINEIN复用脚
#else
linein_dec_open(TCFG_LINEIN_LR_CH, 44100); // 🔥打开linein解码器
#endif
}
9.2 模拟直通方式
文件 : apps/soundbox/task_manager/linein/linein_api.c
c
static inline void __linein_way_analog_start()
{
app_audio_state_switch(__this->audio_state, get_max_sys_vol());
app_audio_set_volume(__this->audio_state, __this->volume, 1);
// 🔥根据通道配置打开对应的linein
if (TCFG_LINEIN_LR_CH & (BIT(0) | BIT(1))) {
audio_linein0_open(TCFG_LINEIN_LR_CH, 1);
} else if (TCFG_LINEIN_LR_CH & (BIT(2) | BIT(3))) {
audio_linein1_open(TCFG_LINEIN_LR_CH, 1);
} else if (TCFG_LINEIN_LR_CH & (BIT(4) | BIT(5))) {
audio_linein2_open(TCFG_LINEIN_LR_CH, 1);
}
// 🔥通道合并和增益设置
if (TCFG_LINEIN_LR_CH != AUDIO_LIN0_LR && TCFG_LINEIN_LR_CH != AUDIO_LIN1_LR && TCFG_LINEIN_LR_CH != AUDIO_LIN2_LR) {
audio_linein_ch_combine(1, 1);
}
audio_linein_gain(1); // 🔥high gain
if (app_audio_get_volume(__this->audio_state)) {
audio_linein_mute(0);
app_audio_set_volume(__this->audio_state, app_audio_get_volume(__this->audio_state), 1);
}
}
9.3 DAC输入方式
文件 : apps/soundbox/task_manager/linein/linein_api.c
c
static inline void __linein_way_dac_analog_start()
{
app_audio_state_switch(__this->audio_state, get_max_sys_vol());
app_audio_set_volume(__this->audio_state, __this->volume, 1);
// 🔥通过DAC通道输入
if ((TCFG_LINEIN_LR_CH == AUDIO_LIN_DACL_CH)
|| (TCFG_LINEIN_LR_CH == AUDIO_LIN_DACR_CH)) {
audio_linein_via_dac_open(TCFG_LINEIN_LR_CH, 1);
} else {
ASSERT(0, "linein ch err\n");
}
linein_volume_set(app_audio_get_volume(__this->audio_state));
}
10. 系统事件处理

文件 : apps/soundbox/task_manager/linein/linein.c
c
static int linein_sys_event_handler(struct sys_event *event)
{
int ret = TRUE;
switch (event->type) {
case SYS_KEY_EVENT:
return linein_key_msg_deal(event); // 🔥按键事件处理
break;
case SYS_DEVICE_EVENT:
if ((u32)event->arg == DEVICE_EVENT_FROM_LINEIN) {
if (event->u.dev.event == DEVICE_EVENT_IN) {
log_info("linein online \n"); // 🔥设备插入
} else if (event->u.dev.event == DEVICE_EVENT_OUT) {
log_info("linein offline \n"); // 🔥设备拔出
app_task_switch_next(); // 🔥切换到下一模式
}
return true;
}
return false;
break;
default:
return false;
}
return false;
}
11. Linein任务退出和清理
文件 : apps/soundbox/task_manager/linein/linein.c
c
static void linein_task_close(void)
{
UI_HIDE_CURR_WINDOW(); // 🔥隐藏当前窗口
linein_stop(); // 🔥停止linein音频
tone_play_stop_by_path(tone_table[IDEX_TONE_LINEIN]); // 🔥停止提示音
linein_idle_flag = 1; // 🔥设置空闲标志
}
文件 : apps/soundbox/task_manager/linein/linein_api.c
c
void linein_stop(void)
{
if (__this->onoff == 0) {
log_info("linein is aleady stop\n");
return;
}
// 🔥根据输入方式进行相应的关闭操作
#if (TCFG_LINEIN_INPUT_WAY == LINEIN_INPUT_WAY_ADC)
set_dac_start_delay_time(0, 0); //把dac的延时设置回默认的配置
linein_dec_close(); // 🔥关闭解码器
#elif (TCFG_LINEIN_INPUT_WAY == LINEIN_INPUT_WAY_ANALOG)
// 🔥关闭对应的linein通道
if (TCFG_LINEIN_LR_CH & (BIT(0) | BIT(1))) {
audio_linein0_close(TCFG_LINEIN_LR_CH, 0);
} else if (TCFG_LINEIN_LR_CH & (BIT(2) | BIT(3))) {
audio_linein1_close(TCFG_LINEIN_LR_CH, 0);
} else if (TCFG_LINEIN_LR_CH & (BIT(4) | BIT(5))) {
audio_linein2_close(TCFG_LINEIN_LR_CH, 0);
}
audio_dac_vol_mute_lock(0);
#elif (TCFG_LINEIN_INPUT_WAY == LINEIN_INPUT_WAY_DAC)
audio_linein_via_dac_close(TCFG_LINEIN_LR_CH, 0); // 🔥关闭DAC通道
audio_dac_vol_mute_lock(0);
#endif
app_audio_set_volume(APP_AUDIO_STATE_MUSIC, __this->volume, 1);
__this->onoff = 0;
}
关键函数调用链总结
12.1 系统启动到任务切换调用链
main()
├── app_task_handler()
├── app_main()
└── app_task_loop()
├── 检测设备插入事件
├── app_task_switch_to(APP_LINEIN_TASK)
├── app_task_switch_check()
└── linein_app_check()
12.2 Linein主任务调用链
app_linein_task()
├── get_bt_back_flag() // 检查蓝牙后台标志
├── linein_app_init() // 应用初始化
│ ├── UI_SHOW_WINDOW(ID_WINDOW_LINEIN) // 显示界面
│ ├── UI_SHOW_MENU(MENU_AUX) // 显示菜单
│ ├── sys_key_event_enable() // 开启按键
│ ├── ui_update_status(STATUS_LINEIN_MODE) // 更新状态
│ └── clock_idle(LINEIN_IDLE_CLOCK) // 时钟配置
├── tone_play_with_callback_by_name() // 播放提示音
└── 消息循环
├── app_task_get_msg() // 获取消息
├── linein_sys_event_handler() // 事件处理
└── app_task_exitting() // 检查退出
12.3 提示音回调到音频启动调用链
line_tone_play_end_callback()
├── app_task_put_key_msg(KEY_LINEIN_START) // 发送启动消息
└── linein_key_msg_deal() // 按键消息处理
└── linein_start() // 启动音频
├── __linein_way_adc_start() // ADC方式
│ └── linein_dec_open() // 打开解码器
├── __linein_way_analog_start() // 模拟方式
│ ├── audio_linein0/1/2_open() // 打开模拟通道
│ ├── audio_linein_ch_combine() // 通道合并
│ └── audio_linein_gain() // 设置增益
└── __linein_way_dac_analog_start() // DAC方式
└── audio_linein_via_dac_open() // 打开DAC通道
12.4 设备检测调用链
linein_driver_init()
├── linein_set_online() // 设置在线状态
└── sys_timer_add(linein_detect) // 添加检测定时器
└── linein_detect() // 定时检测
├── linein_sample_detect() // 采样检测
├── 滤波处理
└── linein_event_notify() // 发送设备事件
└── linein_sys_event_handler() // 事件处理
└── app_task_switch_next() // 设备拔出时切换模式
12.5 任务退出调用链
app_task_exitting()
└── linein_task_close() // 任务关闭
├── UI_HIDE_CURR_WINDOW() // 隐藏界面
├── linein_stop() // 停止音频
│ ├── linein_dec_close() // 关闭解码器(ADC方式)
│ ├── audio_linein0/1/2_close() // 关闭模拟通道(模拟方式)
│ └── audio_linein_via_dac_close() // 关闭DAC通道(DAC方式)
├── tone_play_stop_by_path() // 停止提示音
└── linein_idle_flag = 1 // 设置空闲标志
配置和接口说明
13.1 关键配置宏定义
文件 : apps/soundbox/board/br25/board_xxx_cfg.h
c
#define TCFG_APP_LINEIN_EN 1 // linein功能使能
#define TCFG_LINEIN_ENABLE TCFG_APP_LINEIN_EN // linein使能
#define TCFG_LINEIN_LR_CH AUDIO_LIN0_LR // linein通道配置
#define TCFG_LINEIN_CHECK_PORT IO_PORTB_01 // linein检测IO
#define TCFG_LINEIN_PORT_UP_ENABLE 1 // 检测IO上拉使能
#define TCFG_LINEIN_PORT_DOWN_ENABLE 0 // 检测IO下拉使能
#define TCFG_LINEIN_DETECT_ENABLE ENABLE // 是否使用linein检测
#define TCFG_LINEIN_INPUT_WAY LINEIN_INPUT_WAY_ANALOG // 输入方式选择
13.2 输入方式选择
c
// 三种输入方式定义
#define LINEIN_INPUT_WAY_ADC 0 // ADC采样方式
#define LINEIN_INPUT_WAY_ANALOG 1 // 模拟直通方式
#define LINEIN_INPUT_WAY_DAC 2 // DAC输入方式
13.3 通道配置选项
c
// 通道配置选项
#define AUDIO_LIN0_LR (BIT(0) | BIT(1)) // LIN0左右声道
#define AUDIO_LIN1_LR (BIT(2) | BIT(3)) // LIN1左右声道
#define AUDIO_LIN2_LR (BIT(4) | BIT(5)) // LIN2左右声道
#define AUDIO_LIN_DACL_CH BIT(6) // DAC左声道
#define AUDIO_LIN_DACR_CH BIT(7) // DAC右声道
时序控制要点
14.1 关键时序说明
- 设备检测时序:50ms定时器检测,连续检测到相同状态LINEIN_DETECT_CNT次才确认状态变化
- 提示音控制:必须等待提示音播放完毕才启动音频,通过回调机制控制
- 音频启动延时:ADC方式需要设置DAC启动延时,确保音频链路稳定
- 任务切换时序:设备拔出时立即切换到下一模式,避免无效状态
14.2 关键状态标志
c
// 关键状态变量
static u8 linein_last_onoff = (u8)-1; // 上次开关状态
static u8 linein_bt_back_flag = 0; // 蓝牙后台返回标志
static u8 linein_idle_flag = 1; // 空闲状态标志
14.3 音频状态管理
c
// 音频状态定义
#define APP_AUDIO_STATE_MUSIC 0 // 音乐状态(ADC方式)
#define APP_AUDIO_STATE_LINEIN 1 // Linein状态(模拟/DAC方式)
调试要点
15.1 关键调试信息
- 设备检测:观察"linein online/offline"日志
- 任务切换:观察"APP_LINEIN_TASK"和任务切换日志
- 音频启动:观察"linein is aleady start"等状态日志
- 按键响应:观察"KEY_LINEIN_START"、"KEY_MUSIC_PP"等按键日志
15.2 常见问题排查
- 无法切换到linein模式:检查linein_app_check()返回值和设备检测
- 无音频输出:检查输入方式配置和通道配置是否正确
- 设备检测异常:检查GPIO配置和检测阈值设置
- 任务无法退出:检查app_task_exitting()和消息循环逻辑
这个完整的执行流程展示了从系统启动到linein正常工作的每一个关键步骤,帮助您深入理解整个linein模式的运行机制。