Search…
Voice Calling

Voice Calling Setup

iOS
Android
Configure your Xcode project for outgoing calls.
    In your app's info.plist, add the NSMicrophoneUsageDescription key. This is required to request microphone permission.
    In your app's capabilities, add the background mode capabilities Audio, Airplay, and Picture in Picture ,Voice over IP, and Remote Notifications
    Add the Push Notifications capability.
Configure your Android application for outgoing calls.
    Add the following to your Android Manifest file:
    1
    <uses-permission android:name="android.permission.RECORD_AUDIO"/>
    Copied!
    Request microphone permissions from within your application code:
    1
    ActivityCompat.requestPermissions(
    2
    this,
    3
    arrayOf(Manifest.permission.RECORD_AUDIO),
    4
    MIC_PERMISSION_REQUEST_CODE // a code you set for monitoring whether or not the permission was granted
    5
    )
    Copied!
Configure your Android application for incoming calls.
    Incoming calls take advantage of Firebase Cloud Messaging. To get started with Cloud Messaging follow the Firebase set up instructions here. **

Making an Outgoing Call

Outgoing calls are made using the createVoiceCall method. The active call is returned to the provided delegate or listener once it connects. During this time the call can be considered to be in progress.
Swift
Kotlin
1
let localNumber: PhoneNumber!
2
let remoteNumber = "2024561414"
3
let delegate: ActiveCallDelegate
4
try! telephonyClient.createVoiceCall(localNumber: localNumber, remoteNumber: remoteNumber, delegate: delegate)
Copied!
1
val localNumber: PhoneNumber
2
val remoteNumber = "2024561414"
3
val listener: ActiveCallListener
4
telephonyClient.createVoiceCall(localNumber, remoteNumber, listener)
Copied!

Interacting With an Active Call

The active call delegate (iOS) / listener (Android) must be provided when a call is created and is used to communicate active call events such as when the call connects, disconnects, or fails.
If a call connects successfully, the delegate/listener will be provided with anActiveVoiceCall object via the activeVoiceCallDidConnect method. This object provides functions for manipulating the call such as muting the microphone, ending the call, or switching the audio to speakerphone.
Swift
Kotlin
1
public protocol ActiveCallDelegate {
2
​
3
/// Notifies the delegate that the call has connected
4
/// - Parameters:
5
/// - call: The `ActiveVoiceCall`
6
func activeVoiceCallDidConnect(_ call: ActiveVoiceCall)
7
​
8
/// Notifies the delegate that the call failed to connect
9
/// - Parameters:
10
/// - error: `CallingError` that occurred.
11
func activeVoiceCallDidFailToConnect(withError error: CallingError)
12
​
13
/// Notifies the delegate that the call has been disconnected
14
/// - Parameters:
15
/// - call: The `ActiveVoiceCall`
16
/// - error: Error that caused the call to disconnect if one occurred.
17
func activeVoiceCall(_ call: ActiveVoiceCall, didDisconnectWithError error: Error?)
18
​
19
/// Notifies the delegate that the call has been muted or un-muted
20
/// - Parameters:
21
/// - call: The `ActiveVoiceCall`
22
/// - isMuted: Whether outgoing call audio is muted
23
func activeVoiceCall(_ call: ActiveVoiceCall, didChangeMuteState isMuted: Bool)
24
​
25
/// Called when the system audio route has changed.
26
/// Use `call.isOnSpeaker` to determine if the call is on speaker.
27
///
28
/// - Parameter call: The `ActiveVoiceCall`
29
func activeVoiceCallAudioRouteDidChange(_ call: ActiveVoiceCall)
30
}
Copied!
1
interface ActiveCallListener : TelephonySubscriber {
2
/**
3
* Notifies the listener that the call has connected
4
* @param call The `ActiveVoiceCall`
5
*/
6
fun activeVoiceCallDidConnect(call: ActiveVoiceCall)
7
​
8
/**
9
* Notifies the listener that the call failed to connect
10
* @param exception An Exception that occurred
11
*/
12
fun activeVoiceCallDidFailToConnect(exception: Exception)
13
​
14
/**
15
* Notifies the listener that the call has been disconnected
16
* @param call The `ActiveVoiceCall`
17
* @param exception An optional Exception that is the cause of the disconnect if not null
18
*/
19
fun activeVoiceCallDidDisconnect(call: ActiveVoiceCall, exception: Exception?)
20
​
21
/**
22
* Notifies the listener that the call has been muted or un-muted
23
* @param call The `ActiveVoiceCall`
24
* @param isMuted Whether outgoing call audio is muted
25
*/
26
fun activeVoiceCallDidChangeMuteState(call: ActiveVoiceCall, isMuted: Boolean)
27
​
28
/**
29
* Notifies the listener that the call audio routing has changed
30
* @param call The `ActiveVoiceCall`
31
* @param audioDevice The `AudioDevice` that the audio has been routed to
32
*/
33
fun activeVoiceCallDidChangeAudioDevice(call: ActiveVoiceCall, audioDevice: VoiceCallAudioDevice)
34
}
Copied!

Receiving an Incoming Call

VOIP Notifications for Incoming Calls. Receiving incoming voice calls on iOS and Android devices requires APNS and FCM push credentials, respectively. If you would like to enable this functionality, contact your solutions engineer to assist you in configuring your environments with push credentials for your applications.
iOS
Android

Subscribe to Incoming Calls

In AppDelegate.swift import PushKit and add a PKPushRegistry variable:
AppDelegate.swift
1
import PushKit
2
class AppDelegate: UIResponder, UIApplicationDelegate {
3
// ...
4
var pushRegistry: PKPushRegistry!
5
}
Copied!
In the applicationDidFinishLaunchingWithOptions function set up the push registry:
1
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
2
// ...
3
self.pushRegistry = PKPushRegistry(queue: nil)
4
pushRegistry.delegate = self
5
pushRegistry.desiredPushTypes = [.voIP]
6
return true
7
}
Copied!
Implement the PKPushRegistryDelegate methods to register, deregister and handle incoming call push notifications. When a push notification comes in, pass the payload from the voip push on to the SudoTelephonyClient along with an IncomingCallNotificationDelegate:
1
extension AppDelegate: PKPushRegistryDelegate {
2
​
3
func pushRegistry(_ registry: PKPushRegistry, didUpdate pushCredentials: PKPushCredentials, for type: PKPushType) {
4
try! self.telephonyClient.registerForIncomingCalls(with: pushCredentials.token, useSandbox: true, completion: { (error) in
5
if let error = error {
6
// Error updating push credentials
7
}
8
else {
9
// Push credentials updated with telephony SDK
10
}
11
})
12
}
13
​
14
func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType, completion: @escaping () -> Void) {
15
let _ = try! self.telephonyClient.handleIncomingPushNotificationPayload(payload.dictionaryPayload, notificationDelegate: self)
16
completion()
17
}
18
​
19
func pushRegistry(_ registry: PKPushRegistry, didInvalidatePushTokenFor type: PKPushType) {
20
try! self.telephonyClient.deregisterForIncomingCalls(completion: { (error) in
21
if let error = error {
22
// Error de-registering for push notifications
23
} else {
24
// Successfully de-registered
25
}
26
})
27
}
28
}
Copied!

IncomingCallNotificationDelegate:

1
public protocol IncomingCallNotificationDelegate: class {
2
/// Called when an incoming call is recieved. This is called before reporting the call to callkit so the correct
3
/// display name can be provided.
4
///
5
/// In your implementation of this function you should set the `displayName` property of the incoming call that should be displayed by callKit.
6
///
7
/// You should also set the `delegate` of the incoming call. When the call is answered, `incomingCallAnswered(_ call: ActiveVoiceCall)` will be called
8
/// and future call related events will be delivered to the delegate.
9
func incomingCallReceived(_ call: IncomingCall) -> Void
10
​
11
/// Indicates that the incoming call was canceled.
12
/// - Parameter call: The incoming call
13
/// - Parameter error: The error that occured, if any.
14
func incomingCall(_ call: IncomingCall, cancelledWithError error: Error?)
15
​
16
​
17
/// An incoming call was answered through CallKit and is in the process of connecting.
18
/// No more updates on the incoming call will be provided to this delegate.
19
/// Future call updates will be provided to the delegate set on the incoming call delegate in `incomingCallReceived(_ call: IncomingCall) -> Void`.
20
func incomingCallAnswered(_ call: ActiveVoiceCall)
21
}
Copied!
When the incomingCallReceived() function is called, you can take the IncomingCall object and either accept the call or decline the call. The accept method takes an ActiveCallDelegate instance which will then handle all of the call events.

IncomingCall:

1
public protocol IncomingCall: class {
2
​
3
/// When an incoming call is recieved the delegate should be set in order to get updates on call related events.
4
/// For example if the call is answered through CallKit the delegate will recieve the call connected event with
5
/// a handle to the call.
6
var delegate: ActiveCallDelegate? { get set }
7
​
8
/// The phone number receiving the call
9
var localNumber: String { get }
10
​
11
/// The phone number the call is coming from
12
var remoteNumber: String { get }
13
​
14
/// The UUID for the call
15
var uuid: UUID { get }
16
​
17
/// Accepts the call with a delegate to provide call lifecycle updates.
18
func accept(with delegate: ActiveCallDelegate)
19
​
20
/// Decline the call.
21
func decline()
22
​
23
/// The display name used by callKit when reporting a call
24
var displayName: CallKitDisplayName? { get set }
25
}
Copied!

Subscribe to Incoming Calls

In order to receive calls you must first set up Firebase Cloud Messaging in your app. Instructions can be found here.
_**_Subscribe to incoming calls using the fcmToken provided by Firebase. The following code will fail if Google Play Services are not enabled on the device.
1
FirebaseInstanceId.getInstance().instanceId
2
.addOnCompleteListener(OnCompleteListener { task ->
3
if (!task.isSuccessful) {
4
// failed to get instance id
5
return@OnCompleteListener
6
}
7
​
8
val fcmToken = task.result!!.token
9
sudoTelephonyClient.calling.registerForIncomingCalls(fcmToken) { result ->
10
when (result) {
11
is Result.Success -> {
12
// successfully registered
13
}
14
is Result.Error -> {
15
// failed to register
16
}
17
}
18
}
19
})
Copied!

Handle Incoming Firebase Messages

When a message comes in from Firebase, pass it on to the SudoTelephonyClient along with an IncomingCallNotificationListener:
1
override fun onMessageReceived(message: RemoteMessage) {
2
super.onMessageReceived(message)
3
// listener: IncomingCallNotificationListener
4
sudoTelephonyClient.calling.handleIncomingPushNotification(message.data, listener)
5
}
Copied!

IncomingCallNotificationListener:

1
/**
2
* Listener for receiving notifications about new `IncomingCall` events.
3
*/
4
interface IncomingCallNotificationListener: TelephonySubscriber {
5
/**
6
* Notifies the listener that the call was received
7
* @param call The `IncomingCall`
8
*/
9
fun incomingCallReceived(call: IncomingCall)
10
​
11
/**
12
* Notifies the listener that the call was canceled
13
* @param call The `IncomingCall`
14
*/
15
fun incomingCallCanceled(call: IncomingCall, error: Throwable?)
16
}
Copied!
When the incomingCallReceived() function is called, you can take the IncomingCall object and either accept the call or decline the call. The accept method takes an ActiveCallListener instance which will then handle all of the call events.

IncomingCall:

1
class IncomingCall() {
2
/**
3
* The phone number receiving the call
4
*/
5
var localNumber: String
6
​
7
/**
8
* The phone number the call is coming from
9
*/
10
var remoteNumber: String
11
​
12
/**
13
* The unique string identifying the call invite
14
*/
15
var callSid: String
16
​
17
/**
18
* Accepts the call
19
* @param listener A listener to receive call lifecycle updates
20
*/
21
fun acceptWithListener(listener: ActiveCallListener)
22
​
23
/**
24
* Declines the call
25
*/
26
fun decline()
27
}
Copied!

Manage Call Records

A call record is generated for each call made and received. The SDK provides three methods for accessing that data and one for deleting call records.

Get Call Records

Retrieve a list of call records with a provided PhoneNumber and an optional limit and token for pagination:
Swift
Kotlin
1
// localNumber: PhoneNumber
2
// nextToken: String
3
try telephonyClient.getCallRecords(localNumber: localNumber, limit: nil, nextToken: nextToken) { (result) in
4
switch result {
5
case .success(let listToken):
6
// listToken: TelephonyListToken<CallRecord>
7
case .failure(let error):
8
// error: SudoTelephonyClientError
9
}
10
}
Copied!
1
// localNumber: PhoneNumber
2
// nextToken: String
3
sudoTelephonyClient.calling.getCallRecords(localNumber, null, nextToken) { result ->
4
when (result) {
5
is Result.Success -> {
6
// result.value.items: List<CallRecord>
7
}
8
is Result.Absent -> {
9
// no call records
10
}
11
is Result.Error -> {
12
// result.throwable: Throwable
13
}
14
}
15
}
Copied!

Get Call Record

Get a CallRecord providing its ID.
Swift
Kotlin
1
// callRecordId: String
2
try telephonyClient.getCallRecord(callRecordId: callRecordId) { (result) in
3
switch result {
4
case .success(let callRecord):
5
// callRecord: CallRecord
6
case .failure(let error):
7
// error: SudoTelephonyClientError
8
}
9
}
Copied!
1
// callRecordId: String
2
sudoTelephonyClient.calling.getCallRecord(callRecordId) { result ->
3
when (result) {
4
is Result.Success -> {
5
// result.value: CallRecord
6
}
7
is Result.Error -> {
8
// result.throwable: Throwable
9
}
10
}
11
}
Copied!

Subscribe To Call Records

Subscribe to CallRecord events and state changes. On iOS the subscribeToCallRecords() function returns a SubscriptionToken which can be used to cancel the subscription. On Android the function takes a CallRecordSubscriber instance which will receive CallRecord updates.
Swift
Kotlin
1
let subscriptionToken = try telephonyClient.subscribeToCallRecords(resultHandler: { (result) in
2
switch result {
3
case .success(let callRecord):
4
// callRecord: CallRecord
5
case .failure(let error):
6
// error: SudoTelephonyClientError
7
}
8
})
Copied!
1
sudoTelephonyClient.calling.subscribeToCallRecords(this, "CallRecordSubscriberId")
2
​
3
​
4
​
5
/**
6
* Subscriber for receiving notifications about new `CallRecord` objects.
7
*/
8
interface CallRecordSubscriber : TelephonySubscriber {
9
​
10
/**
11
* Notifies the subscriber of a new 'CallRecord'.
12
*/
13
fun callRecordReceived(callRecord: CallRecord)
14
}
Copied!

Delete Call Record

Delete a CallRecord providing its ID.
Swift
Kotlin
1
// callRecordId: String
2
try telephonyClient.deleteCallRecord(id: callRecordId) { (result) in
3
switch result {
4
case .success(let deletedId):
5
// deletedId: String
6
case .failure(let error):
7
// error: SudoTelephonyClientError
8
}
9
}
Copied!
1
// callRecordId: String
2
sudoTelephonyClient.calling.deleteCallRecord(callRecordId) { result ->
3
when (result) {
4
is Result.Success -> {
5
// result.value: String (callRecordId)
6
}
7
is Result.Error -> {
8
// result.throwable: Throwable
9
}
10
}
11
}
Copied!

Call Record

A CallRecord contains all the information for a voice call made or received.
Swift
Kotlin
1
public struct CallRecord {
2
/// Enum that represents the direction of the call.
3
public enum Direction {
4
case inbound
5
case outbound
6
case unknown
7
​
8
init(internalDirection: SudoTelephony.Direction) {
9
switch internalDirection {
10
case .inbound:
11
self = .inbound
12
case .outbound:
13
self = .outbound
14
case .unknown:
15
self = .unknown
16
}
17
}
18
}
19
​
20
// Enum that represents the state of the call record.
21
public enum State {
22
case authorized
23
case queued
24
case ringing
25
case answered
26
case completed
27
case unanswered
28
case unknown
29
​
30
init(internalState: CallState) {
31
switch internalState {
32
case .authorized:
33
self = .authorized
34
case .queued:
35
self = .queued
36
case .ringing:
37
self = .ringing
38
case .answered:
39
self = .answered
40
case .completed:
41
self = .completed
42
case .unanswered:
43
self = .unanswered
44
case .unknown:
45
self = .unknown
46
}
47
}
48
}
49
​
50
/// Voicemail data belonging to a call record
51
public struct VoicemailData {
52
/// Unique ID of the voicemail record
53
public let id: String
54
/// The duration of the voicemail recording in seconds
55
public let durationSeconds: UInt
56
/// The media object that can be used to download the voicemail recording
57
public let media: MediaObject
58
}
59
​
60
/// Unique ID of the call record
61
public let id: String
62
/// The user ID of the owner of the call record (also referred to as the subject)
63
public let owner: String
64
/// The ID of the sudo that made or received the call
65
public let sudoOwner: String
66
/// The ID of the `PhoneNumber` associated with the call record
67
public let phoneNumberId: String
68
/// The direction of the call. Either `outbound` or `inbound`
69
public let direction: Direction
70
/// The state of the call record
71
public let state: State
72
/// Timestamp that represents the last time the call was updated
73
public let updated: Date
74
/// Timestamp that represents the time the call was created
75
public let created: Date
76
/// The E164Number of the local phone number
77
public let localPhoneNumber: String
78
/// The E164Number of the remote phone number
79
public let remotePhoneNumber: String
80
/// The duration of the call in seconds
81
public let durationSeconds: UInt32
82
/// The voicemail data of this call record if it exists
83
public let voicemail: VoicemailData?
84
}
Copied!
1
data class CallRecord(
2
/**
3
* Unique ID of the call record
4
*/
5
val id: String,
6
/**
7
* The user ID of the owner of the call record (also referred to as the subject)
8
*/
9
val owner: String,
10
/**
11
* The ID of the sudo that made or received the call
12
*/
13
val sudoOwner: String,
14
/**
15
* The ID of the `PhoneNumber` associated with the call record
16
*/
17
val phoneNumberId: String,
18
/**
19
* The direction of the call. Either `outbound` or `inbound`
20
*/
21
val direction: Direction,
22
/**
23
* The state of the call record
24
*/
25
val state: CallRecordState,
26
/**
27
* Timestamp that represents the last time the call was updated
28
*/
29
val updated: Instant,
30
/**
31
* Timestamp that represents the time the call was created
32
*/
33
val created: Instant,
34
/**
35
* The E164Number of the local phone number
36
*/
37
val localPhoneNumber: String,
38
/**
39
* The E164Number of the remote phone number
40
*/
41
val remotePhoneNumber: String,
42
/**
43
* The duration of the call in seconds
44
*/
45
val durationSeconds: Int,
46
/**
47
* The voicemail data of this call record if it exists
48
*/
49
val voicemail: VoicemailData?
50
​
51
) : Parcelable
52
​
53
/**
54
* Enum that represents the state of the call record.
55
*/
56
enum class CallRecordState() {
57
AUTHORIZED,
58
QUEUED,
59
RINGING,
60
ANSWERED,
61
COMPLETED,
62
UNANSWERED,
63
UNKNOWN;
64
}
65
​
66
/**
67
* Voicemail data belonging to a call record
68
*/
69
data class VoicemailData (
70
/**
71
* Unique ID of the voicemail record
72
*/
73
val id: String,
74
/**
75
* The duration of the voicemail recording in seconds
76
*/
77
val durationSeconds: Int,
78
/**
79
* The media object that can be used to download the voicemail recording
80
*/
81
val media: MediaObject
82
) : Parcelable
Copied!

Voicemail

When an incoming call is rejected or times out, the caller is sent to voicemail. After hearing a recorded greeting, the caller can record up to 3 minutes of voicemail. The SDK provides several methods to manage these stored voicemail recordings.

Get Voicemails

Retrieve a list of voicemail records with a provided PhoneNumber and an optional limit and token for pagination:
Swift
Kotlin
1
// localNumber: PhoneNumber
2
// nextToken: String
3
telephonyClient.getVoicemails(localNumber: localNumber, limit: nil, nextToken: nextToken) { (result) in
4
switch result {
5
case .success(let listToken):
6
// listToken: TelephonyListToken<Voicemail>
7
case .failure(let error):
8
// error: SudoTelephonyClientError
9
}
10
}
Copied!
1
// localNumber: PhoneNumber
2
// nextToken: String
3
sudoTelephonyClient.calling.getVoicemails(localNumber, null, nextToken) { result ->
4
when (result) {
5
is Result.Success -> {
6
// result.value.items: List<Voicemail>
7
}
8
is Result.Absent -> {
9
// no voicemails
10
}
11
is Result.Error -> {
12
// result.throwable: Throwable
13
}
14
}
15
}
Copied!

Get Voicemail

Get a Voicemail by its ID.
Swift
Kotlin
1
// voicemailId: String
2
telephonyClient.getVoicemail(id: voicemailId) { (result) in
3
switch result {
4
case .success(let voicemail):
5
// voicemail: Voicemail
6
case .failure(let error):
7
// error: SudoTelephonyClientError
8
}
9
}
Copied!
1
// voicemailId: String
2
sudoTelephonyClient.calling.getVoicemail(voicemailId) { result ->
3
when (result) {
4
is Result.Success -> {
5
// result.value: Voicemail
6
}
7
is Result.Error -> {
8
// result.throwable: Throwable
9
}
10
}
11
}
Copied!

Subscribe To Voicemails

Subscribe to Voicemail create events, update events, and delete events. On iOS the subscribeToVoicemails() function returns a SubscriptionToken which can be used to cancel the subscription. On Android the function takes a VoicemailSubscriber instance which will receive Voicemail events.
Swift
Kotlin
1
let subscriptionToken = try telephonyClient.subscribeToVoicemails(resultHandler: { (result) in
2
switch result {
3
case .success(let voicemail):
4
// voicemail: Voicemail
5
case .failure(let error):
6
// error: SudoTelephonyClientError
7
}
8
})
Copied!
1
sudoTelephonyClient.calling.subscribeToVoicemails(this, "VoicemailSubscriberId")
2
​
3
​
4
​
5
/**
6
* Subscriber for receiving notifications about new `Voicemail` updates.
7
*/
8
interface VoicemailSubscriber : TelephonySubscriber {
9
​
10
/**
11
* Notifies the subscriber of a new 'Voicemail' update.
12
*/
13
fun voicemailUpdated(voicemail: Voicemail)
14
}
Copied!
Delete Voicemail
Delete a Voicemail by its ID.
Swift
Kotlin
1
// voicemailId: String
2
try telephonyClient.deleteVoicemail(id: voicemailId) { (result) in
3
switch result {
4
case .success:
5
// successfully deleted
6
case .failure(let error):
7
// error: SudoTelephonyClientError
8
}
9
}
Copied!
1
// voicemailId: String
2
sudoTelephonyClient.calling.deleteVoicemail(voicemailId) { result ->
3
when (result) {
4
is Result.Success -> {
5
// result.value: String (voicemailId)
6
}
7
is Result.Error -> {
8
// result.throwable: Throwable
9
}
10
}
11
}
Copied!

Voicemail Record

A Voicemail contains all the information for a voicemail recording.
Swift
Kotlin
1
public struct Voicemail {
2
/// Unique ID of the voicemail record
3
public let id: String
4
/// The ID of the Sudo Platform user that owns the voicemail.
5
public let owner: String
6
/// The ID of the Sudo that received the voicemail.
7
public let sudoOwner: String
8
/// The ID of the `PhoneNumber` associated with the voicemail.
9
public let phoneNumberId: String
10
/// The ID of the `CallRecord` associated with the voicemail.
11
public let callRecordId: String?
12
/// Timestamp that represents the time the voicemail was created.
13
public let created: Date
14
/// Timestamp that represents the last time the voicemail was updated.
15
public let updated: Date
16
/// The E.164 formatted phone number that received the voicemail.
17
public let localPhoneNumber: String
18
/// The E.164 formatted phone number of the caller.
19
public let remotePhoneNumber: String
20
/// The duration of the voicemail recording in seconds.
21
public let durationSeconds: UInt
22
/// The media object that can be used to download the voicemail recording.
23
public let media: MediaObject
24
}
Copied!
1
data class Voicemail(
2
/**
3
* Unique ID of the voicemail record
4
*/
5
val id: String,
6
/**
7
* The ID of the Sudo Platform user that owns the voicemail.
8
*/
9
val owner: String,
10
/**
11
* The ID of the Sudo that received the voicemail.
12
*/
13
val sudoOwner: String,
14
/**
15
* The ID of the `PhoneNumber` associated with the voicemail.
16
*/
17
var phoneNumberId: String,
18
/**
19
* The ID of the `CallRecord` associated with the voicemail.
20
*/
21
var callRecordId: String?,
22
/**
23
* Timestamp that represents the time the voicemail was created.
24
*/
25
val created: Instant,
26
/**
27
* Timestamp that represents the last time the voicemail was updated.
28
*/
29
val updated: Instant,
30
/**
31
* The E.164 formatted phone number that received the voicemail.
32
*/
33
val localPhoneNumber: String,
34
/**
35
* The E.164 formatted phone number of the caller.
36
*/
37
val remotePhoneNumber: String,
38
/**
39
* The duration of the voicemail recording in seconds.
40
*/
41
val durationSeconds: Int,
42
/**
43
* The media object that can be used to download the voicemail recording.
44
*/
45
val media: MediaObject
46
) : Parcelable
Copied!

Downloading Voicemail Audio Data

When voicemail records are retrieved, the audio data is not automatically downloaded. This gives you control over performance when retrieving voicemail records, particularly those with long recordings.
To download voicemail audio data, use the downloadData() method, passing it a MediaObject which can be retrieved from the media property of a Voicemail. This method returns the raw audio data.
Swift
Kotlin
1
import AVFoundation
2
​
3
let voicemail: Voicemail
4
telephonyClient.downloadData(for: voicemail.media) { (result) in
5
switch result {
6
case .success(let data):
7
let audioPlayer = try! AVAudioPlayer(data: data)
8
audioPlayer.play()
9
case .failure(let error):
10
// error: SudoTelephonyClientError
11
}
12
}
Copied!
1
// voicemail: Voicemail
2
sudoTelephonyClient.downloadData(voicemail.media) { result ->
3
when (result) {
4
is Result.Success -> {
5
// result.value: ByteArray
6
}
7
is Result.Error -> {
8
// result.throwable: Throwable
9
}
10
}
11
}
Copied!

Associating Voicemail Records with Call Records

Voicemail records and call records can be managed independently. However, a call record that has a corresponding voicemail has an additional voicemail property containing a copy of the voicemail data. When said voicemail is deleted this copy is also deleted.
Swift
Kotlin
1
let callRecord: CallRecord
2
if let voicemailData: CallRecord.VoicemailData = callRecord.voicemail {
3
// The call record has associated voicemail data.
4
// voicemailData.id: String
5
// voicemailData.durationSeconds: UInt
6
// voicemailData.media: MediaObject
7
}
Copied!
1
val callRecord: CallRecord
2
callRecord.voicemail?.let { voicemailData ->
3
// The call record has associated voicemail data.
4
// voicemailData.id: String
5
// voicemailData.durationSeconds: Int
6
// voicemailData.media: MediaObject
7
}
Copied!
The Voicemailrecord also has an optional callRecordId property which relates the voicemail to its call record if the call record has not been deleted.
Last modified 1yr ago