Android VoIP Development with Kotlin: PJSIP, ConnectionService & Push

Build a production Android VoIP app in Kotlin: PJSIP-Android integration, ConnectionService/Telecom framework, FCM push notifications for background calls, audio routing, and Google Play submission for calling apps.

Mobile Development13 min readApril 14, 2026

Android VoIP Development with Kotlin: PJSIP, ConnectionService & Push

Build a production Android VoIP app in Kotlin: PJSIP-Android integration, ConnectionService/Telecom framework, FCM push notifications for background calls, audio routing, and Google Play submission for calling apps.

Kaushik Parmar

Founder & VoIP Architect, CelloIP Technologies

Kotlin for Android VoIP Development

Kotlin is the modern standard for Android development and an excellent choice for VoIP apps. Kotlin coroutines handle the async nature of SIP call events cleanly. Jetpack Compose delivers a modern declarative UI for call screens. The Telecom framework's ConnectionService API gives your app deep integration with the Android phone system — similar to how CallKit works on iOS. For the SIP stack, PJSIP-Android compiled as a native library (via JNI) provides production-grade SIP, RTP, and codec handling.

PJSIP Integration in Kotlin/Android

PJSIP for Android is compiled as a .so native library via the Android NDK. You wrap PJSIP's Java bindings in a Kotlin service (a foreground service to survive background). The service manages SIP account registration, incoming/outgoing call state, and RTP media. Kotlin's coroutines and Flow make handling PJSIP's callback-heavy API significantly cleaner than the equivalent Java code.

SipService.kt — PJSIP account registration in Kotlin

class SipService : Service(), PjSipObserver {
  private lateinit var endpoint: Endpoint
  private lateinit var account: SipAccount

  override fun onCreate() {
    super.onCreate()
    endpoint = Endpoint()
    endpoint.libCreate()
    val epConfig = EpConfig()
    epConfig.logConfig.level = 4u
    endpoint.libInit(epConfig)

    val tcfg = TransportConfig()
    tcfg.port = 5060u
    endpoint.transportCreate(pjsip_transport_type_e.PJSIP_TRANSPORT_UDP, tcfg)
    endpoint.libStart()

    val acfg = AccountConfig()
    acfg.idUri = "sip:[email protected]"
    acfg.regConfig.registrarUri = "sip:example.com"
    acfg.sipConfig.proxies.add("<sip:example.com;lr>")
    val authCreds = AuthCredInfo("digest", "*", "alice", 0, "secret")
    acfg.sipConfig.authCreds.add(authCreds)

    account = SipAccount(this)
    account.create(acfg)
  }

  override fun onIncomingCall(prm: OnIncomingCallParam) {
    // Notify via ConnectionService
    startActivity(IncomingCallActivity.intent(this, prm.callId))
  }
}

ConnectionService and FCM Push

Android's ConnectionService API integrates your VoIP calls with the native phone system. Implement a PhoneAccountRegistrar, register a PhoneAccount with TelecomManager, and extend Connection for each call. The system handles audio routing, Bluetooth SCO, Android Auto, and Do Not Disturb integration automatically. For background incoming calls, use FCM high-priority data messages. Unlike iOS PushKit, FCM cannot guarantee instant wakeup — maintain a persistent WebSocket or SIP REGISTER with short expiry as a backup mechanism.

KotlinAndroidVoIPPJSIPConnectionServiceFCM

Frequently Asked Questions

PJSIP vs WebRTC native library for Android VoIP?

PJSIP for SIP/telephony apps — mature, full codec support, proven on millions of devices. WebRTC native library for browser-interop or video conferencing. Many production apps use both: PJSIP for the SIP stack, WebRTC for media processing.

How do I handle battery optimisation blocking background calls?

Request DISABLE_BATTERY_OPTIMIZATION permission, use a persistent foreground service, and implement WorkManager for re-registration tasks. Guide users to whitelist your app in battery settings on Chinese OEM devices (MIUI, EMUI) which aggressively kill background apps.

What audio codecs should I support?

Opus (highest quality, adapts to network conditions — ideal for data networks), G.711 ulaw/alaw (universal compatibility with PSTN), G.729 (low bandwidth for poor connections). Always negotiate Opus first, fall back to G.711.

Back to Blog

Need help implementing this for your project?

Talk to a VoIP Engineer