Video Conference

Learn how to add video conference calls to your app.

🚧

This feature is available for customers on the Enterprise plan only. Take advantage of Enterprise features to unlock new value and opportunities for users. For more information and if you want to request a Demo, please contact us by mail: [email protected].

QuickBlox provides a Multiparty Video Conferencing solution allowing to set up a video conference between 10-12 people. It is built on top of WebRTC SFU technologies.

Features supported:

- Video/Audio Conference with 10-12 people.
- Join/Rejoin video room functionality (like Skype).
- Mute/Unmute audio/video stream (own and opponents).
- Display bitrate.
- Switch video input device (camera).

Initialize

In order to start working with Multiparty Video Conferencing API, you need to initialize a conference endpoint. To request the conference server URL, please contact us: [email protected].

String conferenceServer = "your_conference_server";
ConferenceConfig.setUrl(conferenceServer);
val conferenceServer = "your_conference_server"
ConferenceConfig.setUrl(conferenceServer)
ArgumentRequiredDescription
conferenceServeryesA conference server URL.

Create session

Create a session using createSession() method. ConferenceClient instance is a client model responsible for managing the conference session. ConferenceClient has a setAutoSubscribeAfterJoin option signifying that your client will be subscribed to all online publishers after joining some room. By default, setAutoSubscribeAfterJoin is true. ConferenceSession is a session within a certain video room, managing all current processes.

ConferenceClient client = ConferenceClient.getInstance(getApplicationContext());

QBRTCTypes.QBConferenceType conferenceType = isVideoCall
    ? QBRTCTypes.QBConferenceType.QB_CONFERENCE_TYPE_VIDEO
    : QBRTCTypes.QBConferenceType.QB_CONFERENCE_TYPE_AUDIO;

client.setAutoSubscribeAfterJoin(true);

client.createSession(userId, conferenceType, new ConferenceEntityCallback<ConferenceSession>() {
    @Override
    public void onSuccess(ConferenceSession conferenceSession) {
        // session Created Successfully
    }

    @Override
    public void onError(WsException exception) {
        // create Session Error
    }
});
val client = ConferenceClient.getInstance(applicationContext)

val conferenceType = if (isVideoCall) {
    QBRTCTypes.QBConferenceType.QB_CONFERENCE_TYPE_VIDEO
} else {
    QBRTCTypes.QBConferenceType.QB_CONFERENCE_TYPE_AUDIO
}

client.isAutoSubscribeAfterJoin = true

client.createSession(userId, conferenceType, object : ConferenceEntityCallback<ConferenceSession> {
    override fun onSuccess(conferenceSession: ConferenceSession?) {
        // session Created Successfully
    }

    override fun onError(exception: WsException?) {
        // create Session Error
    }
})

Callbacks

To have the ability to receive callbacks about the current ConferenceSession instance state and conference events, you should implement appropriate interfaces. Implement the QBRTCSessionStateCallback for tracking connection state:

QBRTCSessionStateCallback sessionStateCallback = new QBRTCSessionStateCallback<ConferenceSession>() {
    @Override
    public void onStateChanged(ConferenceSession conferenceSession, BaseSession.QBRTCSessionState sessionState) {
    
    }

    @Override
    public void onConnectedToUser(ConferenceSession conferenceSession, Integer userId) {

    }

    @Override
    public void onDisconnectedFromUser(ConferenceSession conferenceSession, Integer userId) {

    }

    @Override
    public void onConnectionClosedForUser(ConferenceSession conferenceSession, Integer userId) {

    }
};

currentConferenceSession.addSessionCallbacksListener(sessionStateCallback);
// or
currentConferenceSession.removeSessionCallbacksListener(sessionStateCallback);
val sessionStateCallback = object : QBRTCSessionStateCallback<ConferenceSession> {
    override fun onStateChanged(conferenceSession: ConferenceSession?, sessionState: BaseSession.QBRTCSessionState?) {

    }

    override fun onConnectedToUser(conferenceSession: ConferenceSession?, userId: Int?) {

    }

    override fun onDisconnectedFromUser(conferenceSession: ConferenceSession?, userId: Int?) {

    }

    override fun onConnectionClosedForUser(conferenceSession: ConferenceSession?, userId: Int?) {

    }
}

currentConferenceSession.addSessionCallbacksListener(sessionStateCallback)
// or
currentConferenceSession.removeSessionCallbacksListener(sessionStateCallback)

Implement ConferenceSessionCallbacks for tracking conference events:

ConferenceSessionCallbacks conferenceSessionCallbacks = new ConferenceSessionCallbacks() {
    @Override
    public void onPublishersReceived(ArrayList<Integer> publishersList) {
        // publisher or Publishers (users) joined
    }

    @Override
    public void onPublisherLeft(Integer userId) {
        // publisher left
    }

    @Override
    public void onMediaReceived(String type, boolean success) {
        // media received (audio or video type)
    }

    @Override
    public void onSlowLinkReceived(boolean uplink, int nacks) {
        // called when slowLink is received from server.
        // slowLink with uplink = true - several missing packets from server;
        // uplink = false means server is not receiving all your packets.
    }

    @Override
    public void onError(WsException exception) {
        // error from Server Received
    }

    @Override
    public void onSessionClosed(ConferenceSession conferenceSession) {
        // cession Closed
    }
};

currentConferenceSession.addConferenceSessionListener(conferenceSessionCallbacks);
// or
currentConferenceSession.removeConferenceSessionListener(conferenceSessionCallbacks);
val conferenceSessionCallbacks = object : ConferenceSessionCallbacks {
    override fun onPublishersReceived(publishersList: ArrayList<Int>?) { 
        // publisher or Publishers (users) joined
    }

    override fun onPublisherLeft(userId: Int?) {
        // publisher left
    }

    override fun onMediaReceived(type: String?, success: Boolean) {
        // media received (audio or video type)
    }

    override fun onSlowLinkReceived(uplink: Boolean, nacks: Int) {
        // called when slowLink is received from server.
        // slowLink with uplink = true - several missing packets from server;
        // uplink = false means server is not receiving all your packets.
    }

    override fun onError(exception: WsException?) {
        // error from Server Received
    }

    override fun onSessionClosed(conferenceSession: ConferenceSession?) {
        // cession Closed
    }
}
        
currentConferenceSession.addConferenceSessionListener(conferenceSessionCallbacks)
// or
currentConferenceSession.removeConferenceSessionListener(conferenceSessionCallbacks)

Video and audio tracks

For obtaining video and audio tracks implement interface RTCClientVideoTracksCallbacks and RTCClientAudioTracksCallback.

QBRTCClientVideoTracksCallbacks videoTracksCallbacks = new QBRTCClientVideoTracksCallbacks<ConferenceSession>() {
    @Override
    public void onLocalVideoTrackReceive(ConferenceSession conferenceSession, QBRTCVideoTrack videoTrack) {

    }

    @Override
    public void onRemoteVideoTrackReceive(ConferenceSession conferenceSession, QBRTCVideoTrack videoTrack, Integer userId) {

    }
};

// add callback
currentConferenceSession.addVideoTrackCallbacksListener(videoTracksCallbacks);
// or remove
currentConferenceSession.removeVideoTrackCallbacksListener(videoTracksCallbacks);
  


QBRTCClientAudioTracksCallback audioTracksCallback = new QBRTCClientAudioTracksCallback<ConferenceSession>() {
    @Override
    public void onLocalAudioTrackReceive(ConferenceSession conferenceSession, QBRTCAudioTrack audioTrack) {

    }

    @Override
    public void onRemoteAudioTrackReceive(ConferenceSession conferenceSession, QBRTCAudioTrack audioTrack, Integer userId) {

    }
};

// add callback
currentConferenceSession.addAudioTrackCallbacksListener(audioTracksCallback);
// or remove
currentConferenceSession.removeAudioTrackCallbacksListener(audioTracksCallback);
val videoTracksCallbacks = object : QBRTCClientVideoTracksCallbacks<ConferenceSession> {
    override fun onLocalVideoTrackReceive(conferenceSession: ConferenceSession?, videoTrack: QBRTCVideoTrack?) {

    }

    override fun onRemoteVideoTrackReceive(conferenceSession: ConferenceSession?, videoTrack: QBRTCVideoTrack?, userId: Int?) {

    }
}

// add callback
currentConferenceSession.addVideoTrackCallbacksListener(videoTracksCallbacks)
// or remove
currentConferenceSession.removeVideoTrackCallbacksListener(videoTracksCallbacks)



val audioTracksCallback = object : QBRTCClientAudioTracksCallback<ConferenceSession> {
    override fun onLocalAudioTrackReceive(conferenceSession: ConferenceSession?, audioTrack: QBRTCAudioTrack?) {

    }

    override fun onRemoteAudioTrackReceive(conferenceSession: ConferenceSession?, audioTrack: QBRTCAudioTrack?, userId: Int?) {

    }
}

// Add callback
currentConferenceSession.addAudioTrackCallbacksListener(audioTracksCallback)
// Or remove
currentConferenceSession.removeAudioTrackCallbacksListener(audioTracksCallback)

To render the video track, use the QBConferenceSurfaceView as renderer:

QBConferenceSurfaceView videoView = findViewById(R.id.opponentView);

videoTrack.removeRenderer(videoTrack.getRenderer());
videoTrack.addRenderer(videoView);
val videoView = findViewById<QBConferenceSurfaceView>(R.id.opponentView)

qbrtcVideoTrack.removeRenderer(qbrtcVideoTrack.renderer)
qbrtcVideoTrack.addRenderer(videoView)

Join video room

You can join a room as a listener or as a publisher. As a listener, you subscribe only to the publishers, without giving your own video and audio streams.

boolean asPublisher = true;
int userId = currentConferenceSession.getCurrentUserID();

QBConferenceRole conferenceRole = asPublisher ? QBConferenceRole.PUBLISHER : QBConferenceRole.LISTENER;

currentConferenceSession.joinDialog(dialogId, conferenceRole, new ConferenceEntityCallback<ArrayList<Integer>>() {
    @Override
    public void onSuccess(ArrayList<Integer> publishers) {

    }

    @Override
    public void onError(WsException exception) {

    }
});
val asPublisher = true
val userId = currentConferenceSession.currentUserID

val conferenceRole = if (asPublisher) {
    QBConferenceRole.PUBLISHER
} else {
    QBConferenceRole.LISTENER
}

currentConferenceSession.joinDialog(userId, conferenceRole, object : ConferenceEntityCallback<ArrayList<Int>> {
    override fun onSuccess(publishers: ArrayList<Int>?) {

    }

    override fun onError(exception: WsException?) {

    }
})

To subscribe to the active publisher, you should use the snippet below:

Set<Integer> publishersSet = currentConferenceSession.getActivePublishers();
for (Integer publisher : publishersSet) {
    currentConferenceSession.subscribeToPublisher(publisher);
}
val publishersSet = currentConferenceSession.activePublishers
for (publisher in publishersSet) {
    currentConferenceSession.subscribeToPublisher(publisher)
}

📘

You should subscribe to publishers only when the session state becomes connected. Use onStateChanged() callback method to track session states.

If you are subscribing as a listener, then you can subscribe to publishers right after the successful joinDialog(). To unsubscribe from the publisher, use the unSubscribeFromPublisher() method.

currentConferenceSession.unsubscribeFromPublisher(publisher);
currentConferenceSession.unsubscribeFromPublisher(publisher)

Mute local audio

Mute the audio by calling getLocalAudioTrack().setEnabled() method. Using this method, we can tell SDK to send/not send audio data from a local peer in the specified WebRTC session.

currentConferenceSession.getMediaStreamManager().getLocalAudioTrack().setEnabled(isAudioEnabled);
currentConferenceSession.mediaStreamManager.localAudioTrack.setEnabled(isAudioEnabled)

Mute remote audio

You can always get remote audio tracks for a specific user ID in the call using the above-specified QBRTCSession methods (assuming that they are existent). You can also mute remote media tracks on your side by changing the value of the enabled property for a specific remote media track.

boolean isAudioEnabled = false;

currentConferenceSession.getMediaStreamManager().getAudioTrack(opponentId).setEnabled(isAudioEnabled);
val isAudioEnabled = false

currentConferenceSession.mediaStreamManager.getAudioTrack(opponentId).setEnabled(isAudioEnabled)

Disable local video

Turn off the video by calling getLocalVideoTrack().setEnabled(). Using this method, we can tell SDK not to send video data from a local peer in the specified session.

currentConferenceSession.getMediaStreamManager().getLocalVideoTrack().setEnabled(isVideoEnabled);
currentConferenceSession.mediaStreamManager.localVideoTrack.setEnabled(isVideoEnabled)

Disable remote video

Turn off the video by calling getVideoTrack(opponentID).setEnabled(). Using this method, we can tell SDK not to send video data from a remote peer in the specified session.

boolean isVideoEnabled = false;

currentConferenceSession.getMediaStreamManager().getVideoTrack(opponentId).setEnabled(isVideoEnabled);
val isVideoEnabled = false

currentConferenceSession.mediaStreamManager.getVideoTrack(opponentId).setEnabled(isVideoEnabled)

Leave video room

To leave the current joined video room, use the leave() method.

currentConferenceSession.leave();
currentConferenceSession.leave()

Camera resolution

The camera resolution is a video stream encoding parameter. It's possible to set the custom video resolution to provide guarantees for the predictable behavior of the video stream.

int videoWidth = QBRTCMediaConfig.VideoQuality.QBGA_VIDEO.width;
int videoHeight = QBRTCMediaConfig.VideoQuality.QBGA_VIDEO.height;

// VGA Resolution
//videoWidth = QBRTCMediaConfig.VideoQuality.VGA_VIDEO.width;
//videoHeight = QBRTCMediaConfig.VideoQuality.VGA_VIDEO.height;

// HD Resolution
//videoWidth = QBRTCMediaConfig.VideoQuality.HD_VIDEO.width;
//videoHeight = QBRTCMediaConfig.VideoQuality.HD_VIDEO.height;

// custom Resolution (for example FullHD)
//videoWidth = 1920;
//videoHeight = 1080;
        
QBRTCMediaConfig.setVideoWidth(videoWidth);
QBRTCMediaConfig.setVideoHeight(videoHeight);
var videoWidth = QBRTCMediaConfig.VideoQuality.QBGA_VIDEO.width
var videoHeight = QBRTCMediaConfig.VideoQuality.QBGA_VIDEO.height

// VGA Resolution
//videoWidth = QBRTCMediaConfig.VideoQuality.VGA_VIDEO.width
//videoHeight = QBRTCMediaConfig.VideoQuality.VGA_VIDEO.height

// HD Resolution
//videoWidth = QBRTCMediaConfig.VideoQuality.HD_VIDEO.width
//videoHeight = QBRTCMediaConfig.VideoQuality.HD_VIDEO.height

// Custom Resolution (for example FullHD)
//videoWidth = 1920
//videoHeight = 1080

QBRTCMediaConfig.setVideoWidth(videoWidth)
QBRTCMediaConfig.setVideoHeight(videoHeight)

What’s Next