# Realize group voice calling

This guide introduces how to implement group voice calling. The API call sequence of group voice calls is shown in the figure below:

../../../../_images_en/multiaudioworkflow.jpg

# Initialize

Extend the JCMediaChannelCallback (opens new window) object and JCMediaDeviceCallback (opens new window) object, and implement the pure virtual functions in these two objects.

class JCManager : public JCMediaDeviceCallback, public JCMediaChannelCallback
{
public:

    //The callback of MediaChannel state change
    virtual void onMediaChannelStateChange(JCMediaChannelState state, JCMediaChannelState oldState);
    //The callback of channel property change
    virtual void onMediaChannelPropertyChange(JCMediaChannelPropChangeParam propChangeParam);
    //The callback of joining ChannelReason
    virtual void onJoin(bool result, JCMediaChannelReason reason, const char* channelId);
    //The callback of leaving ChannelReason
    virtual void onLeave(JCMediaChannelReason reason, const char* channelId);
    //The callback of channel Stop result
    virtual void onStop(bool result, JCMediaChannelReason reason);
    //The callback of channel Query result
    virtual void onQuery(int operationId, bool result, JCMediaChannelReason reason, JCMediaChannelQueryInfo* queryInfo);
    //The callback of ParticipantJoin
    virtual void onParticipantJoin(JCMediaChannelParticipant* participant);
    //The callback of ParticipantLeft
    virtual void onParticipantLeft(JCMediaChannelParticipant* participant);
    //The callback of ParticipantUpdate
    virtual void onParticipantUpdate(JCMediaChannelParticipant* participant, JCMediaChannelParticipant::ChangeParam changeParam);
    //This callback triggers when messages are received in the channel
    virtual void onMessageReceive(const char* type, const char* content, const char* fromUserId);
    //The callback of InviteSipUserResult
    virtual void onInviteSipUserResult(int operationId, bool result, JCMediaChannelReason reason);
    //The volume change of Participants
    virtual void onParticipantVolumeChange(JCMediaChannelParticipant* participant);

public:
    //mediaDevice object
    JCMediaDevice* mediaDevice;
    //mediaChannel object
    JCMediaChannel* mediaChannel;
};

Call createJCMediaDevice (opens new window) and createJCCall (opens new window) to initialize the modules needed for group video calls:

//Initialize
bool JCManager::initialize()
{
    //1. Media class
    mediaDevice = createJCMediaDevice(client, this);
    //1. mediaChannel class
    mediaChannel = createJCMediaChannel(client, mediaDevice, this);
}

Among them:

  • This in the JCMediaDevice create method is a derived class of JCMediaDeviceCallback (opens new window) , which is used to notify the upper layer of media device-related events. Therefore, you need to create a derived class of JCMediaDeviceCallback, and then implement the pure virtual function of JCMediaDeviceCallback in the derived class.

  • This in the JCMediaChannel create method is a derived class of JCMediaChannelCallback (opens new window) , which is used to notify related events in the channel to the upper layer. Therefore, you need to create a derived class of JCMediaChannelCallback, and then implement the pure virtual function of JCMediaChannelCallback in the derived class.

TIP

The object in the callback can only be used in the callback and cannot be saved. The upper layer can obtain the call object through the corresponding method.

# Join a channel

JC SDK does not upload local audio streams by default, so if you need to enter the meeting to hear each other’s voices, you need to pre-open the upload logo of audio stream before joining the channel:

  1. Call enableUploadAudioStream (opens new window) to enable audio streaming:

    // Turn on audio streaming
    JCManager::shared()->mediaChannel->enableUploadAudioStream(true);
    

TIP

This interface can be called before joining the channel, or after joining the channel. The differences between the two circumstances are as follows.

If it is called before joining the channel, it only turns on or off the “Upload Audio”, but not send data. When joining the channel successfully, it will determine whether to upload audio data according to the value set by enableUploadAudioStream. At the same time, other members in the channel receive the status change callback (onParticipantUpdate) of the member “whether to upload audio”.

If called after joining the channel, it will turn on or off sending local audio stream data, and the server will also determine whether to upload audio data according to the value set by enableUploadAudioStream. At the same time, other members in the channel will receive the state change callback (onParticipantUpdate) of the member “whether to upload audio”.

In addition, this method can also implement the function of turning on/off mute. When the enable value is false, the local audio stream will be stopped, and you can hear other members’ voices, but other members will not hear your voice. Thus, the mute function has been realized.

Since the SDK uploads video streams by default, you need to turn off the upload video stream logo before joining the channel for voice calls:

// Turn off uploading video stream
JCManager::shared()->mediaChannel->enableUploadVideoStream(false);
  1. Call the join (opens new window) method to join the channel. You need to pass in the following parameters in this method:
  • channelIdOrUri: Channel ID or channel Uri. When uriMode in param is set to true, it means channel Uri, and others mean channel ID. Users with the same channel ID or Uri will enter the same channel.

  • joinParam: Join parameters, if not, fill in NULL. See JCMediaChannelJoinParam (opens new window) object for details.

// Join a channel
JCManager::shared()->mediaChannel->join("channel ID", NULL);
  1. Receive onJoin (opens new window) callback after joining a channel:

    // The callback of joining ChannelReason
    void JCManager::onJoin(bool result, JCMediaChannelReason reason, const char* channelId)
    {
        if (result) {
        //the logic of successful joining in
        ...
        } else {
        //the logic of failed joining in
        ...
        }
    }
    

# Leave a channel

Call the leave (opens new window) method to leave the current channel:

JCManager::shared()->mediaChannel->leave();

After leaving the channel, they receive the onLeave (opens new window) callback, and other members receive the onParticipantLeft (opens new window) callback at the same time:

// The callback of leaving the channel
void JCManager::onLeave(JCMediaChannelReason reason, const char* channelId);
{
    //The logic of leaving a channel
}

# Destroy a channel

If you want to destroy a channel, you can call the following interface, and all members will be quit:

// End a channel
JCManager::shared()->mediaChannel->stop();

After the channel is stopped, the member that initiated the termination receives the onStop (opens new window) callback, and other members receive the onLeave (opens new window) callback at the same time. Please refer to JCMediaChannelReason (opens new window) for the enumeration value of the reason for failure.

void JCManager::onStop(bool result, JCMediaChannelReason reason)
{
    //The pocess logic of ending a channel
}

Now, you have completed the basic function of group voice calling.