Skip to content

Call lifecycle

Use lifecycle callbacks to keep call UI synchronized with real-time call progress. The diagrams below show the two main perspectives: placing a call and receiving one.

Outbound call (caller perspective)

When your app calls serverCall(), the callee leg progresses through status updates reported by onLegStatusUpdate.

Inbound call (callee perspective)

When your app receives a call invite, the local call transitions through invite handling into an active call.

Callback sources

Status updates

onLegStatusUpdate provides callee leg progression (for example: ringing -> answered -> completed). This is most relevant for outbound calls where you want to reflect the callee's state in your UI.

 client.setOnLegStatusUpdate { call, legId, status ->
     when(status) {
         LegStatus.ringing -> println("Leg $legId for call $call is ringing")
         LegStatus.answered -> println("Leg $legId for call $call was answered")
         LegStatus.completed -> println("Leg $legId for call $call was completed")
     }
 }

Initiating hangup

Use hangup to terminate your call.


 // Callback
 client.hangup("callId") {
     it?.let { err ->
         // Handle Error hanging up call
         println("Error hanging up call: $err")
     }
 }

 // Coroutine
 try {
     client.hangup("callId")
 } catch (e: Error) {
     // Handle Error hanging up call
 }

Handling hangup errors

hangup() can fail if the call has already ended, the session expired, or there is a network issue. Always handle the error to ensure your UI transitions to the ended state regardless:

kotlin
client.hangup(callId) { error ->
    if (error != null) {
        // Hangup request failed — but the call may still end via server-side timeout.
        // Clean up local UI anyway to avoid a stuck call screen.
        println("Hangup error: ${error.message}")
    }
    // Always transition to end-of-call UI
    showCallEndedUI()
}

TIP

Even if hangup() fails, always clean up your local call state and UI. The server will terminate the call independently via timeout if the client-side hangup did not reach it. Waiting for onCallHangup as a secondary confirmation is good practice.

Receiving hangup events

Use onCallHangup to handle final call teardown and UI cleanup.


 client.setOnCallHangupListener { call, callQuality, reason ->
     println("Received $reason callQuality: $callQuality for Call $call")
 }

Debugging lifecycle events

If call events are not arriving as expected, enable verbose logging during development to trace lifecycle transitions. See Logging and diagnostics for full configuration options including custom loggers and topic filtering.

NCCO hangup behavior

  • connect NCCO behaves like standard two-party calling — when one party hangs up, the point-to-point connection ends and both legs are terminated.
  • conversation NCCO behavior is conversation-scoped — hanging up only removes that participant's leg from the shared room. Other participants remain connected until they leave individually.

Built with VitePress.