【BES】系统总览(03):事件如何触发业务处理

上一篇介绍了开机初始化:创建线程、邮箱,初始化按键、蓝牙、音频等模块。

初始化完成后,耳机就可以响应各种变化。例如,用户双击耳机、手机连接成功、App 切换降噪模式,都会触发相应的处理。

这一篇主要介绍:一个事件发生后,是怎样进入业务代码的。

一、事件与业务的区别

事件描述“发生了什么”,业务决定“接下来做什么”。

例如,用户双击左耳:

  • 事件:左耳发生双击。
  • 业务:根据当前状态,执行播放、暂停或者接听电话等操作。

同一个操作,在不同状态下可能执行不同功能。

整体流程可以这样理解:

%%{init: {"flowchart": {"htmlLabels": true, "wrappingWidth": 1000, "rankSpacing": 30}, "themeVariables": {"lineColor": "#71829a"}}}%%
flowchart TB
    subgraph R0["① 事件传递"]
        direction LR
        R0N0["检测到变化"]
        R0N1["传递事件"]
        R0N2["找到处理函数"]
        R0N0 --> R0N1 --> R0N2
    end
    class R0N0,R0N1,R0N2 blue;
    style R0 fill:#f1f6fd,stroke:#b8cfe8,color:#23456b
    subgraph R1["② 业务处理"]
        direction LR
        R1N0["判断当前状态"]
        R1N1["执行具体操作"]
        R1N0 --> R1N1
    end
    class R1N0,R1N1 green;
    style R1 fill:#f0f8f3,stroke:#b9d7c4,color:#24563a
    R0 --> R1
    classDef blue fill:#e8f2ff,stroke:#7ba4d8,color:#23456b,stroke-width:1.5px;
    classDef green fill:#e7f4ec,stroke:#78aa8b,color:#24563a,stroke-width:1.5px;
    classDef amber fill:#fff3df,stroke:#d5a25b,color:#72501e,stroke-width:1.5px;

下面结合 BES 的触摸链路来看。

二、触摸事件如何进入业务处理

1. 将触摸操作变成消息

触摸模块识别出操作后,会调用 capsensor_key_event_process(),传入按键编号和事件类型。

正文配图

该函数把“哪个按键、发生了什么操作”打包成按键消息,放入 app 邮箱,等待处理。此时还没有决定双击要执行什么功能。

2. app 线程取出消息,交给按键模块

上一篇提到,app_thread 会从邮箱中取消息,再根据模块编号分发。

正文配图

这条消息的模块编号是 APP_MODULE_KEY,所以会交给按键处理函数 app_key_handle_process()。按键模块初始化时,会先登记由哪个函数处理按键消息;运行时再按登记结果分发。

正文配图

3. 按键模块进入产品业务

app_key_handle_process() 从消息中还原按键编号和事件类型,然后调用 app_ibrt_user_key()。

正文配图

app_ibrt_user_key() 会检查当前状态,并决定如何处理按键事件。例如,设备正在充电或耳机在充电仓内时会直接返回;如果当前耳机是从耳,会尝试把按键事件转发给对耳;否则在本机继续处理。

这里的“主从”指 TWS 角色,“左右耳”是按键编号表示的左右身份,是两种不同判断。下面以本机继续处理的分支为例。

4. 区分测试模式和左右耳

本机处理时会进入 app_wgr_ui_handle_key(),这是按键业务的统一入口。

正文配图

测试模式下,函数处理特定的超长按关机事件;正常模式下,根据 status->code 区分左右耳,并调用对应的按键处理函数。该函数负责分流,不判断双击对应什么功能。

5. 右耳函数根据事件类型分发

下面以右耳为例。

正文配图

右耳处理函数根据事件类型,分发到单击、双击、三击、长按等对应分支。源码中单击调用已注释,目前不会执行单击功能。

6. 右耳双击根据当前状态执行功能

正文配图

bt_key_handle_func_doubleclick_right() 会先读取当前通话状态,再决定双击的用途:

  • 空闲时:读取右耳双击配置。如果配置为播放/暂停,会继续进入播放处理函数,发送 AVRCP 播放或暂停请求。
  • 来电时:接听电话。
  • 拨出或通话中:按代码处理挂断。
  • 三方通话时:根据当前通话组合处理接听、挂断等操作。

这里可以看出,同一个双击事件会根据耳机当前状态进入不同业务。 产品也可以按需求调整各状态下的处理逻辑。

其他按键事件也是类似流程:先按左右耳和事件类型分发,再结合当前状态执行具体操作。

三、其他事件也可以这样理解

看其他事件时,先关注:事件从哪里来、在哪里接收、由谁分发、最后执行什么业务。

场景事件从哪里来业务主要做什么
手机连接耳机蓝牙协议栈上报连接结果更新连接状态,处理后续连接业务
App 切换 ANC手机通过 BLE 发送设置命令接收目标模式,进入 ANC 控制流程
电池电量变化定时采样得到电池电压更新电量,按条件上报或处理低电量

这些事件的入口和传递方式不完全相同,但都可以根据事件触发源头,顺着调用链查下去。

四、看业务代码时,怎么找入口

先选一个具体操作,例如“双击暂停音乐”,然后顺着四步查:

  1. 哪里检测到这个操作?
  2. 事件通过邮箱还是回调传递?
  3. 哪个函数判断状态和功能?
  4. 最后调用什么接口执行?

上一篇主要看“模块怎样初始化”,这一篇看“模块初始化后怎样响应事件”。 先把按键链路看通,再用同样的方法看连接、ANC 和电池等流程。