最近做一個VOIP的項目,調研了CSipSimple。都說CSipSimple結構清晰,但是代碼下下來看了一下,還是一頭霧水,不知從何看起。於是想到從最簡單的打電話開始,借助網上一篇博文"CSipSimple 撥通電話機制分析",看看整個流程是怎么走的。由於工程圍繞sip協議這個核心,因此我們從底層往上層逐步分析。
流程梳理
1. jni
CSipSimple底層sip協議棧用的是pjsip,而pjsip是用c寫的,這必然牽扯到jni的問題。jni的代碼位於org.pjsip.pjsua包中。該包里面的文件非常多。目前我們先關心兩個,一個是pjsuaJNI.java,另一個是pjsua.java,分別對應兩個類。 ua是User Agent的簡稱,也就是客戶端代理,用於處理打開會話,維護,收發等。pjsuaJNI里面的函數都有native關鍵字,這些函數是直接調用so庫中用c寫的函數的。從這里往上是java代碼,是我們要關注的;往下是c代碼,也就是pjsip的內容,暫時不管。pusua對pjsuaJNI作了一個輕度封裝:基本上是直接調用。這樣就對上層屏蔽了本地調用的代碼。
2. sip協議接口
上面說到pjsua。該類可以理解為java層sip協議的接口。我們要用sip協議的哪個功能,最終都要調用該類的方法。與打電話相關的函數名為call_make_call,具體參數暫不作分析。另外還有call_setting_default函數等進行一些設置。
3. sip服務
sip協議接口中的函數都是基本函數,功能單一,不方便使用,因此作進一步分裝。該封裝位於包com.csipsimple.pjsip中。最主要的類為PjSipService。與打電話對應的函數是makeCall,它在打電話之前作了一些設置。PjSipService可以認為是高層次的API。目前來看,進行二次開發基本上調用這一層的代碼就可以了。
4. android框架
以上其實都沒有涉及到android的部分。為了維護一些狀態等,也為了方便使用,CSipSimple把sip服務封裝成了android中的標准service。所有的csipsimple的服務接口都定義在com.csipsimple.api中,與sip服務相關的定義是ISipService.aidl,其中關於打電話的函數是makeCallWithOptions。服務接口定義在aidl文件中,看來是為了方便進程間通信,不過這是后話,先不管。
當然,eclipse會把aidl編譯為java文件,在gen文件中,包名仍為com.csipsimple.api,文件名為ISipService.java。打開文件,毫無疑問會有一個makeCallWithOptions函數。
接口的實現在com.csipsimple.service包中的SipService類。
// Implement public interface for the service private final ISipService.Stub binder = new ISipService.Stub() { /** * {@inheritDoc} */ @Override public void sipStart() throws RemoteException { SipService.this.enforceCallingOrSelfPermission(SipManager.PERMISSION_USE_SIP, null); Log.d(THIS_FILE, "Start required from third party app/serv"); getExecutor().execute(new StartRunnable()); } ... ... }
上述服務肯定是要在android的服務管理器中注冊的。
5. 使用服務
既然是標准的android服務,那么使用起來也是很簡單的。使用服務的基本方法可以參考com.csipsimple.ui.dialpad.DialerFragment.java。先調用ServiceConnection.onServiceConnected()獲得IBinder對象,再用ISipService.Stub.asInterface((IBinder)service)轉為ISipService對象,這樣就可以調用它的函數了。
流程簡圖
綜合上述分析,可以得出如下簡要流程圖。