forked from xiaozhi/xiaozhi-esp32
Compare commits
109 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3a3dfc003e | ||
|
|
fc355605f5 | ||
|
|
5d3f597137 | ||
|
|
3e37551923 | ||
|
|
d09537ed5c | ||
|
|
86921f4862 | ||
|
|
7af366b7b2 | ||
|
|
ddbb24942d | ||
|
|
610a4a0703 | ||
|
|
7cd37427b2 | ||
|
|
2d772dad68 | ||
|
|
156eb15f58 | ||
|
|
c59c515706 | ||
|
|
44b8d5e4c1 | ||
|
|
cc07ef447e | ||
|
|
cf4afde88e | ||
|
|
d6b1414967 | ||
|
|
00dd89079b | ||
|
|
cfb635d870 | ||
|
|
9ae34d3b45 | ||
|
|
08b8b04c6c | ||
|
|
f890acfc7c | ||
|
|
a4fe4d8d99 | ||
|
|
593b495139 | ||
|
|
2a02dd65be | ||
|
|
845b760db3 | ||
|
|
f86637cf1c | ||
|
|
363073658a | ||
|
|
da228f2582 | ||
|
|
36476f05cd | ||
|
|
90602d3802 | ||
|
|
b2e1c5bb5c | ||
|
|
d58d55cfe7 | ||
|
|
cd23e0f155 | ||
|
|
26d9ff283f | ||
|
|
fb85019c3c | ||
|
|
4859d57fea | ||
|
|
03394fe38d | ||
|
|
e0e12450c5 | ||
|
|
e5ac40aac8 | ||
|
|
345c8be467 | ||
|
|
def6301292 | ||
|
|
df7cbdfcb6 | ||
|
|
d38763d5ef | ||
|
|
e90e540933 | ||
|
|
656bf3c7fa | ||
|
|
ca35b0761b | ||
|
|
b031a829c0 | ||
|
|
3c11cceb43 | ||
|
|
15f233e773 | ||
|
|
721b58f8c7 | ||
|
|
eb0bba2c89 | ||
|
|
0d45c636a8 | ||
|
|
3e2bc9ee74 | ||
|
|
6a7a403117 | ||
|
|
d1c047d060 | ||
|
|
a35a344f42 | ||
|
|
efc6f238e7 | ||
|
|
3c71558a5f | ||
|
|
0621578f55 | ||
|
|
5c8707075f | ||
|
|
c68c959e9b | ||
|
|
1aea59a472 | ||
|
|
be46cf1731 | ||
|
|
0c971f76e3 | ||
|
|
6bb95073a4 | ||
|
|
ea8769e1fc | ||
|
|
0b0e1391f0 | ||
|
|
0b364a83b3 | ||
|
|
5da837541b | ||
|
|
cec0b5b273 | ||
|
|
8e0f76c0ef | ||
|
|
f556e72604 | ||
|
|
2cdec25162 | ||
|
|
f002a1185b | ||
|
|
1314ccfc0f | ||
|
|
b7c1989a34 | ||
|
|
10016a3ea5 | ||
|
|
f744c9bf3e | ||
|
|
ad2c187433 | ||
|
|
8a0ec8b657 | ||
|
|
d1c586239c | ||
|
|
f2f54ba1fd | ||
|
|
f1277934d1 | ||
|
|
c17bd15baa | ||
|
|
b3ab3d0920 | ||
|
|
2b0362a812 | ||
|
|
d3367d6b92 | ||
|
|
116234a147 | ||
|
|
f29c1a11d9 | ||
|
|
f98ffdbb5c | ||
|
|
89f10365b1 | ||
|
|
e9f23ea231 | ||
|
|
7435c98609 | ||
|
|
bf125446b3 | ||
|
|
dfad6a5b2c | ||
|
|
d460af8426 | ||
|
|
7bb17f7539 | ||
|
|
f8c9126442 | ||
|
|
a118e8f786 | ||
|
|
85f3f1ba9f | ||
|
|
e2777cc16b | ||
|
|
5bb7c6deb8 | ||
|
|
895a3cfa72 | ||
|
|
c9dec29d73 | ||
|
|
968ed1fae3 | ||
|
|
f8cd0d30cd | ||
|
|
01215d77ed | ||
|
|
3df2f3970a |
112
.github/workflows/build.yml
vendored
112
.github/workflows/build.yml
vendored
@@ -1,32 +1,106 @@
|
||||
name: Build and Test
|
||||
name: Build Boards
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- ci/* # for ci test
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
build:
|
||||
prepare:
|
||||
name: Determine boards to build
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
outputs:
|
||||
boards: ${{ steps.select.outputs.boards }}
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Espressif IoT Development Framework (ESP-IDF)
|
||||
# You may pin to the exact commit or the version.
|
||||
# uses: espressif/esp-idf-ci-action@8cd22ae10042fadc37890e81e9988a9113e7b506
|
||||
uses: espressif/esp-idf-ci-action@v1.1.0
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
# Relative path under $GITHUB_WORKSPACE to place the repository
|
||||
#path: # optional, default is
|
||||
# Version of ESP-IDF docker image to use
|
||||
esp_idf_version: release-v5.4
|
||||
# ESP32 variant to build for
|
||||
target: esp32s3
|
||||
# Command to run inside the docker container (default: builds the project)
|
||||
# command: # optional, default is idf.py build
|
||||
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Install jq
|
||||
run: sudo apt-get update && sudo apt-get install -y jq
|
||||
|
||||
- id: list
|
||||
name: Get all board list
|
||||
run: |
|
||||
echo "all_boards=$(python scripts/release.py --list-boards --json)" >> $GITHUB_OUTPUT
|
||||
|
||||
- id: select
|
||||
name: Select boards based on changes
|
||||
env:
|
||||
ALL_BOARDS: ${{ steps.list.outputs.all_boards }}
|
||||
run: |
|
||||
EVENT_NAME="${{ github.event_name }}"
|
||||
|
||||
# For push to main branch, build all boards
|
||||
if [[ "$EVENT_NAME" == "push" ]]; then
|
||||
echo "boards=$ALL_BOARDS" >> $GITHUB_OUTPUT
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# For pull_request
|
||||
BASE_SHA="${{ github.event.pull_request.base.sha }}"
|
||||
HEAD_SHA="${{ github.event.pull_request.head.sha }}"
|
||||
echo "Base: $BASE_SHA, Head: $HEAD_SHA"
|
||||
|
||||
CHANGED=$(git diff --name-only $BASE_SHA $HEAD_SHA || true)
|
||||
echo "Changed files:\n$CHANGED"
|
||||
|
||||
NEED_ALL=0
|
||||
declare -A AFFECTED
|
||||
while IFS= read -r file; do
|
||||
if [[ "$file" == main/* && "$file" != main/boards/* ]]; then
|
||||
NEED_ALL=1
|
||||
fi
|
||||
|
||||
if [[ "$file" == main/boards/* ]]; then
|
||||
board=$(echo "$file" | cut -d '/' -f3)
|
||||
AFFECTED[$board]=1
|
||||
fi
|
||||
done <<< "$CHANGED"
|
||||
|
||||
if [[ "$NEED_ALL" -eq 1 ]]; then
|
||||
echo "boards=$ALL_BOARDS" >> $GITHUB_OUTPUT
|
||||
else
|
||||
if [[ ${#AFFECTED[@]} -eq 0 ]]; then
|
||||
echo "boards=[]" >> $GITHUB_OUTPUT
|
||||
else
|
||||
JSON=$(printf '%s\n' "${!AFFECTED[@]}" | sort -u | jq -R -s -c 'split("\n")[:-1]')
|
||||
echo "boards=$JSON" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
fi
|
||||
|
||||
build:
|
||||
name: Build ${{ matrix.board }}
|
||||
needs: prepare
|
||||
if: ${{ needs.prepare.outputs.boards != '[]' }}
|
||||
strategy:
|
||||
fail-fast: false # 单个 board 失败不影响其它 board
|
||||
matrix:
|
||||
board: ${{ fromJson(needs.prepare.outputs.boards) }}
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: espressif/idf:release-v5.4
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Build current board
|
||||
shell: bash
|
||||
run: |
|
||||
source $IDF_PATH/export.sh
|
||||
python scripts/release.py ${{ matrix.board }}
|
||||
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: xiaozhi_${{ matrix.board }}_${{ github.sha }}.bin
|
||||
path: build/merged-binary.bin
|
||||
if-no-files-found: error
|
||||
5
.gitignore
vendored
5
.gitignore
vendored
@@ -13,4 +13,7 @@ main/assets/lang_config.h
|
||||
main/mmap_generate_emoji.h
|
||||
.DS_Store
|
||||
.cache
|
||||
main/mmap_generate_emoji.h
|
||||
main/mmap_generate_emoji.h
|
||||
*.pyc
|
||||
*.bin
|
||||
mmap_generate_*.h
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
# CMakeLists in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
set(PROJECT_VER "1.7.2")
|
||||
set(PROJECT_VER "1.9.0")
|
||||
|
||||
# Add this line to disable the specific warning
|
||||
add_compile_options(-Wno-missing-field-initializers)
|
||||
|
||||
3
LICENSE
3
LICENSE
@@ -1,6 +1,7 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2024 Xiaoxia
|
||||
Copyright (c) 2025 Shenzhen Xinzhi Future Technology Co., Ltd.
|
||||
Copyright (c) 2025 Project Contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
我们希望通过这个项目,能够帮助大家了解 AI 硬件开发,将当下飞速发展的大语言模型应用到实际的硬件设备中。
|
||||
|
||||
如果你有任何想法或建议,请随时提出 Issues 或加入 QQ 群:575180511
|
||||
如果你有任何想法或建议,请随时提出 Issues 或加入 QQ 群:1011329060
|
||||
|
||||
### 基于 MCP 控制万物
|
||||
|
||||
@@ -125,11 +125,12 @@
|
||||
- [自定义开发板指南](main/boards/README.md) - 学习如何为小智 AI 创建自定义开发板
|
||||
- [MCP 协议物联网控制用法说明](docs/mcp-usage.md) - 了解如何通过 MCP 协议控制物联网设备
|
||||
- [MCP 协议交互流程](docs/mcp-protocol.md) - 设备端 MCP 协议的实现方式
|
||||
- [MQTT + UDP 混合通信协议文档](docs/mqtt-udp.md)
|
||||
- [一份详细的 WebSocket 通信协议文档](docs/websocket.md)
|
||||
|
||||
## 大模型配置
|
||||
|
||||
如果你已经拥有一个的小智 AI 聊天机器人设备,并且已接入官方服务器,可以登录 [xiaozhi.me](https://xiaozhi.me) 控制台进行配置。
|
||||
如果你已经拥有一个小智 AI 聊天机器人设备,并且已接入官方服务器,可以登录 [xiaozhi.me](https://xiaozhi.me) 控制台进行配置。
|
||||
|
||||
👉 [后台操作视频教程(旧版界面)](https://www.bilibili.com/video/BV1jUCUY2EKM/)
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ This is an open-source ESP32 project, released under the MIT license, allowing a
|
||||
|
||||
We hope this project helps everyone understand AI hardware development and apply rapidly evolving large language models to real hardware devices.
|
||||
|
||||
If you have any ideas or suggestions, please feel free to raise Issues or join the QQ group: 575180511
|
||||
If you have any ideas or suggestions, please feel free to raise Issues or join the QQ group: 1011329060
|
||||
|
||||
### Control Everything with MCP
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
このプロジェクトを通じて、AIハードウェア開発を理解し、急速に進化する大規模言語モデルを実際のハードウェアデバイスに応用できるようになることを目指しています。
|
||||
|
||||
ご意見やご提案があれば、いつでもIssueを提出するか、QQグループ:575180511 にご参加ください。
|
||||
ご意見やご提案があれば、いつでもIssueを提出するか、QQグループ:1011329060 にご参加ください。
|
||||
|
||||
### MCPであらゆるものを制御
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ MCP 的交互主要围绕客户端(后台 API)发现和调用设备上的“
|
||||
|
||||
- **时机:** 设备启动并成功连接到后台 API 后。
|
||||
- **发送方:** 设备。
|
||||
- **消息:** 设备发送基础协议的 "hello" 消息给后台 API,消息中包含设备支持的能力列表,例如通过 `CONFIG_IOT_PROTOCOL_MCP` 配置来表明支持 MCP 协议 (`"mcp": true`)。
|
||||
- **消息:** 设备发送基础协议的 "hello" 消息给后台 API,消息中包含设备支持的能力列表,例如通过支持 MCP 协议 (`"mcp": true`)。
|
||||
- **示例 (非 MCP 负载,而是基础协议消息):**
|
||||
```json
|
||||
{
|
||||
|
||||
393
docs/mqtt-udp.md
Normal file
393
docs/mqtt-udp.md
Normal file
@@ -0,0 +1,393 @@
|
||||
# MQTT + UDP 混合通信协议文档
|
||||
|
||||
基于代码实现整理的 MQTT + UDP 混合通信协议文档,概述设备端与服务器之间如何通过 MQTT 进行控制消息传输,通过 UDP 进行音频数据传输的交互方式。
|
||||
|
||||
---
|
||||
|
||||
## 1. 协议概览
|
||||
|
||||
本协议采用混合传输方式:
|
||||
- **MQTT**:用于控制消息、状态同步、JSON 数据交换
|
||||
- **UDP**:用于实时音频数据传输,支持加密
|
||||
|
||||
### 1.1 协议特点
|
||||
|
||||
- **双通道设计**:控制与数据分离,确保实时性
|
||||
- **加密传输**:UDP 音频数据使用 AES-CTR 加密
|
||||
- **序列号保护**:防止数据包重放和乱序
|
||||
- **自动重连**:MQTT 连接断开时自动重连
|
||||
|
||||
---
|
||||
|
||||
## 2. 总体流程概览
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Device as ESP32 设备
|
||||
participant MQTT as MQTT 服务器
|
||||
participant UDP as UDP 服务器
|
||||
|
||||
Note over Device, UDP: 1. 建立 MQTT 连接
|
||||
Device->>MQTT: MQTT Connect
|
||||
MQTT->>Device: Connected
|
||||
|
||||
Note over Device, UDP: 2. 请求音频通道
|
||||
Device->>MQTT: Hello Message (type: "hello", transport: "udp")
|
||||
MQTT->>Device: Hello Response (UDP 连接信息 + 加密密钥)
|
||||
|
||||
Note over Device, UDP: 3. 建立 UDP 连接
|
||||
Device->>UDP: UDP Connect
|
||||
UDP->>Device: Connected
|
||||
|
||||
Note over Device, UDP: 4. 音频数据传输
|
||||
loop 音频流传输
|
||||
Device->>UDP: 加密音频数据 (Opus)
|
||||
UDP->>Device: 加密音频数据 (Opus)
|
||||
end
|
||||
|
||||
Note over Device, UDP: 5. 控制消息交换
|
||||
par 控制消息
|
||||
Device->>MQTT: Listen/TTS/MCP 消息
|
||||
MQTT->>Device: STT/TTS/MCP 响应
|
||||
end
|
||||
|
||||
Note over Device, UDP: 6. 关闭连接
|
||||
Device->>MQTT: Goodbye Message
|
||||
Device->>UDP: Disconnect
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. MQTT 控制通道
|
||||
|
||||
### 3.1 连接建立
|
||||
|
||||
设备通过 MQTT 连接到服务器,连接参数包括:
|
||||
- **Endpoint**:MQTT 服务器地址和端口
|
||||
- **Client ID**:设备唯一标识符
|
||||
- **Username/Password**:认证凭据
|
||||
- **Keep Alive**:心跳间隔(默认240秒)
|
||||
|
||||
### 3.2 Hello 消息交换
|
||||
|
||||
#### 3.2.1 设备端发送 Hello
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "hello",
|
||||
"version": 3,
|
||||
"transport": "udp",
|
||||
"features": {
|
||||
"mcp": true
|
||||
},
|
||||
"audio_params": {
|
||||
"format": "opus",
|
||||
"sample_rate": 16000,
|
||||
"channels": 1,
|
||||
"frame_duration": 60
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 3.2.2 服务器响应 Hello
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "hello",
|
||||
"transport": "udp",
|
||||
"session_id": "xxx",
|
||||
"audio_params": {
|
||||
"format": "opus",
|
||||
"sample_rate": 24000,
|
||||
"channels": 1,
|
||||
"frame_duration": 60
|
||||
},
|
||||
"udp": {
|
||||
"server": "192.168.1.100",
|
||||
"port": 8888,
|
||||
"key": "0123456789ABCDEF0123456789ABCDEF",
|
||||
"nonce": "0123456789ABCDEF0123456789ABCDEF"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**字段说明:**
|
||||
- `udp.server`:UDP 服务器地址
|
||||
- `udp.port`:UDP 服务器端口
|
||||
- `udp.key`:AES 加密密钥(十六进制字符串)
|
||||
- `udp.nonce`:AES 加密随机数(十六进制字符串)
|
||||
|
||||
### 3.3 JSON 消息类型
|
||||
|
||||
#### 3.3.1 设备端→服务器
|
||||
|
||||
1. **Listen 消息**
|
||||
```json
|
||||
{
|
||||
"session_id": "xxx",
|
||||
"type": "listen",
|
||||
"state": "start",
|
||||
"mode": "manual"
|
||||
}
|
||||
```
|
||||
|
||||
2. **Abort 消息**
|
||||
```json
|
||||
{
|
||||
"session_id": "xxx",
|
||||
"type": "abort",
|
||||
"reason": "wake_word_detected"
|
||||
}
|
||||
```
|
||||
|
||||
3. **MCP 消息**
|
||||
```json
|
||||
{
|
||||
"session_id": "xxx",
|
||||
"type": "mcp",
|
||||
"payload": {
|
||||
"jsonrpc": "2.0",
|
||||
"id": 1,
|
||||
"result": {...}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
4. **Goodbye 消息**
|
||||
```json
|
||||
{
|
||||
"session_id": "xxx",
|
||||
"type": "goodbye"
|
||||
}
|
||||
```
|
||||
|
||||
#### 3.3.2 服务器→设备端
|
||||
|
||||
支持的消息类型与 WebSocket 协议一致,包括:
|
||||
- **STT**:语音识别结果
|
||||
- **TTS**:语音合成控制
|
||||
- **LLM**:情感表达控制
|
||||
- **MCP**:物联网控制
|
||||
- **System**:系统控制
|
||||
- **Custom**:自定义消息(可选)
|
||||
|
||||
---
|
||||
|
||||
## 4. UDP 音频通道
|
||||
|
||||
### 4.1 连接建立
|
||||
|
||||
设备收到 MQTT Hello 响应后,使用其中的 UDP 连接信息建立音频通道:
|
||||
1. 解析 UDP 服务器地址和端口
|
||||
2. 解析加密密钥和随机数
|
||||
3. 初始化 AES-CTR 加密上下文
|
||||
4. 建立 UDP 连接
|
||||
|
||||
### 4.2 音频数据格式
|
||||
|
||||
#### 4.2.1 加密音频包结构
|
||||
|
||||
```
|
||||
|type 1byte|flags 1byte|payload_len 2bytes|ssrc 4bytes|timestamp 4bytes|sequence 4bytes|
|
||||
|payload payload_len bytes|
|
||||
```
|
||||
|
||||
**字段说明:**
|
||||
- `type`:数据包类型,固定为 0x01
|
||||
- `flags`:标志位,当前未使用
|
||||
- `payload_len`:负载长度(网络字节序)
|
||||
- `ssrc`:同步源标识符
|
||||
- `timestamp`:时间戳(网络字节序)
|
||||
- `sequence`:序列号(网络字节序)
|
||||
- `payload`:加密的 Opus 音频数据
|
||||
|
||||
#### 4.2.2 加密算法
|
||||
|
||||
使用 **AES-CTR** 模式加密:
|
||||
- **密钥**:128位,由服务器提供
|
||||
- **随机数**:128位,由服务器提供
|
||||
- **计数器**:包含时间戳和序列号信息
|
||||
|
||||
### 4.3 序列号管理
|
||||
|
||||
- **发送端**:`local_sequence_` 单调递增
|
||||
- **接收端**:`remote_sequence_` 验证连续性
|
||||
- **防重放**:拒绝序列号小于期望值的数据包
|
||||
- **容错处理**:允许轻微的序列号跳跃,记录警告
|
||||
|
||||
### 4.4 错误处理
|
||||
|
||||
1. **解密失败**:记录错误,丢弃数据包
|
||||
2. **序列号异常**:记录警告,但仍处理数据包
|
||||
3. **数据包格式错误**:记录错误,丢弃数据包
|
||||
|
||||
---
|
||||
|
||||
## 5. 状态管理
|
||||
|
||||
### 5.1 连接状态
|
||||
|
||||
```mermaid
|
||||
stateDiagram
|
||||
direction TB
|
||||
[*] --> Disconnected
|
||||
Disconnected --> MqttConnecting: StartMqttClient()
|
||||
MqttConnecting --> MqttConnected: MQTT Connected
|
||||
MqttConnecting --> Disconnected: Connect Failed
|
||||
MqttConnected --> RequestingChannel: OpenAudioChannel()
|
||||
RequestingChannel --> ChannelOpened: Hello Exchange Success
|
||||
RequestingChannel --> MqttConnected: Hello Timeout/Failed
|
||||
ChannelOpened --> UdpConnected: UDP Connect Success
|
||||
UdpConnected --> AudioStreaming: Start Audio Transfer
|
||||
AudioStreaming --> UdpConnected: Stop Audio Transfer
|
||||
UdpConnected --> ChannelOpened: UDP Disconnect
|
||||
ChannelOpened --> MqttConnected: CloseAudioChannel()
|
||||
MqttConnected --> Disconnected: MQTT Disconnect
|
||||
```
|
||||
|
||||
### 5.2 状态检查
|
||||
|
||||
设备通过以下条件判断音频通道是否可用:
|
||||
```cpp
|
||||
bool IsAudioChannelOpened() const {
|
||||
return udp_ != nullptr && !error_occurred_ && !IsTimeout();
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. 配置参数
|
||||
|
||||
### 6.1 MQTT 配置
|
||||
|
||||
从设置中读取的配置项:
|
||||
- `endpoint`:MQTT 服务器地址
|
||||
- `client_id`:客户端标识符
|
||||
- `username`:用户名
|
||||
- `password`:密码
|
||||
- `keepalive`:心跳间隔(默认240秒)
|
||||
- `publish_topic`:发布主题
|
||||
|
||||
### 6.2 音频参数
|
||||
|
||||
- **格式**:Opus
|
||||
- **采样率**:16000 Hz(设备端)/ 24000 Hz(服务器端)
|
||||
- **声道数**:1(单声道)
|
||||
- **帧时长**:60ms
|
||||
|
||||
---
|
||||
|
||||
## 7. 错误处理与重连
|
||||
|
||||
### 7.1 MQTT 重连机制
|
||||
|
||||
- 连接失败时自动重试
|
||||
- 支持错误上报控制
|
||||
- 断线时触发清理流程
|
||||
|
||||
### 7.2 UDP 连接管理
|
||||
|
||||
- 连接失败时不自动重试
|
||||
- 依赖 MQTT 通道重新协商
|
||||
- 支持连接状态查询
|
||||
|
||||
### 7.3 超时处理
|
||||
|
||||
基类 `Protocol` 提供超时检测:
|
||||
- 默认超时时间:120 秒
|
||||
- 基于最后接收时间计算
|
||||
- 超时时自动标记为不可用
|
||||
|
||||
---
|
||||
|
||||
## 8. 安全考虑
|
||||
|
||||
### 8.1 传输加密
|
||||
|
||||
- **MQTT**:支持 TLS/SSL 加密(端口8883)
|
||||
- **UDP**:使用 AES-CTR 加密音频数据
|
||||
|
||||
### 8.2 认证机制
|
||||
|
||||
- **MQTT**:用户名/密码认证
|
||||
- **UDP**:通过 MQTT 通道分发密钥
|
||||
|
||||
### 8.3 防重放攻击
|
||||
|
||||
- 序列号单调递增
|
||||
- 拒绝过期数据包
|
||||
- 时间戳验证
|
||||
|
||||
---
|
||||
|
||||
## 9. 性能优化
|
||||
|
||||
### 9.1 并发控制
|
||||
|
||||
使用互斥锁保护 UDP 连接:
|
||||
```cpp
|
||||
std::lock_guard<std::mutex> lock(channel_mutex_);
|
||||
```
|
||||
|
||||
### 9.2 内存管理
|
||||
|
||||
- 动态创建/销毁网络对象
|
||||
- 智能指针管理音频数据包
|
||||
- 及时释放加密上下文
|
||||
|
||||
### 9.3 网络优化
|
||||
|
||||
- UDP 连接复用
|
||||
- 数据包大小优化
|
||||
- 序列号连续性检查
|
||||
|
||||
---
|
||||
|
||||
## 10. 与 WebSocket 协议的比较
|
||||
|
||||
| 特性 | MQTT + UDP | WebSocket |
|
||||
|------|------------|-----------|
|
||||
| 控制通道 | MQTT | WebSocket |
|
||||
| 音频通道 | UDP (加密) | WebSocket (二进制) |
|
||||
| 实时性 | 高 (UDP) | 中等 |
|
||||
| 可靠性 | 中等 | 高 |
|
||||
| 复杂度 | 高 | 低 |
|
||||
| 加密 | AES-CTR | TLS |
|
||||
| 防火墙友好度 | 低 | 高 |
|
||||
|
||||
---
|
||||
|
||||
## 11. 部署建议
|
||||
|
||||
### 11.1 网络环境
|
||||
|
||||
- 确保 UDP 端口可达
|
||||
- 配置防火墙规则
|
||||
- 考虑 NAT 穿透
|
||||
|
||||
### 11.2 服务器配置
|
||||
|
||||
- MQTT Broker 配置
|
||||
- UDP 服务器部署
|
||||
- 密钥管理系统
|
||||
|
||||
### 11.3 监控指标
|
||||
|
||||
- 连接成功率
|
||||
- 音频传输延迟
|
||||
- 数据包丢失率
|
||||
- 解密失败率
|
||||
|
||||
---
|
||||
|
||||
## 12. 总结
|
||||
|
||||
MQTT + UDP 混合协议通过以下设计实现高效的音视频通信:
|
||||
|
||||
- **分离式架构**:控制与数据通道分离,各司其职
|
||||
- **加密保护**:AES-CTR 确保音频数据安全传输
|
||||
- **序列化管理**:防止重放攻击和数据乱序
|
||||
- **自动恢复**:支持连接断开后的自动重连
|
||||
- **性能优化**:UDP 传输保证音频数据的实时性
|
||||
|
||||
该协议适用于对实时性要求较高的语音交互场景,但需要在网络复杂度和传输性能之间做出权衡。
|
||||
@@ -84,7 +84,7 @@
|
||||
在建立 WebSocket 连接时,代码示例中设置了以下请求头:
|
||||
|
||||
- `Authorization`: 用于存放访问令牌,形如 `"Bearer <token>"`
|
||||
- `Protocol-Version`: 固定示例中为 `"1"`,与 hello 消息体内的 `version` 字段保持一致
|
||||
- `Protocol-Version`: 协议版本号,与 hello 消息体内的 `version` 字段保持一致
|
||||
- `Device-Id`: 设备物理网卡 MAC 地址
|
||||
- `Client-Id`: 软件生成的 UUID(擦除 NVS 或重新烧录完整固件会重置)
|
||||
|
||||
@@ -92,11 +92,44 @@
|
||||
|
||||
---
|
||||
|
||||
## 3. JSON 消息结构
|
||||
## 3. 二进制协议版本
|
||||
|
||||
设备支持多种二进制协议版本,通过配置中的 `version` 字段指定:
|
||||
|
||||
### 3.1 版本1(默认)
|
||||
直接发送 Opus 音频数据,无额外元数据。Websocket 协议会区分 text 与 binary。
|
||||
|
||||
### 3.2 版本2
|
||||
使用 `BinaryProtocol2` 结构:
|
||||
```c
|
||||
struct BinaryProtocol2 {
|
||||
uint16_t version; // 协议版本
|
||||
uint16_t type; // 消息类型 (0: OPUS, 1: JSON)
|
||||
uint32_t reserved; // 保留字段
|
||||
uint32_t timestamp; // 时间戳(毫秒,用于服务器端AEC)
|
||||
uint32_t payload_size; // 负载大小(字节)
|
||||
uint8_t payload[]; // 负载数据
|
||||
} __attribute__((packed));
|
||||
```
|
||||
|
||||
### 3.3 版本3
|
||||
使用 `BinaryProtocol3` 结构:
|
||||
```c
|
||||
struct BinaryProtocol3 {
|
||||
uint8_t type; // 消息类型
|
||||
uint8_t reserved; // 保留字段
|
||||
uint16_t payload_size; // 负载大小
|
||||
uint8_t payload[]; // 负载数据
|
||||
} __attribute__((packed));
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. JSON 消息结构
|
||||
|
||||
WebSocket 文本帧以 JSON 方式传输,以下为常见的 `"type"` 字段及其对应业务逻辑。若消息里包含未列出的字段,可能为可选或特定实现细节。
|
||||
|
||||
### 3.1 设备端→服务器
|
||||
### 4.1 设备端→服务器
|
||||
|
||||
1. **Hello**
|
||||
- 连接成功后,由设备端发送,告知服务器基本参数。
|
||||
@@ -183,7 +216,7 @@ WebSocket 文本帧以 JSON 方式传输,以下为常见的 `"type"` 字段及
|
||||
|
||||
---
|
||||
|
||||
### 3.2 服务器→设备端
|
||||
### 4.2 服务器→设备端
|
||||
|
||||
1. **Hello**
|
||||
- 服务器端返回的握手确认消息。
|
||||
@@ -227,17 +260,43 @@ WebSocket 文本帧以 JSON 方式传输,以下为常见的 `"type"` 字段及
|
||||
}
|
||||
```
|
||||
|
||||
6. **音频数据:二进制帧**
|
||||
6. **System**
|
||||
- 系统控制命令,常用于远程升级更新。
|
||||
- 例:
|
||||
```json
|
||||
{
|
||||
"session_id": "xxx",
|
||||
"type": "system",
|
||||
"command": "reboot"
|
||||
}
|
||||
```
|
||||
- 支持的命令:
|
||||
- `"reboot"`:重启设备
|
||||
|
||||
7. **Custom**(可选)
|
||||
- 自定义消息,当 `CONFIG_RECEIVE_CUSTOM_MESSAGE` 启用时支持。
|
||||
- 例:
|
||||
```json
|
||||
{
|
||||
"session_id": "xxx",
|
||||
"type": "custom",
|
||||
"payload": {
|
||||
"message": "自定义内容"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
8. **音频数据:二进制帧**
|
||||
- 当服务器发送音频二进制帧(Opus 编码)时,设备端解码并播放。
|
||||
- 若设备端正在处于 "listening" (录音)状态,收到的音频帧会被忽略或清空以防冲突。
|
||||
|
||||
---
|
||||
|
||||
## 4. 音频编解码
|
||||
## 5. 音频编解码
|
||||
|
||||
1. **设备端发送录音数据**
|
||||
- 音频输入经过可能的回声消除、降噪或音量增益后,通过 Opus 编码打包为二进制帧发送给服务器。
|
||||
- 如果设备端每次编码生成的二进制帧大小为 N 字节,则会通过 WebSocket 的 **binary** 消息发送这块数据。
|
||||
- 根据协议版本,可能直接发送 Opus 数据(版本1)或使用带元数据的二进制协议(版本2/3)。
|
||||
|
||||
2. **设备端播放收到的音频**
|
||||
- 收到服务器的二进制帧时,同样认定是 Opus 数据。
|
||||
@@ -246,7 +305,7 @@ WebSocket 文本帧以 JSON 方式传输,以下为常见的 `"type"` 字段及
|
||||
|
||||
---
|
||||
|
||||
## 5. 常见状态流转
|
||||
## 6. 常见状态流转
|
||||
|
||||
以下为常见设备端关键状态流转,与 WebSocket 消息对应:
|
||||
|
||||
@@ -307,7 +366,7 @@ stateDiagram
|
||||
|
||||
---
|
||||
|
||||
## 6. 错误处理
|
||||
## 7. 错误处理
|
||||
|
||||
1. **连接失败**
|
||||
- 如果 `Connect(url)` 返回失败或在等待服务器 "hello" 消息时超时,触发 `on_network_error_()` 回调。设备会提示"无法连接到服务"或类似错误信息。
|
||||
@@ -319,7 +378,7 @@ stateDiagram
|
||||
|
||||
---
|
||||
|
||||
## 7. 其它注意事项
|
||||
## 8. 其它注意事项
|
||||
|
||||
1. **鉴权**
|
||||
- 设备通过设置 `Authorization: Bearer <token>` 提供鉴权,服务器端需验证是否有效。
|
||||
@@ -331,17 +390,23 @@ stateDiagram
|
||||
3. **音频负载**
|
||||
- 代码里默认使用 Opus 格式,并设置 `sample_rate = 16000`,单声道。帧时长由 `OPUS_FRAME_DURATION_MS` 控制,一般为 60ms。可根据带宽或性能做适当调整。为了获得更好的音乐播放效果,服务器下行音频可能使用 24000 采样率。
|
||||
|
||||
4. **物联网控制推荐 MCP 协议**
|
||||
4. **协议版本配置**
|
||||
- 通过设置中的 `version` 字段配置二进制协议版本(1、2 或 3)
|
||||
- 版本1:直接发送 Opus 数据
|
||||
- 版本2:使用带时间戳的二进制协议,适用于服务器端 AEC
|
||||
- 版本3:使用简化的二进制协议
|
||||
|
||||
5. **物联网控制推荐 MCP 协议**
|
||||
- 设备与服务器之间的物联网能力发现、状态同步、控制指令等,建议全部通过 MCP 协议(type: "mcp")实现。原有的 type: "iot" 方案已废弃。
|
||||
- MCP 协议可在 WebSocket、MQTT 等多种底层协议上传输,具备更好的扩展性和标准化能力。
|
||||
- 详细用法请参考 [MCP 协议文档](./mcp-protocol.md) 及 [MCP 物联网控制用法](./mcp-usage.md)。
|
||||
|
||||
5. **错误或异常 JSON**
|
||||
6. **错误或异常 JSON**
|
||||
- 当 JSON 中缺少必要字段,例如 `{"type": ...}`,设备端会记录错误日志(`ESP_LOGE(TAG, "Missing message type, data: %s", data);`),不会执行任何业务。
|
||||
|
||||
---
|
||||
|
||||
## 8. 消息示例
|
||||
## 9. 消息示例
|
||||
|
||||
下面给出一个典型的双向消息示例(流程简化示意):
|
||||
|
||||
@@ -418,13 +483,13 @@ stateDiagram
|
||||
|
||||
---
|
||||
|
||||
## 9. 总结
|
||||
## 10. 总结
|
||||
|
||||
本协议通过在 WebSocket 上层传输 JSON 文本与二进制音频帧,完成功能包括音频流上传、TTS 音频播放、语音识别与状态管理、MCP 指令下发等。其核心特征:
|
||||
|
||||
- **握手阶段**:发送 `"type":"hello"`,等待服务器返回。
|
||||
- **音频通道**:采用 Opus 编码的二进制帧双向传输语音流。
|
||||
- **JSON 消息**:使用 `"type"` 为核心字段标识不同业务逻辑,包括 TTS、STT、MCP、WakeWord 等。
|
||||
- **音频通道**:采用 Opus 编码的二进制帧双向传输语音流,支持多种协议版本。
|
||||
- **JSON 消息**:使用 `"type"` 为核心字段标识不同业务逻辑,包括 TTS、STT、MCP、WakeWord、System、Custom 等。
|
||||
- **扩展性**:可根据实际需求在 JSON 消息中添加字段,或在 headers 里进行额外鉴权。
|
||||
|
||||
服务器与设备端需提前约定各类消息的字段含义、时序逻辑以及错误处理规则,方能保证通信顺畅。上述信息可作为基础文档,便于后续对接、开发或扩展。
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
set(SOURCES "audio_codecs/audio_codec.cc"
|
||||
"audio_codecs/no_audio_codec.cc"
|
||||
"audio_codecs/box_audio_codec.cc"
|
||||
"audio_codecs/es8311_audio_codec.cc"
|
||||
"audio_codecs/es8374_audio_codec.cc"
|
||||
"audio_codecs/es8388_audio_codec.cc"
|
||||
"audio_processing/audio_debugger.cc"
|
||||
set(SOURCES "audio/audio_codec.cc"
|
||||
"audio/audio_service.cc"
|
||||
"audio/codecs/no_audio_codec.cc"
|
||||
"audio/codecs/box_audio_codec.cc"
|
||||
"audio/codecs/es8311_audio_codec.cc"
|
||||
"audio/codecs/es8374_audio_codec.cc"
|
||||
"audio/codecs/es8388_audio_codec.cc"
|
||||
"audio/codecs/es8389_audio_codec.cc"
|
||||
"audio/codecs/dummy_audio_codec.cc"
|
||||
"audio/processors/audio_debugger.cc"
|
||||
"led/single_led.cc"
|
||||
"led/circular_strip.cc"
|
||||
"led/gpio_led.cc"
|
||||
@@ -14,22 +17,16 @@ set(SOURCES "audio_codecs/audio_codec.cc"
|
||||
"protocols/protocol.cc"
|
||||
"protocols/mqtt_protocol.cc"
|
||||
"protocols/websocket_protocol.cc"
|
||||
"iot/thing.cc"
|
||||
"iot/thing_manager.cc"
|
||||
"mcp_server.cc"
|
||||
"system_info.cc"
|
||||
"application.cc"
|
||||
"ota.cc"
|
||||
"settings.cc"
|
||||
"background_task.cc"
|
||||
"device_state_event.cc"
|
||||
"main.cc"
|
||||
)
|
||||
|
||||
set(INCLUDE_DIRS "." "display" "audio_codecs" "protocols" "audio_processing")
|
||||
|
||||
# 添加 IOT 相关文件
|
||||
file(GLOB IOT_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/iot/things/*.cc)
|
||||
list(APPEND SOURCES ${IOT_SOURCES})
|
||||
set(INCLUDE_DIRS "." "display" "audio" "protocols")
|
||||
|
||||
# 添加板级公共文件
|
||||
file(GLOB BOARD_COMMON_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/boards/common/*.cc)
|
||||
@@ -89,8 +86,14 @@ elseif(CONFIG_BOARD_TYPE_ATOMS3R_ECHO_BASE)
|
||||
set(BOARD_TYPE "atoms3r-echo-base")
|
||||
elseif(CONFIG_BOARD_TYPE_ATOMS3R_CAM_M12_ECHO_BASE)
|
||||
set(BOARD_TYPE "atoms3r-cam-m12-echo-base")
|
||||
elseif(CONFIG_BOARD_TYPE_ATOM_ECHOS3R)
|
||||
set(BOARD_TYPE "atom-echos3r")
|
||||
elseif(CONFIG_BOARD_TYPE_ATOMMATRIX_ECHO_BASE)
|
||||
set(BOARD_TYPE "atommatrix-echo-base")
|
||||
elseif(CONFIG_BOARD_TYPE_XMINI_C3_V3)
|
||||
set(BOARD_TYPE "xmini-c3-v3")
|
||||
elseif(CONFIG_BOARD_TYPE_XMINI_C3_4G)
|
||||
set(BOARD_TYPE "xmini-c3-4g")
|
||||
elseif(CONFIG_BOARD_TYPE_XMINI_C3)
|
||||
set(BOARD_TYPE "xmini-c3")
|
||||
elseif(CONFIG_BOARD_TYPE_ESP32S3_KORVO2_V3)
|
||||
@@ -101,8 +104,14 @@ elseif(CONFIG_BOARD_TYPE_ESP_SPOT_S3)
|
||||
set(BOARD_TYPE "esp-spot-s3")
|
||||
elseif(CONFIG_BOARD_TYPE_ESP_HI)
|
||||
set(BOARD_TYPE "esp-hi")
|
||||
elseif(CONFIG_BOARD_TYPE_ECHOEAR)
|
||||
set(BOARD_TYPE "echoear")
|
||||
elseif(CONFIG_BOARD_TYPE_ESP32S3_AUDIO_BOARD)
|
||||
set(BOARD_TYPE "waveshare-s3-audio-board")
|
||||
elseif(CONFIG_BOARD_TYPE_ESP32S3_Touch_AMOLED_1_8)
|
||||
set(BOARD_TYPE "esp32-s3-touch-amoled-1.8")
|
||||
elseif(CONFIG_BOARD_TYPE_ESP32S3_Touch_AMOLED_2_06)
|
||||
set(BOARD_TYPE "waveshare-s3-touch-amoled-2.06")
|
||||
elseif(CONFIG_BOARD_TYPE_ESP32S3_Touch_AMOLED_1_75)
|
||||
set(BOARD_TYPE "waveshare-s3-touch-amoled-1.75")
|
||||
elseif(CONFIG_BOARD_TYPE_ESP32S3_Touch_LCD_1_85C)
|
||||
@@ -113,6 +122,12 @@ elseif(CONFIG_BOARD_TYPE_ESP32S3_Touch_LCD_1_46)
|
||||
set(BOARD_TYPE "esp32-s3-touch-lcd-1.46")
|
||||
elseif(CONFIG_BOARD_TYPE_ESP32S3_Touch_LCD_3_5)
|
||||
set(BOARD_TYPE "esp32-s3-touch-lcd-3.5")
|
||||
elseif(CONFIG_BOARD_TYPE_ESP32S3_Touch_LCD_3_5B)
|
||||
set(BOARD_TYPE "waveshare-s3-touch-lcd-3.5b")
|
||||
elseif(CONFIG_BOARD_TYPE_ESP32C6_LCD_1_69)
|
||||
set(BOARD_TYPE "waveshare-c6-lcd-1.69")
|
||||
elseif(CONFIG_BOARD_TYPE_ESP32C6_Touch_AMOLED_1_43)
|
||||
set(BOARD_TYPE "waveshare-c6-touch-amoled-1.43")
|
||||
elseif(CONFIG_BOARD_TYPE_ESP32P4_NANO)
|
||||
set(BOARD_TYPE "waveshare-p4-nano")
|
||||
elseif(CONFIG_BOARD_TYPE_ESP32P4_WIFI6_Touch_LCD_4B)
|
||||
@@ -143,6 +158,10 @@ elseif(CONFIG_BOARD_TYPE_ATK_DNESP32S3_BOX)
|
||||
set(BOARD_TYPE "atk-dnesp32s3-box")
|
||||
elseif(CONFIG_BOARD_TYPE_ATK_DNESP32S3_BOX0)
|
||||
set(BOARD_TYPE "atk-dnesp32s3-box0")
|
||||
elseif(CONFIG_BOARD_TYPE_ATK_DNESP32S3_BOX2_WIFI)
|
||||
set(BOARD_TYPE "atk-dnesp32s3-box2-wifi")
|
||||
elseif(CONFIG_BOARD_TYPE_ATK_DNESP32S3_BOX2_4G)
|
||||
set(BOARD_TYPE "atk-dnesp32s3-box2-4g")
|
||||
elseif(CONFIG_BOARD_TYPE_ATK_DNESP32S3M_WIFI)
|
||||
set(BOARD_TYPE "atk-dnesp32s3m-wifi")
|
||||
elseif(CONFIG_BOARD_TYPE_ATK_DNESP32S3M_4G)
|
||||
@@ -177,6 +196,8 @@ elseif(CONFIG_BOARD_TYPE_ESP32_CGC_144)
|
||||
set(BOARD_TYPE "esp32-cgc-144")
|
||||
elseif(CONFIG_BOARD_TYPE_ESP_S3_LCD_EV_Board)
|
||||
set(BOARD_TYPE "esp-s3-lcd-ev-board")
|
||||
elseif(CONFIG_BOARD_TYPE_ESP_S3_LCD_EV_Board_2)
|
||||
set(BOARD_TYPE "esp-s3-lcd-ev-board-2")
|
||||
elseif(CONFIG_BOARD_TYPE_ZHENGCHEN_1_54TFT_WIFI)
|
||||
set(BOARD_TYPE "zhengchen-1.54tft-wifi")
|
||||
elseif(CONFIG_BOARD_TYPE_MINSI_K08_DUAL)
|
||||
@@ -191,6 +212,16 @@ elseif(CONFIG_BOARD_TYPE_OTTO_ROBOT)
|
||||
set(BOARD_TYPE "otto-robot")
|
||||
elseif(CONFIG_BOARD_TYPE_ELECTRON_BOT)
|
||||
set(BOARD_TYPE "electron-bot")
|
||||
elseif(CONFIG_BOARD_TYPE_BREAD_COMPACT_WIFI_CAM)
|
||||
set(BOARD_TYPE "bread-compact-wifi-s3cam")
|
||||
elseif(CONFIG_BOARD_TYPE_JIUCHUAN)
|
||||
set(BOARD_TYPE "jiuchuan-s3")
|
||||
elseif(CONFIG_BOARD_TYPE_LABPLUS_MPYTHON_V3)
|
||||
set(BOARD_TYPE "labplus-mpython-v3")
|
||||
elseif(CONFIG_BOARD_TYPE_LABPLUS_LEDONG_V2)
|
||||
set(BOARD_TYPE "labplus-ledong-v2")
|
||||
elseif(CONFIG_BOARD_TYPE_SURFER_C3_1_14TFT)
|
||||
set(BOARD_TYPE "surfer-c3-1.14tft")
|
||||
endif()
|
||||
file(GLOB BOARD_SOURCES
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/boards/${BOARD_TYPE}/*.cc
|
||||
@@ -199,16 +230,16 @@ file(GLOB BOARD_SOURCES
|
||||
list(APPEND SOURCES ${BOARD_SOURCES})
|
||||
|
||||
if(CONFIG_USE_AUDIO_PROCESSOR)
|
||||
list(APPEND SOURCES "audio_processing/afe_audio_processor.cc")
|
||||
list(APPEND SOURCES "audio/processors/afe_audio_processor.cc")
|
||||
else()
|
||||
list(APPEND SOURCES "audio_processing/no_audio_processor.cc")
|
||||
list(APPEND SOURCES "audio/processors/no_audio_processor.cc")
|
||||
endif()
|
||||
if(CONFIG_USE_AFE_WAKE_WORD)
|
||||
list(APPEND SOURCES "audio_processing/afe_wake_word.cc")
|
||||
list(APPEND SOURCES "audio/wake_words/afe_wake_word.cc")
|
||||
elseif(CONFIG_USE_ESP_WAKE_WORD)
|
||||
list(APPEND SOURCES "audio_processing/esp_wake_word.cc")
|
||||
else()
|
||||
list(APPEND SOURCES "audio_processing/no_wake_word.cc")
|
||||
list(APPEND SOURCES "audio/wake_words/esp_wake_word.cc")
|
||||
elseif(CONFIG_USE_CUSTOM_WAKE_WORD)
|
||||
list(APPEND SOURCES "audio/wake_words/custom_wake_word.cc")
|
||||
endif()
|
||||
|
||||
# 根据Kconfig选择语言目录
|
||||
@@ -220,18 +251,55 @@ elseif(CONFIG_LANGUAGE_EN_US)
|
||||
set(LANG_DIR "en-US")
|
||||
elseif(CONFIG_LANGUAGE_JA_JP)
|
||||
set(LANG_DIR "ja-JP")
|
||||
elseif(CONFIG_LANGUAGE_KO_KR)
|
||||
set(LANG_DIR "ko-KR")
|
||||
elseif(CONFIG_LANGUAGE_VI_VN)
|
||||
set(LANG_DIR "vi-VN")
|
||||
elseif(CONFIG_LANGUAGE_TH_TH)
|
||||
set(LANG_DIR "th-TH")
|
||||
elseif(CONFIG_LANGUAGE_DE_DE)
|
||||
set(LANG_DIR "de-DE")
|
||||
elseif(CONFIG_LANGUAGE_FR_FR)
|
||||
set(LANG_DIR "fr-FR")
|
||||
elseif(CONFIG_LANGUAGE_ES_ES)
|
||||
set(LANG_DIR "es-ES")
|
||||
elseif(CONFIG_LANGUAGE_IT_IT)
|
||||
set(LANG_DIR "it-IT")
|
||||
elseif(CONFIG_LANGUAGE_RU_RU)
|
||||
set(LANG_DIR "ru-RU")
|
||||
elseif(CONFIG_LANGUAGE_AR_SA)
|
||||
set(LANG_DIR "ar-SA")
|
||||
elseif(CONFIG_LANGUAGE_HI_IN)
|
||||
set(LANG_DIR "hi-IN")
|
||||
elseif(CONFIG_LANGUAGE_PT_PT)
|
||||
set(LANG_DIR "pt-PT")
|
||||
elseif(CONFIG_LANGUAGE_PL_PL)
|
||||
set(LANG_DIR "pl-PL")
|
||||
elseif(CONFIG_LANGUAGE_CS_CZ)
|
||||
set(LANG_DIR "cs-CZ")
|
||||
elseif(CONFIG_LANGUAGE_FI_FI)
|
||||
set(LANG_DIR "fi-FI")
|
||||
elseif(CONFIG_LANGUAGE_TR_TR)
|
||||
set(LANG_DIR "tr-TR")
|
||||
elseif(CONFIG_LANGUAGE_ID_ID)
|
||||
set(LANG_DIR "id-ID")
|
||||
elseif(CONFIG_LANGUAGE_UK_UA)
|
||||
set(LANG_DIR "uk-UA")
|
||||
elseif(CONFIG_LANGUAGE_RO_RO)
|
||||
set(LANG_DIR "ro-RO")
|
||||
endif()
|
||||
|
||||
# 定义生成路径
|
||||
set(LANG_JSON "${CMAKE_CURRENT_SOURCE_DIR}/assets/${LANG_DIR}/language.json")
|
||||
set(LANG_JSON "${CMAKE_CURRENT_SOURCE_DIR}/assets/locales/${LANG_DIR}/language.json")
|
||||
set(LANG_HEADER "${CMAKE_CURRENT_SOURCE_DIR}/assets/lang_config.h")
|
||||
file(GLOB LANG_SOUNDS ${CMAKE_CURRENT_SOURCE_DIR}/assets/${LANG_DIR}/*.p3)
|
||||
file(GLOB COMMON_SOUNDS ${CMAKE_CURRENT_SOURCE_DIR}/assets/common/*.p3)
|
||||
file(GLOB LANG_SOUNDS ${CMAKE_CURRENT_SOURCE_DIR}/assets/locales/${LANG_DIR}/*.ogg)
|
||||
file(GLOB COMMON_SOUNDS ${CMAKE_CURRENT_SOURCE_DIR}/assets/common/*.ogg)
|
||||
|
||||
# 如果目标芯片是 ESP32,则排除特定文件
|
||||
if(CONFIG_IDF_TARGET_ESP32)
|
||||
list(REMOVE_ITEM SOURCES "audio_codecs/box_audio_codec.cc"
|
||||
"audio_codecs/es8388_audio_codec.cc"
|
||||
list(REMOVE_ITEM SOURCES "audio/codecs/box_audio_codec.cc"
|
||||
"audio/codecs/es8388_audio_codec.cc"
|
||||
"audio/codecs/es8389_audio_codec.cc"
|
||||
"led/gpio_led.cc"
|
||||
)
|
||||
endif()
|
||||
@@ -255,7 +323,7 @@ target_compile_definitions(${COMPONENT_LIB}
|
||||
add_custom_command(
|
||||
OUTPUT ${LANG_HEADER}
|
||||
COMMAND python ${PROJECT_DIR}/scripts/gen_lang.py
|
||||
--input "${LANG_JSON}"
|
||||
--language "${LANG_DIR}"
|
||||
--output "${LANG_HEADER}"
|
||||
DEPENDS
|
||||
${LANG_JSON}
|
||||
@@ -310,3 +378,24 @@ spiffs_create_partition_assets(
|
||||
MMAP_FILE_SUPPORT_FORMAT ".aaf"
|
||||
)
|
||||
endif()
|
||||
|
||||
if(CONFIG_BOARD_TYPE_ECHOEAR)
|
||||
|
||||
idf_build_get_property(build_components BUILD_COMPONENTS)
|
||||
foreach(COMPONENT ${build_components})
|
||||
if(COMPONENT MATCHES "esp_emote_gfx" OR COMPONENT MATCHES "espressif2022__esp_emote_gfx")
|
||||
set(EMOTE_GFX_COMPONENT ${COMPONENT})
|
||||
idf_component_get_property(EMOTE_GFX_COMPONENT_PATH ${EMOTE_GFX_COMPONENT} COMPONENT_DIR)
|
||||
set(SPIFFS_DIR "${EMOTE_GFX_COMPONENT_PATH}/emoji_normal")
|
||||
break()
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
spiffs_create_partition_assets(
|
||||
assets_A
|
||||
${SPIFFS_DIR}
|
||||
FLASH_IN_PROJECT
|
||||
MMAP_FILE_SUPPORT_FORMAT ".aaf, ttf, bin"
|
||||
IMPORT_INC_PATH ${CMAKE_CURRENT_SOURCE_DIR}/boards/${BOARD_TYPE}
|
||||
)
|
||||
endif()
|
||||
|
||||
@@ -21,6 +21,42 @@ choice
|
||||
bool "English"
|
||||
config LANGUAGE_JA_JP
|
||||
bool "Japanese"
|
||||
config LANGUAGE_KO_KR
|
||||
bool "Korean"
|
||||
config LANGUAGE_VI_VN
|
||||
bool "Vietnamese"
|
||||
config LANGUAGE_TH_TH
|
||||
bool "Thai"
|
||||
config LANGUAGE_DE_DE
|
||||
bool "German"
|
||||
config LANGUAGE_FR_FR
|
||||
bool "French"
|
||||
config LANGUAGE_ES_ES
|
||||
bool "Spanish"
|
||||
config LANGUAGE_IT_IT
|
||||
bool "Italian"
|
||||
config LANGUAGE_RU_RU
|
||||
bool "Russian"
|
||||
config LANGUAGE_AR_SA
|
||||
bool "Arabic"
|
||||
config LANGUAGE_HI_IN
|
||||
bool "Hindi"
|
||||
config LANGUAGE_PT_PT
|
||||
bool "Portuguese"
|
||||
config LANGUAGE_PL_PL
|
||||
bool "Polish"
|
||||
config LANGUAGE_CS_CZ
|
||||
bool "Czech"
|
||||
config LANGUAGE_FI_FI
|
||||
bool "Finnish"
|
||||
config LANGUAGE_TR_TR
|
||||
bool "Turkish"
|
||||
config LANGUAGE_ID_ID
|
||||
bool "Indonesian"
|
||||
config LANGUAGE_UK_UA
|
||||
bool "Ukrainian"
|
||||
config LANGUAGE_RO_RO
|
||||
bool "Romanian"
|
||||
endchoice
|
||||
|
||||
choice BOARD_TYPE
|
||||
@@ -34,6 +70,9 @@ choice BOARD_TYPE
|
||||
config BOARD_TYPE_BREAD_COMPACT_WIFI_LCD
|
||||
bool "面包板新版接线(WiFi)+ LCD"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_BREAD_COMPACT_WIFI_CAM
|
||||
bool "面包板新版接线(WiFi)+ LCD + Camera"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_BREAD_COMPACT_ML307
|
||||
bool "面包板新版接线(ML307 AT)"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
@@ -43,6 +82,12 @@ choice BOARD_TYPE
|
||||
config BOARD_TYPE_BREAD_COMPACT_ESP32_LCD
|
||||
bool "面包板(WiFi+ LCD) ESP32 DevKit"
|
||||
depends on IDF_TARGET_ESP32
|
||||
config BOARD_TYPE_XMINI_C3_V3
|
||||
bool "虾哥 Mini C3 V3"
|
||||
depends on IDF_TARGET_ESP32C3
|
||||
config BOARD_TYPE_XMINI_C3_4G
|
||||
bool "虾哥 Mini C3 4G"
|
||||
depends on IDF_TARGET_ESP32C3
|
||||
config BOARD_TYPE_XMINI_C3
|
||||
bool "虾哥 Mini C3"
|
||||
depends on IDF_TARGET_ESP32C3
|
||||
@@ -58,6 +103,9 @@ choice BOARD_TYPE
|
||||
config BOARD_TYPE_ESP_HI
|
||||
bool "ESP-HI"
|
||||
depends on IDF_TARGET_ESP32C3
|
||||
config BOARD_TYPE_ECHOEAR
|
||||
bool "EchoEar"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_ESP_BOX_3
|
||||
bool "ESP BOX 3"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
@@ -130,12 +178,20 @@ choice BOARD_TYPE
|
||||
config BOARD_TYPE_ATOMS3R_CAM_M12_ECHO_BASE
|
||||
bool "AtomS3R CAM/M12 + Echo Base"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_ATOM_ECHOS3R
|
||||
bool "AtomEchoS3R"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_ATOMMATRIX_ECHO_BASE
|
||||
bool "AtomMatrix + Echo Base"
|
||||
depends on IDF_TARGET_ESP32
|
||||
config BOARD_TYPE_ESP32S3_AUDIO_BOARD
|
||||
bool "Waveshare ESP32-S3-Audio-Board"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_ESP32S3_Touch_AMOLED_1_8
|
||||
bool "Waveshare ESP32-S3-Touch-AMOLED-1.8"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_ESP32S3_Touch_AMOLED_2_06
|
||||
bool "Waveshare ESP32-S3-Touch-AMOLED-2.06"
|
||||
config BOARD_TYPE_ESP32S3_Touch_AMOLED_1_75
|
||||
bool "Waveshare ESP32-S3-Touch-AMOLED-1.75"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
@@ -148,9 +204,18 @@ choice BOARD_TYPE
|
||||
config BOARD_TYPE_ESP32S3_Touch_LCD_1_46
|
||||
bool "Waveshare ESP32-S3-Touch-LCD-1.46"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_ESP32C6_LCD_1_69
|
||||
bool "Waveshare ESP32-C6-LCD-1.69"
|
||||
depends on IDF_TARGET_ESP32C6
|
||||
config BOARD_TYPE_ESP32C6_Touch_AMOLED_1_43
|
||||
bool "Waveshare ESP32-C6-Touch-AMOLOED-1.43"
|
||||
depends on IDF_TARGET_ESP32C6
|
||||
config BOARD_TYPE_ESP32S3_Touch_LCD_3_5
|
||||
bool "Waveshare ESP32-S3-Touch-LCD-3.5"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_ESP32S3_Touch_LCD_3_5B
|
||||
bool "Waveshare ESP32-S3-Touch-LCD-3.5B"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_ESP32P4_NANO
|
||||
bool "Waveshare ESP32-P4-NANO"
|
||||
depends on IDF_TARGET_ESP32P4
|
||||
@@ -193,6 +258,12 @@ choice BOARD_TYPE
|
||||
config BOARD_TYPE_ATK_DNESP32S3_BOX0
|
||||
bool "正点原子DNESP32S3-BOX0"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_ATK_DNESP32S3_BOX2_WIFI
|
||||
bool "正点原子DNESP32S3-BOX2-WIFI"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_ATK_DNESP32S3_BOX2_4G
|
||||
bool "正点原子DNESP32S3-BOX2-4G"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_ATK_DNESP32S3M_WIFI
|
||||
bool "正点原子DNESP32S3M-WIFI"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
@@ -238,6 +309,9 @@ choice BOARD_TYPE
|
||||
config BOARD_TYPE_ESP_S3_LCD_EV_Board
|
||||
bool "乐鑫ESP S3 LCD EV Board开发板"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_ESP_S3_LCD_EV_Board_2
|
||||
bool "乐鑫ESP S3 LCD EV Board 2开发板"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_ZHENGCHEN_1_54TFT_WIFI
|
||||
bool "征辰科技1.54(WIFI)"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
@@ -263,6 +337,18 @@ choice BOARD_TYPE
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
select LV_USE_GIF
|
||||
select LV_GIF_CACHE_DECODE_DATA
|
||||
config BOARD_TYPE_JIUCHUAN
|
||||
bool "九川智能"
|
||||
config BOARD_TYPE_LABPLUS_MPYTHON_V3
|
||||
bool "labplus mpython_v3 board"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_LABPLUS_LEDONG_V2
|
||||
bool "labplus ledong_v2 board"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
config BOARD_TYPE_SURFER_C3_1_14TFT
|
||||
bool "Surfer-C3-1-14TFT"
|
||||
depends on IDF_TARGET_ESP32C3
|
||||
endchoice
|
||||
|
||||
choice ESP_S3_LCD_EV_Board_Version_TYPE
|
||||
@@ -292,7 +378,7 @@ choice DISPLAY_OLED_TYPE
|
||||
endchoice
|
||||
|
||||
choice DISPLAY_LCD_TYPE
|
||||
depends on BOARD_TYPE_BREAD_COMPACT_WIFI_LCD || BOARD_TYPE_BREAD_COMPACT_ESP32_LCD || BOARD_TYPE_ESP32_CGC || BOARD_TYPE_ESP32P4_NANO || BOARD_TYPE_ESP32P4_WIFI6_Touch_LCD_XC
|
||||
depends on BOARD_TYPE_BREAD_COMPACT_WIFI_LCD || BOARD_TYPE_BREAD_COMPACT_ESP32_LCD || BOARD_TYPE_ESP32_CGC || BOARD_TYPE_ESP32P4_NANO || BOARD_TYPE_ESP32P4_WIFI6_Touch_LCD_XC || BOARD_TYPE_BREAD_COMPACT_WIFI_CAM
|
||||
prompt "LCD Type"
|
||||
default LCD_ST7789_240X320
|
||||
help
|
||||
@@ -342,15 +428,27 @@ endchoice
|
||||
choice DISPLAY_ESP32S3_KORVO2_V3
|
||||
depends on BOARD_TYPE_ESP32S3_KORVO2_V3
|
||||
prompt "ESP32S3_KORVO2_V3 LCD Type"
|
||||
default LCD_ST7789
|
||||
default ESP32S3_KORVO2_V3_LCD_ST7789
|
||||
help
|
||||
屏幕类型选择
|
||||
config LCD_ST7789
|
||||
config ESP32S3_KORVO2_V3_LCD_ST7789
|
||||
bool "ST7789, 分辨率240*280"
|
||||
config LCD_ILI9341
|
||||
config ESP32S3_KORVO2_V3_LCD_ILI9341
|
||||
bool "ILI9341, 分辨率240*320"
|
||||
endchoice
|
||||
|
||||
choice DISPLAY_ESP32S3_AUDIO_BOARD
|
||||
depends on BOARD_TYPE_ESP32S3_AUDIO_BOARD
|
||||
prompt "ESP32S3_AUDIO_BOARD LCD Type"
|
||||
default AUDIO_BOARD_LCD_JD9853
|
||||
help
|
||||
屏幕类型选择
|
||||
config AUDIO_BOARD_LCD_JD9853
|
||||
bool "JD9853, 分辨率320*172"
|
||||
config AUDIO_BOARD_LCD_ST7789
|
||||
bool "ST7789, 分辨率240*320"
|
||||
endchoice
|
||||
|
||||
config USE_WECHAT_MESSAGE_STYLE
|
||||
bool "Enable WeChat Message Style"
|
||||
default n
|
||||
@@ -360,9 +458,9 @@ config USE_WECHAT_MESSAGE_STYLE
|
||||
config USE_ESP_WAKE_WORD
|
||||
bool "Enable Wake Word Detection (without AFE)"
|
||||
default n
|
||||
depends on IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32C5
|
||||
depends on IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32C5 || IDF_TARGET_ESP32C6 || (IDF_TARGET_ESP32 && SPIRAM)
|
||||
help
|
||||
支持 ESP32 C3 与 ESP32 C5
|
||||
支持 ESP32 C3、ESP32 C5 与 ESP32 C6,增加ESP32支持(需要开启PSRAM)
|
||||
|
||||
config USE_AFE_WAKE_WORD
|
||||
bool "Enable Wake Word Detection (AFE)"
|
||||
@@ -371,6 +469,35 @@ config USE_AFE_WAKE_WORD
|
||||
help
|
||||
需要 ESP32 S3 与 PSRAM 支持
|
||||
|
||||
config USE_CUSTOM_WAKE_WORD
|
||||
bool "Enable Custom Wake Word Detection"
|
||||
default n
|
||||
depends on (IDF_TARGET_ESP32S3 || IDF_TARGET_ESP32P4) && SPIRAM && (!USE_AFE_WAKE_WORD)
|
||||
help
|
||||
需要 ESP32 S3 与 PSRAM 支持
|
||||
|
||||
config CUSTOM_WAKE_WORD
|
||||
string "Custom Wake Word"
|
||||
default "xiao tu dou"
|
||||
depends on USE_CUSTOM_WAKE_WORD
|
||||
help
|
||||
自定义唤醒词,中文用拼音表示,每个字之间用空格隔开
|
||||
|
||||
config CUSTOM_WAKE_WORD_DISPLAY
|
||||
string "Custom Wake Word Display"
|
||||
default "小土豆"
|
||||
depends on USE_CUSTOM_WAKE_WORD
|
||||
help
|
||||
唤醒后发送给服务器的问候语
|
||||
|
||||
config CUSTOM_WAKE_WORD_THRESHOLD
|
||||
int "Custom Wake Word Threshold (%)"
|
||||
default 20
|
||||
range 1 99
|
||||
depends on USE_CUSTOM_WAKE_WORD
|
||||
help
|
||||
自定义唤醒词阈值,范围1-99,越小越敏感,默认10
|
||||
|
||||
config USE_AUDIO_PROCESSOR
|
||||
bool "Enable Audio Noise Reduction"
|
||||
default y
|
||||
@@ -381,7 +508,7 @@ config USE_AUDIO_PROCESSOR
|
||||
config USE_DEVICE_AEC
|
||||
bool "Enable Device-Side AEC"
|
||||
default n
|
||||
depends on USE_AUDIO_PROCESSOR && (BOARD_TYPE_ESP_BOX_3 || BOARD_TYPE_ESP_BOX || BOARD_TYPE_ESP_BOX_LITE || BOARD_TYPE_LICHUANG_DEV || BOARD_TYPE_ESP32S3_KORVO2_V3 || BOARD_TYPE_ESP32S3_Touch_AMOLED_1_75 || BOARD_TYPE_ESP32P4_WIFI6_Touch_LCD_4B || BOARD_TYPE_ESP32P4_WIFI6_Touch_LCD_XC)
|
||||
depends on USE_AUDIO_PROCESSOR && (BOARD_TYPE_ESP_BOX_3 || BOARD_TYPE_ESP_BOX || BOARD_TYPE_ESP_BOX_LITE || BOARD_TYPE_LICHUANG_DEV || BOARD_TYPE_ESP32S3_KORVO2_V3 || BOARD_TYPE_ESP32S3_Touch_AMOLED_1_75 || BOARD_TYPE_ESP32S3_Touch_AMOLED_2_06 || BOARD_TYPE_ESP32P4_WIFI6_Touch_LCD_4B || BOARD_TYPE_ESP32P4_WIFI6_Touch_LCD_XC || BOARD_TYPE_ESP_S3_LCD_EV_Board_2)
|
||||
help
|
||||
因为性能不够,不建议和微信聊天界面风格同时开启
|
||||
|
||||
@@ -398,6 +525,12 @@ config USE_AUDIO_DEBUGGER
|
||||
help
|
||||
启用音频调试功能,通过UDP发送音频数据
|
||||
|
||||
config USE_ACOUSTIC_WIFI_PROVISIONING
|
||||
bool "Enable Acoustic WiFi Provisioning"
|
||||
default n
|
||||
help
|
||||
启用声波配网功能,使用音频信号传输 WiFi 配置数据
|
||||
|
||||
config AUDIO_DEBUG_UDP_SERVER
|
||||
string "Audio Debug UDP Server Address"
|
||||
default "192.168.2.100:8000"
|
||||
@@ -405,15 +538,22 @@ config AUDIO_DEBUG_UDP_SERVER
|
||||
help
|
||||
UDP服务器地址,格式: IP:PORT,用于接收音频调试数据
|
||||
|
||||
choice IOT_PROTOCOL
|
||||
prompt "IoT Protocol"
|
||||
default IOT_PROTOCOL_MCP
|
||||
config RECEIVE_CUSTOM_MESSAGE
|
||||
bool "Enable Custom Message Reception"
|
||||
default n
|
||||
help
|
||||
IoT 协议,用于获取设备状态与发送控制指令
|
||||
config IOT_PROTOCOL_MCP
|
||||
bool "MCP 2024-11-05"
|
||||
config IOT_PROTOCOL_XIAOZHI
|
||||
bool "Xiaozhi IoT 1.0 (Deprecated)"
|
||||
启用接收自定义消息功能,允许设备接收来自服务器的自定义消息(最好通过 MQTT 协议)
|
||||
|
||||
choice I2S_TYPE_TAIJIPI_S3
|
||||
depends on BOARD_TYPE_ESP32S3_Taiji_Pi
|
||||
prompt "taiji-pi-S3 I2S Type"
|
||||
default TAIJIPAI_I2S_TYPE_STD
|
||||
help
|
||||
I2S 类型选择
|
||||
config TAIJIPAI_I2S_TYPE_STD
|
||||
bool "I2S Type STD"
|
||||
config TAIJIPAI_I2S_TYPE_PDM
|
||||
bool "I2S Type PDM"
|
||||
endchoice
|
||||
|
||||
endmenu
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -8,25 +8,23 @@
|
||||
|
||||
#include <string>
|
||||
#include <mutex>
|
||||
#include <list>
|
||||
#include <vector>
|
||||
#include <condition_variable>
|
||||
#include <deque>
|
||||
#include <memory>
|
||||
|
||||
#include <opus_encoder.h>
|
||||
#include <opus_decoder.h>
|
||||
#include <opus_resampler.h>
|
||||
|
||||
#include "protocol.h"
|
||||
#include "ota.h"
|
||||
#include "background_task.h"
|
||||
#include "audio_processor.h"
|
||||
#include "wake_word.h"
|
||||
#include "audio_debugger.h"
|
||||
#include "audio_service.h"
|
||||
#include "device_state_event.h"
|
||||
|
||||
|
||||
#define MAIN_EVENT_SCHEDULE (1 << 0)
|
||||
#define MAIN_EVENT_SEND_AUDIO (1 << 1)
|
||||
#define MAIN_EVENT_WAKE_WORD_DETECTED (1 << 2)
|
||||
#define MAIN_EVENT_VAD_CHANGE (1 << 3)
|
||||
#define MAIN_EVENT_ERROR (1 << 4)
|
||||
#define MAIN_EVENT_CHECK_NEW_VERSION_DONE (1 << 5)
|
||||
#define MAIN_EVENT_CLOCK_TICK (1 << 6)
|
||||
|
||||
#define SCHEDULE_EVENT (1 << 0)
|
||||
#define SEND_AUDIO_EVENT (1 << 1)
|
||||
#define CHECK_NEW_VERSION_DONE_EVENT (1 << 2)
|
||||
|
||||
enum AecMode {
|
||||
kAecOff,
|
||||
@@ -34,22 +32,6 @@ enum AecMode {
|
||||
kAecOnServerSide,
|
||||
};
|
||||
|
||||
enum DeviceState {
|
||||
kDeviceStateUnknown,
|
||||
kDeviceStateStarting,
|
||||
kDeviceStateWifiConfiguring,
|
||||
kDeviceStateIdle,
|
||||
kDeviceStateConnecting,
|
||||
kDeviceStateListening,
|
||||
kDeviceStateSpeaking,
|
||||
kDeviceStateUpgrading,
|
||||
kDeviceStateActivating,
|
||||
kDeviceStateFatalError
|
||||
};
|
||||
|
||||
#define OPUS_FRAME_DURATION_MS 60
|
||||
#define MAX_AUDIO_PACKETS_IN_QUEUE (2400 / OPUS_FRAME_DURATION_MS)
|
||||
|
||||
class Application {
|
||||
public:
|
||||
static Application& GetInstance() {
|
||||
@@ -61,8 +43,9 @@ public:
|
||||
Application& operator=(const Application&) = delete;
|
||||
|
||||
void Start();
|
||||
void MainEventLoop();
|
||||
DeviceState GetDeviceState() const { return device_state_; }
|
||||
bool IsVoiceDetected() const { return voice_detected_; }
|
||||
bool IsVoiceDetected() const { return audio_service_.IsVoiceDetected(); }
|
||||
void Schedule(std::function<void()> callback);
|
||||
void SetDeviceState(DeviceState state);
|
||||
void Alert(const char* status, const char* message, const char* emotion = "", const std::string_view& sound = "");
|
||||
@@ -71,69 +54,39 @@ public:
|
||||
void ToggleChatState();
|
||||
void StartListening();
|
||||
void StopListening();
|
||||
void UpdateIotStates();
|
||||
void Reboot();
|
||||
void WakeWordInvoke(const std::string& wake_word);
|
||||
void PlaySound(const std::string_view& sound);
|
||||
bool CanEnterSleepMode();
|
||||
void SendMcpMessage(const std::string& payload);
|
||||
void SetAecMode(AecMode mode);
|
||||
AecMode GetAecMode() const { return aec_mode_; }
|
||||
BackgroundTask* GetBackgroundTask() const { return background_task_; }
|
||||
void PlaySound(const std::string_view& sound);
|
||||
AudioService& GetAudioService() { return audio_service_; }
|
||||
|
||||
private:
|
||||
Application();
|
||||
~Application();
|
||||
|
||||
std::unique_ptr<WakeWord> wake_word_;
|
||||
std::unique_ptr<AudioProcessor> audio_processor_;
|
||||
std::unique_ptr<AudioDebugger> audio_debugger_;
|
||||
Ota ota_;
|
||||
std::mutex mutex_;
|
||||
std::list<std::function<void()>> main_tasks_;
|
||||
std::deque<std::function<void()>> main_tasks_;
|
||||
std::unique_ptr<Protocol> protocol_;
|
||||
EventGroupHandle_t event_group_ = nullptr;
|
||||
esp_timer_handle_t clock_timer_handle_ = nullptr;
|
||||
volatile DeviceState device_state_ = kDeviceStateUnknown;
|
||||
ListeningMode listening_mode_ = kListeningModeAutoStop;
|
||||
AecMode aec_mode_ = kAecOff;
|
||||
std::string last_error_message_;
|
||||
AudioService audio_service_;
|
||||
|
||||
bool has_server_time_ = false;
|
||||
bool aborted_ = false;
|
||||
bool voice_detected_ = false;
|
||||
bool busy_decoding_audio_ = false;
|
||||
int clock_ticks_ = 0;
|
||||
TaskHandle_t check_new_version_task_handle_ = nullptr;
|
||||
|
||||
// Audio encode / decode
|
||||
TaskHandle_t audio_loop_task_handle_ = nullptr;
|
||||
BackgroundTask* background_task_ = nullptr;
|
||||
std::chrono::steady_clock::time_point last_output_time_;
|
||||
std::list<AudioStreamPacket> audio_send_queue_;
|
||||
std::list<AudioStreamPacket> audio_decode_queue_;
|
||||
std::condition_variable audio_decode_cv_;
|
||||
|
||||
// 新增:用于维护音频包的timestamp队列
|
||||
std::list<uint32_t> timestamp_queue_;
|
||||
std::mutex timestamp_mutex_;
|
||||
|
||||
std::unique_ptr<OpusEncoderWrapper> opus_encoder_;
|
||||
std::unique_ptr<OpusDecoderWrapper> opus_decoder_;
|
||||
|
||||
OpusResampler input_resampler_;
|
||||
OpusResampler reference_resampler_;
|
||||
OpusResampler output_resampler_;
|
||||
|
||||
void MainEventLoop();
|
||||
void OnAudioInput();
|
||||
void OnAudioOutput();
|
||||
bool ReadAudio(std::vector<int16_t>& data, int sample_rate, int samples);
|
||||
void ResetDecoder();
|
||||
void SetDecodeSampleRate(int sample_rate, int frame_duration);
|
||||
void CheckNewVersion();
|
||||
void ShowActivationCode();
|
||||
void OnClockTimer();
|
||||
void OnWakeWordDetected();
|
||||
void CheckNewVersion(Ota& ota);
|
||||
void ShowActivationCode(const std::string& code, const std::string& message);
|
||||
void SetListeningMode(ListeningMode mode);
|
||||
void AudioLoop();
|
||||
};
|
||||
|
||||
#endif // _APPLICATION_H_
|
||||
|
||||
BIN
main/assets/common/exclamation.ogg
Normal file
BIN
main/assets/common/exclamation.ogg
Normal file
Binary file not shown.
Binary file not shown.
BIN
main/assets/common/low_battery.ogg
Normal file
BIN
main/assets/common/low_battery.ogg
Normal file
Binary file not shown.
Binary file not shown.
BIN
main/assets/common/popup.ogg
Normal file
BIN
main/assets/common/popup.ogg
Normal file
Binary file not shown.
Binary file not shown.
BIN
main/assets/common/success.ogg
Normal file
BIN
main/assets/common/success.ogg
Normal file
Binary file not shown.
Binary file not shown.
BIN
main/assets/common/vibration.ogg
Normal file
BIN
main/assets/common/vibration.ogg
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
main/assets/locales/ar-SA/0.ogg
Normal file
BIN
main/assets/locales/ar-SA/0.ogg
Normal file
Binary file not shown.
BIN
main/assets/locales/ar-SA/1.ogg
Normal file
BIN
main/assets/locales/ar-SA/1.ogg
Normal file
Binary file not shown.
BIN
main/assets/locales/ar-SA/2.ogg
Normal file
BIN
main/assets/locales/ar-SA/2.ogg
Normal file
Binary file not shown.
BIN
main/assets/locales/ar-SA/3.ogg
Normal file
BIN
main/assets/locales/ar-SA/3.ogg
Normal file
Binary file not shown.
BIN
main/assets/locales/ar-SA/4.ogg
Normal file
BIN
main/assets/locales/ar-SA/4.ogg
Normal file
Binary file not shown.
BIN
main/assets/locales/ar-SA/5.ogg
Normal file
BIN
main/assets/locales/ar-SA/5.ogg
Normal file
Binary file not shown.
BIN
main/assets/locales/ar-SA/6.ogg
Normal file
BIN
main/assets/locales/ar-SA/6.ogg
Normal file
Binary file not shown.
BIN
main/assets/locales/ar-SA/7.ogg
Normal file
BIN
main/assets/locales/ar-SA/7.ogg
Normal file
Binary file not shown.
BIN
main/assets/locales/ar-SA/8.ogg
Normal file
BIN
main/assets/locales/ar-SA/8.ogg
Normal file
Binary file not shown.
BIN
main/assets/locales/ar-SA/9.ogg
Normal file
BIN
main/assets/locales/ar-SA/9.ogg
Normal file
Binary file not shown.
BIN
main/assets/locales/ar-SA/activation.ogg
Normal file
BIN
main/assets/locales/ar-SA/activation.ogg
Normal file
Binary file not shown.
BIN
main/assets/locales/ar-SA/err_pin.ogg
Normal file
BIN
main/assets/locales/ar-SA/err_pin.ogg
Normal file
Binary file not shown.
BIN
main/assets/locales/ar-SA/err_reg.ogg
Normal file
BIN
main/assets/locales/ar-SA/err_reg.ogg
Normal file
Binary file not shown.
58
main/assets/locales/ar-SA/language.json
Normal file
58
main/assets/locales/ar-SA/language.json
Normal file
@@ -0,0 +1,58 @@
|
||||
{
|
||||
"language": {
|
||||
"type" :"ar-SA"
|
||||
},
|
||||
"strings": {
|
||||
"WARNING":"تحذير",
|
||||
"INFO":"معلومات",
|
||||
"ERROR":"خطأ",
|
||||
"VERSION": "الإصدار ",
|
||||
"LOADING_PROTOCOL":"الاتصال بالخادم...",
|
||||
"INITIALIZING":"التهيئة...",
|
||||
"PIN_ERROR":"يرجى إدخال بطاقة SIM",
|
||||
"REG_ERROR":"لا يمكن الوصول إلى الشبكة، يرجى التحقق من حالة بطاقة البيانات",
|
||||
"DETECTING_MODULE":"اكتشاف الوحدة...",
|
||||
"REGISTERING_NETWORK":"انتظار الشبكة...",
|
||||
"CHECKING_NEW_VERSION":"فحص الإصدار الجديد...",
|
||||
"CHECK_NEW_VERSION_FAILED":"فشل فحص الإصدار الجديد، سيتم المحاولة خلال %d ثانية: %s",
|
||||
"SWITCH_TO_WIFI_NETWORK":"التبديل إلى Wi-Fi...",
|
||||
"SWITCH_TO_4G_NETWORK":"التبديل إلى 4G...",
|
||||
|
||||
"STANDBY":"في الانتظار",
|
||||
"CONNECT_TO":"الاتصال بـ ",
|
||||
"CONNECTING":"جاري الاتصال...",
|
||||
"CONNECTED_TO":"متصل بـ ",
|
||||
|
||||
"LISTENING":"الاستماع...",
|
||||
"SPEAKING":"التحدث...",
|
||||
|
||||
"SERVER_NOT_FOUND":"البحث عن خدمة متاحة",
|
||||
"SERVER_NOT_CONNECTED":"لا يمكن الاتصال بالخدمة، يرجى المحاولة لاحقاً",
|
||||
"SERVER_TIMEOUT":"انتهت مهلة الاستجابة",
|
||||
"SERVER_ERROR":"فشل الإرسال، يرجى التحقق من الشبكة",
|
||||
|
||||
"CONNECT_TO_HOTSPOT":"اتصل الهاتف بنقطة الاتصال ",
|
||||
"ACCESS_VIA_BROWSER":"،الوصول عبر المتصفح ",
|
||||
"WIFI_CONFIG_MODE":"وضع تكوين الشبكة",
|
||||
"ENTERING_WIFI_CONFIG_MODE":"الدخول في وضع تكوين الشبكة...",
|
||||
"SCANNING_WIFI":"فحص Wi-Fi...",
|
||||
|
||||
"NEW_VERSION": "إصدار جديد ",
|
||||
"OTA_UPGRADE":"تحديث OTA",
|
||||
"UPGRADING":"تحديث النظام...",
|
||||
"UPGRADE_FAILED":"فشل التحديث",
|
||||
"ACTIVATION":"تفعيل الجهاز",
|
||||
|
||||
"BATTERY_LOW":"البطارية منخفضة",
|
||||
"BATTERY_CHARGING":"جاري الشحن",
|
||||
"BATTERY_FULL":"البطارية ممتلئة",
|
||||
"BATTERY_NEED_CHARGE":"البطارية منخفضة، يرجى الشحن",
|
||||
|
||||
"VOLUME":"الصوت ",
|
||||
"MUTED":"صامت",
|
||||
"MAX_VOLUME":"أقصى صوت",
|
||||
|
||||
"RTC_MODE_OFF":"AEC مُوقف",
|
||||
"RTC_MODE_ON":"AEC مُشغل"
|
||||
}
|
||||
}
|
||||
BIN
main/assets/locales/ar-SA/upgrade.ogg
Normal file
BIN
main/assets/locales/ar-SA/upgrade.ogg
Normal file
Binary file not shown.
BIN
main/assets/locales/ar-SA/welcome.ogg
Normal file
BIN
main/assets/locales/ar-SA/welcome.ogg
Normal file
Binary file not shown.
BIN
main/assets/locales/ar-SA/wificonfig.ogg
Normal file
BIN
main/assets/locales/ar-SA/wificonfig.ogg
Normal file
Binary file not shown.
BIN
main/assets/locales/cs-CZ/0.ogg
Normal file
BIN
main/assets/locales/cs-CZ/0.ogg
Normal file
Binary file not shown.
BIN
main/assets/locales/cs-CZ/1.ogg
Normal file
BIN
main/assets/locales/cs-CZ/1.ogg
Normal file
Binary file not shown.
BIN
main/assets/locales/cs-CZ/2.ogg
Normal file
BIN
main/assets/locales/cs-CZ/2.ogg
Normal file
Binary file not shown.
BIN
main/assets/locales/cs-CZ/3.ogg
Normal file
BIN
main/assets/locales/cs-CZ/3.ogg
Normal file
Binary file not shown.
BIN
main/assets/locales/cs-CZ/4.ogg
Normal file
BIN
main/assets/locales/cs-CZ/4.ogg
Normal file
Binary file not shown.
BIN
main/assets/locales/cs-CZ/5.ogg
Normal file
BIN
main/assets/locales/cs-CZ/5.ogg
Normal file
Binary file not shown.
BIN
main/assets/locales/cs-CZ/6.ogg
Normal file
BIN
main/assets/locales/cs-CZ/6.ogg
Normal file
Binary file not shown.
BIN
main/assets/locales/cs-CZ/7.ogg
Normal file
BIN
main/assets/locales/cs-CZ/7.ogg
Normal file
Binary file not shown.
BIN
main/assets/locales/cs-CZ/8.ogg
Normal file
BIN
main/assets/locales/cs-CZ/8.ogg
Normal file
Binary file not shown.
BIN
main/assets/locales/cs-CZ/9.ogg
Normal file
BIN
main/assets/locales/cs-CZ/9.ogg
Normal file
Binary file not shown.
BIN
main/assets/locales/cs-CZ/activation.ogg
Normal file
BIN
main/assets/locales/cs-CZ/activation.ogg
Normal file
Binary file not shown.
BIN
main/assets/locales/cs-CZ/err_pin.ogg
Normal file
BIN
main/assets/locales/cs-CZ/err_pin.ogg
Normal file
Binary file not shown.
BIN
main/assets/locales/cs-CZ/err_reg.ogg
Normal file
BIN
main/assets/locales/cs-CZ/err_reg.ogg
Normal file
Binary file not shown.
58
main/assets/locales/cs-CZ/language.json
Normal file
58
main/assets/locales/cs-CZ/language.json
Normal file
@@ -0,0 +1,58 @@
|
||||
{
|
||||
"language": {
|
||||
"type" :"cs-CZ"
|
||||
},
|
||||
"strings": {
|
||||
"WARNING":"Varování",
|
||||
"INFO":"Informace",
|
||||
"ERROR":"Chyba",
|
||||
"VERSION": "Verze ",
|
||||
"LOADING_PROTOCOL":"Připojování k serveru...",
|
||||
"INITIALIZING":"Inicializace...",
|
||||
"PIN_ERROR":"Prosím vložte SIM kartu",
|
||||
"REG_ERROR":"Nelze se připojit k síti, zkontrolujte stav datové karty",
|
||||
"DETECTING_MODULE":"Detekce modulu...",
|
||||
"REGISTERING_NETWORK":"Čekání na síť...",
|
||||
"CHECKING_NEW_VERSION":"Kontrola nové verze...",
|
||||
"CHECK_NEW_VERSION_FAILED":"Kontrola nové verze selhala, opakování za %d sekund: %s",
|
||||
"SWITCH_TO_WIFI_NETWORK":"Přepínání na Wi-Fi...",
|
||||
"SWITCH_TO_4G_NETWORK":"Přepínání na 4G...",
|
||||
|
||||
"STANDBY":"Pohotovost",
|
||||
"CONNECT_TO":"Připojit k ",
|
||||
"CONNECTING":"Připojování...",
|
||||
"CONNECTED_TO":"Připojeno k ",
|
||||
|
||||
"LISTENING":"Naslouchání...",
|
||||
"SPEAKING":"Mluvení...",
|
||||
|
||||
"SERVER_NOT_FOUND":"Hledání dostupné služby",
|
||||
"SERVER_NOT_CONNECTED":"Nelze se připojit ke službě, zkuste to později",
|
||||
"SERVER_TIMEOUT":"Čas odpovědi vypršel",
|
||||
"SERVER_ERROR":"Odeslání selhalo, zkontrolujte síť",
|
||||
|
||||
"CONNECT_TO_HOTSPOT":"Připojte telefon k hotspotu ",
|
||||
"ACCESS_VIA_BROWSER":",přístup přes prohlížeč ",
|
||||
"WIFI_CONFIG_MODE":"Režim konfigurace sítě",
|
||||
"ENTERING_WIFI_CONFIG_MODE":"Vstup do režimu konfigurace sítě...",
|
||||
"SCANNING_WIFI":"Skenování Wi-Fi...",
|
||||
|
||||
"NEW_VERSION": "Nová verze ",
|
||||
"OTA_UPGRADE":"OTA upgrade",
|
||||
"UPGRADING":"Aktualizace systému...",
|
||||
"UPGRADE_FAILED":"Upgrade selhal",
|
||||
"ACTIVATION":"Aktivace zařízení",
|
||||
|
||||
"BATTERY_LOW":"Slabá baterie",
|
||||
"BATTERY_CHARGING":"Nabíjení",
|
||||
"BATTERY_FULL":"Baterie plná",
|
||||
"BATTERY_NEED_CHARGE":"Slabá baterie, prosím nabijte",
|
||||
|
||||
"VOLUME":"Hlasitost ",
|
||||
"MUTED":"Ztlumeno",
|
||||
"MAX_VOLUME":"Maximální hlasitost",
|
||||
|
||||
"RTC_MODE_OFF":"AEC vypnuto",
|
||||
"RTC_MODE_ON":"AEC zapnuto"
|
||||
}
|
||||
}
|
||||
BIN
main/assets/locales/cs-CZ/upgrade.ogg
Normal file
BIN
main/assets/locales/cs-CZ/upgrade.ogg
Normal file
Binary file not shown.
BIN
main/assets/locales/cs-CZ/welcome.ogg
Normal file
BIN
main/assets/locales/cs-CZ/welcome.ogg
Normal file
Binary file not shown.
BIN
main/assets/locales/cs-CZ/wificonfig.ogg
Normal file
BIN
main/assets/locales/cs-CZ/wificonfig.ogg
Normal file
Binary file not shown.
BIN
main/assets/locales/de-DE/0.ogg
Normal file
BIN
main/assets/locales/de-DE/0.ogg
Normal file
Binary file not shown.
BIN
main/assets/locales/de-DE/1.ogg
Normal file
BIN
main/assets/locales/de-DE/1.ogg
Normal file
Binary file not shown.
BIN
main/assets/locales/de-DE/2.ogg
Normal file
BIN
main/assets/locales/de-DE/2.ogg
Normal file
Binary file not shown.
BIN
main/assets/locales/de-DE/3.ogg
Normal file
BIN
main/assets/locales/de-DE/3.ogg
Normal file
Binary file not shown.
BIN
main/assets/locales/de-DE/4.ogg
Normal file
BIN
main/assets/locales/de-DE/4.ogg
Normal file
Binary file not shown.
BIN
main/assets/locales/de-DE/5.ogg
Normal file
BIN
main/assets/locales/de-DE/5.ogg
Normal file
Binary file not shown.
BIN
main/assets/locales/de-DE/6.ogg
Normal file
BIN
main/assets/locales/de-DE/6.ogg
Normal file
Binary file not shown.
BIN
main/assets/locales/de-DE/7.ogg
Normal file
BIN
main/assets/locales/de-DE/7.ogg
Normal file
Binary file not shown.
BIN
main/assets/locales/de-DE/8.ogg
Normal file
BIN
main/assets/locales/de-DE/8.ogg
Normal file
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user