這一陣子都在玩SIP的東東,也成功的把PJSIP porting在有DSP的板子上運作(板子上的DSP可以直接編解碼RTP,所以我修改PJSIP以便攔截RTP),而藉著PJSIP強大的函式庫,我的程式除了硬體控制的部份外,其它SIP控制的部份零零總總加起來可能連100行都不到,由此可見PJSIP封裝的能力,但難能可貴的是以下幾點
1.它實在很好移植-好像有網友已經把PJSIP擺在PSP上了
2.明確的程式架構-PJSIP的架構讓讀它的人很爽
3.詳細的說明文件-就是這點贏過oSIP,Sofia SIP…等

先來看看PJSIP的模組架構如下圖

由上圖中可知道PJSIP一共擁有10大模組,而從模組的描述可概略看出每個模組負責的功能,如PJNATH的功能就是做STUN,PJMEDIA-CODEC就是負責RTP編解碼,而最重要的部份就是PJSUA這個模組,它除了函蓋下面模組的功能外,也把這些模組的介面封裝成易懂易用的API給programmer快速開發softphone

我在這邊舉的pjsip-IM範例是用PJSIP-UA兜出來的測試程式碼,所以還沒用到PJSUA,不過可藉由這個的範例瞭解PJSIP對於INVITE,200 OK,ACK, BYE…等控制訊息的操作方式

SIP的transaction與dialog的概念圖如下,由下圖可知道,transaction 1包含了Invite,Ringing,OK與ACK, transaction 2包含了Bye與OK,而這兩段transaction同屬於一個dialog

PJSIP的程式架構與上面所提及的概念對應,請參考下圖

當TRANSPORT MANAGER收到SIP封包時,會把其內的SIP event通知上層的ENDPOINT,而ENDPOINT會找到對應的接收者,並把event傳給Transaction layer然後再傳給UA layer(傳遞的順序由每個模組的優先權決定), 如果UA layer的程式有指定要處理transaction的event,Transaction layer也會把解析後的event傳給UA layer,而UA處理事件的註冊方式請參考以下程式

static pjsip_module mod_simpleua =
{ 
NULL, NULL, /* prev, next. */ 
{ "mod-simpleua", 12 }, /* Name. */ 
-1, /* Id */ 
PJSIP_MOD_PRIORITY_APPLICATION, /* Priority */ 
NULL, /* load() */ 
NULL, /* start() */ 
NULL, /* stop() */ 
NULL, /* unload() */ 
&on_rx_request, /* on_rx_request() */ 
NULL, /* on_rx_response() */ 
NULL, /* on_tx_request. */ 
NULL, /* on_tx_response() */ 
NULL, /* on_tsx_state() */ 
};

我這邊傳遞訊息的範例就是做完transaction 1(Invite,OK,ACK)後,UAC與UAS可互傳訊息給對方(outside dialog),當要結束對話時,再作transaction 2(Bye,OK),詳細的內容請參考這份原始碼,編譯的方式請參考這篇文章

執行時先執行UAS,然後再執行UAC,執行UAC時請下命令參數uac sip:simpleuac@[your IP],就可以觀察uac與uas的連線情況,執行時如下圖

Cross compile pjsip的方法也很簡單,請參考我之前交叉編譯的文章,但configure後記得要更改build.mak這個檔案,把export CROSS_COMPILE :=改為arm-linux-,如果binary用static的方式連接PJSIP library,那傳訊息的範例程式大約為700多k,算是相當精簡了,但如果用PJSUA的library,可能會到1MB多

在我寫這篇文章時,PJSIP已經出了正式release的版本了,我覺得PJSIP的作者真是厲害,常常看到他晚上1,2點還在回mailing list,open source多了這位奇材,真是我們的福氣

最後修改日期: 3 6 月, 2022

作者

留言

撰寫回覆或留言

發佈留言必須填寫的電子郵件地址不會公開。