iOS
Calls Key Functions

Key Functions

This page explains key functions of Sendbird Calls consisting of how to make, receive, handle, and end a call from your client app.


DirectCall object

This object represents a one-to-one call. It has the following properties and functions:

Properties

Property nameDescription

callId

Type: String
A unique identifier for a direct call.

caller

Type: DirectCallUser
The user’s role that initiates the call.

callee

Type: DirectCallUser
The user’s role that receives the call.

callLog

Type: DirectCallLog
The history of the call. A value of nil indicates that the call is ongoing. The value after the call has ended can be different due to the synchronization with Sendbird server. This object's isFromServer property indicates whether the call log is from the server.

isEnded

Type: Bool
Indicates whether the call is ended.

isVideoCall

Type: Bool
Indicates whether the call is a video call. The call should be configured with the video call option when initiating it.

endResult

Type: DirectCallEndResult
The result of how the call has ended.

myRole

Type: DirectCall.UserRole
The role of the local user in the call.

localUser

Type: DirectCallUser
The local user of the call.

isLoaclAudioEnabled

Type: Bool
Indicates whether the local user has enabled their audio.

isLocalVideoEnabled

Type: Bool
Indicates whether the local user has enabled their video.

localVideoView

Type: SendBirdVideoView
The SendBirdVideoView object that represents the view which renders the local user’s video. Update this property by the updateLocalVideo(_:) method.

remoteUser

Type: DirectCallUser
The remote user of the call.

isRemoteAudioEnabled

Type: Bool
Indicates whether the remote user has enabled their audio.

isRemoteVideoViewEnabled

Type: Bool
Indicates whether the remote user has enabled their video.

remoteVideoView

Type: SendBirdVideoView
The SendBirdVideoView object that represents the view which renders the remote user’s video. Update this property by the updateRemoteVideo(_:) method.

startedAt

Type: Int64
The timestamp of when the call was dialed, in Unix milliseconds. A value of 0 indicates that the call hasn’t started yet.

endAt

Type: Int64
The timestamp of when the call was ended, in Unix milliseconds. A value of 0 indicates that the call hasn’t ended yet.

duration

Type: Int64
The period from the call was accepted to when the call was ended, in Unix milliseconds. A value of 0 indicates that the call hasn’t started yet.

customItems

Type: [String:String]
A dictionary of key-value items to store customized data for the call.

Methods

MethodDescription

accept(with: AcceptParams)

Accepts an incoming call.

end()

Ends the call. The DirectCallDelegate.didEnd(call:) delegate method will be called after receiving a success callback from Sendbird server. This delegate is also called when the remote user has ended the call.

muteMicrophone()

Mutes the local user's audio. The remote user will be notified through the DirectCallDelegate.didRemoteAudioSettingsChange() delegate method. If the remote user changes audio settings, the local user will be notified through the same delegate method.

unmuteMicrophone()

Unmutes the local user's audio. The remote user will be notified through the DirectCallDelegate.didRemoteAudioSettingsChange() delegate method. If the remote user changes audio settings, the local user will be notified through the same delegate method.

startVideo()

Starts the local user's video. The local user will be notified through the DirectCallDelegate.didRemoteVideoSettingsChange() delegate method if the remote user changes video settings.

stopVideo()

Stops the local user's video. The local user will be notified through the DirectCallDelegate.didRemoteVideoSettingsChange() delegate method if the remote user changes video settings.

updateLocalVideoView(_:)

Updates the SendBirdVideoView object of the local user. Another view object can be used to render the local video.

updateRemoteVideoView(_:)

Updates the SendBirdVideoView object of the remote user. Another view object can be used to render the remote video.

updateCustomItems(customItems:completionHandler:)

Updates the custom items of the call.

deleteCustomItems(customItemsKeys:completionHandler:)

Deletes the custom items of the call.

deleteAllCustomItems(completionHandler:)

Delete all custom items of the call.


DirectCallDelegate event delegate

MethodDescription

didConnect(call:)

Media devices (for example, microphone and speakers) between the caller and callee are connected and can start the call.

didEstablish(call:)

The callee has accepted the call by using the call.accept() method, but the media devices of caller and callee are not yet connected.

didStartReconnecting(call:)

The call begins attempting to reconnect to Sendbird server after losing connection.

didReconnect(call:)

The call successfully reconnects to Sendbird server.

didRemoteAudioSettingsChange(call:)

The remote user changes audio settings.

didRemoteVideoSettingsChange(call:)

The remote user changes video settings.

didEnd(call:)

One of the parties ends a call by using the call.end() method and a call is ended due to other reasons such as decline or connection lost.

didAudioDeviceChange(call:session:previousRoute:reason:)

The audio device has been changed. It provides information about the audio session, previous audio route, and change of reason.

didUpdateCustomItems(call:updatedKeys:)

The custom items of the call that match the updatedKeys parameter are updated.

didDeleteCustomItems(call:deletedKeys:)

The custom items of the call that match the deletedKeys parameter are deleted.


Make a call

Initiate a call by providing the callee’s user ID into the SendBirdCall.dial() method. Use the CallOptions object to choose a call’s initial settings.

Light Color Skin
Copy
let directCall = SendBirdCall.dial(to: CALLEE_ID, callOptions: CallOptions()) { (directCall, error) in
    // 
}

directCall.delegate = self

Configure video settings

In a video call, configure the video view settings prior to making the call so that the transition from a voice call to a video call will be seamless. Create SendBirdVideoView instances to render local and remote video streams as shown below:

Light Color Skin
Copy
let localSBView = SendBirdVideoView(frame: self.localVideoView?.frame ?? CGRect.zero) 
let remoteSBView = SendBirdVideoView(frame: self.remoteVideoView?.frame ?? CGRect.zero)
 
self.call.updateLocalVideoView(localSBView)
self.call.updateRemoteVideoView(remoteSBView)
 
// When making a call or accepting an incoming call.
let callOptions = CallOptions(
            isAudioEnabled = true,
            isVideoEnabled = true,
            localVideoView: localSBVideoView
            remoteVideoView: remoteSBVideoView)
 
// Or when updating local / remote view
self.call.updateLocalVideoView(localSBView)
self.call.updateRemoteVideoView(remoteSBView)

Receive a call

To receive an incoming call, a SendBirdCallDelegate event delegate should already be registered in the callee’s client app. Accept or decline the call using the directCall.accept() or the directCall.end() method. If the call is accepted, a media session will automatically be established by the Calls SDK.

Before accepting the call, the call-specific DirectCallDelegate event delegate must be added to the call object. It enables the callee’s app to react to events during the call through its delegate methods.

Light Color Skin
Copy
class MyClass: SendBirdCallDelegate {
    func didEnterRinging(_ call: DirectCall) { 
        call.delegate = self
    }
}

The callee’s client app receives an incoming call through either the established connection with Sendbird server or PushKit if the app uses CallKit. To use the Calls SDK in the callee’s client app, the SendBirdCall instance must deliver received PushKit messages to the Calls SDK.

Light Color Skin
Copy
class AppDelegate: PKPushRegistryDelegate {
    func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType, completion: @escaping () -> Void) {
        SendBirdCall.pushRegistry(registry, didReceiveIncomingPushWith: payload, for: type)
    }
}

If a client app has CallKit implemented and propagates PushKit messages through the PKPushRegistryDelegate’s pushRegistry(:didReceiveIncomingPushWith:for:completion) method, incoming calls displayed by PushKit messages should be delivered to the DidStartRinging delegate method as shown below:

Light Color Skin
Copy
func didStartRinging(_ call: DirectCall) { 
    // IMPORTANT: An incoming call should be delivered to this delegate method when you receive a PushKit push message for the call.
    let provider = CXProvider(configuration: CXProviderConfiguration)
    let update = CXCallUpdate()
    update.remoteHandle = CXHandle(type: .generic, value: HANDLE_VALUE)
    provider.reportNewIncomingCall(with: uuid, update: update) { (error) in
        completion()
    })
}

Handle a current call

Audio

During a current call, both the caller and callee’s audio can be muted or unmuted by the directCall.muteMicrophone() or directCall.unmuteMicrophone() method. If one party changes audio settings, the other party receives an event callback through the DirectCallDelegate.didRemoteAudioSettingsChange(_:) delegate method.

Light Color Skin
Copy
// Mute my microphone
call.muteMicrophone()
// Unmute my microphone
call.unmuteMicrophone()
class MyClass: SendBirdCallDelegate {
    func didRemoteAudioSettingsChange(_ call: DirectCall) {
        if (call.isRemoteAudioEnabled) {
            // The remote user has been unmuted. 
            // TODO: Update UI components accordingly
             } else {
            // The remote user has been muted. 
            // TODO: Update UI components accordingly
             }
         }
}

Video

During a current call, both the caller and callee’s video can be enabled or disabled by the directCall.startVideo() or directCall.stopVideo() method. If one party changes audio settings, the other party receives an event callback through the DirectCallDelegate.didRemoteVideoSettingsChange(_:) delegate method.

Light Color Skin
Copy
// Start my local video
call.startVideo()
// Stop my local video
call.stopVideo()
 
// receives the event
class MyClass: DirectCallDelegate {
    func didRemoteVideoSettingsChange(_ call: DirectCall) {
        if (call.isRemoteVideoEnabled) {
            // The remote user has started video.
        } else {
            // The remote user has ended video.
        }
    }
}

End a call

The directCall.end() method ends a current call of either the caller or callee’s side. If one party ends a current call, the other party receives an event callback through the DirectCallDelegate.didEnd() method.

Light Color Skin
Copy
// End a call
call.end();
 
// Receiving the end event
class MyClass: DirectCallDelegate {
    ...
    
    func didEnd(_ call: DirectCall) {
        // TODO: Update UI components accordingly
    }

    ...
}

Manage custom items

With custom items, you can store additional information to a call in addition to default values in the DirectCall object. These key-value custom items are delivered as a [String: String] dictionary and can be updated during the call. Examples of items that could be included in the call are customer service, refund, or inquiry for better user experience.

Add

Custom items can be added to a call either by a caller or a callee. When dialing, the caller can add a [String: String] to the customItems of DialParam. The default value of customItems is an empty dictionary.

Light Color Skin
Copy
let customItemsToAdd = ["key1": "value1", "key2": "value2"]
call.updateCustomItems(customItems: customItemsToAdd) { (addedCustomItems, addedCustomItemKeys, error) in 
    // Handle added custom items.
}

Update and delete

During a call, custom items can be modified by directly updating or deleting custom items of a given call. You can use directCall.updateCustomItems(:completionHandler:) to update current custom items with new custom items. If keys for the new custom items don't exist, new custom items will be added to the existing list of items. Otherwise, existing items will be replaced with new custom items.

You can modify custom items without directly referring to the DirectCall object. The custom items of the call from the SendBirdCall can also be modified by calling the same set of methods with an additional callId parameter. If a call with the corresponding callId exists, the SendBirdCall will update the custom items of that call.

You can delete a specific custom item with its given key by using directCall.deleteCustomItems(:completionHandler:) or delete all the items associated with the call by using directCall.deleteAllCustomItems(:). Through a completion handler, you will receive the updated custom items, a list of keys of the modified custom items, and an error from Sendbird server.

Light Color Skin
Copy
let customItemsToModify = ["key1": "value3", "key2": "value4"]
call.updateCustomItems(customItems: customItemsToModify) { (modifiedCustomItems, modifiedCustomItemKeys, error) in 
    // Handle updated custom items.
}

let customItemKeysToDelete = ["key1", "key2"]
call.deleteCustomItems(customItemKeys: customItemKeysToDelete) { (deletedCustomItems, deletedCustomItemKeys, error) in
    // Handle deleted custom items.
}

call.deleteAllCustomItems { (deletedCustomItems, deletedCustomItemKeys, error) in
    // Handle deleted custom items. 
}

Receive events

To receive events from Sendbird server when custom items are modified, you can implement didUpdateCustomItems() and didDeleteCustomItems() from the DirectCallDelegate. Events contain the DirectCall object of changed custom items and updatedKeys or deletedKeys. Custom items can always be modified, however these events will only be delivered if the call is ongoing. If the call ends, events are not delivered to the DirectCallDelegate. You can always access modified custom items even after the call ends with the Calls API or by using the directCall.customItems.

Light Color Skin
Copy
class MyClass: DirectCallDelegate {
    ...
    
    func didUpdateCustomItems(call: DirectCall, updatedKeys: [String]) {
        // Handle updated custom items with 'call.customItems' and 'updatedKeys'. 
    }

    func didDeleteCustomItems(call: DirectCall, deletedKeys: [String]) {
        // Handle deleted custom items with 'call.customItems' and 'deletedKeys'.
    }
    ...

}

Retrieve call information

One party’s information can be retrieved through the directCall.getLocalUser() method while the other party’s information through the directCall.getRemoteUser() method.


Retrieve call history

A user’s call history can be retrieved using the next() method of a DirectCallLogListQuery instance which returns a list of call objects.

Light Color Skin
Copy
let params = DirectCallLogListQuery.Params()
params.myRole = .caller     // Filter for current user’s role in the call
params.endResultsArray = [.cancel, .decline, .complete]     // Filter for end results of the call
params.limit = 25       // Number of call logs to be returned at once. 
let query = SendBirdCall.createDirectCallLogListQuery(with: params)
 
if query.hasNext {
    query.next() { [weak query] (callLogs, error) in
        // The 'query.next()' can be called once more to fetch more call logs.
    }
}

The call log can be immediately obtained after a call has ended. However, in the caller’s case, only the local log will be retrieved unless the sync has been made with the server. If you want to check whether a call log is synchronized with the server or not, use the directCallLog.isFromServer. To retrieve call history from the server instead of the local log, use the SendBirdCall.DirectCallLogListQuery.

Light Color Skin
Copy
class MyClass: DirectCallDelegate {
    ...

    func didEnd(_ call: DirectCall) {
        ...
        
        let callLog = call.callLog
        // Appropriately add this callLog object to the callLog list.
    }
}