在asterisk执行拨号计划的业务过程当中,咱们常常会调用Hangup()这个App来结束呼叫,然而在asterisk中有多处逻辑位置能够调用Hangup(),并且调用此App后,呼叫通道还要继续执行后续的业务逻辑(好比:是否写CDR,是否调用发送短信接口等)。下面咱们就来"踩"一下拨号计划中调用Hangup()后的一些"坑"。编程
在asterisk拨号计划中,主要能够在如下几处位置调用拨号计划的Hangup() App:
1)普通的context段,包含Goto语句跳转的嵌入context段。
2)Macro()宏调用context里面。
3)Gosub()子程序的context里面。
下面来实际测试每种状况,并根据拨号计划的走向得出具体的结论。编程语言
1. 普通的context段的状况:
1.1 Hangup()调用和h分机同在一个context中的状况。
1.1.1 拨号计划脚本以下:
[from-internal]
exten => _.,1,NoOp(cid=${CALLERID(num)})
exten => _.,n,Hangup()
exten => h,1,NoCDR()
exten => h,n,Verbose(-----1----)
exten => h,n,Hangup()
1.1.2 用软电话测试执行结果以下:
dotasterisk*CLI>
== Using SIP RTP TOS bits 184
== Using SIP RTP CoS mark 5
-- Executing [8888@from-internal:1] NoOp("SIP/8001-00000025", "cid=8001") in new stack
-- Executing [8888@from-internal:2] Hangup("SIP/8001-00000025", "") in new stack
== Spawn extension (from-internal, 8888, 2) exited non-zero on 'SIP/8001-00000025'
-- Executing [h@from-internal:1] NoCDR("SIP/8001-00000025", "") in new stack
-- Executing [h@from-internal:2] Verbose("SIP/8001-00000025", "-----1----") in new stack
-----1----
-- Executing [h@from-internal:3] Hangup("SIP/8001-00000025", "") in new stack
== Spawn extension (from-internal, h, 3) exited non-zero on 'SIP/8001-00000025'
dotasterisk*CLI>
1.1.3 说明:
执行流程很简单,在当前context(8888@from-internal)上执行Hangup()后,直接调到当前context的h分机(h@from-internal),整个过程很天然,无需过多解释。函数
1.2 用Goto语句跳到下一级,并在下一级中执行Hangup()的状况:
1.2.1 拨号计划脚本以下:
[from-internal]
exten => _.,1,NoOp(cid=${CALLERID(num)})
exten => _.,n,Goto(next-context,${EXTEN},1)
exten => h,1,NoCDR()
exten => h,n,Verbose(-----1----)
exten => h,n,Hangup()测试
[next-context]
exten => _8.,1,NoOp(come here)
exten => _8.,n,Hangup()
exten => h,1,Verbose(-----2----) ;注:此处是h分机执行代码的开始
exten => h,n,Hangup()spa
1.2.2 用软电话测试执行结果以下:
dotasterisk*CLI>
== Using SIP RTP TOS bits 184
== Using SIP RTP CoS mark 5
-- Executing [8888@from-internal:1] NoOp("SIP/8001-0000002a", "cid=8001") in new stack
-- Executing [8888@from-internal:2] Goto("SIP/8001-0000002a", "next-context,8888,1") in new stack
-- Goto (next-context,8888,1)
-- Executing [8888@next-context:1] NoOp("SIP/8001-0000002a", "come here") in new stack
-- Executing [8888@next-context:2] Hangup("SIP/8001-0000002a", "") in new stack
== Spawn extension (next-context, 8888, 2) exited non-zero on 'SIP/8001-0000002a'
-- Executing [h@next-context:1] Verbose("SIP/8001-0000002a", "-----2----") in new stack //注:仅仅执行了当前context的h分机
-----2----
-- Executing [h@next-context:2] Hangup("SIP/8001-0000002a", "") in new stack
== Spawn extension (next-context, h, 2) exited non-zero on 'SIP/8001-0000002a'
dotasterisk*CLI>
1.3.3 说明:
从执行结果看,发现只输出了[h@next-context]里面的Verbose(-----2----),而没有输出上一级[from-internal]里面Hangup()以后的拨号计划。接口
结论:对于普通context段里面的Hangup() App,无论里面Goto到了多少层级别,只要在某一个context执行的Hangup(),那么就在当前这个context里面寻找h分机,若是有h分机匹配,就执行h分机里面的流程。注意,h分机的拨号计划只在此处context执行,毫不会跳出此处的context,即便是当前context中没有匹配到h分机,也仍然不会跳出此context而去寻找上一级调用Goto()语句的context里面的h分机来执行。举个例子,拨号计划是:
[from-internal]
exten => _.,1,NoOp(cid=${CALLERID(num)})
exten => _.,n,Goto(next-context,${EXTEN},1)
exten => h,1,NoCDR()
exten => h,n,Verbose(-----1----)
exten => h,n,Hangup()ci
[next-context] ;此段没有匹配h分机
exten => _8.,1,NoOp(come here)
exten => _8.,n,Hangup()
执行结果以下:
dotasterisk*CLI>
== Using SIP RTP TOS bits 184
== Using SIP RTP CoS mark 5
-- Executing [8888@from-internal:1] NoOp("SIP/8001-00000029", "cid=8001") in new stack
-- Executing [8888@from-internal:2] Goto("SIP/8001-00000029", "next-context,8888,1") in new stack
-- Goto (next-context,8888,1)
-- Executing [8888@next-context:1] NoOp("SIP/8001-00000029", "come here") in new stack
-- Executing [8888@next-context:2] Hangup("SIP/8001-00000029", "") in new stack //注:仅仅在这里就中止了,没有跳到上一层context
== Spawn extension (next-context, 8888, 2) exited non-zero on 'SIP/8001-00000029'
dotasterisk*CLI> 作用域
2. Macro()宏里面执行Hangup():
2.1 拨号计划以下:
[from-internal]
exten => _.,1,NoOp(cid=${CALLERID(num)})
exten => _.,n,Macro(m1)
exten => h,1,NoCDR()
exten => h,n,Verbose(-----1----)
exten => h,n,Hangup()it
[macro-m1]
exten => s,1,NoOp(come here)
exten => s,n,Hangup()
exten => s,n,MacroExit()
exten => h,1,Verbose(-----2----) ;//此处的h分机永远不会被执行
exten => h,n,Hangup()
2.2 执行结果以下:
dotasterisk*CLI>
== Using SIP RTP TOS bits 184
== Using SIP RTP CoS mark 5
-- Executing [8888@from-internal:1] NoOp("SIP/8001-0000002b", "cid=8001") in new stack
-- Executing [8888@from-internal:2] Macro("SIP/8001-0000002b", "m1") in new stack
-- Executing [s@macro-m1:1] NoOp("SIP/8001-0000002b", "come here") in new stack
-- Executing [s@macro-m1:2] Hangup("SIP/8001-0000002b", "") in new stack
== Spawn extension (macro-m1, s, 2) exited non-zero on 'SIP/8001-0000002b' in macro 'm1'
== Spawn extension (from-internal, 8888, 2) exited non-zero on 'SIP/8001-0000002b'
-- Executing [h@from-internal:1] NoCDR("SIP/8001-0000002b", "") in new stack //注:没有执行宏里面的h分机
-- Executing [h@from-internal:2] Verbose("SIP/8001-0000002b", "-----1----") in new stack
-----1----
-- Executing [h@from-internal:3] Hangup("SIP/8001-0000002b", "") in new stack
== Spawn extension (from-internal, h, 3) exited non-zero on 'SIP/8001-0000002b'
dotasterisk*CLI>
2.3 说明:从执行结果看,发现宏里面执行Hangup()后没有执行宏里面的h分机,而是跳到调用宏的普通的context里面的h分机(h@from-internal)中去执行了。
2.4 结论:在宏Macro中通常只执行s分机,定义的h分机永远也不会执行,只会跳到调用处的Macro()代码里面的context去执行,也就是说宏中定义h分机原本就是没意义的。io
3. Gosub()子程序里面执行Hangup():
3.1 状况1:sub子程序明确指定了h分机
3.1.1 拨号脚本以下:
[from-internal]
exten => _.,1,NoOp(cid=${CALLERID(num)})
exten => _.,n,Gosub(s1,${EXTEN},1)
exten => h,1,NoCDR()
exten => h,n,Verbose(-----1----)
exten => h,n,Hangup()
[s1]
exten => _.,1,NoOp(come here)
exten => _.,n,Hangup()
exten => _.,n,Return()
exten => h,1,Verbose(-----2----)
exten => h,n,Hangup()
3.1.2 执行结果以下:
dotasterisk*CLI>
== Using SIP RTP TOS bits 184
== Using SIP RTP CoS mark 5
-- Executing [8888@from-internal:1] NoOp("SIP/8001-0000002c", "cid=8001") in new stack
-- Executing [8888@from-internal:2] Gosub("SIP/8001-0000002c", "s1,8888,1") in new stack
-- Executing [8888@s1:1] NoOp("SIP/8001-0000002c", "come here") in new stack
-- Executing [8888@s1:2] Hangup("SIP/8001-0000002c", "") in new stack
== Spawn extension (s1, 8888, 2) exited non-zero on 'SIP/8001-0000002c'
-- Executing [h@s1:1] Verbose("SIP/8001-0000002c", "-----2----") in new stack //注:只执行当前context的h分机,没有调到上一层
-----2----
-- Executing [h@s1:2] Hangup("SIP/8001-0000002c", "") in new stack
== Spawn extension (s1, h, 2) exited non-zero on 'SIP/8001-0000002c'
dotasterisk*CLI>
3.2 状况2:sub子程序里面没有h分机
3.2.1 拨号脚本以下:
[s1]
exten => _8.,1,NoOp(come here)
exten => _8.,n,Hangup()
exten => _8.,n,Return()
3.2.2 执行结果以下:
dotasterisk*CLI>
== Using SIP RTP TOS bits 184
== Using SIP RTP CoS mark 5
-- Executing [8888@from-internal:1] NoOp("SIP/8001-0000002f", "cid=8001") in new stack
-- Executing [8888@from-internal:2] Gosub("SIP/8001-0000002f", "s1,8888,1") in new stack
-- Executing [8888@s1:1] NoOp("SIP/8001-0000002f", "come here") in new stack //注:发现直接在这里挂机中止了,end了
-- Executing [8888@s1:2] Hangup("SIP/8001-0000002f", "") in new stack
== Spawn extension (s1, 8888, 2) exited non-zero on 'SIP/8001-0000002f'
dotasterisk*CLI>
3.3 结论:
goSub的context和普通的context执行Hangup() App后后续的拨号计划执行流程规则是同样的。能够这样理解:普通的context和子程序context是同样的,除了子程序context里面能够有Return()语句跳回到上一处拨号计划,其他方面的特性是如出一辙的。据测试,通道变量也没有什么变量做用域的概念,在子程序里面同样能够直接用外面的变量,子程序里面设置的变量同样能够带到外面去,不一样于其余编程语言里面有什么函数里面有局部变量的概念。同子程序同样,宏也没有局部变量的概念。关于变量测试代码以下:
[from-internal]
exten => _.,1,NoOp(cid=${CALLERID(num)})
exten => _.,n,Set(varOUT=AA)
exten => _.,n,Gosub(s1,${EXTEN},1)
exten => _.,n,NoOp(--varIN=${varIN}--) ;//能够直接用子程序里面定义的变量,不存在变量做用域的概念
exten => _.,n,WaitExten(100)
exten => h,1,NoCDR()
exten => h,n,Verbose(-----1----)
exten => h,n,Hangup()
[s1]
exten => _8.,1,NoOp(--varOUT=${varOUT}--) ;//能够打印外部变量
exten => _8.,n,Set(varIN=BB) ;//定义的变量,能够带到外部去
exten => _8.,n,Return()
输出结果:
dotasterisk*CLI>
== Using SIP RTP TOS bits 184
== Using SIP RTP CoS mark 5
-- Executing [8888@from-internal:1] NoOp("SIP/8001-00000031", "cid=8001") in new stack
-- Executing [8888@from-internal:2] Set("SIP/8001-00000031", "varOUT=AA") in new stack
-- Executing [8888@from-internal:3] Gosub("SIP/8001-00000031", "s1,8888,1") in new stack
-- Executing [8888@s1:1] NoOp("SIP/8001-00000031", "--varOUT=AA--") in new stack
-- Executing [8888@s1:2] Set("SIP/8001-00000031", "varIN=BB") in new stack
-- Executing [8888@s1:3] Return("SIP/8001-00000031", "") in new stack
-- Executing [8888@from-internal:4] NoOp("SIP/8001-00000031", "--varIN=BB--") in new stack -- Executing [8888@from-internal:5] WaitExten("SIP/8001-00000031", "100") in new stack