返回博客

OpenClaw 源码解读(7): 跨平台语音唤醒实现机制

2026年3月17日

深入 OpenClaw 跨平台语音唤醒架构,解析从本地 VAD 检测、端侧唤醒词引擎到云端流式 ASR 的完整链路,以及多设备统一调度机制。


在前面的篇章中,我们解析了 OpenClaw 的路由、A2UI 和工具链。但作为个人 AI 助手,如果每次都要你掏出手机、打开 App、打字输入,那它充其量只是个“高级搜索引擎”。真正的助手,应该是在你做饭、开车或者敲代码时,只需喊一声,它就能随时待命。

语音交互(Voice UI)是通向 AGI 终极形态的必经之路。但跨平台语音开发是个大坑:macOS、iOS 和 Android 对麦克风权限和后台存活机制的管理完全不同。

今天,我们就来拆解 OpenClaw 的 Nodes(节点)架构,看看它是如何通过 TypeScript、Swift 和 Kotlin 的混编,实现全平台“唤醒与聆听”的。


语音流转核心:从声波到文字,再到声音

在 OpenClaw 中,所有的硬件设备(Mac、iPhone、安卓机)都被抽象为一个个“Node(节点)”。节点负责收集声音,而 Gateway(网关)负责大脑的思考和转化。

一次完整的语音交互流转如下:

  1. Node(端侧): 监听唤醒词 -> 录制音频 -> 通过 WebSocket 将音频流(PCM/WAV)推送到 Gateway。

  2. Gateway(云/局域网端): 调用 STT(Speech-to-Text,如 Whisper)将语音转为文字 -> 路由给 Agent -> Agent 生成回复文本。

  3. Gateway(云/局域网端): 调用 TTS(Text-to-Speech,如 ElevenLabs 或系统自带 TTS)生成音频流 -> 推送回 Node。

  4. Node(端侧): 播放音频。

我们看看 Gateway 是如何处理这段双向音频流的:

// src/core/audio/VoicePipeline.ts (源码概念简化版)

import { STTEngine } from './stt';
import { TTSEngine } from './tts';

export class VoicePipeline {
  /**
   * 处理来自 Node 的音频流
   */
  public async handleNodeAudioStream(nodeId: string, audioBuffer: Buffer) {
    // 1. 语音转文本 (STT)
    const transcribedText = await STTEngine.transcribe(audioBuffer);
    
    // 2. 扔给 Agent 处理,获取回复文本
    const agentReply = await AgentManager.routeAndProcess(nodeId, transcribedText);
    
    // 3. 文本转语音 (TTS),结合 ElevenLabs 实现高度拟人化的声音
    // 注意:这里通常采用流式 (Streaming) 处理来降低首字节延迟 (TTFB)
    const audioStream = await TTSEngine.synthesizeStream(agentReply, {
      voiceId: 'eleven_labs_molty_voice',
      model: 'eleven_turbo_v2'
    });
    
    // 4. 将音频流通过 WebSocket 发送回设备 Node 进行播放
    await GatewayServer.sendAudioToNode(nodeId, audioStream);
  }
}


macOS/iOS:轻量级本地唤醒词机制

在苹果生态中,一直开着麦克风把音频传到服务器是不可行的(既耗电,又会被 iOS 的后台机制杀掉)。因此,OpenClaw 在 apps/apple 目录下,使用了约 8.9% 的 Swift 原生代码来实现一个端侧轻量级唤醒监听器

端侧只负责一件事:在本地运行一个极小的离线模型(比如基于 Apple 框架或 Porcupine),专门监听唤醒词。

// apps/apple/OpenClawNode/Speech/WakeWordEngine.swift (源码概念简化版)

import AVFoundation
import Speech

class WakeWordEngine: ObservableObject {
    private let audioEngine = AVAudioEngine()
    private let speechRecognizer = SFSpeechRecognizer(locale: Locale(identifier: "en-US"))
    
    func startListening() {
        let inputNode = audioEngine.inputNode
        let recordingFormat = inputNode.outputFormat(forBus: 0)
        
        inputNode.installTap(onBus: 0, bufferSize: 1024, format: recordingFormat) { (buffer, when) in
            // 本地极速分析音频帧,匹配唤醒词
            if self.detectWakeWord(in: buffer) {
                self.triggerGatewayWakeup()
                self.startRecordingCommand() // 唤醒后开始录制真正的指令
            }
        }
        
        try? audioEngine.start()
    }
    
    private func triggerGatewayWakeup() {
        // 通过 WebSocket 通知 Gateway:主人叫你了!
        WebSocketClient.shared.send(event: "NODE_WAKED", payload: ["nodeId": Device.currentId])
    }
}

通过 Swift 原生介入,Mac 和 iPhone 节点可以以极低的功耗在后台常驻。只有听到唤醒词的瞬间,才会打通与 TypeScript 编写的 Gateway 的高耗能长连接。


Android 端侧:持续语音拾音逻辑(Talk Mode)

相比之下,安卓系统的开放性给了 OpenClaw 更多发挥空间。在 apps/android 目录下,OpenClaw 利用 2.1% 的 Kotlin 代码实现了一个非常硬核的“Talk Mode(持续对话模式)”。

在这个模式下,Agent 不再是一问一答,而是通过 VAD(Voice Activity Detection,静音检测) 算法,像真人打语音电话一样持续沟通。

// apps/android/OpenClawNode/audio/VADManager.kt (源码概念简化版)

class VADManager {
    private val threshold = -40.0 // 分贝阈值
    private var isSpeaking = false
    private val audioBufferChunk = mutableListOf<ByteArray>()

    fun processAudioFrame(frame: ByteArray, dbLevel: Double) {
        if (dbLevel > threshold) {
            // 用户正在说话
            if (!isSpeaking) {
                isSpeaking = true
                WebSocketClient.sendEvent("USER_SPEECH_START")
            }
            audioBufferChunk.add(frame)
        } else {
            // 检测到停顿 (例如超过 1.5 秒没有说话)
            if (isSpeaking && hasSilenceExceeded(1500)) {
                isSpeaking = false
                
                // 将刚才的一整段话打包发给 Gateway
                WebSocketClient.sendAudioStream(audioBufferChunk.toByteArray())
                audioBufferChunk.clear()
            }
        }
    }
}

在 Android 端的 Talk Mode 中,VAD 会自动切分你的句子。你停顿思考时,它就把前半句发给云端处理;你继续说,它就继续录。这种体验打破了传统语音助手“说完必须傻等”的僵硬感,实现了真正意义上的全双工(Full-duplex)对话流。


总结

跨平台开发不应该只是简单的套壳(Webview)。OpenClaw 为我们做了一个极佳的示范:

  • 核心业务逻辑 留在 TypeScript(Gateway)中,保证迭代速度与跨平台复用。

  • 高频、底层、敏感的硬件交互(如 iOS 的唤醒词、Android 的 VAD),果断采用 Swift 和 Kotlin 编写 Native Node,以获取系统级最高权限与最优性能。

正是这种“各司其职”的设计,让那只叫 Open Claw 的空间龙虾真正长出了灵敏的“耳朵”和拟真的“嘴巴”。

当我们用语音唤醒了设备之后,AI 还能对这台设备做些什么?仅仅是聊天吗? 敬请期待下一篇,老金带你看看 Agent 是如何跨端调用你的摄像头、截取屏幕,甚至执行本地终端命令的!我们下期见。