我正在使用Starpy和Twisted为Asterisk IVR实现开发FastAgi应用程序。到目前为止,当应用程序只有一个电话时,它运行得很好。
建立第二个呼叫后,Asterisk的所有连续响应都被发送到第二个调用:属于第二个通话中听到的第一个呼叫的流音频,Hangup()断开第二个电话(第一个电话保持连接,直到手动断开与软电话的连接)
我使用的是带有Elastix发行版的X-lite软电话。我的FastAgi服务器在Windows笔记本电脑上。在Extension_custom.conf上,我有以下条目来路由调用:
extent=>2000,1,AGI(agi://10.0.0.7:4573)extent=>2000,n,朝鲜文()
这就是在服务器上设置协议的方式:
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中)和一台物理机。同样的事情。在和安卓手机上安装了不同的软电话。同样的事情。使用了物理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()
感谢提供完整信息:
现在,您所拥有的设置的明显缺陷如下:Dialplan()在最初传递给FastAGIFactory时初始化。从那时起,你总是一遍又一遍地访问类的同一个实例。现在,每当Dialplan().__call__()
方法中出现新调用,并且Dialplan().agi
参数被上一次调用覆盖时。看看你使用的样本,我建议尝试以下方法,然后从中提取:
#! /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,application, agi ):
self.application = application
self.agi = agi
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!"""
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.application.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(),
)
class CallCounterApplication(object):
def __init__( self ):
self.count = 0
def __call__(self,agi):
self.count = self.count+1
dp = Dialplan(self,agi)
return dp.start()
if __name__ == "__main__":
logging.basicConfig()
fastagi.log.setLevel( logging.DEBUG )
f = fastagi.FastAGIFactory(CallCounterApplication())
reactor.listenTCP(4573, f, 50, '10.0.0.167') # only binding on local interface
reactor.run()
我在这里所做的是创建一个应用程序容器,它将在每次成功调用时创建一个新的Dialplan()实例。
编辑:请注意,由于我没有可用的星号框,这没有经过测试,并且可能在1:1复制粘贴时无法运行。但是原理仍然是相同的