沙愛軍,沈衛(wèi)康,毛其林
(南京工程學(xué)院通信工程學(xué)院,江蘇南京,211167)
SIP(Session Initiation Protocol)會(huì)話初始協(xié)議,最新的SIP 規(guī)范為RFC 3261。作為應(yīng)用層控制信令協(xié)議,SIP具有簡(jiǎn)單、靈活的特點(diǎn),正逐步取代H.323 協(xié)議成為 VoIP 的標(biāo)準(zhǔn)協(xié)議。
SIP 基于客戶機(jī)/服務(wù)器結(jié)構(gòu)。用戶代理(User Agent ),即SIP 終端,是SIP 系統(tǒng)中的最終用戶,可分為:用戶代理客戶端UAC,用于發(fā)起呼叫請(qǐng)求;用戶代理服務(wù)器UAS,用于響應(yīng)呼叫請(qǐng)求,一個(gè)終端往往既可以充當(dāng)UAC,也可以充當(dāng)UAS。
在一個(gè)VoIP網(wǎng)絡(luò)中,UA作為終端設(shè)備,需求大,而且對(duì)移動(dòng)便攜和價(jià)格也有要求。嵌入式設(shè)備具有便攜、專用、可裁剪、性價(jià)比等優(yōu)點(diǎn),本文將在嵌入式平臺(tái)上實(shí)現(xiàn)一個(gè)基于SIP的的語(yǔ)音電話終端,并對(duì)系統(tǒng)實(shí)現(xiàn)中所需的關(guān)鍵技術(shù)和工作過程進(jìn)行介紹。
需求分析可知,作為一個(gè)語(yǔ)音電話終端,需要如下幾個(gè)方面的功能:(1)要有音頻采集/播放設(shè)備以及相關(guān)的編解碼算法;(2)要有網(wǎng)卡處理設(shè)備,傳輸雙方的信令和音頻數(shù)據(jù);(3)要采用實(shí)時(shí)傳輸協(xié)議保證語(yǔ)音傳輸質(zhì)量。基于上述分析,系統(tǒng)的實(shí)現(xiàn)框架可設(shè)計(jì)如圖1,后面將具體闡述。
圖1 UA 實(shí)現(xiàn)框架
硬件平臺(tái)采用一款A(yù)RM開發(fā)板:CPU為三星公司生產(chǎn)的主頻可達(dá)400MHz的S3C2440A;音頻處理設(shè)備采用Philips公司生產(chǎn)的UDA1341TS,可實(shí)現(xiàn)A/D的相互轉(zhuǎn)換, S3C2440A 通過 L3接口可以控制和配置 UDA1341TS,L3 接口有 L3MODE、L3DATA和 L3CLOCK 三根信號(hào)線,音頻的驅(qū)動(dòng)采用OSS架構(gòu),類似其他驅(qū)動(dòng),音頻驅(qū)動(dòng)的實(shí)現(xiàn)分為初始化、打開設(shè)備、讀寫操作、設(shè)備查詢/控制、釋放設(shè)備和注銷設(shè)備等部分;開發(fā)板帶有網(wǎng)絡(luò)芯片DM9000,滿足聯(lián)網(wǎng)的要求;系統(tǒng)還帶有串口等其他設(shè)備。本次使用的內(nèi)核Linux-2.6.32.2 已經(jīng)能支持UDA1341 音頻芯片的驅(qū)動(dòng),但提供的是針對(duì)SMDK2440,SMDK2440的錄音通道,使用的是VIN1,而在本開發(fā)板使用的則是VIN2,因此需修改內(nèi)核驅(qū)動(dòng)linux-2.6.32.2/sound/soc/codecs/ uda134x.c中添加uda134x_write(codec, 2, 2|(5U<<2)),把錄音通道改為VIN2。
軟件平臺(tái)采用linux-2.6.32.2,Linux作為一種開源操作系統(tǒng),具有較高的穩(wěn)定和可移植性,可以根據(jù)需要進(jìn)行內(nèi)核、驅(qū)動(dòng)的裁剪配置,這里將TCP、UDP協(xié)議以及聲卡,網(wǎng)卡、串口等相關(guān)的驅(qū)動(dòng)配置進(jìn)去。
SIP協(xié)議作為會(huì)話控制協(xié)議,用來建立、修改和終止多媒體會(huì)話,其重要性不言而喻。這里對(duì)SIP再做點(diǎn)介紹。
SIP采用分層結(jié)構(gòu),最低層是語(yǔ)法和編碼,第2層是傳輸層,第3層是事務(wù)層。最上層是事務(wù)用戶。每個(gè)有狀態(tài)的SIP 實(shí)體,都是事務(wù)用戶,當(dāng)發(fā)送請(qǐng)求時(shí),將創(chuàng)建一個(gè)客戶端事務(wù)實(shí)例,并將請(qǐng)求與目的IP 地址、端口一起發(fā)送。SIP消息分為兩大類:請(qǐng)求(Request)和 響應(yīng)(Response。請(qǐng)求消息分為 6 種:REGISTER、INVITE、ACK、BYE、CANCEL、OPTIONS。響應(yīng)消息分為6類:1xx,2xx,3xx,4xx,5xx,6xx。其中1xx是臨時(shí)響應(yīng)(Provisional Response),其余是最終響應(yīng)(Final Response)。
目前符合RFC3261規(guī)范的開源SIP協(xié)議棧有OPAL,VOCAL,sipX ,oSIP[5]等,oSIP 結(jié)構(gòu)簡(jiǎn)單、功能齊全,可移植性好,因此本次選用了oSIP。
oSIP協(xié)議棧主要分為3大部分:狀態(tài)機(jī)模塊、解析器模塊、工具和對(duì)話模塊。其核心是狀態(tài)機(jī)模塊。狀態(tài)機(jī)有4種類型:ICT、IST、NICT以及 NST,對(duì)不同的事務(wù),oSIP用不同的狀態(tài)機(jī)處理,并推動(dòng)自身狀態(tài)的改變。解析器模塊主要完成對(duì)SIP 消息結(jié)構(gòu)剖析、SDP 消息的結(jié)構(gòu)剖析以及URI 結(jié)構(gòu)的剖析。工具模塊主要提供一些處理工具用于對(duì)話管理和SDP協(xié)商。
eXosip是對(duì)oSIP的擴(kuò)展,它對(duì)oSIP協(xié)議棧進(jìn)行了部分封裝,增加了registration、 call、dialog等過程的解析,使得調(diào)用接口更加友好,使用eXosip可以簡(jiǎn)化開發(fā)任務(wù)。
流媒體處理分為3個(gè)部分Mediastreamer2和ORTP以及編解碼算法。這3個(gè)本來是獨(dú)立的,由于它們相互協(xié)作處理用于處理音頻流,因此這里一起介紹。
Mediastreamer2負(fù)責(zé)媒體流的處理,采用純C開發(fā),是一個(gè)功能強(qiáng)大且小巧的流引擎,最小依賴只需oRTP和LIBC,可根據(jù)需要添加其他庫(kù),如SPEEX。Mediastreamer2媒體庫(kù)將語(yǔ)音模塊的工作分為幾大MSFilter實(shí)體:對(duì)聲卡的讀寫soundread/soundwrite,調(diào)用音頻庫(kù)的encode/decode,接收/發(fā)送RTP數(shù)據(jù)包的rtpsend/rtprecv等,利用函數(shù)指針將一系列的FILTER組合起來,多個(gè)MSFilter進(jìn)行連接,形成一個(gè)MSFilter chain。
oRTP負(fù)責(zé)流媒體如何安全可靠的傳輸,是用C語(yǔ)言編寫的RTP的開源協(xié)議棧,并且實(shí)現(xiàn)了RTCP,RTP在初始化的時(shí)候會(huì)對(duì)全局變量RtpProfile賦值,RtpProfile中的PayloadType數(shù)組的每個(gè)元素對(duì)應(yīng)一種媒體流,包括了名稱,采樣率,聲音位數(shù),靜音格式,占用帶寬等媒體流屬性。rtp_session_send_with_ts和rtp_session_recv_with_ts分別是oRTP發(fā)送和接收的主要函數(shù)。
語(yǔ)音壓縮編解碼算法很多,常見的有G.711PCM、GSM等算法,本次采用的G.711PCM算法,如需要更多算法,還可以使用SPEEX庫(kù)。
本次UA部分實(shí)現(xiàn)了注冊(cè)、呼叫、應(yīng)答、掛斷、退出 等電話呼叫的基本功能。UA主程序的流程圖如圖2示。
圖2 UA主流程圖
圖3 mysip_init()執(zhí)行流程圖
(1)系統(tǒng)首先調(diào)用add_port_set(),設(shè)置注冊(cè)時(shí)所用的注冊(cè)服務(wù)器地址和端口號(hào),通話時(shí)對(duì)端的sip url地址及本地sip端口和rtp端口號(hào)、用戶名和密碼等;然后調(diào)用mysip_init()。
(2)在mysip_init()中,進(jìn)行一系列初始化,見圖3。首先調(diào)用eXosip_init()對(duì)eXosip變量、osip庫(kù)初始化,設(shè)置回調(diào)函數(shù)以及傳輸方式;mysip_init()接著調(diào)用eXosip_listen_addr(),eXosip_listen_addr()則對(duì)開始監(jiān)聽sip端口,并執(zhí)行eXosip_execute ()去讀取各種osip事件,并進(jìn)行處理:對(duì)于要發(fā)送的message,管理程序會(huì)主動(dòng)調(diào)用接口發(fā)送,對(duì)于接收到的message,可能會(huì)創(chuàng)建新的call、新的transaction,生成新的transaction的event,還有exosip的event,其中exosip的event是上報(bào)給管理程序的;在mysip_init()中會(huì)創(chuàng)建一個(gè)新的線程ua_exosip來處理這些eXosip事件,為便于描述,在(3)中再討論這些事情,該線程創(chuàng)建后,會(huì)對(duì)UAC和UAS事件分別作出處理,見圖4;mysip_init()繼續(xù)完成初始化的調(diào)用ortp()和ms_init(),分別對(duì)oRTP協(xié)議棧和對(duì)Mediastreamer2初始化。
(3)ua_exosip()線程創(chuàng)建后就一直獨(dú)立運(yùn)行,在程序初始化完成后,它的運(yùn)行要和主程序的循環(huán)讀取用戶輸入的命令并做出響應(yīng)的運(yùn)行結(jié)合起來。
在ua_exosip中的exosip事件處理有很多,這里僅僅選取了UAS端收到的EXOSIP_CALL_INVITE, EXOSIP_CALL_ACK以及UAC端收到的EXOSIP_CALL_RINGING,EXOSIP_CALL_ANSWERED在圖4中展示。
(4)在主程序中進(jìn)入一個(gè)死循環(huán)中,循環(huán)中不斷讀取當(dāng)前輸入的命令,并根據(jù)命令的輸入,執(zhí)行相應(yīng)的處理函數(shù)。圖2中,列舉了一些常見的命令,當(dāng)輸入r時(shí),代表要向注冊(cè)服務(wù)器注冊(cè),將執(zhí)行函數(shù)sregister()完成此功能;當(dāng)輸入i時(shí),代表作為UAC,將執(zhí)行函數(shù)sinvite()發(fā)起一次呼叫;當(dāng)輸入a時(shí),代表作為UAS,將執(zhí)行函數(shù)sanswer()接聽電話;當(dāng)按下h時(shí),代表掛斷電話,將執(zhí)行shang();當(dāng)按下q時(shí),代表退出系統(tǒng),將執(zhí)行squit()。這里分別以UAC端的sinvite()和UAS端的sanswer()為例,介紹實(shí)現(xiàn)過程。
圖5為UAC端的sinvite()過程,由于這是一個(gè)呼叫發(fā)起請(qǐng)求,將主要調(diào)用eXosip_call_build_initial_invite(&invite, dest_call, source_call, NULL, "invite")和eXosip_call_send_initial_invite (invite)等,它們將構(gòu)造一個(gè)invite 請(qǐng)求信息,創(chuàng)建一個(gè)新的call,并為該invite創(chuàng)建一個(gè)新的transaction,創(chuàng)建完call和transaction后,會(huì)根據(jù)要發(fā)送的invite生成一個(gè)transaction的event,并將event添加到transaction的event隊(duì)列中,最后喚醒處理線程對(duì)transaction上的event處理。
圖6 為UAS端的sanswer()過程。當(dāng)接收方接聽一個(gè)電話時(shí),將向發(fā)起方發(fā)送200OK的信息,此時(shí)將建立起來一次dialog。但正式的通話要等到發(fā)起方發(fā)出ack信息之后。
(5)終端的運(yùn)行分析
結(jié)合圖4、圖5、圖6來分析一次執(zhí)行的過程。當(dāng)在主程序中輸入i命令時(shí),UAC將調(diào)用sinvite()發(fā)起一次呼叫,向接收端發(fā)送呼叫請(qǐng)求(INVITE),接收端UAS收到了來自EXOSIP層的EXOSIP_CALL_INVITE,則將執(zhí)行圖4中的EXOSIP_CALL_INVITE分支下的處理程序,顯示“收到來自xx的呼叫”,本地振鈴,發(fā)送“180”消息給UAC;當(dāng)UAC收到來自EXOSIP層的EXOSIP_CALL_RINGING時(shí),會(huì)顯示“對(duì)方已振鈴”;UAS端打算接聽電話,在主程序中輸入a命令,則調(diào)用sanswer()接聽,這里將進(jìn)行媒體協(xié)商,并發(fā)送200OK消息給UAC,表明已應(yīng)答,一次dialog建立;UAC收到來自EXOSIP報(bào)告的EXOSIP_CALL_ANSWERED,將“顯示對(duì)方已通話”,并構(gòu)建、發(fā)送ACK消息給UAS,獲取編碼方式,調(diào)用start_media()函數(shù)進(jìn)行媒體流的建立,為隨時(shí)準(zhǔn)備利用RTP傳輸通話語(yǔ)音;UAS收到來自EXOSIP報(bào)告的EXOSIP_CALL_ACK,將會(huì)顯示“通話開始”,同時(shí)調(diào)用start_media()函數(shù)進(jìn)行媒體流的建立。start_media()中將調(diào)用Mediastreamer2和oRTP來進(jìn)行音頻數(shù)據(jù)的RTP傳輸。
在移植好開發(fā)板所用的內(nèi)核和文件系統(tǒng)后,再交叉編譯libosip、libexosip、mediastream、ortp等庫(kù)和應(yīng)用程序myua.c等,得到可執(zhí)行文件myua,將可執(zhí)行文件和前述生成的動(dòng)態(tài)庫(kù)拷貝到開發(fā)板的相應(yīng)目錄下,就可以運(yùn)行。
圖4 ua_exosip中的exosip事件處理
圖5 UAC端的sinvite()過程
圖6 UAS端的sanswer()過程
系統(tǒng)的運(yùn)行環(huán)境:在一個(gè)局域網(wǎng)內(nèi),由一臺(tái)在ubuntu下運(yùn)行的brekeke sip sever擔(dān)任服務(wù)器,提供注冊(cè)員、代理服務(wù)、定位等功能;客戶端由兩個(gè)移植了UA的開發(fā)板組成,地址和用戶名見圖7。運(yùn)行時(shí),假設(shè)1002(此時(shí)擔(dān)當(dāng)UAC)向1001(此時(shí)擔(dān)當(dāng)UAS)發(fā)起呼叫:先將兩者分別運(yùn)行注冊(cè);再在1002上輸入i,則會(huì)發(fā)起一次呼叫;1001收到后輸入a應(yīng)答;1002收到發(fā)ACK則兩者建立語(yǔ)音通話。
圖7 系統(tǒng)的運(yùn)行環(huán)境
測(cè)試表明,局域網(wǎng)內(nèi)RTP包的丟包率為0,通話通話質(zhì)量較為清晰,通話情況良好。進(jìn)一步的工作可以實(shí)現(xiàn)視頻通話,增加SPEEX等語(yǔ)音編碼,使其能用于更多的場(chǎng)合。
[1]Rosenberg J.SIP: Session Initiation Protocol[S].RFC3261 ,IETF , 2002
[2]張遼.基于ARM 的嵌入式 IP 電話系統(tǒng)設(shè)計(jì)與實(shí)現(xiàn)[D].武漢:華中科技大學(xué),2012.1.
[3]劉剛,趙劍川.Linux系統(tǒng)移植 [M].北京: 清華大學(xué)出版社, 2011.1.
[4]友善之臂.Mini2440 之Linux 移植開發(fā)實(shí)戰(zhàn)指南[EB].http://www.arm9.net/.2010.04
[5]潘健等.基于Mediastreamer2的嵌入式語(yǔ)音終端的實(shí)現(xiàn)[J],湖北工業(yè)大學(xué)學(xué)報(bào),2012,27(5):48-51
[6]胡斌.VoIP系統(tǒng)中基于RTP/RTCP協(xié)議的語(yǔ)音及視頻傳輸?shù)脑O(shè)計(jì)與實(shí)現(xiàn)[D].廈門:廈門大學(xué),2009.05