做低延迟直播或者实时互动项目时,很多团队会遇到一个很典型的问题:浏览器端使用 WebRTC 推流,延迟低、免插件、秒开体验好;但下游的 CDN、云直播平台或传统播放器却常常只认 RTMP 流。两边“方言”不通,就需要在中间搭一个转换网关,把 WebRTC 的传输媒体转换成 RTMP 协议输出。这个问题困扰过不少刚接触流媒体开发的同学,网上资料又分散。本文就把“webrtc2rtmp 测试环境”整套链路整理成一份可直接照做的教程,从协议原理讲到容器化部署,再把常见坑点一次说清楚。

1. 为什么要搭 WebRTC 转 RTMP 测试环境

1.1 两个协议各自的定位

WebRTC 是一套浏览器原生支持的实时音视频通信能力集合,底层使用 SRTP 加密媒体包,默认走 UDP 传输,配合 ICE、DTLS、SCTP 等机制完成连接建立和数据收发。它的优势在于端到端延迟极低,通常在几百毫秒以内,非常适合视频会议、连麦、在线课堂这类强互动场景。

RTMP 则是 Adobe 推出的老牌直播协议,基于 TCP 长连接,封装的是 FLV 流。它在直播行业沉淀了十几年,几乎所有 CDN、云直播服务商、播放器软件都支持 RTMP 推流,兼容性极强。虽然延迟比 WebRTC 高一些,通常在 1 到 3 秒,但胜在稳定成熟、接入成本低。

所以,实际项目中往往出现“浏览器用 WebRTC 推流做低延迟采集,但最终要进入 RTMP 生态供大规模分发播放”的需求。webrtc2rtmp 就是连接这两套生态的桥梁。

1.2 测试环境解决什么问题

在生产环境做协议对接之前,我们需要先在一个隔离的测试环境里验证链路是否通。具体来说,测试环境可以解决以下几个问题:

  • 验证 WebRTC 推流地址、RTMP 拉流地址是否能正常建立连接;
  • 验证转封装后的画面、音频是否能被下游播放器识别;
  • 验证端口、防火墙、网络策略是否满足要求;
  • 为后续接入 CDN、云直播平台提供本地排错基础。

很多人一开始直接拿着测试机去对接生产 CDN,一旦拉流失败,根本分不清是 CDN 配置问题、网络问题,还是协议转换的问题。所以先搭建一套本地 webrtc2rtmp 测试环境,把链路跑通,再进入下一步,会稳妥很多。

2. 核心链路与协议转换原理

2.1 WebRTC 推流和拉流需要注意什么

WebRTC 本身不区分“推流”和“拉流”两个协议,而是通过 SDP 协商双方的角色。普通话筒端调用 getUserMedia 采集音视频,再通过 RTCPeerConnection 添加轨道,这个过程通常叫推流。浏览器或播放器端收到远端轨道并渲染,这个过程通常叫拉流。

但要注意,WebRTC 是端到端模型,如果没有信令服务器和媒体服务器,浏览器之间无法直接互连。因此在 webrtc2rtmp 的场景里,我们需要一个媒体服务器来接收浏览器的 WebRTC 流,再由媒体服务器转封装后以 RTMP 协议推出去。

这里需要澄清一个概念:webrtc2rtmp 通常不需要重新转码视频编码,而主要是转封装。WebRTC 常见的视频编码是 H.264,音频编码是 Opus;RTMP 常见视频编码是 H.264,音频编码是 AAC。如果双方视频编码一致,那么视频轨道可以直接转封装,但音频轨道如果从 Opus 转为 AAC,就需要考虑音频转码能力。这是后面排错时最容易忽略的地方。

2.2 协议转换的完整步骤

一条标准的 webrtc2rtmp 链路可以拆成以下几步:

  1. 浏览器采集摄像头和麦克风,得到本地音视频轨道;
  2. 浏览器与媒体服务器建立 WebRTC 连接,通过 SRTP 上传音视频数据;
  3. 媒体服务器收到 WebRTC 流,进行解封装;
  4. 媒体服务器将 H.264 视频重新封装为 FLV,并将音频按需转换为 AAC;
  5. 媒体服务器以 RTMP 推流模式连接下游 RTMP 服务或者直接对外提供 RTMP 输出;
  6. 播放器通过 rtmp:// 地址拉流播放。

在这条链路里,媒体服务器承担了信令、媒体转发、转封装、RTMP 输入输出等多重角色。常见的选择有 SRS、ZLMediaKit、MediaMTX、Ant Media Server 等。本文的实战部分以 SRS 为例,因为它的 Docker 镜像使用方便,WebRTC 和 RTMP 支持都比较完整。

3. 测试环境搭建前期准备

3.1 硬件与操作系统要求

webrtc2rtmp 测试环境不需要很高配置,普通的 Linux 服务器、虚拟机甚至本机 Docker 都可以跑。如果只是本机验证,建议使用 Linux 系统或者 macOS;如果使用 Windows,也可以通过 Docker Desktop 完成,但要注意 WebRTC 的 UDP 端口映射和防火墙设置。

本文示例以 Linux + Docker 为主。这样做的好处是环境隔离、部署快速、清理方便,不会污染宿主机。

3.2 端口规划

在搭建之前,建议先规划好测试环境的端口,避免后面排查时手忙脚乱。SRS 默认使用以下端口:

端口 协议 用途
1935 TCP RTMP 推流与拉流
1985 TCP HTTP API 接口
8080 TCP HTTP 服务器 / 演示页面
8000 UDP WebRTC 媒体传输

其中 8000/udp 是 WebRTC 媒体流的关键端口,很多人在测试时只开放了 TCP 端口,导致 WebRTC 推流一直失败。搭建测试环境时,一定要保证 UDP 端口可通。

3.3 安装 Docker

如果还没有安装 Docker,可以用以下命令快速安装(Ubuntu/Debian 系):

sudo apt update
sudo apt install -y docker.io docker-compose
sudo systemctl enable docker
sudo systemctl start docker

CentOS/RHEL 系可以用:

sudo yum install -y yum-utils
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
sudo yum install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
sudo systemctl enable docker
sudo systemctl start docker

版本不需要刻意追求最新,能正常拉取镜像、运行容器即可。如果你使用的是其他操作系统,按对应平台的 Docker 安装文档操作就行。

4. 完整实战:用 SRS 搭建 webrtc2rtmp 测试环境

4.1 拉取镜像并启动 SRS

SRS(Simple Realtime Server)是国产开源流媒体服务器,支持 RTMP、WebRTC、HLS、HTTP-FLV 等多种协议。它的 Docker 镜像使用非常方便,一条命令就能启动一个带 WebRTC 能力的服务。

先创建独立的测试目录:

mkdir -p ~/webrtc2rtmp-test
cd ~/webrtc2rtmp-test

然后直接运行容器。假设你的服务器 IP 是局域网地址,例如 192.168.1.10 ,那启动命令如下:

docker run --rm -it \
  -p 1935:1935 \
  -p 1985:1985 \
  -p 8080:8080 \
  -p 8000:8000/udp \
  -e CANDIDATE=192.168.1.10 \
  ossrs/srs:5

如果你是纯本机测试,可以把 CANDIDATE 设为 127.0.0.1 :

docker run --rm -it \
  -p 1935:1935 \
  -p 1985:1985 \
  -p 8080:8080 \
  -p 8000:8000/udp \
  -e CANDIDATE=127.0.0.1 \
  ossrs/srs:5

这里 CANDIDATE 是 WebRTC ICE 协商时需要告知浏览器的服务器公网或局域网 IP。如果配置错误,浏览器可能一直停留在 connecting 状态。

4.2 验证 SRS 服务是否正常

容器启动后,可以通过 HTTP API 检查服务状态:

curl http://localhost:1985/api/v1/versions

如果正常,会返回类似下面的 JSON:

{
  "code": 0,
  "server": "SRS/5.0",
  "version": "5.0.x"
}

也可以用浏览器访问 http://localhost:8080/ 查看 SRS 自带的演示页面。不同小版本页面地址可能有差异,但一般都有 WebRTC 推流和播放的 demo 入口。如果页面打不开,优先检查 8080 端口是否被占用,以及容器是否还在运行。

4.3 浏览器端 WebRTC 推流

SRS 自带的演示页面承担了信令服务器的角色,我们不需要另外写信令服务。在浏览器打开 SRS 的 WebRTC 演示页面,进入推流/播放相关入口,根据页面提示填写或选择默认参数,点击开始推流。

如果没有现成的页面入口,也可以直接使用 SRS 支持的 WebRTC 推流地址格式:

webrtc://192.168.1.10/live/livestream

在页面或者自定义前端中把推流地址设置成上面的格式,然后授权摄像头和麦克风。浏览器会先获取本地媒体流,再通过 WebRTC 与 SRS 建立连接,开始上传。

这里需要注意:浏览器只有在 localhost 或 HTTPS 环境下才会授予摄像头和麦克风权限。如果你用 IP 访问测试页面,请确认页面是通过 HTTPS 提供的,或者直接使用 127.0.0.1 访问。

推流成功后,SRS 的控制台日志中会出现推流记录,浏览器页面也会显示本地预览和推流状态。此时我们可以认为 WebRTC 推流这半条链路已经通了。

4.4 验证 RTMP 输出链路

WebRTC 推流成功之后,SRS 已经将收到的流转封装为 RTMP 流输出。在测试机上用 ffplay 拉流验证:

ffplay -i rtmp://127.0.0.1:1935/live/livestream

如果没有安装 ffplay,也可以用 VLC 打开同一个地址:

rtmp://127.0.0.1:1935/live/livestream

如果播放器能正常出画面、有声音,说明 webrtc2rtmp 整条链路已经跑通。

如果只想验证 RTMP 服务本身是否正常,可以先用 ffmpeg 推一路普通的 RTMP 流:

ffmpeg -re -i sample.mp4 -c copy -f flv rtmp://127.0.0.1:1935/live/test

然后用播放器打开 rtmp://127.0.0.1:1935/live/test 。如果能播放,说明 RTMP 端口没有问题,问题就集中在 WebRTC 一侧。

4.5 用 Docker Compose 固化测试环境

实际工作中,直接跑一条 docker run 命令虽然方便,但参数多,不容易维护。更推荐用 Docker Compose 把测试环境固化下来。

在 ~/webrtc2rtmp-test 目录下创建 docker-compose.yml :

services:
  srs:
    image: ossrs/srs:5
    container_name: srs-webrtc2rtmp
    restart: unless-stopped
    ports:
      - "1935:1935"
      - "1985:1985"
      - "8080:8080"
      - "8000:8000/udp"
    environment:
      - CANDIDATE=192.168.1.10
    volumes:
      - ./srs.conf:/usr/local/srs/conf/srs.conf:ro

如果你需要自定义 SRS 配置,可以准备一份 srs.conf 并挂载进容器。例如把 RTMP 和 WebRTC 端口明确写出来:

listen              1935;
max_connections     1000;
daemon              off;
srs_log_tank        console;

http_api {
    enabled         on;
    listen          1985;
}

http_server {
    enabled         on;
    listen          8080;
    dir             ./objs/nginx/html;
}

rtc_server {
    enabled         on;
    listen          8000;
}

vhost __defaultVhost__ {
    rtc {
        enabled     on;
    }
}

配置中的路径和参数需要根据你实际使用的 SRS 版本调整。保存后用下面的命令启动:

docker compose up -d

这样后续重新搭建测试环境就非常快,团队成员之间也能通过一份 compose 文件保持环境一致。

5. 备选方案:Nginx RTMP 和 Node Media Server

5.1 Nginx RTMP 快速启动

SRS 是 webrtc2rtmp 场景里比较省心的方案。但如果你只是想单独搭一个 RTMP 测试地址,用于验证 RTMP 推流和拉流,那么 Nginx RTMP 模块也很常用。

基于 Docker 的启动方式:

docker run -d \
  -p 1935:1935 \
  -p 8080:80 \
  -v /path/to/nginx.conf:/etc/nginx/nginx.conf:ro \
  --name nginx-rtmp \
  alfg/nginx-rtmp

其中 nginx.conf 至少需要包含以下配置:

worker_processes auto;

events {
    worker_connections 1024;
}

rtmp {
    server {
        listen 1935;
        chunk_size 4096;

        application live {
            live on;
            record off;
        }
    }
}

启动后,RTMP 测试地址就是:

rtmp://127.0.0.1:1935/live/test

用 ffmpeg 推流:

ffmpeg -re -i sample.mp4 -c copy -f flv rtmp://127.0.0.1:1935/live/test

用播放器拉流:

ffplay -i rtmp://127.0.0.1:1935/live/test

Nginx RTMP 本身不能直接接收 WebRTC 推流,它只负责 RTMP 一侧。如果你需要把 WebRTC 流推到 Nginx RTMP,前面仍然要有一个协议转换层,比如 SRS 或 ZLMediaKit,先把 WebRTC 转成 RTMP 再推到 Nginx RTMP。

5.2 Node Media Server 搭建 RTMP 服务

Node Media Server 是一个基于 Node.js 的开源流媒体服务器,支持 RTMP、HTTP-FLV、HLS,也能通过插件实现 WebRTC 播放。它的特点是安装简单,适合快速验证。

创建测试目录:

mkdir -p ~/nms-test
cd ~/nms-test
npm init -y
npm install node-media-server

创建 app.js :

const NodeMediaServer = require('node-media-server');

const config = {
  rtmp: {
    port: 1935,
    chunk_size: 60000,
    gop_cache: true,
    ping: 30,
    ping_timeout: 60
  },
  http: {
    port: 8000,
    mediaroot: './media',
    allow_origin: '*'
  },
  auth: {
    play: false,
    publish: false
  }
};

const nms = new NodeMediaServer(config);
nms.run();

启动:

node app.js

然后同样用 ffmpeg 推流测试,RTMP 测试地址仍然是:

rtmp://127.0.0.1:1935/live/test

Node Media Server 更适合快速搭一个 RTMP 服务来模拟下游接收端,但它的 WebRTC 推流原生支持有限,所以不推荐把它作为 webrtc2rtmp 的转换主力。

5.3 如何选择

如果你需要一条链路同时支持 WebRTC 推流和 RTMP 输出,最推荐 SRS 或 ZLMediaKit。如果你已经有一个 RTMP 接收端,只是想验证推流地址通不通,那么 Nginx RTMP 或 Node Media Server 就够了。

测试环境的搭建目标不是“用最炫的架构”,而是用最小成本把链路验证清楚。因此建议先跑通 SRS 方案,再按需引入 Nginx RTMP 或 Node Media Server。

6. 常见问题与排查思路

6.1 问题排查表

问题现象 常见原因 解决思路
浏览器一直 connecting,推不上流 UDP 8000 端口不通 检查防火墙、安全组,确认 UDP 端口开放
本机可以推流,局域网其他机器不行 CANDIDATE 配置成了 127.0.0.1 改为服务器实际局域网 IP
页面打不开摄像头 使用了非 HTTPS 环境访问 使用 localhost 或配置 HTTPS
画面正常但没有声音 WebRTC 使用 Opus,RTMP 常用 AAC 推流端改用 AAC 或增加音频转码
ffplay 拉流黑屏 RTMP 端口未通或流名不匹配 确认流名与推流时一致,检查 1935 端口
推流结束后播放端有缓存画面 启用了 GOP cache 测试环境可关闭 gop_cache,观察效果

6.2 推流失败排查思路

如果你遇到 WebRTC 推流失败,可以按下面的顺序排查:

  1. 先确认浏览器控制台是否有 ICE 相关报错,如果出现 ice connection failed ,说明浏览器到服务器之间 UDP 不通。
  2. 在服务器上执行命令,确认 SRS 容器是否正常运行,1985 端口是否能返回版本信息。
  3. 检查防火墙是否放行了 UDP 8000 端口:
    sudo ufw status
    sudo iptables -L -n | grep 8000
    
  4. 检查 CANDIDATE 环境变量是否设置为浏览器能够访问到的 IP。本机测试用 127.0.0.1 ,局域网测试用局域网 IP,公网测试用公网 IP。

6.3 声音问题的处理思路

如果你的业务对声音有强需求,建议在一开始就明确音频编码。WebRTC 默认优先使用 Opus 音频编码,而很多 RTMP 服务端和播放器更熟悉 AAC。SRS 在转封装时如果遇到 Opus 音频,可能需要额外的转码链路支持,否则可能出现无声或者播放器不兼容。

在测试环境中,可以先用视频流验证整体链路,确认视频通路正常后,再单独排查音频问题。如果音频始终有问题,可以考虑在推流端配置浏览器优先使用 AAC 音频,或者部署 SRS 的转码能力,把 Opus 转成 AAC。生产环境还需要根据 CDN 的音频编码要求做匹配。

6.4 弱网卡顿怎么优化

WebRTC 自带拥塞控制和弱网对抗机制,包括 FEC 前向纠错、NACK 丢包重传、码率自适应等。在 webrtc2rtmp 测试环境里,如果遇到弱网卡顿,可以从以下几个方面调整:

  • 限制 WebRTC 发送码率上限,避免上行带宽被占满;
  • 调整分辨率与帧率,降低带宽压力;
  • 在浏览器端设置合理的码率控制参数;
  • 如果是 Wi-Fi 环境,尽量使用 5GHz 频段或者有线网络;
  • 用 Linux tc 命令或 Windows Clumsy 工具模拟弱网,验证卡顿在哪个环节发生。

需要明确的是,WebRTC 推流侧的弱网优化只能改善浏览器到媒体服务器这一段,RTMP 下行到播放器的卡顿需要依靠 CDN 和播放器缓冲策略来解决。因此在联调时,要分清卡顿发生在推流段还是拉流段。

7. 最佳实践与工程建议

7.1 端口最小化开放

测试环境虽然可以放开所有端口,但建议仍然遵循最小开放原则。只开放必要的 TCP 1935、1985、8080 和 UDP 8000,其他端口一律不开放。特别是不要让 SSH、数据库等端口暴露到无约束网络,避免安全隐患。

7.2 配置统一且可回滚

把 SRS 的启动参数、配置文件、Docker Compose 文件统一纳入代码仓库,标注清楚测试环境地址和端口。当配置变更后,保留历史版本,方便快速回滚。避免在服务器上手工改文件导致环境不可复现。

7.3 HTTPS 尽早纳入测试范围

浏览器 WebRTC 权限对 HTTPS 有硬性要求。如果你的测试环境最终要面向局域网或公网用户,建议尽早把 HTTPS 纳入测试范围。可以使用自签名证书或者内网 CA,只要能模拟正式环境的安全策略即可。否则到了联调阶段才发现权限问题,会浪费不少时间。

7.4 日志与监控

启动 SRS 容器时,尽量把日志输出到控制台或者按天分割的日志文件。出现推流失败时,日志能帮助你快速定位 ICE 协商、RTMP 发布等环节的问题。如果团队成员较多,还可以为测试环境加一个简单的统一日志查看入口。

7.5 明确转封装与转码的成本边界

很多刚接触流媒体的人会把 webrtc2rtmp 理解成“转码”,实际上视频轨道大概率不需要转码,只需要转封装。转封装是轻量操作,CPU 消耗低。但如果真的遇到编码格式不匹配,比如 H.265 视频或者 Opus 音频需要转成 H.264/AAC,那就变成了转码,CPU 和延迟都会明显上升。在测试环境里提前确认编码格式,能帮助你在生产方案选型时避开不必要的转码开销。

7.6 利用测试环境模拟下游 CDN

测试环境不只是用来验证本地播放器,也可以用来模拟 CDN 链路的多个环节。例如先让 SRS 推到 Nginx RTMP,再从 Nginx RTMP 拉流验证,模拟“WebRTC 推流 -> 中间转换 -> 边缘节点 -> 播放器”的完整链路。这样做可以在上线前发现很多架构层面潜在问题。

8. 总结与下一步学习建议

到这里,你的本机 or 局域网测试机上已经有了一个可运行的 webrtc2rtmp 测试链路:浏览器通过 WebRTC 推流到 SRS,SRS 转封装为 RTMP 后由播放器拉流验证。核心步骤概括下来就是:规划端口、启动 SRS、配置正确的 CANDIDATE、浏览器推流、播放器验证 RTMP。

后续想深入的话,可以沿着几个方向继续学习:一是理解 WHIP 这类 WebRTC 推流标准协议,了解它和传统 WebRTC 信令的区别;二是研究 SRS 的转码能力,掌握 Opus 转 AAC、H.265 转 H.264 等场景下的配置方法;三是尝试把测试链路的 SRS 输出接入真实 CDN 或云直播平台,并在生产环境里验证鉴权、断流重推、延迟监控等细节。

建议你先把本文的流程在自己的测试机上完整跑一遍,再换真实 IP 和 HTTPS 环境验证一次。只有亲手解决了 ICE 协商、UDP 端口、音频编码这几个典型问题,后续做正式直播项目时才会更从容。

Logo

火山引擎视频云技术社区,是面向 AI 音视频开发者的技术交流平台。这里汇聚源自抖音、豆包等亿级 DAU 产品的 RTC、直播、点播、AI 媒体处理、音视频互动技术,提供接入指南、最佳实践、性能调优、场景案例、Demo 代码、开源项目、白皮书和 API 文档。社区汇聚官方工程师与一线开发者,为 AI 视频通话、数字人、AI 视频处理等应用的开发与落地提供技术支持。

更多推荐