logo
On this page

Call invitation


Overview

ZEGO Instant Messaging (ZIM) SDK provides the call invitation feature that supports full service procedure control. For example, the feature allows a caller to send a call invitation to a called user and allows the called user to accept or refuse the invitation. In this case, the caller and the called user can be offline. A call invitation can be in a common mode or an advanced mode.

In common mode, a user can initiate, cancel, accept, and reject a call invitation, and does not respond to a call invitation within the specified timeout period. On this basis, in advanced mode, a user can invite a new user during the call, and quit and terminate the call.

The call invitation feature provides only basic capabilities for service procedure control. The service requirements for using this feature must be manually implemented. For example, the feature is commonly used in a chat tool for initiating a voice call invitation or a video call invitation.

User states

ZIMCallUserState specifies the state of a user in each call invitation procedure. This section describes how a user state changes, and the relationship among a state, an operation, and a callback.

State changes

The following figure shows how a user state changes in an entire call invitation process from call initiation to call termination.

StateDescriptionTriggering eventApplicable mode
InvitingBeing invited.The user is being invited.
  • Common mode
  • Advanced mode
AcceptedInvitation accepted.
  • A user initiates a call invitation.
  • A user accepts a call invitation.
RejectedInvitation rejected.A user rejects a call invitation.
CanceledInvitation canceled.
  • A user cancels a call invitation.
  • The called user does not respond to the invitation. The caller gets offline and the heartbeat times out.
ReceivedInvitation received.
  • An online user receives a call invitation.
  • An offline user gets online within the specified timeout period.
TimeoutInvitation times out.The called user fails to respond to the invitation within the specified timeout period.
QuitQuit the call.A user in the call quit the call.
  • Advanced mode
UnknownUnknownContact ZEGOCLOUD technical support.

States and corresponding operations and callbacks

In a call invitation process, the call state of a user determines whether the user can call a specific operation or listen to a specific event.

  • The following table describes the correspondence between a call state and an operation.
callInvitecallCancelcallAcceptcallRejectcallingInvitecallQuitcallEnd
InvitingA user can call this operation when the user is in a call, regardless of the call state of the user.A user can call this operation when no response is given to a call invitation after the user initiates the call invitation, regardless of the user state.✔️✔️
Accepted✔️✔️✔️
Rejected
Canceled
Received✔️✔️
Timeout
Quit
Unknown
  • The following table describes the correspondence between a call state and a callback.
onCallInvitationReceivedonCallInvitationTimeoutonCallInvitationCancelledonCallInvitationEndedonCallUserStateChanged
Inviting✔️✔️✔️✔️✔️
Accepted✔️✔️
Rejected
Cancelled
Received✔️✔️✔️
Timeout
Quit✔️
Unknown

Common mode

In common mode, the lifecycle of a call invitation ends after all invitees respond to the invitation. To be specific, a call invitation is terminated after all invitees accept or refuse the invitation, or the invitation times out. The following example shows that a client A initiates a call invitation to a client B in common mode.

1. Listen to the state changes of call invitation users

You can invoke the callUserStateChanged callback to listen to the state changes of an invitee.

Untitled
// Listen to the state changes of users related to the call invitation.
zim.on('callUserStateChanged', (zim, info) => {
    // the userID whose state has changed
    const changeCallID = info.callID;
    info.callUserList.forEach(userInfo => {
        // The state-changed user's user ID, the latest user status, and the passthrough field (consistent with the extended data carried when the user accepts, rejects, or exits a call)
        const { userID, state, extendedData } = userInfo;
    });
})
1
Copied!

2. Initiate a call invitation

The client A initiates a call invitation to the client B. The following figure shows the corresponding flowchart.

  1. Client A registers the callInvitationCreated callback interface to receive notifications that a call invitation has been created; Client B registers the callInvitationReceived callback interface to receive invitation notifications from client A.
  2. Client A initiates a call invitation by calling the callInvite interface. After receiving the invitation information, client B can choose to Accept or Reject.
Note

If the client B is offline, the following two cases are involved:

  • The client B logs in before the invitation times out. In this case, the client B can invoke the callInvitationReceived callback interface to receive the invitation notification.vitation notification.
  • The client B logs in after the invitation times out. In this case, the client B can call the queryCallInvitationList operation to query the invitation list.
  • Send a call invitation to an online user:
Untitled
/** Send a call invitation to online users */
var invitees = ['xxxx'];  // List of invitees' IDs
var config = { timeout: 200 }; // Invitation timeout period in seconds, ranging from 1 to 600
zim.callInvite(invitees, config)
    .then(({ callID, timeout, errorInvitees }) => {
        // Operation succeeded. The call invitation ID that is internally generated by ZIM SDK after the call invitation is initiated. The ID uniquely identifies a call invitation. The call invitation ID is required when the inviter wants to cancel the call invitation or when the invitee wants to accept or reject the invitation.
    })
    .catch(err => {
        // Operation failed
    })
1
Copied!
    • Send a call invitation to offline users.
  • Untitled
    /** Send a call invitation to offline users */
    var invitees = ['xxxx'];  // List of invitees' IDs
    // To push the offline messages about the call invitation to offline users, you should configure the pushConfig and integrated the ZPNs SDK 
    var pushConfig = {
        title: 'push title',
        content: 'push content',
        payload: 'push payload'
    };
    
    var config = { 
        timeout: 200, // Invitation timeout period in seconds, ranging from 1 to 600
        extendedData: 'your call invite extendedData',
        pushConfig,
    };
    zim.callInvite(invitees, config)
        .then(({ callID, timeout, errorInvitees }) => {
            // Operation succeeded. The call invitation ID that is internally generated by ZIM SDK after the call invitation is initiated. The ID uniquely identifies a call invitation. The call invitation ID is required when the inviter wants to cancel the call invitation or when the invitee wants to accept or reject the invitation.
        })
        .catch(err => {
            // Operation failed
        })
    
    1
    Copied!
    • The invitation initiator receives a notification that the call invitation has been created.
    Untitled
    /** Notification for the initiator of the call invitation that it has been created */
    zim.on('callInvitationCreated', (zim, info) => {
        // console.log('callInvitationCreated', info)
    })
    
    1
    Copied!
    • The callback notification after the invitee receives the invitation
    Untitled
    /** Callback notification for the invitee after receiving an invitation */
    zim.on('callInvitationReceived', (zim, { callID, inviter, timeout, extendedData }) => {
        // console.log('callInvitationReceived', { callID, inviter, timeout, extendedData })
    })
    
    1
    Copied!

    3. Cancel a call invitation

    The client A sends a call invitation to the client B and then cancels the call invitation. The following figure shows the corresponding flowchart.

    1. After the client A initiates a call invitation, the client A can call the callCancel operation to cancel the call invitation.
    Note

    After a call invitation is successfully initiated and before it times out, if no callee accepts, and if the caller actively logs out or disconnects due to a heartbeat timeout, the call invitation will also be canceled.

    1. After the call invitation is canceled, the client B can receive a notification that is returned by the callInvitationCancelled callback.
    • Cancel a call invitation.
    Untitled
    // Cancel the call invitation
    var callID = 'xxxx';
    var invitees = ['xxxx'];  // List of invitees' IDs
    var config = { extendedData: 'xxxx' }; 
    zim.callCancel(invitees, callID, config)
        .then(res => {
            // Operation successful
        })
        .catch(err => {
            // Operation failed
        })
    
    1
    Copied!
    • The callback notification received by the invitee after the call invitation is canceled.
    Untitled
    // Callback notification for the invitee after the invitation is cancelled
    zim.on('callInvitationCancelled',(zim, { callID, inviter, extendedData }) => {
        // console.log('callInvitationCancelled', { callID, inviter, extendedData })
    })
    
    1
    Copied!

    4. Accept a call invitation

    The client B receives a call invitation from the client A and then accepts the call invitation. The following figure shows the corresponding flowchart.

    1. After the client B receives a call invitation from the client A, the client B can call the callAccept operation to accept the call invitation.
    2. After the client B accepts the call invitation, the client A can receive a notification that is returned by the callUserStateChanged callback. If multiple users are involved in the call invitation, all involved users can receive the notification returned by this callback.
    • Accept a call invitation.
    Untitled
    // Accept the call invitation
    var callID = 'xxxx';
    var config = { extendedData: 'xxxx' }; 
    zim.callAccept(callID, config)
        .then(res => {
            // Operation succeeded
        })
        .catch(err => {
            // Operation failed
        })
    
    1
    Copied!
    • The callback notification returned after the invitee accepts the call invitation.
    Untitled
    // Callback received by the inviter after an invitee accepts the invitation
    zim.on('callUserStateChanged', (zim, info) => {
        // Related callID
        const changeCallID = info.callID;
        info.callUserList.forEach(userInfo => {
            // The state-changed user's user ID, the latest user status, and the passthrough field (consistent with the extended data carried when the user accepts, rejects, or exits a call)
            const { userID, state, extendedData } = userInfo;
            // state = 1 indicates acceptance, please refer to the ZIMCallUserState enumeration for details
            if (state == 1) {
                // Your logic
            } 
        });
    })
    
    1
    Copied!

    5. Reject a call invitation

    The client B receives a call invitation from the client A and then rejects the call invitation. The following figure shows the corresponding flowchart.

    1. After the client B receives a call invitation from the client A, the client B can call the callReject operation to reject the call invitation.
    2. After the client B rejects the call invitation, the client A can receive a notification that is returned by the callUserStateChanged callback.
    • Reject a call invitation.
    Untitled
    // Reject a call invitation
    var callID = 'xxxx';
    var config = { extendedData: 'xxxx' }; 
    zim.callReject(callID, config)
        .then(res => {
            // Operation succeeded
        })
        .catch(err => {
            // Operation failed
        })
    
    1
    Copied!
    • The callback notification returned after the invitee rejects the call invitation.
    Untitled
    // Callback received by the inviter after an invitee rejects the invitation
    zim.on('callUserStateChanged', (zim, info) => {
        // Related callID
        const changeCallID = info.callID;
        info.callUserList.forEach(userInfo => {
            // The state-changed user's user ID, the latest user status, and the passthrough field (consistent with the extended data carried when the user accepts, rejects, or exits a call)
            const { userID, state, extendedData } = userInfo;
            // state = 2 indicates rejection, please refer to the ZIMCallUserState enumeration for details
            if (state == 2) {
                // Your logic
            }
        });
    })
    
    1
    Copied!

    6. A call invitation times out

    The client B receives a call invitation from the client A, but does not respond to the call invitation within the timeout period. The following figure shows the corresponding flowchart.

    1. The client A, namely, the inviter, can invoke the callUserStateChanged callback to receive a notification indicating that the call invitation times out because the client B does not respond to the invitation. If multiple users are involved in the call invitation, all involved users can receive the notification returned by this callback.
    2. The client B, namely, the invitee, can invoke the callInvitationTimeout callback to receive a notification indicating that the call invitation times out because the client B itself does not respond to the invitation.
    • Callback received by the inviter:
    Untitled
    zim.on('callUserStateChanged', (zim, info) => {
        // Related callID
        const changeCallID = info.callID;
        info.callUserList.forEach(userInfo => {
            // The state-changed user's user ID, the latest user status, and the passthrough field (consistent with the extended data carried when the user accepts, rejects, or exits a call)
            const { userID, state, extendedData } = userInfo;
            // state = 6 indicates timeout, please refer to the enumeration ZIMCallUserState for details
            if (state == 6) {
                // Your business logic
            }
        });
    })
    
    1
    Copied!
    • Callback received by the invitee:
    Untitled
    // Callback notification received by the "invitee" after the invitee's response timeout, timeout time unit: seconds
    zim.on('callInvitationTimeout', (zim, { callID }) => {
        // console.log('callInvitationTimeout', { callID })
    })
    
    1
    Copied!

    Advanced mode

    You can initiate a call invitation in advanced mode in a call invitation scenario involving a plurality of users, such as a multi-invitee call invitation scenario.

    After a call invitation is initiated in advanced mode, the lifecycle of the call invitation ends when a user calls the callEnd operation to terminate the call. Before the call is terminated, a user in the call can invite a new user or quit the call.

    Initiate a call invitation in advanced mode

    To initiate a call invitation in advanced mode, you must specify the mode when you call the callInvite operation.

    Untitled
    /**Send a call invitation to an online user in advanced mode.**/
    var invitees = ['xxxx'];  // List of invitees' IDs
    // Timeout for the invitation in seconds, ranging from 1 to 600
    // mode represents the call invitation mode, 1 represents the advanced mode.
    var config = { timeout: 200, mode: 1 };
    zim.callInvite(invitees, config)
        .then(({ callID, timeout, errorInvitees }) => {
            // Operation succeeded. 
            // The call invitation ID that is internally generated by ZIM SDK after the call invitation is initiated. The ID uniquely identifies a call invitation. The call invitation ID is required when the inviter wants to cancel the call invitation or when the invitee wants to accept or reject the invitation.
        })
        .catch(err => {
            // Operation failed
        })
    
    1
    Copied!
    Note

    The advanced mode is the same as the common mode in call invitation cancellation, acceptance, rejection, and timeout. The only difference between the two modes lies in call invitation initiation.

    Invite a user during a call

    After a call invitation is initiated in advanced mode, a user in the Accepted state can call the callingInvite operation to invite a new user. Note that a maximum of 10 users(including the invitation initiator) are allowed in a call.

    • Invite a user during a call
    Untitled
    //Invite a user during a call
    const config = { timeout: 60, extendedData: 'callingInvite extendedData' };
    const userList = [];
    // The callID is obtained through the callback of creating an advanced mode call invitation.
    zim.callingInvite(userList, 'callID', config)
        .then(res => {
            // Operation successful
        }).catch(err => {
            // Operation failed
        });
    
    1
    Copied!

    Actively join a call or switch devices

    After implementing the advanced mode call invitation, the callJoin interface can be called in the following two situations:

    • A user who has not joined the call wishes to join the call.
    • After a multi-terminal login user uses device A to initiate or accept an invitation, he or she wants to make other devices the new primary device.
    Note
    • The main device refers to the device that actively calls the interface to initiate, accept or join the call to participate in the call.
    • Only the main device can detect changes in call invitations, and other devices can only obtain the data in the call invitations by querying the call invitation list.

    For the scenario where the user outside the call joins successfully, the user's state will flow to accepted. At this time, all users in the call will receive the notification callback of callUserStateChanged

    For the scenario of switching devices, other users in the call will not be aware of it.

    Untitled
    // Join a call or switch the device
    
    const config = { extendedData: 'callJoin extendedData' };
    zim.callJoin('callID', config)
        .then(res => {
            // Operation succeeded
        }).catch(err => {
            // Operation failed
        });
    
    1
    Copied!

    Quit a call

    After a call invitation is initiated in advanced mode, a user in the Accepted state can call the callQuit operation to quit the call. After the user quits the call, the state of the user is changed to quit. Then, the user and other users who still stay in the call receive a notification returned by the callUserStateChanged callback.

    • Quit a call.
    Untitled
    // Quit a call
    const config = { extendedData: 'callQuit extendedData' };
    zim.callQuit('callID', config).then(res => {
        // Operation successful
    }).catch(err => {
        // Operation failed
    });
    
    1
    Copied!
    • The users in the call receive a notification indicating that a user quits the call.
    Untitled
    // Other users whose user state are "inviting", "received", and "accept" and the quitting user can receive notifications that a user exits the call
    zim.on('callUserStateChanged', (zim, info) => {
        // callID obtained through the callback of creating an advanced mode call invitation
        const changeCallID = info.callID;
        info.callUserList.forEach(userInfo => {
            // The state-changed user's user ID, the latest user status, and the passthrough field (consistent with the extended data carried when the user accepts, rejects, or exits a call)
            const { userID, state, extendedData } = userInfo;
            // state = 7 indicates exit, please refer to the enumeration ZIMCallUserState for details
            if (state == 7) {
                // Your logic
            }
            
        });
    })
    
    1
    Copied!

    Terminate a call

    After a call invitation is initiated in advanced mode, a user in the Accepted state can call the callEnd operation to terminate the call. Subsequently, states of all users remain unchanged, and the call state is changed to end. The users in the Iniviting, Accepted, and Received states receive a notification returned by the callInvitationEnded callback.

    • Terminate a call.
    Untitled
    //Terminate a call.
    const config = { extendedData: 'callEnd extendedData' };
    // callID obtained through the callback of creating an advanced mode call invitation
    zim.callEnd('callID', config).then(res => {
        // Operation succeeded
    }).catch(err => {
        // Operation failed
    });
    
    1
    Copied!
    • The users in the call receive a notification indicating that the call is terminated.
    Untitled
    zim.on('callInvitationEnded', (zim, info) => {
        // console.log('callInvitationEnded', info)
    })
    
    1
    Copied!

    What's more

    Check whether the invitation has been delivered

    If you want to let the online users in the invitation know whether other users have received the invitation, so as to implement related business logic, please change enableNotReceivedCheck in ZIMCallInviteConfig to YES when initiating a call invitation, so as to start checking whether the invitation has been delivered.

    Untitled
    /** Send call invitation to users */
    var invitees = ['xxxx'];  // List of user IDs to be invited
    var config = { 
        timeout: 200, // Invitation timeout in seconds, ranging from 1 to 600  
        enableNotReceivedCheck: true // Enable not received check
    };  
    zim.callInvite(invitees, config)
        .then(({ callID, timeout, errorInvitees }) => {
            // Operation successful, the callID here is the ID generated by the SDK internally to uniquely identify a call invitation; this callID will be used when the initiator cancels the call or the invitee accepts/rejects the call
        })
        .catch(err => {
            // Operation failed
        })
    
    1
    Copied!

    After the caller initiates a call invitation, if the called party does not receive this invitation within 5 seconds (you can contact ZEGOCLOUD Technical Support to adjust the interval to 3 seconds or 4 seconds) due to network disconnection, offline, etc.:

    • If the called party client uses the ZIM SDK version 2.14.0 or later, its user state will flow to ZIMCallUserStateNotYetReceived, indicating that the invitation has not yet been delivered. At this time, the business logic can be implemented to display UI prompts such as "This user may be offline and cannot receive call invitations temporarily" to online users in the call invitation.
    • If the called client uses ZIM SDK version 2.14.0 or earlier, its user state remains ZIMCallUserStateInviting. If this state remains for more than 5 seconds, the above business logic can also be implemented.
    Note

    Please refer to listen to the state changes of call invitation users for more information.

    Afterwards, if the called user goes online and accepts the invitation before the invitation times out, the user state of the member will flow to ZIMCallUserStateReceived.

    Query the list of call invitations

    A user can call the queryCallInvitationList operation to query the list of call invitations related to the user. The maximum entries for a single query is 100, and any number exceeding 100 will be processed as 100.

    Untitled
    /**
      * Query the call invitation list
      * 1. Query the user's own call invitation list, with 20 call invitation data per query
      * 2. Fill in nextFlag as 0 for the first query, indicating starting from the latest call invitation (the one with the latest creation time)
      */
    const config = { count: 20, nextFlag: 0 };
    zim.queryCallInvitationList(config).then(res => {
        const { callList, nextFlag } = res;
        // next page
        config.nextFlag = nextFlag;
        zim.queryCallInvitationList(config);
    });
    
    1
    Copied!

    Previous

    Reply to a message

    Next

    Get the conversion list