
一眼望去网上关于“ZLM安装”和“wvp-GB28181-pro配置”的零散教程并不少但真正能把“语音对讲”点通、系统跑稳的确实需要自己踩一堆坑。这阵子我刚好把一套基于ZLMediaKit和wvp-GB28181-pro 2.7.4的国标流媒体平台完整搭起来从空机器到设备接入、预览、双向语音全通前前后后花了两天。这篇文章就把整个部署配置过程、踩过的坑、以及语音对讲开启的关键细节完整梳理一遍给正在搞GB28181接入、或者准备把wvp-pro用起来的朋友做个参考。整套方案解决的问题很清晰用wvp-GB28181-pro作为信令与业务层负责SIP注册、设备目录、录像回放、平台级联这些国标交互用ZLMediaKit简称ZLM当媒体层负责RTP收流、转封装、分发和语音推流。信令和媒体分离两边各干各的扩展性和稳定性都要比“单体内置媒体服务”的方案好不少。适合的人主要包括安防项目集成商、车联网平台的开发者、以及想在校园或园区场景里快速搭一套国标上云系统的朋友。其实语音对讲这块文档里往往就一两句话带过但实际跑起来涉及的环节不少ZLM的RTP端口策略、wvp音频推流地址拼接、GB28181的语音广播与双向对讲信令差异、音频编码格式匹配、还有流媒体服务器的“无人观看自动回收”机制等等任何一个环节没配合上最后都会表现为“画面正常但没声音”或“对讲几秒就断”。下面我会按照从底向上的顺序把整个部署链路拆开讲透。1. 部署前的整体思路与组件拆分1.1 信令面与媒体面的分工先理解一个基础概念GB28181国标体系里信令和媒体是两条独立通道。信令走SIP协议负责设备注册、邀请INVITE、目录查询、云台控制这些控制指令媒体走RTP协议承载实际的音视频数据。wvp-GB28181-pro承担的就是信令网关加业务平台的角色它向设备暴露SIP服务端口维护设备在线状态处理国标平台之间的级联和向上级平台的注册。而ZLM是纯媒体服务不关心SIP会话只负责接收RTP流、解析成可播放的流媒体格式再有需要时把平台侧要发送的音频数据推给设备。拆开之后有个明显好处信令服务器即使重启已经接入的RTP媒体流不会断媒体服务器扩容时信令面也完全不用动。生产环境里这两个服务通常分机部署这次为了调试方便放在同一台机器上但要留意端口规划后面我会用表格给出明确的端口清单。1.2 为什么选wvp-pro 2.7.4这个版本wvp-GB28181-pro一直在迭代2.7.4属于功能比较完整、社区反馈相对稳定的一版。它把很多常见能力都收进来了设备接入、实时预览、云台控制、录像回放、语音广播、语音对讲、级联向上注册、拉流代理等。界面也做得比较清楚左侧树形目录、视频预览、录像检索这些日常操作都有。更关键的是这一版本对ZLM的对接做得比较成熟。wvp通过API接口与ZLM通信把设备拉流产生的流ID与通道ID做映射预览时自动向ZLM发起流代理请求关闭预览时自动收回流。2.7.4里这个流程已经打磨得比较顺滑我实际用下来“自动收流”这个动作基本没出过问题。1.3 硬件与系统环境建议我部署用的服务器配置不高4核8G内存Ubuntu 22.04系统磁盘预留了200GB做录像空间。实际跑一个100路以下的监控接入场景这套配置完全够。如果要接入几百路甚至上千路建议至少16G内存ZLM的socket缓冲和三四个并发转码进程会吃不少内存。因为要编译ZLM和wvp-pro还需要装一些基础构建工具比如gcc/cmake/maven等。操作系统版本不太挑CentOS 7、Ubuntu 20.04以上的发行版都没问题注意JDK版本要配好wvp-pro 2.7.4推荐用JDK 8或JDK 11太高版本可能遇到依赖兼容问题。2. 安装ZLMediaKit从源码编译到基础验证2.1 获取源码与编译参数选择ZLM的官方仓库里维护得很勤建议直接拉最新的稳定发布标签而不要用master分支的滚动版本。拉取后进入目录编译方式比较固定git clone -b release-tag --depth 1 https://gitee.com/zlmediakit/ZLMediaKit.git cd ZLMediaKit git submodule update --init mkdir build cd build cmake .. make -j$(nproc)这里有几个编译期的选择值得注意。第一-D ENABLE_WEBRTC默认开启如果不需要WebRTC拉流或推流可以编译时关掉能减少一些依赖但如果你后续想给网页端做低延迟播放建议保留。第二-D ENABLE_FFMPEG这个选项建议开启它会在ZLM里编译进ffmpeg相关功能对音频转码、录像合成这些场景有直接帮助。第三-D ENABLE_MP4默认开启别关录像全靠它。整个编译过程大概十分钟到二十分钟取决于机器性能。编译完成后在build/bin下会生成MediaServer可执行文件这就是ZLM的主程序。2.2 配置文件与端口规划ZLM的默认配置文件config.ini在release/目录下启动时会依次寻找当前目录、默认路径下的配置。用之前建议先把模板复制到显眼的位置然后重点核对几个关键段[api] apiDebug1 secret你的自定义密钥 [rtsp] port554 [rtmp] port1935 [rtp_proxy] port10000 [hook] enable1配置项里的secret在wvp里配置ZLM时要用两边必须完全一致这是wvp调用ZLM API的鉴权凭证。RTP接收端口我习惯用一段连续区间而不是单一端口比如10000-20000因为国标设备并发推流时多个端口同时开放能有效降低端口冲突概率。ZLM启动后会自动监听这些端口收到RTP包后根据SSRC识别流。2.3 验证ZLM服务是否正常启动ZLM./MediaServer -d -c /你的配置路径/config.iniZLM默认开启了HTTP API服务端口是80。验证接口是否正常可以这样请求curl http://127.0.0.1/index/api/getServerConfig?secret你的密钥返回JSON里包含服务版本、启动时间、已存活时长等信息说明ZLM的API接口正常。接着再验证流媒体端口是否监听netstat -lnpt | grep -E 554|1935|10000把554和1935这两个都确认到位。实测中我发现一个很隐蔽的问题ZLM启动后默认流媒体服务是IPv6优先的某些老设备或者某些网络环境走IPv4会连不上。遇到这种情况在config.ini的[general]段把IPv6相关选项关掉或调整监听地址为0.0.0.0就能解决。3. wvp-GB28181-pro 2.7.4 的构建与配置3.1 获取源码与打包wvp-pro 2.7.4是一个典型的Spring Boot项目构建前确认JDK版本和Maven环境正确。我用的JDK 11Maven 3.6以上源码拉下来后执行mvn clean package -Dmaven.test.skiptrue打包完成后在target/目录下会生成一个可执行的jar包名称类似wvp-pro-2.7.4.jar。整个打包过程需要联网下载依赖第一次会比较耗时建议用国内Maven镜像加速。3.2 数据库准备MySQL初始化wvp-pro使用MySQL保存设备、通道、用户、录制计划等业务数据同时需要Redis缓存会话状态和流媒体信息。数据库部分需要手动执行初始化脚本脚本在源码的sql/目录下。我的建议是新建一个独立数据库不要和别的应用共用避免字段冲突。执行脚本时注意字符集要设成utf8mb4因为GB28181设备名称中含有中文和特殊符号utf8mb4才能完整存下。初始化完成后还需要在脚本里预设管理员账号和密码一般在user表里插入一条管理员记录。3.3 核心配置文件application.yml逐项解析wvp-pro的配置集中在application.yml其中sip、media、redis三个段落是最关键的。贴出一份我实际用过的核心配置片段server: port: 18080 sip: ip: 你的服务器内网IP port: 5060 domain: 34020000002000000001 id: 34020000002000000001 password: 12345678 media: ip: 127.0.0.1 port: 80 secret: 你的ZLM密钥 ssrc-prefix: 000000 rtp-port: 10000-20000 playback-port: 20000 redis: host: 127.0.0.1 port: 6379 password:这些配置牵涉到国标设备注册时的SIP认证。sip.id相当于本平台在国标体系里的“设备编号”domain指向国标行政区域代码password是设备向平台注册时的认证密码和设备端配置的页面里填的SIP密码必须一致。media.secret就是之前ZLM里设置的API密钥这里填进去之后wvp才能成功调用ZLM接口。值得特别注意的是sip.ip这个字段。它既不能随便填成0.0.0.0也不能填成公网IP而是要填本机在局域网内的实际地址。设备向平台注册时这个IP是SIP信令中的Contact头域地址设备靠它回包填错了最典型的症状就是“设备显示在线但目录请求超时”。3.4 配置完成后的启动与基础排查配置无误后启动java -jar wvp-pro-2.7.4.jar首启时会自动建表、初始化Redis缓存、向ZLM注册流媒体节点。此时观察日志如果出现类似的输出向ZLM发送接口请求失败、连接Redis被拒绝之类的内容按字面意思去查对应服务就行。我遇到过这样一个问题wvp启动后日志一切正常但页面登录后一片空白接口返回401。查下来是因为 Redis 里缓存了旧的系统配置而缓存里的加密算法与当前版本不匹配。解决方案很简单启动前先清空Redis整个数据库或者执行FLUSHALL命令让wvp重新初始化缓存。启动完成后打开管理页面验证登录默认端口是18080。如果页面能正常登录说明wvp自身没问题可以开始对接设备。4. 设备接入、媒体拉流与语音对讲开启4.1 设备侧SIP参数配置要点国标摄像头或NVR要接入wvp通常在设备的“平台接入”或“GB28181”菜单里配置以下参数SIP服务器IPwvp所在服务器IPSIP服务器端口5060SIP用户ID设备自身的国标编号比如34020000001320000001SIP认证用户ID同上SIP认证密码配置里sip.password对应的值视频通道ID通道编号比如34020000001320000002注册有效期建议3600心跳周期建议60设备填完后去wvp的设备列表页刷新正常情况下几秒内就能看到新设备上线。如果一直显示离线主要排查SIP端口是否被防火墙拦截以及sip.ip是否填得可以让设备路由回来。4.2 实时预览的媒体拉流链路设备上线只是第一步接下来要看实时预览是否通。点击设备通道的“播放”按钮时wvp内部会依次做几件事向设备发送INVITE邀请携带ZLM预先分配好的ssrc设备收到邀请后开始向media.rtp-port范围内某端口推RTP流ZLM收到RTP后根据ssrc和端口自动识别通道转封装成RTSP/RTMP/HTTP-FLV等格式wvp把播放地址返回给前端前端播放器拉流显示。这个链路里最影响成败的是端口和ssrc的对应关系。真实场景中设备主动推流的目标IP是wvp在SIP信令中告诉它的这个地址ZLM必须在同一台机器或同一内网可达。如果ZLM部署在另一台服务器设备又推不到那台服务器的IP就会出现“信令正常、播放失败”的典型故障。4.3 语音对讲的原理与两条不同路径语音对讲在国标体系里实际上分成两个场景语音广播和双向语音对讲wvp的界面里也分成了两个按钮。很多人一开始没分清导致配置方向跑偏。语音广播是单向的由平台主动播放一段音频给某通道或某设备设备侧扬声器出声平台侧只听设备回传的声音。语音广播在国标里用Broadcast指令实现音频数据由平台侧推流给设备通常是通过ZLM把一段媒体流发送到设备的RTP接收端口。双向对讲则更像微信语音通话两边同时说话、同时收听。wvp 实现双向语音的方式是先让设备向平台推流用于平台听设备端的声音同时平台再向设备推流用于设备听平台端的声音两路流同时存在界面上的“开始对讲”按钮其实就是同时触发这两路。不管是广播还是双向对讲平台的推流动作都依赖ZLM的能力。ZLM支持通过API创建“流代理”即把一路已有的音视频流转发到指定目标地址。wvp开启语音时就是创建了一条从ZLM到设备的RTP推流通道。4.4 实际开启语音对讲的关键步骤在wvp 2.7.4的通道详情或播放页面里点击“语音对讲”按钮时后端会依次完成向设备发送SIP INVITE请求建立音频双向传输会话从ZLM获取或创建一个音频推流地址通常形如rtsp://127.0.0.1/voice/{channelId}由前端或后端将一段音频数据推到这个地址ZLM把它转发给设备设备端收到音频后通过扬声器播放同时设备端麦克风采集的声音继续通过已建立的RTP会话回传整个链路里最容易出问题的反而是第三步的音频数据来源。ZLM并不会凭空生成音频它需要一路真实的音频流作为输入。wvp的语音对讲功能实现里前端会从浏览器或指定音频源采集声音通过audio/vorbis或其他编码推流到ZLM再由ZLM完成格式转换和转发。我在实测中遇到最典型的现象是点击对讲后设备端完全没声音但wvp提示对讲成功。排查后发现问题出在推流地址的编码格式上——设备端只支持PCMA/PCMUG.711音频而前端采集后推给ZLM的是AACZLM默认没有开启音频转码于是音频格式不匹配设备直接丢弃。解决办法是在ZLM的流代理配置中加上音频转码参数或者在推流时直接采用PCMA编码。实际最简单的方式就是让推流端使用G.711a格式。4.5 配置ZLM音频转码与推流细节如果采用ZLM作为语音推流中转需要理解ZLM的“转码”选项。ZLM在编译时开启了ffmpeg的前提下可以在流代理配置里增加音频转码参数将输入音频转为设备支持的PCMA。操作上可以在ZLM的config.ini中为某一路流代理指定transcode选项或者在创建流代理的API请求里附带audio_codec : alaw这类参数。还需要注意音频采样率。国标设备普遍支持8000Hz采样率的PCM音频而浏览器推流往往默认为48000Hz。如果采样率不匹配即使编码格式对了设备端也可能出现“刺耳的变声”或“沙沙声”。因此对讲推流时建议先把音频重采样到8000Hz再推出去。ZLM的ffmpeg转码选项可以顺带完成重采样。我把这一段的配置梳理成了一份标准动作方便直接抄在ZLM中确认enable_ffmpeg和相关转码开关为true语音对讲开始时wvp向ZLM申请一路“用于语音播放的流”地址中包含通道编号前端采集到的音频经浏览器编码为G.711或PCM通过rtsp或rtmp协议推送到该地址若格式非G.711要让ZLM在转发时完成音频转码确保设备收到的音频是PCMA/PCMU其中一个确认设备端SIP会话里的音频媒体描述与实际音频编码一致4.6 单向语音广播的补充配置语音广播的逻辑比双向对讲简单一些。wvp里“语音广播”按钮被点击时平台侧会创建一路音频流并直接向设备的SIP接收端口推送同时使用SIP MESSAGE或INVITE触发设备播放。配置上和双向对讲高度重合多数设备在双向对讲通了之后广播也能直接用。但广播有个额外参数需要留意设备接收RTP音频的目标端口一般被固定在设备SIP配置里的某个端口段比如15060。如果这个端口和设备端其他协议端口冲突设备可能不响应。这个参数通常在设备端的GB28181配置页里叫“媒体端口”或“本地RTP端口”保持默认即可不要随便改。5. 常见问题与排查技巧实录5.1 设备注册失败列表持续离线最典型的“设备注册不上”分两类一是网络层通不到二是SIP认证失败。先用tcpdump -i eth0 port 5060抓包看设备有没有发REGISTER到平台如果没抓到包基本是网络或服务器IP填错如果抓到了401或403响应检查wvp里sip.password与设备端SIP密码是否一致。另外一个很容易被忽视的点是平台ID和域名的长度。国标编号一般是20位数字设备端如果填的SIP服务器ID少于20位有些设备会直接拒绝注册。可以在设备端查看注册状态日志一般能看到具体的拒绝原因码。5.2 INVITE超时实时预览黑屏信令已通、设备在线、目录能查到、就是点播放不出画面这是第二大类高发问题。按下面顺序排查先看wvp日志里有没有“收到INVITE响应”的提示如果没有说明INVITE请求没到达设备检查设备端是否限制了平台IP。接着看ZLM日志里有没有新端口收到RTP的记录设备推流会体现在ZLM的日志里如果ZLM没任何反应大概率是设备的媒体目标IP配成了wvp的IP但wvp实际运行在容器里或双网卡环境导致设备把RTP推到了错误的网卡。还有一种隐蔽的场景wvp所在服务器有多个网卡设备默认推流到sip.ip但sip.ip填的是不对外提供媒体服务的网卡RTP流自然丢失。这种就把sip.ip改成设备能实际路由到的那块网卡地址同时media.ip也要与之一致。5.3 语音对讲时设备无声音或声音异常汇总我这几天踩过的和对别人咨询过的语音类问题整理成速查表现象可能原因处理方式设备端完全没声音推流音频编码与设备不支持转成PCMA/PCMU有声音但爆音/变调采样率不匹配重采样到8000Hz对讲几秒后自动断开音频流被ZLM自动收回关闭流的无人观看自动回收或延长超时只能听到一端声音双向对讲只建立了一条单向流检查双向INVITE是否都收到200 OK点击对讲后平台报错ZLM的secret不匹配或创建流失败核对ZLM API鉴权与推流地址ZLM对流自动回收的默认策略当某路流没有任何播放者时过一段时间就自动关闭。用于语音对讲的流如果没有被前端播放器正常“观看”很容易被ZLM判定为无人使用然后回收。遇到对讲中断问题优先检查ZLMconfig.ini里[general]段的mediaTimeout参数调成0或一个很大的值再重启ZLM。5.4 平台日志与ZLM日志的配合定位这类联调问题纯看一端日志很难定位我习惯按照“信令先于媒体”的顺序排查。wvp日志定位信令问题谁向谁发了什么请求回包是什么状态码一目了然。ZLM日志定位媒体问题哪些端口收到了RTP流的ssrc是多少转码有没有报错。实际过程中wvp日志里经常会出现类似“向ZLM请求流失败”的提示这时不要急着怀疑ZLM先把ZLM的API接口直接用curl调一遍看看鉴权是否通过。我就是因为当初wvp配置里的media.secret和ZLMconfig.ini里的secret不一致白白多排查了一个小时。6. 一些值得记录的实操心得整套环境部署下来我最想单独说的一个点是语音对讲不是“配置完就能用”的功能它比实时预览更依赖音频编码链路的完整。预览画面黑屏问题往往集中在网络和端口语音没声音或断断续续则八成是编码和流回收策略没调好。所以建议先把实时预览跑通、把ZLM日志看熟再来折腾语音对讲排查效率会高一截。另外建议把所有服务的监听端口、流媒体端口区间、API鉴权密钥全部整理成一份清单放在项目目录下面。我在实际部署时把这份清单贴在服务器终端旁边出问题时扫一眼就能定位不用临时去翻配置文件。还有个小技巧尽量让ZLM和wvp的日志级别保持“可调试”状态排查完再调低。wvp的日志默认级别已经够用ZLM的apiDebug建议开启方便看到API请求的完整参数和返回。调试期多打日志不丢人线上出问题的时候日志就是唯一的线索。这个部署方案后续还可以扩展的方向很多比如配上录像计划、级联到上级平台、接入WebRTC播放页面、再做一层负载均衡把媒体流分散到多台ZLM。不过先把基础的注册、预览、语音对讲这三条链路跑通后面的所有扩展才有地基。按我个人的体验最耗时的往往不是安装和配置本身而是理解每条链路背后“信令怎么走、媒体怎么传、编码怎么匹配”的机制把这三个问号拉直了剩下的都是体力活。