一、WebRTC + AI + IoT:摄像头流接入、AI边缘推理、告警推送、双向语音对讲

说实话,这个标题看着挺长,但拆开来看,其实就是一套完整的智能安防闭环。我做了这么多年音视频,发现很多团队要么只懂WebRTC推流,要么只懂AI算法,真正能把摄像头流、边缘推理、告警、语音对讲串起来的人,其实不多。

今天这一章,我就带你走一遍这个闭环。从摄像头怎么把流推到边缘设备,到AI在边缘做推理,再到告警怎么推送到手机,最后实现双向语音对讲。嗯,这套架构我在好几个智慧工地项目里都落地过,踩过的坑也不少,咱们边聊边避。

1.1 整体架构:四层模型

先看一张图,把整个体系的结构理清楚。我个人习惯把这种系统分成四层:

摄像头接入层 RTSP / ONVIF / GB28181 → WebRTC 转换 AI边缘推理层 TensorRT / OpenVINO / TFLite 推理引擎 告警推送层 WebSocket / MQTT / FCM 推送 双向语音对讲层 WebRTC DataChannel / Opus 编解码 数据流方向 推理结果 告警事件 音频流

你看,数据从摄像头一路往上走,每一层都有明确的职责。我最早做这个架构时,把AI推理和告警推送混在一起写,结果代码耦合得一塌糊涂。后来才明白,分层不只是为了好看,更是为了后期维护和扩展。

1.2 摄像头流接入:从RTSP到WebRTC

市面上绝大多数摄像头都支持RTSP协议。但WebRTC不认RTSP,它只认自己的SDP和ICE那一套。所以我们需要一个「转码桥接」的过程。

我个人常用的方案是:用FFmpeg拉RTSP流,解码成原始帧,再通过WebRTC的Native API重新编码推出去。核心代码如下:

// C++ 示例:RTSP 转 WebRTC 推流
#include <ffmpeg/avformat.h>
#include <webrtc/api/peerconnectioninterface.h>

// 1. 打开 RTSP 流
AVFormatContext* fmtCtx = nullptr;
avformat_open_input(&fmtCtx, "rtsp://192.168.1.100:554/stream1", nullptr, nullptr);

// 2. 读取视频帧
AVPacket packet;
while (av_read_frame(fmtCtx, &packet) >= 0) {
    // 3. 将帧送入 WebRTC 编码器
    webrtc::VideoFrame frame = ConvertAVPacketToWebRTCFrame(&packet);
    peerConnection->AddTrack(frame);
}

// 4. 创建 Offer 并发送
peerConnection->CreateOffer(options, callback);
注意:RTSP 的 TCP/UDP 模式选择很关键。我在项目中遇到过,某些海康摄像头默认用 UDP 模式,但公网环境下 UDP 容易被防火墙拦截。建议强制使用 TCP 模式拉流,参数加 ?tcp 后缀。

1.3 AI边缘推理:在设备上跑模型

为什么要做边缘推理?说白了,就是把AI计算放在摄像头附近,而不是把视频流全部传到云端。你想想看,一个1080p的摄像头,一天产生的数据量是几十GB,全传云端成本太高了。

我建议在边缘设备(比如NVIDIA Jetson、RK3588、树莓派+TPU)上部署轻量级模型。以Jetson为例,用TensorRT加速YOLOv5做目标检测:

# Python 示例:Jetson 上运行 YOLOv5 推理
import tensorrt as trt
import pycuda.driver as cuda

# 加载 TensorRT 引擎
with open("yolov5s.engine", "rb") as f:
    engine = trt.Runtime(trt.Logger(trt.Logger.WARNING)).deserialize_cuda_engine(f.read())

# 创建执行上下文
context = engine.create_execution_context()

# 从 WebRTC 帧中获取图像数据
frame = webrtc_frame_to_numpy(video_frame)
input_data = preprocess(frame)

# 执行推理
output = np.empty(output_size, dtype=np.float32)
context.execute_v2([int(input_ptr), int(output_ptr)])

# 解析检测结果
boxes, scores, class_ids = postprocess(output, conf_threshold=0.5)

这里有个坑,我必须要说。边缘设备的算力有限,模型不能太大。我曾经试过直接把YOLOv5x(大模型)部署到Jetson Nano上,结果推理延迟到了800ms,根本没法用。后来换成YOLOv5s,延迟降到40ms,效果完全够用。

经验之谈:边缘推理的模型选型,建议遵循「够用就好」原则。检测精度从0.95降到0.90,用户感知不明显,但推理速度可能快3倍。我一般先在云端用大模型标数据,然后蒸馏成小模型部署到边缘。

1.4 告警推送:从边缘到手机

AI检测到异常事件后,需要立刻通知用户。这里涉及两个问题:推什么?怎么推?

推什么?我建议推三样东西:

  • 告警截图:从视频流中截取关键帧,压缩成JPEG(一般50KB以内)
  • 告警类型:比如「人员闯入」「车辆违停」「火焰检测」
  • 时间戳和位置:方便用户快速定位

怎么推?我推荐用WebSocket + MQTT的组合。边缘设备通过MQTT发布告警主题,云端或手机订阅。WebSocket则用于实时推送截图数据。

// JavaScript 示例:手机端接收告警
const ws = new WebSocket('wss://alert-server.example.com/ws');
const mqtt = mqtt.connect('mqtt://broker.example.com');

ws.onmessage = (event) => {
    const alert = JSON.parse(event.data);
    // 显示告警截图
    document.getElementById('alertImage').src = alert.snapshotUrl;
    // 显示告警信息
    document.getElementById('alertInfo').innerText = 
        `${alert.type} | ${alert.timestamp}`;
};

mqtt.subscribe('camera/+/alert');
mqtt.on('message', (topic, payload) => {
    const alert = JSON.parse(payload.toString());
    // 触发手机通知
    showNotification(alert);
});
关键点:告警推送的延迟必须控制在1秒以内。如果用户看到告警时,事件已经过去10秒,那这个告警基本没意义。我实测过,WebSocket + MQTT的组合在4G网络下,端到端延迟通常在300-500ms。

1.5 双向语音对讲:WebRTC的看家本领

双向语音对讲,说白了就是让用户能通过手机和摄像头那边的人说话。WebRTC天生支持这个功能,因为它本身就是为实时通信设计的。

实现思路很简单:手机端采集麦克风音频,通过WebRTC的音频轨道发送到边缘设备;边缘设备解码后通过扬声器播放。反过来,边缘设备采集麦克风音频,发送到手机端播放。

// JavaScript 示例:手机端发起语音对讲
const constraints = {
    audio: {
        sampleRate: 16000,
        channelCount: 1,
        echoCancellation: true,
        noiseSuppression: true
    },
    video: false
};

// 获取本地音频流
const localStream = await navigator.mediaDevices.getUserMedia(constraints);

// 添加到 PeerConnection
localStream.getAudioTracks().forEach(track => {
    pc.addTrack(track, localStream);
});

// 接收远端音频
pc.ontrack = (event) => {
    const remoteAudio = document.createElement('audio');
    remoteAudio.srcObject = event.streams[0];
    remoteAudio.play();
};

这里有个容易忽略的问题:回声消除。如果摄像头端的扬声器和麦克风距离太近,用户说话的声音从手机传到摄像头,再从摄像头扬声器出来,又被摄像头麦克风采集,传回手机,就形成了回声。

避坑指南:我曾经在一个项目中,摄像头端的回声消除没做好,用户投诉说「听到自己的回声,根本没法用」。后来我在边缘设备上启用了WebRTC内置的AEC(回声消除模块),并调整了扬声器音量到60%以下,问题才解决。记住:echoCancellation: true 必须两端都开启。

1.6 完整流程串联

把上面几块串起来,一个完整的智能安防流程是这样的:

  1. 摄像头通过RTSP推流到边缘设备(Jetson/RK3588)
  2. 边缘设备用FFmpeg拉流,转成WebRTC格式
  3. WebRTC流同时做两件事:一路转发到手机端供用户查看,另一路送入AI推理引擎
  4. AI推理引擎检测到异常(比如有人闯入),生成告警截图和类型
  5. 告警通过MQTT/WebSocket推送到手机端
  6. 用户点击告警,进入实时视频页面,发起双向语音对讲
  7. 语音对讲通过WebRTC的音频轨道双向传输

你看,整个流程其实不复杂,但每个环节都有细节。我最早做这个系统时,光RTSP转WebRTC就折腾了两周,后来发现是SDP协商的参数没对齐。嗯,这些坑咱们后面章节会一个个填。

1.7 性能指标参考

最后给一张表,是我在实际项目中测出来的性能数据,供你参考:

环节 指标 实测值 备注
RTSP拉流延迟 端到端 200-400ms 取决于网络和摄像头编码
AI推理延迟 单帧 30-50ms Jetson Nano + YOLOv5s
告警推送延迟 端到端 300-500ms 4G网络下
语音对讲延迟 端到端 150-300ms WebRTC默认配置
系统总延迟 摄像头→手机 500-800ms 含AI推理和传输

这些数据不是绝对的,但可以作为你搭建系统时的参考基线。如果你的延迟比这个高很多,那就要排查具体哪个环节出了问题。

最后说一句:这套架构的扩展性很好。你可以在边缘设备上换不同的AI模型,比如换成行为识别、口罩检测、甚至车牌识别。核心的WebRTC流通道和告警推送机制不用动。这就是分层设计的好处。

公众号:蓝海资料掘金营,微信deep3321