Calls SDKs JavaScript v1
Calls SDKs JavaScript
Calls SDKs
JavaScript
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.


Call object

Copy link

Direct call in the Calls SDK refers to a 1-to-1 call. A connection for a direct call is established through the following steps:

  1. When a caller initiates the call, the dial event will be sent to the callee and invoke onRinging.
  2. When the callee accepts the call, WebRTC attempts to establish a media stream to connect the users. During another round of handshake between the caller and callee, information related to WebRTC will be transferred.
  3. After the handshake, a WebRTC connection is established between the caller and callee. Also, the media stream will start for the call.

For the caller, the dial() method will return a promise resolved as the call object. For the callee, the call object will be delivered through the onRinging() method as an argument to a parameter. And for both the caller and callee, the call object will be returned by the SendBirdCall.getCall(callId) method.


Make a call

Copy link

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

const dialParams = {
    userId: CALLEE_ID,
    isVideoCall: true,
    callOption: {
        localMediaView: document.getElementById('local_video_element_id'),
        remoteMediaView: document.getElementById('remote_video_element_id'),
        audioEnabled: true,
        videoEnabled: true
    }
};


const call = SendBirdCall.dial(dialParams, (call, error) => {
    if (error) {
        // Dialing failed.
    }

    // Dialing succeeded.
});

call.onEstablished = (call) => {
    //...
};

call.onConnected = (call) => {
    //...
};

call.onEnded = (call) => {
    //...
};

call.onRemoteAudioSettingsChanged = (call) => {
    //...
};

call.onRemoteVideoSettingsChanged = (call) => {
    //...
};

A media viewer is a HTMLMediaElement such as <audio> and <video> to display media stream. The remoteMediaView accessor is required for the remote media stream to be displayed. It is also recommended to set the value of a media viewer's autoplay property to true.

<video id="remote_video_element_id" autoplay></video>

Likewise, localMediaView is required for the local media stream to be displayed. And it is also recommended to set the values of a media viewer's autoplay and muted properties to true.

<video id="local_video_element_id" autoplay muted>

Note: Media viewers can be set using the directCall.setLocalMediaView() or directCall.setRemoteMediaView() method as well.

// Setting media viewers lazily.
call.setLocalMediaView(document.getElementById('local_video_element_id'));
call.setRemoteMediaView(document.getElementById('remote_video_element_id'));

Receive a call

Copy link

To receive an incoming call, a device-specific 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 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.

const acceptCall = (call) => {
    call.onEstablished = (call) => {
        //...
    };

    call.onConnected = (call) => {
        //...
    };

    call.onEnded = (call) => {
        //...
    };

    call.onRemoteAudioSettingsChanged = (call) => {
        //...
    };

    call.onRemoteVideoSettingsChanged = (call) => {
        //...
    };

    const acceptParams = {
        callOption: {
            localMediaView: document.getElementById('local_video_element_id'),
            remoteMediaView: document.getElementById('remote_video_element_id'),
            audioEnabled: true,
            videoEnabled: true
        }
    };

    call.accept(acceptParams);
}

SendBirdCall.addListener(UNIQUE_HANDLER_ID, {
    onRinging: (call) => {
        acceptCall(call)
    }
});

Note: If media viewer elements have been set by the setLocalMediaView() and setRemoteMediaView() methods of the DirectCall, make sure that the same media viewers are set in the acceptParam’s callOption. If not, they will be overridden during executing the directCall.accept() method.

Incoming calls are received via the application's persistent internal server connection, which is established by the SendBirdCall.connectWebSocket(). In the event of accidental disconnection, the application will attempt to reconnect every 2 seconds.


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 directCall.onRemoteAudioSettingsChanged() listener.

// Mute my microphone.
call.muteMicrophone();
// Unmute my microphone.
call.unmuteMicrophone();

// Receive the event
call.onRemoteAudioSettingsChanged(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.
    }
};

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 directCall.onRemoteVideoSettingsChange() listener.

// Start my local video.
call.startVideo();
// Stop my local video.
call.stopVideo();

// Receive the event.
call.onRemoteVideoSettingsChanged(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 directCall.onEnded() listener.

// End a call.
call.end();

// Receive the event.
call.onEnded = (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()
    .then(() => {
        // Call is successfully put on hold.
    })
    .catch(error => {
        // Handle error.
    });

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 direcCall.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()
    .then(() => {
        // A hold is successfully removed from the call.
    })
    .catch(error => {
        // Handle error.
    });

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

onRinging: (call) => {
    // ...
    const acceptParams = {
        callOption: {
            localMediaView: document.getElementById('local_video_element_id'),
            remoteMediaView: document.getElementById('remote_video_element_id'),
            audioEnabled: true,
            videoEnabled: 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 the SendBirdCall.getOngoingCalls() method.

// Retrieve a list of calls on hold.
const callOnHold = SendBirdCall.getOngoingCalls().find(call => call.isOnHold);

callOnHold?.unhold(true)
    .then(() => {
        // A hold is successfully removed from the call.
    })
    .catch(error => {
        // Handle error.
    });

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 directCall.onUserHoldStatusChanged event handler 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.

// Receive notifications by setting the property. This way will soon be deprecated.
call.onUserHoldStatusChanged = (call, isLocalUser, isUserOnHold) => {
    // Use `isLocalUser` and `isUserOnHold` to identify the users' hold status of a call.
    // Use the updated `call.isOnHold` value to update the call view.
}

// Receive notifications by calling the `on` method.
const unsubscribe = call.on('onUserHoldStatusChanged', (call, isLocalUser, isUserOnHold) => {
    // 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 Dictionary of string and 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 Dictionary of String and String to a DialParams object by using the customItems property. The default value of a call's custom items is an empty Dictionary.

const customItemsToAdd = { key1: 'value1', key2: 'value2' };
const addedCustomItems = call.updateCustomItems(
    customItemsToAdd,
    (result, error) => {
        // Handle added custom items within a callback.
    },
);
addedCustomItems.then((result) => {
    // Handle added custom items using a returned promise.
});

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 updateCustomItems(): promise.then() 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 deleteCustomItems(): promise.then() or delete all custom items associated with the call by using deleteAllCustomItems(): promise.then(). Through a completion handler or a returned promise, you will receive the updated custom items, a list of keys of the modified custom items, and an error from Sendbird server.

const customItemsToModify = { key1: 'value3', key2: 'value4' };
const modifiedCustomItems = call.updateCustomItems(
    customItemsToModify,
    (result, error) => {
        // Handle updated custom items within a callback.
    },
);
modifiedCustomItems.then((result) => {
    // Handle updated custom items using a returned promise.
});

const customItemKeysToDelete = ['key1', 'key2'];
const deletedCustomItems = call.deleteCustomItems(
    customItemKeysToDelete,
    (result, error) => {
        // Handle deleted custom items within a callback.
    },
);
deletedCustomItems.then((result) => {
    // Handle deleted custom items using a returned promise.
});

const deleteCustomItems = call.deleteAllCustomItems((result, error) => {
    // Handle deleted custom items within a callback.
});
deletedCustomItems.then((result) => {
    // Handle deleted custom items using a returned promise.
});

Receive events

Copy link

To receive events from Sendbird server when custom items are modified, you can implement onCustomItemsUpdated() and onCustomItemsDeleted() from the DirectCall. 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 DirectCall. You can always access modified custom items even after the call ends with the Calls API or by using the directCall.customItems.

call.onCustomItemsUpdated = (call, updatedKeys) => {
    //...
};
call.onCustomItemsDeleted = (call, deletedKeys) => {
    //...
};

Configure media devices

Copy link

The SendBirdCall object contains a collection of methods used to configure media devices: retrieve a list of devices, retrieve the current device, select a device, and update a list of devices.

Methods

Copy link
NameDescription

useMedia(constraints)

Grants permission to access media devices.

getCurrentAudioInputDevice()

Returns the current audio input device.

getAvailableAudioInputDevices()

Returns a set of available audio input devices.

selectAudioInputDevice(mediaDeviceInfo)

Selects the audio input device.

getCurrentAudioOutputDevice()

Returns the current audio output device.

getAvailableAudioOutputDevices()

Returns a set of available audio input devices.

selectAudioOutputDevice(mediaDeviceInfo)

Select the audio output device.

getCurrentVideoInputDevice()

Returns the current video input device.

getAvailableVideoInputDevices()

Returns a set of available video devices.

selectVideoInputDevice(mediaDeviceInfo)

Selects the video input device.

updateMediaDevices(constraints)

Manually updates media devices.

The device specific-event handler also contains a collection of event listeners used to handle changes in media devices.

Event lists

Copy link
Event listenerInvoked when

onAudioInputDeviceChanged

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

onAudioOutputDeviceChanged

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

onVideoInputDeviceChanged

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

Before using the methods and event listeners listed above, ensure that the SendBirdCall.useMedia(constraints) has been executed. Failing to do this will result in these methods causing unexpected behaviors or failed outcomes.

const mediaAccess = SendBirdCall.useMedia({audio: true, video: true});

// This code demonstrates for audio input devices. The same can also be done for audio output and video input devices.
const availableDevices = SendBirdCall.getAvilableAudioInputDevices();
const currentDevice = SendBirdCall.getCurrentAudioInputDevice();
// Populate option elements in select element.
populateSelectOption(availableDevices);
// Select option which matches current device.
selectOption(currentDevice);

SendBirdCall.addListener('my-listener', {
    onAudioInputDeviceChanged: (currentDevice, availableDevices) => {
        // Populate option elements in a select element.
        populateSelectOption(availableDevices);
        // Select option which matches current device.
        selectOption(currentDevice);
    }
});

//...

SendBirdCall.removeListener('my-listener');

// on settings view closed.
mediaAccess.dispose();

Make sure that the retrieved mediaAccess's dispose() method always gets called from the SendBirdCall.useMedia() method to prevent the unintended use of camera or microphone.

Note: In Chrome or Firefox, the SendBirdCall.updateMediaDevices() doesn’t need to be called if the media device event listener is used to update the view or device list. However, in Safari, those event listeners might not need to be called after a media device has been changed. In such cases, calling the SendBirdCall.updateMediaDevices() manually may be required.


Add event handlers

Copy link

There are two types of event handlers that the Calls SDK provides: a device-specific listener and a call-specific listener.

Device-specific listener

Copy link

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

Note: If a device-specific 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 client app. Also, the device-specific 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, {
    onRinging: (call) => {
        //...
    }
});

Methods

Copy link
NameInvoked 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.

onVideoInputDeviceChanged()

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

Call-specific listener

Copy link

Before accepting the call, the call-specific 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.

// call is 'DirectCall' object
call.onEstablished = (call) => {
    //...
};

call.onConnected = (call) => {
    //...
};

call.onEnded = (call) => {
    //...
};

call.onReconnecting = (call) => {
    //...
};

call.onReconnected = (call) => {
    //...
};

call.onRemoteAudioSettingsChanged = (call) => {
    //...
};

call.onRemoteVideoSettingsChanged = (call) => {
    //...
};

call.onCustomItemsUpdated = (call, updatedKeys) => {
    //...
};

call.onCustomItemsDeleted = (call, deletedKeys) => {
    //...
};

call.onRemoteRecordingStatusChanged = (call) => {
    //...
};

call.onCalleeDialReceived = (call) => {
    //...
};

Methods

Copy link
NameInvoked 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()

The call 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.

onRemoteAudioSettingsChanged()

The remote user changes their audio settings.

onRemoteVideoSettingsChanged()

The remote user changes their video settings.

leted.

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 using the directCall.localUser property while the other party’s information using the directCall.remoteUser property.


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.

/*
interface DirectCallLogListQueryParams {
    myRole: string
    endResults: string[],
    limit: number
}
*/

const params = {
    myRole: 'dc_caller',
    endResults: ['DECLINED', 'COMPLETED'],
    limit: 100,
};

const listQuery = SendBirdCall.createDirectCallLogListQuery(params);

listQuery.next((directCallLog) => {
    if (listQuery.hasNext && !listQuery.isLoading) {
        // The listQuery.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 callLog.isFromServer() method. To retrieve call history from the server instead of the local log, use the DirectCallLogListQuery instance.

call.onEnded = (call) => {
    //...

    let callLog = call.callLog
    // Appropriately add this callLog object to the callLog list.
    //...

}

Capture video views

Copy link

During a video call, the caller and callee can capture the images of their streaming video by using the captureLocalVideoView() method.

Local video view

Copy link
PromiseCallback
try {
    const resultImage = await call.captureLocalVideoView();
    // Implement your custom code for a successfully-captured image.
} catch (e) {
    // Handle error.
}

Parameters

Copy link
NameTypeDescription

function (optional)

callback

A callback function to receive the result of video streaming capture images. If a Promise is used instead of the callback function, the returned resultImage and error must be processed within a try-catch block.

Properties of return value

Copy link
NameTypeDescription

resultImage

nested object

A JSON object which contains the information of the captured result image.

resultImage.width

number

The width of the captured result image.

resultImage.height

number

The height of the captured result image.

resultImage.data

string

The data URL containing a representation of the captured result image, which is returned by the toDataURL() method.

Remote video view

Copy link
PromiseCallback
try {
    const resultImage = await call.captureRemoteVideoView();
    // Implement code for handling a successfully-captured image.
} catch (e) {
    // Handle error.
}

Parameters

Copy link
NameTypeDescription

function (optional)

callback

A callback function to receive the result of video streaming capture images. If a Promise is used instead of the callback function, the returned resultImage and error must be processed within a try-catch block.

Properties of return value

Copy link
NameTypeDescription

resultImage

nested object

A JSON object which contains the information of the captured result image.

resultImage.width

number

The width of the captured result image.

resultImage.height

number

The height of the captured result image.

resultImage.data

string

The data URL containing a representation of the captured result image, which is returned by the toDataURL() method.

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:

Recording types

Copy link
TypeDescription

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.

Note: Sendbird Calls SDK uses the MediaRecorder from the MediaStream Recording API when recording a direct call. To check if your browser supports the recording feature, refer to MediaRecorder. If the browser doesn't support the MediaRecorder, directCall.startRecording() will throw error through returned Promise.

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

import { DirectCallRecordOption, RecordingType } from 'sendbird-calls';

...

let options = new DirectCallRecordOption({recordingType: RecordingType.REMOTE_AUDIO_AND_VIDEO, callId: callId, fileName: FILE_NAME})
// Record remote user’s audio and video and download it under the name 'FILE_NAME.mp4'.

const recordingId = call.startRecording(options);
if(recordingId){
    // Recording start succeed.
} else {
    // Recording start failed.
}

A recordingId is returned from the completion handler of the directCall.startRecording() method when the recording has been successfully started. 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 directCall.startRecording() method. If the recording session isn’t stopped by the time the call has ended, the recording session automatically ends as well.

call.stopRecording((recordingId: recordingId));
// Stops a recording session with the given ‘recordingId’.
// If the provided ‘recordingId’ is invalid, return false.

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

Receive events

Copy link

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

SendBirdCall.addRecordingListener((identifier: string), {
    onRecordingSucceeded: (
        callId: string,
        recordingId: string,
        options: DirectCallRecordOption,
        fileName: string,
    ) => {
        // Recording was successfully saved to ‘fileName’.
    },
    onRecordingFailed: (callId: string, recordingId: string, error: Error) => {
        // Recording wasn’t saved due to an ‘error’.
    },
});

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

SendBirdCall.removeRecordingListener((id: string));
// Remove a recording event listener with the specified identifier.

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

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

Recorded files

Copy link

Each browser has a different policy and supported codec for recording which means the format of a recorded file is MP4 for safari and WEBM for Chrome and Firefox. If the recorded file is created in Chrome or Firefox, it can't be played with the native media player of your operating system. The recorded file can be played with Browser, VLC media player, or a media player that supports VP8 and Opus codecs. For Safari versions 14 and later, recordings are created in the MP4 file format encoded with H.264 and AAC so that recorded files can be played with the native media player of your operating system. When the recording is complete, the recorded file will automatically be saved to the browser's default download folder.

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, SendBirdCallRecordingListener.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 DirectCall.onRemoteRecordingStatusChanged method. Users can also check the recording status of the other user with DirectCall.remoteRecordingStatus.

// Start local recording.
const recordId = call.startRecording(options);
// Stop local recording.
call.stopRecording(recordId);

// Receive the event.
call.onRemoteRecordingStatusChanged = (call) => {
    if (call.remoteRecordingStatus === RecordingStatus.RECORDING) {
        console.log('The remote user has started recording.');
    } else if (call.remoteRecordingStatus === RecordingStatus.NONE){
        console.log('The remote user has stopped recording.');
    }
}

Screen share

Copy link

During a video call, both the caller and callee can share their screens with each other using the browser’s screen share feature.

Start screen share

Copy link
try {
    await call.startScreenShare();
    call.onScreenShareStopped = () => {
        // add your process for screen share stop.
    };
} catch (e) {
    // add your process for start screen share fail.
}

When the startScreenShare method is called, the list of contents on your screen will be displayed. Then you can select a content or a screen to share with both the local user's localVideoView and the remote user’s remoteVideoView. Currently, displaying the local camera view and the local screen share view together is not supported.

Note: The screen share function is not provided in mobile browsers.

The following types of content are supported for screen share on each browser when using the Calls SDK for JavaScript.

ChromeFirefoxSafari

Monitor

O

* Screens of all connected monitors

O

O

* Only the screen of the default monitor

App

O

O

X

Tab

O

X

X

Note: If an app that is being shared is minimized, the screen share view will show as black. If the app closes, the screen share view will end.

Stop screen share

Copy link

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

call.stopScreenShare();

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


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.

import { ConnectionQualityMonitoringMode } from 'sendbird-calls';

// call connection quality listener only when the connection quality is changed
const mode = ConnectionQualityMonitoringMode.CONNECTION_QUALITY_CHANGE;

call.setConnectionQualityListener(mode, (metrics) => {
  // quality changed to `metrics.connectionQuality`
});

ConnectionQualityMonitoringMode

Copy link
PropertiesDescription

frequency

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

connectionQualityChange

Monitors the changes in connection quality level when the onConnectionQualityUpdate() method is called.

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.

call.removeConnectionQualityListener();