干过视频监控或者做直播技术的人,应该都经历过这种折磨:想做一个实时预览的摄像头页面,结果要么上 RTMP 推到流媒体服务器再转 HLS,播放端等上三五秒是常事;要么自己写一套 UDP 拉流协议,App 倒是装了,家里人还得教怎么点、怎么连。到了智慧养老这种场景,需求更苛刻——画面必须秒开,声音要双向清晰,老人按一下 SOS 就得让远端的子女或者服务人员立刻看到现场、最好还能直接通话。你会发现,传统的那套“监控推流 + 播放器拉流”思路,在交互性面前捉襟见肘。
我后来把项目从 RTMP/FLV 架构整个切到了 WebRTC,用手机当移动摄像机,再从 WebRTC 媒体流桥接到电话线路做告警呼叫,整个体验完全不一样了。这篇文章不是讲入门 Demo,而是复盘我在这套“WebRTC 移动摄像机 + 家庭监控 + 智慧养老联动”方案里做的选型、踩过的坑、以及最终跑通的落地方案,尤其会聊到 WHIP 在监控场景里的实际价值、FreeSWITCH 怎么和 WebRTC 打通,以及移动端采集那些文档里很少写的细节。
1. 为什么偏偏是 WebRTC:家庭监控与养老场景给技术出的难题
1.1 从“能看”到“真得能靠它救命”的需求变化
传统家庭监控,比如市面上的 IPCamera,核心需求就是“能看”。用户上班时瞄一眼家里猫在干嘛,或者看看有没有陌生人。这种场景下,HLS 的 5~10 秒延迟是可以忍的,毕竟没有强交互。但智慧养老不一样,我手里接到的需求是:独居老人在家里活动,系统要能识别跌倒,识别后不仅要录像,还要立刻让值班人员看到现场并通话确认。现场画面晚一秒,老人的风险就高一分。
这里有个很多人容易忽略的事实:养老场景里,摄像机不是给人看的,是给服务流程用的。报警、确认、救助、回访,这是一条完整的链路。链路上每个环节都可能需要音视频能力。老人按 SOS 后,值班人员要能“看到现场 + 听到声音 + 开口询问”,这就不是单向视频流能搞定的,它需要双工通信,需要低延迟,需要浏览器直接能跑。WebRTC 几乎是唯一一个不用装插件、不用装客户端、浏览器原生就支持的双工实时音视频方案。
1.2 WebRTC 与 RTMP/HLS 的差距:在延迟这件事上的本质区别
很多人一提到直播就想到 RTMP 推流 + HLS 播放,这是 CDN 时代的经典组合。但它的延迟通常在 3 到 10 秒,原因在于 HLS 基于 HTTP 的切片分发,播放器至少要缓冲几个 TS/MP4 分片才能保证流畅。RTMP 本身延迟不高,但 HLS 播放延迟高,而且整个链路是单向的,想实现双向通话基本不可能。
WebRTC 则走的是另一种思路:
- 传输层默认用 SRTP/SRTCP,加密与实时性兼顾;
- 用 UDP + 自适应码率,网络变差时降低视频质量而不是卡住等缓冲;
- 通过 ICE/STUN/TURN 做 NAT 穿透,让两个内网设备能直接建立点对点连接;
- 端到端延迟通常在 200~500ms,声音画面基本同步,双向通话的体验和打电话差不多。
我拿同样的摄像头源做了对比测试:RTMP 推流到 SRS,再经 HLS 播放,我用浏览器打开,从发起到画面出现花了 6.8 秒;而 WebRTC 直连,从点击呼叫到首帧显示只花了 700 多毫秒。这样的差距在家庭监控里可能只是体验问题,但在跌倒告警场景里就是救命问题。
1.3 WHIP 到底是什么,为什么监控场景越来越离不开它
搜 WebRTC 相关热词时,很多人都在问 “WebRTC WHIP 是啥意思”。WHIP 全称 WebRTC-HTTP Ingestion Protocol,直译是“基于 HTTP 的 WebRTC 推流协议”。我理解它的价值只有一句话:它把 WebRTC 从“点对点通话”扩展成了“一对多直播/监控”的标准接入方式。
以往 WebRTC 做监控,每个观看端都要和摄像头做一次 SDP 协商,摄像头侧要维护 N 个 PeerConnection,压力很大。WHIP 的做法是:摄像头先向流媒体服务器发一个 HTTP POST 请求,携带 SDP Offer,服务器返回 201 和 SDP Answer,一个稳定的推流会话就建立了。之后观看端统一从服务器拉流,摄像头不再关注有多少人在看。
我实际项目里就把移动摄像机端用 WHIP 推到了 Janus 网关,再由 Janus 做 WebRTC 分发。手机端代码量减少了很多,不需要自己维护 PeerConnection 列表,出错率也降了。这个模式几乎就是专门为 IotCamera、移动摄像机这类会长期在线、但观看端不固定的设备设计的。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 移动摄像机端搭建:手机摄像头如何变成一路稳定的 WebRTC 流
2.1 采集端的前置准备:权限、分辨率、码率与帧率怎么取舍
移动摄像机,我的实现是直接用 Android/iOS 手机作为采集设备。相比买硬件摄像头,手机方案有几个好处:
- 自带 4G/5G 网络模组,不需要额外配 Wi-Fi;
- 屏幕可以本地显示预览画面,也可以做成老人能看懂的“大字模式”;
- 麦克风、扬声器、陀螺仪齐全,跌倒检测可以直接靠传感器辅助;
- 最容易做 SOS 按钮交互。
但手机毕竟不是专用摄像头,采集端有几个参数必须仔细调。
分辨率。 别一上来就上 4K。移动网络的上行带宽根本不支持稳定传输 4K,而且养老场景不需要看清毛孔,需要看清的是“人是否倒地、是否有异常动作”。我认为在移动网络下 720p 是甜点,1080p 在 Wi-Fi 环境下可用,4K 在移动端是灾难。实测 720p、30fps、码率 1.5Mbps 配置下,画面质量和流畅度最平衡。
帧率。 监控场景 15fps 其实也能看,但 WebRTC 通话要双向,帧率太低会导致声音和画面不同步感明显。我建议至少 24fps,让画面连续性够好。如果老人家里光线暗,帧率别硬扛,优先保亮度。
码率与网络匹配。 4G 网络上下行不对称,很多地方上行只有 5~10Mbps,不能把码率设得太死。我建议初始码率设 1.5Mbps,然后开启 WebRTC 的带宽估计,让它根据网络状况自动调整。代码层面可以通过 RTCRtpSender.setParameters 或者 RTCRtpSender.replaceTrack 配合动态调整,但更省心的是直接在 SDP 里设置 b=AS 上限。
我踩过的一个比较典型的坑是:没有做权限持久化处理。WebRTC 的 getUserMedia 在页面每次刷新后,如果浏览器不信任这个域名,都会再弹一次权限请求。对养老场景这不现实——老人根本不会处理权限弹窗。解决方法是使用 HTTPS + 首次使用时申请权限并记住,或者在原生 App 里用 WebView 的 grantPermission 提前授权。
2.2 信令服务与 SDP 协商的落地细节
WebRTC 传输音视频的是 SRTP,但建立连接前需要交换 SDP(Session Description Protocol)。SDP 里面包含了编解码器、IP 端口、指纹、ICE 候选等信息。信令服务器就是为了交换这些信息的。
我建议直接使用 WebSocket + JSON 自定义一个简单信令协议,别一上来就引入太重的东西。核心信令就四条:
join:客户端进入房间/会话;offer:发起方发送 SDP Offer;answer:接收方返回 SDP Answer;candidate:双方交换 ICE Candidate。
下面这个 JSON 是我项目里实际用的消息格式,简化过,供参考:
json复制{
"type": "offer",
"roomId": "room_001",
"senderId": "camera_10",
"sdp": "v=0\r\no=- 83778964134 2 IN IP4 127.0.0.1\r\ns=-\r\n..."
}
信令服务器用 Node.js + ws 库几百行就能写出来,关键是要支持 Broadcast 或者 Topic 路由。比如一个摄像头绑定了多个家属,家属端上线时要能收到摄像头的在线状态,也要能发起拉流请求。
有一个容易忽略的点:如果使用 WHIP 推流给网关,那么信令不再是 PeerConnection 直连,而是由 WHIP 的 HTTP POST 完成 Offer/Answer 协商,摄像头端不需要单独部署信令服务器了。这个取舍我在 1.3 里提到了,实际项目里,我把“手机摄像头”做成“WHIP 推流终端”,把“观看端”做成“WebRTC 拉流播放器”,这样信令压力小很多。
2.3 弱网下的编码器选择与码率自适应
养老场景的移动摄像机,大多数时间不在 Wi-Fi 环境,而是用家里宽带或 4G。一旦网络抖动,视频画面会卡顿甚至花屏,这个时候考验的就是编码器和拥塞控制的功力。
编码器选择上,我强烈建议优先用硬编。
- 在 Android/iOS 上,优先使用
RTCPeerConnection的RTCRtpSender默认编码器,通常会优先 H.264; - 在 Chrome/Edge 里,WebRTC 默认支持 VP8、VP9、H.264,不同版本偏好不一样;
- 服务端如果要转码分发,H.264 兼容性最好,否则 Janus 或 mediasoup 可能需要在网关做转码,增加延迟。
我这边测试下来,H.264 的硬编在手机上发热和功耗远低于 VP8 软编,毕竟移动摄像机要 7x24 小时在线,发热直接决定设备稳定性。
码率自适应是 WebRTC 的看家本领。它通过 REMB 或 Transport-CC 机制实时估算可用带宽,然后反馈给发送端,发送端动态调整编码码率和分辨率。实测在 4G 网络下,带宽从 2Mbps 跌到 300kbps 时,画面会主动降到 320p 左右,但不会断流,音频仍然保持清晰。
实际运营中你会发现,音频优先级高于视频。尤其养老告警场景,判断老人是否安全,很多时候是靠声音而不是画面。如果带宽实在不够,我建议把音频码率设为最高优先级,视频可以降到 10fps、低分辨率,但声音必须双向畅通。WebRTC 本身支持这个,可以通过配置 maxBitrate 和 degradationPreference 来实现:
javascript复制const sender = pc.getSenders().find(s => s.track && s.track.kind === 'video');
const params = sender.getParameters();
params.degradationPreference = 'maintain-framerate';
params.encodings[0].maxBitrate = 1500000; // 1.5Mbps 上限
await sender.setParameters(params);
3. 观看端与联动层:从浏览器实时预览到 FreeSWITCH 呼叫告警
3.1 浏览器播放端:不需要插件的 H5 实时画面
WebRTC 最大的优势之一就是浏览器原生支持,无需安装插件。家属端或者值班人员只要打开一个网页,输入房间号,就能实时看到摄像头画面,并且可以直接语音对讲。
一个标准的拉流播放器大概是这样:
javascript复制const pc = new RTCPeerConnection({ iceServers: [{ urls: 'stun:stun.l.google.com:19302' }] });
pc.ontrack = (event) => {
if (event.track.kind === 'audio') {
audioElement.srcObject = event.streams[0];
} else if (event.track.kind === 'video') {
videoElement.srcObject = event.streams[0];
}
};
// 发起拉流请求,服务端返回 SDP Offer,这里用一个 fetch 处理
const response = await fetch('https://your-signaling-server/api/view', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ roomId: 'room_001' })
});
const data = await response.json();
await pc.setRemoteDescription(data.offer);
const answer = await pc.createAnswer();
await pc.setLocalDescription(answer);
// answer 再发回信令服务器
这里有几个体验细节:
- 首帧时间:浏览器的
ontrack触发时,画面已经可以开始渲染,不需要等全部缓冲完。 - 自动播放策略:浏览器禁止带声音的视频自动播放,所以要做一次用户点击手势,然后调用
video.play()。养老场景里,值班人员点击“接听”按钮是一个天然的手势,正好满足策略。 - 画面旋转:手机摄像头竖屏推流时,在网页可能出现画面旋转 90 度的问题。需要协商时在 SDP 里带上
degrationPreference,或者服务端用transform做旋转。
实际做的时候,我把“拉流”和“告警”做在了同一个页面:页面长驻后台,一旦收到告警事件的 WebSocket 推送,立即弹出全屏播放窗口,并自动播放音频。这个交互逻辑比传统监控软件那种“先打开 App 再找到设备再点预览”快太多。
3.2 接入 FreeSWITCH:WebRTC 与电话线路打通后能干什么
热搜词里有“freeswitch webrtc配置”,我专门说下这里。FreeSWITCH 是一个开源软交换,天然支持 SIP 协议,可以对接传统电话网络(PSTN)或内部分机。WebRTC 和 FreeSWITCH 打通的原理,本质上是把 WebRTC 的媒体流转换成 SIP/RTP 流。
FreeSWITCH 里有一个比较典型的模块叫 mod_verto,专门用于 WebRTC 接入。配置好后,WebRTC 客户端可以通过 WebSocket 连上 FreeSWITCH,然后像 SIP 电话一样注册、拨号。
打通后,我能实现什么场景?
- SOS 按钮触发自动呼叫:手机摄像机端检测到跌倒或老人按下 SOS,通过信令服务器触发业务后端,后端调用 FreeSWITCH 的 API,自动拨打预设的家属电话或 120;
- 双向语音:通话建立后,家属/值班人员可以从电话端听到现场声音,也可以直接说话,老人不需要操作任何设备;
- 通话录音:FreeSWITCH 可以对每次告警通话录音留档,方便事后复盘。
配置方面,一个最小可用的 FreeSWITCH WebRTC 环境大致如下(freeswitch 版本 1.10+):
xml复制<configuration name="verto.conf.xml" description="WebRTC">
<verto>
<profiles>
<profile name="default">
<param name="ws-binding" value=":8080"/>
<param name="wss-binding" value=":7443"/>
<param name="moh-sound" value="$${hold_music}"/>
<param name="dialplan" value="XML"/>
</profile>
</profiles>
</verto>
</configuration>
然后在拨号计划里配置一个分机,呼叫时可以通过 bridge 到 sofia 网关,或者直接桥接到 WebRTC 的 dial string。具体的拨号计划需要根据自己的内网号码段写,这里就不贴全了。
关键提醒:WebRTC 的音频编码通常使用 Opus,而传统电话线路使用 G.711。FreeSWITCH 默认会做编码转换,要留意转换带来的 CPU 开销。如果是低频告警场景(一天几次呼叫),完全没问题;如果要做 7x24 小时全双工通话,服务器要选好一点的 CPU。
3.3 告警联动设计:跌倒检测、SOS 按钮与自动呼叫的触发链路
智慧养老的核心不是“视频”,而是“事件驱动的服务闭环”。我设计的联动链路如下:
- 手机摄像机端(或硬件摄像头)通过 WebRTC 推流到 Janus/FreeSWITCH;
- 业务后端持续接收设备心跳和事件消息,比如跌倒检测通过手机陀螺仪+AI 视觉模型判断,识别到异常后发送告警 WebSocket 事件;
- 后端收到告警后,调用 FreeSWITCH ESL API,发起自动外呼;
- 家属接听电话后,可以通过 DTMF 按键,选择“查看现场画面”;
- 后端收到 DTMF 指令后,在正在进行的通话会话中,把 WebRTC 视频流附加进去,家属手机/浏览器直接弹出画面。
这里有一个比较 tricky 的技术点:普通电话线路不支持视频。要真正实现“电话接通后看视频”,家属手机也需要用 WebRTC/App 来做接听端。我在实际项目里的做法是:家属安装一个轻量 App,App 常驻后台,收到推送后自动拉流,音频走 WebRTC,而不是真的打运营商电话。FreeSWITCH 在这里承担的角色是桥接内侧分机和外线,确保当老人不在 WiFi 覆盖时,还能通过蜂窝网络建立语音通道。
更稳妥的方案是:告警电话通过 FreeSWITCH 拨打家属手机,接通后家属手机 App 自动弹出现场视频,视频走 4G/5G 数据通道,整个通话体验和的视频通话一致。这种“电话+数据通道”双通道设计,可靠性比单一 WebRTC P2P 高得多。
4. 实战踩坑记录:NAT 穿透、回声、设备兼容性
4.1 NAT 穿透:STUN/TURN 的取舍,以及 TURN 服务器带宽成本
WebRTC 连接最怕 NAT,尤其移动摄像机在家庭 4G 网络下,运营商级 NAT 非常常见。STUN 是帮助客户端发现公网地址的,能穿透大多数 NAT;但遇到对称型 NAT,STUN 就不够了,必须依赖 TURN 中转。
实际项目里,我把 TURN 服务器作为兜底方案,但严格控制使用频率,因为 TURN 服务器带宽成本很高,尤其是在长期在线、视频码率 1.5Mbps 的情况下,一个月流量可能轻松跑掉几百 GB。
我的做法是:
- 先部署 STUN,让多数 P2P 连接直接打通;
- 如果 ICE 候选里没有
srflx或relay类型,后端就自动切换为“TURN 中转模式”; - 监控中如果长期使用 TURN,考虑把摄像头和观看端拉到同一个内网段,比如通过家庭路由器做端口映射,减少中转流量。
坦率讲,在运营商 4G 网络下,P2P 直连成功率并不高。我实测过一版,直连成功率大约 60%~70%,其余 30% 只能走 TURN。所以 TURN 服务器不是可选项,而是必需项,只是必须控制成本。
4.2 回声与啸叫:免提通话场景下的音频处理
移动摄像机放在老人家里,一般开免提,这样老人不用按住手机也能说话。但免提会导致扬声器声音被麦克风采集,产生回声。WebRTC 有内置的 AEC(Acoustic Echo Cancellation),getUserMedia 里需要显式开启:
javascript复制const stream = await navigator.mediaDevices.getUserMedia({
audio: { echoCancellation: true, noiseSuppression: true, autoGainControl: true },
video: { facingMode: 'environment', width: { ideal: 1280 }, height: { ideal: 720 } }
});
但现实是,手机扬声器的回声消除效果远不如专用硬件设备。我想了一个变通方案:在告警通话时,优先使用听筒模式而非扬声器模式,让老人靠近手机说话。但我又意识到,老人不一定能马上把手机举到耳边,所以这个方案只能作为备选。
真正有效的做法是,在采集端做一个音频轨动态切换:检测到老人按 SOS 后,开启大音量扬声器,同时调高回声消除强度,并压低扬声器音量到 80%。实测能明显减少啸叫,但无法完全消除,所以后台值班端关闭手机扬声器的自动增益,改用耳机也是必要的。
4.3 设备兼容性差异:Android 碎片化与 iOS 的约束
WebRTC 本身跨平台,但具体到移动端浏览器,坑不少。
Android 端:
- 不同 ROM 对
getUserMedia的权限策略不一致,有的必须打开“允许后台访问相机”,否则锁屏后视频轨会断开; - Chrome 在部分国产 ROM 上不支持
RTCPeerConnection.addTransceiver,需要用兼容写法; - 息屏之后,WebRTC 仍在推流,但系统可能回收相机资源,导致黑屏。解决方法是保持前台 Service + 部分手机需要开启“省电策略-无限制”;
- 个别机型(尤其低端机)的 H.264 硬编只在特定分辨率下才可用,比如 1280x720 没问题,但 640x360 反而走软编,导致延迟和 CPU 升高。
iOS 端:
- Safari 的
RTCPeerConnection在某些 iOS 版本上和 WebRTC 标准实现有差异,特别是setParameters的行为不够一致; - 屏幕常亮限制较严格,如果手机长时间熄屏,WebRTC 采集可能会被系统挂起;需要配置后台模式,并且使用原生封装而非纯 H5;
- iOS 上获取摄像头权限需要
NSCameraUsageDescription和NSMicrophoneUsageDescription。
我的建议是:如果做的是商用智慧养老产品,不要依赖纯 H5 WebRTC,一定要封装一个原生 App 的 WebView,把 getUserMedia 权限、后台常驻、音频焦点这些系统能力控制住,否则坑会非常多。
5. 从家庭监控到智慧养老:这套方案的边界、成本与落地建议
5.1 隐私与数据安全
养老场景最敏感的就是隐私。摄像头 7x24 小时采集室内画面,涉及老人日常生活,一旦泄露,后果很严重。WebRTC 的传输层强制 SRTP 加密,这点比传统 RTMP/HTTP-FLV 有优势。但仍需注意几个环节:
- 信令服务器要上 TLS,否则 SDP 明文可以被中间人窃取,听到通话内容;
- 录像存储不能裸存,建议用 HLS 加密分片或者 MP4 加密后再上传;
- 权限模型要细粒度,不能一个房间号全公司都能看,必须至少做到“设备owner”和“临时访客”两级;
- 摄像机端要支持远程一键销毁数据或者关闭采集。
我还做了一个“本地闭环”设计:如果网络断开,摄像机本地继续录像,但关键事件(跌倒/告警)先缓存在本地,网络恢复后自动上传。这个设计在隐私上有一个好处,就是普通时段数据不上云,只有事件前后 30 秒的录像会加密上传,减少了隐私暴露面。
5.2 服务器带宽与成本估算
做技术选型时,必须把成本算清楚。以一套 100 路移动摄像机、每天平均在线 10 小时的方案为例:
- 每路视频码率 1.5Mbps,每小时流量约 675MB;
- 100 路一天总流量约 675GB;
- 如果 30% 会话走 TURN 中转,TURN 服务器一天就要扛 200GB 左右的带宽;
- 按国内主流云厂商 CDN/带宽报价,单月带宽成本可能在几千到几万元之间。
所以我的建议是:能做 P2P 就做 P2P,TURN 只做兜底。还可以做网络层优化,比如视频码率在非紧急时降到 800kbps,只在告警期间提升到 2Mbps。这样既保证日常成本可控,也保证了紧急时刻的画质。
另外,移动摄像机如果主要在家里用,可以考虑让手机端连家里 Wi-Fi 后,通过局域网直连观看端做 P2P,不经过公网服务器,这个模式对多子女家庭很实用。
5.3 部署架构建议
我跑通的最终部署架构大概是这样的:
| 模块 | 技术选型 | 作用 |
|---|---|---|
| 采集端 | Android/iOS 原生 App + WebRTC + WHIP | 手机摄像头采集、编码、推流 |
| 信令/业务后端 | Node.js/Koa + WebSocket | 房间管理、事件推送、权限控制 |
| 流媒体网关 | Janus 或 mediasoup(可选 SRS) | WHIP 拉流、WebRTC 分发 |
| 软交换 | FreeSWITCH(mod_verto + ESL) | 电话外呼、录音、与 WebRTC 桥接 |
| 观看端 | H5(WebRTC API)或嵌入式 WebView | 实时预览、双向语音、告警弹窗 |
| 存储 | MinIO/云存储 + HLS 加密分片 | 事件录像、回放 |
这个架构最明显的好处是模块化。摄像头端、观看端、软交换、存储各自独立,任何一个模块出问题不影响其他。尤其对于智慧养老这种长时间运行、又需要稳定服务的场景,模块化比“一套大而全的私有协议”更可控。
不过也要提醒一句:这套架构里,Janus 和 FreeSWITCH 都要吃不少 CPU。如果你在线路数不多(50 路以内),一台 8 核 16G 的云主机足够;但如果要做 4K 转码或多路并发,建议 GPU 实例或者把转码放到流媒体服务端。
6. 从“能用”到“好用”的最后一公里
整个项目做完,我最大的体会是,WebRTC 解决的是“实时链路”问题,而智慧养老真正解决的是“服务链路”问题。链路通了之后,要让家属愿意长期使用,还差几个体验细节:
- 摄像机端必须支持断线自动重连、重新推流,否则老人家里路由器一重启,画面就永久性消失了;
- 观看端要有“事件回看”功能,不能只有直播,否则用户不知道自己离线时发生了什么;
- 告警通知不能只推 App 消息,还必须支持短信和电话,因为家属可能没装 App;
- 所有操作界面,包括 WebRTC 播放页,尽量做无障碍适配,字号要大,操作要少。
我个人在多次灰度测试里发现,很多看起来“技术完美”的方案,最终都是败给了使用门槛。老人家属最常用的操作其实就是“收到告警、点开链接、看到画面、听到声音”。如果一步做不到,这个产品就会从“刚需”变成“摆设”。
WebRTC 在这套链路里真正扮演的是一个“连接器”,把手机摄像头、浏览器播放器、软交换电话系统全部串在一个实时媒体平面上。相比传统 RTMP/HLS 方案,它把延迟从秒级降到了毫秒级,把单向视频升级成了双向通信,也让监控事件能直接联动到电话网络。技术上每一步都有不少细节,但走通之后,你会发现家庭监控与智慧养老的融合,不再是堆硬件、凑功能,而是真正从“能不能看”进化到了“能不能救”。如果你也在评估类似场景,我建议先用一个 WebRTC Demo 跑通端到端延迟和采集端稳定性,再决定是否投入完整架构。这一步的验证成本最低,也最能暴露真实瓶颈。
