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)
Argument | Required | Description |
---|---|---|
conferenceServer | yes | A 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)
Updated almost 3 years ago