Twisted / Starpy FastAgi app只能正确处理一个电话

时间:2013-02-14 03:12:40

标签: python twisted asterisk fastagi

我正在使用Starpy和Twisted为Asterisk IVR实现开发FastAgi应用程序。到目前为止,只有一个电话,应用程序运行良好。

在建立第二个呼叫之后,来自Asterisk的所有连续响应都被发送到第二个呼叫:属于第二个呼叫时听到的第一个呼叫的流音频,Hangup()断开第二个呼叫(第​​一个呼叫)保持连接,直到手动断开与软电话的连接)

我正在使用带有Elastix发行版的X-lite软电话。我的FastAgi服务器在Windows笔记本电脑上。 在Extensions_custom.conf上我有这些条目来路由调用:

exten => 2000,1,AGI(AGI://10.0.0.7:4573) exten => 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()应用程序,该应用程序只播放应用程序被访问的次数。即使该应用程序在运行而不是我的应用程序时也存在同样的问题,只能正确处理一个调用。

我使用的是无线网络,但使用电缆时也会发生同样的事情。我尝试了带有星号(在虚拟机中)和物理机器的虚拟机。一样。在Android手机上安装了不同的软电话。一样。使用物理IP电话。一样。我还没有尝试过的唯一的事情是将我的FastAgi服务器移动到Linux机器而不是使用我的Windows笔记本电脑。

任何帮助将不胜感激。

提前致谢。

赫克托耳

编辑:

我正在从Asterisk添加AGI调试日志。如您所见,在建立第二个呼叫之后,从第二个信道发送/接收所有Tx和Rx命令。星号从未与第一个保持连接的频道再次通话。

== 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()

1 个答案:

答案 0 :(得分:1)

感谢您提供完整信息:

现在设置的明显缺陷如下: Dialplan()在最初传递给FastAGIFactory时启动。从那以后 - 你总是在agian上一遍又一遍地访问同一个类的实例。现在 - 只要有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复印时可能无法运行。但原则仍然相同