Pixel Soul Service 模块复习总览
这组笔记用于重新阅读 Pixel Soul 设备侧项目。它不是源码文档的搬运,而是把每个 Service 模块整理成可复习、可面试表达的工程说明。
components/service 是设备基础能力集合。它把网络、按键、音频、语音识别、会话协议、播放、传感器、时间、SD、电源等能力封装为 App 可组合的 Service。
Service 层维护内部状态和任务,但不直接渲染 UI,不决定页面切换,也不写产品文案。
Application -> Service -> Driver / HAL -> BSP -> ESP-IDF / Hardware建议按链路读,而不是按目录读:
- 基础状态服务:理解事件、snapshot、硬件缺失不阻塞。
- NetworkService:理解网络状态和配网入口。
- AudioService:理解音频资源租约和 ringbuf。
- SRService:理解 WakeNet、Voice Activity、Audio Publish。
- Protocol + WebSocketTask:理解 JSON 控制帧和 binary PCM 传输。
- TTSPlayer:理解下行 PCM 播放和本地停播。
- Session:理解 AI Session owner 和 turn 状态机。
- PowerService:理解电池状态服务设计草案。
核心心智模型
Section titled “核心心智模型”flowchart TD
APP["AppCore / AppAIRuntime"] --> BUTTON["ButtonService"]
APP --> NETWORK["NetworkService"]
APP --> SENSOR["Sensor / Time / SD"]
APP --> SESSION["Session"]
SESSION --> PROTOCOL["Protocol"]
SESSION --> WS["WebSocketTask"]
SESSION --> PLAYER["TTSPlayer"]
SESSION --> SR["SRService"]
SR --> AUDIO["AudioService input"]
PLAYER --> AUDIO_OUT["AudioService output"]
WS --> TX["audio_tx_ringbuf"]
WS --> RX["audio_rx_ringbuf"]
面试时要先讲清楚 owner:
AppCore管产品语义:页面、按键、Footer、是否进入 AI。Session管 AI 会话语义:session、turn、上下行授权、播放完成后的状态。SRService管语音输入执行:WakeNet、Voice Activity、授权后发布 PCM。WebSocketTask管 WebSocket IO:text frame 和 binary frame 搬运。Protocol管 JSON 格式:构建、解析、校验。AudioService管音频硬件资源租约:input/output token。
面试表达模板
Section titled “面试表达模板”回答模块问题时按这个顺序:
1. 这个模块的 owner 是什么。2. 它上游是谁,下游是谁。3. 它不负责什么,边界在哪里。4. 核心流程是什么。5. 为什么不把这些逻辑放到 App 或底层 driver。6. 失败时如何收口。这个顺序比直接背 API 更稳,因为它先回答设计意图,再进入实现细节。
| 笔记 | 覆盖模块 |
|---|---|
| 基础状态服务 | ButtonService、SensorService、TimeService、SdService |
| NetworkService | NetworkService、network_storage、network_portal、network_dns |
| AudioService | AudioService、sr_ringbuf |
| SRService | SRService |
| Session | Session |
| Protocol + WebSocketTask | Protocol、WebSocketTask |
| TTSPlayer | TTSPlayer |
| PowerService | PowerService 设计草案 |
- 能否一句话说清 App / Service / Driver / BSP 的边界?
- 能否说明为什么 UI 读 snapshot,而不是直接读硬件?
- 能否说明为什么
Session是 AI 会话 owner? - 能否画出上行 PCM 和下行 PCM 的路径?
- 能否解释
turn_new为什么是强边界? - 能否解释 KEY 打断为什么先本地停播,再发
turn_terminate?