1.问题描述

使用如下的命令进行呼叫:
originate user/9988001 9988002

在主叫接通后,会接着呼被叫,但是被叫振铃后,主叫没有任何回铃音。
直到被叫接听,主叫才能听到声音。

2.问题分析

180抓包如下:
呼叫命令:originate user/9988001 9988002
image.png
通过抓包可以发现,被叫开始振铃时,会回发180,但是FreeSWITCH收到180后并没有转给主叫,因为此时主叫已经处于answer状态,不可能再接收180.
所以FreeSWITCH直接就忽略了该180,直接导致的情况是主叫听不到任何回铃音。

183抓包如下:
呼叫命令:originate user/9988002 1865200306ximage.png
通过抓包可以发现,FreeSWITCH可以将183转给主叫,所以主叫在呼叫的时候,可以听到回铃音。
也就是说,FreeSWITCH在主叫已接听的情况下,转发183,不转发180。
那180的问题该如何解决呢?
尝试过在主叫方设置instant_ringback=true,还是不可以让主叫产生回铃音。猜测即使发过去,主叫方也会自动忽略掉180,因为主叫本身已经处于接听状态。

3.解决方案

目前能想到的解决办法是在被叫接听之前,手工向主叫播放回铃音。

3.1 增加lua脚本handle_ring.lua

脚本内容如下:

  1. local api=freeswitch.API();
  2. function getUUID(num)
  3. local uuid;
  4. local res=api:executeString("show channels like "..num.." as xml")
  5. if res then
  6. _,_,uuid = string.find(res,"<uuid>(.-)<%/uuid>")
  7. end
  8. return uuid;
  9. end
  10. --main function
  11. do
  12. local num = argv[1];
  13. local uuid = getUUID(num);
  14. if uuid then
  15. freeswitch.consoleLog("debug", argv[0] .. ":>>>>start to play early media to caller {" .. num .. "}\n")
  16. api:executeString("uuid_broadcast " .. uuid .. " ringback.wav aleg");
  17. api:executeString("uuid_setvar ringback_for_caller true");
  18. end
  19. end

3.2 增加脚本event.lua

该脚本用于订阅CHANNEL_ANSWER和CHANNEL_HANGUP事件,在收到该事件后,调用下面的函数取消回铃音的播放:

  1. --检查主叫通道上面是否正在播放回铃音,如果是的话,则需要停止
  2. function stopRingBackMedia(evt, isHangup)
  3. --只有被叫通道变量中含有variable_originator
  4. local callerUUID = evt:getHeader("variable_originator");
  5. if callerUUID then
  6. freeswitch.consoleLog("debug", "=====>caller uuid:" .. callerUUID .. "\n");
  7. local hasRingbackForCaller = api:executeString("uuid_getvar " .. callerUUID .. " ringback_for_caller") or "";
  8. freeswitch.consoleLog("debug", "=====>variable_ringback_for_caller:" .. hasRingbackForCaller .. "\n");
  9. if hasRingbackForCaller and string.len(hasRingbackForCaller)>0 then
  10. freeswitch.consoleLog("debug", "=====>caller has autogenerated ringback, need to stop\n");
  11. --api:executeString("uuid_break " .. callerUUID .. " all");
  12. api:executeString("uuid_fileman " .. callerUUID .. " stop");
  13. end
  14. end
  15. end

3.3 修改呼叫命令

修改后的呼叫命令如下所示:

  1. originate {nolocal:api_on_ring='lua handle_ring.lua 9988001',export_vars='nolocal:api_on_ring'}user/9988001 9988002

这里稍微解释下{}里面的用法,使用nolocal:和export_vars实现了拨号方案中export的效果,也就是说将api_on_ring属性设置到被叫通道上。
在被叫收到180后,调用handle_ring.lua脚本。

4.其他问题

4.1 若主叫设置自动接听参数sip_auto_answer会导致挂断延迟

如果是需要主叫自动接听,按照上面的思路,应该使用如下的命令:

  1. originate [sip_auto_answer='true',execute_on_originate='unset::sip_h_call-info']user/8924002 &bridge([api_on_ring='lua handle_ring.lua 8924002']user/9988002

但是会出现下面的问题,正常通话后,被叫挂断,主叫会仍处于通话中,直到二三十秒后才自动挂断。
正确呼叫命令为:

  1. originate [sip_h_call-info='<sip:192.168.4.204>;answer-after=0',execute_on_originate='unset::sip_h_call-info']user/8924002 &bridge([api_on_ring='lua handle_ring.lua 8924002']user/9988002