我們在asterisk裡面若有不只一個外撥路由的話,我們該怎樣設定比較好?
若你想要查找更多這方便的資料,可試試試這些關鍵字 asterisk dial fail over
外撥路由,指的是我們撥打到PSTN的那一段路由。
一般若沒有加任何判斷式,會是這樣子的設定
[Call_out]
exten => _XXX.,1,Noop
same => n,Dial(SIP/sip1/${EXTEN},60,XxWw)
same => n,Dial(SIP/sip2/${EXTEN},60,XxWw)
same => n,Hangup
直接就將兩個外撥路由給設定上去了,這是最簡單無腦式的設定方法。
缺點是,在某些情況下,同一個號碼會被撥兩次,比如對方拒絕你的來電又沒有設定語音信箱,就會撥兩次。
若你的外撥路由是在內網,或者你只需要擔心它ping得通不通的問題,可加入一點簡單的判斷式,底下的判斷式是參考此頁所寫。
#sip.conf 裡的設定
[sip1]
---
---
;先在這裡設定檢查存活
qualify=yes
qualifyfreq=30
;檢查存活頻率
; Qualification: How often to check for the host to be up in seconds
; and reported in milliseconds with sip show settings.
; Set to low value if you use low timeout for NAT of UDP sessions
; 預設 60 秒
qualifygap=60 ; Number of milliseconds between each group of peers being qualified
; Default: 100
[sip2]
---
---
qualify=yes
#extensions.conf 裡的設定
[Call_out]
exten => _XXX.,1,Noop
;設定變數名稱 sip1status
same => n,Set(sip1status=${SIPPEER(sip1,status)})
;same => n,Set(sip1status=${IAXPEER(sip1,status)})
;若你的 sip1 是使用IAX協定的話,上面的變數也要記得改成 IAXPEER
;語法 GotoIf(條件指定?真值名稱:假值名稱)
same => n,Gotoif($[ "${sip1status}" = "UNREACHABLE" ]?sip2)
;條件判斷,若sip1斷線,則跳往sip2
same => n,Dial(SIP/sip1/${EXTEN},60,XxWw)
same => n,Hangup
same => n(sip2),Dial(SIP/sip2/${EXTEN},60,XxWw)
same => n,Hangup
若你的外撥路由是跟二類電信申請的SIP trunk的話,這些路由大多都有一個問題,就是超賣。比如說他們只申請了 T1 專線,有24路電話訊號,也就是同時間可供24人通話,但他們不可能只賣給24個客戶來使用這些線路,他可能會是賣給100個客戶,大家共同來擠這24線,這樣我們上面的判斷式就會有一個問題了,雖然這個 sip trunk 是ping得通的,但是對方的線路太忙了,擠不上,就會撥出失敗,所以上面的判斷式針對這種情況就不太適用,得改一下。底下的判斷式是參考此頁所修改的。
[Call_outbound]
exten => _XXX.,1,Noop
same => n,Dial(SIP/sip1/${EXTEN},60,XxWw)
same => n,GotoIf($[${DIALSTATUS}=CHANUNAVAIL | ${DIALSTATUS}=CONGESTION]?dial2)
same => n,Hangup
same => n(dial2),Noop(啟用備用路由)
same => n,Dial(SIP/sip2/${EXTEN},60,XxWw)
same => n,Hangup
上面的判斷式只簡單的檢查物 dial status 的兩個狀態 CHANUNAVAIL 和 CONGESTION 這兩個都會是sip trunk 忙線或有狀況時常會出現的狀態,當然你也可以自己多加一點 dial status 狀態進來。
Dial() 的傳回狀態有幾種:
ANSWER, BUSY, NOANSWER, CANCEL, CONGESTION, CHANUNAVAIL, DONTCALL, TORTURE, INVALIDARGS
基本上,以上的判斷式大概就夠用了,但我在查資料時發現還有另一種寫法,它是使用巨集的方式來寫的,記下來參考用。
底下的語法是經我測試過可行的,我在網路上查到的,可能是它的asterisk版本過舊,直接照它的語法copy來用不了,所以我仿照它的方式修改如下:
[globals]
ROUTE1 = SIP/sip1/
ROUTE2 = SIP/sip2/#前綴碼1
ROUTE3 = SIP/sip3/#前綴碼2
ROUTE4 = SIP/sip4/#前綴碼3
MAX_ROUTE = 4
[macro-direct-dial]
exten => s,1,Set(CALL_ATTEMPT=1)
exten => s,2,Set(OUT=${ROUTE1})
exten => s,3,Dial(${OUT}${ARG1},60,XxWw)
exten => s,4,GotoIf($["${CALL_ATTEMPT}" >= "${MAX_ROUTE}"]?s-CANCEL,1)
; 若變數 CALL_ATTEMP 大於 ${MAX_ROUTE} 則跳往 s-CANCEL 標,取消撥號
exten => s,5,Set(CALL_ATTEMPT=$[ ${CALL_ATTEMPT} + 1])
;變數 CALL_ATTEMP 加1
exten => s,6,Goto(${DIALSTATUS})
same => n(CHANUNAVAIL),Set(OUT=${EVAL(${ROUTE${CALL_ATTEMPT}})})
same => n,Noop(${OUT})
same => n,Goto(s,3)
same => n(CONGESTION),Set(OUT=${EVAL(${ROUTE${CALL_ATTEMPT}})})
same => n,Noop(${EVAL(${ROUTE${CALL_ATTEMPT}})})
same => n,Goto(s,3)
same => n(BUSY),Noop()
same => n(NOANSWER),Noop()
same => n,Hangup()
exten => s-CANCEL,1,Hangup()
[Call_outbound]
exten => _XXX.,1,Noop
same => n,Macrol(direct-dial,${EXTEN})
same => n,Hangup
以上的方式經我反覆的測試,修正了語法錯誤之後,確定是可行的,但是對我來說不好用,最後沒用上,為什麼呢? 雖然不同的二類電信業者要帶不同的前綴碼給他們的這個問題我解決了,但是,外撥的號碼,有些是要加02、03…這些區碼,送去二類電信時,就得把這些0給拿掉,但送去一類電信時,又要加上0,一會兒加0,一會兒減0…算了,反正前面的判斷式夠我用就可以了,這個問題,暫時就不去傷腦筋了。