我正在使用 Starpy 和 Twisted 为 Asterisk IVR 实现开发一个 FastAgi 应用程序。到目前为止,该应用程序在只有一个电话呼叫时运行良好。
在建立第二个呼叫后,来自 Asterisk 的所有连续响应都将发送到第二个呼叫:属于第一个呼叫的流音频在第二个呼叫中听到,Hangup() 断开第二个呼叫(第一个保持连接直到手动断开与软电话的连接)
我正在使用带有 Elastix 发行版的 X-lite 软件电话。我的 FastAgi 服务器在 Windows 笔记本电脑上。在 Extensions_custom.conf 我有这些条目来路由呼叫:
扩展 => 2000,1,AGI(agi://10.0.0.7:4573) 扩展 => 2000,n,Hangup()
这是在服务器上设置协议的方式:
logging.basicConfig()
fastagi.log.setLevel( logging.DEBUG )
f = fastagi.FastAGIFactory(MyIVRApplication())
reactor.listenTCP(4573, f, 50, '10.0.0.167')
reactor.run()
我使用 starpy 提供的示例之一构建了我的应用程序,即 DialPlan() 应用程序,它只播放应用程序被访问的次数。即使那个应用程序在运行而不是我的应用程序时也有同样的问题,只能正确处理一个调用。
我使用的是无线网络,但使用电缆时也会发生同样的情况。我尝试了带有星号的虚拟机(在 virtualbox 中)和物理机。一样。在 Android 手机上安装了不同的软件电话。一样。使用物理IP电话。一样。我唯一还没有尝试过的是将我的 FastAgi 服务器移动到 linux 机器上,而不是使用我的 windows 笔记本电脑。
任何帮助将不胜感激。
提前致谢。
赫克托
编辑:
我正在从 Asterisk 添加 AGI 调试日志。如您所见,在第二个呼叫建立后,所有的 Tx 和 Rx 命令都从第二个通道发送/接收。Asterisk 不再与保持连接的第一个通道对话。
== Using SIP RTP TOS bits 184
== Using SIP RTP CoS mark 5
-- Executing [2000@from-internal:1] AGI("SIP/4001-00000006", "agi://10.0.0.167") in new stack
AGI Tx >> agi_network: yes
<SIP/4001-00000006>AGI Tx >> agi_request: agi://10.0.0.167
<SIP/4001-00000006>AGI Tx >> agi_channel: SIP/4001-00000006
<SIP/4001-00000006>AGI Tx >> agi_language: en
<SIP/4001-00000006>AGI Tx >> agi_type: SIP
<SIP/4001-00000006>AGI Tx >> agi_uniqueid: 1360854557.6
<SIP/4001-00000006>AGI Tx >> agi_version: 1.8.11.0
<SIP/4001-00000006>AGI Tx >> agi_callerid: 4001
<SIP/4001-00000006>AGI Tx >> agi_calleridname: device
<SIP/4001-00000006>AGI Tx >> agi_callingpres: 0
<SIP/4001-00000006>AGI Tx >> agi_callingani2: 0
<SIP/4001-00000006>AGI Tx >> agi_callington: 0
<SIP/4001-00000006>AGI Tx >> agi_callingtns: 0
<SIP/4001-00000006>AGI Tx >> agi_dnid: 2000
<SIP/4001-00000006>AGI Tx >> agi_rdnis: unknown
<SIP/4001-00000006>AGI Tx >> agi_context: from-internal
<SIP/4001-00000006>AGI Tx >> agi_extension: 2000
<SIP/4001-00000006>AGI Tx >> agi_priority: 1
<SIP/4001-00000006>AGI Tx >> agi_enhanced: 0.0
<SIP/4001-00000006>AGI Tx >> agi_accountcode:
<SIP/4001-00000006>AGI Tx >> agi_threadid: -1219851376
<SIP/4001-00000006>AGI Tx >>
<SIP/4001-00000006>AGI Rx << ANSWER
<SIP/4001-00000006>AGI Tx >> 200 result=0
<SIP/4001-00000006>AGI Rx << STREAM FILE "custom/bienvenida" '' 0
-- Playing 'custom/bienvenida' (escape_digits='') (sample_offset 0)
<SIP/4001-00000006>AGI Tx >> 200 result=0 endpos=24402
<SIP/4001-00000006>AGI Rx << GET DATA "custom/cuando_este_listo" 5000.0 1
-- <SIP/4001-00000006> Playing 'custom/cuando_este_listo.slin' (language 'en')
<SIP/4001-00000006>AGI Tx >> 200 result=
<SIP/4001-00000006>AGI Rx << STREAM FILE "custom/14" '' 0
-- Playing 'custom/14' (escape_digits='') (sample_offset 0)
<SIP/4001-00000006>AGI Tx >> 200 result=0 endpos=7028
<SIP/4001-00000006>AGI Rx << STREAM FILE "custom/menos" '' 0
-- Playing 'custom/menos' (escape_digits='') (sample_offset 0)
<SIP/4001-00000006>AGI Tx >> 200 result=0 endpos=6762
<SIP/4001-00000006>AGI Rx << STREAM FILE "custom/9" '' 0
-- Playing 'custom/9' (escape_digits='') (sample_offset 0)
<SIP/4001-00000006>AGI Tx >> 200 result=0 endpos=5666
<SIP/4001-00000006>AGI Rx << GET DATA "" 5000.0 2
== Using SIP RTP TOS bits 184
== Using SIP RTP CoS mark 5
-- Executing [2000@from-internal:1] AGI("SIP/4002-00000007", "agi://10.0.0.167") in new stack
AGI Tx >> agi_network: yes
<SIP/4002-00000007>AGI Tx >> agi_request: agi://10.0.0.167
<SIP/4002-00000007>AGI Tx >> agi_channel: SIP/4002-00000007
<SIP/4002-00000007>AGI Tx >> agi_language: en
<SIP/4002-00000007>AGI Tx >> agi_type: SIP
<SIP/4002-00000007>AGI Tx >> agi_uniqueid: 1360854568.7
<SIP/4002-00000007>AGI Tx >> agi_version: 1.8.11.0
<SIP/4002-00000007>AGI Tx >> agi_callerid: 4002
<SIP/4002-00000007>AGI Tx >> agi_calleridname: device
<SIP/4002-00000007>AGI Tx >> agi_callingpres: 0
<SIP/4002-00000007>AGI Tx >> agi_callingani2: 0
<SIP/4002-00000007>AGI Tx >> agi_callington: 0
<SIP/4002-00000007>AGI Tx >> agi_callingtns: 0
<SIP/4002-00000007>AGI Tx >> agi_dnid: 2000
<SIP/4002-00000007>AGI Tx >> agi_rdnis: unknown
<SIP/4002-00000007>AGI Tx >> agi_context: from-internal
<SIP/4002-00000007>AGI Tx >> agi_extension: 2000
<SIP/4002-00000007>AGI Tx >> agi_priority: 1
<SIP/4002-00000007>AGI Tx >> agi_enhanced: 0.0
<SIP/4002-00000007>AGI Tx >> agi_accountcode:
<SIP/4002-00000007>AGI Tx >> agi_threadid: -1220097136
<SIP/4002-00000007>AGI Tx >>
<SIP/4002-00000007>AGI Rx << ANSWER
<SIP/4002-00000007>AGI Tx >> 200 result=0
<SIP/4002-00000007>AGI Rx << STREAM FILE "custom/bienvenida" '' 0
-- Playing 'custom/bienvenida' (escape_digits='') (sample_offset 0)
<SIP/4001-00000006>AGI Tx >> 200 result= (timeout)
<SIP/4002-00000007>AGI Rx << STREAM FILE "custom/respuesta_incorrecta" '' 0
-- Playing 'custom/respuesta_incorrecta' (escape_digits='') (sample_offset 0)
<SIP/4002-00000007>AGI Tx >> 200 result=0 endpos=14260
<SIP/4002-00000007>AGI Rx << GET DATA "custom/cuando_este_listo" 5000.0 1
-- <SIP/4002-00000007> Playing 'custom/cuando_este_listo.slin' (language 'en')
<SIP/4002-00000007>AGI Tx >> 200 result=
-- <SIP/4002-00000007>AGI Script agi://10.0.0.167 completed, returning 0
<SIP/4002-00000007>AGI Tx >> HANGUP
-- Executing [2000@from-internal:2] Hangup("SIP/4002-00000007", "") in new stack
== Spawn extension (from-internal, 2000, 2) exited non-zero on 'SIP/4002-00000007'
-- Executing [h@from-internal:1] Macro("SIP/4002-00000007", "hangupcall") in new stack
-- Executing [s@macro-hangupcall:1] GotoIf("SIP/4002-00000007", "1?endmixmoncheck") in new stack
-- Goto (macro-hangupcall,s,9)
-- Executing [s@macro-hangupcall:9] NoOp("SIP/4002-00000007", "End of MIXMON check") in new stack
-- Executing [s@macro-hangupcall:10] GotoIf("SIP/4002-00000007", "1?nomeetmemon") in new stack
-- Goto (macro-hangupcall,s,15)
-- Executing [s@macro-hangupcall:15] NoOp("SIP/4002-00000007", "MEETME_RECORDINGFILE=") in new stack
-- Executing [s@macro-hangupcall:16] GotoIf("SIP/4002-00000007", "1?noautomon") in new stack
-- Goto (macro-hangupcall,s,18)
-- Executing [s@macro-hangupcall:18] NoOp("SIP/4002-00000007", "TOUCH_MONITOR_OUTPUT=") in new stack
-- Executing [s@macro-hangupcall:19] GotoIf("SIP/4002-00000007", "1?noautomon2") in new stack
-- Goto (macro-hangupcall,s,25)
-- Executing [s@macro-hangupcall:25] NoOp("SIP/4002-00000007", "MONITOR_FILENAME=") in new stack
-- Executing [s@macro-hangupcall:26] GotoIf("SIP/4002-00000007", "1?skiprg") in new stack
-- Goto (macro-hangupcall,s,29)
-- Executing [s@macro-hangupcall:29] GotoIf("SIP/4002-00000007", "1?skipblkvm") in new stack
-- Goto (macro-hangupcall,s,32)
-- Executing [s@macro-hangupcall:32] GotoIf("SIP/4002-00000007", "1?theend") in new stack
-- Goto (macro-hangupcall,s,34)
-- Executing [s@macro-hangupcall:34] Hangup("SIP/4002-00000007", "") in new stack
== Spawn extension (macro-hangupcall, s, 34) exited non-zero on 'SIP/4002-00000007' in macro 'hangupcall'
== Spawn extension (from-internal, h, 1) exited non-zero on 'SIP/4002-00000007'
localhost*CLI>
编辑:
这是我用作指南的代码。它是 Starpy 库中作为示例提供的应用程序。当我把这个应用程序我得到相同的结果。我放这个是因为我的有点太大了。
#! /usr/bin/env python
"""Read digits from the user in various ways..."""
from twisted.internet import reactor, defer
from starpy import fastagi, error
import logging, time
log = logging.getLogger( 'hellofastagi' )
class DialPlan( object ):
"""Stupid little application to report how many times it's been accessed"""
def __init__( self ):
self.count = 0
def __call__( self, agi ):
"""Store the AGI instance for later usage, kick off our operations"""
self.agi = agi
return self.start()
def start( self ):
"""Begin the dial-plan-like operations"""
return self.agi.answer().addCallbacks( self.onAnswered, self.answerFailure )
def answerFailure( self, reason ):
"""Deal with a failure to answer"""
log.warn(
"""Unable to answer channel %r: %s""",
self.agi.variables['agi_channel'], reason.getTraceback(),
)
self.agi.finish()
def onAnswered( self, resultLine ):
"""We've managed to answer the channel, yay!"""
self.count += 1
return self.agi.wait( 2.0 ).addCallback( self.onWaited )
def onWaited( self, result ):
"""We've finished waiting, tell the user the number"""
return self.agi.sayNumber( self.count, '*' ).addErrback(
self.onNumberFailed,
).addCallbacks(
self.onFinished, self.onFinished,
)
def onFinished( self, resultLine ):
"""We said the number correctly, hang up on the user"""
return self.agi.finish()
def onNumberFailed( self, reason ):
"""We were unable to read the number to the user"""
log.warn(
"""Unable to read number to user on channel %r: %s""",
self.agi.variables['agi_channel'], reason.getTraceback(),
)
def onHangupFailure( self, reason ):
"""Failed trying to hang up"""
log.warn(
"""Unable to hang up channel %r: %s""",
self.agi.variables['agi_channel'], reason.getTraceback(),
)
if __name__ == "__main__":
logging.basicConfig()
fastagi.log.setLevel( logging.DEBUG )
f = fastagi.FastAGIFactory(DialPlan())
reactor.listenTCP(4573, f, 50, '10.0.0.167') # only binding on local interface
reactor.run()