Starpy Click to Call无法发起呼叫求助(使用voip.ms)
排查Starpy Click-to-Call无呼叫动作的问题
我帮你梳理几个针对Starpy + voip.ms场景下Click-to-Call无动作的排查点,都是我之前做类似功能时踩过的坑:
1. 先确认AMI连接真的有权限发起呼叫
虽然你说配置正确,但Starpy的AMI连接经常会出现「连接成功但权限不足」的隐性问题——表面上连得上,但根本没权限执行originate命令。
你可以给代码加个DEBUG级日志,同时在AMI登录成功的回调里打印权限列表,明确确认:
from starpy import manager from starpy.manager import AMIFactory from twisted.internet import reactor from twisted.web import server,resource import logging logging.basicConfig(level=logging.DEBUG) # 打开DEBUG日志,能看到AMI交互细节 log = logging.getLogger("ClickToCall") class ClickToCallResource(resource.Resource): isLeaf = True def render_GET(self, request): number = request.args.get('number', [None])[0] ext = request.args.get('ext', [None])[0] if not number or not ext: return b"Missing number or extension parameter" # 登录成功后的回调,这里才是真正发起呼叫的地方 def on_ami_login(client): log.debug(f"✅ AMI登录成功!当前权限:{client.capabilities}") # 检查有没有originate权限 if 'originate' not in client.capabilities: log.error("❌ AMI用户没有originate权限,无法发起呼叫") request.write(b"AMI user lacks originate permission.") request.finish() return # 构造呼叫命令,适配voip.ms的拨号规则 def on_call_success(result): log.debug(f"📞 呼叫发起成功:{result}") request.write(b"Call initiated successfully!") request.finish() def on_call_failed(failure): log.error(f"❌ 呼叫失败:{failure.getErrorMessage()}") request.write(b"Failed to initiate call. Check logs for details.") request.finish() # 注意:voip.ms要求呼叫外部号码时必须走正确的出站上下文 originate_cmd = manager.Originate( Channel=f"SIP/{ext}", # 先呼叫目标分机 Context="from-internal", # 这个上下文要在extensions.conf里配置指向voip.ms的出站路由 Exten=number, Priority=1, Timeout=30000, # 30秒超时 CallerID=f"ClickToCall <{ext}>" ) # 异步发送命令并绑定回调 client.sendCommand(originate_cmd).addCallbacks(on_call_success, on_call_failed) def on_ami_login_fail(failure): log.error(f"❌ AMI登录失败:{failure.getErrorMessage()}") request.write(b"Failed to connect to Asterisk AMI.") request.finish() # 初始化AMI工厂,替换成你的AMI账号密码 factory = AMIFactory(username='your_ami_username', secret='your_ami_password', host='127.0.0.1') # 连接AMI端口(默认5038) reactor.connectTCP('127.0.0.1', 5038, factory) # 绑定登录回调 factory.deferredLogin.addCallbacks(on_ami_login, on_ami_login_fail) # 因为是异步处理,返回NOT_DONE表示稍后响应 return server.NOT_DONE_YET site = server.Site(ClickToCallResource()) reactor.listenTCP(8000, site) reactor.run()
重点看日志里的「当前权限」,必须包含originate;如果登录失败,先去manager.conf里检查账号密码、permit规则(要允许127.0.0.1访问)。
2. 先在Asterisk控制台手动测试拨号规则
很多时候问题不在Starpy,而是voip.ms的拨号规则没配置对。你可以先在服务器上执行这个命令,验证Asterisk能不能正常发起呼叫:
asterisk -rx "channel originate SIP/101 extension 00593968196867@from-internal"
如果这个命令能正常发起呼叫,说明Asterisk和voip.ms的配置没问题,问题出在Starpy代码;如果不行,先去extensions.conf里检查from-internal上下文有没有正确指向voip.ms的出站路由,比如:
[from-internal] exten => _00.,1,Dial(SIP/voipms/${EXTEN}) ; 这里的voipms是你在sip.conf里配置的voip.ms trunk名称
3. 修正Twisted异步逻辑的坑
Starpy基于Twisted,异步逻辑很容易踩坑:
- 呼叫命令必须在AMI登录成功的回调里执行,不能在登录前调用
- Web请求的响应要用
request.write()和request.finish(),不能直接返回字符串(否则会阻塞reactor,导致呼叫命令没机会执行) - 一定要返回
server.NOT_DONE_YET,告诉Twisted这个请求会异步处理
4. 最后检查分机状态和防火墙
- 确认分机101已经正常注册到Asterisk(可以用
asterisk -rx "sip show peers"查看) - 确认voip.ms的SIP端口(默认5060)没有被服务器防火墙拦截
- 确认Asterisk的AMI端口5038允许localhost访问(
manager.conf里的permit=127.0.0.1/255.255.255.0)
先按这个顺序排查,尤其是手动测试Asterisk命令,能快速定位问题根源。
内容的提问来源于stack exchange,提问作者X defStack
相关产品推荐
相关产品推荐

