《電子技術(shù)應(yīng)用》
您所在的位置:首頁 > 通信與網(wǎng)絡(luò) > 設(shè)計(jì)應(yīng)用 > 基于Android的VoIP系統(tǒng)實(shí)現(xiàn)原理
基于Android的VoIP系統(tǒng)實(shí)現(xiàn)原理
OFweek電子工程網(wǎng)
摘要: 隨著我國(guó)三網(wǎng)融合的推進(jìn),VoIP與IPTV一起成為這一龐大工程的重要標(biāo)志。而目前手機(jī)中,VoIP的解決方案并不是很多,特別是在Google公司推出的開源操作系統(tǒng)Android中。
Abstract:
Key words :

  0 引言

  VoIP" title="VoIP">VoIP(Voice over Internet Protocol)即首先數(shù)字化語音信號(hào)并壓縮成幀,轉(zhuǎn)換為IP數(shù)據(jù)包在網(wǎng)絡(luò)上傳輸,以此完成語音通話的業(yè)務(wù),是一種利用IP協(xié)議傳輸語音數(shù)據(jù)的、新興的通信技術(shù)。

  隨著我國(guó)三網(wǎng)融合" title="三網(wǎng)融合">三網(wǎng)融合的推進(jìn),VoIP與IPTV(Interactive Personality TV)一起成為這一龐大工程的重要標(biāo)志。而目前手機(jī)中,VoIP的解決方案并不是很多,特別是在Google公司推出的開源操作系統(tǒng)Android" title="Android">Android中。盡管該系統(tǒng)推出時(shí)間不長(zhǎng),憑借強(qiáng)大的功能、良好的界面、廣泛的商業(yè)支持,為用戶帶來很好的體驗(yàn),成為2010年最熱門且發(fā)展最快的手機(jī)操作系統(tǒng)。因此,兩者的結(jié)合,將是未來的發(fā)展趨勢(shì)。本文提出一種基于PJSIP協(xié)議棧的解決方案,通過Android本地開發(fā)工具(NDK),實(shí)現(xiàn)一個(gè)高效、穩(wěn)定且功能強(qiáng)大的VoIP系統(tǒng),具有較高的參考和實(shí)用價(jià)值。

  1 VoIP設(shè)計(jì)方案

  1.1 設(shè)計(jì)目標(biāo)

  本方案所設(shè)計(jì)的系統(tǒng)包含以下功能:首先,完成用戶終端(如手機(jī))中語音數(shù)據(jù)的采集與編碼,并通過RTP(實(shí)時(shí)傳輸協(xié)議)/RTCP(RTP傳輸控制協(xié)議)進(jìn)行傳輸和控制;其次,完成會(huì)話的控制,包括會(huì)話的注冊(cè)、發(fā)起、維護(hù)與結(jié)束、注銷等;再次,作為一個(gè)應(yīng)用程序,必須實(shí)現(xiàn)一個(gè)良好的界面,與用戶交互;最后,作為一個(gè)開放系統(tǒng),需具有良好的可擴(kuò)展性。

  1.2 總體設(shè)計(jì)

  本方案基本上符合Android的NDK框架的開發(fā)規(guī)范,將系統(tǒng)分為4層,如圖1所示。最上層為應(yīng)用層,該層將在Android SDK的框架內(nèi),采用Java語言來實(shí)現(xiàn);第二層為JNI層,SIP協(xié)議棧有很多種實(shí)現(xiàn),其中,采用C語言的SIP協(xié)議棧在效率、速度、系統(tǒng)占用方面有著超越其他庫(如Java協(xié)議棧)的優(yōu)勢(shì),因此,該方案將在第三層采用純C語言實(shí)現(xiàn)的PJSIP協(xié)議棧。為了讓Java應(yīng)用層能調(diào)用協(xié)議棧層,在兩層之間需要一個(gè)銜接的橋梁,這就是JNI層。最后一層是驅(qū)動(dòng)層,這部分一般是由手機(jī)廠商來實(shí)現(xiàn)的,本文將不做重點(diǎn)介紹。

  

  2 VoIP的具體實(shí)現(xiàn)

  這里將實(shí)現(xiàn)一個(gè)完整的VoIP系統(tǒng),包括協(xié)議棧的實(shí)現(xiàn)、JNI的編寫以及上層UI的設(shè)計(jì)實(shí)現(xiàn)等。

  2.1 SIP協(xié)議棧及UA

  SIP協(xié)議棧直接關(guān)系到整個(gè)系統(tǒng)的質(zhì)量與效率,本文將采用純C語言開發(fā)的PJSIP庫。該庫采用C語言開發(fā),且源碼開放,在兼容性與效率上有明顯優(yōu)勢(shì),不僅體積小(完整的SIP封裝也不過150 KB),同時(shí)還實(shí)現(xiàn)了一個(gè)內(nèi)存池,使得安全系數(shù)與運(yùn)行效率大為提高,該系統(tǒng)所采用的就是優(yōu)化后的PJSIP庫。

  2.1.1 PJSIP協(xié)議棧

  PJSIP協(xié)議棧遵循標(biāo)準(zhǔn)的SIP協(xié)議,采用分層架構(gòu):SIP/SDP消息編碼解析層、傳輸管理層、SIP終端、事務(wù)層、會(huì)話層以及應(yīng)用層等。由于SIP協(xié)議采用文本消息發(fā)送請(qǐng)求和響應(yīng),所以首先需要將SIP消息按照巴斯克范式(ABNF)編碼和解析,這就是SIP/SDP消息編碼解析層所完成的功能。傳輸管理層用來管理用戶代理與服務(wù)器之間的請(qǐng)求和相應(yīng);SIP終端是PJSIP中轉(zhuǎn)機(jī)制的實(shí)現(xiàn),它主要負(fù)責(zé)管理各個(gè)SIP組建,例如像SIP終端實(shí)例注冊(cè)組件,分發(fā)消息到事務(wù)層、會(huì)話層及應(yīng)用層,回傳處理結(jié)果,管理定時(shí)器、I/O隊(duì)列等;事務(wù)層通過狀態(tài)機(jī)機(jī)制管理SIP信令,每一次狀態(tài)機(jī)狀態(tài)的改變都將觸發(fā)回調(diào)函數(shù);會(huì)話層負(fù)責(zé)會(huì)話的發(fā)起與響應(yīng),一般與應(yīng)用層結(jié)合在一起,用于用戶交互,不同的平臺(tái)有不同的實(shí)現(xiàn),本文使用Andriod的GUI來實(shí)現(xiàn)。

  PJSIP是一個(gè)高度封裝的庫,實(shí)際上它是通過PJSUA子庫來實(shí)現(xiàn)應(yīng)用的。一個(gè)完整的PJSUA生命周期,首先需要初始化,通過函數(shù)init()來實(shí)現(xiàn)。在這個(gè)函數(shù)中,將創(chuàng)建代理、初始化變量和堆棧,以及創(chuàng)建一個(gè)UDP傳輸并在最后啟動(dòng)代理;第二步將為UA添加用戶,如果需要的話,還要向服務(wù)器注冊(cè)用戶;當(dāng)用戶添加成功后,此時(shí)可以建立一個(gè)呼叫連接,發(fā)起會(huì)話;當(dāng)會(huì)話連接成功后,就可以使用SRTP協(xié)議實(shí)時(shí)傳輸加密后的數(shù)據(jù),進(jìn)行通話。最后的過程是掛起或銷毀呼叫。

  2.1.2 UA原理

  UA(User Agency)是協(xié)議棧的具體實(shí)現(xiàn),PJSIP通過封裝了的PJSUA來實(shí)現(xiàn),在這一點(diǎn)上,大部分的SIP庫都大同小異,在此將介紹UA的工作原理。

  一個(gè)典型的UA包含UAC(User Agency Client)和UAS(User Agency Server)兩部分。會(huì)話由UAC發(fā)起。當(dāng)呼叫發(fā)起時(shí),UAC將首先發(fā)送“IN-VITE”消息給SIP代理服務(wù)器,服務(wù)器收到“INVITE”消息后將返回一個(gè)應(yīng)答“200 OK”,并回答“ACK”進(jìn)行確認(rèn),同時(shí)通知主叫用戶(即會(huì)話發(fā)起用戶)上線通話。如果主叫端(用戶端)主動(dòng)結(jié)束會(huì)話,UAC將返回“BYE”消息,同時(shí)通知服務(wù)器;如果用戶端收到服務(wù)器傳來的“BY-E”消息,回答“200”,并結(jié)束會(huì)話。

  服務(wù)器端,UAS收到UAC(用戶端)發(fā)來的“INVITE”消息,首先從消息中提取出主、被叫對(duì)象,然后檢查當(dāng)前是否有空閑信道,若沒有則返回“486 BUSY HERE”(即系統(tǒng)忙)消息;接著將檢查被叫用戶是否在服務(wù)區(qū),如果被叫對(duì)象不在服務(wù)范圍,則返回“404 NOT FOUND”(即用戶不在服務(wù)區(qū));若被叫用戶成功上線,則返回“200 OK”,同時(shí)準(zhǔn)備開始會(huì)話。

  SIP協(xié)議棧一般使用SIP統(tǒng)一資源定位符(URL)來標(biāo)識(shí),它根據(jù)URL來尋址,如集群用戶“200”,“300”分別對(duì)應(yīng)SIP用戶為“200@192.168. 1.100”,“300@192.168.1.100”。本文中也使用這種方式來測(cè)試通信。

  2.2 JNI的實(shí)現(xiàn)

  PJSIP庫和Java類連接是通過JNI來實(shí)現(xiàn)的,這也是Android NDK的實(shí)現(xiàn)機(jī)制,JNI是SUN公司推出的用于Java調(diào)用其他語言的接口。

  首先需要一個(gè)中間類,這個(gè)類中主要建立一些方法用于調(diào)用C/C++本地函數(shù)。它們的類型均為“publicstatic native int”,以便其他的Java類能夠調(diào)用。

  2.2.1 新建PJSIP類

  為各個(gè)待實(shí)現(xiàn)的類新建一個(gè)包,可以命名為“com.a(chǎn)ndroid.VoIP.pjsip”,在該包中添加該系統(tǒng)相關(guān)的一些類,主要有如下6個(gè)類:

  

  這些類分別為上節(jié)中原理各個(gè)步驟的實(shí)現(xiàn)。這部分僅僅是為C庫的調(diào)用提供一個(gè)接口,因此具體的實(shí)現(xiàn)將放在本地C/C++程序中。

  2.2.2 頭文件的生成

  C庫與Java間還需通過一個(gè)后綴為“.h”的頭文件來銜接,這個(gè)頭文件可以手動(dòng)編寫,也可以通過“Javah”來生成,該工具包含在JDK中,是由SUN公司提供的。

  Javah生產(chǎn)的頭文件包含一定的規(guī)則,例如,本例中,它將生成的函數(shù)聲明為“Java_com_android_IMSandroid_pjsip_**”的形式,以便在調(diào)用C庫時(shí)能正確識(shí)別。

  由于Java中的數(shù)據(jù)類型與C/C++不盡相同,因此還必須注意參數(shù)傳遞時(shí)參數(shù)類型的轉(zhuǎn)換。本文所涉及到的Java數(shù)據(jù)類型有String和int型,Javah生成的頭文件中會(huì)先定義好需要傳遞的參數(shù)類型以及函數(shù)返回類型,例如方法“add_account(String sip_user,Stringsip_dom-ain,String sip_passwd)”,在頭文件中將定義函數(shù)的形式為“JNIEXPORT jint JNICALL Java_com_android_IMSandroid_pjsip_add_lac-count(JNIEnv*,jclass,jstring,jstring,jstring)”,其中JNIEXPORT為JNI外部函數(shù)聲明,jint是“jni.h”中定義C語言中整形的對(duì)應(yīng)類型,JNCALL是JNI關(guān)鍵字。比較特殊的是JNIEnv,它是一個(gè)指向類型為JNIEnv_的一個(gè)特殊JNI數(shù)據(jù)結(jié)構(gòu)的指針,它的每個(gè)元素都指向一個(gè)JNI函數(shù)的指針,jclass會(huì)根據(jù)引用Java類的不同而不同,本文中“pjsip.class”是靜態(tài)類,因此這里的jclass指的是類本身,如果是非靜態(tài)類則指的是對(duì)象。后面幾個(gè)就是pjsip類需要傳遞的參數(shù),根據(jù)“jni.h”的定義,String類型對(duì)應(yīng)jstring,int對(duì)應(yīng)jint。然而這只是函數(shù)申明與類中方法的形式對(duì)應(yīng),參數(shù)的具體傳遞還需要相應(yīng)的轉(zhuǎn)化,具體實(shí)現(xiàn)將在下一節(jié)詳細(xì)介紹。

  2.2.3 JNI接口函數(shù)的實(shí)現(xiàn)

  創(chuàng)建了pjsip庫類和頭文件之后,必須應(yīng)用一個(gè)庫接口函數(shù),這部分是pjsip接口的實(shí)現(xiàn),限于篇幅,本文只講解幾個(gè)重要函數(shù)的實(shí)現(xiàn)。

  (1)init函數(shù)

  首先是init函數(shù),對(duì)應(yīng)的接口函數(shù)為JNICALL Java_com_android_IMSandroid_pjsip_init。該函數(shù)在系統(tǒng)初始化時(shí)調(diào)用,其作用是配置相關(guān)參數(shù),并發(fā)起一個(gè)pjsua應(yīng)用。它先通過函數(shù)“pjsua_create()”創(chuàng)建一個(gè)“pjsua”應(yīng)用,然后通過三個(gè)函數(shù)“pjsua_config_default(&cfg)”,“pjsua_logging_config_default(&log_cfg”),“pjsua_media_config_default(&media_cfg)”配置其相關(guān)參數(shù),其中cfg是pjsua的相關(guān)參數(shù),主要是狀態(tài)改變時(shí)的回調(diào)函數(shù);log_cfg用來配置log級(jí)別;media_cfg中包含時(shí)鐘頻率、聲道數(shù)目等相關(guān)參數(shù)。

  完成配置之后就可以使用pjsua_init(&cfg,&log_cfg,&media_cfg)將先前配置的參數(shù)初始化。在初始化之后,還需為pjsua添加一個(gè)udp傳輸,這一步是通過pjsua_transport_create(PJSIP_TRANSPORT_UDP,&cfg,NULL)來實(shí)現(xiàn)的,cfg中包含指定的通訊端口,3GPP建議使用5060。

  需要注意的是,配置完以上參數(shù)之后,還需指定SPEEX編碼優(yōu)先級(jí),一般將其設(shè)為最大,可以通過函數(shù)pisua_codec_set_priority(&-speex_codec_id,255)來實(shí)現(xiàn)。所有配置完成之后,就可以發(fā)起pjsua,即最后調(diào)用pjsua_start()。成功的話,本函數(shù)的返回類型為PJ_SUCCESS。

  (2)make_call函數(shù)

  另一個(gè)很重要的函數(shù)是make_call,其在本接口文件中對(duì)應(yīng)的函數(shù)為Java_com_Android_IMSandroid_pjsip_make_lcall,這個(gè)函數(shù)一般在發(fā)起會(huì)話時(shí)調(diào)用,它與上一個(gè)函數(shù)在結(jié)構(gòu)上最大的不同在于本函數(shù)需要傳遞一個(gè)字符串參數(shù),前面提到,Java與C/C++在參數(shù)結(jié)構(gòu)上并不完全相同,因此這里需要將Java傳遞過來的String類型的參數(shù)轉(zhuǎn)化,可以通過“url_ptr=(char*)env-》GetStringUTFChars(url,&iscopy)”來實(shí)現(xiàn)。env-》GetStringUTFChars在“jni.h”中定義,其功能是將jsting類型(Java)的url復(fù)制到char*類型(C)的url_ptr中,以此來完成參數(shù)類型的轉(zhuǎn)換。

  為了保證傳遞地址的有效性,還需要使用pjsua_verify_sip_url(url_ptr)驗(yàn)證,這個(gè)函數(shù)主要驗(yàn)證url_ptr是符合SIP的規(guī)則,即是否是一個(gè)合法的SIP地址。然而char*型的地址pjsua中還是不能直接使用的,這是因?yàn)閜jsua重新封裝了參數(shù)類型,所以最后還需要將其轉(zhuǎn)化成pj_ str_t類型,pjlib提供pj_str()函數(shù)可以完成轉(zhuǎn)化。在完成了參數(shù)的轉(zhuǎn)化后,調(diào)用“pjsua_call_make_call()”,將發(fā)起會(huì)話。

  (3)hangup函數(shù)和pjsua_destroy函數(shù)

  這兩個(gè)函數(shù)用來銷毀和掛斷會(huì)話,一般在需結(jié)束的時(shí)候調(diào)用,它們?cè)诮涌诤瘮?shù)中對(duì)應(yīng)Java_com_android_

  IMSandroid_pjsip_hangup和Java_com_android_IMSandroid_pjsip_destroy,由于沒有參數(shù)傳遞,也沒有其他的調(diào)用,因此這兩個(gè)函數(shù)非常簡(jiǎn)單,基本上直接調(diào)用pjsua提供的pjsua_call_hangup_all()和pjsua_destroy()就能實(shí)現(xiàn)。pisua中這兩個(gè)函數(shù)將完成內(nèi)存釋放、賬戶注銷等工作。

  (4)add_account函數(shù)

  該函數(shù)在基本的pjsua中并不是必須的,但如果要使用SIP服務(wù)器的話,就必須實(shí)現(xiàn)該函數(shù),它在接口函數(shù)中對(duì)應(yīng)“Java_com_android_I-MSandroid_pjsip_add_1account”,同“make_call”一樣,也需要傳遞參數(shù),不同的是,它傳遞三個(gè)參數(shù),只是原理大體一樣。

  首先它將參數(shù)轉(zhuǎn)化后保持到cfg,通過“pjsua_acc_add(&cfg,PJ_TRUE,&ace_id)”將參數(shù)添加到pjsua。pjsua將以其中的sip服務(wù)器為目的地址,注冊(cè)會(huì)話發(fā)起申請(qǐng),經(jīng)過一系列的操作之后,與目的地址發(fā)起會(huì)話。

  0 引言

  VoIP(Voice over Internet Protocol)即首先數(shù)字化語音信號(hào)并壓縮成幀,轉(zhuǎn)換為IP數(shù)據(jù)包在網(wǎng)絡(luò)上傳輸,以此完成語音通話的業(yè)務(wù),是一種利用IP協(xié)議傳輸語音數(shù)據(jù)的、新興的通信技術(shù)。

  隨著我國(guó)三網(wǎng)融合的推進(jìn),VoIP與IPTV(Interactive Personality TV)一起成為這一龐大工程的重要標(biāo)志。而目前手機(jī)中,VoIP的解決方案并不是很多,特別是在Google公司推出的開源操作系統(tǒng)Android中。盡管該系統(tǒng)推出時(shí)間不長(zhǎng),憑借強(qiáng)大的功能、良好的界面、廣泛的商業(yè)支持,為用戶帶來很好的體驗(yàn),成為2010年最熱門且發(fā)展最快的手機(jī)操作系統(tǒng)。因此,兩者的結(jié)合,將是未來的發(fā)展趨勢(shì)。本文提出一種基于PJSIP協(xié)議棧的解決方案,通過Android本地開發(fā)工具(NDK),實(shí)現(xiàn)一個(gè)高效、穩(wěn)定且功能強(qiáng)大的VoIP系統(tǒng),具有較高的參考和實(shí)用價(jià)值。

  1 VoIP設(shè)計(jì)方案

  1.1 設(shè)計(jì)目標(biāo)

  本方案所設(shè)計(jì)的系統(tǒng)包含以下功能:首先,完成用戶終端(如手機(jī))中語音數(shù)據(jù)的采集與編碼,并通過RTP(實(shí)時(shí)傳輸協(xié)議)/RTCP(RTP傳輸控制協(xié)議)進(jìn)行傳輸和控制;其次,完成會(huì)話的控制,包括會(huì)話的注冊(cè)、發(fā)起、維護(hù)與結(jié)束、注銷等;再次,作為一個(gè)應(yīng)用程序,必須實(shí)現(xiàn)一個(gè)良好的界面,與用戶交互;最后,作為一個(gè)開放系統(tǒng),需具有良好的可擴(kuò)展性。

  1.2 總體設(shè)計(jì)

  本方案基本上符合Android的NDK框架的開發(fā)規(guī)范,將系統(tǒng)分為4層,如圖1所示。最上層為應(yīng)用層,該層將在Android SDK的框架內(nèi),采用Java語言來實(shí)現(xiàn);第二層為JNI層,SIP協(xié)議棧有很多種實(shí)現(xiàn),其中,采用C語言的SIP協(xié)議棧在效率、速度、系統(tǒng)占用方面有著超越其他庫(如Java協(xié)議棧)的優(yōu)勢(shì),因此,該方案將在第三層采用純C語言實(shí)現(xiàn)的PJSIP協(xié)議棧。為了讓Java應(yīng)用層能調(diào)用協(xié)議棧層,在兩層之間需要一個(gè)銜接的橋梁,這就是JNI層。最后一層是驅(qū)動(dòng)層,這部分一般是由手機(jī)廠商來實(shí)現(xiàn)的,本文將不做重點(diǎn)介紹。

  

  2 VoIP的具體實(shí)現(xiàn)

  這里將實(shí)現(xiàn)一個(gè)完整的VoIP系統(tǒng),包括協(xié)議棧的實(shí)現(xiàn)、JNI的編寫以及上層UI的設(shè)計(jì)實(shí)現(xiàn)等。

  2.1 SIP協(xié)議棧及UA

  SIP協(xié)議棧直接關(guān)系到整個(gè)系統(tǒng)的質(zhì)量與效率,本文將采用純C語言開發(fā)的PJSIP庫。該庫采用C語言開發(fā),且源碼開放,在兼容性與效率上有明顯優(yōu)勢(shì),不僅體積小(完整的SIP封裝也不過150 KB),同時(shí)還實(shí)現(xiàn)了一個(gè)內(nèi)存池,使得安全系數(shù)與運(yùn)行效率大為提高,該系統(tǒng)所采用的就是優(yōu)化后的PJSIP庫。

  2.1.1 PJSIP協(xié)議棧

  PJSIP協(xié)議棧遵循標(biāo)準(zhǔn)的SIP協(xié)議,采用分層架構(gòu):SIP/SDP消息編碼解析層、傳輸管理層、SIP終端、事務(wù)層、會(huì)話層以及應(yīng)用層等。由于SIP協(xié)議采用文本消息發(fā)送請(qǐng)求和響應(yīng),所以首先需要將SIP消息按照巴斯克范式(ABNF)編碼和解析,這就是SIP/SDP消息編碼解析層所完成的功能。傳輸管理層用來管理用戶代理與服務(wù)器之間的請(qǐng)求和相應(yīng);SIP終端是PJSIP中轉(zhuǎn)機(jī)制的實(shí)現(xiàn),它主要負(fù)責(zé)管理各個(gè)SIP組建,例如像SIP終端實(shí)例注冊(cè)組件,分發(fā)消息到事務(wù)層、會(huì)話層及應(yīng)用層,回傳處理結(jié)果,管理定時(shí)器、I/O隊(duì)列等;事務(wù)層通過狀態(tài)機(jī)機(jī)制管理SIP信令,每一次狀態(tài)機(jī)狀態(tài)的改變都將觸發(fā)回調(diào)函數(shù);會(huì)話層負(fù)責(zé)會(huì)話的發(fā)起與響應(yīng),一般與應(yīng)用層結(jié)合在一起,用于用戶交互,不同的平臺(tái)有不同的實(shí)現(xiàn),本文使用Andriod的GUI來實(shí)現(xiàn)。

  PJSIP是一個(gè)高度封裝的庫,實(shí)際上它是通過PJSUA子庫來實(shí)現(xiàn)應(yīng)用的。一個(gè)完整的PJSUA生命周期,首先需要初始化,通過函數(shù)init()來實(shí)現(xiàn)。在這個(gè)函數(shù)中,將創(chuàng)建代理、初始化變量和堆棧,以及創(chuàng)建一個(gè)UDP傳輸并在最后啟動(dòng)代理;第二步將為UA添加用戶,如果需要的話,還要向服務(wù)器注冊(cè)用戶;當(dāng)用戶添加成功后,此時(shí)可以建立一個(gè)呼叫連接,發(fā)起會(huì)話;當(dāng)會(huì)話連接成功后,就可以使用SRTP協(xié)議實(shí)時(shí)傳輸加密后的數(shù)據(jù),進(jìn)行通話。最后的過程是掛起或銷毀呼叫。

  2.1.2 UA原理

  UA(User Agency)是協(xié)議棧的具體實(shí)現(xiàn),PJSIP通過封裝了的PJSUA來實(shí)現(xiàn),在這一點(diǎn)上,大部分的SIP庫都大同小異,在此將介紹UA的工作原理。

  一個(gè)典型的UA包含UAC(User Agency Client)和UAS(User Agency Server)兩部分。會(huì)話由UAC發(fā)起。當(dāng)呼叫發(fā)起時(shí),UAC將首先發(fā)送“IN-VITE”消息給SIP代理服務(wù)器,服務(wù)器收到“INVITE”消息后將返回一個(gè)應(yīng)答“200 OK”,并回答“ACK”進(jìn)行確認(rèn),同時(shí)通知主叫用戶(即會(huì)話發(fā)起用戶)上線通話。如果主叫端(用戶端)主動(dòng)結(jié)束會(huì)話,UAC將返回“BYE”消息,同時(shí)通知服務(wù)器;如果用戶端收到服務(wù)器傳來的“BY-E”消息,回答“200”,并結(jié)束會(huì)話。

  服務(wù)器端,UAS收到UAC(用戶端)發(fā)來的“INVITE”消息,首先從消息中提取出主、被叫對(duì)象,然后檢查當(dāng)前是否有空閑信道,若沒有則返回“486 BUSY HERE”(即系統(tǒng)忙)消息;接著將檢查被叫用戶是否在服務(wù)區(qū),如果被叫對(duì)象不在服務(wù)范圍,則返回“404 NOT FOUND”(即用戶不在服務(wù)區(qū));若被叫用戶成功上線,則返回“200 OK”,同時(shí)準(zhǔn)備開始會(huì)話。

  SIP協(xié)議棧一般使用SIP統(tǒng)一資源定位符(URL)來標(biāo)識(shí),它根據(jù)URL來尋址,如集群用戶“200”,“300”分別對(duì)應(yīng)SIP用戶為“200@192.168. 1.100”,“300@192.168.1.100”。本文中也使用這種方式來測(cè)試通信。

  2.2 JNI的實(shí)現(xiàn)

  PJSIP庫和Java類連接是通過JNI來實(shí)現(xiàn)的,這也是Android NDK的實(shí)現(xiàn)機(jī)制,JNI是SUN公司推出的用于Java調(diào)用其他語言的接口。

  首先需要一個(gè)中間類,這個(gè)類中主要建立一些方法用于調(diào)用C/C++本地函數(shù)。它們的類型均為“publicstatic native int”,以便其他的Java類能夠調(diào)用。

  2.2.1 新建PJSIP類

  為各個(gè)待實(shí)現(xiàn)的類新建一個(gè)包,可以命名為“com.a(chǎn)ndroid.VoIP.pjsip”,在該包中添加該系統(tǒng)相關(guān)的一些類,主要有如下6個(gè)類:

  

  這些類分別為上節(jié)中原理各個(gè)步驟的實(shí)現(xiàn)。這部分僅僅是為C庫的調(diào)用提供一個(gè)接口,因此具體的實(shí)現(xiàn)將放在本地C/C++程序中。

  2.2.2 頭文件的生成

  C庫與Java間還需通過一個(gè)后綴為“.h”的頭文件來銜接,這個(gè)頭文件可以手動(dòng)編寫,也可以通過“Javah”來生成,該工具包含在JDK中,是由SUN公司提供的。

  Javah生產(chǎn)的頭文件包含一定的規(guī)則,例如,本例中,它將生成的函數(shù)聲明為“Java_com_android_IMSandroid_pjsip_**”的形式,以便在調(diào)用C庫時(shí)能正確識(shí)別。

  由于Java中的數(shù)據(jù)類型與C/C++不盡相同,因此還必須注意參數(shù)傳遞時(shí)參數(shù)類型的轉(zhuǎn)換。本文所涉及到的Java數(shù)據(jù)類型有String和int型,Javah生成的頭文件中會(huì)先定義好需要傳遞的參數(shù)類型以及函數(shù)返回類型,例如方法“add_account(String sip_user,Stringsip_dom-ain,String sip_passwd)”,在頭文件中將定義函數(shù)的形式為“JNIEXPORT jint JNICALL Java_com_android_IMSandroid_pjsip_add_lac-count(JNIEnv*,jclass,jstring,jstring,jstring)”,其中JNIEXPORT為JNI外部函數(shù)聲明,jint是“jni.h”中定義C語言中整形的對(duì)應(yīng)類型,JNCALL是JNI關(guān)鍵字。比較特殊的是JNIEnv,它是一個(gè)指向類型為JNIEnv_的一個(gè)特殊JNI數(shù)據(jù)結(jié)構(gòu)的指針,它的每個(gè)元素都指向一個(gè)JNI函數(shù)的指針,jclass會(huì)根據(jù)引用Java類的不同而不同,本文中“pjsip.class”是靜態(tài)類,因此這里的jclass指的是類本身,如果是非靜態(tài)類則指的是對(duì)象。后面幾個(gè)就是pjsip類需要傳遞的參數(shù),根據(jù)“jni.h”的定義,String類型對(duì)應(yīng)jstring,int對(duì)應(yīng)jint。然而這只是函數(shù)申明與類中方法的形式對(duì)應(yīng),參數(shù)的具體傳遞還需要相應(yīng)的轉(zhuǎn)化,具體實(shí)現(xiàn)將在下一節(jié)詳細(xì)介紹。

  2.2.3 JNI接口函數(shù)的實(shí)現(xiàn)

  創(chuàng)建了pjsip庫類和頭文件之后,必須應(yīng)用一個(gè)庫接口函數(shù),這部分是pjsip接口的實(shí)現(xiàn),限于篇幅,本文只講解幾個(gè)重要函數(shù)的實(shí)現(xiàn)。

  (1)init函數(shù)

  首先是init函數(shù),對(duì)應(yīng)的接口函數(shù)為JNICALL Java_com_android_IMSandroid_pjsip_init。該函數(shù)在系統(tǒng)初始化時(shí)調(diào)用,其作用是配置相關(guān)參數(shù),并發(fā)起一個(gè)pjsua應(yīng)用。它先通過函數(shù)“pjsua_create()”創(chuàng)建一個(gè)“pjsua”應(yīng)用,然后通過三個(gè)函數(shù)“pjsua_config_default(&cfg)”,“pjsua_logging_config_default(&log_cfg”),“pjsua_media_config_default(&media_cfg)”配置其相關(guān)參數(shù),其中cfg是pjsua的相關(guān)參數(shù),主要是狀態(tài)改變時(shí)的回調(diào)函數(shù);log_cfg用來配置log級(jí)別;media_cfg中包含時(shí)鐘頻率、聲道數(shù)目等相關(guān)參數(shù)。

  完成配置之后就可以使用pjsua_init(&cfg,&log_cfg,&media_cfg)將先前配置的參數(shù)初始化。在初始化之后,還需為pjsua添加一個(gè)udp傳輸,這一步是通過pjsua_transport_create(PJSIP_TRANSPORT_UDP,&cfg,NULL)來實(shí)現(xiàn)的,cfg中包含指定的通訊端口,3GPP建議使用5060。

  需要注意的是,配置完以上參數(shù)之后,還需指定SPEEX編碼優(yōu)先級(jí),一般將其設(shè)為最大,可以通過函數(shù)pisua_codec_set_priority(&-speex_codec_id,255)來實(shí)現(xiàn)。所有配置完成之后,就可以發(fā)起pjsua,即最后調(diào)用pjsua_start()。成功的話,本函數(shù)的返回類型為PJ_SUCCESS。

  (2)make_call函數(shù)

  另一個(gè)很重要的函數(shù)是make_call,其在本接口文件中對(duì)應(yīng)的函數(shù)為Java_com_Android_IMSandroid_pjsip_make_lcall,這個(gè)函數(shù)一般在發(fā)起會(huì)話時(shí)調(diào)用,它與上一個(gè)函數(shù)在結(jié)構(gòu)上最大的不同在于本函數(shù)需要傳遞一個(gè)字符串參數(shù),前面提到,Java與C/C++在參數(shù)結(jié)構(gòu)上并不完全相同,因此這里需要將Java傳遞過來的String類型的參數(shù)轉(zhuǎn)化,可以通過“url_ptr=(char*)env-》GetStringUTFChars(url,&iscopy)”來實(shí)現(xiàn)。env-》GetStringUTFChars在“jni.h”中定義,其功能是將jsting類型(Java)的url復(fù)制到char*類型(C)的url_ptr中,以此來完成參數(shù)類型的轉(zhuǎn)換。

  為了保證傳遞地址的有效性,還需要使用pjsua_verify_sip_url(url_ptr)驗(yàn)證,這個(gè)函數(shù)主要驗(yàn)證url_ptr是符合SIP的規(guī)則,即是否是一個(gè)合法的SIP地址。然而char*型的地址pjsua中還是不能直接使用的,這是因?yàn)閜jsua重新封裝了參數(shù)類型,所以最后還需要將其轉(zhuǎn)化成pj_ str_t類型,pjlib提供pj_str()函數(shù)可以完成轉(zhuǎn)化。在完成了參數(shù)的轉(zhuǎn)化后,調(diào)用“pjsua_call_make_call()”,將發(fā)起會(huì)話。

  (3)hangup函數(shù)和pjsua_destroy函數(shù)

  這兩個(gè)函數(shù)用來銷毀和掛斷會(huì)話,一般在需結(jié)束的時(shí)候調(diào)用,它們?cè)诮涌诤瘮?shù)中對(duì)應(yīng)Java_com_android_

  IMSandroid_pjsip_hangup和Java_com_android_IMSandroid_pjsip_destroy,由于沒有參數(shù)傳遞,也沒有其他的調(diào)用,因此這兩個(gè)函數(shù)非常簡(jiǎn)單,基本上直接調(diào)用pjsua提供的pjsua_call_hangup_all()和pjsua_destroy()就能實(shí)現(xiàn)。pisua中這兩個(gè)函數(shù)將完成內(nèi)存釋放、賬戶注銷等工作。

  (4)add_account函數(shù)

  該函數(shù)在基本的pjsua中并不是必須的,但如果要使用SIP服務(wù)器的話,就必須實(shí)現(xiàn)該函數(shù),它在接口函數(shù)中對(duì)應(yīng)“Java_com_android_I-MSandroid_pjsip_add_1account”,同“make_call”一樣,也需要傳遞參數(shù),不同的是,它傳遞三個(gè)參數(shù),只是原理大體一樣。

  首先它將參數(shù)轉(zhuǎn)化后保持到cfg,通過“pjsua_acc_add(&cfg,PJ_TRUE,&ace_id)”將參數(shù)添加到pjsua。pjsua將以其中的sip服務(wù)器為目的地址,注冊(cè)會(huì)話發(fā)起申請(qǐng),經(jīng)過一系列的操作之后,與目的地址發(fā)起會(huì)話。

  2.2.4 主程序與用戶界面

  系統(tǒng)的主程序是一個(gè)標(biāo)準(zhǔn)的Android應(yīng)用程序,它使用Java語言開發(fā),符合SDK規(guī)范。與一般的SDK程序不同的是,該類中必須使用Syst-em.loadLibrary加載PJSIP庫文件。形式如下:

  System.loadLibrary(“pjsip-jni”);

  其中,pjsip-jni就是上節(jié)中PJSIP協(xié)議棧生成的庫。

  主程序中的基本方式均按照上節(jié)中的過程,創(chuàng)建并初始化PJSUA;當(dāng)call按鍵被觸發(fā)時(shí)發(fā)起會(huì)話,調(diào)用make-call()方法;當(dāng)用戶接受通話時(shí),點(diǎn)擊hang或cancel按鍵,觸發(fā)hang()或采用destry()方法等。

  用戶接口是通過Android SDK來實(shí)現(xiàn)的,這部分幾乎全都是Java語言,由于UI不是本文的重點(diǎn),因此只介紹一個(gè)簡(jiǎn)單的界面,實(shí)際應(yīng)用中用戶交互是非常重要的。為了實(shí)現(xiàn)所需的功能,至少需要一個(gè)文本框來提供SIP地址,以及兩個(gè)按鍵來控制會(huì)話發(fā)起和結(jié)束。另外,在呼叫與通話過程中,還需要一個(gè)頁面來顯示,這里可以通過對(duì)話框來顯示,最后的界面如圖2所示。

  

  3 封裝與調(diào)試

  為了能在Android平臺(tái)上方便地使用該系統(tǒng),在實(shí)現(xiàn)了PJSIP協(xié)議棧、JNI接口以及UI之后,還需將上面所有的模塊進(jìn)行封裝。Android SDK提供了一些很有用的工具,如aapt等,由于本文重點(diǎn)不在AndriodSDK,所以可以采用集成開發(fā)工具(如集成在Eclipse中的ADT)來封裝。在工程libs(如果不存在則新建)目錄下新建一個(gè)名為armeabi的目錄,將上節(jié)生成的.so庫文件放到該目錄下。ADT在封裝資源時(shí)會(huì)自動(dòng)將該庫文件封裝到apk文件中,apk是Android操作系統(tǒng)中應(yīng)用程序的封裝形式,在所有android平臺(tái)中均能使用。

  封裝后安裝到Android手機(jī)、MID或虛擬機(jī)中,并發(fā)起會(huì)話。與開源SIP軟件Linphone通信的結(jié)果如圖2所示。

  4 結(jié)語

  通過測(cè)試表明,該系統(tǒng)能夠?qū)Πl(fā)起并很好地控制SIP信令,該系統(tǒng)由于采用SIP協(xié)議,因此與所有采用這一協(xié)議的軟件均能通信,如Lin-phone,Kphone等,功能測(cè)試中表現(xiàn)良好,實(shí)現(xiàn)了VoIP的基本需求。同時(shí)如果要增加功能,可以在Java類中添加相應(yīng)的方法并在應(yīng)用層調(diào)用即可,具有一定的可擴(kuò)展性。

  由于手機(jī)等手持設(shè)備在規(guī)格和配置上的差異,該系統(tǒng)在具體的設(shè)備上使用時(shí),界面略有不同,但是同系統(tǒng)架構(gòu)的手機(jī)使用時(shí)并不影響功能,在HTC Desire和MOTO Milestone上測(cè)試均能正常使用。但是,當(dāng)移植到不同的架構(gòu)時(shí)(即使同時(shí)ARM架構(gòu)),仍需做一定的優(yōu)化,一般采取主流平臺(tái)的多種版本方式來解決,這也是所有多廠商移動(dòng)設(shè)備上一個(gè)無法避免的問題。

此內(nèi)容為AET網(wǎng)站原創(chuàng),未經(jīng)授權(quán)禁止轉(zhuǎn)載。
亚洲一区二区欧美_亚洲丝袜一区_99re亚洲国产精品_日韩亚洲一区二区
亚洲激情在线观看| 亚洲欧美日韩人成在线播放| 欧美体内she精视频在线观看| 麻豆精品在线视频| 久久精品系列| 欧美在线视屏| 欧美一级大片在线免费观看| 亚洲在线日韩| 亚洲自拍电影| 亚洲欧美乱综合| 亚洲一区三区在线观看| 一区二区激情视频| 一区二区欧美日韩视频| a91a精品视频在线观看| 99re这里只有精品6| 亚洲日韩视频| 99精品免费网| 亚洲视频免费在线| 亚洲一区二区三区成人在线视频精品| 一本一本久久a久久精品综合麻豆| 99香蕉国产精品偷在线观看| 日韩性生活视频| 一区二区久久久久| 亚洲一区二区视频在线观看| 亚洲一区二区视频在线| 亚洲专区一区| 久久不射网站| 久久久www成人免费无遮挡大片| 久久久久久久久一区二区| 久久久青草婷婷精品综合日韩| 久久夜色精品| 欧美国产日韩a欧美在线观看| 欧美了一区在线观看| 欧美日韩国产综合一区二区| 欧美日韩精品一区二区在线播放 | 久久精品亚洲一区| 久久视频在线看| 欧美电影资源| 国产精品白丝av嫩草影院| 国产精品久久久久久久久久久久| 国产精品人人爽人人做我的可爱| 国产视频精品xxxx| 在线成人免费观看| 日韩午夜在线视频| 亚洲免费在线播放| 亚洲成人在线视频网站| 日韩亚洲国产精品| 小黄鸭精品密入口导航| 久久网站免费| 欧美日韩亚洲91| 国产午夜久久久久| 亚洲片国产一区一级在线观看| 一区二区三区视频观看| 久久av资源网站| 一区二区高清| 久久久久国产精品一区| 欧美日韩1区| 国产亚洲综合性久久久影院| 1000部国产精品成人观看| 一本一本久久| 久久狠狠一本精品综合网| 在线综合欧美| 久久久久久9999| 欧美精品一卡| 国产欧美精品日韩区二区麻豆天美| 1024精品一区二区三区| 亚洲视频每日更新| 亚洲国产小视频| 亚洲欧美精品一区| 欧美大片在线观看一区| 国产精品久久一卡二卡| 在线精品国产欧美| 亚洲综合成人婷婷小说| 亚洲精品免费在线| 欧美在线免费看| 欧美精品一区二区蜜臀亚洲 | 亚洲国产成人久久综合| 亚洲欧美电影在线观看| 亚洲裸体在线观看| 久久精品一区二区| 欧美午夜一区二区| 亚洲国产精品成人va在线观看| 亚洲欧美日韩另类| 99视频精品| 久久综合久久久| 国产免费亚洲高清| 日韩视频在线观看免费| 亚洲国产导航| 欧美伊久线香蕉线新在线| 欧美精品一区三区在线观看| 国产亚洲欧美另类中文| 在线一区日本视频| 一本色道久久综合亚洲精品婷婷| 久久三级视频| 国产日韩在线不卡| 亚洲一二区在线| 亚洲小说欧美另类婷婷| 欧美激情中文字幕一区二区| 黄色国产精品| 欧美影院午夜播放| 欧美影院视频| 国产精品蜜臀在线观看| 99re6这里只有精品| 日韩午夜激情电影| 欧美成人免费va影院高清| 国产综合网站| 欧美一区二区在线免费观看| 欧美亚洲综合网| 国产精品成人一区二区三区吃奶| 最近中文字幕mv在线一区二区三区四区 | 欧美在线综合视频| 久久国产精彩视频| 国产精品尤物福利片在线观看| 一区二区三区欧美视频| 中文日韩欧美| 欧美视频精品在线| 亚洲免费不卡| 亚洲少妇在线| 欧美婷婷六月丁香综合色| 日韩午夜av在线| 一本色道久久综合亚洲精品不| 欧美精品成人| 亚洲黄色小视频| 亚洲精品自在在线观看| 欧美大片91| 亚洲日本免费| 一级成人国产| 欧美日韩一区二区视频在线| 日韩视频一区| 亚洲一区久久| 国产精品欧美一区喷水| 亚洲制服av| 欧美在线视频一区二区| 国产亚洲毛片在线| 亚洲第一精品福利| 欧美高清视频在线播放| 亚洲精品视频在线看| 一区二区三区视频观看| 欧美视频在线观看免费网址| 一本色道久久99精品综合| 亚洲一区精品视频| 国产精品系列在线播放| 欧美一区二区三区日韩| 久久夜色精品亚洲噜噜国产mv| 伊人久久婷婷色综合98网| 亚洲美女av在线播放| 欧美日韩亚洲综合在线| 亚洲一区二区三区中文字幕在线| 久久不见久久见免费视频1| 狠狠色丁香婷婷综合久久片| 亚洲人成在线观看一区二区| 欧美日韩一区二区三区四区五区| 亚洲图片欧洲图片av| 久久精品免费播放| 亚洲第一精品夜夜躁人人爽| 99热精品在线观看| 国产精品无人区| 亚洲第一视频| 欧美日韩伦理在线免费| 亚洲欧美日本视频在线观看| 久久手机免费观看| 亚洲精品视频在线| 欧美伊人久久| 亚洲高清视频一区| 亚洲综合精品| 激情五月婷婷综合| 亚洲深夜av| 国内久久婷婷综合| 一本久道综合久久精品| 国产精品综合| 亚洲三级影片| 国产精品午夜国产小视频| 亚洲国内在线| 国产精品老牛| 亚洲激情国产精品| 国产精品毛片va一区二区三区| 久久国产一区| 欧美日韩亚洲另类| 欧美在线1区| 欧美视频在线观看| 久久精品三级| 国产精品yjizz| 亚洲欧洲精品成人久久奇米网| 国产精品成人va在线观看| 亚洲国产精品久久久久| 国产精品久久久久久户外露出 | 久久精品夜色噜噜亚洲a∨| 欧美人牲a欧美精品| 久久精品国产999大香线蕉| 欧美午夜不卡在线观看免费 | 麻豆freexxxx性91精品| 一区二区三区视频观看| 美女尤物久久精品| 亚洲一区二区三区欧美| 欧美激情视频一区二区三区在线播放| 亚洲已满18点击进入久久| 欧美日本成人| 亚洲国产国产亚洲一二三| 国产精品亚洲第一区在线暖暖韩国| 亚洲激情亚洲|