RTMP转WebRTC测试环境搭建与排错指南 RTMP 和 WebRTC 之间的测试环境很多人第一次搭的时候并不是卡在概念上而是卡在“推流地址、播放地址、端口、协议转换”这四件事的对应关系上。RTMP 推流端OBS把流推到服务器浏览器端却没法直接用 RTMP 播放WebRTC 播放器需要的是另一种接入方式。测试环境的本质就是把这条链路拆成“推流-服务-播放”三段逐段验证。这篇文章就用一套本地可复现的流程把 RTMP 转 WebRTC 的测试环境从安装到排错完整过一遍适合刚接触流媒体、需要搭一套本地验证环境的人也适合已有环境但经常遇到推不上流、播不出画面、弱网卡顿的开发。1. 先搞清楚 RTMP 和 WebRTC 在测试环境里各扮演什么角色1.1 为什么浏览器不能直接播放 RTMP 地址RTMP 是一种基于 TCP 的流媒体传输协议以前主要用于 Flash 播放器的推拉流。现在 OBS、摄像头、编码器、推流软件仍然大量采用 RTMP 向服务器推流。可问题是浏览器原生 HTML5 播放器不支持 RTMP 协议也没有类似rtmp://地址的解码通道。拿到一个rtmp://开头的地址时不能直接塞给video标签播放必须经过服务器转换封装或转换协议变成 WebRTC、HLS、HTTP-FLV 这类浏览器能处理的形式。这里要区分两个层面RTMP 解决的是“推流端到服务器”和“部分播放器到服务器”的传输问题WebRTC 是浏览器内部的实时通信能力集合包含采集、编码、传输、播放多以 UDP 传输为主。RTMP 走 TCPWebRTC 走 UDP两者不会天然互通。测试环境要解决的核心问题就是让同一路视频流能在两种协议之间完成转换和播放。还有一个容易踩的坑很多人以为把 RTMP 地址改个前缀就可以在浏览器里播放。不是这样。协议转换需要在服务端完成不能靠前端猜。1.2 一套最小测试环境由哪些组件组成一个 RTMP 转 WebRTC 的测试环境至少需要四块推流端OBS、ffmpeg、硬件编码器向 RTMP 地址推流。流媒体服务器接收 RTMP 流并完成到 WebRTC 的协议转换。信令服务让浏览器和服务器协商 SDP、ICE candidate完成 WebRTC 连接建立。播放端Chrome、Edge 等浏览器或自己写的 WebRTC 客户端。如果只测试 RTMP 推拉流nginx-rtmp 就够了。但如果要验证 RTMP 转 WebRTC就要引入支持 WebRTC 的流媒体服务。不要试图在浏览器里直接用 JS 解析 RTMP 流这条路兼容性差维护成本高而且实现难度远超普通业务需求。从测试角度看组件越少越好。SRS、ZLMediaKit 这类服务已经同时内置 RTMP 接入和 WebRTC 播放能力信令也自带测试环境一条命令就能启动。1.3 两条常见链路与选择建议链路 AOBS - nginx-rtmp 接收 RTMP - ffmpeg 转封装 - WebRTC 服务/播放器。链路 BOBS - SRS/ZLMediaKit 同时接收 RTMP、内部转换 WebRTC - 浏览器播放。链路 A 把每一步拆得很开适合学习协议细节但中间要自己处理转封装、转协议、信令步骤多排查点分散。链路 B 的转换在服务端内部完成推流地址和播放地址各只有一个最省事。我建议第一次接触这个主题的人直接用链路 B先把端到端跑通再回头理解内部细节。后文统一用 SRS 作为主服务来演示nginx-rtmp 放在前面做 RTMP 链路的单独验证。2. 搭建前先确认硬件、系统和端口条件2.1 本地测试环境的最低配置RTMP 转 WebRTC 的本地测试对硬件要求并没有想象中高。单路流、三五路并发的情况下2 核 CPU、4GB 内存的 Linux 虚拟机就能运行。长时间跑压测或者还要做录制、转码就建议 4 核 8GB 起步。磁盘方面系统、镜像、日志和录制文件都会占空间预留 10GB 以上比较稳妥。网络条件要看测试范围如果只是本机或局域网测试普通千兆内网完全足够如果要在云服务器上做外网播放测试就要重点关注带宽、UDP 端口和云安全组配置。我一般会把测试环境分成两种一种是 Docker 方式运行的 Linux 环境适合快速验证另一种是编译安装方式适合需要定制模块的环境。第一次做功能验证不建议一上来就下载 WebRTC 源码编译过程重、耗时长而且对测试结论没有直接帮助。WebRTC 源码下载和编译是深度开发阶段的事不是测试环境搭建的第一步。2.2 端口规划、防火墙与系统差异以 SRS 为例它默认会占用这些端口端口协议用途1935TCPRTMP 推流和拉流1985TCPHTTP API、信令8080TCPWeb 播放器、静态页面8000UDPWebRTC 媒体传输测试前先确认这些端口没有被占用依次检查本机防火墙、云服务器安全组、Docker 端口映射。很多人 RTMP 推流正常HTTP 页面也正常但 WebRTC 播放一直连接不上最后发现是 UDP 8000 被安全组拦截了。TCP 放行不代表 UDP 放行这点要单独确认。注意WebRTC 媒体传输走 UDP看到 HTTP 页面能打开并不等于 WebRTC 能通。排查时一定要确认 UDP 端口、服务器内外网 IP、防火墙策略三条链路。如果测试机器用的是麒麟这类国产 Linux 发行版还需要多看一层系统默认是否启用了额外的防火墙策略Docker 版本的安装方式、内核网络模块是否和 Ubuntu/CentOS 一致。很多时候服务起不来或端口不通不是 SRS 配置问题而是系统安全策略默认拦截了 UDP 大包或限制了端口映射。遇到这种情况先把 firewalld/ufw/安全组策略列出来再改服务配置。2.3 提前准备推流端和播放端工具推流端我一般准备两个OBS Studio界面化适合手工测。ffmpeg命令行适合脚本化、批量测试。播放端一般用 Chrome 或 Edge直接访问 SRS 自带的 WebRTC 播放器页面。ffplay 则用来验证 RTMP 原始拉流是否正常。浏览器里还要知道 chrome://webrtc-internals 这个调试页面它可以查看 WebRTC 连接状态、RTT、丢包率、音视频轨道信息对排查弱网卡顿非常关键。网络层工具可以准备 nc 或 telnet验证 TCP 端口连通nc -u 可以粗略验证 UDP 端口是否可以到达对方主机。不过 UDP 端口验证需要服务端配合光靠 nc 不一定能得出最终结论。3. 用 nginx-rtmp 先打通最基础的 RTMP 推拉流链路3.1 快速启动 nginx-rtmpDocker 优先在进入 WebRTC 之前我建议先用 nginx-rtmp 把 RTMP 推拉流这个基本盘打通。这样后面一旦出问题能快速判断是 RTMP 环节的问题还是 WebRTC 转换的问题。安装方式上Docker 优先docker run -d --name nginx-rtmp \ -p 1935:1935 \ -p 8080:8080 \ -v /path/to/nginx.conf:/etc/nginx/nginx.conf:ro \ your-nginx-rtmp-image如果需要自己编译 nginx-rtmp-module流程一般是安装 nginx 编译依赖下载 nginx 源码和 nginx-rtmp-module 源码用--add-module参数重新编译。这种方式适合需要定制 nginx 模块、或者公司有统一基础镜像要求的场景。第一次测试没必要在编译上花时间。nginx.conf 中 RTMP 最核心的配置如下rtmp { server { listen 1935; chunk_size 4096; application live { live on; record off; } } } http { server { listen 8080; location /stat { rtmp_stat all; rtmp_stat_stylesheet stat.xsl; } } }这个配置启动后nginx 会监听 1935 端口接受推往rtmp://服务器IP/live/任意流名的流。record off表示默认不录制避免测试时磁盘被写满。3.2 配置推流地址在 OBS 里正确填写流名OBS 里的设置看起来简单实际最容易错服务选择“自定义”。服务器填rtmp://127.0.0.1:1935/live。推流码填test。这里的“推流码”就是流名最终会拼成rtmp://127.0.0.1:1935/live/test。很多人会把推流码写成带斜杠的路径或者写成.flv后缀结果推流地址和服务端不匹配。点击开始推流后打开http://127.0.0.1:8080/stat正常情况下能看到test这条流已经出现在列表里同时有对应的连接数和码率信息。这就是成功判断标准。3.3 用 ffplay 和 OpenCV 验证拉流解决打开 RTMP 失败的问题RTMP 推流成功后用 ffplay 验证拉流ffplay -fflags nobuffer -flags low_delay \ -i rtmp://127.0.0.1:1935/live/testOpenCV 里读取 RTMP 流也是常见需求。很多报错是“OpenCV 打开 RTMP 失败”但这个问题要拆开看不能直接怪 OpenCV。OpenCV 的 VideoCapture 读取 RTMP本质是通过 FFmpeg 输入模块实现的。以下几种情况最容易出错OpenCV 安装时没有编译 FFmpeg 支持cv2.VideoCapture.open返回 false。这个要确认安装的 opencv-python 是否自带 FFmpeg。RTMP 服务还没推流流不存在VideoCapture 会长时间卡在打开阶段表现像死锁。输入流编码格式兼容性问题。OpenCV/FFmpeg 读 H.265 不如 H.264 稳定测试阶段建议优先 H.264 视频 AAC 音频。地址写错。OpenCV 里 RTMP 地址不需要额外拼接参数直接传rtmp://IP/live/test字符串即可。所以我一般会先用 ffplay 手动确认流是好的再用 OpenCV 去读。如果 ffplay 能出画面OpenCV 读不到问题大概率在 OpenCV 本身如果 ffplay 也读不到说明问题在推流环节或服务端口。4. 加一层 SRS让 RTMP 流可以 WebRTC 播放4.1 用 SRS 同时接管 RTMP 和 WebRTCRTMP 链路正常后进入主菜把 RTMP 输入的流转成 WebRTC 播放。SRS 是最适合这类测试的开源流媒体服务器之一它同时支持 RTMP 接入和 WebRTC 播放。ZLMediaKit 也能实现但 SRS 的演示页面和默认配置更简洁。SRS 6.x 用 Docker 启动docker run --rm -p 1935:1935 -p 1985:1985 -p 8080:8080 \ -p 8000:8000/udp \ ossrs/srs:6启动后 RTMP 推流地址仍然是rtmp://服务器IP:1935/live/test和 nginx-rtmp 的推流方式几乎一样。差别在于SRS 同时具备 WebRTC 播放和推流能力。我建议先保持推流端不变OBS 推流到 SRS继续在浏览器测试。打开http://服务器IP:8080/players/rtc_player.html在播放地址里填webrtc://服务器IP/live/test点击播放。注意这里填的是webrtc://开头不是rtmp://也不是ws://。SRS 内部会完成 RTMP 到 WebRTC 的协议转换播放地址使用webrtc://这个标识。如果一切正常浏览器会播放出 OBS 推送的画面。4.2 浏览器播放器的接入和判断标准浏览器播放成功不代表可以结束测试。还要看几个指标播放是否流畅画面有没有卡顿、花屏、马赛克。音画是否同步音频和视频时间戳是否对齐。延迟情况说话和画面播放之间是否有明显延迟。WebRTC 连接状态在 chrome://webrtc-internals 里查看 RTCPeerConnection 的状态。RTT 和丢包率RTT 低于几十毫秒属于正常局域网水平丢包率越高卡顿风险越大。测试时我一般会在播放器页面播放 3 到 5 分钟拖动画面或者切换场景观察是否有异常。只播放几秒钟就关掉很难发现真问题。SRS 的 API 也可以用来验证流是否存在curl http://服务器IP:1985/api/v1/streams/返回的 JSON 里会列出当前活跃流字段包含 stream 名称、状态、源地址等信息。如果这里能看到 SRS 的源但浏览器无法播放 WebRTC问题就在 WebRTC 连接或网络层而不是推流端。4.3 RTMP 转 WebRTC 背后的信令与 ICE 边界这里不要求测试时实现自己的信令但至少要明白发生了什么。浏览器要播放 WebRTC 流需要和 SRS 完成 SDP 协商、交换 ICE candidate、建立 DTLS-SRTP 加密通道。SRS 的 demo 播放器已经把这些步骤封装好了所以你不需要自己写信令。但如果要集成到自己的前端项目里就要关注三个东西SDP包含音视频编码能力、传输参数。ICE candidate包含可供连接尝试的 IP 和端口列表。DTLS-SRTPWebRTC 的传输加密浏览器和服务器自动完成。排查连接问题时优先看 chrome://webrtc-internals 里的iceConnectionState。如果一直停留在checking说明 ICE candidate 没有找到可用通道。常见原因有两个UDP 8000 端口被防火墙拦截服务器有多网卡SRS 返回了浏览器无法访问的 IP。SRS 默认会自动探测本机网卡 IP但如果容器网络或云服务器多网卡环境复杂可能探测到错的 IP。这种情况需要在 SRS 配置文件里明确设置rtc_server_ip手动指定服务器对外可访问的内网或公网 IP。测试时如果遇到浏览器无法连接第一步就查 SRS 日志和返回给浏览器的 candidate IP 是不是客户端能访问到的地址。4.4 WebRTC 推流也一起测从页面到流名分配除了 RTMP 推流、WebRTC 拉流另一个常见测试是 WebRTC 推流。场景是网页端直接用摄像头推流给 SRS其他人通过 RTMP 或 WebRTC 拉流观看。SRS demo 页面有 WebRTC 推流演示。浏览器推流时SRS 会分配一个 whisper 形式的流地址通常形如webrtc://服务器IP/live/test?secretxxx或带有动态参数。不同版本细节有差异但流程类似在页面里点击推流授权摄像头和麦克风SRS 收到流后把它当作普通直播流其他播放端可以通过对应的 RTMP 或 WebRTC 地址观看。验证 WebRTC 推流是否成功可以直接请求 SRS 的流列表 API看是否多了一条由 WebRTC Source 产生的流。如果流列表里能看到说明推流成功如果看不到优先检查浏览器权限、SRS 信令地址和 UDP 端口。另外STUN/TURN 的边界要分清楚。同一个局域网内一般不需要 TURN只要 UDP 端口通就行。跨公网、对称 NAT 等复杂环境才需要 TURN 中继。不要一开始就引入 TURN测试环境越简单越好先内网直连验证功能再考虑跨网段。5. 从单路跑通到多路并发、弱网卡顿的测试重点5.1 多路并发测试先看资源再下结论测试环境跑通后很多人会马上开多路并发。但我建议按这个节奏来单路先稳定跑 10 分钟再加入第二路、第三路最后再挑战更多路。并发测试时最怕只看“画面还能出来”就下结论。真正要记录的是CPU 使用率SRS 进程占了多少 CPU是否持续上涨。内存使用量进程 RSS 是否稳定。UDP 端口占用8000 端口对应多少活跃流。RTT 和丢包在 webrtc-internals 里看每个连接单独看。流之间是否互相干扰多路流的音画时间戳、码率、起始时间是否一致。失败率有多少路连接失败、中途断开。低配机器能跑通单路不代表能跑批量。默认参数适合入门但不一定适合并发测试。真正的压力测试要设置客户端连接数上限、码率上限、超时时间还要规划流名命名规则。多路流如果都叫同一个名字后推的流会把先推的流覆盖掉这是非常容易踩的坑。5.2 WebRTC 弱网卡顿的排查与优化顺序“WebRTC 弱网卡顿怎么优化”是测试环境里经常遇到的需求。先给结论卡顿主要来自网络丢包、带宽不足、拥塞控制策略、编码码率设置这几个方向。WebRTC 内部有拥塞控制算法但不同服务端实现的细节差异很大浏览器端的 buffer 策略也会影响恢复速度。我建议按这个顺序排查先确认是不是真的弱网导致的卡顿。同一局域网内播放如果也卡说明不是弱网问题要优先检查服务端 CPU、编码参数和推流端码率。压低码率。视频码率、分辨率、帧率都压到目标场景的上限。不要让 SRS 或浏览器自己无限拉高否则网络波动时很难恢复。在服务器端配置码率上下限。SRS 对 WebRTC 客户端可以设置视频码率限制合理的范围比完全放开更稳定。用丢包工具模拟弱网。可以用 tc/netem 或带损耗的 Wi-Fi把丢包率设置为 1%、2%、5%观察画面卡顿和恢复速度。检查 FEC 和重传相关配置。不同服务端对 RTX、FEC 的支持不同但这部分属于优化细节不在环境搭建阶段必须处理。WebRTC 的弱网表现受编码器影响也很大。VP8、VP9、H.264、AV1 在不同浏览器和服务端的适配程度不同。测试阶段先用浏览器默认支持的编码器和 SRS 默认配置跑通再逐步调整编码参数不要一开始就堆优化项。另外WebRTC 源码下载和编译不需要放在这个阶段。浏览器自带的 WebRTC 实现已经足够验证协议和功能只有做深度定制或二次开发时才需要源码。5.3 录制、转码、合流不是协议转换的一部分测试过程中如果发现延迟大、画质差不要先想着加录制、转码、合流这些额外功能会占用 CPU、磁盘和带宽反而干扰问题定位。正确顺序是先把传输链路的质量稳住再按需添加扩展能力。录制nginx-rtmp、SRS 都可以录制 FLV 或 MP4。批量测试时单独规划磁盘录制会影响单路性能和磁盘 I/O。转码实时转码非常吃 CPU。H.264 转 H.264、分辨率缩放、码率控制都属于中等以上开销。低端机器不要在测试阶段开实时转码。合流把多路视频合到一路属于重型处理。它和协议转换是不同的能力不要混淆。每次增加一个扩展能力后都要重新跑一遍单路、多路、弱网测试对比 CPU、内存、延迟和丢包指标而不是只看功能是否出现。6. 常见报错、调试顺序和最终验收清单6.1 按现象快速定位推流、拉流、播放、卡顿分开查实际测试时报错表象多种多样。我一般会先按现象分类再沿固定顺序排查。现象优先排查次优先排查常见原因OBS 推流失败或一直重连1935 端口是否监听RTMP 服务是否启动推流服务器地址、流名是否正确服务未启动、防火墙挡 TCP 1935、流名覆盖ffplay/OpenCV 拉流失败推流是否正在进行URL 格式是否正确OpenCV/FFmpeg 是否支持 RTMP流不存在、OpenCV 缺少 FFmpeg、H.265 编码推流成功但 WebRTC 播放黑屏播放地址是否填成了 rtmp://浏览器控制台、webrtc-internals流名不一致、HTTP API 端口跨域、播放 URL 协议错误WebRTC 一直 checking 或连接失败UDP 8000 是否通了服务器多网卡、candidate IP 是否可达安全组挡 UDP、防火墙挡 UDP、rtc_server_ip 未设置播放卡顿、画面花屏网络丢包和带宽服务端 CPU、内存占用码率过高、网络不稳、并发过高没有限制延迟突然变大是否开启了录制或转码服务端拥塞控制参数服务器负载过高、录制/转码抢占资源排查链路固定是先看现象在哪一步再对照日志、浏览器控制台、webrtc-internals、API 返回最后才改参数。不要一上来就调 SRS 的码率或并发。6.2 容易踩坑的细节有几个细节我每次测试都会特别注意本机测试用 127.0.0.1跨容器或跨机器测试时播放地址和 candidate IP 都可能是内网地址。Docker bridge 网络下 SRS 可能拿到 docker0 网卡 IP导致浏览器无法访问。稳妥做法是设置rtc_server_ip为宿主机内网 IP或用--network host启动容器。云服务器只开 TCP 端口是不够的。WebRTC 媒体传输是 UDP安全组和防火墙都要放行 UDP 8000。浏览器自动播放策略可能导致有画面无声音。这属于浏览器行为不是服务器问题。需要在页面交互后触发播放或检查 autoplay 策略。测试地址容易被别人占用。如果多人共用一台测试服务器建议使用带日期或随机数的流名比如rtmp2webrtc_test_20250120。SRS 日志很重要。一次推流、一次播放都会在日志里留下记录包含协议、流名、连接 IP、结果状态。日志里出现 UDP bind 失败时优先查端口占用和权限。6.3 最小验收清单与后续建议完成一套可验收的 RTMP 转 WebRTC 测试环境我建议按这个清单过一遍服务启动后1935、1985、8080、8000 端口正常监听。OBS 成功推流到rtmp://服务器IP:1935/live/test。ffplay 能从同一地址拉流出画面。OpenCV 能通过 VideoCapture 读取 RTMP 流。SRS demo 播放器用webrtc://服务器IP/live/test播放成功iceConnectionState 为 connected。同时播放 3 到 5 路流CPU、内存、RTT、丢包在可控范围。模拟 1% 到 3% 丢包后画面可以恢复不会持续花屏。如果这些都能通过说明这套环境不仅能演示还能支撑后续的接口开发、并发压测、弱网验证和播放器调试。如果做集成开发下一步再考虑把 SRS 的推流、拉流接口封装成内部 API加上监控和日志收集。我个人更建议先把单路跑稳再考虑批量和弱网。这个测试环境真正落地时最该盯住的不是功能列表而是输入格式、UDP 端口、多网卡地址和失败重试。踩过几次之后会发现很多问题不是工具能力不够而是前置环境没有清理干净。