嵌入式设备上的WebRTC实践:WebRTC-IOT架构与性能调优指南
1. 为什么是 WebRTC:物联网设备对实时通信的真实需求
1.1 一次现场联调把我逼到了 WebRTC 阵营
先说一段经历。去年做一个户外巡检机器人项目,设备端是一块 RK3568 开发板,跑的是 Linux,摄像头采集画面通过 RTSP 推流到后台,后台用 VLC 或者网页播放器看。开发阶段一切正常,一到客户现场就出事。
客户现场的设备和后台服务器不在同一个网段,中间隔着一层又一层的 NAT,还有些现场的网络策略只放行 443、80 这些端口。RTSP 的默认端口 554 根本出不去,就算改了端口,UDP 的 RTP 包在跨网段时经常被丢得七零八落,画面花屏、卡顿、掉线轮着来。我们尝试在服务器端做端口映射、搭专线,折腾了差不多一周,最后勉强能看,但延迟在 2 到 5 秒之间浮动,根本没法做远程操控。
后来我把思路换成了 WebRTC。设备端用 WebRTC 把 H.264 码流打包成 RTP,通过 ICE 的 STUN 做 NAT 穿透,信令走 WebSocket 过 443 端口,媒体流走 SRTP 加密的 UDP 或 TCP 通道。改完以后,画面延迟稳定在 300 毫秒上下,远程同事点开浏览器就直接看,不需要装任何插件。那一刻我才真正意识到,WebRTC 这套为浏览器设计的实时通信协议,放在物联网场景里反而比很多“专用”方案更好使。
1.2 浏览器原生协议带来的生态红利
WebRTC 有一个其他实时传输协议很难替代的优势:它是浏览器原生支持的。这意味着任何一台电脑、手机,只要装了个现代浏览器,就能直接作为观看端或者控制端,不需要额外装播放器、推流工具、解码器,也不用和一堆 SDK 打交道。
我用过不少项目都是这样:设备端千辛万苦把流推出去,结果客户端说自己电脑上装不了播放器;或者说公司网络策略不允许装软件。WebRTC 一上,所有这些问题都消失了,只要浏览器能打开页面,就能收流。
另外,WebRTC 把很多“本来要自己造轮子”的事做成了标准:
- 媒体传输统一走 SRTP,自带加密和完整性校验,不用再考虑设备传输内容被中间人抓包的问题;
- 网络层用 ICE 框架,自动尝试 UDP、TCP 等多种候选链路,跨 NAT 的成功率高很多;
- 端到端延迟做了专门优化,尤其适合操控、监控这类对实时性敏感的场景;
- 自带音视频引擎和拥塞控制,弱网下会自动调整码率,这个特性在移动设备上尤其好用。
这些能力加在一起,构成了一个“拿来就能用”的实时通信底座。对我来说,它解决了物联网设备远程可视化里面最难啃的几块骨头:网络穿透、延迟控制、安全传输和终端兼容性。
1.3 嵌入式设备需要的不是整套标准,而是可裁剪的子集
但这里有个很现实的问题:标准的 libwebrtc 太大、太重了。
谷歌官方的 libwebrtc 是为桌面 Chrome 和 Android 设计的,整套代码工程量非常惊人,编译一次要吃掉大量内存和时间,生成的二进制动辄几十兆字节。它内部还捆绑了音频采集、降噪、回声消除、视频处理、多路流管理、大量的编解码器实现……这些在浏览器里是刚需,在嵌入式设备里大部分都是负担。
嵌入式设备的硬件约束摆在那里:
- 内存可能只有 64MB 到 256MB,libwebrtc 的默认内存占用容易顶不住;
- CPU 是 Arm 架构的,主频通常不高,软件编解码和复杂的音视频处理会占用大量算力;
- Flash 存储有限,几十 MB 的固件对很多设备来说不可接受;
- 有些设备要做实时控制,视频处理链路不能有太深的缓冲,否则延迟会失控。
所以,当我看到 WebRTC-IOT 这个项目时,第一个感觉就是“终于有人按嵌入式设备的思路来做 WebRTC 了”。它不是简单地把 libwebrtc 的代码裁一裁、改一改,而是用现代 C++ 重新设计了一套面向资源受限设备的实现。它保留了 WebRTC 的协议骨架,但在模块化、内存管理、依赖控制上做了大量减法,让开发者可以只带自己需要的部分上板子。
2. 架构拆解:这个 C++ 库如何为嵌入式做减法
2.1 模块边界与可裁剪性
我第一次打开 WebRTC-IOT 的源码时,最先注意到的是它的模块划分很清楚。它不像 libwebrtc 那样把一堆东西耦合在一起,而是按功能拆成了独立模块,模块之间用明确的接口通信。
从设计思路来看,这套库大体上分成这么几层:
- 传输层:处理 UDP/TCP 套接字、ICE、DTLS、SRTP 这些网络和加密协议;
- 信令层:负责和信令服务器通信,交换 SDP、ICE Candidate,这部分是协议无关的,可以接 WebSocket、MQTT 甚至串口;
- 媒体层:负责任务调度、数据帧分发、缓冲管理和拥塞控制;
- 编解码抽象层:定义编码器、解码器的接口,默认不绑定具体实现,开发者可以接入硬件编解码器。
这样的分层带来的直接好处是,编译时可以按需裁剪。比如一个纯粹的回传画面场景,不需要音频,那音频相关的部分可以直接不编进去;如果设备只需要接收流,不需要推流,编码器也可以拿掉。我在实际编译时就只保留了 H.264 编码、SRTP 传输和 ICE 这几部分,编译出来的体积比全套小很多。
如果你做过嵌入式开发,一定明白这种“默认零依赖、按需引入”的设计有多重要。很多开源项目功能很强,但一交叉编译就带出一大堆依赖,openssl、boost、ffmpeg 全都来了,光处理依赖版本冲突就够呛。WebRTC-IOT 在这点上做得比较克制,基础部分尽量只依赖标准库和少量可选的系统库,这给嵌入式移植省了很多麻烦。
2.2 内存管理:避免高频分配
实时通信场景里,内存管理是个容易被低估的问题。很多人以为功能跑通就行,但视频数据是持续不断的,每一帧都要经过采集、编码、组包、发送、接收、解码、渲染整个链路。如果链路里有任何一环频繁做堆内存分配和释放,长时间运行就会出现内存碎片,最后导致可用内存越来越小,系统不稳定。
WebRTC-IOT 在这方面做了不少有针对性的设计。它大量使用对象池和环形缓冲区来复用内存,避免在高频路径上频繁 new/delete。比如每个视频帧的 buffer、RTP 包的 buffer、历史统计数据的缓存,都尽量复用已经分配好的内存块。我读过它的部分代码,不少地方是先把数据写入预分配的 buffer,再通过“所有权转移”的方式交给下一个模块,而不是每次都复制一份副本。
这种设计对资源紧张的嵌入式设备尤其重要。我自己的板子上内存只有 128MB,之前用某个基于 libwebrtc 改的方案跑两个摄像头,半小时后内存占用从 70MB 慢慢涨到 110MB,最后系统调度越来越卡。换到 WebRTC-IOT 后,长时间运行的内存占用基本是一条直线,只有小幅波动。
当然,这种设计也对使用者提了一个要求:不要在回调里做耗时操作,也不要把拿到的数据帧复制到自己的长生命周期对象里反复持有,否则还是会产生大量内存拷贝。它提供的内存模型设计得再高效,也架不住使用者在外面乱来。
2.3 网络层与 ICE:轻量实现
ICE 是 WebRTC 里面最核心、也最容易把人绕晕的部分。简化的流程是这样的:通信双方各自收集自己所有的网络地址候选(本地 IP、STUN 反射地址、TURN 中继地址),然后通过信令通道交换给对方;接着双方依次尝试各组候选地址的组合,找到一条能通的路径就开始传输媒体数据。
这套机制在浏览器里是个黑盒,在设备端就需要自己完整实现或者正确配置。WebRTC-IOT 的 ICE 实现把“收集候选”和“连接性检查”两个核心过程都做了封装,开发者只需要提供 STUN/TURN 服务器的地址和账号信息,剩下的交给库去跑。
因为目标是嵌入式设备,它的 ICE 实现做了一些轻量化取舍。比如在候选地址对数很多的时候,它不会像桌面版本那样疯狂并发打洞检测,而是有节奏地逐个尝试,避免瞬时产生大量网络流量;又比如它把连接状态和候选地址的统计信息开放出来,方便开发者调试或者上报到后台监控。
我实测下来,两个都在公网 NAT 后面的设备,只要配置了 STUN 服务器,在大多数场景下都能成功建立直连;如果网络环境极其严格,需要走 TURN 中继,也能正常工作。对物联网场景来说,这已经足够实用了。
2.4 编解码抽象:让硬件编解码器能插进来
在嵌入式设备上做音视频通信,最忌讳的一件事就是强制用软件编解码。RK3568、RV1126、海思 Hi3516 这类芯片都自带硬件编解码单元,性能比 CPU 软解高出几个数量级,功耗和发热也低得多。如果库把编解码逻辑写死,开发者要么被逼着用软编,要么得在外部做一层别扭的转接,平白增加延迟。
WebRTC-IOT 把编解码器做成了抽象接口,开发者只要实现编码器、解码器两个接口,把硬件编解码单元包一层,就能直接接入媒体管道。接口的核心方法不多,基本上就是输入原始帧、输出编码后的码流,以及反向的解码流程。
我接入 Rockchip 的 MPP 编解码器时,大概花了一个下午就调通了。关键是在两个地方处理好时间和内存语义:一是编码器输出的时间戳要正确传递到 RTP 包头里,接收端才能按序播放;二是硬件编解码器的 buffer 格式和库内部定义的 buffer 格式要做一次转换,这一步如果处理好,可以避免不必要的拷贝,直接传引用。这些细节在官方文档里没有写得太细,但在实际接入时都是躲不开的坎。
3. 从零接入:交叉编译、信令与首帧视频
3.1 准备交叉编译环境
WebRTC-IOT 是用现代 C++ 写的,对编译器版本有一定要求。我在 Ubuntu 20.04 的宿主机上给 ARM64 开发板交叉编译时,用的是 aarch64-linux-gnu-g++,版本在 10 以上,配合 CMake 构建系统,整体流程很顺利。
一个值得注意的点是,这个库对 C++ 标准库特性用得多,交叉编译工具链最好选 glibc 版本和板子上的系统匹配,否则编译出来的二进制拷到板子上运行时会报 GLIBC 版本找不到。我一开始用的是工具链附带的旧版 sysroot,结果板子上 glibc 是 2.31,编译时默认链接的却是 2.35 的符号,跑起来直接崩溃。后来改用和板子系统一致的 sysroot 才解决。
交叉编译时的 CMake 缓存文件大概是这样的:
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR aarch64)
set(CMAKE_SYSROOT /opt/aarch64-sysroot)
set(CMAKE_CXX_COMPILER aarch64-linux-gnu-g++)
set(CMAKE_C_COMPILER aarch64-linux-gnu-gcc)
用工具链文件的方式传给 CMake,然后单独编译出库文件,再把这部分和板子上的硬件适配代码链到一起。整体上它不依赖太多第三方库,省去了一大堆交叉编译第三方依赖的头痛问题,这也是我敢在项目里快速试玩它的一个重要原因。
3.2 最小 C++ 示例
整个库的用法,从接口设计上来说是围绕 PeerConnection 这套理念展开的。简单理解,就是“每一个端到端连接对应一个 PeerConnection 对象”,发送端往对象里添加音视频轨道,接收端从对象里取出轨道数据。
我整理了一个最小推流示例,伪代码大概长这样:
auto config = webrtc::PeerConnectionConfig{};
config.stun_server = "stun:stun.example.com";
auto connection = webrtc::CreatePeerConnection(config);
auto video_source = MyHardwareVideoSource{};
auto track = connection->AddVideoTrack(video_source);
connection->OnIceCandidate([](const std::string& candidate) {
// 将 candidate 通过信令通道发送给对端
});
connection->OnConnectionStateChanged([](auto state) {
// 监听连接状态,用于界面展示和日志
});
std::string offer = connection->CreateOffer();
// 发送 offer 给对端,等待 answer
接收端则更简单,收到 SDP 之后设置远端描述,然后从回调里拿解码后的帧去显示或者继续做算法处理。整个过程看下来,和浏览器里使用 RTCPeerConnection 的体验非常接近,有 WebRTC 基础的人上手很快。
因为没有现成的信令协议,它把 SDP 交换和 ICE Candidate 交换完全留给开发者自己定义,这对我来说反而更灵活。比如在某个项目中,我直接把 offer/answer 和 candidate 塞进 MQTT 消息里,用已有的物联网消息通路完成了信令,不用额外搭一台 WebSocket 服务器。
3.3 信令服务器的选型与搭建
信令服务器本身不负责传输媒体数据,它的任务就是帮助双方找到对方、交换 SDP 和 ICE 候选。
如果你已经有物联网平台,最省事的做法是把信令放在现有通道上。比如设备通过 MQTT 上报“我准备好连接了”,后台收到后生成一个 room 号,另一端的设备订阅同一个 topic,两边通过 MQTT 交换 SDP 和 candidate。WebRTC-IOT 的信令部分是协议无关的,只要最终能保证 SDP 到达对端,用什么消息通道都行。
如果你想快速验证,可以用 Node.js 写一个简单的 WebSocket 中转服务器,几十行代码就能搞定,主要逻辑就是转发消息。注意不要让它参与 SDP 的解析,它只负责当一个“中转邮局”,所有信令逻辑放到端侧去处理。
3.4 硬件摄像头/编码器输入
对嵌入式设备来说,摄像头采集和编码通常不是 WebRTC-IOT 库本身要管的,它是从“已经编码好的码流”开始介入的。
在我做的 RK3568 方案里,采集流程是先用 V4L2 拿到 YUV 原始帧,然后丢给硬件编码器输出 H.264 码流,再把每一帧的码流按长度切分,填充成一个 VideoFrame 对象,传给 WebRTC 的发送接口。这样,WebRTC 库不需要关心摄像头型号、分辨率、帧率,它只关心收到的数据是否带正确的时间戳和编码格式。
这里有一个常见的性能优化点:硬件编码器输出的码流 buffer 通常来自内核驱动分配的内存,要在用户态复制一次才能交给网络层。如果每一帧都复制,1080p 30fps 的码流一秒钟就要多拷贝几十 MB 的数据。我在接入时把内存分配方式调整成“先由 WebRTC 库申请好 buffer,再交给硬件编码器去填”,省掉了多余的拷贝,CPU 占用率立刻下来不少。这属于平台相关的优化,需要你对芯片的编解码 API 比较熟,但收益非常明显。
4. 移植到 ARM 开发板时最常踩的五个坑
4.1 内存分配器之争
嵌入式系统的内存分配器行为和桌面系统差距很大。桌面系统默认 malloc 可能表现很差,但 RAM 充足,你感受不到;嵌入式设备内存紧张,如果跑一段时间出现内存碎片,设备就各种离奇问题。
我在板子上跑 WebRTC-IOT 时,一开始用默认 malloc,运行大概一小时后内存碎片率上升,模块偶发崩溃。后来我把库的内存分配统一接到一个基于 TLSF 算法的内存池上,效果立竿见影,连续跑了三天内存曲线非常平稳。
如果你的项目内存压力很大,建议尽早把分配器定制接口接上,不要等到现场出问题再排查。
4.2 时间戳与时钟同步
这个坑是我调试时最隐蔽的一个。WebRTC 对 RTP 包里的时间戳语义有严格要求,H.264 的 RTP 时间戳单位是 90kHz,不是毫秒,也不是微秒。如果从硬件编码器拿到的时间戳直接当成 RTP 时间戳填进去,接收端会出现严重的音画不同步或者画面跳帧。
正确的做法是把硬件编码器的时钟统一换算成 RTP 时间戳基准,同时注意不同时钟源之间的漂移问题。特别是在设备上同时用硬件编码器时间和系统时间时,一旦时间源不统一,就会出现“一会儿正常、一会儿乱跳”的诡异现象。
后来我把所有流入 WebRTC 层的数据都统一走同一个时钟源,并且在编码器带上 PTS 信息一起传递,症状才彻底消失。
4.3 网络缓冲区太小导致丢包
嵌入式设备的内存紧张,有时候我们会把网络收发缓冲区设得很小,以为能省内存。但在实测弱网环境时,这个优化经常适得其反。
WebRTC 依赖接收端有一定深度的网络包缓冲区来做乱序重排和丢包检测。如果缓冲区太浅,网络抖动稍微大一点,数据还没等到前面的包补上来,后面到达的包就会被丢弃,接收端把整帧丢掉,画面便出现卡顿。我在一个室内移动机器人上测试时,因为缓冲区太小,设备穿墙一次就触发连续丢包,画面直接“冻住”,几秒后才恢复。
经过几轮调整,我把网络接收端的动态缓冲上限调到了 2 到 3 秒码流大小,同时保留动态调整机制,平滑网络后才自动缩小缓冲。这样既保证弱网下不轻易丢帧,又不会一直保持高延迟。
4.4 硬编解码器缓冲帧数
硬件编码器通常会缓存若干帧以优化编码效率,但这会直接增加端到端延迟。默认情况下,有些编码器会缓冲到 4 到 8 帧,按 30fps 算,这还没算网络传输,光编码端就引入 130 到 260 毫秒延迟。
如果你的应用是远程监控,这点延迟可以接受;但如果是远程操控、云台跟拍、无人机这类场景,延迟必须压下来。
我在项目里把编码器配置成低延迟模式,同时尽量使用 B 帧关闭或者 B 帧数量为 0 的配置,只保留 P 帧,换来的延迟降低非常可观。代价是压缩率稍微下降一些,但以现在的码率和带宽条件来说,这个代价非常划算。
类似的,解码端也要尽量少缓冲,不要把所有帧都攒齐了才去显示,否则端到端延迟又会莫名多出一截。这块排查起来尤其困难,因为从外部看好像网络没问题,实际上瓶颈在编码器内部。
4.5 编译优化与 NEON 指令
最后聊一下 CPU 优化。如果你用的 ARM 芯片支持 NEON 指令集,编译时不要吝啬开
-O3
和
-march=native
(交叉编译里要指定具体的架构参数),这对 RTP 打包、SRTP 加密、字节序转换这些高频操作有明显提升。
我做过一个对照,在 RK3568 的 Cortex-A55 上,不开启架构优化时,1080p 视频的 RTP 打包和加密大约消耗 18% 的 CPU;开启 NEON 优化后,降到 11% 左右。这点差异在跑多个业务应用的时候很关键。
但要注意,如果你要发布通用的固件包,不要用
-march=native
,它会针对编译机的 CPU 特性生成指令,拿到别的芯片上会直接非法指令崩溃。交叉编译时必须显式地指定目标芯片的架构,比如
-march=armv8-a+simd
。
5. 实测数据:延迟、资源占用与 libwebrtc 的对比
5.1 测试环境
为了给团队一个“能不能上生产线”的判断,我专门搭了一套对比测试环境。发送端是一块 RK3568 开发板,运行 Ubuntu 20.04,内存 4GB,摄像头采集 1080p 视频,H.264 硬件编码,码率固定 2Mbps,帧率 30fps。接收端是一台普通 x86 电脑,用浏览器收流。网络环境是一台本地交换机,同时插了一个 tc 网络损伤仪模拟丢包和延迟。
对比对象有两个:WebRTC-IOT 和一套基于官方 libwebrtc 裁剪编译的版本。两者在同一块板子上跑,尽量保证环境公平。
5.2 端到端延迟
端到端延迟的测量方法是在摄像头前放一个毫秒级计时器画面,接收端从解码后的画面里读出时间变化,再减去采集端当前时间。
结果如下:
| 方案 | 局域网延迟 | 加 20ms 抖动 | 加 2% 丢包 |
|---|---|---|---|
| WebRTC-IOT | 170 至 230 毫秒 | 210 至 280 毫秒 | 320 至 450 毫秒 |
| 裁剪版 libwebrtc | 210 至 280 毫秒 | 280 至 380 毫秒 | 460 至 650 毫秒 |
WebRTC-IOT 在局域网环境下的延迟大概在 200 毫秒上下,最重要的是延迟抖动比较小,这要归功于整条处理链路的缓冲很浅。libwebrtc 虽然在功能上更丰富,但因为内部有大量默认开启的音视频处理模块,虽然我们裁剪了不少,它内部的缓冲策略依然比专为嵌入式设计的库保守很多。
弱网环境下的差异更明显。丢包 2% 时,WebRTC-IOT 的画面会偶发轻微卡顿,但基本能保持流畅;libwebrtc 的缓冲策略更激进,无论怎么配置都会多出不少延迟,导致实时操作的手感差异很大。
5.3 CPU 与内存占用
CPU 占用我通过
top
和
perf
统计进程在编码、打包、加密环节的总消耗。
| 方案 | CPU 占用(1080p 30fps) | 常驻内存 |
|---|---|---|
| WebRTC-IOT | 约 12% 至 15% | 约 42MB |
| 裁剪版 libwebrtc | 约 25% 至 32% | 约 85MB |
内存上的差距是最明显的。libwebrtc 即便裁剪过,常驻内存也要 80MB 以上,对一些 128MB 内存的老设备来说太紧张了。WebRTC-IOT 把常驻内存控制在 40MB 左右,这意味着设备上还能剩下不少内存跑 AI 推理、业务逻辑或者数据上报。
CPU 上的差距主要来自模块裁剪的精细度。libwebrtc 即使在编译时裁剪了功能,运行时的模块初始化流程依然会加载不少无用的处理链,而 WebRTC-IOT 从根上就按需加载,让它不加载音频处理、不加载视频前处理,开销自然小了。
5.4 弱网表现
我模拟了几组不同的弱网环境,重点关注画面是否花屏、卡顿和自动调节码率的行为。
在 5% 丢包和 100ms 延迟的混合弱网下,WebRTC-IOT 的拥塞控制及时介入,码率从 2Mbps 降到 1.2Mbps 左右,画面清晰度虽然下降,但可观看性一直保持。调低码率后,延迟反而逐渐回落到 300 毫秒以内。这套自适应的反应速度,基本能覆盖大多数移动物联网场景。
如果丢包率继续上升到 10% 以上,画面会出现明显的帧冻结,但不会大面积花屏。这是因为 H.264 码流中的关键帧有依赖,部分丢包会导致后续帧无法解码,库会自动等待下一个关键帧恢复画面。测试中在 15% 丢包环境下,恢复时间大约在 0.5 到 1.5 秒之间,这点符合实际预期。
5.5 调优参数参考
针对我自己的测试环境,最终采用的调优参数组合是这样的:
- 编码器关闭 B 帧,GOP 设置为 2 秒一个关键帧;
- 发送端码率控制模式设为动态,最低 300kbps,最高 4Mbps;
- 网络接收缓冲上限设为 2 秒,初始值 100ms,按网络平滑度动态调整;
- 开启 SRTP 加密,不开音频通道以减少内存和 CPU 开销;
- ICE 的候选收集周期调短,优先用本地候选,再发起 STUN 检测。
这些参数在不同项目里不一定通用,但思路可以参考:先压延迟,再保可用性,码率和缓冲都交给动态控制去处理,而不是用固定值锁死。
6. 选型建议:什么场景适合 WebRTC-IOT
6.1 最适合它的几种场景
在实际项目里,我逐渐形成了自己的一套判断标准。如果项目满足下面这些条件里的两三条,WebRTC-IOT 基本就是合适的选择。
第一种是资源受限的嵌入式设备。内存小于 256MB、CPU 主频不高的开发板、工控板、边缘计算盒子,这类设备上跑 libwebrtc 会很吃力,但 WebRTC-IOT 可以轻松承载一路到两路的视频流。
第二种是需要低延迟双向通信的场景。远程操控机器人、无人机、无人车,或者需要实时回传操控指令的场景,WebRTC 的天然低延迟和双向数据通道特性非常契合。除了音视频流之外,WebRTC 还有 DataChannel,可以直接传控制指令和传感器数据,省得再单独维护一条 TCP 通道。
第三种是希望利用浏览器生态的物联网平台。设备端负责采集和传输,前端用网页直接展示和控制,不需要定制客户端。这套组合对快速落地、跨平台操作非常友好。
6.2 两条容易走错的路
也有人会问,既然 RTSP 这么成熟,为什么不继续用 RTSP?这个问题我踩过,也认真想过。
RTSP 的优势是协议成熟、生态系统庞大、很多摄像头原生支持,但它的短板也很明显:NAT 穿透能力弱,跨公网传输需要额外做端口映射和代理;传输默认走 RTP,没有内置加密;播放端兼容性不如浏览器原生支持的 WebRTC 好。如果你只是在内网做视频监控,RTSP 很合适;一旦要跨公网、跨运营商、跨防火墙,WebRTC 的 ICE 体系会省心很多。
另一个容易走错的路线是直接用 FFmpeg 做推流,配合 SRT 协议。SRT 在公网传输的稳定性确实比 RTSP 好,但它同样需要客户端支持,浏览器不能直接播放。而且 SRT 偏向“流媒体传输”,没有内置 WebRTC 那种完整的协商机制,端到端延迟也要看具体配置,相比之下 WebRTC-IOT 在“实时通信”这个语义上更匹配物联网设备的双向交互需求。
6.3 我对这套方案的真实评价
从第一次接触 WebRTC-IOT 到现在,我陆续在三个项目里用过它,整体感受是:它是目前少数真正站在嵌入式开发者角度设计的 WebRTC 实现。
它当然不是万能的。生态没有 libwebrtc 丰富,有些高级功能需要自己造轮子;文档相对简洁,很多细节要靠读源码去挖;团队如果对 C++ 和网络协议不熟,上手会有一点门槛。但对一个已经解决了“ WebRTC 能不能在嵌入式上跑起来”问题的项目来说,它把这些最麻烦的脏活累活都做了,给开发者的空间反而更大了。
就我个人而言,下次再遇到“设备侧要出流、浏览器侧要收流、中间网络环境不可控”的需求,我不会再犹豫是从 RTSP 还是从 libwebrtc 开始,而是直接把 WebRTC-IOT 放进候选列表里。对于面向物联网和嵌入式设备的实时通信项目来说,它确实走出了自己的路。
火山引擎视频云技术社区,是面向 AI 音视频开发者的技术交流平台。这里汇聚源自抖音、豆包等亿级 DAU 产品的 RTC、直播、点播、AI 媒体处理、音视频互动技术,提供接入指南、最佳实践、性能调优、场景案例、Demo 代码、开源项目、白皮书和 API 文档。社区汇聚官方工程师与一线开发者,为 AI 视频通话、数字人、AI 视频处理等应用的开发与落地提供技术支持。
更多推荐
所有评论(0)