我在 DigitalOcean 上托管了一个 Asterisk 服务器,使用 Twilio 的中继服务后,通话在 120 秒后中断。值得注意的是,直接连接的软件电话不会中断通话。防火墙上的端口 5060 是开放的,这是理所当然的。
有一个自动接线员接收呼叫并将其传递给脚本,但使用 SIP 软件电话,它可以完全正常工作,而无需挂断呼叫。我给 Twilio 发了电子邮件,他们说问题可能是因为 Asterisk 没有发送 180 振铃,我可以理解,因为我没有拨打电话,只是立即接听。
真正切断通话的是什麽?
配置文件
[twilio]
type=peer
secret=secret
username=user
host=host.domain.com
dtmfmode=rfc2833
canreinvite=no
disallow=all
allow=ulaw
insecure=port,invite
fromuser=+15555555555
fromdomain=from-domain.domain.com
context=incoming
deny=0.0.0.0/0
permit=x.x.x.x/32
permit=x.x.x.x/32
permit=x.x.x.x/32
permit=x.x.x.x/32
extensions.ael 上下文
+15555555555 => {
Answer();
EAGI(tincan.js);
AGI(agi://127.0.0.1/saytext,"Goodbye.");
Hangup();
}
开始通话数据包捕获
21 4.827782 (Them) (Us) SIP/SDP 1341 Request: INVITE sip:[email protected] |
22 4.831487 (Us) (Them) SIP 819 Status: 100 Trying |
23 4.833205 (Us) (Them) SIP/SDP 1112 Status: 200 OK |
通话结束数据包捕获
16066 124.821787 (Them) (Us) SIP 650 Request: BYE sip:[email protected]:5060 |
16067 124.822736 (Us) (Them( SIP 700 Status: 200 OK |
答案1
Twilio 报告称,问题是由于我们的服务器长时间未发送任何 RTP 数据,因此连接超时。我使用的拨号方案运行了一个自定义 EAGI 脚本,该脚本会无限期地记录通话人。这个过程在另一端超时了。
我的解决方案如下:
- 我没有使用 RECORD FILE 命令,而是使用了 GET OPTION 命令来播放 10 秒的静音,等待井号 (#) 键。
- 我使用 EAGI stderr+1 fd 通过我的脚本手动将音频捕获到文件中。
- 我使用 STREAM FILE 命令播放录音给用户确认。
反复发送 10 秒的静音可防止服务器超时。我可以想象发送 1 秒的静音可达到相同的效果并节省带宽,但您的情况可能有所不同。
我的 Node.js 脚本函数取代了 WAIT FOR DIGIT 或 RECORD FILE 函数:
/**
* Loop playing silence until interrupted
* @param done =function( timedout ) Callback when the silence has been interrupted
* @param maxRecordTime Length of time to be able to record max. Leave blank for no timeout.
* @param stopTime Timestamp when the recording should be stopped
*/
Index.prototype.loopSilenceUntilInterrupted = function( done, maxRecordTime, stopTime ) {
var that = this;
// Set the stopTime?
if( maxRecordTime!==undefined && stopTime===undefined )
stopTime = Date.now()+maxRecordTime;
this.context.getOption( "silence/10", "#", 10, function( error, response ) {
if( response.result==35 )
done( false ); // We have been diggery
else if( stopTime!==undefined && Date.now()>=stopTime )
done( true ); // We have timed out!
else
that.loopSilenceUntilInterrupted( done, maxRecordTime, stopTime ); // Do it again
},
0 ); // No cooldown
};