You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Asterisk AMI Originate如何为第一通话支路设置hangup_handler?

问题描述

我们的软件通过Asterisk AMI Originate发起外呼,成功接通第一通话支路(外线)后,会通过拨号计划(dialplan)呼叫第二通话支路(内线)并处理挂断逻辑。目前我们是通过AMI捕获第一通话支路/通道的Hangup Event(比如遇忙、无应答等未接通场景),想知道能不能在AMI Originate中直接为第一通道设置挂断处理器(hangup_handler),类似Asterisk Application Originate的b选项。

补充说明:我已经通过Local通道实现了这个功能,但流程比较复杂,有没有更简便的实现方式?

相关命令示例

channel originate Local/0123456789@to_caller extension ivm_100@process_ivm

现有Dialplan配置

[to_caller]
exten => _X.,1,Log(VERBOSE,OUTGOING CALL)
same => n,NoCDR()
; 注意变量继承
; 可在此设置统一变量
same => n,Set(CALLERID(num)=0123456789) 
same => n,Set(CALLERID(name)=${CALLERID(num)})
same => n,Set(__clrCID=${CALLERID(num)})
; 测试结束
same => n,Dial(SIP/${EXTEN},30,b(set_hangup_handler,s,1)U(remove_hangup_handler,s,1)))

[set_hangup_handler]
exten => s,1,Set(CHANNEL(hangup_handler_push)=to_caller_hangup_handler,s,1)
; 在新通道中测试变量
same => n,NoOp(clrCID: ${clrCID})
; 需为新通道设置主叫ID
same => n,Set(CALLERID(num)=${clrCID})
same => n,Set(CALLERID(name)=${CALLERID(num)})
; 测试结束
same => n,Return()

[remove_hangup_handler]
exten => s,1,NoOp(Remove hangup_handler)
same => n,Set(CHANNEL(hangup_handler_pop)=)
same => n,Set(MASTER_CHANNEL(clrFCH)=${CHANNEL(name)})
same => n,Return()

[to_caller_hangup_handler]
exten => s,1,NoOp(TO_CALLER_HANGUP_HANDLER First Call Leg)
same => n,NoOp(Data: CHANNEL: ${CHANNEL}, SIP Cause - ${HANGUPCAUSE}, Technology Cause Code "${HANGUPCAUSE(${CHANNEL},tech)}", Asterisk Cause Code "${HANGUPCAUSE(${CHANNEL},ast)}")
same => n,Return()

[process_ivm]
exten => _ivm.,1,NoOp(Process dialplan IVM)
same => n,NoCDR()
same => n,ChannelRedirect(${clrFCH},ivms,${EXTEN},1) ; 将Local通道重定向至真实通道
same => n,Hangup() ; 挂断Local通道

exten => h,1,NoOp(Hangup Local channel)

[ivms]
; 此处为DIALSTATUS为ANSWER时的主逻辑

解答

核心结论

AMI Originate本身不支持直接通过参数设置hangup_handler(类似Application Originate的b选项),但有两种更简便的替代方案,无需复杂的Local通道嵌套:


方案1:通过AMI传递变量,在Dialplan中自动挂载hangup_handler

发起AMI Originate时,用Variable参数传递标记变量,在目标拨号计划的首条逻辑中直接为通道挂载挂断处理器:

  1. AMI命令示例:
Action: Originate
Channel: SIP/0123456789
Context: direct_outbound
Exten: s
Priority: 1
Variable: NEED_HANGUP_HANDLER=1
CallerID: 0123456789
Timeout: 30
  1. 对应Dialplan配置:
[direct_outbound]
exten => s,1,Log(VERBOSE,OUTGOING CALL)
same => n,NoCDR()
same => n,Set(CALLERID(num)=0123456789)
same => n,Set(CALLERID(name)=${CALLERID(num)})
; 条件挂载hangup_handler
same => n,GosubIf($["${NEED_HANGUP_HANDLER}" = "1"]?set_hangup_handler,s,1)
same => n,Dial(SIP/${EXTEN},30)

[set_hangup_handler]
exten => s,1,Set(CHANNEL(hangup_handler_push)=to_caller_hangup_handler,s,1)
same => n,Return()

[to_caller_hangup_handler]
exten => s,1,NoOp(处理第一支路挂断逻辑:CHANNEL=${CHANNEL}, 挂断原因=${HANGUPCAUSE})
; 在此添加你的业务处理逻辑(如通知业务系统、记录详细日志等)
same => n,Return()

方案2:使用全局通道钩子(Global Hangup Handlers)

如果所有外呼通道都需要统一的挂断处理逻辑,可设置全局hangup_handler,避免重复配置:

  1. 在extensions.conf中添加全局配置:
[globals]
; 全局挂载挂断处理器
CHANNEL(hangup_handler_push)=global_hangup_handler,s,1

[global_hangup_handler]
exten => s,1,NoOp(全局挂断处理:CHANNEL=${CHANNEL}, 主叫=${CALLERID(num)}, 挂断原因=${HANGUPCAUSE})
; 过滤第一支路逻辑(通过通道变量标记外呼主通道)
same => n,GosubIf($["${CALL_TYPE}" = "OUTBOUND_PRIMARY"]?handle_outbound_hangup,s,1)
same => n,Return()

[handle_outbound_hangup]
exten => s,1,NoOp(处理外呼第一支路挂断)
; 在此添加你的业务逻辑
same => n,Return()
  1. 发起AMI Originate时传递标记变量:
Action: Originate
Channel: SIP/0123456789
Context: direct_outbound
Exten: s
Priority: 1
Variable: CALL_TYPE=OUTBOUND_PRIMARY
CallerID: 0123456789
Timeout: 30

方案优势

  • 无需额外Local通道中转,减少通道层级和变量传递复杂度
  • 直接在目标通道挂载处理器,避免ChannelRedirect等跳转逻辑
  • 逻辑直观,便于维护和调试

内容的提问来源于stack exchange,提问作者Artem Vyshniakov

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 18:14:54