Manage call
Receive call
Add two new properties onGoingCallID to hold the current live call and callInviteID to hold an incoming call invite at the top of the MainActivity class:
private var onGoingCallID: CallId? = null
private var callInviteID: CallId? = null
To listen for incoming calls add call invite listener at the end of onCreate method inside MainActivity class:
client.setCallInviteListener { callId, from, channelType ->
callInviteID = callId
runOnUiThread {
answerCallButton.visibility = View.VISIBLE
rejectCallButton.visibility = View.VISIBLE
endCallButton.visibility = View.GONE
}
}
The app will now listen for the incoming call event. The above code shows the answer and the reject call buttons when the incoming call event is received. Notice that you are storing callInviteID reference to interact later with the call.
Next below the call invite listener add the on RTC hangup listener, this will handle when the person calling you hangs up and the call ends.
client.setOnCallHangupListener { callId, callQuality, isRemote ->
onGoingCallID = null
answerCallButton.visibility = View.GONE
rejectCallButton.visibility = View.GONE
endCallButton.visibility = View.GONE
}
Before you will be able to perform actions using UI you also need to add listeners to the buttons. Add this code at of the onCreate inside MainActivity class:
answerCallButton.setOnClickListener { answerCall() }
rejectCallButton.setOnClickListener { rejectCall() }
endCallButton.setOnClickListener { endCall() }
To answer the call add answerCall method inside MainActivity class:
@SuppressLint("MissingPermission")
private fun answerCall() {
callInviteID?.let {
client.answer(it) {
err ->
when {
err != null -> {
connectionStatusTextView.text = err.localizedMessage
}
else -> {
onGoingCallID = it
answerCallButton.visibility = View.GONE
rejectCallButton.visibility = View.GONE
endCallButton.visibility = View.VISIBLE
}
}
}
}
}
After answering the call the end call button will be shown.
NOTE: The SuppressLint annotation is used for simplicity. In the production app you should make sure permissions are granted before answering the call.
To reject the call add rejectCall method inside MainActivity class:
private fun rejectCall() {
callInviteID?.let {
client.reject(it) { err ->
when {
err != null -> {
connectionStatusTextView.text = err.localizedMessage
}
else -> {
answerCallButton.visibility = View.GONE
rejectCallButton.visibility = View.GONE
endCallButton.visibility = View.GONE
}
}
}
onGoingCallID = null
}
}
To end the call add endCall method inside MainActivity class:
private fun endCall() {
onGoingCallID?.let {
client.hangup(it) {
err ->
when {
err != null -> {
connectionStatusTextView.text = err.localizedMessage
}
else -> {
answerCallButton.visibility = View.GONE
rejectCallButton.visibility = View.GONE
endCallButton.visibility = View.GONE
}
}
}
}
onGoingCallID = null
}
Notice that after a successful rejecting or ending the call you set call property value back to null.
Build and Run
Please make sure that the webhook server you built in the previous steps is still running.
Press the Ctrl + R keys to build and run the app. Call the number.
Call the number linked with your application from the earlier step.
Webhooks
As you proceed with the call, please switch to the terminal and notice the /voice/answer endpoint being called to retrieve the NCCO:
Also, as the call progresses through various stages, /voice/event is being sent events:
EVENT:
{
headers: {},
from: '447700900000',
to: '442038297050',
uuid: '0779a56d002f1c7f47f82ef5fe84ab79',
conversation_uuid: 'CON-8f5a100c-fbce-4218-8d4b-16341335bcd6',
status: 'ringing',
direction: 'inbound',
timestamp: '2021-03-29T21:20:05.582Z'
}
---
EVENT:
{
headers: {},
from: '447700900000',
to: '442038297050',
uuid: '0779a56d002f1c7f47f82ef5fe84ab79',
conversation_uuid: 'CON-8f5a100c-fbce-4218-8d4b-16341335bcd6',
status: 'started',
direction: 'inbound',
timestamp: '2021-03-29T21:20:05.582Z'
}
---
EVENT:
{
start_time: null,
headers: {},
rate: null,
from: '447700900000',
to: '442038297050',
uuid: '0779a56d002f1c7f47f82ef5fe84ab79',
conversation_uuid: 'CON-8f5a100c-fbce-4218-8d4b-16341335bcd6',
status: 'answered',
direction: 'inbound',
network: null,
timestamp: '2021-03-29T21:20:06.182Z'
}
---
EVENT:
{
from: '447700900000',
to: 'Alice',
uuid: '944bf4bf-8dc7-4e23-86b2-2f4234777416',
conversation_uuid: 'CON-8f5a100c-fbce-4218-8d4b-16341335bcd6',
status: 'started',
direction: 'outbound',
timestamp: '2021-03-29T21:20:13.025Z'
}
---
EVENT:
{
start_time: null,
headers: {},
rate: null,
from: '447700900000',
to: 'Alice',
uuid: '944bf4bf-8dc7-4e23-86b2-2f4234777416',
conversation_uuid: 'CON-8f5a100c-fbce-4218-8d4b-16341335bcd6',
status: 'answered',
direction: 'outbound',
network: null,
timestamp: '2021-03-29T21:20:13.025Z'
}
---
EVENT:
{
headers: {},
end_time: '2021-03-29T21:20:16.000Z',
uuid: '944bf4bf-8dc7-4e23-86b2-2f4234777416',
network: null,
duration: '5',
start_time: '2021-03-29T21:20:11.000Z',
rate: '0.00',
price: '0',
from: '447700900000',
to: 'Alice',
conversation_uuid: 'CON-8f5a100c-fbce-4218-8d4b-16341335bcd6',
status: 'completed',
direction: 'outbound',
timestamp: '2021-03-29T21:20:17.574Z'
}
---
EVENT:
{
headers: {},
end_time: '2021-03-29T21:20:18.000Z',
uuid: '0779a56d002f1c7f47f82ef5fe84ab79',
network: 'GB-FIXED',
duration: '12',
start_time: '2021-03-29T21:20:06.000Z',
rate: '0.00720000',
price: '0.00144000',
from: ' 447700900000',
to: '442038297050',
conversation_uuid: 'CON-8f5a100c-fbce-4218-8d4b-16341335bcd6',
status: 'completed',
direction: 'inbound',
timestamp: '2021-03-29T21:20:17.514Z'
}
---
Receiving a phone call in-app
You receive a call from a phone to your app