Cleer Arc5耳机中介者模式减少对象通信

你有没有遇到过这样的情况:改一个功能,结果十个模块都得跟着动?😅
在TWS耳机这种“小身材大智慧”的设备里,这简直是家常便饭。Cleer Arc5这种高端真无线耳机,集成了触控、降噪、蓝牙多连、空间音频、语音唤醒……光是想想这些模块之间要怎么“对话”,就让人头大。

要是每个模块都直接找另一个模块“说事”——比如触控模块直接调蓝牙模块暂停音乐,那整个系统很快就会变成一张密不透风的“蜘蛛网”。一牵发而动全身,别说加新功能了,能不崩就算赢。

那怎么办?聪明的工程师们没硬刚,而是请来了一个“中间人”—— 中介者(Mediator) 。这个角色不干活,专管“传话”。谁有事,只告诉它;谁要听消息,也只订阅它。大家互不见面,全靠它撮合。神奇的是,这么一搞,系统居然变清爽了!


想象一下,你戴着Cleer Arc5在跑步,突然手机来电话了。这时:

  • 蓝牙模块发现来电 → 发个事件:“我这儿有来电!”
  • 中介者一听,立马广播:“各位注意!来电了!”
  • 降噪模块收到 → 切到通透模式,让你听得清周围;
  • 音频路由模块 → 暂停本地音乐,切到通话通道;
  • 触控模块 → 更新状态,双击可以拒接;
  • 电源管理 → 记录一次高频事件,准备动态调频省电。

全程没有哪个模块直接打电话给另一个模块。它们甚至不知道对方是谁,只知道“有人发了个 EVENT_CALL_INCOMING 事件”。是不是有点像微信群?你发一条消息,群里的人各看各的,该干嘛干嘛,没人需要单独私聊你确认一遍。

这就是 中介者模式 的魔力:把原本N个模块之间可能产生的 $ N(N-1)/2 $ 条连接,压缩成N条“连接中介者”的线,从“网状”变成“星型”。✨

// 事件类型定义,简洁明了
typedef enum {
    EVENT_TOUCH_TAP,
    EVENT_BT_CONNECTED,
    EVENT_BATTERY_LOW,
    EVENT_ANC_MODE_CHANGED,
    EVENT_AUDIO_ROUTE_UPDATE,
    EVENT_CALL_INCOMING
} SystemEvent_t;

// 核心接口就两个:注册和发布
void Mediator_RegisterListener(SystemEvent_t event, void (*callback)(void*));
void Mediator_PostEvent(SystemEvent_t event, void* data);

看看这个双击切换降噪模式的例子:

// anc_controller.c
void ANC_Init() {
    // 我只关心“触控双击”这个事件
    Mediator_RegisterListener(EVENT_TOUCH_TAP, OnTouchTapForANC);
}

static void OnTouchTapForANC(void* data) {
    TapInfo_t* tap = (TapInfo_t*)data;
    if (tap->count == 2) {
        anc_mode_t next = (current_anc_mode + 1) % MODE_COUNT;
        ANC_SetMode(next);
        // 嘿,大家注意,我的模式变了!
        Mediator_PostEvent(EVENT_ANC_MODE_CHANGED, &next);
    }
}

再看看音频路由模块怎么响应:

// audio_router.c
void AudioRouter_Init() {
    // 我只订阅“降噪模式变化”事件
    Mediator_RegisterListener(EVENT_ANC_MODE_CHANGED, OnANCModeChange);
}

static void OnANCModeChange(void* data) {
    anc_mode_t mode = *(anc_mode_t*)data;
    switch(mode) {
        case ANC_ON:
            RouteToNoiseCancellationPath();
            break;
        case TRANSPARENCY:
            RouteToAmbientSoundPath();
            break;
        default:
            RouteToNormalPath();
    }
}

瞧见没? ANCController AudioRouter 完全不认识彼此,也不需要include对方的头文件。它们只依赖一个简单的事件协议。你要加个UI模块显示当前模式?行啊,注册监听 EVENT_ANC_MODE_CHANGED 就完事了,不用动前面一行代码。🚀


这种设计在嵌入式系统里特别香,尤其是资源紧张的MCU环境。我们来看几个关键点:

🧩 松耦合 + 高内聚,开发效率拉满

以前加个新功能,得改三个模块的接口,还得协调联调。现在呢?你只要想清楚“我需要什么事件”和“我会发出什么事件”,剩下的交给中介者就行。团队并行开发不再打架,模块可以独立测试——用个假的中介者模拟输入输出,单元测试写起来飞快。

🔄 动态配置,场景模式秒切换

Cleer Arc5支持“会议模式”、“运动模式”等预设场景。这背后其实就是一套事件映射表的动态加载。比如开会时,你希望:

  • 单击 → 静音麦克风
  • 双击 → 拒接来电
  • 摘下耳机 → 不暂停音乐(避免误触发)

这些逻辑不需要硬编码在各个模块里,而是在运行时通过中介者重新注册监听函数来实现:

void Scene_SwitchToMeetingMode() {
    Mediator_ClearAllListeners();        // 清空当前所有监听
    RegisterMeetingModeListeners();      // 注册会议专用监听组
    Mediator_PostEvent(EVENT_SCENE_CHANGED, &(Scene_t){.id=MEETING});
}

是不是有点像“插件化”?不同的使用场景,加载不同的行为组合,核心架构不动。

⚠️ 工程落地,这些坑得避开

中介者虽好,但用不好也会翻车。我们在实际项目中总结了几条经验:

  1. 别让中介者变成“上帝对象”
    它只负责转发,别掺和业务逻辑。比如“双击切降噪”是业务规则,应该由 ANCController 自己判断,而不是让中介者去解析手势再决定发什么事件。

  2. 事件粒度要拿捏准
    太细?比如 EVENT_BUTTON_LEFT_PRESSED ,会导致事件泛滥。
    太粗?比如 EVENT_SYSTEM_STATE_CHANGED ,接收方还得自己解析状态,等于没解耦。
    推荐命名法: 动词 + 主体 ,如 EVENT_MIC_MUTE_TOGGLED EVENT_NOISE_LEVEL_HIGH

  3. 内存和性能要平衡
    在RAM只有几十KB的MCU上,事件队列不能无限制增长。我们通常设个上限(比如16个事件),超了就丢弃低优先级的,或者打个日志报警。

  4. 线程安全必须考虑
    触控中断、蓝牙回调可能来自不同上下文。我们用RTOS的消息队列把事件推送到主任务处理,避免在ISR里做复杂操作:

```c
// 中断中只做最轻的事
void GPIO_IRQHandler() {
xQueueSendFromISR(event_queue, &evt, NULL);
}

// 主任务循环里统一处理
void MainTask() {
while(1) {
if (xQueueReceive(event_queue, &evt, portMAX_DELAY)) {
Mediator_PostEvent(evt.type, evt.data);
}
}
}
```

  1. 调试友好性很重要
    加个DEBUG开关,把事件流打出来,查问题时简直救命:

c #ifdef DEBUG_EVENT printf("[EVENT] 📢 Posted: %s\n", EventToString(event)); #endif


回到开头那个问题:为什么Cleer Arc5能在功能这么多的情况下还保持稳定和快速迭代?答案就藏在这个看似简单的 Mediator_PostEvent() 调用里。

它不只是一个函数,更是一种 设计哲学 让模块专注于自己的职责,把协作交给机制 。当每个模块都“各司其职、互不打扰”时,系统的复杂度才真正可控。

而且这套思路完全不限于耳机。你家里的智能音箱、手上的智能手表、墙上的温控面板……只要是多个传感器+多种交互+多设备联动的IoT产品,都能从中受益。

💡 一个小建议:下次你面对一堆互相调用的模块时,不妨先停下来问一句:“能不能让它们都不直接说话,而是通过一个‘群聊’来沟通?” 也许,一个更优雅的架构就在这一念之间。

中介者模式不是银弹,但它是一把锋利的小刀,专治“高耦合、难维护”的嵌入式顽疾。在算力有限、迭代飞快的智能硬件时代,这种经典设计模式,反而焕发出了新的生命力。🌱

Logo

openvela 操作系统专为 AIoT 领域量身定制,以轻量化、标准兼容、安全性和高度可扩展性为核心特点。openvela 以其卓越的技术优势,已成为众多物联网设备和 AI 硬件的技术首选,涵盖了智能手表、运动手环、智能音箱、耳机、智能家居设备以及机器人等多个领域。

更多推荐