文章目录
- 1. 问题现象
- 2. 抓包排查
- 3. 问题分析及解决方案
1. 问题现象
在 SIP 应用的开发中,通话一端听不到声音是比较常见的问题。一般来说,没有声音意味着 RTP 传输存在障碍,追根究底就是网络不通或者端口未开放等原因。但在实践中,真正造成 RTP 传输故障的原因各式各样,以下是笔者遇到的一个案例:
- 坐席使用软电话注册到 OpenSIPS,常驻拉起后拨打外部用户,媒体流传输正常
- 坐席使用硬话机注册到 OpenSIPS,常驻拉起后拨打外部用户,没有声音
2. 抓包排查
问题的切入点显而易见,硬话机的行为肯定和软电话存在不一致,从而导致问题的发生。通常遇到这种情况 SIP 抓包是不二的法门,以下是笔者使用 sngrep 抓到的 SIP 交互包,对比可以发现一个明显的差异:
使用硬话机时,在 SDP 协商完成 SIP 会话已经建立的情况下,使用 FreeSWITCH 的 bridge 命令接通坐席和用户时 FreeSWITCH 发出了一个 UPDATE 请求给到 OpenSIPS
3. 问题分析及解决方案
在进行问题分析前首先要确定以下两点:
SIP 协议中的 UPDATE 请求
UPDATE 请求用于不改变会话状态的前提下修改会话的参数,可用于 SDP 的重新协商OpenSIPS 的媒体代理
笔者的应用架构中 OpenSIPS 不仅仅具有注册代理的功能,在其核心脚本中也会使用 rtpengine 作为媒体代理服务器。OpenSIPS 进行媒体代理的原理并不复杂,关键逻辑只有两个:
- 替换 INVITE 请求中 SDP 的 IP 和端口为媒体代理服务器 IP 端口,再将其转发给 SIP 终端;
- 当 SIP 终端响应 200 时,替换响应中 SDP 的 IP 端口为媒体代理服务器 IP 端口,再将其转发给 INVITE 请求的发起端
综合以上信息,再来分析 sngrep 抓到的 SIP 交互就可以发现问题所在:
- 经过 OpenSIPS 处理后,由 INVITE 请求响应建立起的会话已经形成了
FreeSWITCH <--> rtpengine
和rtpengine <--> 硬话机
之间的 rtp 传输连接,此时 rtp 传输正常- 在 bridge 接通外部用户和使用硬话机的坐席时,FreeeSWITCH 不知道出于什么原因发起了 UPDATE 请求重新进行 SDP 协商。从 SIP 交互报文看,此次协商的结果是 FreeSWITCH 和 硬话机 绕过了 rtpengine 进行 rtp 直连,而二者之间网络并未打通
- 检查 OpenSIPS 脚本,发现脚本中对 INVITE 请求进行了媒体代理,但是未对 UPDATE 请求做任何处理
至此问题原因已经清晰,一个简单快速的解决方案是在 OpenSIPS 脚本中对 UPDATE 请求也进行媒体代理的处理,经修改后问题不复现