什么是通道
Asterisk中,通道是介于終端和Asterisk自己本身的一個(gè)通信媒介。它包含了所有相關(guān)信息傳遞到終端,或者從終端傳遞到Asterisk服務(wù)器端。這些信息中包含了信令(設備狀態(tài)或掛機命令)和媒體(從終端發(fā)送或者接收的語(yǔ)音和視頻)。
當通道創(chuàng )建以后,這表示成功創(chuàng )建了一個(gè)通信的介質(zhì),Asterisk會(huì )指定兩個(gè)變量,一個(gè)是UniqueID -它用來(lái)處理通道的整個(gè)生命周期。另外一個(gè)是unique Name。UniqueID是一個(gè)全局的唯一標識符,可以由ARIclient。如果 ARI client不能給通道提供UniqueID,那么Asterisk會(huì )給通道設置一個(gè)UniqueID。默認環(huán)境下,它會(huì )使用Unix時(shí)間戳帶一個(gè)不斷遞增的整數 ,和可選的Asterisk系統名稱(chēng)。
通道和終端的綁定關(guān)系
通道名稱(chēng)有兩部分組成:已創(chuàng )建的通道類(lèi)型帶一個(gè)可描述的通道類(lèi)型標志符。支持的通道類(lèi)型取決于A(yíng)sterisk的配置。這里,我們使用PJSIP通道來(lái)和SIP終端設備進(jìn)行通信。

在上面的例子中,Alice的SIP終端設備呼叫Asterisk,Asterisk會(huì )指定一個(gè)通道帶一個(gè)UniqueID-Asterisk01-123456789.1,PJSIP通道驅動(dòng)器也指定了一個(gè)名稱(chēng)PJSIP名稱(chēng)- PJSIP/Alice-00000001。為了對此通道進(jìn)行控制,ARI操作會(huì )使用UniqueIDAsterisk01-123456789.1來(lái)進(jìn)行操作修改的處理。
內部通道- Local Channels
大部分的通道是介于外部終端和Asterisk本身進(jìn)行通信。Asterisk也可以創(chuàng )建內部的通道。這些通道稱(chēng)之為 Local 通道-它們用來(lái)幫助處理Asterisk中各種資源之間的媒體轉移。
Local channel 是一種非常特別的通道,它們總是以一對通道的方式出現。如果系統創(chuàng )建一個(gè)Local"通道"的話(huà),實(shí)際上會(huì )創(chuàng )建出兩個(gè)通道。在local通道之間會(huì )出現一個(gè)virtualendpoint,它負責來(lái)發(fā)送local通道之間的媒體。Local通道中的其中一端是和virtualendpoint永久綁定的,但是另外一端的Local通道則可以通過(guò)任何方式被修改或者被控制。Local通道的雙方會(huì )各自對對端發(fā)送媒體。

在以上的例子中,ARI已創(chuàng )建了一個(gè)Localchannel, Local/myapp@default.同樣,Asterisk會(huì )創(chuàng )建一對Local通道,帶了UniqueIDsof Asterisk01-123456790.1 和 Asterisk01-123456790.2。Local通道的名稱(chēng)分別是Local/myapp@default-00000000;1和Local/myapp@default-00000000;2 -這里的 ;1和;2 表示Local通道的兩個(gè)部分。
在Stasis應用程序中的通道
當通道在A(yíng)sterisk中創(chuàng )建以后,它會(huì )開(kāi)始執行Asterisk撥號規則。Asterisk通過(guò)context/extension/priority 的方式定義了進(jìn)入到撥號規則的通道。通道在不同的層級會(huì )執行不同的Asterisk應用程序。當優(yōu)先級增加以后,撥號規則會(huì )自動(dòng)進(jìn)入到下一個(gè)的優(yōu)先級和相應的應用程序,撥號規則會(huì )繼續執行,直到最后撥號規則的應用程序通知通道掛機或終端設備自己掛機。
ARI控制通道是通過(guò)Stasis撥號規則的應用程序。這個(gè)特別的程序會(huì )從撥號規則中來(lái)控制通道,ARI客戶(hù)端連接一個(gè)websocket,這個(gè)websocket已經(jīng)控制了通道。這里已經(jīng)啟動(dòng)了一個(gè)StasisStart事件;當通道離開(kāi)這個(gè)Stasis撥號規則的應用程序后-或者它被告知離開(kāi),或者因為設備掛機,然后啟動(dòng)一個(gè)StasisEnd事件。當這個(gè)StasisEnd事件啟動(dòng)以后,ARI不在控制這個(gè)通道,通道從ARI釋放出來(lái),返回到撥號規則中。
在A(yíng)sterisk的資源默認情況下不會(huì )自己發(fā)送事件連接ARI應用程序。為了獲得資源的事件,必須滿(mǎn)足其中以下之一的條件:
- 資源必須是已進(jìn)入Stasis撥號規則應用的一個(gè)通道。在這個(gè)環(huán)境中,訂閱是在后臺創(chuàng )建。當通道離開(kāi)Stasis撥號規則的應用程序后,訂閱也是在后臺被銷(xiāo)毀。
- 當通道進(jìn)入到Stasis撥號規則的程序后,通道可能會(huì )和其他資源進(jìn)行互動(dòng)-例如bridge。當通道和這些資源互動(dòng)時(shí),訂閱事件已經(jīng)被這個(gè)資源啟動(dòng)。當在Stasis撥號規則中無(wú)任何通道后,后臺的訂閱事件被銷(xiāo)毀。
- 在任何時(shí)候,一個(gè)ARI程序可以在A(yíng)sterisk中通過(guò)應用程序來(lái)訂閱資源。資源操作的話(huà),ARI應用程序就會(huì )有自己的訂閱事件。
舉例:和通道進(jìn)行通信
在這個(gè)例子中,我們會(huì )按照以下方式寫(xiě)一個(gè)ARI應用程序:
- 當ARI連接以后,它會(huì )打印出當前通道的名稱(chēng)。如果無(wú)通道存在,也會(huì )有提示信息。
- 當通道進(jìn)入到Stasis程序后,它會(huì )打印出關(guān)于通道的信息。
- 當通道離開(kāi)Stasis程序后,它也會(huì )打印離開(kāi)的通道。
撥號規則
此撥號規則非常直接:一個(gè)extension的通道進(jìn)入Stasis程序。

Python實(shí)例
在Python例子中,我們是基于ari-py這個(gè)支持包來(lái)實(shí)現的。因為ari支持包通過(guò)Python日志系統支持了豐富的信息,我們可以直接設置使用。帶Error的 basicConfig 可以顯示基本的錯誤信息,它完全可以支持基本的工作需求。最后,我們需要一個(gè)終端來(lái)發(fā)起對Asterisk的連接。終端使用的方式是ari.connect 的方式,這里,我們需要設置三個(gè)參數:
一個(gè)HTTPURL連接。這里,我們假設腳本運行在同一臺服務(wù)器,使用AsteriskHTTP 服務(wù)器默認端口- 8088。
使用的是ARI用戶(hù)名稱(chēng)連接服務(wù)器。這里,我們設置為asterisk。
ARI賬號密碼是asterisk。
注意:
當用戶(hù)是生產(chǎn)系統時(shí),請修改默認的用戶(hù)名和密碼。

一旦我們發(fā)起了連接,第一個(gè)任務(wù)是打印出當前所有的通道,如果沒(méi)有通道則打印無(wú)通道信息。通道資源可以支持- GET/channels操作。因為ari-py 支持包是動(dòng)態(tài)操作的,它操作的對象結構可以通過(guò)映射到方式來(lái)進(jìn)行,我們這里可以使用列出所有通道資源的列表來(lái)實(shí)現對通道的各種控制:

通過(guò)GET/channels 的操作可以獲得通道資源的列表。這些資源是從操作中通過(guò)JSON的格式返回,同時(shí),ari-py支持包會(huì )轉換uniqueid 的用戶(hù)屬性來(lái)附加到操作對象,它會(huì )把其他的信息保存在JSON目錄下。因為,這里我們僅需要此名稱(chēng),所以,我們這里僅通過(guò)JSON提取名稱(chēng),然后打印此名稱(chēng)。
下一步,當通道進(jìn)入到Stasis應用程序channel-dump后,我們打印出通道的相關(guān)信息,離開(kāi)時(shí)打印出通道名稱(chēng)。為了實(shí)現以上要求,我們需要訂閱StasisStart 和 StasisEnd 事件:

這里,我們仍然需要兩個(gè)函數來(lái)處理stasis_start_cb 負責StasisStart 的事件,stasis_end_cb 處理StasisEnd 事件:

最后,系統需要告訴終端來(lái)運行應用程序。一旦client.run執行以后,系統會(huì )做一個(gè)websocket連接,應用程序會(huì )一直等待觸發(fā)的事件。用戶(hù)可以使用 Ctrl+C 組合鍵來(lái)殺死這個(gè)連接。

channel-dump.py
完整的channel-dump.py 代碼:
channel-dump.py

channel-dump.py 實(shí)戰測試
以下是channel-dump.py的輸出結果。第一次連接以后,沒(méi)有發(fā)現任何的通道,然后Alice(extension1000)使用的PJSIP通道進(jìn)入到Stasis應用程序。輸出打印所有Alice的通道信息。一段時(shí)間以后,她掛機離開(kāi)了應用程序。

JavaScript (Node.js)
在這個(gè)例子中,我們是基于Node.js ari-client 這個(gè)支持包來(lái)實(shí)現的。我們需要一個(gè)終端來(lái)發(fā)起對Asterisk的連接。終端使用的方式是ari.connect 的方式,這里,我們需要設置三個(gè)參數:
一個(gè)HTTPURL連接。這里,我們假設腳本運行在同一臺服務(wù)器,使用Asterisk HTTP 服務(wù)器默認端口- 8088。
使用的是ARI用戶(hù)名稱(chēng)連接服務(wù)器。這里,我們設置為asterisk。
ARI賬號密碼是asterisk。
注意:
在生成系統中,一定要修改實(shí)例中的用戶(hù)名稱(chēng)和密碼。

一旦我們發(fā)起了連接,第一個(gè)任務(wù)是打印出當前所有的通道,如果沒(méi)有通道則打印無(wú)通道信息。通道資源可以支持- GET/channels操作。因為ari-client支持包是動(dòng)態(tài)操作的,它操作的對象結構可以通過(guò)映射到方式來(lái)進(jìn)行,我們這里可以使用列出所有通道資源的列表來(lái)實(shí)現對通道的各種控制:

通過(guò)GET/channels 的操作可以獲得通道資源的列表。這些資源是從操作中通過(guò)JSON的格式返回,同時(shí),ari-client支持包會(huì )轉換uniqueid 的用戶(hù)屬性來(lái)附加到操作對象,它會(huì )把其他的信息保存在JSON目錄下。因為,這里我們僅需要此名稱(chēng),所以,我們這里僅通過(guò)JSON提取名稱(chēng),然后打印此名稱(chēng)。
下一步,當通道進(jìn)入到Stasis應用程序channel-dump后,我們打印出通道的相關(guān)信息,離開(kāi)時(shí)打印出通道名稱(chēng)。為了實(shí)現以上要求,我們需要訂閱StasisStart 和 StasisEnd 事件:

這里,我們仍然需要兩個(gè)函數來(lái)處理stasis_start_cb 負責StasisStart的事件,stasis_end_cb 處理StasisEnd 事件:

最后,系統需要通知終端來(lái)運行應用程序。一旦client.run執行以后,系統會(huì )做一個(gè)websocket連接,應用程序會(huì )一直等待觸發(fā)的事件。用戶(hù)可以使用 Ctrl+C 組合鍵來(lái)殺死這個(gè)連接。

channel-dump.js
完整的channel-dump.js 源代碼:

channel-dump.js 實(shí)戰測試
以下是channel-dump.js的輸出結果。第一次連接以后,沒(méi)有發(fā)現任何的通道,然后Alice(extension1000)使用的PJSIP通道進(jìn)入到Stasis應用程序。輸出打印所有Alice的通道信息。一段時(shí)間以后,她掛機離開(kāi)了應用程序。

以上技術(shù)結合介紹了ARI對通道的基本使用方式和兩個(gè)腳本實(shí)例,在未來(lái)的文檔中,我們會(huì )介紹ARI接口對媒體的控制和管理,以及ARI配置,ARI中的等待橋接的幾個(gè)關(guān)鍵要點(diǎn)。
獲得有價(jià)值的技術(shù)分享,請關(guān)注我們的微信號:asterisk-cn, 技術(shù)論壇:www.freesip.org.