序言:
Android提供了API來支援Session Initiation Protocol(SIP)。
這個API讓你可以將SIP-based網路電話功能(internet telephony features)加到app上。
Android包含了一整套的SIP protocol stack以及整合的呼叫管理服務,
讓apps可以輕易的設定好收發語音通話的功能,
而不需去管理sessions,transport層的溝通,
或者音訊錄製或直接播放等問題。
下面是幾個可能會用到SIP API的幾種apps。
1. 視訊會議(Video conferencing)
2. 即時訊息(Instant messaging)
Requirements and Limitations:
開發一個SIP app有幾點需求的條件:
1. 要有一台手機且其使用Android 2.3或更新版本的系統。
2. SIP是透過無線的資料連結,所以你的裝置必須要有一個資料連結。
(透過手機資料服務或者Wi-Fi)。這表示你不能在AVD上測試,
只能在實體裝置上進行測試。
3. 每一個在app溝通階段(communication session)的參加者必須都有一個SIP帳號。
有需多不同的SIP供應者能提供SIP帳號。
SIP API Classes and Interfaces:
下表是對於Android SIP API裡classes和一個interface(SipRegistrationListener)的總結。
Class/Interface | Description |
---|---|
SipAudioCall | 處理一個透過SIP的網路語音通話。 |
SipAudioCall.Listener | 監聽和SIP通話有關的events,比如說像接收中通話("on ringing"), 或是外播中的通話("on calling")。 |
SipErrorCode | 定義了SIP actions裡的錯誤碼(error codes)。 |
SipManager | 提供APIs給SIP tasks,像是開始SIP連線, 以及提供相對應於SIP服務的存取。 |
SipProfile | 定義一個SIP的profile,當中包含一個SIP帳號, domain及server的資訊。 |
SipProfile.Builder | 製作SipProfile的Helper class。 |
SipSession | 代表跟SIP dialog或一個不含dialog獨自(standalong)交換(transaction) 相關的SIP session。 |
SipSession.Listener | 監聽跟SIP session有關的events, 像是當一個session被註冊("on registering"), 或者一個通話外撥("on calling")。 |
SipSession.State | 定義SIP session狀態,像是"registering","outgoing call",以及"in call"。 |
SipRegistrationListener | 作為SIP registration events的監聽者的介面。 |
Creating the Manifest:
如果你在開發一個使用SIP API的app,
記得這個功能只在Android 2.3(API level 9)及更新的版本平台。
並且在所有跑Android 2.3或更新的版本的裝置並不是全都會提供SIP支援。
要使用SIP,將下列的許可授權加到你的app的manifest:
1. android.permission.USE_SIP
2. android.permission.INTERNET
要確保你的app只能被裝到支援SIP的裝置,
將下面列出來的加到manifest:
1. <uses-sdk android:minSdkVersion="9" />
這表示了你的app需求Android 2.3或更新的版本。
2. <uses-feature android:name="android.hardware.sip.voip" />
這敘述了你的app使用SIP API。
聲明中必須要包含android:required的屬性,
以指示你要不要讓app被不支援SIP的裝置給篩到。
其他的
<uses-feature>
聲明可能也會需要(視你的實作而定)。如果你的app是被設計來接受通話的話,那麼你也必須要定義一個receiver。
(BroadcastReceiver subclass)
在app的manifest裡:
<receiver android:name=".IncomingCallReceiver" android:label="Call Receiver"/>
下面是從SipDemo的manifest取來的片段(excerpts):
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.android.sip"> ... <receiver android:name=".IncomingCallReceiver" android:label="Call Receiver"/> ... <uses-sdk android:minSdkVersion="9" /> <uses-permission android:name="android.permission.USE_SIP" /> <uses-permission android:name="android.permission.INTERNET" /> ... <uses-feature android:name="android.hardware.sip.voip" android:required="true" /> <uses-feature android:name="android.hardware.wifi" android:required="true" /> <uses-feature android:name="android.hardware.microphone" android:required="true" /> </manifest>
Creating a SipManager:
要使用SIP API,你的app必須要作一個
SipManager
物件。SipManager
在你的app中做這些事情:1. 開始SIP sessions。
2. 開始並接收calls。
3. 向SIP provider註冊及反註冊。
4. 確認session的連線性。
你可以如下建立一個
SipManager
的實例。public SipManager mSipManager = null; ... if(mSipManager == null) { mSipManager = SipManager.newInstance(this); }
Registering with a SIP Server:
一個典型的Android SIP app包含了一個或多個使用者,
每一個都有一個SIP帳號。
在一個Android SIP app裡,每一個SIP帳號被一個SipProfile物件所代表。
一個SipProfile定義了一個SIP profile,當中包含了:
SIP帳號,domain,以及server information。
關聯著在裝置上跑的app的SIP帳號的那個profile,
被稱作local profile。
session被連結到的那個profile稱作peer profile。
當你的SIP app將local的
SipProfile
記錄到SIP server時。這有效率地註冊裝置作為發送SIP calls的地點到你的SIP address。
這段展示了如何去製作SipProfile,
使用SIP server來註冊,以及追蹤註冊的events。
你可以如下作一個
SipProfile
的物件:public SipProfile mSipProfile = null; ... SipProfile.Builder builder = new SipProfile.Builder(username, domain); builder.setPassword(password); mSipProfile = builder.build();
下面的code節錄了打開local profile來打且/或接收通用的SIP通話。
呼叫者可以透過來打一連串的通話,透過mSipManager.makeAudioCall。
這個節錄也設定了action android.SipDemo.INCOMING_CALL,
當裝置接受到一個通話時,其將會被一個intent filter來使用。
下面是註冊步驟:
Intent intent = new Intent(); intent.setAction("android.SipDemo.INCOMING_CALL"); PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, Intent.FILL_IN_DATA); mSipManager.open(mSipProfile, pendingIntent, null);
最後,這個code在SipManager上設定了一個SipRegistrationListener。
這追蹤了是否能成功被SIP service供應商給註冊。
mSipManager.setRegistrationListener(mSipProfile.getUriString(), new SipRegistrationListener() { public void onRegistering(String localProfileUri) { updateStatus("Registering with SIP Server..."); } public void onRegistrationDone(String localProfileUri, long expiryTime) { updateStatus("Ready"); } public void onRegistrationFailed(String localProfileUri, int errorCode, String errorMessage) { updateStatus("Registration failed. Please check settings."); }
當你的app使用profile完畢的時候,它應該要被關閉,
以釋放相關的物件回到記憶體,以及從server那反註冊裝置。
舉例來說:
public void closeLocalProfile() { if (mSipManager == null) { return; } try { if (mSipProfile != null) { mSipManager.close(mSipProfile.getUriString()); } } catch (Exception ee) { Log.d("WalkieTalkieActivity/onDestroy", "Failed to close local profile.", ee); } }
Making an Audio Call:
要打一通語音電話,你必須有下面的東西:
1. 一個
SipProfile
用以打電話(the "local profile"),以及一個有效的SIP address來接收呼叫(the "peer profile")。
2. 一個
SipManager
物件。要打一通語音電話,你應該要設定一個
SipAudioCall.Listener
。大部分client和SIP stack間的互動交流是透過監聽器發生的。
在下面的片段裡,你可以看到
SipAudioCall.Listener
是如何設定的。(在通話建立後)。
SipAudioCall.Listener listener = new SipAudioCall.Listener() { @Override public void onCallEstablished(SipAudioCall call) { call.startAudio(); call.setSpeakerMode(true); call.toggleMute(); ... } @Override public void onCallEnded(SipAudioCall call) { // Do something. } };
一旦你設定好了
SipAudioCall.Listener
以後,你就可以打語音電話了。
SipManager的method makeAudioCall取得下面的參數:
1. 一個local SIP profile(呼叫者)。
2. 一個peer SIP profile(被呼叫者)。
3. 一個從
SipAudioCall
監聽call events的SipAudioCall.Listener
。這可以是null,但就如上面所示,監聽器在通話建立後馬上就設定了。
4. 以秒計算的timeout值。
舉例來說:
call = mSipManager.makeAudioCall(mSipProfile.getUriString(), sipAddress, listener, 30);
Receiving Calls:
要接收通話,一個SIP app必須要包括一個BroadcastReceiver的subclass,
其要有能力來對於一個指示有打進來的通話作回應。
那麼你必需在你的app裡做這些事情:
1. 在AndroidManifest.xml裡,定義一個<receiver>。
在SipDemo裡,
這是
<receiver android:name=".IncomingCallReceiver"
android:label="Call Receiver"/>
。2. 實作接收器,它是BroadcastReceiver的subclass。在SipDemo裡,
這是IncomingCallReceiver。
3. 新增local file(SipProfile)偕同一個當有人呼叫local file時,
會找你的監聽器的pending intent。
4. 設定一個intent filter來篩代表撥進來的通話的action。
這個action是
android.SipDemo.INCOMING_CALL
。Subclassing Broadcast Receiver:
要接收呼叫,你的SIP app必須要有class繼承BroadcastReceiver。
Android系統處理了打進來的SIP calls,
並當接收一個通話時,廣播一個"incoming call" intent(如同程式定義)。
這裡是從SipDemo節錄出來的繼承了BroadcastReceiver的code。
/*** Listens for incoming SIP calls, intercepts and hands them off to WalkieTalkieActivity. */ public class IncomingCallReceiver extends BroadcastReceiver { /** * Processes the incoming call, answers it, and hands it over to the * WalkieTalkieActivity. * @param context The context under which the receiver is running. * @param intent The intent being received. */ @Override public void onReceive(Context context, Intent intent) { SipAudioCall incomingCall = null; try { SipAudioCall.Listener listener = new SipAudioCall.Listener() { @Override public void onRinging(SipAudioCall call, SipProfile caller) { try { call.answerCall(30); } catch (Exception e) { e.printStackTrace(); } } }; WalkieTalkieActivity wtActivity = (WalkieTalkieActivity) context; incomingCall = wtActivity.mSipManager.takeAudioCall(intent, listener); incomingCall.answerCall(30); incomingCall.startAudio(); incomingCall.setSpeakerMode(true); if(incomingCall.isMuted()) { incomingCall.toggleMute(); } wtActivity.call = incomingCall; wtActivity.updateStatus(incomingCall); } catch (Exception e) { if (incomingCall != null) { incomingCall.close(); } } } }
Setting up an intent filter to receive calls:
當SIP服務接收了一個新的call,它由app來提供,傳出一個帶有action string。
在SipDemo裡,這個action string是
android.SipDemo.INCOMING_CALL
。這個從SipDemo來的code片段展示了SipProfile物件,
如何從一個基於action string
android.SipDemo.INCOMING_CALL
的pending intent來建立起來。
當
SipProfile
接收到call時,PendingIntent物件將會執行廣播。public SipManager mSipManager = null; public SipProfile mSipProfile = null; ... Intent intent = new Intent(); intent.setAction("android.SipDemo.INCOMING_CALL"); PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, Intent.FILL_IN_DATA); mSipManager.open(mSipProfile, pendingIntent, null);
廣播將會被intent filter給截下來,並在稍後將receiver(IncomingCallReceiver)發射。
你可以在你的app的manifest file裡,指定一個intent filter,
或者在code裡這麼做,
就如在SipDemo的sample app的Activity的onCreate() method裡。
public class WalkieTalkieActivity extends Activity implements View.OnTouchListener { ... public IncomingCallReceiver callReceiver; ... @Override public void onCreate(Bundle savedInstanceState) { IntentFilter filter = new IntentFilter(); filter.addAction("android.SipDemo.INCOMING_CALL"); callReceiver = new IncomingCallReceiver(); this.registerReceiver(callReceiver, filter); ... } ... }
Testing SIP Application:
要測試SIP apps,你需要下面的條件:
1. Android 2.3以上的手機裝置。SIP透過無線來執行,必須要在實體機器上跑,
使用AVD來測試並不會有效。
2. 一個SIP account。有很多供應者可以提供SIP帳號。
3. 如果你進行了呼叫,必須要是一個有效的SIP帳號。
要測試SIP app:
1. 在裝置上連接到無線。(Settings > Wireless & networks > Wi-Fi > Wi-Fi settings)
2. 設定你的手機裝置以進行測試。
3. 在你的手機裝置上跑app。
4. 如果是使用Eclipse可以透過LogCat來檢視app log的輸出。
(Window > Show View > Other > Android > LogCat)
沒有留言:
張貼留言