Group Call
This section will provide you a tutorial on how you can implement one-to-many group calls using Channelize.io Call SDK.
Let's pick up some volunteers (Alice, Bob, Charlie & David) to understand group calls. ALICE_ID
will refer to the user ID of Alice
, BOB_ID
as the user ID of Bob and so on. Let us assume you are logged in as Alice and you are the caller.
We will be covering this tutorial in the below parts.
Initializing SDK
First, initialize the Channelize.io Call SDK using connect functions.
HTML Code
<script src='https://cdn.channelize.io/calls/sdk/4.1.0/browser.js'></script>
JavaScript Code
const channelizeCall = new ChannelizeCall.client({publicKey: YOUR_PUBLIC_KEY});
const webrtcOptions = {}
channelizeCall.connect(userId, accessToken, webrtcOptions, function (err, res) {
});
To know more about the initialization of Channelize.io Call SDK, Please visit the overview section. Once Channelize.io Calls SDK is connected, a user can initiate or receive a call.
HTML Structure
As we know, we need to show audio/video streams in HTML elements. In a one-to-one call, we have two users and so we used only two HTML elements i.e call_local_stream
and call_remote_stream
. However, in the case of group calls, the number of remote streams can be multiple and so we need multiple HTML elements to play these streams. Also, these HTML elements should be created dynamically when a new user joins the call and it should be removed when the user leaves the call.
Let's say we use the below HTML structure for our group calls where we have a local stream element and one remote stream wrapper. We will dynamically add/remove elements in this remote stream wrapper div.
<body>
<div id="call_local_stream"></div>
<div id="call_remote_streams">
<!-- <div id="call_remote_stream_user_1"> -->
<!-- <div id="call_remote_stream_user_2"> -->
</div>
</body>
Initiate Call (Caller's End)
- To start a call use the
startCall
function with the required parameters. Let us assume Alice started a call with Bob and Charlie. ThestartCall
function will return call model and you will be using it in the next few steps. - Bob and Charlie will be notified using event
user.call_invite_received
and they have choices to either join, reject, or ignore the call invitation. - On the success of start call show the local media stream on an HTML element using
playLocalStream
function. - To show call status (
Connecting
/Ringing
/Connected
) for each user, create an HTML element for each of them. In this case, create an HTML element for Bob and Charlie. But if you want to show joined members only, then you can create HTML elements later. - Use the
member.invite_received
event on the call model to know if the call invite is received at the other end. After call invite receive you can start showing Ringing status on your end. You can also add a ringing sound for a better user experience. - Use the
member.joined
event on the call model to know if the receiver has accepted/joined the call. Once the receiver has accepted the call, you need to show the remote media stream on an HTML element usingplayRemoteStream
function. Once it is done, you will start receiving the receiver's audio/video. - Use the
member.rejected
event on the call model to know if the receiver has rejected/declined the call. After this you can provide options to the caller to Call Again or end the call usingend
function. - Once the call is successfully established the caller can end the call. The caller can use the
end
function to end the call. Using SDK, any joined member of the call can end the call but if you want that only caller to end the call, you can manage this through UI.
const data = {
type: 'video',
members: [ BOB_ID, CHARLIE_ID ],
}
channelizeCall.Call.startCall(data, {}, (err, call) => {
if (err) return console.error(err);
// play local media stream on html element #call_local_stream
call.playLocalStream('call_local_stream');
// Create HTML element for Bob and Charlie
call.getMembers('invited').forEach(member => {
// create HTML element - `call_remote_stream_${member.user.id}`
// Show status Connecting/Contacting
});
// Add required events on the call model
call.on('member.invited', (res) => {
res.members.forEach(member => {
// Create HTML element - `call_remote_stream_${member.user.id}`
// Show status Connecting/Contacting
});
});
call.on('member.invite_received', (res) => {
if (res.busy === true) {
// Show busy status in HTML element `call_remote_stream_${res.user.id}`
// Now you can either wait for the user accept/reject or call again or remove the html element
}
// Show Ringing status in HTML element `call_remote_stream_${res.user.id}`
});
call.on('member.rejected', (res) => {
const user = res.members[0];
// Show rejected status in HTML element `call_remote_stream_${user.id}`
// Now either you can remove the HTML element or invite this user again to join the call
call.invite([ BOB_ID ], () => {
// Bob invited again to the call
});
});
call.on('member.joined', (res) => {
// Show connected status in HTML element `call_remote_stream_${user.id}`
// Play remote media stream on html element #call_remote_stream_${user.id}
const user = res.members[0];
call.playRemoteStream(user.id, `call_remote_stream_${user.id}`);
});
call.on('member.removed', (res) => {
res.members.forEach(member => {
// remove HTML element - `call_remote_stream_${member.user.id}`
});
});
call.on('ended', (res) => {
// Show call ended status if any joined member ends the call.
});
});
Receive a Call (Receiver's End)
- On call receive you will be notified using
user.call_invite_received
event. You will get acall
property in the callback function of this event which will be a call model and will be used in the next few steps. - Use the
sendInviteReceivedEvent
function on the call model to let the caller know that you have received the call. This function will triggermember.invite_received
event on caller's end and then the caller can change the status ofConnecting
/Contacting
toRinging
. - Use the
busy
parameter as true insendInviteReceivedEvent
function if you are busy on another call. The caller will use this parameter to show a busy message on its end. - You can start showing a popup on your side that will prompt the option to Accept or Decline the call. Simultaneously you can also start Ringing sound for better user experience.
- Now there are several options for you and the caller i.e Accept the call, Reject the call and Caller ends the call before you accept it. On any of these three actions, stop the ringing sound and remove the actions prompted in the above step.
- Use the
join
function to accept/join the call. On the success of join function show the local media stream as well as remote media stream in an HTML element. UseplayLocalStream
function to show local media stream andplayRemoteStream
to show remote media stream. - Use the
reject
function to reject/decline the call. The caller will be notified usingmember.rejected
event and then the caller can either proceed to call again or end the call. - Use the
ended
event on the call model to notify if the caller has ended the call. The caller can end the call before or after the receiver accepts or rejects it. So you can useended
event for both the cases. - Once you successfully join/accept the call, you can start showing time and end call options. On click of end call CTA, trigger the
end
function.
channelizeCall.chsocket.on('user.call_invite_received', (res) => {
const call = res.call;
// Start ringing sound
// Open popup having options to accept/reject
// Send an event so that caller can show ringing status at its end.
const busy = false;
call.sendInviteReceivedEvent(busy);
// Rejects the call - caller will be notified using member.rejected event
call.reject(() => {
// Stop ringing sound and close the popup
});
// Joins the call - caller will be notified using member.joined event
call.join({}, () => {
// Stop ringing sound, close the popup
// play local media stream on html element #call_local_stream
call.playLocalStream('call_local_stream');
// You can also show non joined members as per your use case
call.getMembers('joined').forEach(member => {
if (member.user.id === LOGIN_USER_ID) return ;
// Create remote div for each user - `call_remote_stream_${member.user.id}`
// Play remote media stream on html element #call_remote_stream_${user.id}
call.playRemoteStream(member.user.id, `call_remote_stream_${member.user.id}`);
});
// Add required events on the call model
call.on('member.invited', (res) => {
...
});
call.on('member.invite_received', (res) => {
...
});
call.on('member.rejected', (res) => {
...
});
call.on('member.joined', (res) => {
...
});
call.on('member.removed', (res) => {
...
});
});
// if caller cancel/end the call
call.on('ended', (res) => {
});
});
Actions on Call
Once the call is established and you are a part of the call. Now you can perform various actions like leaving the call, inviting new members to the call, removing members from the call, and ending the call.
- Use the
leave
function to leave a call, this function will trigger themember.removed
event. Upon leaving the call remove all the HTML elements for remote stream and local stream. - Use the
invite
function to invite new members to the call. A newly invited member will receive the call as mentioned in the above Receive a Call section. You can also invite members again even if they have rejected or completed(left) the call. - Use the
remove
function to remove a member from the call, this function will trigger themember.removed
event. - Use the
end
function to end the call, this function will trigger theended
event.
channelizeCall.chsocket.on('user.call_invite_received', (res) => {
const call = res.call;
...
call.join({}, () => {
...
// Invite new members
const memberIds = [ DAVID_ID ];
call.invite(memberIds, () => {
memberIds.forEach(memberId => {
// Create HTML element - `call_remote_stream_${memberId}`
// Show status Connecting/Contacting
});
});
// Remove members
const memberIds = [ CHARLIE_ID ];
call.remove(memberIds, () => {
memberIds.forEach(memberId => {
// Remove HTML element - `call_remote_stream_${memberId}`
});
});
// Leave the call
call.leave(() => {
// Remove call_local_stream element
// Remove call_remote_stream elements
});
// Ends the call
call.end({}, () => {
// Remove call_local_stream element
// Remove call_remote_stream elements
});
...
});
});
Channelize.io group calls scales to include up to 17 participants as of now.