Android menyediakan API yang mendukung Protokol Pemulaian Sesi (SIP) Hal ini memungkinkan Anda menambahkan fitur telepon internet berbasis SIP ke aplikasi Anda. Android menyertakan stack protokol SIP penuh dan layanan pengelolaan panggilan terintegrasi yang memungkinkan aplikasi dengan mudah menyiapkan panggilan suara keluar dan masuk, tanpa harus mengelola sesi, komunikasi tingkat transport, atau rekaman/pemutaran audio secara langsung.
Berikut adalah contoh jenis aplikasi yang menggunakan SIP API:
- Konferensi video
- Instant messaging
Persyaratan dan batasan
Berikut adalah beberapa persyaratan untuk mengembangkan aplikasi SIP:
- Anda harus memiliki perangkat seluler yang menjalankan Android 2.3 atau yang lebih baru.
- SIP berjalan melalui koneksi data nirkabel, sehingga perangkat Anda harus memiliki koneksi data (dengan layanan data seluler atau Wi-Fi). Ini berarti, Anda tidak dapat menguji di AVD—Anda hanya dapat menguji di perangkat fisik. Untuk detailnya, lihat Menguji aplikasi SIP.
- Setiap peserta dalam sesi komunikasi aplikasi harus memiliki akun SIP. Ada banyak penyedia SIP berbeda yang menawarkan akun SIP.
Antarmuka dan class SIP API
Berikut adalah ringkasan class dan satu antarmuka (SipRegistrationListener
) yang termasuk dalam Android SIP API:
Class/Antarmuka | Deskripsi |
---|---|
SipAudioCall |
Menangani panggilan audio Internet melalui SIP. |
SipAudioCall.Listener |
Pemroses untuk peristiwa yang berkaitan dengan panggilan SIP, seperti ketika panggilan sedang diterima ("sedang berdering") atau panggilan sedang keluar ("sedang memanggil"). |
SipErrorCode |
Menentukan kode error yang ditampilkan selama tindakan SIP. |
SipManager |
Menyediakan API untuk tugas SIP, seperti memulai koneksi SIP, dan memberikan akses ke layanan SIP terkait. |
SipProfile |
Menentukan profil SIP, termasuk informasi akun, domain, dan server SIP. |
SipProfile.Builder |
Class helper untuk membuat SipProfile. |
SipSession |
Merepresentasikan sesi SIP yang terkait dengan dialog SIP atau transaksi mandiri tidak dalam dialog. |
SipSession.Listener |
Pemroses untuk peristiwa yang berkaitan dengan sesi SIP, seperti saat sesi sedang didaftarkan ("sedang mendaftar") atau panggilan sedang keluar ("sedang memanggil"). |
SipSession.State |
Menentukan status sesi SIP, seperti "mendaftar", "panggilan keluar", dan "dalam panggilan". |
SipRegistrationListener |
Antarmuka yang merupakan pemroses untuk peristiwa pendaftaran SIP. |
Membuat manifes
Jika Anda mengembangkan aplikasi yang menggunakan SIP API, perhatikan bahwa fitur tersebut hanya didukung di Android 2.3 (API level 9) dan versi platform yang lebih baru. Selain itu, di antara perangkat yang menjalankan Android 2.3 (API level 9) atau yang lebih tinggi, tidak semua perangkat akan menawarkan dukungan SIP.
Untuk menggunakan SIP, tambahkan izin berikut ke manifes aplikasi:
android.permission.USE_SIP
android.permission.INTERNET
Untuk memastikan bahwa aplikasi Anda hanya dapat diinstal di perangkat yang mampu mendukung SIP, tambahkan kode berikut ke manifes aplikasi Anda:
<uses-sdk android:minSdkVersion="9" />
Ini akan mengindikasikan bahwa aplikasi Anda mewajibkan Android 2.3 atau yang lebih tinggi. Untuk informasi selengkapnya, lihat Tingkat API dan dokumentasi untuk elemen <uses-sdk>
.
Untuk mengontrol cara aplikasi Anda difilter dari perangkat yang tidak mendukung SIP (misalnya, di Google Play), tambahkan kode berikut ke manifes aplikasi Anda:
<uses-feature android:name="android.hardware.sip.voip" />
Ini akan menegaskan bahwa aplikasi Anda menggunakan SIP API. Deklarasinya harus menyertakan atribut android:required
yang menunjukkan apakah Anda ingin aplikasi tersebut difilter dari perangkat yang tidak menawarkan dukungan SIP.
Deklarasi <uses-feature>
lain mungkin juga diperlukan bergantung pada implementasi Anda. Untuk informasi selengkapnya, lihat dokumentasi untuk elemen <uses-feature>
.
Jika aplikasi Anda dirancang untuk menerima panggilan, Anda juga harus menentukan penerima (subclass BroadcastReceiver
) dalam manifes aplikasi:
<receiver android:name=".IncomingCallReceiver" android:label="Call Receiver" />
Berikut adalah cuplikan manifes SipDemo:
<?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>
Membuat SipManager
Untuk menggunakan SIP API, aplikasi Anda harus membuat objek SipManager
. SipManager
menangani beberapa hal berikut dalam aplikasi Anda:
- Memulai sesi SIP.
- Memulai dan menerima panggilan.
- Mendaftarkan dan membatalkan pendaftaran dengan penyedia SIP.
- Memverifikasi konektivitas sesi.
Buat instance SipManager
baru seperti berikut:
Kotlin
val sipManager: SipManager? by lazy(LazyThreadSafetyMode.NONE) { SipManager.newInstance(this) }
Java
public SipManager sipManager = null; ... if (sipManager == null) { sipManager = SipManager.newInstance(this); }
Mendaftar dengan Server SIP
Aplikasi SIP Android umumnya melibatkan satu atau beberapa pengguna, yang masing-masing memiliki akun SIP. Dalam aplikasi SIP Android, setiap akun SIP diwakili oleh objek SipProfile
.
SipProfile
menentukan profil SIP, termasuk akun SIP, dan informasi server serta domain. Profil yang dikaitkan dengan akun SIP di perangkat yang menjalankan aplikasi tersebut dinamakan profil lokal. Profil yang sesinya terhubung dinamakan profil peer. Saat aplikasi SIP Anda login ke server SIP dengan SipProfile
lokal, tindakan ini secara efektif akan mendaftarkan perangkat tersebut sebagai lokasi untuk mengirim panggilan SIP untuk alamat SIP Anda.
Bagian ini menunjukkan cara membuat SipProfile
, mendaftarkannya dengan server SIP, dan melacak peristiwa pendaftaran.
Buat objek SipProfile
seperti berikut:
Kotlin
private var sipProfile: SipProfile? = null ... val builder = SipProfile.Builder(username, domain) .setPassword(password) sipProfile = builder.build()
Java
public SipProfile sipProfile = null; ... SipProfile.Builder builder = new SipProfile.Builder(username, domain); builder.setPassword(password); sipProfile = builder.build();
Cuplikan kode berikut membuka profil lokal untuk melakukan panggilan dan/atau menerima panggilan SIP umum. Pemanggil dapat melakukan panggilan berikutnya melalui mSipManager.makeAudioCall
. Cuplikan ini juga menetapkan tindakan android.SipDemo.INCOMING_CALL
, yang akan digunakan oleh filter intent ketika perangkat menerima panggilan (lihat Menyiapkan filter intent untuk menerima panggilan). Berikut adalah langkah pendaftarannya:
Kotlin
val intent = Intent("android.SipDemo.INCOMING_CALL") val pendingIntent: PendingIntent = PendingIntent.getBroadcast(this, 0, intent, Intent.FILL_IN_DATA) sipManager?.open(sipProfile, pendingIntent, null)
Java
Intent intent = new Intent(); intent.setAction("android.SipDemo.INCOMING_CALL"); PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, Intent.FILL_IN_DATA); sipManager.open(sipProfile, pendingIntent, null);
Terakhir, kode ini akan menetapkan SipRegistrationListener
di SipManager
. Kode ini melacak apakah SipProfile
berhasil didaftarkan dengan penyedia layanan SIP Anda:
Kotlin
sipManager?.setRegistrationListener(sipProfile?.uriString, object : SipRegistrationListener { override fun onRegistering(localProfileUri: String) { updateStatus("Registering with SIP Server...") } override fun onRegistrationDone(localProfileUri: String, expiryTime: Long) { updateStatus("Ready") } override fun onRegistrationFailed( localProfileUri: String, errorCode: Int, errorMessage: String ) { updateStatus("Registration failed. Please check settings.") } })
Java
sipManager.setRegistrationListener(sipProfile.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."); } }
Saat selesai menggunakan profil, aplikasi Anda harus menutupnya untuk membebaskan objek terkait ke dalam memori dan membatalkan pendaftaran perangkat dari server. Contoh:
Kotlin
fun closeLocalProfile() { try { sipManager?.close(sipProfile?.uriString) } catch (ee: Exception) { Log.d("WalkieTalkieActivity/onDestroy", "Failed to close local profile.", ee) } }
Java
public void closeLocalProfile() { if (sipManager == null) { return; } try { if (sipProfile != null) { sipManager.close(sipProfile.getUriString()); } } catch (Exception ee) { Log.d("WalkieTalkieActivity/onDestroy", "Failed to close local profile.", ee); } }
Melakukan panggilan audio
Untuk melakukan panggilan audio, Anda harus memiliki:
SipProfile
yang membuat panggilan ("profil lokal"), dan alamat SIP yang valid untuk menerima panggilan ("profil peer").- Objek
SipManager
.
Untuk melakukan panggilan audio, Anda harus menyiapkan SipAudioCall.Listener
. Sebagian besar interaksi klien dengan stack SIP terjadi melalui pemroses. Dalam cuplikan ini, Anda akan melihat cara SipAudioCall.Listener
menyiapkan beberapa hal setelah panggilan dilakukan:
Kotlin
var listener: SipAudioCall.Listener = object : SipAudioCall.Listener() { override fun onCallEstablished(call: SipAudioCall) { call.apply { startAudio() setSpeakerMode(true) toggleMute() } } override fun onCallEnded(call: SipAudioCall) { // Do something. } }
Java
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. } };
Setelah menyiapkan SipAudioCall.Listener
, Anda dapat melakukan panggilan. Metode SipManager
makeAudioCall
akan menggunakan beberapa parameter berikut:
- Profil SIP lokal (pemanggil).
- Profil SIP peer (pengguna yang dipanggil).
SipAudioCall.Listener
untuk memproses peristiwa panggilan dariSipAudioCall
. Ini dapat bernilainull
, tetapi seperti yang ditampilkan di atas, pemroses tersebut digunakan untuk menyiapkan beberapa hal setelah panggilan dilakukan.- Nilai waktu tunggu, dalam detik.
Contoh:
Kotlin
val call: SipAudioCall? = sipManager?.makeAudioCall( sipProfile?.uriString, sipAddress, listener, 30 )
Java
call = sipManager.makeAudioCall(sipProfile.getUriString(), sipAddress, listener, 30);
Menerima panggilan
Untuk menerima panggilan, aplikasi SIP harus menyertakan subclass BroadcastReceiver
yang memiliki kemampuan untuk merespons intent yang mengindikasikan bahwa ada panggilan masuk. Dengan demikian, Anda harus melakukan beberapa hal berikut dalam aplikasi Anda:
- Di
AndroidManifest.xml
, deklarasikan<receiver>
. Di SipDemo, ini adalah<receiver android:name=".IncomingCallReceiver" android:label="Call Receiver" />
. - Implementasikan penerima, yakni subclass
BroadcastReceiver
. Di SipDemo, ini adalahIncomingCallReceiver
. - Inisialisasi profil lokal (
SipProfile
) dengan intent tertunda yang mengaktifkan penerima Anda ketika seseorang memanggil profil lokal. - Siapkan filter intent yang memfilter berdasarkan tindakan yang mewakili panggilan masuk. Di SipDemo, tindakan ini adalah
android.SipDemo.INCOMING_CALL
.
Memasukkan BroadcastReceiver ke subclass
Untuk menerima panggilan, aplikasi SIP Anda harus memasukkan BroadcastReceiver
ke subclass. Sistem Android menangani panggilan masuk SIP dan menyiarkan intent "panggilan masuk" (seperti yang ditentukan oleh aplikasi) saat menerima panggilan. Berikut adalah kode
BroadcastReceiver
yang dimasukkan ke subclass dari Contoh SipDemo.
Kotlin
/** * Listens for incoming SIP calls, intercepts and hands them off to WalkieTalkieActivity. */ class IncomingCallReceiver : 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 fun onReceive(context: Context, intent: Intent) { val wtActivity = context as WalkieTalkieActivity var incomingCall: SipAudioCall? = null try { incomingCall = wtActivity.sipManager?.takeAudioCall(intent, listener) incomingCall?.apply { answerCall(30) startAudio() setSpeakerMode(true) if (isMuted) { toggleMute() } wtActivity.call = this wtActivity.updateStatus(this) } } catch (e: Exception) { incomingCall?.close() } } private val listener = object : SipAudioCall.Listener() { override fun onRinging(call: SipAudioCall, caller: SipProfile) { try { call.answerCall(30) } catch (e: Exception) { e.printStackTrace() } } } }
Java
/** * 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.sipManager.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(); } } } }
Menyiapkan filter intent untuk menerima panggilan
Saat menerima panggilan baru, layanan SIP akan mengirimkan intent dengan string tindakan yang diberikan oleh aplikasi. Di SipDemo, string tindakan ini adalah android.SipDemo.INCOMING_CALL
.
Cuplikan kode yang berasal SipDemo ini menunjukkan cara objek SipProfile
dibuat dengan intent tertunda berdasarkan string tindakan android.SipDemo.INCOMING_CALL
. Objek PendingIntent
akan melakukan siaran saat SipProfile
menerima panggilan:
Kotlin
val sipManager: SipManager? by lazy(LazyThreadSafetyMode.NONE) { SipManager.newInstance(this) } var sipProfile: SipProfile? = null ... val intent = Intent("android.SipDemo.INCOMING_CALL") val pendingIntent: PendingIntent = PendingIntent.getBroadcast(this, 0, intent, Intent.FILL_IN_DATA) sipManager?.open (sipProfile, pendingIntent, null)
Java
public SipManager sipManager = null; public SipProfile sipProfile = null; ... Intent intent = new Intent(); intent.setAction("android.SipDemo.INCOMING_CALL"); PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, Intent.FILL_IN_DATA); sipManager.open(sipProfile, pendingIntent, null);
Siaran tersebut akan dicegat oleh filter intent, yang kemudian akan mengaktifkan penerima (IncomingCallReceiver
). Anda dapat menentukan filter intent di file manifes aplikasi, atau melakukannya di kode seperti dalam metode onCreate()
aplikasi contoh SipDemo pada Activity
aplikasi tersebut:
Kotlin
class WalkieTalkieActivity : Activity(), View.OnTouchListener { ... lateinit var callReceiver: IncomingCallReceiver ... override fun onCreate(savedInstanceState: Bundle) { val filter = IntentFilter().apply { addAction("android.SipDemo.INCOMING_CALL") } callReceiver = IncomingCallReceiver() this.registerReceiver(callReceiver, filter) ... } ... }
Java
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); ... } ... }
Menguji aplikasi SIP
Untuk menguji aplikasi SIP, Anda memerlukan beberapa hal berikut:
- Perangkat seluler yang menjalankan Android 2.3 atau yang lebih tinggi. SIP berjalan melalui jaringan nirkabel, sehingga Anda harus menguji di perangkat yang sebenarnya. Pengujian pada AVD tidak akan bekerja.
- Akun SIP. Ada banyak penyedia SIP berbeda yang menawarkan akun SIP.
- Jika Anda melakukan panggilan, panggilan tersebut juga harus dilakukan ke akun SIP yang valid.
Untuk menguji aplikasi SIP:
- Di perangkat, sambungkan ke jaringan nirkabel ( Setelan > Nirkabel & jaringan > Wi-Fi > Setelan Wi-Fi).
- Siapkan perangkat seluler untuk pengujian, seperti yang dijelaskan dalam Melakukan Pengembangan di Perangkat.
- Jalankan aplikasi Anda di perangkat seluler, seperti yang dijelaskan dalam Melakukan Pengembangan di Perangkat.
- Jika menggunakan Android Studio, Anda dapat melihat output log aplikasi dengan membuka konsol Event Log (View > Tool Windows > Event Log).
- Pastikan aplikasi Anda dikonfigurasi untuk otomatis meluncurkan Logcat saat dijalankan:
- Pilih Run > Edit Configurations.
- Pilih tab Miscellaneous di jendela Run/Debug Configurations.
- Di bagian Logcat, pilih Show logcat automatically, lalu pilih OK.