Doubango voip 框架分析之tinysip 協(xié)議棧
1. tinysip 介紹 :
兼容性 : SIP (RFC 3261) 以及 3GPP IMS/LTE (TS 24.229) implementation
依賴 tinySAK, tinyNET, tinySDP, tinyMEDIA, tinyHTTP and tinyIPSec.
2. SIP 協(xié)議 - tinysip 的實現(xiàn)機制
SIP 是一個分層結(jié)構的協(xié)議,這意味著它的行為是根據(jù)一組平等獨立的處理階段來描述,每一階段之間只是松耦合。協(xié)議分層描述是為了表達,從而允許功能的描述可在一個部分跨越幾個元素。它不指定任何方式的實現(xiàn)。當我們說某元素包含某層,我們是指它順從該層定義的規(guī)則集。
不是協(xié)議規(guī)定的每個元素都包含各層。而且,由SIP 規(guī)定的元素是邏輯元素,不是物理元素。一個物理實現(xiàn)可以選擇作為不同的邏輯元素,甚至可能在一個個事務的基礎上。
SIP 的最底層是語法和編碼。它的編碼使用增強Backus-Nayr 形式語法(BNF )來規(guī)定。
第二層是傳輸層。它定義了網(wǎng)絡上一個客戶機如何發(fā)送請求和接收響應以及一個服務器如何接收請求和發(fā)送響應。所有的SIP 元素包含傳輸層。
第三層是事務層。事務是SIP 的基本元素。一個事務是由客戶機事務發(fā)送給服務器事務的請求(使用傳輸層),以及對應該請求的從服務器事務發(fā)送回客戶機的所有響應組成。事務層處理應用層重傳,匹配響應到請求,以及應用層超時。任何用戶代理客戶機(UAC )完成的任務使用一組事務產(chǎn)生。用戶代理包含一個事務層,有狀態(tài)的代理也有。無狀態(tài)的代理不包含事務層。事務層具有客戶機組成部分(稱為客戶機事務)和服務器組成部分(稱為服務器事務),每個代表有限的狀態(tài)機,它被構造來處理特定的請求。
事務層之上的層稱為事務用戶(TU )。每個SIP 實體,除了無狀態(tài)代理,都是事務用戶。當一個TU 希望發(fā)送請求,它生成一個客戶機事務實例并且向它傳遞請求和IP 地址,端口,和用來發(fā)送請求的傳輸機制。一個TU 生成客戶機事務也能夠刪除它。當客戶機取消一個事務時,它請求服務器停止進一步的處理,將狀態(tài)恢復到事務初始化之前,并且生成特定的錯誤響應到該事務。這由CANCEL 請求完成,它構成自己的事務,但涉及要取消的事務。
SIP 通過EMAIL 形式的地址來標明用戶地址。每一用戶通過一等級化的URL 來標識,它通過諸如用戶電話號碼或主機名等元素來構造(例如:SIP:vision-com.com )。因為它與EMAIL 地址的相似性,SIP URLs 容易與用戶的EMAIL 地址關聯(lián)。
SIP 提供它自己的可靠性機制從而獨立于分組層,并且只需不可靠的數(shù)據(jù)包服務即可。SIP 可典型地用于UDP 或TCP 之上。
Register,Invite, Options …
Nat Tranversal
Dialog Layer
Transaction Layer
Parsing Layer
Transport Layer
sip 協(xié)議棧分層結(jié)構圖
根據(jù)sip 消息流向可以分為incoming message 和outgoing message, incoming 消息從 下到上,即Transport Layer → Register,Invite, Options; outgoing message 消息流向與此相反。
3 . 根據(jù)以上定義,tinysip 分如下模塊:
1).api 外部接口,對sip 協(xié)議支持的方法的接口封裝,協(xié)議棧提供的發(fā)起請求及接受請求對應的接口, 包括 registar layer, presence layer 等上層應用,當前版本支持如下請求:
REGISTER ,SUBSCRIBE( 訂閱),MESSAGE( 即時通信),PUBLISH (狀態(tài)展示),OPTIONS (查詢服務器能力),INVITE (發(fā)起請求),Cancel (取消一個請求),
BYE (結(jié)束通話)。
2). Nat traversal :Nat 穿越層,tinysip 目前支持stun ,turn 穿透。
3).Dialog , 會話模塊,一路呼叫的唯一標識, 處于sip 事務層之上。
4).parsers ,sip 消息解析,處于 sip 語法層,解析從傳輸層傳遞的數(shù)據(jù)包為協(xié)議棧理解的結(jié)構。
5). transactions , 事務層,事務是一個請求以及與此請求相關的所有響應組成,用 transaction id 唯一標識,由于sip 信令一般由udp 承載,所以不能保證信息的可靠到達,所以事務層必須提供一種機制處理udp 所不能提供的功能,這里一般通過定時器及一個有限狀態(tài)機來實現(xiàn)。
6). transports , 傳輸層,即 udp , TCP, TLS, SCTP socket 系統(tǒng)調(diào)用系列,此層隱藏了所有傳輸層的細節(jié),對于incoming sip message , 此層為sip 消息的入口, 對于outgoing sip message, 此層為sip 消息的出口。
4. doubango sip 協(xié)議棧使用流程:
1 ). 初始化
doubango sip 協(xié)議棧依賴于tinyNET 模塊,所以必須先調(diào)用tnet_startup 函數(shù)初始化,退出時調(diào)用tnet_cleanup 清除資源,初始化sip
協(xié)議棧之前必須設置用戶的域(realm 參見(1 )) 及用戶的私有(IMPI (2 ))及共有標別(IMPU (3 )), 這些為ims 引入的概念。
(1) realm 解釋:reaml 為域名,用來作客戶端認證用(authenticate ). 必須是一個有效的 sip uri 如:sip:vision-com.com.cn ,realm 為sip 協(xié)議棧啟動之前必須設置的選項,一旦協(xié)議棧啟動realm 就不可以更改,如果不填寫sip 代理服務器地址,則系統(tǒng)會用realm 通過 dns NAPTR + SRV 或者DHCP ( 還沒實現(xiàn)) 動態(tài) 查找機制確定sip 服務器地址。
(2) 用戶私有標識,為用戶所屬網(wǎng)絡賦予的唯一值,用來做驗證,為IMS 中的概念,如果用doubango sip 協(xié)議棧作為普通sip 功能,即非IMS 網(wǎng)絡中的sip 功能,此處的impi 意義與sip 協(xié)議棧中的驗證域名相同。
(3 )用戶公有標識,ims 網(wǎng)絡中 一個impi 可以對應多個impu. 對比理解,比如我們的手機只能屬于一個地方,而當我們到不同外地后會有漫游,此處的impi 即是我們手機本地給的唯一標識,而impu 是手機到外地后,當?shù)鼐W(wǎng)絡給的一個標識。
2 ). 創(chuàng)建以及啟動
通過調(diào)用 tsip_stack_create 創(chuàng)建協(xié)議棧, 調(diào)用tsip_stack_start 啟動,
完整例子:
tsip_stack_handle_t *stack = tsk_null;
int ret;
const char* realm_uri = "sip:vision-com.com.cn";
const char* impi_uri = "lideping@vision-com.com.cn";
const char* impu_uri = "sip:bob@vision-com.com.cn";
// ... 必須先初始化tnet 工具
tnet_startup();
// ...
// 創(chuàng)建協(xié)議棧,指定回調(diào)函數(shù),參數(shù)為域名,公有及私有標識。
stack = tsip_stack_create(sip_callback, realm_uri, impi_uri, impu_uri,
TSIP_STACK_SET_PASSWORD("yourpassword"),
// ...other macros...
// 此處初始化 其他信息,比如代理服務器地址,編碼信息等。
tsip_stack_start(stack) // 啟動協(xié)議棧
TSIP_STACK_SET_NULL()); // 用來終止傳給app_callback 的參數(shù)。
TSK_OBJECT_SAFE_FREE(stack);
tnet_cleanup();
// 釋放資源
// 事件回調(diào)
int sip_callback(const tsip_event_t *sipevent)
{
// 事件類型
switch(sipevent->type){
case tsip_event_register:
{ /* REGISTER */
break;
}
case tsip_event_invite:
{ /* INVITE */
break
}
case tsip_event_message:
{ /* MESSAGE */
break
}
case tsip_event_publish:
{ /* PUBLISH */
break
}
case tsip_event_subscribe:
{ /* SUBSCRIBE */
break
}
case tsip_event_options:
{ /* OPTIONS */
break
}
case tsip_event_dialog:
{ /* Common to all dialogs */
break
}
/* case …*/
}
3 ). 代碼分析
首先調(diào)用tsip_stack_create 創(chuàng)建協(xié)議棧 ,tsip_stack_create 內(nèi)部首先檢查參數(shù)是否合法,然后創(chuàng)建協(xié)議棧結(jié)構tsip_stack_t ,設置realm, IMPI and IMPU ,初始化一些協(xié)議棧默認值。創(chuàng)建 SigComp 信令壓縮模塊(可選) 創(chuàng)建dns 處理模寬,DHCP context ,接下來創(chuàng)建上面提到的sip 協(xié)議棧各層,分別調(diào)用tsip_dialog_layer_create ,tsip_transac_layer_create,tsip_transport_layer_create 創(chuàng)建會話層,事務層及傳輸層。至此,創(chuàng)建協(xié)議棧畢。
在真正啟動協(xié)議棧之前,即 tsip_stack_create 與tsip_stack_start 之間 可調(diào)用協(xié)議棧提供的api 初始化其他參數(shù), 然后調(diào)用tsip_stack_start 啟動協(xié)議棧,首先啟動定時器線程,這里定時器主要在事務層提供狀態(tài)機功調(diào)度功能。然后設置傳輸層類型,設置是否用ipsec 把sip 信令加密, 然后如果協(xié)議棧是處于客戶端模式并且代理服務器地址沒有設置則用認證的域名查找代理服務器的地址(用S NAPTR+SRV), 然后設置Runnable 回調(diào),啟動run 線程,run 內(nèi)部不斷從消息隊列里取消息,這里的消息是從傳輸層從下到上傳送過來,最終串聯(lián)到消息隊列,然后調(diào)用協(xié)議棧創(chuàng)建時指定的回調(diào)sip_callback ,所有incoming sip 消息以及媒體信息的改變最終都會走到此回調(diào)函數(shù),此函數(shù)內(nèi)部根據(jù)消息類型的不同調(diào)用相應的handler , 接下來啟動nat 穿越模塊,設置stun 地址。然后調(diào)用tsip_transport_layer_start 啟動傳輸層線程,在sip 端口5060 接收數(shù)據(jù),最后,設置stack->started = tsk_true; 至此協(xié)議棧啟動完畢,各層在相應端口或狀態(tài)機上監(jiān)聽,不斷輪詢到來的事件并處理。
驅(qū)動過程:
協(xié)議棧啟動完畢后,對于每一個incoming 及outgoing 消息的 入口是不一樣的,下面分別分析對于呼入請求(incoming) 及外乎請求(outgoing) 的代碼流程。
a. 呼入請求
1 )客戶端傳輸層在5060 端口上接收到udp 包,語法層解析成識別的sip 消息后傳給事務層。
2 )事務層鎖住本地事務鏈表,根據(jù)sip 消息的 事務id 在事務鏈查找是否存在匹配的事務,沒有則創(chuàng)建。
3 )一旦找到事務或創(chuàng)建新事務完畢,釋放鎖并把消息傳遞到會話層。
4 )會話層收到sip 消息后查找會話鏈,找不到則創(chuàng)建會話,同時根據(jù)消息類型(invite, ack 等)設置此消息的狀態(tài)機,狀態(tài)機內(nèi)指定具體事件的回調(diào)。
b. 呼出請求
........
外部編程接口
為了在android 上層通過java 訪問doubango 核心,imsdroid 對doubango voip 框架做了面向?qū)ο蠓庋b,根據(jù)具體模塊功能抽象成具體Java 類供應用層使用,應用層通過jni 訪問doubango 核心,同時,在imsdroid 2.0 版本中,根據(jù)android 上應用層的架構抽象出一個類庫,doubango-ngn-stack, 利用此類庫我們可以在android 上自己開發(fā)一些客戶端應用程序,包括語音,視頻,即時通信,多媒體共享,會議等應用。Imsdroid 2.0 即是構建在 doubango-ngn-stack 上的一個具體應用。
Doubango-ngn-stack 原理
doubango-ngn-stack 是對doubango voip 框架的一個java 層封裝,內(nèi)部通過java 本地調(diào)用技術實現(xiàn)(jni), 這與android 上的框架設計是相符的( 如 java 類庫提供的攝像頭功能即依賴于底層驅(qū)動,上層通過jni 訪問底層驅(qū)動) ,
doubango/bindings/java
歡迎光臨 Chinaunix (http://www.72891.cn/) | Powered by Discuz! X3.2 |