☰
FreeSWITCH proxy_media视频流故障:黑屏花屏根因与修复
2026/10/16 7:09:58 网站建设 项目流程

聊视频呼叫的时候,很多人都挂过同一个号:信令完全正常,电话也通了,声音一点问题都没有,但画面就是出不来,黑屏、单通、花屏轮着来。这种问题十有八九不是终端兼容性,而是FreeSWITCH的proxy_media模式在视频媒体流上根本没给你干该干的活。这篇文章就围绕这个标题里的那条主线来说:proxy_media模式下的video流会出现什么问题,以及要怎么修。

我先把结论放在前面:proxy_media本身不是错误配置,它是FreeSWITCH处理媒体路径的一种正常模式,但它在设计之初更关注音频SIP业务,对视频RTP流的感知和处理都很弱。你如果不理解它到底做了什么、没做什么,就会在视频业务上踩坑。这篇文章适合做VoIP接入、视频客服、视频坐席、SBC替代方案,以及所有在FreeSWITCH里跑视频呼叫的朋友参考,内容尽量不绕弯,直接说机制和做法。

1. 为什么绕不开proxy_media:这是video问题的前置背景

1.1 proxy_media和bypass_media到底差在哪

要搞清楚视频流的问题,必须先分清FreeSWITCH的两种媒体模式。很多人把bypass_media理解成"媒体不经过FreeSWITCH",把proxy_media理解成"媒体经过FreeSWITCH",这样理解大方向没错,但不精确。

bypass_media是媒体绕过:FreeSWITCH只做信令面的B2BUA,RTP流在呼叫双方之间尽量直连,服务器的CPU压力最小,延迟也最低。它的问题是一旦中间有NAT、防火墙或者需要对媒体内容做处理,直连就会失败或者让业务拿不到媒体。

proxy_media则是媒体代理:RTP流会经过FreeSWITCH这台机器,但FreeSWITCH只做转发,不解码、不转码、不录音、不分析内容。它的角色更像一个"媒体管道",把两端的RTP包按照SDP协商好的地址和端口投递过去。之所以叫proxy,是因为FreeSWITCH既不在RTP层面做深度处理,又不像bypass那样彻底放手。

通俗一点说:bypass_media是双方约好地点,你们直接碰面聊;proxy_media是你们把话都递给我,我原封不动转达,但我只负责传话,不负责翻译、不负责录音,也不负责检查你们说的是不是同一门语言。

对比项bypass_mediaproxy_media
信令处理B2BUA,两端信令都经过FSB2BUA,两端信令都经过FS
媒体路径RTP不经过FS,直连或经NAT穿透RTP经过FS,由FS转发
CPU开销低中低,取决于包量和RTP重写
录音/监听能力不支持,除非额外做旁路可配合media bug等机制做旁路
视频支持天然友好,两端自行协商需要正确配置RTP重写和SDP处理

在SIP协议层面,bypass_media模式下FreeSWITCH通常会在SDP里把连接地址改写成对端可达的公网或内网地址,或者通过ICE等机制让两端自己跑起来;proxy_media模式下FreeSWITCH必须把SDP里的媒体地址和端口改成自己的地址和端口,让两端都把RTP发到FreeSWITCH这里来。

这一改,就改出了很多和视频流相关的坑。音频通常只有一条m=audio媒体线,视频则可能有m=video、多路视频、甚至音频+视频+辅助流共存,SDP结构复杂得多,媒体转发逻辑也比音频更容易出错。

1.2 非要走proxy_media的业务场景

既然bypass_media对视频更友好,为什么大家不直接用bypass?因为很多业务场景不允许。我自己遇到过的场景至少有下列这些:

  • 呼叫中心要对通话录音、质检,必须让媒体经过服务器才能抓到音频和视频流;
  • 视频坐席系统需要在IVR环节播放视频提示,或者让用户排队时看到等待画面;
  • 外呼线路对端不支持某些视频编码,需要FreeSWITCH做转码或协商裁剪;
  • 需要通过FreeSWITCH统一控制RTP端口区间、带宽限制、QoS标记,而不是放给两端乱传;
  • 信令路由复杂,有多个代理层时,媒体直连很难穿透多级NAT,走代理反而更可控。

在这些需求下,proxy_media是绕不开的。既然绕不开,就得搞清楚视频流在这个模式下为什么会坏,以及修起来该从哪下手。

2. 黑屏、单通、画面撕裂:proxy_media下video的三种故障表现

2.1 第一种:双方信令正常,但一端持续黑屏

这是最常见的故障。呼叫能建立,音频双向正常,但其中一端的画面始终不出。我遇到过的一个典型案例是:坐席端用的WebRTC,客户端用的是手机App,两边都是H264,音频协商完全正常,INVITE和200 OK里也都有m=video那几行,但从手机这端看过去,就是没画面。

用抓包工具看RTP流,能明显看到坐席端发出来的视频包根本没有到达手机端。原因在于FreeSWITCH在转发媒体时,修改了SDP里的媒体地址和端口,但没有把视频流的RTP包也按照新地址转出去,或者转出去的包在NAT回程时丢失了。画面迟迟不出现,就是典型的"协商成功、转发黑洞"。

2.2 第二种:声音双向正常,视频只有一个方向

这种故障比全黑更容易误导人。A能看到B,B却完全看不到A。看起来像是某一端的终端问题或者编码问题,其实问题经常出在媒体代理的SDP处理上。

如果FreeSWITCH在改写offer和answer时,把A侧视频的媒体地址改对了,但B侧返回的answer包含多个视频编码,或者B侧在协商后重新发起了re-INVITE,FreeSWITCH只更新了音频部分,视频部分的关联关系就错乱了,于是变成一条方向通、另一条方向不通。单通问题的隐蔽性在于:它跟两端终端的摄像头、网络质量都没关系,你换两台终端测试,故障依旧,这时就要往SDP和媒体代理层排查。

2.3 第三种:视频能出画面,但花屏、卡顿、马赛克

还有一种故障是画面能出来,但质量完全不能看。延迟翻倍、频繁掉帧、马赛克堆积。这种问题往往是RTP转发时序列号和负载格式出了问题。

RTP是基于UDP的实时传输协议,依靠sequence number和timestamp来排序和播放。FreeSWITCH在proxy_media模式下做转发时,如果对RTP包头不进行重写,而两端的SSRC、序列号起始值并不相同,对端终端在播放时就会丢失同步,视频解码器拿到乱序或错位的包后自然只能输出残缺画面。这个问题尤其在两端都使用相同IPT时更容易出现,因为接收端可能会把来自不同SSRC的包混淆。

3. 根因拆解:SDP协商与RTP转发,各有一道关

3.1 SDP阶段:媒体代理如何"改写"offer/answer

当FreeSWITCH作为B2BUA进行媒体代理时,它需要对SDP做一次"转发地址改写"。简单来说,两端各自发来的m=audio和m=video行里,地址和端口必须指向FreeSWITCH本身,否则RTP不会流经服务器,媒体代理就名存实亡。

音频SDP通常只有一个m=audio行,处理起来很单一。视频SDP则复杂得多,一个呼叫里可能有:

  • m=video主视频流;
  • a=rtpmap行里包含H264、VP8、H265等多种编码;
  • a=fmtp行里带有profile-level-id、packetization-mode等关键参数;
  • 甚至还有m=application这类RTP扩展流。

FreeSWITCH的SDP改写逻辑如果没有针对多m行做完整处理,就很容易出现两种情况:第一,只改写了音频m行的地址,视频m行的地址没改;第二,视频m行改了端口,但对应的c=行(连接地址)没有跟着改。无论哪种情况,对端终端都会把视频RTP包发到一个错误的目标,画面自然出不来。

这种情况在纯音频呼叫里几乎不会遇到,因为你只有一个m行。所以很多在一线做过几年音频业务的朋友,第一次碰视频代理问题时,会完全想不通为什么音频没问题、视频全废——其实就是视频SDP多出来的那些行没人管。

3.2 RTP阶段:SSRC、序列号和转发路径的混乱

就算SDP改写得完美,RTP转发阶段仍可能出岔子。原因在于RTP包的头部信息本来应该自己管自己的,但FreeSWITCH转发时默认不对RTP包头做修改,于是两端直接拿对方的原始RTP包来做通信。

RTP包里有个字段叫SSRC,用来标识这是哪一路媒体流。A端发出来的RTP流SSRC和B端发出来的SSRC通常不同,FreeSWITCH把它们转发到对端时,对端会收到两个不同SSRC的RTP包。如果终端实现不够健壮,就会认为视频通道有问题,停止播放。

另外还有一个容易被忽视的细节:RTP的序列号和时间戳都是从随机值开始的。媒体代理在转发时若不做任何干预,接收端可能会检测到序列号跳变或者时间戳回退,触发PLC(丢包补偿)或者等到重传包,表现为视频卡顿和花屏。

很多视频黑屏表面上看起来是兼容性问题,实际上就是这些底层字段信息没理清,把无关的SSRC包发过去,终端直接放弃显示了。

3.3 一次实际排障走查:问题出在哪一层

我之前帮一位同事排查过一个视频坐席项目,现象是坐席端和客户端的视频完全消失。排查过程大致是这样的:

第一步,先看fs_cli里的通道状态,确认media_handling是proxy,这说明我们确实走的媒体代理模式,没有意外进入bypass。

第二步,抓两端的SIP信令,发现INVITE里有m=video 0 RTP/AVP ...,对端返回的200 OK里也有完整的视频媒体行。从信令上看,协商是成功的。

第三步,抓RTP包。发现坐席端发往FreeSWITCH的RTP包里有视频流,但FreeSWITCH转发出去之后,客户端网络出口上根本收不到对应的视频RTP包。换句话说,视频流堵在了FreeSWITCH转发这一层。

第四步,在FreeSWITCH里查看SDP改写结果。发现FreeSWITCH把音频地址改写成了代理地址,但视频地址仍然指向原来终端的内网IP。由于那个IP在公网不可达,视频包发出去就丢了。

问题定位后,解决方案并不复杂:开启RTP重写、调整代码里对SDP多m行的处理方式,视频马上恢复正常。这个案例给我留下的最深印象是:问题根本不在终端也不在网络,而在媒体代理对多路媒体流的处理不够彻底。

4. 修正路径:rtp-rewrite、codec收紧与配套调优

4.1 先分诊:确定故障属于协商层还是转发层

遇到视频故障,别急着改代码或者换终端,先做一个简单的分诊。拿着fs_cli、SIP抓包和RTP抓包,按下面这个顺序判断:

  • 看协商:信令里m=video是否存在?SDP里的连接地址是否指向FreeSWITCH代理地址?如果没有,就是SDP改写问题;
  • 看转发:协商正常,但对端没收到RTP包,或者收到的包无法解码,就是RTP转发问题;
  • 看终端:两端直连(bypass)时视频正常、走代理的时候故障复现,九成是代理配置问题,不要再去折腾终端。

这个分诊流程能帮你快速锁定方向。我见过太多人在终端兼容性上钻牛角尖,回头发现只是FreeSWITCH少开了一个开关。

4.2 开启RTP重写,把转发路径理顺

修正视频代理问题,第一步通常就是开启RTP重写。在FreeSWITCH里,这个动作通常由rtp_rewrite,或者说部分版本里的media_rewrite来控制。开启后,FreeSWITCH会重写RTP包头里的SSRC、序列号和时间戳,让每一侧看到的是独立、完整的RTP流,而不是被代理过的半成品。

配置位置可以在拨号计划里按需设置,也可以放到SIP profile里作为全局默认。我习惯在Dialplan里对特定业务开启,影响范围更可控:

<extension name="video-proxy-fix"> <condition field="destination_number" expression="^vtest$"> <action application="set" data="media_handling=proxy"/> <action application="set" data="rtp_rewrite=true"/> <action application="answer"/> <action application="bridge" data="user/1001"/> </condition> </extension>

不同版本的FreeSWITCH对这个参数的命名略有差异,有的叫rtp_rewrite,有的叫media_rewrite,还有的老配置习惯用set_proxy_media=true配合其他变量。你以自己环境中真实存在的变量名为准,但核心逻辑是同一个:让FreeSWITCH把RTP包头和媒体元数据理顺,再转发出去。

开启rtp_rewrite不等于什么都不用管了。它有一个代价是CPU消耗明显上升,因为FreeSWITCH需要对每个RTP报文的头部做修改,这在纯音频呼叫里问题不大,但在视频高并发场景下会占不少CPU资源。部署前先估算并发路数,给主机留足余量。

4.3 收紧视频codec与payloadType,减少协商歧义

光开RTP重写还不够,很多视频黑屏问题还出在codec协商的歧义上。SDP里同一个payloadType在两个m行里代表不同的编码,或者同一路视频里出现了H264和VP8混用,终端解析SDP时就会有歧义,媒体流建立不了。

我的建议是:在代理模式下主动收敛视频编码范围。如果你的业务终端都支持H264,就在SDP改写时过滤掉VP8、H265等不必要编码,只留下一到两种。这样能降低两端协商出"两边各自支持、但格式互为独立流"这类尴尬局面的概率。

同时注意a=fmtp里的参数,特别是H264的profile-level-id和packetization-mode。FreeSWITCH做纯媒体代理时不会去转换这些参数,如果一端要求High Profile,另一端只支持Baseline,协商可能显示成功,实际视频却因为解码能力不足出不了画。遇到这种情况,要么做真正的转码,要么在前端就统一终端的编码规格。

4.4 配套参数与边界情况处理

除了RTP重写和codec收敛,还有几个配套参数容易被人忽略。

第一个是RTP超时机制。proxy_media下,如果FreeSWITCH在一段时间内没有收到某侧的RTP包,会认为媒体流已死。在视频业务中,某些终端在呼叫建立初期可能短暂不发送视频包,如果超时设置得太短,就会被FreeSWITCH误判为流中断。建议把RTP超时适当调长,或者结合业务逻辑做更宽容的判定。

第二个是NAT穿透。如果呼叫两端在公网,而FreeSWITCH在内网或者有多个网卡,一定要确认转发使用的IP端口是外部可达的。很多黑屏问题不是逻辑问题,而是SDP里改写成了内网地址,外面根本访问不到。

第三个是ICE支持。WebRTC终端的ICE协商是和普通SIP终端不一样的,如果FreeSWITCH没有正确传递ICE候选,视频流就可能建立失败。遇到WebRTC场景,需要检查SDP里的a=ice-ufrag、a=ice-pwd以及candidate信息是否被正确转发。

4.5 验证手段:别只看画面,要看RTP统计

修完之后,不要在界面上看到画面就收工。视频能显示,不代表代理路径完全健康。更好的做法是看RTP统计信息,确认双方的包量是否对等、丢包率是否正常、SSRC是否只有一个来源。

在FreeSWITCH里可以查看通道的媒体统计,也可以用外部抓包工具同时抓FreeSWITCH入口和出口的流量,对比确认每个RTP包都被正确转发了。我自己常用的做法是搭一套RTP抓包分析环境,把每通呼叫的信令和媒体流都记录成文件,排障时可以直接回放对照。视频问题往往有规律,把几通失败呼叫的SDP和RTP信息放在一起对比,根因很快就浮出来。

5. 修正不了的场景怎么处理:bypass、media bug与透明媒体

5.1 哪些场景别硬扛proxy_media

有些视频场景,proxy_media修来修去都修不好,不是你的配置不够认真,而是这个模式的适用边界本身就不适合。最典型的例子是:

  • 两端都要求高分辨率、高帧率视频,比如4K视频会议,媒体转发的CPU开销和延迟会大到你无法接受;
  • 终端用了很多私有扩展的RTP能力,比如屏幕共享、多路辅流,FreeSWITCH的SDP改写逻辑跟不上;
  • 业务本身对媒体内容完全不关心,只是需要一个信令网关。

遇到这种场景,最务实的办法就是走bypass_media。信令继续走FreeSWITCH做路由、鉴权和计费,媒体直接让两端互通。这样视频流完全由终端自行协商,FreeSWITCH不参与转发,问题自然消失。

5.2 如果只是为了录音和质检:用media bug做旁路

很多时候你坚持要proxymedia,不是因为信令需要,而是因为业务需要录音、监听或者质检。但你要清楚,proxy_media执行的RTP转发不是录音的必要条件。FreeSWITCH里实现录音更优雅的方式是使用media bug机制,也就是在媒体流上挂一个"旁路分析器",让音频或视频流在FreeSWITCH内部被分支复制出来做录制和分析,而主媒体路径仍然可以是bypass。

这样做的好处不只是降低转发压力,还避免了proxy模式下的视频RTP问题。媒体主路径直连,视频流质量有保证;录音和质检走旁路分支,业务功能一样不缺。前提是你的FreeSWITCH版本以及相关模块支持对视频流做分支处理,有些老版本对视频流的media bug支持有限,需要提前验证。

5.3 信令代理+透明媒体的折中方案

很多时候我们走到最后,会发现最合适的方案是"信令走代理、媒体透明"的折中模式。听起来像矛盾,其实这是一种非常实用的部署思路。

信令面继续由FreeSWITCH做完整处理,包括路由、号码变换、权限控制、计费。但媒体面通过GUID、媒体透明等策略,让RTP的最终路径不经过FreeSWITCH。终端之间通过SDP协商出的地址直接互发,FreeSWITCH只负责在信令面维护呼叫状态,媒体质量完全交给两端网络。

这种方案特别适合视频呼叫这类对延迟敏感的实时业务。在不需要录音转码、不需要IVR插播媒体的纯视频通话场景下,我一直推荐用这种思路。它既保留了FreeSWITCH作为SIP应用服务器的调度能力,又规避了媒体代理在视频处理上的短板。

6. 这些坑踩过之后,我的应急工具箱

最后聊一点实际的心得。在FreeSWITCH上跑视频业务,我吃过的亏不少,现在遇到视频媒体问题,基本按这三板斧来:

第一斧头永远先看SDP。不管问题表象是黑屏还是花屏,一定把两端的SDP拉出来对比,确认每个m行的连接地址是不是指向正确的位置。SDP错了一切都白搭。

第二斧头是开RTP重写。如果SDP没问题,就检查rtp_rewrite这类参数是否开启。很多老项目从纯音频升级到视频业务时,这些参数从来没有打开过,开了之后效果立竿见影。

第三斧头才是去折腾codec和终端。能收敛的编码先收敛,能统一的终端参数先统一,最后才去谈兼容性和硬件问题。

另外强烈建议你在测试环境准备一套RTP抓包分析工具,最好是能关联SIP信令和RTP流的。视频RTP故障排查,光看黑屏是看不出原因的,能把包层面的证据找到,很多问题的定位时间能从几天缩短到几小时。

每一次视频故障排查,最后都会回归到一个朴素的问题:你在信令面做了B2BUA,那么在媒体面,你到底做不做代理?如果做代理,就要接受它的规则、补上它的缺口;如果不做,就干脆放媒体直连。两者之间摇摆,才是视频流问题源源不断的根源。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询