交叉编译ZLMediaKit到RK3588与配置公网 WebRTC 播放

发布时间:2026/9/4 18:04:19
交叉编译ZLMediaKit到RK3588与配置公网 WebRTC 播放 一、引言这是一篇关于 RK3588、GStreamer、ZLMediaKit 与公网 WebRTC 配置的实践文章先解释为什么 媒体服务器要部署在板端再给出从 ARM64 运行包、WebRTC candidate 到公网端口映射的可验证落地方法。先看安全边界本文验证方案使用 HTTP、公网 IPv4 和路由器端口映射。 生产环境应使用 HTTPS、域名、Token 鉴权限制管理端口。已验证结论播放器将 H.264/Opus WebRTC 流发布到同机 ZLMediaKitZLM 再向公网浏览器分发。 板内发布 ICE candidate 固定为127.0.0.1浏览器获得的 candidate 仍为公网 IP可避免板内 RTP 绕行路由器 NAT 造成音频丢包和抖动。二、背景为什么RK3588需要部署ZLMediaKit在我们开发的一个软件系统中GStreamer 负责把素材或采集输入变成可播放的音视频管线rk3588_gst_player是运行在板端的我们开发的播放器进程负责驱动这些管线并发布 WebRTC 流RK3588 硬件负责高效完成视频采集/播放、H.264 编码和 Opus 音频。RK3588 很适合承担这些工作但让浏览器直接连接播放器 会把多客户端访问、公网 NAT、WebRTC 信令和 ICE candidate 管理全部压到嵌入式进程上。连接一多资源 生命周期和公网可达性就很难统一处理。ZLMediaKit 的角色不是播放器而是板端的 WebRTC 媒体服务器它接收播放器发布的流统一维护媒体源 再为每个浏览器建立播放连接。这样播放器负责“产生媒体”ZLM 负责“分发媒体和管理连接”素材/采集输入 │ GStreamer 管线H.264 Opus ▼ RK3588 播放器 │ WebRTC publish ▼ ZLMediaKit │ WebRTC play ▼ 公网浏览器三、方案架构与数据流视频素材 │ ├─物理 HDMI 播放 │ └─rk3588_gst_player └─H.264 Opus RTP WebRTC publisher │ 板内信令127.0.0.1:ZLM_HTTP_PORT │ 板内 ICE candidate127.0.0.1 ▼ ZLMediaKit │ 公网 HTTPWebRTC SDP API │ 公网 UDPDTLS/SRTP 音视频 ▼ 路由器 NAT 端口映射 ▼ 公网浏览器路径地址用途播放器→ZLM 信令http://127.0.0.1:HTTP_PORT/index/api/webrtc?...typepush不经过路由器。播放器→ZLM 媒体zlm_publisher_ice_ip127.0.0.1避免公网 NAT hairpin。浏览器→ZLM 信令http://PUBLIC_IP:HTTP_PORT/index/api/webrtc?...typeplay前端向此 API POST offer SDP。浏览器→ZLM 媒体PUBLIC_IP:RTC_PORT/udpZLM 通过rtc.externIP向浏览器公布。四、一个系统中存在两段 WebRTC两段连接彼此独立candidate 不同、网络路径不同、配置目的不同。把 publisher 的公网配置和 browser 的 公网配置混在一起是“板内音频卡顿”和“公网浏览器无画面”中最常见的排查错误。五、candidate 设计原则一为什么 publisher 使用 127.0.0.1播放器和 ZLMediaKit 位于同一块 RK3588板内发布路径应当是rk3588_gst_player ── localhost ── ZLMediaKitzlm_publisher_ice_ip127.0.0.1把这条连接固定在本机。若误用公网 candidate流量可能变成播放器 → 路由器 → 公网 IP → ZLMediaKit这会引入 NAT hairpin、额外延迟和丢包风险板内发布使用127.0.0.1公网播放则使用rtc.externIP公布的公网地址二者不能混用。二rtc.externIP 到底给谁用rtc.externIP不是给播放器使用的它告诉 ZLMediaKit返回给外部浏览器的 ICE candidate 应该 使用哪个地址。配置项本身只填写PUBLIC_IPcandidate 最终会与rtc.port组合成PUBLIC_IP:RTC_PORT。若写成127.0.0.1公网浏览器会收到不可达地址公网端口还必须与路由器映射保持一致。六、前置条件一开发机Ubuntu 开发机项目路径为/home/cuijc/xiangmu/RK3588-GStreamer-Player。能通过 SSH 访问目标板并已安装sshpass、ssh、scp和tar。使用仓库的scripts/build.sh交叉编译播放器不在 RK3588 板上原生编译播放器。sudo apt-get update sudo apt-get install sshpass openssh-client tar二板端CPU 架构必须为aarch64。板子可访问公网 IP 检测站点并能向浏览器发送 UDP。目标板最好使用静态 LAN IP 或 DHCP 保留否则路由器映射会失效。Buildroot 中已有 ZLM 依赖的libssl.so.1.1、libcrypto.so.1.1、C/C 运行库。本项目的 ZLM 包额外携带libsrtp2.so.1。uname -m # 期望aarch64 ip addr df -h /root三公网网络路由器 WAN 口必须拥有真实、可入站的公网 IPv4。若 WAN IP 与公网查询结果不同通常是 CGNAT 或上级 NAT仅配置家用路由器映射无法解决。防火墙和运营商不得阻断所选 RTC UDP 端口。四从零部署路线下图中的streamControl是播放器的启流控制消息调用它会启动指定通道的 WebRTC publisher并等待媒体源达到可播放状态。准备 ARM64 ZLMediaKit 运行包 │ ▼ 上传到 RK3588 │ ▼ 配置 config.ini │ ▼ 启动 MediaServer │ ▼ 启动 rk3588_gst_player │ ▼ 发送 streamControl │ ▼ 浏览器 WebRTC 播放这条路线的关键不是命令顺序本身而是每一步都为下一层提供前提先有可运行的 ARM64 服务再有正确 的 HTTP/RTC 配置最后才验证浏览器播放。七、交叉编译 ZLMediaKit ARM64 安装包WebRTC 依赖 OpenSSL、libsrtp 和 SCTPCMake 找不到依赖时 可能自动关闭 WebRTC编译成功不代表 WebRTC 功能已开启必须检查配置结果和运行时 codec。需要升级或重建 ZLMediaKit 时应以官方文档为准ZLMediaKit 官方仓库ZLM 启用 WebRTC 编译指南已验证编译基线ZLMediaKit commit0e9e59bf4382335bce22b2214877803f3beeeeca版本时间 2026-08-06libsrtp2.5.0GCC10.3.1 Buildroot sysroot 中的 OpenSSL1.1。当前已验证二进制内嵌的版本信息为ZLMediaKit(git hash:0e9e59b/...)不建议在交付环境直接编译不固定的master。一安装开发机构建工具以下命令只在 Ubuntu 开发机执行。ZLM 和 libsrtp 都使用本项目的 RK3588 Buildroot 交叉工具链不在板子上原生编译。sudo apt-get update sudo apt-get install -y \ git curl ca-certificates cmake make \ autoconf automake libtool pkg-config \ file binutils确认项目 SDK 完整cd /home/cuijc/xiangmu/RK3588-GStreamer-Player test -x third_party/rk3588-sdk/host/bin/aarch64-none-linux-gnu-gcc test -f third_party/rk3588-sdk/host/share/buildroot/toolchainfile.cmake test -f third_party/rk3588-sdk/host/aarch64-buildroot-linux-gnu/sysroot/usr/lib/libssl.so.1.1 third_party/rk3588-sdk/host/bin/aarch64-none-linux-gnu-gcc --version # 已验证环境GCC 10.3.1二建立隔离的构建目录下列变量应在同一个 shell 中持续使用。mktemp会创建独立目录不污染项目源码和 SDK sysroot。PROJECT_ROOT/home/cuijc/xiangmu/RK3588-GStreamer-Player SDK_ROOT$PROJECT_ROOT/third_party/rk3588-sdk SDK_HOST$SDK_ROOT/host SYSROOT$SDK_HOST/aarch64-buildroot-linux-gnu/sysroot TOOLCHAIN_FILE$SDK_HOST/share/buildroot/toolchainfile.cmake ZLM_WORK_ROOT$(mktemp -d /tmp/zlm-rk3588-build.XXXXXX) SRTP_SOURCE$ZLM_WORK_ROOT/libsrtp-2.5.0 SRTP_PREFIX$ZLM_WORK_ROOT/stage/libsrtp/usr ZLM_SOURCE$ZLM_WORK_ROOT/ZLMediaKit ZLM_BUILD$ZLM_WORK_ROOT/zlm-build ZLM_STAGE$ZLM_WORK_ROOT/stage/ZLMediaKit printf build workspace: %s\n $ZLM_WORK_ROOT不要把SRTP_PREFIX直接指向 SDK sysroot否则构建过程会修改项目共享的交叉编译环境。三下载并固定 ZLMediaKit 源码git clone --recursive \ https://github.com/ZLMediaKit/ZLMediaKit.git \ $ZLM_SOURCE git -C $ZLM_SOURCE checkout \ 0e9e59bf4382335bce22b2214877803f3beeeeca git -C $ZLM_SOURCE submodule sync --recursive git -C $ZLM_SOURCE submodule update --init --recursive git -C $ZLM_SOURCE rev-parse HEAD # 必须输出 # 0e9e59bf4382335bce22b2214877803f3beeeeca--recursive和后续的submodule update不能省略。ZLM 使用多个子模块只下载主仓库会导致配置或链接失败。四交叉编译 libsrtp 2.5.0WebRTC 必须使用 SRTP。本步通过 libsrtp 的 autotoolsshared_library目标生成 soname 为libsrtp2.so.1的 ARM64 动态库与已验证 MediaServer 一致。curl -fL \ -o $ZLM_WORK_ROOT/libsrtp-2.5.0.tar.gz \ https://github.com/cisco/libsrtp/archive/refs/tags/v2.5.0.tar.gz tar -xzf $ZLM_WORK_ROOT/libsrtp-2.5.0.tar.gz \ -C $ZLM_WORK_ROOT cd $SRTP_SOURCE autoreconf -fi export PKG_CONFIG$SDK_HOST/bin/pkg-config export PKG_CONFIG_SYSROOT_DIR$SYSROOT export PKG_CONFIG_LIBDIR$SYSROOT/usr/lib/pkgconfig:$SYSROOT/usr/share/pkgconfig CC$SDK_HOST/bin/aarch64-none-linux-gnu-gcc \ AR$SDK_HOST/bin/aarch64-none-linux-gnu-ar \ RANLIB$SDK_HOST/bin/aarch64-none-linux-gnu-ranlib \ STRIP$SDK_HOST/bin/aarch64-none-linux-gnu-strip \ ./configure \ --hostaarch64-none-linux-gnu \ --prefix$SRTP_PREFIX \ --enable-openssl \ --with-openssl-dir$SYSROOT/usr make -j$(nproc) make -j$(nproc) shared_library make install检查产物file $SRTP_PREFIX/lib/libsrtp2.so.1 readelf -d $SRTP_PREFIX/lib/libsrtp2.so.1 | \ grep -E SONAME|NEEDED strings $SRTP_PREFIX/lib/libsrtp2.so.1 | grep libsrtp2 2.5.0 # 期望ARM aarch64SONAME 为 libsrtp2.so.1如果此处产物是 x86-64说明CC未生效必须清理本次临时目录并重新构建不要把错误库拷到板子。五配置 ZLMediaKit ARM64 构建这里显式指定 OpenSSL 和 SRTP防止 CMake 误用 Ubuntu 主机的 x86-64 库。CMAKE_SYSTEM_NAMELinux同时使 ZLM 使用 Linux 的链接分组逻辑产物位于release/linux/Release。cmake -S $ZLM_SOURCE -B $ZLM_BUILD \ -DCMAKE_TOOLCHAIN_FILE$TOOLCHAIN_FILE \ -DCMAKE_SYSTEM_NAMELinux \ -DCMAKE_BUILD_TYPERelease \ -DCMAKE_BUILD_RPATH$ORIGIN/lib \ -DCMAKE_INSTALL_RPATH$ORIGIN/lib \ -DENABLE_SERVERON \ -DENABLE_APION \ -DENABLE_OPENSSLON \ -DENABLE_WEBRTCON \ -DENABLE_SCTPON \ -DENABLE_TESTSOFF \ -DENABLE_SRTOFF \ -DENABLE_FFMPEGOFF \ -DENABLE_OBJCOPYOFF \ -DOPENSSL_ROOT_DIR$SYSROOT/usr \ -DOPENSSL_INCLUDE_DIR$SYSROOT/usr/include \ -DOPENSSL_SSL_LIBRARY$SYSROOT/usr/lib/libssl.so \ -DOPENSSL_CRYPTO_LIBRARY$SYSROOT/usr/lib/libcrypto.so \ -DSRTP_INCLUDE_DIRS$SRTP_PREFIX/include \ -DSRTP_LIBRARIES$SRTP_PREFIX/lib/libsrtp2.so \ 21 | tee $ZLM_WORK_ROOT/zlm-configure.log配置阶段必须确认 WebRTC 没有被 CMake 自动关闭grep -E \ found library:.*ENABLE_(OPENSSL|WEBRTC) defined \ $ZLM_WORK_ROOT/zlm-configure.log # 至少应出现 # found library: ... ENABLE_OPENSSL defined # found library: ... ENABLE_WEBRTC definedZLM 在找不到 OpenSSL 或 SRTP 时可能只输出 warning然后自动把ENABLE_WEBRTC设为OFF整体编译仍可能成功。因此不能只看cmake --build退出码必须检查上述配置日志。六编译 MediaServercmake --build $ZLM_BUILD \ --target MediaServer \ --parallel $(nproc) ZLM_OUTPUT$ZLM_SOURCE/release/linux/Release test -x $ZLM_OUTPUT/MediaServer test -f $ZLM_OUTPUT/config.ini test -f $ZLM_OUTPUT/default.pem test -f $ZLM_OUTPUT/www/webrtc/index.htmlZLM 的 CMake 脚本会自动把conf/config.ini、default.pem和www/拷到产物目录。如果CMAKE_SYSTEM_NAME被其他工具链覆盖可使用下列命令定位实际输出find $ZLM_SOURCE/release -type f -name MediaServer -print七检查 ARM64、动态依赖和 RUNPATHfile $ZLM_OUTPUT/MediaServer readelf -l $ZLM_OUTPUT/MediaServer | grep interpreter readelf -d $ZLM_OUTPUT/MediaServer | \ grep -E NEEDED|RPATH|RUNPATH strings $ZLM_OUTPUT/MediaServer | \ grep -m1 ^ZLMediaKit(git hash:期望的关键结果ELF 64-bit ... ARM aarch64 interpreter /lib/ld-linux-aarch64.so.1 RUNPATH: [$ORIGIN/lib] NEEDED: libssl.so.1.1 NEEDED: libcrypto.so.1.1 NEEDED: libsrtp2.so.1 ZLMediaKit(git hash:0e9e59b/...)Ubuntu 主机的ldd不能正确加载 ARM64 程序此处使用readelf。完整ldd检查应在 RK3588 板端执行。八组装可部署运行目录mkdir -p $ZLM_STAGE/lib install -m 0755 \ $ZLM_OUTPUT/MediaServer \ $ZLM_STAGE/MediaServer install -m 0600 \ $ZLM_OUTPUT/config.ini \ $ZLM_STAGE/config.ini install -m 0600 \ $ZLM_OUTPUT/default.pem \ $ZLM_STAGE/default.pem cp -a $ZLM_OUTPUT/www $ZLM_STAGE/www # libsrtp2.so.1 不能省略 cp -a \ $SRTP_PREFIX/lib/libsrtp2.so.1 \ $ZLM_STAGE/lib/ # 一键部署脚本会再安装最新 supervisor # 运行包内也可预置一份 install -m 0755 \ $PROJECT_ROOT/scripts/run-zlmediakit.sh \ $ZLM_STAGE/run-zlmediakit.sh首次交付时应打开$ZLM_STAGE/config.ini把[api].secret替换为高强度随机值。不要在文档、日志或部署命令中回显实际 secret。公网端口和rtc.externIP可交由一键部署脚本写入。九生成安装包mkdir -p $PROJECT_ROOT/output tar -czf \ $PROJECT_ROOT/output/zlmediakit-rk3588.tar.gz \ -C $ZLM_WORK_ROOT/stage \ ZLMediaKit tar -tzf \ $PROJECT_ROOT/output/zlmediakit-rk3588.tar.gz | \ grep -E \ MediaServer$|config.ini$|default.pem$|libsrtp2.so.1$|www/webrtc/index.html$ sha256sum \ $PROJECT_ROOT/output/zlmediakit-rk3588.tar.gz每次重新编译后的 SHA-256 都可能不同应将当次 commit、构建时间和 SHA-256 一起记录在发布说明中。十使用新包部署并做板端冒烟测试先使用本文第七章的--dry-run检查包然后通过--zlm-package部署。不要在已运行板上手工覆盖MediaServer。cd $PROJECT_ROOT BOARD_PASSWORD板子密码 \ bash scripts/deploy-rk3588-stack.sh \ --board 192.168.31.163 \ --public-ip PUBLIC_IP \ --http-port 65521 \ --rtc-port 65522 \ --player-port 8050 \ --zlm-package output/zlmediakit-rk3588.tar.gz \ --dry-run去掉--dry-run才会实际上传、备份、安装和重启。部署后在板端检查LD_LIBRARY_PATH/root/ZLMediaKit/lib \ ldd /root/ZLMediaKit/MediaServer /etc/init.d/S96zlmediakit status wget -S -O /dev/null http://127.0.0.1:65521/ ss -lnup | grep 65522 grep -E \ Load codec: (H264|opus)|WebRtcSession.*listening \ /root/ZLMediaKit/log/MediaServer.log | tail -n 20十一编译完成条件重新编译必须满足以下交付条件否则不要替换已验证包产物是 ARM64 ELF兼容板端 glibc 和 OpenSSL 1.1。编译时找到 libsrtp2MediaServer动态依赖的 soname 与包中文件一致。包含生成的config.ini、default.pem、www/和非系统标准动态库。在板端使用LD_LIBRARY_PATH/root/ZLMediaKit/lib ldd MediaServer时不得出现not found。/index/api/webrtc可用日志启动时加载 H264 和 Opus codec。板内 publisher ICE 选路是127.0.0.1公网浏览器 answer candidate 是当前公网 IP。在 4G/5G 网络中完成至少 30 分钟的音视频播放验收。八、ZLMediaKit WebRTC 配置ZLM 配置位于/root/ZLMediaKit/config.ini。以192.168.31.163我们的模块RK3588板子的已验证配置为例[api] # 必须使用高强度随机值不要暴露到公网 secret 请使用板上实际密钥 [http] port 65521 allow_cross_domains 1 allow_ip_range [rtc] externIP PUBLIC_IP port 65522 tcpPort 65522这些配置分别回答不同问题HTTP 端口承载信令CORS 决定浏览器能否读取 answerRTC 端口承载 DTLS/SRTPexternIP决定公网浏览器收到什么 candidate。不要把它们当成一个“WebRTC 端口”处理。需要特别注意CORS 导致的问题看起来像 WebRTC 网络失败但实际上浏览器甚至没有进入 ICE 阶段先确认响应头和跨域策略再继续检查 candidate 与 RTC 媒体端口。配置作用错误后果http.port承载网页、API 和 WebRTC SDP 交换。前端无法访问/index/api/webrtc。allow_cross_domains1允许前端站点跨域请求 WebRTC API。浏览器 CORS 报错。allow_ip_range允许公网客户端访问 HTTP 端口。只有本机或局域网可访问。rtc.externIP放入 ZLM 返回给浏览器的 ICE candidate。信令成功但无画面或 ICE failed。rtc.portWebRTC UDP/DTLS/SRTP 端口。音视频无法通过 UDP 传输。rtc.tcpPortUDP 不通时的 WebRTC TCP 回退端口。受限网络中没有 TCP 备用路径。修改静态端口后重启 ZLM/etc/init.d/S96zlmediakit restart /etc/init.d/S96zlmediakit status ss -lntp | grep 65521 ss -lnup | grep 65522 ss -lntp | grep 65522九、播放器 ZLM 后端配置播放器rk3588_gst_player是我们开发的应用程序启动WebRTC推流后会查询 ZLM 媒体列表只有目标流的 H.264 与 Opus 轨道均为 ready 且已收到帧时才返回code200。zlm_stream_ready_timeout_seconds的范围为 1-30 秒默认 10 秒超时返回code500并清理本次新启动的流资源。因此成功回复的含义是“此时可播放”而不只是“SDP 已协商”。一公网 IP 自动检测启用后播放器启动时立即检测之后按配置周期复查。检测到变化时通过 ZLMsetServerConfigAPI 更新rtc.externIP。当zlm_public_base_url使用裸 IPv4 时同步替换 URL 主机部分。检测失败时保留上一个有效地址不中断 HDMI 和已有流。正常日志[WebRTC-ZLM] Public IP synchronized: PUBLIC_IP, streamBaseUrlhttp://PUBLIC_IP:65521二板内 publisher ICE 与公网 ICE 分离播放器向 ZLM 发布时会把 ZLM push answer 中的 candidate 改写为zlm_publisher_ice_ip。成功日志[WebRTC-1] ZLMediaKit SDP answer: ... internal ICE IP127.0.0.1, rewritten candidates4selected_pair是 ICE 最终选中的本地/远端候选地址对它比“候选列表里出现过什么”更能说明媒体实际走哪条路径。ZLM 的选路日志应类似Initial selected_pair: tcp 127.0.0.1:65522 - 192.168.31.163:临时端口不应再出现 publisher 连接到网关192.168.31.1的选中对。浏览器播放 SDP 仍由 ZLM 直接生成其 candidate 保持公网地址。这是两段 WebRTC 的配置边界publisher 看本机browser 看公网。三无人观看时回收资源播放器使用 ZLMon_stream_none_readerhook 识别无观众状态日志或状态接口中的readerCount表示当前正在读取该媒体源的播放连接数量降为 0 才进入无人观看处理viewer_idle_actionstop彻底停流下次必须重新下发streamControl。viewer_idle_actionsuspend挂起编码资源通道保持逻辑可用新观众触发on_stream_not_found后自动恢复。viewer_idle_timeout_seconds0禁用空闲回收。这两个 hook 只接受 ZLM 从127.0.0.1或::1发起的回调不需要把播放器8050端口映射到公网。十、路由器映射与公网条件一192.168.31.163的板子的映射公网端口内网目标协议用途必需65521192.168.31.163:65521TCPHTTP 页面和 WebRTC SDP API是65522192.168.31.163:65522UDPWebRTC DTLS/SRTP 媒体是65522192.168.31.163:65522TCPWebRTC TCP 回退可选建议二端口映射原则ZLMrtc.port与公网映射端口应保持一致不要只做端口号转换。同一个公网 IP 下部署多块板时每块板必须使用独立的 HTTP 和 RTC 公网端口。不要映射 SSH、播放器8050、DEP 或其他管理端口。验收时使用手机 4G/5G不要只在同一 LAN 通过公网 IP 测试后者依赖路由器 NAT loopback 能力。十一、启动实时流与前端播放一启动服务/etc/init.d/S96zlmediakit start /etc/init.d/S97rk3588-player start /etc/init.d/S96zlmediakit status /etc/init.d/S97rk3588-player status wget -qO- http://127.0.0.1:8050/health二下发streamControlstreamControl是播放器的启流控制接口它启动指定通道的 publisher并在媒体轨道真正就绪后返回播放地址。指令只负责启动指定通道不再使用controlType{ messageId: 8a7b3f2c4d5e6f7a8b9c0d1e2f3a4b5c, messageType: streamControl, payload: {\channelIndex\:1}, datetime: 2026-08-19 10:00:00, reply: true, client: clientId, messageModel: HTTP, address: http://192.168.31.163:8050/message/receipt, deviceId: 1001 }backendzlmediakit时响应的streamUrl应为http://PUBLIC_IP:65521/index/api/webrtc?applivestreamrk3588-channel-1typeplay通道 2 的流名为rk3588-channel-2。三前端如何使用streamUrl/index/api/webrtc?...typeplay是 WebRTC SDP API不是可直接当作video src的媒体文件也不是完整播放页。前端需要创建RTCPeerConnection加入recvonly音频和视频 transceiver。创建 offer等待 ICE gathering 完成。向streamUrlPOST JSON其中包含 offer SDP。取出 ZLM 返回的 answer SDP调用setRemoteDescription。在ontrack中把MediaStream设置到video.srcObject。ZLM 包中的测试页位于http://192.168.31.163:65521/webrtc/index.html该页适合验证 ZLM 本身业务前端应按相同协商流程集成到自己的页面。十二、分层验收WebRTC 不能只测试 HTTPHTTP 成功 ≠ SDP 成功 ≠ ICE 成功 ≠ DTLS 成功 ≠ 视频播放成功。每一层都要有自己的证据不能用 HTTP 200 代替后面的媒体验证。一进程和端口ps -ef | grep [M]ediaServer ps -ef | grep [r]k3588_gst_player ss -lntp | grep 65521 ss -lnup | grep 65522 wget -qO- http://127.0.0.1:8050/health二ZLM HTTP 与公网入口# 板端本机 wget -S -O /dev/null http://127.0.0.1:65521/ # 开发机或外网主机 curl -sS -o /dev/null -w HTTP %{http_code}\n \ http://PUBLIC_IP:65521/返回 HTTP 200 只说明 TCP 信令可达不代表 RTC UDP 媒体已可达。三确认 ZLM 加载 WebRTC 和 Opusgrep -E Load codec: (H264|opus)|WebRtcSession.*listening \ /root/ZLMediaKit/log/MediaServer.log | tail -n 20四确认板内发布不绕行 NATgrep internal ICE IP /root/Test/gst-test/player.log | tail -n 1 grep setSelectedPair /root/ZLMediaKit/log/MediaServer.log | tail -n 5期望结果internal ICE IP127.0.0.1, rewritten candidates4 selected_pair: ... 127.0.0.1:RTC_PORT - 192.168.31.x:临时端口五确认公网 candidate在浏览器 WebRTC internals 或 ZLM 返回的 answer SDP 中candidate 应包含公网 IP 和 RTC 端口不应是127.0.0.1。同时检查awk BEGIN{p0} /^\[rtc\]/{p1} /^\[/ !/^\[rtc\]/{if(p)exit} p{print} \ /root/ZLMediaKit/config.ini | grep -E externIP|port|tcpPort六音视频稳定性连续播放至少 30 分钟重点检查播放器日志的Audio RTP continuity中missingPackets0、maxPtsStepMs20。ZLM 不持续出现RtpReceiver packet dropped抖动缓冲不增长到数秒。浏览器 FPS 稳定丢帧不持续增长jitter 没有长时间高位。分别在 LAN 和 4G/5G 验证避免把 NAT loopback 问题误判为 ZLM 问题。十三、日常更新、启停和日志一ZLM 已安装后的播放器日常更新不传--zlm-package时脚本保留板上的 ZLM 主程序和配置只校验安装并更新 supervisorBOARD_PASSWORD板子密码 bash scripts/deploy-rk3588-stack.sh \ --board 192.168.31.163 \ --public-ip PUBLIC_IP \ --http-port 65521 \ --rtc-port 65522 \ --player-port 8050二服务命令# ZLMediaKit /etc/init.d/S96zlmediakit start /etc/init.d/S96zlmediakit stop /etc/init.d/S96zlmediakit restart /etc/init.d/S96zlmediakit status # rk3588_gst_player /etc/init.d/S97rk3588-player start /etc/init.d/S97rk3588-player stop /etc/init.d/S97rk3588-player restart /etc/init.d/S97rk3588-player status播放器重启后实时流启用状态不保留需要重新下发streamControl。三日志位置组件日志或状态文件ZLMediaKit/root/ZLMediaKit/log/MediaServer.logZLM 最近退出码/root/ZLMediaKit/log/last-exit-code播放器普通日志/root/Test/gst-test/player.log播放器 supervisor/root/Test/gst-test/player-supervisor.log播放器最近退出/root/Test/gst-test/last-exit播放器 core dump/root/Test/gst-test/crash/tail -f /root/ZLMediaKit/log/MediaServer.log tail -f /root/Test/gst-test/player.log四备份每次一键部署会创建/root/deployment-backups/YYYYMMDD-HHMMSS/更新 ZLM 包时旧的config.ini和default.pem会保留到新目录旧日志也会保留。回退会中断播放执行前应先确认恢复整个组件还是只恢复配置。十四、常见故障排查一公网 WebRTC 最容易踩的坑现象原因与处理libsrtp2.so.1: cannot open shared object file安装包缺少 ARM64libsrtp2.so.1或未通过 supervisor 设置LD_LIBRARY_PATH。确认/root/ZLMediaKit/lib/libsrtp2.so.1存在用/etc/init.d/S96zlmediakit start启动。ZLM 报Please login first播放器未取到正确的[api].secret。检查zlm_config_path、ZLM[api]段和配置文件格式。zlm_api_secret也可显式配置但不要写入公开日志。局域网能播公网连不上检查是否 CGNAT、TCP HTTP 映射、UDP RTC 映射、防火墙和rtc.externIP。使用 4G/5G 测试。HTTP API 成功但无画面或 ICE failedHTTP 只是信令。重点检查 RTC UDP 映射、candidate 的公网 IP/端口、双向 UDP 和公网入站条件。板内发布后音频严重卡顿检查 ZLMsetSelectedPair。如果 publisher 对端是网关192.168.31.1说明发布流绕行 NAT。确认zlm_publisher_ice_ip127.0.0.1并使用支持 candidate 改写的新版播放器。启流前几秒有packet dropped可能是初始 GOP/轨道就绪的短暂缓存对齐。应从All track ready之后开始独立采样 30–60 秒若仍持续增长再查 RTP 连续性和 ICE 路径。公网 IP 变化后无法播放检查zlm_public_ip_auto_detecttrue、检测 URL 可访问、API secret 正确以及日志是否出现Public IP synchronized。路由器映射仍必须存在。HTTPS 前端请求 HTTP 流地址被拦截这是浏览器 Mixed Content 限制。将 ZLM 接入域名 HTTPS或使用同源 HTTPS 反向代理不能靠前端代码绕过。MediaServer 反复重启查看/root/ZLMediaKit/log/MediaServer.log和last-exit-code然后用ldd检查库、用df -h检查空间并检查config.ini是否有超长行、缺少]或。二快速采集排障信息date uname -a ip addr ip route ps -ef | grep -E [M]ediaServer|[r]k3588_gst_player ss -lntup | grep -E 65521|65522|8050 LD_LIBRARY_PATH/root/ZLMediaKit/lib ldd /root/ZLMediaKit/MediaServer tail -n 300 /root/ZLMediaKit/log/MediaServer.log tail -n 300 /root/Test/gst-test/player.log十五、安全与生产化建议纯 HTTP 方案已可用但不加密。生产环境建议升级为域名 HTTPS并使用与证书匹配的zlm_public_base_url。不要在页面、指令响应或普通日志中暴露 ZLM[api].secret。对公网流增加业务鉴权、时效 token 或反向代理鉴权一个可访问的streamUrl本身不等于访问控制。修改板子默认 SSH 密码使用 SSH key 和管理网段限制。公网只放行 ZLM HTTP/HTTPS 和 RTC 所需端口不放行播放器控制端口8050。定期检查 ZLM 日志大小和磁盘使用率并为配置、证书和 API secret 建立受控备份。十六、部署检查清单ZLM 包是 ARM64包含MediaServer、config.ini、www/和libsrtp2.so.1。ldd MediaServer没有not found。S96zlmediakit和S97rk3588-player均在运行。ZLM HTTP 和 RTC UDP 端口均已监听。/root/config.ini使用backendzlmediakit。板内使用zlm_api_base_url127.0.0.1和zlm_publisher_ice_ip127.0.0.1。ZLMrtc.externIP是当前公网 IP不是板子 LAN IP。路由器已映射 HTTP TCP、RTC UDP建议同时映射 RTC TCP。streamControlReply.streamUrl使用公网 IP 和正确 HTTP 端口。ZLM publisher selected pair 不经过路由器网关。使用 4G/5G 完成公网播放、长时间音视频和断线恢复验证。相关文档doc/一键部署与公网HTTP配置说明.html、doc/CONFIG_INI_REFERENCE.html、README.md。十七、结论我们应该记住什么ZLMediaKit 不是播放器而是 WebRTC 媒体服务器。它接收 RK3588 发布的流再为浏览器分发。系统中存在两段 WebRTCpublisher → ZLM和ZLM → browser必须分别配置和排查。板内发布使用 127.0.0.1公网播放使用 externIP。二者不能混用。公网 WebRTC 成功需要完整链路HTTP 信令、正确 SDP、ICE candidate、RTC 端口以及可达的 UDP/TCP 媒体链路。排障不要只测试 HTTP。沿 HTTP → SDP → ICE → DTLS → RTP → video 逐层确认。十八、文件结构说明理解各文件的职责有助于快速判断问题属于运行包、ZLM 配置、播放器配置还是浏览器链路/root/ZLMediaKit/ ├── MediaServer # ARM64 ZLMediaKit 主程序 ├── config.ini # HTTP、RTC、API secret、externIP 等配置 ├── default.pem # ZLM 默认或部署时替换的证书 ├── lib/libsrtp2.so.1 # WebRTC SRTP 运行时依赖 ├── www/webrtc/index.html # ZLM 内置 WebRTC 播放测试页 └── log/MediaServer.log # ZLM 运行与 ICE/媒体日志 /root/config.ini # rk3588_gst_player 的 backend、publisher candidate 和公网 URL /root/Test/gst-test/player.log # 播放器启流、轨道 ready 与控制接口日志播放器调用同机 ZLM 使用127.0.0.1浏览器播放地址和 ZLM 返回的公网 candidate 则使用rtc.externIP对应的公网入口。