在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