在日常维护中,经常会遇到有客户报488错误的问题,有客户端返回的,也有服务器返回的,问题是随机出现,从日志及抓包或者软电话接通发现提示488 Not Acceptable Here。 根据往常经验认为一般是SDP 的codec协商失败,双方codec不兼容,但是实际场景中有很多其他原因导致,下面就分享一下我曾经踩到的坑及解决方案。
####场景一:典型场景 codec协商失败,双方语音或者视频的codec不兼容
一般如果是codec不兼容,通过wireshark
抓包观察invite的sdp
codec描述部分 和对端带SDP响应的183或者180响应的sdp
codec描述部分,就可以知道兼不兼容,
或者你打开freeswitch的debug日志,很容易看到相关的日志打印,关键字“no
suitable candidates found.“,如下:
3133f78a-48e9-11ea-affa-87c9172e3dc8 2020-02-06 18:01:37.631217 [DEBUG] switch_core_media.c:4449 Audio Codec Compare [CN:105:16000:20:0:1]/[PCMA:8:8000:20:64000:1]
3133f78a-48e9-11ea-affa-87c9172e3dc8 2020-02-06 18:01:37.631217 [DEBUG] switch_core_media.c:4449 Audio Codec Compare [CN:105:16000:20:0:1]/[opus:116:48000:20:0:1]
3133f78a-48e9-11ea-affa-87c9172e3dc8 2020-02-06 18:01:37.631217 [DEBUG] switch_core_media.c:4449 Audio Codec Compare [CN:105:16000:20:0:1]/[G7221:115:32000:20:48000:1]
3133f78a-48e9-11ea-affa-87c9172e3dc8 2020-02-06 18:01:37.631217 [DEBUG] switch_core_media.c:4449 Audio Codec Compare [CN:105:16000:20:0:1]/[G7221:107:16000:20:32000:1]
3133f78a-48e9-11ea-affa-87c9172e3dc8 2020-02-06 18:01:37.631217 [DEBUG] switch_core_media.c:4449 Audio Codec Compare [CN:105:16000:20:0:1]/[G722:9:8000:20:64000:1]
3133f78a-48e9-11ea-affa-87c9172e3dc8 2020-02-06 18:01:37.631217 [DEBUG] switch_core_media.c:4449 Audio Codec Compare [CN:13:8000:20:0:1]/[PCMU:0:8000:20:64000:1]
3133f78a-48e9-11ea-affa-87c9172e3dc8 2020-02-06 18:01:37.631217 [DEBUG] switch_core_media.c:4449 Audio Codec Compare [CN:13:8000:20:0:1]/[PCMA:8:8000:20:64000:1]
3133f78a-48e9-11ea-affa-87c9172e3dc8 2020-02-06 18:01:37.631217 [DEBUG] switch_core_media.c:4449 Audio Codec Compare [CN:13:8000:20:0:1]/[opus:116:48000:20:0:1]
3133f78a-48e9-11ea-affa-87c9172e3dc8 2020-02-06 18:01:37.631217 [DEBUG] switch_core_media.c:4449 Audio Codec Compare [CN:13:8000:20:0:1]/[G7221:115:32000:20:48000:1]
3133f78a-48e9-11ea-affa-87c9172e3dc8 2020-02-06 18:01:37.631217 [DEBUG] switch_core_media.c:4449 Audio Codec Compare [CN:13:8000:20:0:1]/[G7221:107:16000:20:32000:1]
3133f78a-48e9-11ea-affa-87c9172e3dc8 2020-02-06 18:01:37.631217 [DEBUG] switch_core_media.c:4449 Audio Codec Compare [CN:13:8000:20:0:1]/[G722:9:8000:20:64000:1]
3133f78a-48e9-11ea-affa-87c9172e3dc8 2020-02-06 18:01:37.631217 [DEBUG] switch_core_media.c:4365 Set telephone-event payload to 110@48000
2020-02-06 18:01:37.631217 [DEBUG] mod_opus.c:603 Opus encoder: set bitrate to local settings [72000bps]
2020-02-06 18:01:37.631217 [DEBUG] mod_opus.c:603 Opus encoder: set bitrate to local settings [72000bps]
3133f78a-48e9-11ea-affa-87c9172e3dc8 2020-02-06 18:01:37.631217 [DEBUG] switch_core_media.c:3061 Set Codec sofia/internal/501@198.50.194.89 opus/48000 20 ms 960 samples 0 bits 1 channels
3133f78a-48e9-11ea-affa-87c9172e3dc8 2020-02-06 18:01:37.631217 [DEBUG] switch_core_codec.c:111 sofia/internal/501@198.50.194.89 Original read codec set to opus:116
3133f78a-48e9-11ea-affa-87c9172e3dc8 2020-02-06 18:01:37.631217 [DEBUG] switch_core_media.c:3481 Save audio Candidate cid: 1 proto: udp type: host addr: x.x.x.x:55901
3133f78a-48e9-11ea-affa-87c9172e3dc8 2020-02-06 18:01:37.631217 [DEBUG] switch_core_media.c:3481 Save audio Candidate cid: 2 proto: udp type: host addr: x.x.x.x:55902
3133f78a-48e9-11ea-affa-87c9172e3dc8 2020-02-06 18:01:37.631217 [DEBUG] switch_core_media.c:3523 Searching for rtp candidate.
3133f78a-48e9-11ea-affa-87c9172e3dc8 2020-02-06 18:01:37.631217 [DEBUG] switch_core_media.c:3523 Searching for rtcp candidate.
3133f78a-48e9-11ea-affa-87c9172e3dc8 2020-02-06 18:01:37.631217 [DEBUG] switch_core_media.c:3567 sofia/internal/501@198.50.194.89 no suitable candidates found.
这种解决思路如下,一般是如果能调整a路invite的语音编码,调整编码就可以解决 如果不能,看下是否可以调整编码早协商为晚协商,再不行就设置支持编码转码即可 profile增加如下参数
<param name="inbound-late-negotiation" value="false"/>
<param name="inbound-zrtp-passthru" value="false"/>
<param name="disable-transcoding" value="false"/>
FreeSwitch 1.6+以上系统 增加这一行,在profile 结尾
X-PRE-PROCESS cmd="set" data="media_mix_inbound_outbound_codecs=true"/> <
分析信令invite和183 所携带的信息完全一致,只是小于96标准codec序号,没有a行描述字段。 invite sdp信息
v=0
o=ZhongTou 1681950938 1681950939 IN IP4 10.210.215.136
s=ZhongTou
c=IN IP4 10.210.215.136
t=0 0
m=audio 8058 RTP/AVP 8 101
a=rtpmap:8 PCMA/8000
a=rtpmap:101 telephone-event/8000
a=fmtp:101 0-15
a=ptime:20
183 sdp信息
v=0
o=- 1681958996 1681958996 IN IP4 10.210.0.5
s=SBC call
c=IN IP4 10.210.0.5
t=0 0
m=audio 50722 RTP/AVP 8 101
a=rtpmap:101 telephone-event/8000
a=fmtp:101 0-15
a=content:g.3gpp.cat
a=sendrecv
freeswtich收到183信息后,返回了 488 Not Acceptable Here。 查询 SIP协议中 对于codec编码8 是默认PCMA编码,所有小于96的序号 都是协议规定的编码类型,因此不严格校验这个编码描述,是可以兼容的。
freeswitch本身也提供了解决办法,在profile里面增加配置这个参数‘NDLB-allow-bad-iananam’ 为true,即可兼容这种场景。
param name="NDLB-allow-bad-iananame" value="true"/> <
在对接ims遇到对于sdp的其他参数不兼容也会导致488错误,例如sdp里fmtp参数。
这个问题在用wireshark
分析后 invite 也响应了200
ok,从消息比较来看,codec是完全兼容没有问题的,差异点就是fmtp。
用于DTMF数字信号、电话音和电话信号的RTP负载格式,数字表示当前所在设备具有的一种能力。
invite sdp
v=0
o=- 46271 46271 IN IP4 127.0.0.1
s=VOS3000
c=IN IP4 127.0.0.1
t=0 0
m=audio 10000 RTP/AVP 8 101
a=rtpmap:8 PCMA/8000
a=rtpmap:101 telephone-event/8000
a=fmtp:101 0-16
a=sendrecv
183响应
v=0
o=sip-01.06.01.09 536047122 536047123 IN IP4 140.206.187.98
s=-
c=IN IP4 140.206.187.98
t=0 0
m=audio 9736 RTP/AVP 8 101
a=rtpmap:8 PCMA/8000
a=rtpmap:101 telephone-event/8000
a=fmtp:101 0-16
a=ptime:20
紧接着收到被叫的update消息
v=0
o=- 46271 46272 IN IP4 116.196.119.131
s=VOS3000
c=IN IP4 116.196.119.131
t=0 0
m=audio 61192 RTP/AVP 8 101
a=rtpmap:8 PCMA/8000
a=rtpmap:101 telephone-event/8000
a=fmtp:101 0-15
a=sendrecv
如果发起方和接受方fmtp的能力,服务器也没有转换兼容的能力,这种只能参考https://blog.csdn.net/yangmingm/article/details/106077948,修复freeswitch源码统一不具备处理。
有一次,一个新对接的客户反馈软电话根本打不通,然后截图过来发现是488错误,检查以上codec协商场景都不存在 查看fs日志,发现挂断前的日志如下:
2022-03-24 14:50:48.663204 [DEBUG] switch_core_codec.c:111 sofia/internal/075512345678@webrtc Original read codec set to PCMA:8
2022-03-24 14:50:48.663204 [DEBUG] switch_core_media.c:3481 Save audio Candidate cid: 1 proto: udp type: host addr: 192.167.10.207:55231
2022-03-24 14:50:48.663204 [DEBUG] switch_core_media.c:3523 Searching for rtp candidate.
2022-03-24 14:50:48.663204 [DEBUG] switch_core_media.c:3523 Searching for rtcp candidate.
2022-03-24 14:50:48.663204 [DEBUG] switch_core_media.c:3567 sofia/internal/075512345678@webrtc no suitable candidates found.
...
a=candidate:3284465256 1 udp 2122260223 192.167.10.207 55231 typ host generation 0 network-id 1
a=candidate:2370243224 1 tcp 1518280447 192.167.10.207 9 typ host tcptype active generation 0 network-id 1
...
2022-03-24 14:50:48.663204 [NOTICE] switch_channel.c:3515 Hangup sofia/internal/075512345678@webrtc [CS_EXECUTE] [INCOMPATIBLE_DESTINATION]
2022-03-24 14:50:48.663204 [DEBUG] switch_ivr_originate.c:3848 Originate Resulted in Error Cause: 88 [INCOMPATIBLE_DESTINATION]
从日志中,可以看到在媒体协商的过程,有一个“no suitable candidates found”的信息。意思是webrtc中的ice框架没有找到合适的可选媒体地址。 同时,SDP中又有“a=candidate: udp 192.167.10.207 55231”的信息。 日志看起来比较奇怪,明明打印出来的有candidate信息,为什么又说找不到合适的candidate。 我们尝试百度了一下“192.167.10.207”这个地址,居然是属于意大利的IP,是一个公网地址。 经过和客户沟通,客户侧反馈信息是“192.167.10.207”是公司的内网地址。。。网管是个人才。
打开conf/sip_profile/internal.xml配置文件,查找“candidate”,看到如下配置:
param name="apply-candidate-acl" value="rfc1918.auto"/> <
这个配置的意思是,对ice框架中candidate可选地址设置acl规则,对不符合rfc1918规范的IP地址进行拦截。 Rfc1918规定的地址段如下,一般情况下,内网地址都要按照这3个网段来配置:
10.0.0.0 - 10.255.255.255 (10/8 prefix)
172.16.0.0 - 172.31.255.255 (172.16/12 prefix)
192.168.0.0 - 192.168.255.255 (192.168/16 prefix)
问题就出在这里,fs对candidate设置了acl规则为rfc1918,客户配置的candicate又只有192.167的一个公网地址,造成了没有可选的媒体地址的问题
解决方案
首先,客户修改本地地址是最简单的解决方式,只需要把192.167的内网地址修改为192.168网段即可。
但是回到fs服务器本身来看,如果有客户通过公网地址对接,即candidate无法获取到内网地址,还是会有上述的问题存在。
最终,从fs服务端出发的解决方案。
方案1,修改 internal.xml,增加candidate的acl规则,让公网地址也可以通过可选规则。
param name="apply-candidate-acl" value="rfc1918.auto"/>
<
param name="apply-candidate-acl" value="wan.auto"/> <
这样,无论客户的candidate中只有公网地址,还是只有私网地址,fs服务端都可以正常的建立媒体。
方案2,从acl自定义规则出发,设置candidate的acl规则为允许所有。
修改 acl.conf.xml
list name="ice_candidate" default="allow">
<
list> </
修改 internal.xml
param name="apply-candidate-acl" value="ice_candidate"/> <
但是,该方案在实际测试过程中是有问题的,会造成公网和私网地址都无法通过candidate的acl规则,详细原因还未展开,留待后续跟踪
浏览器报错:DOMException: Failed to execute ‘setRemoteDescription’ on ‘RTCPeerConnection’: Failed to set remote offer sdp: SDES and DTLS-SRTP cannot be enabled at the same time. 原因:我们需要禁用 SDES 并且只使用 DTLS a=crypto 和 a=fingleprint 不能一起用 解决方案:在opensips脚本处理rtpengine分配媒体端口时,增加rtpengine_manage(“SDES-off trust-address replace-origin replace-session-connection ICE=force”); 打开SDES-off参数。
488问题无法完全解决,只能尽量减少,根本原因还是运营商侧的设备互通,比如呼叫转移,运营商IMS设备经常在183响应中支持a路编码协商,然后又转发了其他设备的update更新编码请求,从而导致响应488 协商不通过。