1、调试与排错
uuid_debug_media 可以调试媒体流。
直接使用 originate 去调试会阻塞命令行,另开一个 fs_cli 然后 uuid_kill 掉这个channel才能终止。而使用bgapi去调用originate则会另开一个线程,就不会阻塞了。
还可以在fs_cli里直接打开抓包,看sip包:
freeswitch> sofia profile internal siptrace on
freeswitch> sofia profile external siptrace on
也可以全局开关抓包
freeswitch> sofia global siptrace on/off
还可以开底层日志
freeswitch> sofia loglevel all 9
或者可以开某一类型的日志
sofia loglevel <all|default|tport|iptsec|nea|nta|nth_client|nth_server|n ua|soa| sresolv|stun> [0-9]
2、抓包
- tcpdump
可以指定端口、网卡、输出格式之类的,并且可以保存在文件里。它支持使用 用户的ip地址过滤,用户的ip可以用sofia staus查出来。
图1 sofia staus查看用户ip
也可以抓取所有RTP包来进行分析,因为RTP包是有端口范围(16384~32768)的,所以根据端口范围tcpdump即可。
- tshark
跟wirshark差不多,与tcpdump比较起来,tshark能“认识”更多的协议
- ngrep
从抓包结果中可以很清楚地看出数据包的传输方向以及SIP协议的具体内容。
- pcapsipdump
它能将不同通话IP包存到不同的文件里,其中某一路通话所有的SIP和
RTP数据都存到同一个文件中。这样在同时有大量通话的时候抓包分析
比较有用。
3、使用Wireshark抓包并分析呼叫
当然,除了它有一个比较好的图形界面外,它更强大的功能是能识别主流的各种通
信协议,因而可以很方便地分析协议的内容,它可以按照协议过滤包。
具有VoIP通话过滤工具
图2 根据VoIP组合过滤包
点击“流序列”可以看到SIP呼叫流程
图3 wireshark展示 SIP呼叫流程
也可以用于分析RTP包
图4 wireshark分析 RTP包
除此之外,还可以使用Graph按钮生成某一路流相关的统计图,如果图表显示比较规律,那一般说明是比较好的,如果生成的图表不是很规律,那就说明可能是网络上有丢包、延迟或抖动等。
还可以编写过滤条件,如:ip.src == 192.168.1.127 && ip.dst == 192.168.1.143 && udp.port == 5060
4、originate命令实例解
originate命令用于从FreeSWITCH中向外发起一个呼叫,这个“外”就是用这里的呼叫字符串指定的。
- fs 可以同时拨打 两通电话
freeswitch> originate user/1000,user/1001 &echo
- 也可以 一通 呼不通,就打第二通:
freeswitch> originate user/1000|user/1001 &echo
- orginate后面可以接路由,路由走 dialplan,比如这个例子就是走了9196的路由。
freeswitch> originate user/1000 9196
- 可以指定 inline模式
freeswitch> originate user/1000 echo inline
- 对于xml格式的dialplan 可以指定context
freeswitch> originate user/1000 1001 XML public
- originate可以指定主叫号码:
freeswitch> originate user/1000 &echo XML default 'Seven Du' 7777
这样会更改From字段和Remote-Party-ID字段
图5 originate更改主叫号码
- 可以设置超时时间,这个超时不是指对方不接听的超时,而是对方不回复100 Trying的超时时间,一般 表示 ip地址不可达。
freeswitch> originate sofia/internal/1000@192.168.100.100 &echo XML default 'Seven Du' 7777 10
在 FreeSWITCH发出INVITE消息后,由于没有收到100 Trying回复,于是 在1秒后重发INVITE消息,如果还收不到则于2秒、4秒后重发,由 于我们指定了10秒超时,因此该呼叫于10秒后失败,返回NO_ANSWER。
默认的originate命令是阻塞的,如果执行上述命令,则无法输入其 他命令或取消该呼叫。一般用bgapi避免阻塞。
- originate呼叫参数里 允许设置通道变量,注意逗号什么的要转义。 其中,“^^”后面跟冒号表示以后要用冒号代替逗号(真是奇怪的替代方式)
freeswitch> originate {origination_caller_id_name='Seven Du', originatioin_caller_id_number=7777}user/1000 &echo
freeswitch> originate {absolute_codec_string=G729\,PCMU}user/1000 &echo
freeswitch> originate {absolute_codec_string=^^:G729:PCMU'}user/1000 &echo
也可以把不同的通道变量用大括号分开写:
freeswitch> originate {var1=1}{var=2}{var3=3}user/1000 &echo
- 还可以写单腿的局部通道变量,只作用于一个腿
freeswitch> originate {var1=1}[leg_timeout=10]user/1000| [leg_timeout=20]sofia/gateway/gw1/1380000000| [leg_timeout=20]sofia/gateway/gw2/1380000000
- 振铃或者彩铃被称为 early media,一般对方返回这个 就可以认为originate成功
originate命令是在收到媒体指示就返回的(而非接听才返回),如收到SIP中的 183或200消息,可以配置成originate时忽略early media,以保证用户真的接听了才往下一步走。
freeswitch> originate {ignore_early_media=true}sofia/gateway/gw/13800000000 &playback(/tmp/test.wav)
- bridge的底层其实跟originate是同一个函数,区别只是在于参数不同,bridge多传了一个现存session的参数。
在bridge的时候,如果b leg返回 180,而a leg已经接听,变成answered状态,就不能再给a leg发 ringing让他听回铃音乐了。如果b leg发的是183,则可以把媒体流直接给a 不会有问题。为了解决这个问题 可以 在bridge之前设置一 个transfer_ringback变量
freeswitch> originate {transfer_ringback=local_stream://moh}user/1000 &bridge(user/1001)
这时a-leg接听后,如果b-leg振铃,a-leg将能听到假的回铃音。 这里假的回铃音是在收到b-leg的180时开始播放的。
还有个参数(instant_ringback)可以不用等b返回 ringing,只要a接通 就能听见回铃音乐
freeswitch> originate {instant_ringback=true} {transfer_ringback=local_stream://moh}user/1000 &bridge(user/1001)
以上的参数(transfer_ringback,instant_ringback)都是用在a-leg已经接听的情况,即回呼的情况
- bridge中的主叫号码
如果要在freeswitch呼叫a leg的时候,更改a 看见的主叫号码,可以这样
freeswitch> originate {origination_caller_id_number=7777}user/1000 &echo
a 接听了之后,再回呼b的时候,会进行主叫号码翻转,b看见的主叫号码仍然是真实的a的号码 1000
freeswitch> originate {originattion_caller_id_number=7777}user/1000 &bridge(user/1001)
执行之后,能看见日志
[INFO] switch_channel.c:2978 sofia/internal/sip:1000@192.168.1.127:47294 Flipping CID from "" <7777> to "Outbound Call" <1000>
意味着呼叫b的时候主叫号码从7777变成了1000。
如果要更改b看到的主叫号码(这里不会更改a看到的主叫号码)可以这样,因为bridge的本质仍然是originate,所以其实和 更改a看见的主叫号码方式一样。
freeswitch> originate user/1000 &bridge({origination_caller_id_number=8888}user/1001)
如果不想更改b腿上的 通道变量,也可以通过更改a腿上的 通道变量来影响b腿的显示
freeswitch> originate {effective_caller_id_number=8888}user/1000 &bridge(user/1001)
结论:
总之effective_caller_id_number变量设置在a-leg上,但影响bleg的主叫号码显示(俗称来电显示);
origination_caller_id_number可以设置到a-leg,也可以设置到bleg上,它将影响本leg的来电显示。
5、呼叫是怎么工作的
主叫先发100 INVITE到freeswitch的5060内部端口,internal会回复100表示收到,然后是鉴权阶段,鉴权阶段会查找用户,校验密码。
然后电话到路由阶段,开始查找dialplan,根据用户的context(user_context字段)开始查找对应的dialplan。然后会找到 被叫用户,获取他的注册地址(使用 sofia_contact这个API 获取)。
找到被叫用户之后,freeswitch会给被叫用户发INVITE请求,如果被叫用户摘机,则给freeswitch发 200ok,freeswitch再给主叫发200ok,通话开始。
这里注意在5080端口的通话都没有鉴权步骤。
而路由的context来源于external.xml里的配置。
<param name="context" value="public"/>
如果是已经注册,有鉴权步骤的用户,那么以用户指定的context为准,如果没有鉴权步骤,freeswitch就不会去找注册用户,则以external.xml里配置的context为准。
值得一提的是,对于没有经过鉴权的呼叫,同样可以有主、被叫 号码,只不过主叫号码是不可信的,对方可以指定显示任意号码。
6、FreeSWITCH图形用户界面简介
freeswitch有一些 图形化模块,可以使用 load xxx来进行加载。
可以看到一些信息,比如:
·Users:显示所有用户。
·Calls:显示当前的呼叫状态,如果选中“Auto Update”复选 框,则表示它是实时更新的。
·Channels:显示当前所有Channel的状态,它是实时更新的。
·Show:调用系统的show命令显示很多FreeSWITCH内部的东西, 如注册信息、已加载的模块、App、API等。