什么是通道
Asterisk中,通道是介于終端和Asterisk自己本身的一個(gè)通信媒介。它包含了所有相關(guān)信息傳遞到終端,或者從終端傳遞到Asterisk服務(wù)器端。這些信息中包含了信令(設(shè)備狀態(tài)或掛機(jī)命令)和媒體(從終端發(fā)送或者接收的語(yǔ)音和視頻)。
當(dāng)通道創(chuàng)建以后,這表示成功創(chuàng)建了一個(gè)通信的介質(zhì),Asterisk會(huì)指定兩個(gè)變量,一個(gè)是UniqueID -它用來(lái)處理通道的整個(gè)生命周期。另外一個(gè)是unique Name。UniqueID是一個(gè)全局的唯一標(biāo)識(shí)符,可以由ARIclient。如果 ARI client不能給通道提供UniqueID,那么Asterisk會(huì)給通道設(shè)置一個(gè)UniqueID。默認(rèn)環(huán)境下,它會(huì)使用Unix時(shí)間戳帶一個(gè)不斷遞增的整數(shù) ,和可選的Asterisk系統(tǒng)名稱。
通道和終端的綁定關(guān)系
通道名稱有兩部分組成:已創(chuàng)建的通道類型帶一個(gè)可描述的通道類型標(biāo)志符。支持的通道類型取決于Asterisk的配置。這里,我們使用PJSIP通道來(lái)和SIP終端設(shè)備進(jìn)行通信。
在上面的例子中,Alice的SIP終端設(shè)備呼叫Asterisk,Asterisk會(huì)指定一個(gè)通道帶一個(gè)UniqueID-Asterisk01-123456789.1,PJSIP通道驅(qū)動(dòng)器也指定了一個(gè)名稱PJSIP名稱- PJSIP/Alice-00000001。為了對(duì)此通道進(jìn)行控制,ARI操作會(huì)使用UniqueIDAsterisk01-123456789.1來(lái)進(jìn)行操作修改的處理。
內(nèi)部通道- Local Channels
大部分的通道是介于外部終端和Asterisk本身進(jìn)行通信。Asterisk也可以創(chuàng)建內(nèi)部的通道。這些通道稱之為 Local 通道-它們用來(lái)幫助處理Asterisk中各種資源之間的媒體轉(zhuǎn)移。
Local channel 是一種非常特別的通道,它們總是以一對(duì)通道的方式出現(xiàn)。如果系統(tǒng)創(chuàng)建一個(gè)Local"通道"的話,實(shí)際上會(huì)創(chuàng)建出兩個(gè)通道。在local通道之間會(huì)出現(xiàn)一個(gè)virtualendpoint,它負(fù)責(zé)來(lái)發(fā)送local通道之間的媒體。Local通道中的其中一端是和virtualendpoint永久綁定的,但是另外一端的Local通道則可以通過(guò)任何方式被修改或者被控制。Local通道的雙方會(huì)各自對(duì)對(duì)端發(fā)送媒體。
在以上的例子中,ARI已創(chuàng)建了一個(gè)Localchannel, Local/myapp@default.同樣,Asterisk會(huì)創(chuàng)建一對(duì)Local通道,帶了UniqueIDsof Asterisk01-123456790.1 和 Asterisk01-123456790.2。Local通道的名稱分別是Local/myapp@default-00000000;1和Local/myapp@default-00000000;2 -這里的 ;1和;2 表示Local通道的兩個(gè)部分。
在Stasis應(yīng)用程序中的通道
當(dāng)通道在Asterisk中創(chuàng)建以后,它會(huì)開始執(zhí)行Asterisk撥號(hào)規(guī)則。Asterisk通過(guò)context/extension/priority 的方式定義了進(jìn)入到撥號(hào)規(guī)則的通道。通道在不同的層級(jí)會(huì)執(zhí)行不同的Asterisk應(yīng)用程序。當(dāng)優(yōu)先級(jí)增加以后,撥號(hào)規(guī)則會(huì)自動(dòng)進(jìn)入到下一個(gè)的優(yōu)先級(jí)和相應(yīng)的應(yīng)用程序,撥號(hào)規(guī)則會(huì)繼續(xù)執(zhí)行,直到最后撥號(hào)規(guī)則的應(yīng)用程序通知通道掛機(jī)或終端設(shè)備自己掛機(jī)。
ARI控制通道是通過(guò)Stasis撥號(hào)規(guī)則的應(yīng)用程序。這個(gè)特別的程序會(huì)從撥號(hào)規(guī)則中來(lái)控制通道,ARI客戶端連接一個(gè)websocket,這個(gè)websocket已經(jīng)控制了通道。這里已經(jīng)啟動(dòng)了一個(gè)StasisStart事件;當(dāng)通道離開這個(gè)Stasis撥號(hào)規(guī)則的應(yīng)用程序后-或者它被告知離開,或者因?yàn)樵O(shè)備掛機(jī),然后啟動(dòng)一個(gè)StasisEnd事件。當(dāng)這個(gè)StasisEnd事件啟動(dòng)以后,ARI不在控制這個(gè)通道,通道從ARI釋放出來(lái),返回到撥號(hào)規(guī)則中。
在Asterisk的資源默認(rèn)情況下不會(huì)自己發(fā)送事件連接ARI應(yīng)用程序。為了獲得資源的事件,必須滿足其中以下之一的條件:
- 資源必須是已進(jìn)入Stasis撥號(hào)規(guī)則應(yīng)用的一個(gè)通道。在這個(gè)環(huán)境中,訂閱是在后臺(tái)創(chuàng)建。當(dāng)通道離開Stasis撥號(hào)規(guī)則的應(yīng)用程序后,訂閱也是在后臺(tái)被銷毀。
- 當(dāng)通道進(jìn)入到Stasis撥號(hào)規(guī)則的程序后,通道可能會(huì)和其他資源進(jìn)行互動(dòng)-例如bridge。當(dāng)通道和這些資源互動(dòng)時(shí),訂閱事件已經(jīng)被這個(gè)資源啟動(dòng)。當(dāng)在Stasis撥號(hào)規(guī)則中無(wú)任何通道后,后臺(tái)的訂閱事件被銷毀。
- 在任何時(shí)候,一個(gè)ARI程序可以在Asterisk中通過(guò)應(yīng)用程序來(lái)訂閱資源。資源操作的話,ARI應(yīng)用程序就會(huì)有自己的訂閱事件。
舉例:和通道進(jìn)行通信
在這個(gè)例子中,我們會(huì)按照以下方式寫一個(gè)ARI應(yīng)用程序:
- 當(dāng)ARI連接以后,它會(huì)打印出當(dāng)前通道的名稱。如果無(wú)通道存在,也會(huì)有提示信息。
- 當(dāng)通道進(jìn)入到Stasis程序后,它會(huì)打印出關(guān)于通道的信息。
- 當(dāng)通道離開Stasis程序后,它也會(huì)打印離開的通道。
撥號(hào)規(guī)則
此撥號(hào)規(guī)則非常直接:一個(gè)extension的通道進(jìn)入Stasis程序。
Python實(shí)例
在Python例子中,我們是基于ari-py這個(gè)支持包來(lái)實(shí)現(xiàn)的。因?yàn)閍ri支持包通過(guò)Python日志系統(tǒng)支持了豐富的信息,我們可以直接設(shè)置使用。帶Error的 basicConfig 可以顯示基本的錯(cuò)誤信息,它完全可以支持基本的工作需求。最后,我們需要一個(gè)終端來(lái)發(fā)起對(duì)Asterisk的連接。終端使用的方式是ari.connect 的方式,這里,我們需要設(shè)置三個(gè)參數(shù):
一個(gè)HTTPURL連接。這里,我們假設(shè)腳本運(yùn)行在同一臺(tái)服務(wù)器,使用AsteriskHTTP 服務(wù)器默認(rèn)端口- 8088。
使用的是ARI用戶名稱連接服務(wù)器。這里,我們?cè)O(shè)置為asterisk。
ARI賬號(hào)密碼是asterisk。
注意:
當(dāng)用戶是生產(chǎn)系統(tǒng)時(shí),請(qǐng)修改默認(rèn)的用戶名和密碼。
一旦我們發(fā)起了連接,第一個(gè)任務(wù)是打印出當(dāng)前所有的通道,如果沒有通道則打印無(wú)通道信息。通道資源可以支持- GET/channels操作。因?yàn)閍ri-py 支持包是動(dòng)態(tài)操作的,它操作的對(duì)象結(jié)構(gòu)可以通過(guò)映射到方式來(lái)進(jìn)行,我們這里可以使用列出所有通道資源的列表來(lái)實(shí)現(xiàn)對(duì)通道的各種控制:
通過(guò)GET/channels 的操作可以獲得通道資源的列表。這些資源是從操作中通過(guò)JSON的格式返回,同時(shí),ari-py支持包會(huì)轉(zhuǎn)換uniqueid 的用戶屬性來(lái)附加到操作對(duì)象,它會(huì)把其他的信息保存在JSON目錄下。因?yàn),這里我們僅需要此名稱,所以,我們這里僅通過(guò)JSON提取名稱,然后打印此名稱。
下一步,當(dāng)通道進(jìn)入到Stasis應(yīng)用程序channel-dump后,我們打印出通道的相關(guān)信息,離開時(shí)打印出通道名稱。為了實(shí)現(xiàn)以上要求,我們需要訂閱StasisStart 和 StasisEnd 事件:
這里,我們?nèi)匀恍枰獌蓚(gè)函數(shù)來(lái)處理stasis_start_cb 負(fù)責(zé)StasisStart 的事件,stasis_end_cb 處理StasisEnd 事件:
最后,系統(tǒng)需要告訴終端來(lái)運(yùn)行應(yīng)用程序。一旦client.run執(zhí)行以后,系統(tǒng)會(huì)做一個(gè)websocket連接,應(yīng)用程序會(huì)一直等待觸發(fā)的事件。用戶可以使用 Ctrl+C 組合鍵來(lái)殺死這個(gè)連接。
channel-dump.py
完整的channel-dump.py 代碼:
channel-dump.py
channel-dump.py 實(shí)戰(zhàn)測(cè)試
以下是channel-dump.py的輸出結(jié)果。第一次連接以后,沒有發(fā)現(xiàn)任何的通道,然后Alice(extension1000)使用的PJSIP通道進(jìn)入到Stasis應(yīng)用程序。輸出打印所有Alice的通道信息。一段時(shí)間以后,她掛機(jī)離開了應(yīng)用程序。
JavaScript (Node.js)
在這個(gè)例子中,我們是基于Node.js ari-client 這個(gè)支持包來(lái)實(shí)現(xiàn)的。我們需要一個(gè)終端來(lái)發(fā)起對(duì)Asterisk的連接。終端使用的方式是ari.connect 的方式,這里,我們需要設(shè)置三個(gè)參數(shù):
一個(gè)HTTPURL連接。這里,我們假設(shè)腳本運(yùn)行在同一臺(tái)服務(wù)器,使用Asterisk HTTP 服務(wù)器默認(rèn)端口- 8088。
使用的是ARI用戶名稱連接服務(wù)器。這里,我們?cè)O(shè)置為asterisk。
ARI賬號(hào)密碼是asterisk。
注意:
在生成系統(tǒng)中,一定要修改實(shí)例中的用戶名稱和密碼。
一旦我們發(fā)起了連接,第一個(gè)任務(wù)是打印出當(dāng)前所有的通道,如果沒有通道則打印無(wú)通道信息。通道資源可以支持- GET/channels操作。因?yàn)閍ri-client支持包是動(dòng)態(tài)操作的,它操作的對(duì)象結(jié)構(gòu)可以通過(guò)映射到方式來(lái)進(jìn)行,我們這里可以使用列出所有通道資源的列表來(lái)實(shí)現(xiàn)對(duì)通道的各種控制:
通過(guò)GET/channels 的操作可以獲得通道資源的列表。這些資源是從操作中通過(guò)JSON的格式返回,同時(shí),ari-client支持包會(huì)轉(zhuǎn)換uniqueid 的用戶屬性來(lái)附加到操作對(duì)象,它會(huì)把其他的信息保存在JSON目錄下。因?yàn),這里我們僅需要此名稱,所以,我們這里僅通過(guò)JSON提取名稱,然后打印此名稱。
下一步,當(dāng)通道進(jìn)入到Stasis應(yīng)用程序channel-dump后,我們打印出通道的相關(guān)信息,離開時(shí)打印出通道名稱。為了實(shí)現(xiàn)以上要求,我們需要訂閱StasisStart 和 StasisEnd 事件:
這里,我們?nèi)匀恍枰獌蓚(gè)函數(shù)來(lái)處理stasis_start_cb 負(fù)責(zé)StasisStart的事件,stasis_end_cb 處理StasisEnd 事件:
最后,系統(tǒng)需要通知終端來(lái)運(yùn)行應(yīng)用程序。一旦client.run執(zhí)行以后,系統(tǒng)會(huì)做一個(gè)websocket連接,應(yīng)用程序會(huì)一直等待觸發(fā)的事件。用戶可以使用 Ctrl+C 組合鍵來(lái)殺死這個(gè)連接。
channel-dump.js
完整的channel-dump.js 源代碼:
channel-dump.js 實(shí)戰(zhàn)測(cè)試
以下是channel-dump.js的輸出結(jié)果。第一次連接以后,沒有發(fā)現(xiàn)任何的通道,然后Alice(extension1000)使用的PJSIP通道進(jìn)入到Stasis應(yīng)用程序。輸出打印所有Alice的通道信息。一段時(shí)間以后,她掛機(jī)離開了應(yīng)用程序。
以上技術(shù)結(jié)合介紹了ARI對(duì)通道的基本使用方式和兩個(gè)腳本實(shí)例,在未來(lái)的文檔中,我們會(huì)介紹ARI接口對(duì)媒體的控制和管理,以及ARI配置,ARI中的等待橋接的幾個(gè)關(guān)鍵要點(diǎn)。
獲得有價(jià)值的技術(shù)分享,請(qǐng)關(guān)注我們的微信號(hào):asterisk-cn, 技術(shù)論壇:www.freesip.org.