# Realize Group Calling

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

../../../../_images_en/multivideoworkflow.jpg

# Initialize

Call JCMediaDevice create (opens new window) and JCCall create (opens new window) to Initialize modules needed to implement group calls:

//Initialize
-(bool)initialize {
   //1. Media class
   JCMediaDevice *mediaDevice = [JCMediaDevice create:client callback:self];
   //2. Media channel lass
   JCMediaChannel *mediaChannel = [JCMediaChannel create:client mediaDevice:mediaDevice callback:self];
   ...
}

Among them:

  • The callback in the JCMediaDevice create is the proxy object of the JCMediaDeviceCallback (opens new window) protocol, which is used to notify the upper layer of media device related events. Therefore, you need to specify the proxy object of callback first, and then implement the JCMediaDeviceCallback in the proxy object.

The main methods in the JCMediaDeviceCallback are as follows:

//Camera changes
-(void)onCameraUpdate;

//Audio output changes
-(void)onAudioOutputTypeChange:(NSString*)audioOutputType;

//Sound interruption recovery
-(void)onAudioInerruptAndResume:(BOOL)interrupt;

//Receive the first frame of video data
-(void)onRenderReceived:(JCMediaDeviceVideoCanvas*)canvas;

//Render start
-(void)onRenderStart:(JCMediaDeviceVideoCanvas*)canvas;
  • The callback in the JCMediaChannel create method is the proxy object of the JCMediaChannelCallback (opens new window) protocol, which is used to notify the relevant events in the channel to the upper layer. Therefore, you need to specify the proxy object of the callback first, and then implement the JCMediaChannelCallback method in the proxy object.

The main methods in JCMediaChannel are as follows:

//The callback of MediaChannel state change
-(void)onMediaChannelStateChange:(JCMediaChannelState)state oldState:(JCMediaChannelState)oldState;

//The callback of joining ChannelReason
-(void)onJoin:(bool)result reason:(JCMediaChannelReason)reason channelId:(NSString*)channelId;

//The callback of leaving the ChannelReason
-(void)onLeave:(JCMediaChannelReason)reason channelId:(NSString*)channelId;

//The callback of channel Stop result
-(void)onStop:(bool)result reason:(JCMediaChannelReason)reason;

//The callback of ParticipantJoin
-(void)onParticipantJoin:(JCMediaChannelParticipant*)participant;

//The callback of ParticipantLeft
-(void)onParticipantLeft:(JCMediaChannelParticipant*)participant;

//The callback of ParticipantUpdate
-(void)onParticipantUpdate:(JCMediaChannelParticipant*)participant participantChangeParam:(JCMediaChannelParticipantChangeParam *)participantChangeParam;

//The volume change of participants
-(void)onParticipantVolumeChange:(JCMediaChannelParticipant*)participant;

# Join a channel

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

    // 1. Enable the audio stream
    [mediaDeviceChannel enableUploadAudioStream:true];
    // 2. Turn on the video stream
    [mediaDeviceChannel enableUploadVIdeoStream:true];
    
  2. 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, fill in nil if no. See JCMediaChannelJoinParam (opens new window) object for details.

    // Join a channel
    [mediaChannel join:@"222" joinParam:nil];
    
  3. The onJoin (opens new window) callback triggers after joining the channel:

    // The callback of joining ChannelReason
    -(void)onJoin:(bool)result reason:(JCMediaChannelReason)reason channelId:(NSString*)channelId
    {
        if (result) {
          // Successfully joined
        } else {
          // Failed to join
        }
    }
    

# Create local video images

  1. After joining the channel, obtain the self object in the channel through the selfParticipant attribute in JCMediaChannel (opens new window):

    // 1. Access the memeber objects in the channel
    JCMediaChannelParticipant *participant = mediaChannel.selfParticipant;
    
  2. Call the startVideo (opens new window) method in the JCMediaChannelParticipant (opens new window) class to open the local video preview. This method returns a JCMediaDeviceVideoCanvas (opens new window) object, which is used to render the video to the canvas and manage the rendering method. (Calling this method will open the camera):

    // 2. Open local video preview
    JCMediaDeviceVideoCanvas *localCanvas = [participant startVideo:JCMediaDeviceRenderFullScreen pictureSize:JCMediaChannelPictureSizeLarge];
    

# Create remote video images

During a video call, you usually need to see other users. After the remote user successfully joins the channel, the onParticipantJoin (opens new window) callback will be triggered, which contains the object of the remote user.

In this callback, call the startVideo (opens new window) method in the JCMediaChannelParticipant (opens new window) class to set the remote user’s view. Calling this method will return a JCMediaDeviceVideoCanvas (opens new window) object, which is used to render the video to the canvas and manage the rendering method:

-(void)onParticipantJoin:(JCMediaChannelParticipant*)participant {
    if (participant.video) {
        JCMediaDeviceVideoCanvas *remoteCanvas = [participant startVideo:JCMediaDeviceRenderFullScreen pictureSize:JCMediaChannelPictureSizeLarge];
    }
}

More Steps

  • Upload a local audio stream

Since the SDK does not upload local audio streams by default, other members will not be able to hear your voice.If you want other members in the channel to hear your voice, you need to call the enableUploadAudioStream (opens new window) method in JCMediaChannel (opens new window) to upload the local audio stream:

// Send a local audio stream
[mediaChannel enableUploadAudioStream:true];

# Leave a channel

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

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

# Destroy local and remote video images

After the video is hung up, call stopVideo (opens new window) in the JCMediaChannelParticipant (opens new window) to destroy local and remote video images:

-(void)onLeave:(JCMediaChannelReason)reason channelId:(NSString*)channelId {
    if (localCanvas != nil) { // Destroy local video images
        [participant stopVideo];
    }
    if (remoteCanvas != nil) { // Remote video destruction
        [participant stopVideo];
    }
}

# 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
[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.

After stopped the channel, you also need to Call stopVideo (opens new window) in the JCMediaChannelParticipant (opens new window) to destroy local and remote video images.