Calls SDKs Android v1
Calls SDKs Android
Calls SDKs
Android
Version 1

Direct call

Copy link

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


Make a call

Copy link

Initiate a call by providing the callee’s user id into the SendBirdCall.dial() method. Use the CallOptions object to choose initial call configuration, such as audio or video capabilities, video settings, and mute settings.

DialParams params = new DialParams(CALLEE_ID);
params.setVideoCall(true);
params.setCallOptions(new CallOptions());

DirectCall call = SendBirdCall.dial(params, new DialHandler() {
    @Override
    public void onResult(DirectCall call, SendBirdException e) {
        if (e == null) {
            // The call has been created successfully.
        }
    }
});

Receive a call

Copy link

To receive an incoming call, a SendBirdCallListener event handler 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 DirectCallListener event handler must be added to the call object. It enables the callee’s app to react to events during the call through its callback methods.

SendBirdCall.addListener(UNIQUE_HANDLER_ID, new SendBirdCallListener() {
    @Override
    public void onRinging(DirectCall call) {
        call.setListener(new DirectCallListener() {
            @Override
            public void onEstablished(DirectCall call) {
            }

            @Override
            public void onConnected(DirectCall call) {
            }

            @Override
            public void onEnded(DirectCall call) {
            }

            @Override
            public void onRemoteAudioSettingsChanged(DirectCall call) {
            }

        });

        call.accept(new AcceptParams());
    }
});

The callee’s client app receives an incoming call through either the established connection with Sendbird server or a Firebase Cloud Messaging (FCM) push notification when the app is in the background. To use the Calls SDK in the callee’s client app, the SendBirdCall instance must deliver received FCM push notifications to the Calls SDK.

public class MyFirebaseMessagingService extends FirebaseMessagingService {
    @Override
    public void onMessageReceived(@NonNull RemoteMessage remoteMessage) {
        if (SendBirdCall.handleFirebaseMessageData(remoteMessage.getData())) {

        } else {
            // Handle non-SendBirdCall Firebase messages.
        }
    }
}

Handle an active call

Copy link

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 DirectCallListener.onRemoteAudioSettingsChanged() method.

// Mute my microphone
directCall.muteMicrophone();
// Unmute my microphone
directCall.unmuteMicrophone();
// Start to show video
directCall.startVideo();
// Stop showing video
directCall.stopVideo();

// Receive the event
directCall.setListener(new DirectCallListener() {
    ...

    @Override
    public void onRemoteAudioSettingsChanged(DirectCall call) {
        if (call.isRemoteAudioEnabled()) {
            // The remote user has been unmuted.
            // Display an unmuted icon.
        } else {
            // The remote user has been muted.
            // Display and toggles a muted icon.
        }
    }

    @Override
    public void onRemoteVideoSettingsChanged(DirectCall call) {
        if (call.isRemoteVideoEnabled()) {
            // The remote user has started video.
        } else {
            // The remote user has stopped video.
        }
    }
    ...

});

End a call

Copy link

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 DirectCallListener.onEnded() method.

// End a call
directCall.end();

...

// Receive the event
directCall.setListener(new DirectCallListener() {
    ...

    @Override
    public void onEnded(DirectCall call) {
        // Release or destroy call-related views from here.
    }
    ...

});

Hold and resume a call

Copy link

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 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

Copy link

During an active call, you 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.

call.hold(object : CompletionHandler {
    override fun onResult(e: SendBirdException?) {
        if (e == null) {
            // Call is successfully 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 DirectCallListener.onUserHoldStatusChanged() method.

Unhold a call

Copy link

A user can only remove their own hold on a call by using the directCall.unhold() method.

call.unhold(false, object : CompletionHandler {
    override fun onResult(e: SendBirdException?) {
        if (e == null) {
            // A hold is successfully removed from the call.
        }
    }
})

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 DirectCallListener.onUserHoldStatusChanged() method.

Resumed call

Copy link

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 DirectCallListener.onUserHoldStatusChanged() method.

Accept an incoming call

Copy link

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.

override fun onRinging(call: DirectCall) {
    val acceptParams = AcceptParams().setHoldActiveCall(true)
    call.accept(acceptParams)
}

Retrieve a list of ongoing calls

Copy link

When there are multiple calls on hold, you can retrieve a list of all ongoing calls by using theSendBirdCall.ongoingCalls method.

val callOnHold = SendBirdCall.ongoingCalls.firstOrNull { it.isOnHold }
callOnHold?.unhold(true, object : CompletionHandler {
    override fun onResult(e: SendBirdException?) {}
})

Retrieve a list of incoming calls

Copy link

You can retrieve a list of all incoming calls by using the SendBirdCall.incomingCalls method.

val incomingCalls = SendBirdCall.incomingCalls

Receive notifications

Copy link

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 DirectCallListener.onUserHoldStatusChanged(call: DirectCall, isLocalUser: Boolean, isUserOnHold: Boolean) 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.

class MyDirectCallListener : DirectCallListener() {
    override fun onUserHoldStatusChanged(call: DirectCall, isLocalUser: Boolean, isUserOnHold: Boolean) {
        // Use `isLocalUser` and `isUserOnHold` to identify the users' hold status of a call.
        // Use the updated `call.isOnHold` value to update the call view.
    }
}

Manage custom items

Copy link

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 Map<String, String> 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.

Custom items can be added to a call either by a caller or a callee. When dialing, the caller can add a Map<String, String> to a DialParams object by using the setCustomItems() method. The default value of a call's custom items is an empty Map object.

Map<String, String> customItemsToAdd = new HashMap<>();
customItemsToAdd.put("key1", "value1");
customItemsToAdd.put("key2", "value2");
directCall.updateCustomItems(customItemsToAdd, (addedCustomItems, affectedKeys, e) -> {
    // Handle added custom items.
});

Update and delete

Copy link

During a call, custom items can be modified by directly updating or deleting custom items of a given call. You can use directCall.updateCustomItems() 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() or delete all custom 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.

Map<String, String> customItemsToModify = new HashMap<>();
customItemsToModify.put("key1", "value3");
customItemsToModify.put("key2", "value4");
directCall.updateCustomItems(customItemsToModify, (modifiedCustomItems, affectedKeys, e) -> {
    // Handle updated custom items.
});

Set<String> customItemKeysToDelete = new HashSet<>();
customItemsKeysToDelete.add("key1");
customItemsKeysToDelete.add("key2");
directCall.deleteCustomItems(customItemKeysToDelete, (deletedCustomItems, affectedKeys, e) -> {
    // Handle deleted custom items.
});

directCall.deleteAllCustomItems((deletedCustomItems, affectedKeys, e) -> {
    // Handle deleted custom items.
});

Receive events

Copy link

To receive events from Sendbird server when custom items are modified, you can implement onCustomItemsUpdated() and onCustomItemsDeleted() from the DirectCallListener. Events contain the DirectCall object of changed custom items and updatedKeys or deletedKeys. Custom items can always be modified, custom items are always modifiable, 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 DirectCallListener. You can always access modified custom items with the Calls API or by using the directCall.getCustomItems().

directCall.setListener(new DirectCallListener() {
    ...

    @Override
    public void onCustomItemsUpdated(DirectCall call, List<String> updatedKeys) {
    }

    @Override
    public void onCustomItemsDeleted(DirectCall call, List<String> deletedKeys) {
    }

    ...
});

// You can get the call's custom items by calling the getCustomItems() method.
directCall.getCustomItems();

Add event handlers

Copy link

There are two types of event handlers that the Calls SDK provides: SendBirdCallListener and DirectCallListener.

SendBirdCallListener

Copy link

Add a device-specific SendBirdCallListener event handler using the SendBirdCall.addSendBirdCallListener() method. Once the event handler is added, responding to device events such as incoming calls can be managed as shown below.

Note: If a SendBirdCallListener event handler isn’t registered, a user can't receive an onRinging callback event, thus recommended to add this handler at the initialization of the app. Also, the SendBirdCallListener event handler is automatically removed when the app closes by default.

//The UNIQUE_HANDLER_ID below is a unique user-defined ID for a specific event handler.
SendBirdCall.addListener(UNIQUE_HANDLER_ID, new SendBirdCallListener() {
    @Override
    public void onRinging(DirectCall call) {
    }
});

List of methods

Copy link
MethodInvoked when

onRinging()

An incoming call is notified on the callee’s device.

onAudioInputDeviceChanged()

There are changes in the system’s audio input device or the available local audio input devices.

onAudioOutputDeviceChanged()

There are changes in the system’s audio output device or the available local audio output devices.

DirectCallListener

Copy link

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

directCall.setListener(new DirectCallListener() {
    @Override
    public void onEstablished(DirectCall call) {
    }

    @Override
    public void onConnected(DirectCall call) {
    }

    @Override
    public void onEnded(DirectCall call) {
    }

    @Override
    public void onRemoteAudioSettingsChanged(DirectCall call) {
    }

    @Override
    public void onCustomItemsUpdated(DirectCall call) {
    }

    @Override
    public void onCustomItemsDeleted(DirectCall call) {
    }

    @Override
    public void onReconnecting(DirectCall call) {
    }

    @Override
    public void onReconnected(DirectCall call) {
    }

    @Override
    public void onAudioDeviceChanged(DirectCall call, AudioDevice currentAudioDevice, Set<AudioDevice> availableAudioDevices) {
    }

    @Override
    public void onRemoteRecordingStatusChanged(DirectCall call) {
    }
    
    @Override
    public void onCalleeDialReceived(DirectCall call) {
    }
});

List of methods

Copy link
MethodInvoked when

onEstablished()

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

onConnected()

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

onReconnecting()

A DirectCall instance is attempting to reconnect to Sendbird server after losing connection.

onReconnected()

The call successfully reconnects to Sendbird server.

onEnded()

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

onAudioDeviceChanged()

The audio device used for the call has changed.

onRemoteAudioSettingsChanged()

The remote user changes their audio settings.

onRemoteVideoSettingsChanged()

The remote user changes their video settings.

onRemoteRecordingStatusChanged()

The remote user changes their recording status.

onCustomItemsUpdated()

The custom items of the call are updated.

onCustomItemsDeleted()

The custom items of the call are deleted.

onCalleeDialReceived()

The callee has received the call notification through the SendBirdCallListener.onRinging delegate method.


Retrieve call information

Copy link

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

Copy link

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

DirectCallLogListQuery.Params params = new DirectCallLogListQuery.Params().apply {
    setStartedAt(startTimestamp);
    setEndedAt(endTimestamp);
    limit = 20;
}
DirectCallLogListQuery listQuery = SendBirdCall.createDirectCallLogListQuery(params);

listQuery.next(new DirectCallLogListQueryResultHandler() {
    @Override
    public void onResult(List<DirectCallLog> callLogs, SendBirdException e) {
        if (e == null) {
            if (listQuery.hasNext() && !listQuery.isLoading()) {
                // The listQuery.next() can be called once more to fetch more call logs.
            }
        }
    }
});

Parameters in DirectCallLogListQuery.Params

Copy link

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.

ParameterTypeDefaultDescription

myRole

UserRoleFilter

.all

Filters call logs by the user's role (caller, callee, all).

endResults

ArrayList<DirectCallEndResult>

Empty list

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

int

10

Sets the maximum number of call logs to retrieve per query, with a cap of 100 logs.

setStartedAt

long

null

Sets the beginning timestamp for retrieving call logs. The query includes logs starting from this timestamp. Default behavior without setEndedAt: returns logs from start_ts to the lesser of the current time or start_ts + 90 days.

setEndedAt

long

null

Sets the ending timestamp for retrieving call logs. The query includes logs up to this timestamp. Default behavior without setStartedAt: returns logs from end_ts - 90 days to end_ts.

Synchronization and Retrieval of Call Logs

Copy link

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 callLog.isFromServer() method. To retrieve call history from the server instead of the local log, use the DirectCallLogListQuery.

directCall.setListener(new DirectCallListener() {
    ...

    @Override
    public void onEnded(DirectCall call) {
        ...

        DirectCallLog callLog = call.getCallLog();
        // Appropriately add this callLog object to the callLog list.
    }
    ...

});

Retrieve missed direct calls

Copy link

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 retrieveMissedDirectCalls() method to pick up the incoming call. The incoming call will be received through SendBirdListener.onRinging().

SendBirdCall.retrieveMissedDirectCalls { e ->
    // Handle error.
}

SendBirdCall.addListener(UNIQUE_HANDLER_ID) {
    override fun onRinging(call: DirectCall) {
    // If you call "retrieveMissedDirectCalls()", call.ringingSource == RETRIEVAL
    }
}

If you received a push notification of an incoming call through SendBirdCallListener.onRinging() but failed to process it, you can get a list of all incoming calls, including ones that are currently ringing, through SendBirdCall.incomingCalls.

Note: SendBirdCall.retrieveMissedDirectCalls() is automatically triggered internally when the Calls SDK for Android has been successfully authenticated.

You can also identify where a call is coming from through the DirectCall.ringingSource property.

List of properties of ringingSource

Copy link
Property nameDescription

PUSH

When a call arrives through a push notification.

RETRIEVAL

When a call arrives by invoking the SendBirdCall.retrieveMissedDirectCall() method.

WEBSOCKET

When a call arrives through the websocket.


Select video output

Copy link

Users can select a device for video output during a video call. The list of available video devices can be accessed by the directCall.getAvailableVideoDevices() method. To change the current video output device to one of the other available video devices, the directCall.selectVideoDevice() method should be called.

List<VideoDevice> availableVideoDevices = directCall.getAvailableVideoDevices();
VideoDevice currentVideoDevice = directCall.getCurrentVideoDevice();

for (VideoDevice availableVideoDevice : availableVideoDevices) {
    if (!availableVideoDevice.getCameraCharacteristics().get(CameraCharacteristics.LENS_FACING)
            .equals(currentVideoDevice.getCameraCharacteristics().get(CameraCharacteristics.LENS_FACING))) {
        directCall.selectVideoDevice(availableVideoDevice, e -> {
            if (e != null) {
                // An error occurred while selecting a device for video output.
            }
        });
    }
}

To turn on the switch between the front and back cameras function, use the switchCamera() method.

directCall.switchCamera(e -> {
    if (e != null) {
        // An error occurred while switching between the front and back cameras.
    }

    ...
});

Capture video views

Copy link

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

directCall.captureLocalVideoView(new CaptureVideoViewHandler() {
    @Override
    public void onCaptured(Bitmap capturedImage, SendBirdException e) {
        if (e != null) {
            // Handle error.
        }

        // Implement code for handling a successfully-captured image.
    }
});

- Remote video view

directCall.captureRemoteVideoView(new CaptureVideoViewHandler() {
    @Override
    public void onCaptured(Bitmap capturedImage, SendBirdException e) {
        if (e != null) {
            // Handle error.
        }

        // Implement code for handling a successfully-captured image.
    }
});

Note: For errors that may occur when capturing video views, see the Error codes page.


Record audio and video

Copy link

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:

List of recording types

Copy link
Recording typeDescription

REMOTE_AUDIO_AND_VIDEO

An option to record the video and audio of the remote user.

REMOTE_AUDIO_ONLY

An option to record the audio of the remote user.

LOCAL_REMOTE_AUDIOS

An option to record both audios of the local and remote users.

LOCAL_AUDIO_REMOTE_AUDIO_AND_VIDEO

An option to record both audios of the local and remote users, and the video of the remote user.

LOCAL_AUDIO_AND_VIDEO_REMOTE_AUDIO

An option to record both audios of the local and remote users, and the video of the local user.

Start recording a call

Copy link

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}.

RecordingOptions options = new RecordingOptions(RecordingOptions.RecordingType.REMOTE_AUDIO_AND_VIDEO, DIRECTORY_PATH, FILE_NAME);
// Records remote user’s audio and video, with output file path of `OUTPUT_PATH/FILE_NAME.mp4`

directCall.startRecording(options, new RecordingStartedHandler() {
    @Override
    public void onRecordingStarted(@Nullable String recordingId, @Nullable SendBirdException e) {
        if (e == null) {
            // The recording has been started successfully.
        }
    }
});

A recordingId is delivered through the RecordingStartedHandler 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

Copy link

Stop recording a call using the directCall.stopRecording() method with the recordingId received from the RecordingStartedHandler 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.

directCall.stopRecording(recordingId);
// Stop a recording session with the given recordingId.
// If the provided recordingId is invalid, the request will be ignored.

After the recording is finished, the RecordingListener.onRecordingSucceeded() method will be called.

Receive events

Copy link

In order to receive events about the completion of the recordings, add a device-specific RecordingListener by using the SendBirdCall.addRecordingListener() event method. Once the event listener is added, your app can handle the following two events as shown below:

SendBirdCall.addRecordingListener(UNIQUE_ID, new RecordingListener() {
    @Override
    public void onRecordingSucceeded(@NotNull DirectCall directCall, @NotNull String recorderId, @NotNull RecordingOptions recordingOptions, @NotNull String outputFilePath) {
        // Recording was successfully saved to 'outputURL'.
    }

    @Override
    public void onRecordingFailed(@NotNull DirectCall directCall, @NotNull String recorderId, @NotNull SendBirdException e) {
        // Recording wasn’t saved due to an 'e'.
    }
});

You can remove the device-specific RecordingListener as shown below:

SendBirdCall.removeRecordingListener(UNIQUE_ID);
// Remove a recording listener with the specified identifier.

SendBirdCall.removeAllRecordingListeners();
// Remove all recording listeners from the application.

Note: The RecordingListener.onRecordingSucceeded() event method won’t be called if errors occur at the start of recording sessions after calling the directCall.startRecording() method.

Get permission

Copy link

To save the recording session to an external storage, a permission to read and write files must be granted. For more information, visit the Android documentation page.

Recorded files

Copy link

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, RecordingListener.onRecordingFailed will be called.

Recording notifications

Copy link

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 DirectCallListener.onRemoteRecordingStatusChange(DirectCall call) method. Users can also check the recording status of the other user with DirectCall.getRemoteRecordingStatus().

// Recording status of the local user
directCall.getLocalRecordingStatus()

// Recording status of the remote user
directCall.getRemoteRecordingStatus()

directCall.setListener(new DirectCallListener() {
    @Override
    public void onRemoteRecordingStatusChanged(DirectCall call) {

    }
});

Share screen

Copy link

During a video call, both the caller and callee can share their screens with each other by using Android’s MediaProjection.

Start screen share

Copy link

To start sharing your screen, follow the instructions below.

Step 1: Get MediaProjection permission Request screen capturing permission from the user and pass the result to the Calls SDK.

MediaProjectionManager mpm = (MediaProjectionManager) getSystemService(Context.MEDIA_PROJECTION_SERVICE);
startActivityForResult(mpm.createScreenCaptureIntent(), MEDIA_PROJECTION_REQUEST_CODE);
…
@Override
protected void onActivityResult(int requestCode, int resultCode, @androidx.annotation.Nullable Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == MEDIA_PROJECTION_REQUEST_CODE && resultCode == Activity.RESULT_OK) {
        // Save the requested result data here.
        mScreenSharingData = data;
    }
}

Note: When the above code is called, the operating system will automatically ask the user to confirm the permission to record the screen.

Step 2: Start foreground services for MediaProjection (optional)

Call the MediaProjectionManager.getMediaProjection() method in the Calls SDK. Calling this method requires foreground services if the operating system level is higher than Build.VERSION_CODES.Q. Make sure to start the foregroundService before calling the DirectCall.startScreenShare() method.

<!-- AndroidManifest.xml -->
<service android:name=".ScreenSharingService"
    android:foregroundServiceType="mediaProjection" />

Step 3: Start screen share

call.startScreenShare(mediaProjectionPermissionResultData, e -> {
    if (e == null) {
        // Successfully started screen share.
    }
});

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.

Note: MediaProjection requires Android 5.0 (API Level 21) or higher.

Stop screen share

Copy link

You can stop sharing your screen and return to the video view as shown below:

call.stopScreenShare(e -> {
    if (e == null) {
        // Successfully stopped screen share.
    }
});

Note: For more guide on how to add this feature, see this tutorial.


Add sound effects

Copy link

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.Options.addDirectCallSound() 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.Options.removeDirectCallSound() method.

To set the dialing sound effect in silent or vibrate mode, the setDirectCallDialingSoundOnWhenSilentOrVibrateMode() method should be used.

// Play on a caller’s side when making a call.
SendBirdCall.Options.addDirectCallSound(SendBirdCall.SoundType.DIALING, R.raw.dialing);

// Set up dialing sound when silent mode.
SendBirdCall.Options.setDirectCallDialingSoundOnWhenSilentOrVibrateMode(true);

// Play on a callee’s side when receiving a call.
SendBirdCall.Options.addDirectCallSound(SendBirdCall.SoundType.RINGING, R.raw.ringing);

// Play when a connection is lost, but the SDK immediately attempts to reconnect.
SendBirdCall.Options.addDirectCallSound(SendBirdCall.SoundType.RECONNECTING, R.raw.reconnecting);

// Play when the connection is re-established.
SendBirdCall.Options.addDirectCallSound(SendBirdCall.SoundType.RECONNECTED, R.raw.reconnected);

For more information about sound effects, refer to our Calls SDK GitHub repository's README.


Manage call quality

Copy link

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 ConnectionQualityListener

Copy link

To detect changes in call quality, you need to set ConnectionQualityListener and select a monitoring mode by calling the setConnectionQualityListener() method. Based on the specified monitoring mode, the onConnectionQualityUpdate method will be called.

// Set the call quality listener with the specified monitoring mode.
directCall.setConnectionQualityListener(ConnectionQualityMonitoringMode.FREQUENT) { callMetrics ->

}

ConnectionQualityMonitoringMode

Copy link
PropertiesDescription

frequent

Monitors the frequency of connection quality which occurs every 3 seconds when the onConnectionQualityUpdate() method is called.

connectionQualityChange

Monitors the changes in connection quality level which calls the onConnectionQualityUpdate() method.

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

Copy link
StateMOSDescription

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 ConnectionQualityListener

Copy link

Call the removeConnectionQualityListener() method to remove all previous settings.

// Remove the call quality listener.
directCall.removeConnectionQualityListener()