# WebRTC 双向音视频示例 ## 功能说明 本示例面向 `arcs_evb`,在一个 PeerConnection 中同时完成双向音视频通信。板端摄像头画面编码为 QVGA JPEG,通过二进制 DataChannel 的应用层 Video Chunk 协议传输;音频使用标准 WebRTC PCMU 媒体轨,固定为 8 kHz、单声道和 20 ms 包长。 视频不是 WebRTC RTP 视频媒体轨。浏览器与板端传输的是分片 JPEG 帧,浏览器必须创建标签为 `libpeer` 的 DataChannel。板端接收侧只校验 JPEG 并输出统计,不保存或显示图像;浏览器页面显示板端 JPEG。 ## 硬件连接 - **目标板**: `arcs_evb` - **视频输入**: 板载 DVP 摄像头,GC032A 或 GC0328 - **音频输入**: 板载 MIC0 - **音频输出**: 板载扬声器或耳机 - **网络**: 可访问 MQTT broker、NTP 和 STUN 服务的 2.4 GHz WiFi - **日志串口**: 921600 baud ## 测试环境准备 1. 在 `prj.conf` 或 menuconfig 中设置 `CONFIG_WEBRTC_WIFI_SSID` 和 `CONFIG_WEBRTC_WIFI_PASSWORD`。 2. 将 `CONFIG_WEBRTC_SIGNALING_ROOM` 改为不易冲突的完整路径,例如 `webrtc/lab-a1b2c3d4`,并在配套浏览器页面中填写完全相同的值。 3. 在本机通过 HTTP 服务打开 `web/` 下的配套页面(`localhost` 属于浏览器安全上下文),允许摄像头和麦克风权限;远程部署时必须使用 HTTPS。 4. 页面建立 PeerConnection 前必须执行 `createDataChannel('libpeer')`。 默认 `broker.emqx.io` 是公共服务,SDP 和房间名会经过公共 broker。该配置仅用于演示,不适合生产环境。 ## 示例步骤 1. 初始化 WiFi,关联热点并等待 DHCP 获取地址。 2. 通过多个 NTP 服务执行 `lisa_sntp_query()`,更新 mbedTLS `ls_time()` 使用的 epoch/tick 基准。 3. 使用 DigiCert Global Root G2 校验默认 MQTT broker 的证书和主机名。 4. 初始化 QVGA YUV422 摄像头、硬件 JPEG 编码器以及同时录放的音频设备。 5. 创建 `DATA_CHANNEL_BINARY`、`CODEC_NONE` 视频和 `CODEC_PCMU` 音频的 PeerConnection。 6. 以 960 字节负载分片发送 JPEG;接收侧按帧号和偏移重组并校验 SOI/EOI。 7. 网络或会话失败后销毁 signaling 与 PeerConnection,按退避延时自动重建。 ## 编译 ```{eval-rst} .. include:: /sample_build.rst ``` C 和 JavaScript 协议测试共同读取 `tests/vectors/single-frame.hex`,可独立运行: ```bash samples/network/webrtc/bidirectional_av/tests/run_host_tests.sh node --test samples/network/webrtc/bidirectional_av/web/test/protocol.test.mjs ``` 从仓库根目录启动浏览器测试对端: ```bash python3 -m http.server 8000 --directory samples/network/webrtc/bidirectional_av/web ``` 然后访问 `http://localhost:8000/`。 ## 烧录 ```{eval-rst} .. include:: /sample_flash.rst ``` ## 预期输出 ```text I/webrtc_av ... Bidirectional WebRTC AV sample starting I/webrtc_net ... DHCP ready on VIF-0: 192.168.x.x I/webrtc_net ... System time synchronized: ... UTC I/webrtc_cam ... Camera ready: QVGA YUV422, hardware JPEG I/webrtc_audio ... Audio ready: PCMU 8 kHz mono, 20 ms, low playback gain, no AEC I/webrtc_peer ... Signaling connected: broker=mqtts://broker.emqx.io:8883 room=... I/webrtc_peer ... PeerConnection state: completed I/webrtc_peer ... Binary DataChannel opened I/webrtc_av ... video tx=..., rx=... (... fps, ... KiB/s), bad_jpeg=0 bad_chunk=0 incomplete=0 I/webrtc_av ... audio tx=..., rx=... play=... queue_drop=... underrun=..., restarts=0 ``` ## Video Chunk 协议 每条 DataChannel 消息包含 24 字节网络字节序头和最多 960 字节负载: | 偏移 | 长度 | 字段 | 说明 | |-----:|-----:|------|------| | 0 | 4 | magic | ASCII `MJPG` | | 4 | 1 | version | 固定为 `1` | | 5 | 1 | flags | `START=1`,`END=2` | | 6 | 2 | header_size | 固定为 `24` | | 8 | 4 | frame_id | 帧序号 | | 12 | 4 | frame_size | 完整 JPEG 长度 | | 16 | 4 | offset | 当前负载在帧内的偏移 | | 20 | 2 | payload_size | 当前负载长度 | | 22 | 2 | reserved | 固定为 `0` | 接收端固定使用最大 96 KiB 的 PSRAM 缓冲区。新帧到达时会丢弃尚未完成的旧帧;缺块、乱序、越界、错误版本和错误保留字段均会被拒绝并计数。 ## 配置说明 - `CONFIG_WEBRTC_WIFI_SSID`: WiFi 名称,默认是不可运行的占位符。 - `CONFIG_WEBRTC_WIFI_PASSWORD`: WiFi 密码,默认是占位符。 - `CONFIG_WEBRTC_SIGNALING_BROKER`: MQTT signaling 地址,默认 `mqtts://broker.emqx.io:8883`。 - `CONFIG_WEBRTC_SIGNALING_ROOM`: 固件和浏览器共享的完整 MQTT 房间路径,不带首尾 `/`。 - `CONFIG_WEBRTC_SIGNALING_TOKEN`: 可选认证 token,不应提交真实凭据。 - `CONFIG_WEBRTC_VIDEO_FPS`: 板端发送帧率,默认 5 FPS。 - `CONFIG_WEBRTC_VIDEO_MAX_FRAME_SIZE`: JPEG 和重组缓冲上限,最大 98304 字节。 Video Chunk 负载固定为最多 960 字节,属于线协议常量,不通过 Kconfig 修改。 ## 注意事项 1. **无 AEC**: 示例没有声学回声消除,默认使用低播放增益。双向音频测试应使用耳机或将麦克风与扬声器物理隔离,避免回声和啸叫。 2. **公网穿透**: 示例保留 STUN,但不配置 TURN,优先在同一局域网或普通 NAT 环境中测试。 3. **TLS 根证书**: 默认信任锚仅覆盖当前默认 broker 的 DigiCert Global Root G2 链。更换 broker 时必须同步替换或扩展 `ca_certificate.c`。 4. **公共 broker**: 公共 MQTT 服务不提供隐私或可用性保证,应使用唯一房间名且不要传递敏感信息。 5. **实时性策略**: 视频不排队;发送失败时丢弃当前帧。下行音频队列满时丢最旧包,空时写入 20 ms 静音。 6. **实板验收**: 构建通过和主机协议测试不能代替摄像头、双向声卡、DTLS/SCTP、断线重连和浏览器权限的实板验证。