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参数传递标记变量,在目标拨号计划的首条逻辑中直接为通道挂载挂断处理器:
- AMI命令示例:
Action: Originate Channel: SIP/0123456789 Context: direct_outbound Exten: s Priority: 1 Variable: NEED_HANGUP_HANDLER=1 CallerID: 0123456789 Timeout: 30
- 对应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,避免重复配置:
- 在
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()
- 发起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
相关产品推荐
相关产品推荐

