Direct call
This page explains key functions of direct call consisting of how to make, receive, handle, and end a call from your app.
DirectCall object
This object represents a 1-to-1 call. It has the following properties and functions:
Properties
Name | Description |
---|---|
callId | Type: String |
caller | Type: DirectCallUser |
callee | Type: DirectCallUser |
callLog | Type: DirectCallLog |
isEnded | Type: Bool |
isVideoCall | Type: Bool |
endResult | Type: DirectCallEndResult |
myRole | Type: DirectCall.UserRole |
localUser | Type: DirectCallUser |
isLocalAudioEnabled | Type: Bool |
isLocalVideoEnabled | Type: Bool |
localVideoView | Type: SendBirdVideoView |
remoteUser | Type: DirectCallUser |
isRemoteAudioEnabled | Type: Bool |
isRemoteVideoViewEnabled | Type: Bool |
remoteVideoView | Type: SendBirdVideoView |
startedAt | Type: Int64 |
endAt | Type: Int64 |
duration | Type: Int64 |
customItems | Type: [String:String] |
Methods
Name | Description |
---|---|
accept(with: AcceptParams) | Accepts an incoming call. |
end() | Ends the call. The |
muteMicrophone() | Mutes the local user's audio. The remote user will be notified through the |
unmuteMicrophone() | Unmutes the local user's audio. The remote user will be notified through the |
startVideo() | Starts the local user's video. The local user will be notified through the |
stopVideo() | Stops the local user's video. The local user will be notified through the |
updateLocalVideoView(_:) | Updates the |
updateRemoteVideoView(_:) | Updates the |
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
Method | Description |
---|---|
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 |
didStartReconnecting(call:) | The call begins attempting to reconnect to Sendbird server after losing connection. |
didReconnect(call:) | The call successfully reconnects to Sendbird server. |
didEnd(call:) | One of the parties ends a call by using the |
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. |
didRemoteAudioSettingsChange(call:) | The remote user changes audio settings. |
didRemoteVideoSettingsChange(call:) | The remote user changes video settings. |
didRemoteRecordingStatusChange(Call:) | The remote user has changed their recording status. |
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. |
didCalleeReceiveDial(call:) | The callee has received the call notification through the |
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.
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:
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.
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.
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:
Handle an active call
Audio
During an active 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.
Video
During an active 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.
End a call
The directCall.end()
method ends an ongoing call of either the caller or callee’s side. If one party ends an ongoing call, the other party receives an event callback through the DirectCallDelegate.didEnd()
method.
Hold and resume a call
During an active call, users can hold and resume the call. Users can talk to each other on a single active call at a time while putting other ongoing calls on hold. An active call and calls on hold are ongoing calls. By holding a call, users can accept an incoming call or switch between ongoing calls.
Note: Credit usage and billing for a call on hold is the same as with an active call because they are both considered as ongoing calls.
Hold a call
During an active call, a user can hold the call by using the directCall.hold()
method. When an active call is put on hold, audio and video also stops for the call. Therefore, functionalities that require audio and video such as screen share, local recording, and screen capture will not be available for a call that is put on hold.
When a call is placed on hold, the value of directCall.isOnHold
changes to true
and the users will receive a notification on the change of the hold status of the call through the DirectCallDelegate.didUserHoldStatusChange
method.
Unhold a call
A user can only remove their own hold on a call by using the directCall.unhold()
method.
If you try to call the directCall.unhold()
method on a call that is on hold while there is an active call, an error will be returned. If you wish to override this error, you have to forcefully end the active call by calling the directCall.unhold()
method with the force
parameter as true
.
When a hold is removed from a call, users will receive a notification on the change of the hold status of the call through the DirectCallDelegate.didUserHoldStatusChange
method.
Resumed call
Both the caller and callee must return to the same ongoing call in order to resume a call to talk to each other. The users should either hold or end other ongoing calls except for the call they would like to return to. By using the directCall.unhold()
method, the users can remove a hold on the same ongoing call. Once both users remove their holds from the call, audio and video also becomes available for the call which will be resumed.
When the both users remove holds on the same ongoing call, the value of directCall.isOnHold
changes to false
and users will receive a notification on the change of the hold status of the call through the DirectCallDelegate.didUserHoldStatusChange
method.
Accept an incoming call
You can accept an incoming call while there is an active call. Because there can only be one active call at a time, the active call must be either ended or put on hold before the incoming call is accepted.
To end an active call and accept an incoming call, use the directCall.accept()
method. The active call will end and the end result will show as .completed
.
To hold an active call and accept an incoming call, use the directCall.accept()
method with AcceptParams.holdActiveCall
set to true
. The active call will be placed on hold and the incoming call will become the active call.
Retrieve a list of ongoing calls
When there are multiple calls on hold, you can retrieve a list of all ongoing calls by using the SendBirdCall.getOngoingCalls()
method.
Retrieve a list of incoming calls
You can retrieve a list of all incoming calls by using the SendBirdCall.getIncomingCalls()
method.
Receive notifications
You can receive notifications when a local or remote user puts a call on hold or removes a hold from a call. When the hold status of the user changes, the DirectCallDelegate.didUserHoldStatusChange(_:isLocalUser:isUserOnHold:)
delegate method will be called. The isLocalUser
and isUserOnHold
parameters can be used to identify which user has put certain calls on hold. To identify which calls are put on hold by either or both users, use the directCall.isOnHold
property.
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.
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.
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
.
Retrieve call information
One party’s information can be retrieved through the directCall.localUser
property while the other party’s information through the directCall.remoteUser
property.
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.
Parameters in DirectCallLogListQuery.Params
These parameters must be set before initiating the query with the next()
method. They configure the criteria and limits for the call log retrieval, including their default values.
Parameter | Type | Default | Description |
---|---|---|---|
myRole |
|
| Filters call logs by the user's role (caller, callee, all). |
endResults |
|
| Filters call logs based on the end results of calls, such as no answer or canceled. Multiple results are combined with an OR condition. |
limit |
|
| Sets the maximum number of call logs to retrieve per query, with a cap of 100 logs. |
setStartedAt |
|
| Sets the beginning timestamp for retrieving call logs. The query includes logs starting from this timestamp. Default behavior without |
setEndedAt |
|
| Sets the ending timestamp for retrieving call logs. The query includes logs up to this timestamp. Default behavior without |
Synchronization and Retrieval of 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
.
Retrieve missed direct calls
You can receive and be notified of new incoming calls through push notifications. However, if you're unable to do so due to issues with push notifications, you can use the SendBirdCall.retrieveMissedDirectCalls()
method to pick up the incoming call. The incoming call will be received through SendBirdCallDelegate.didStartRinging()
.
If you received a push notification of an incoming call through SendBirdCallDelegate.didStartRinging()
but failed to process it, you can get a list of all incoming calls, including ones that are currently ringing, through SendBirdCall.getIncomingCalls()
.
Note:
SendBirdCall.retrieveMissedDirectCalls()
is automatically triggered internally when the Calls SDK has been successfully authenticated.
You can also identify where a call is coming from through the DirectCall.ringingSource
property.
List of properties of ringingSource
Property name | Description |
---|---|
push | When a call arrives through a push notification. |
retrieval | When a call arrives by invoking the |
websocket | When a call arrives through the websocket. |
Select video output
Users can select a device for video output during a video call. The list of available video devices can be accessed by the DirectCall.availableVideoDevices()
method. In order to change the current video output device to one of the other available video devices, the DirectCall.selectVideoDevice(completionHandler:)
method should be called.
To turn on the switch between the front and back cameras function, use the switchCamera(completionHandler:)
method.
Capture video views
During a video call, the caller and callee can capture the images of their streaming video by using either the captureLocalVideoView()
or captureRemoteVideoView()
methods when needed.
Local video view
Parameters
Name | Description |
---|---|
completionHandler | Type: CaptureVideoViewHandler |
Remote video view
Parameters
Name | Description |
---|---|
completionHandler | Type: CaptureVideoViewHandler |
Note: For errors that may occur when capturing video views, see the Error codes page.
Record audio and video
When making a direct call with Sendbird Calls, audio and video recordings for both local and remote users are available. The recorded file will be saved on the user’s local file storage and users can transfer or process the file.
Only one ongoing recording session is allowed, which means that the current recording session must be stopped in order to start another recording. However, several sessions can be recorded throughout the call, thus multiple recording files created from one call.
The SendBirdCall
currently supports five recording types:
Recording types
Type | Description |
---|---|
remoteAudioAndVideo | An option to record the video and audio of the remote user. |
remoteAudioOnly | An option to record the audio of the remote user. |
localRemoteAudios | An option to record both audios of the local and remote users. |
localAudioRemoteAudioAndVideo | An option to record both audios of the local and remote users, and the video of the remote user. |
localAudioAndVideoRemoteAudio | An option to record both audios of the local and remote users, and the video of the local user. |
Start recording a call
Start recording a call using the directCall.startRecording()
method. You can customize the type and the name of the recording as well as the output path where a recorded file will be saved with a RecordingOptions
object.
If the name of a file isn't specified for the filename
parameter in the method, the recorded file’s name will follow the default pattern of {recording_type}_{call_id}_{timestamp}
.
A recordingId
is delivered through the completion handler of the directCall.startRecording()
method when the recording starts successfully. Make sure to save the recordingId
to stop the recording session. If the recordingId
is invalid or missing when the directCall.stopRecording()
method is called, you can’t stop the recording session when needed.
Note: The
SendBirdCall
doesn’t check for file read and write permissions or any other permissions related to the media. Make sure that the application can write at the specified destination folder before starting a recording session.
Stop recording a call
Stop recording a call using the directCall.stopRecording()
method with the recordingId
received from the completion handler of the directCall.startRecording()
method. If a recording session isn’t stopped by the time the call has ended, the recording session automatically ends as well.
After the recording is finished, the SendBirdRecordingDelegate.didSaveRecording()
event delegate method will be called.
Receive events
In order to receive events about the completion of the recordings, add a device-specific SendBirdRecordingDelegate
by using the SendBirdCall.addRecordingDelegate(:)
delegate method. Once the event delegate is added, your app can handle the following two events as shown below:
You can remove the device-specific SendBirdRecordingDelegate
as shown below:
Note: The
SendBirdRecordingDelegate.didFailToSaveRecording()
event delegate method won’t be called if errors occur at the start of recording sessions after calling thedirectCall.startRecording()
method.
Recorded files
While streaming audio or video is being recorded, it is transcoded almost simultaneously to convert the stream into an MP4
file regardless of the recording option. After your recording is done, it typically takes less than a second to save the recording as an MP4
file.
Recorded videos will have a fixed frame size of 1280x720
pixels. Video recording uses around 20 MB of data per minute, but this may vary depending on the type of the recording content.
The SendBirdCall
doesn’t handle anything related to managing recorded files. If there isn’t enough storage to save the recorded file, SendBirdRecordingDelegate.didFailToSaveRecording
will be called.
Recording notifications
During a voice or video call, users can notify each other if the call is being recorded.
If a user starts or stops local recording on their device, the other user will be able to receive an event callback through the DirectCallDelegate.didRemoteRecordingStatusChange(_ call: DirectCall)
delegate method. Users can also check the recording status of the other user with DirectCall.remoteRecordingStatus
.
During a video call, both the caller and callee can share their screens with each other by using Apple’s ReplayKit.
When the startScreenShare
method is called, both the local user's localVideoView
and the remote user’s remoteVideoView
will be replaced with the screen share view. Currently, displaying the local camera view and the local screen share view together is not supported. If RPScreenRecorder.startCapture
is invoked, the operating system will automatically ask the user to confirm the permission to record the screen.
Note: There is a known issue in iOS that if the user is recording the remote video view while the remote user is sharing the screen, it will result in a distorted video view.
You can stop sharing your screen and return to the video view as shown below:
Note: To learn more about implementing screen sharing, see our tutorial.
Add sound effects
You can use different sound effects to enhance the user experience for events that take place while using Sendbird Calls.
To add sound effects, use the SendBirdCall.addDirectCallSound(_:forType:)
method for the following events: dialing
, ringing
, reconnecting
, and reconnected
. Remember to set sound effects before the mentioned events occur. To remove sound effects, use the SendBirdCall.removeDirectCallSound(_:forType:)
method.
To set the dialing sound effect in silent mode, use the setDirectCallDialingSoundOnWhenSilentMode(isEnabled:)
method.
If you’re using Apple’s CallKit framework, you should use CXProviderConfiguration.ringtoneSound
instead to add sound effects as ringtones like the following:
For more information about sound effects, refer to our Calls SDK GitHub repository's README.
Manage call quality
Users can receive notifications about the changes in call quality so that they can check their network connection to avoid any interruption during an active call.
Set ConnectionQualityDelegate
To detect changes in call quality, you need to set ConnectionQualityDelegate
and select a monitoring mode by calling the setConnectionQualityDelegate()
method. Based on the specified monitoring mode, the didConnectionQualityUpdate
method will be called.
ConnectionQualityMonitoringMode
Properties | Description |
---|---|
frequency | Monitors the frequency of connection quality which occurs every 3 seconds when the |
connectionQualityChange | Monitors the changes in connection quality level which calls the |
The connection quality in the ConnectionMetrics
class represents the quality of the call based on the value of Mean Opinion Score (MOS). MOS is a subjective measure that is used to evaluate the overall quality of direct calls. Scores range from 0.0
to 4.5
and has the following quality states.
List of ConnectionQuality states
State | MOS | Description |
---|---|---|
Poor | 0.0 - 2.0 | The call connection is unstable and some parts of the conversation may not be audible or may be repeated. |
Fair | 2.0 - 3.0 | The call connection is somewhat unstable, but most of the conversation is delivered without any issues. |
Average | 3.0 - 3.6 | The call connection is stable and the conversation is clearly delivered. |
Good | 3.6 - 4.2 | The call connection is extremely stable and the conversation is delivered with crystal-clear sound quality. |
Excellent | 4.2 - 4.5 | The highest level of call connection that delivers the conversation with extremely clean and clear sound quality. |
Depending on the ConnectionQuality
enum, you can determine the current quality of the call and take appropriate actions to improve the call quality. For example, you can choose to show a quality degradation alert to the user if the connection quality drops below average.
Remove ConnectionQualityDelegate
Call the removeConnectionQualityDelegate()
method to remove all previous settings.