This article provides some instructions and considerations for upgrading the ZIM SDK for Windows version.
2.19.0 upgrade guide
Warning
Starting from version 2.19.0, the following interfaces have undergone significant changes. Therefore, when upgrading from an older version to version 2.19.0, please read the following guidelines.
downloadMediaFile and related callbacks
The original downloadMediaFile API is deprecated. Please use the new downloadMediaFile instead. The updated downloadMediaFile introduces a new config parameter, which can be used to specify the download of individual media content in multi-item messages.
The ZIMMediaDownloadedCallback callback has been updated to support multi-item messages. Developers need to fix the calls according to the IDE's compile error hints:
The message parameter in onMediaDownloaded has changed from ZIMMediaMessage to ZIMMessage.
In ZIMMediaDownloadingProgress and ZIMMediaDownloadedCallback, the message parameter type has changed from const std::shared_ptr<ZIMMediaMessage> & to const std::shared_ptr<ZIMMessage> & to support multi-item messages. Developers need to fix the calls according to the IDE's compile error hints.
In ZIMMediaDownloadingProgress and ZIMMediaDownloadedResult, the parameter message type has changed from ZIMMediaMessage to ZIMMessage to support composite messages. TypeScript developers need to update their code based on the compilation error messages from their IDE.
Usage in Version 2.19.0(For Multi-item Messages)
// Assume multipleMessage.messageInfoList[0] is a text message, and multipleMessage.messageInfoList[1] is an image message
ZIMMultipleMessage multipleMessage = (ZIMMultipleMessage) message;
// !mark(1:3)
ZIMMediaDownloadConfig config = new ZIMMediaDownloadConfig();
// Specify to download the image message
config.messageInfoIndex = 1;
// !mark
zim.getInstance().downloadMediaFile(multipleMessage, ZIMMediaFileType.ORIGINAL_FILE, config, new ZIMMediaDownloadedCallback() {
@Override
// !mark
public void onMediaDownloadingProgress(ZIMMessage message, long currentFileSize, long totalFileSize) {
// Download progress
// Developers need to check the type of the message and cast it to the corresponding message type
if (message instanceof ZIMMultipleMessage) {
ZIMMultipleMessage multipleMessage = (ZIMMultipleMessage) message;
// Handle multi-item messages
}
// Handle other types of messages
......
}
@Override
// !mark
public void onMediaDownloaded(ZIMMessage message, ZIMError errorInfo) {
// Download complete
// Developers need to check the type of the message and cast it to the corresponding message type
if (message instanceof ZIMMultipleMessage) {
ZIMMultipleMessage multipleMessage = (ZIMMultipleMessage) message;
// Handle multi-item messages
}
// Handle other types of messages
......
}
});
// Assume multipleMessage.messageInfoList[0] is a text message, and multipleMessage.messageInfoList[1] is an image message
ZIMMultipleMessage multipleMessage = (ZIMMultipleMessage) message;
// !mark(1:3)
ZIMMediaDownloadConfig config = new ZIMMediaDownloadConfig();
// Specify to download the image message
config.messageInfoIndex = 1;
// !mark
zim.getInstance().downloadMediaFile(multipleMessage, ZIMMediaFileType.ORIGINAL_FILE, config, new ZIMMediaDownloadedCallback() {
@Override
// !mark
public void onMediaDownloadingProgress(ZIMMessage message, long currentFileSize, long totalFileSize) {
// Download progress
// Developers need to check the type of the message and cast it to the corresponding message type
if (message instanceof ZIMMultipleMessage) {
ZIMMultipleMessage multipleMessage = (ZIMMultipleMessage) message;
// Handle multi-item messages
}
// Handle other types of messages
......
}
@Override
// !mark
public void onMediaDownloaded(ZIMMessage message, ZIMError errorInfo) {
// Download complete
// Developers need to check the type of the message and cast it to the corresponding message type
if (message instanceof ZIMMultipleMessage) {
ZIMMultipleMessage multipleMessage = (ZIMMultipleMessage) message;
// Handle multi-item messages
}
// Handle other types of messages
......
}
});
Usage in Version 2.19.0(For Multi-item Messages)
// Assume multipleMessage.messageInfoList[0] is a text message, and multipleMessage.messageInfoList[1] is an image message
auto multipleMessage = std::static_pointer_cast<ZIMMultipleMessage>(message);
// !mark(1:3)
ZIMMediaDownloadConfig config;
// Specify to download the image message
config.messageInfoIndex = 1;
ZIM::getInstance()->downloadMediaFile(multipleMessage,
ZIMMediaFileType::ZIM_MEDIA_FILE_TYPE_ORIGINAL_FILE,
// !mark(1:2)
config,
[=](const std::shared_ptr<ZIMMessage> &message, unsigned long long currentFileSize, unsigned long long totalFileSize) {
// Download Progress
// Developers need to check the type of the message and cast it to the corresponding message type
if (message->getType() == ZIMMessageType::ZIM_MESSAGE_TYPE_MULTIPLE) {
auto multipleMessage = std::static_pointer_cast<ZIMMultipleMessage>(message);
// Handle multi-item messages
}
// Handle other message types
......
},
// !mark
[=](const std::shared_ptr<ZIMMessage> &message, const ZIMError &errorInfo) {
// Download completed
// Developers need to check the type of the message and cast it to the corresponding message type
if (message->getType() == ZIMMessageType::ZIM_MESSAGE_TYPE_MULTIPLE) {
auto multipleMessage = std::static_pointer_cast<ZIMMultipleMessage>(message);
// Handle multi-item messages
}
// Handle other message types
......
});
// Assume multipleMessage.messageInfoList[0] is a text message, and multipleMessage.messageInfoList[1] is an image message
auto multipleMessage = std::static_pointer_cast<ZIMMultipleMessage>(message);
// !mark(1:3)
ZIMMediaDownloadConfig config;
// Specify to download the image message
config.messageInfoIndex = 1;
ZIM::getInstance()->downloadMediaFile(multipleMessage,
ZIMMediaFileType::ZIM_MEDIA_FILE_TYPE_ORIGINAL_FILE,
// !mark(1:2)
config,
[=](const std::shared_ptr<ZIMMessage> &message, unsigned long long currentFileSize, unsigned long long totalFileSize) {
// Download Progress
// Developers need to check the type of the message and cast it to the corresponding message type
if (message->getType() == ZIMMessageType::ZIM_MESSAGE_TYPE_MULTIPLE) {
auto multipleMessage = std::static_pointer_cast<ZIMMultipleMessage>(message);
// Handle multi-item messages
}
// Handle other message types
......
},
// !mark
[=](const std::shared_ptr<ZIMMessage> &message, const ZIMError &errorInfo) {
// Download completed
// Developers need to check the type of the message and cast it to the corresponding message type
if (message->getType() == ZIMMessageType::ZIM_MESSAGE_TYPE_MULTIPLE) {
auto multipleMessage = std::static_pointer_cast<ZIMMultipleMessage>(message);
// Handle multi-item messages
}
// Handle other message types
......
});
title="Usage in Version 2.19.0(For Multi-item Messages)
// Assume multipleMessage.messageInfoList[0] is a text message, and multipleMessage.messageInfoList[1] is an image message
const multipleMessage: ZIMMessage = {
type: 10,
messageInfoList: [
{ type: 1, message: "Hello, World!" },
{ type: 11, fileLocalPath: '' }
]
}
const config: ZIMMediaDownloadConfig = {
// Specify to download the image message
messageInfoIndex: 1
}
// !mark(1:4)
zim.downloadMediaFile(multipleMessage, 1, config, (message: ZIMMessage, currentFileSize: number, totalFileSize: number) => {
// Download progress
// Developers need to check the type of the message and cast it to the corresponding message type
if (message.type === 10) {
// !mark
const multipleMessage: ZIMMultipleMessage = message as ZIMMultipleMessage
// Handle multi-item messages
}
// Handle other types of messages
......
}).then((message: ZIMMessage) => {
// Download complete
// Developers need to check the type of the message and cast it to the corresponding message type
if (message.type === 10) {
// !mark
const multipleMessage: ZIMMultipleMessage = message as ZIMMultipleMessage
// Handle multi-item messages
}
// Handle other types of messages
......
}).catch((errorInfo) => {
// Failed to download
})
// Assume multipleMessage.messageInfoList[0] is a text message, and multipleMessage.messageInfoList[1] is an image message
const multipleMessage: ZIMMessage = {
type: 10,
messageInfoList: [
{ type: 1, message: "Hello, World!" },
{ type: 11, fileLocalPath: '' }
]
}
const config: ZIMMediaDownloadConfig = {
// Specify to download the image message
messageInfoIndex: 1
}
// !mark(1:4)
zim.downloadMediaFile(multipleMessage, 1, config, (message: ZIMMessage, currentFileSize: number, totalFileSize: number) => {
// Download progress
// Developers need to check the type of the message and cast it to the corresponding message type
if (message.type === 10) {
// !mark
const multipleMessage: ZIMMultipleMessage = message as ZIMMultipleMessage
// Handle multi-item messages
}
// Handle other types of messages
......
}).then((message: ZIMMessage) => {
// Download complete
// Developers need to check the type of the message and cast it to the corresponding message type
if (message.type === 10) {
// !mark
const multipleMessage: ZIMMultipleMessage = message as ZIMMultipleMessage
// Handle multi-item messages
}
// Handle other types of messages
......
}).catch((errorInfo) => {
// Failed to download
})
sendMessage
The sendMediaMessage and the old sendMessage methods are deprecated. A new sendMessage method is introduced, which supports sending any type of message.
The callback for sendMessage is different from the callback of the old method with the same name. It has changed from ZIMMediaMessageSentCallback to ZIMMessageSentFullCallback.
In ZIMMessageSentFullCallback, the message parameter in onMediaUploadingProgress has changed from ZIMMessage to ZIMMediaMessage to ensure that only media messages are notified in the callback. Developers need to fix the calls according to the compile error hints from the IDE. (Currently, only developers using the replyMessage interface will be affected by the need to resolve compile errors.)
Usage in Version 2.19.0
ZIMImageMessage imageMessage = (ZIMImageMessage) message;
// !mark
zim.getInstance().sendMessage(imageMessage, "TO_CONVERSATION_ID", ZIMConversationType.PEER, new ZIMMessageSentFullCallback() {
@Override
public void onMessageSent(ZIMMessage message, ZIMError errorInfo) {
// Message send result
}
@Override
// !mark
public void onMediaUploadingProgress(ZIMMediaMessage message, long currentFileSize, long totalFileSize) {
// Multimedia upload progress
}
@Override
public void onMessageAttached(ZIMMessage message) {
// Developers can listen to this callback to execute business logic before sending the message
}
});
ZIMImageMessage imageMessage = (ZIMImageMessage) message;
// !mark
zim.getInstance().sendMessage(imageMessage, "TO_CONVERSATION_ID", ZIMConversationType.PEER, new ZIMMessageSentFullCallback() {
@Override
public void onMessageSent(ZIMMessage message, ZIMError errorInfo) {
// Message send result
}
@Override
// !mark
public void onMediaUploadingProgress(ZIMMediaMessage message, long currentFileSize, long totalFileSize) {
// Multimedia upload progress
}
@Override
public void onMessageAttached(ZIMMessage message) {
// Developers can listen to this callback to execute business logic before sending the message
}
});
sendMediaMessage
Since version 2.19.0, multimedia messages must be sent using the sendMessage interface. The sendMediaMessage interface is deprecated to unify message sending and facilitate future general extensions.
In ZIMMessageSendNotification, the message parameter type in the onMediaUploadingProgress callback method has changed from ZIMMessage to ZIMMediaMessage to ensure that only media messages are notified in the callback. TypeScript developers need to fix the calls based on the compile error hints from the IDE. (Currently, only developers using TypeScript and the replyMessage interface will be affected by the need to resolve compile errors.)
Usage in Version 2.19.0
auto imageMessage = std::static_pointer_cast<ZIMImageMessage>(message);
ZIMMessageSendConfig config;
config.priority = ZIMMessagePriority::ZIM_MESSAGE_PRIORITY_MEDIUM;
// !mark
auto notification = std::make_shared<ZIMMessageSendNotification>();
notification->onMessageAttached = [=](const std::shared_ptr<ZIMMessage> &message) {
// Developers can listen to this callback to execute business logic before sending the message
};
notification->onMediaUploadingProgress = [=](const std::shared_ptr<ZIMMediaMessage> &message, unsigned long long currentFileSize, unsigned long long totalFileSize) {
// Upload Progress
};
// !mark
ZIM::getInstance()->sendMessage(imageMessage,
"TO_CONVERSATION_ID",
ZIMConversationType::ZIM_CONVERSATION_TYPE_PEER,
config,
notification,
[=](const std::shared_ptr<ZIMMessage> &message, const ZIMError &errorInfo) {
// Message Send Result
});
auto imageMessage = std::static_pointer_cast<ZIMImageMessage>(message);
ZIMMessageSendConfig config;
config.priority = ZIMMessagePriority::ZIM_MESSAGE_PRIORITY_MEDIUM;
// !mark
auto notification = std::make_shared<ZIMMessageSendNotification>();
notification->onMessageAttached = [=](const std::shared_ptr<ZIMMessage> &message) {
// Developers can listen to this callback to execute business logic before sending the message
};
notification->onMediaUploadingProgress = [=](const std::shared_ptr<ZIMMediaMessage> &message, unsigned long long currentFileSize, unsigned long long totalFileSize) {
// Upload Progress
};
// !mark
ZIM::getInstance()->sendMessage(imageMessage,
"TO_CONVERSATION_ID",
ZIMConversationType::ZIM_CONVERSATION_TYPE_PEER,
config,
notification,
[=](const std::shared_ptr<ZIMMessage> &message, const ZIMError &errorInfo) {
// Message Send Result
});
Starting from version 2.18.0, the following interfaces have undergone significant changes. Therefore, when upgrading from an older version to version 2.18.0, please read the following guidelines.
Callback on receiving one-to-one messages
The deprecated callback onReceivePeerMessage for receiving one-to-one messages has been replaced by onPeerMessageReceived.
The deprecated callback receivePeerMessage for receiving one-to-one messages has been replaced by peerMessageReceived.
The new callback supports the following features:
When a user is online, they can receive one-to-one messages through this callback.
When a user logs back into the ZIM SDK, they can receive all one-to-one messages received during their offline period (up to 7 days).
// New callback
public void onPeerMessageReceived(ZIM zim, ArrayList<ZIMMessage> messageList,
ZIMMessageReceivedInfo info, String fromUserID) {}
// Old callback
public void onReceivePeerMessage(ZIM zim, ArrayList<ZIMMessage> messageList,
String fromUserID) {}
// New callback
public void onPeerMessageReceived(ZIM zim, ArrayList<ZIMMessage> messageList,
ZIMMessageReceivedInfo info, String fromUserID) {}
// Old callback
public void onReceivePeerMessage(ZIM zim, ArrayList<ZIMMessage> messageList,
String fromUserID) {}
// New callback
peerMessageReceived: (zim: ZIM, data: ZIMEventOfConversationMessageReceivedResult) => void;
// Old callback
receivePeerMessage: (zim: ZIM, data: ZIMEventOfReceiveConversationMessageResult) => void;
// New callback
peerMessageReceived: (zim: ZIM, data: ZIMEventOfConversationMessageReceivedResult) => void;
// Old callback
receivePeerMessage: (zim: ZIM, data: ZIMEventOfReceiveConversationMessageResult) => void;
Callback on receiving room messages
The deprecated callback onReceiveRoomMessage for receiving room messages has been replaced by onRoomMessageReceived.
The deprecated callback receiveRoomMessage for receiving room messages has been replaced by roomMessageReceived.
The new callback supports the following features:
When a user is online, they can receive online room messages through this callback.
When a user goes from offline to online and is still in the room, they can receive all room messages that were sent during their offline period through this callback.
// New callback
public void onRoomMessageReceived(ZIM zim, ArrayList<ZIMMessage> messageList,
ZIMMessageReceivedInfo info, String fromRoomID) {}
// Old callback
public void onReceiveRoomMessage(ZIM zim, ArrayList<ZIMMessage> messageList,
String fromRoomID) {}
// New callback
public void onRoomMessageReceived(ZIM zim, ArrayList<ZIMMessage> messageList,
ZIMMessageReceivedInfo info, String fromRoomID) {}
// Old callback
public void onReceiveRoomMessage(ZIM zim, ArrayList<ZIMMessage> messageList,
String fromRoomID) {}
// New callback
roomMessageReceived: (zim: ZIM, data: ZIMEventOfConversationMessageReceivedResult) => void;
// Old callback
receiveRoomMessage: (zim: ZIM, data: ZIMEventOfReceiveConversationMessageResult) => void;
// New callback
roomMessageReceived: (zim: ZIM, data: ZIMEventOfConversationMessageReceivedResult) => void;
// Old callback
receiveRoomMessage: (zim: ZIM, data: ZIMEventOfReceiveConversationMessageResult) => void;
Callback on receiving group messages
The deprecated callback onReceiveGroupMessage for receiving group messages has been replaced by onGroupMessageReceived.
The deprecated callback receiveGroupMessage for receiving group messages has been replaced by groupMessageReceived.
The new callback supports the following features:
When the user is online, they can receive online group messages through this callback.
When the user logs back into the ZIM SDK, they can receive all group chat messages received during the offline period (up to 7 days) through this callback.
// New callback
public void onGroupMessageReceived(ZIM zim, ArrayList<ZIMMessage> messageList,
ZIMMessageReceivedInfo info, String fromGroupID) {}
// Old callback
public void onReceiveGroupMessage(ZIM zim, ArrayList<ZIMMessage> messageList,
String fromGroupID) {}
// New callback
public void onGroupMessageReceived(ZIM zim, ArrayList<ZIMMessage> messageList,
ZIMMessageReceivedInfo info, String fromGroupID) {}
// Old callback
public void onReceiveGroupMessage(ZIM zim, ArrayList<ZIMMessage> messageList,
String fromGroupID) {}
// New callback
groupMessageReceived: (zim: ZIM, data: ZIMEventOfConversationMessageReceivedResult) => void;
// Old callback
receiveGroupMessage: (zim: ZIM, data: ZIMEventOfReceiveConversationMessageResult) => void;
// New callback
groupMessageReceived: (zim: ZIM, data: ZIMEventOfConversationMessageReceivedResult) => void;
// Old callback
receiveGroupMessage: (zim: ZIM, data: ZIMEventOfReceiveConversationMessageResult) => void;
2.16.0 Upgrade Guide
Warning
Starting from version 2.16.0, there are significant changes to the following interfaces. Therefore, when upgrading from an older version to version 2.16.0, please read the following guide.
callCancel
Note
The following changes only apply to advanced mode call invitations.
In the new version of callCancel, if the parameter userIDs contains a userID, this interface will only cancel the invitation for that callee. If the userIDs parameter is empty, this interface will cancel the invitation for all callees.
For the old version of the callCancel interface, regardless of whether the userIDs parameter is empty or not, it is considered as canceling the invitation for all callees.
Since the old version of the ZIM SDK is not compatible with separate cancellation logic, if you need to retain the cancellation logic implemented using the old version of ZIM and also need to use the separate cancellation feature of the new version, please isolate the call functionality between the old and new versions of ZIM.
Usage in 2.16.0 version
// Cancel userIdA and userIdB separately
List<String> invitees = new ArrayList<>();
invitees.add("userIdA");
invitees.add("userIdB");
ZIMCallCancelConfig cancelConfig = new ZIMCallCancelConfig();
ZIM.getInstance().callCancel(invitees, "callID", cancelConfig, new ZIMCallCancelSentCallback() {
@Override
public void onCallCancelSent(String callID, ArrayList<String> errorInvitees, ZIMError errorInfo) {
}
});;
// Cancel the entire call invitation, can be called successfully when none of the callees in the entire call have accepted
List<String> invitees = new ArrayList<>();
ZIMCallCancelConfig cancelConfig = new ZIMCallCancelConfig();
ZIM.getInstance().callCancel(invitees, "callID", cancelConfig, new ZIMCallCancelSentCallback() {
@Override
public void onCallCancelSent(String callID, ArrayList<String> errorInvitees, ZIMError errorInfo) {
}
});
// Cancel userIdA and userIdB separately
List<String> invitees = new ArrayList<>();
invitees.add("userIdA");
invitees.add("userIdB");
ZIMCallCancelConfig cancelConfig = new ZIMCallCancelConfig();
ZIM.getInstance().callCancel(invitees, "callID", cancelConfig, new ZIMCallCancelSentCallback() {
@Override
public void onCallCancelSent(String callID, ArrayList<String> errorInvitees, ZIMError errorInfo) {
}
});;
// Cancel the entire call invitation, can be called successfully when none of the callees in the entire call have accepted
List<String> invitees = new ArrayList<>();
ZIMCallCancelConfig cancelConfig = new ZIMCallCancelConfig();
ZIM.getInstance().callCancel(invitees, "callID", cancelConfig, new ZIMCallCancelSentCallback() {
@Override
public void onCallCancelSent(String callID, ArrayList<String> errorInvitees, ZIMError errorInfo) {
}
});
Usage in version 2.16.0
// Cancel userIdA and userIdB separately
std::vector<std::string> invitees;
invitees.emplace_back("userIdA");
invitees.emplace_back("userIdB");
ZIMCallCancelConfig config;
zim->callCancel(invitees, "callID", config, [=](const std::string& callID, const std::vector<std::string>& errorInvitees,
const ZIMError& errorInfo) {
});
// Cancel the entire call invitation, can be called successfully when none of the callees in the call have accepted
std::vector<std::string> invitees;
ZIMCallCancelConfig config;
zim->callCancel(invitees, "callID", config, [=](const std::string& callID, const std::vector<std::string>& errorInvitees,
const ZIMError& errorInfo) {
});
// Cancel userIdA and userIdB separately
std::vector<std::string> invitees;
invitees.emplace_back("userIdA");
invitees.emplace_back("userIdB");
ZIMCallCancelConfig config;
zim->callCancel(invitees, "callID", config, [=](const std::string& callID, const std::vector<std::string>& errorInvitees,
const ZIMError& errorInfo) {
});
// Cancel the entire call invitation, can be called successfully when none of the callees in the call have accepted
std::vector<std::string> invitees;
ZIMCallCancelConfig config;
zim->callCancel(invitees, "callID", config, [=](const std::string& callID, const std::vector<std::string>& errorInvitees,
const ZIMError& errorInfo) {
});
Usage in version 2.16.0
// Cancel userIdA and userIdB separately
const callID = 'xxxx';
const invitees = ['userIdA','userIdB']; // List of invitees' IDs
const config: ZIMCallCancelConfig = { extendedData: 'xxxx' };
zim.callCancel(invitees, callID, config)
.then(res => {
// Operation successful
})
.catch(err => {
// Operation failed
})
// Cancel the entire call invitation, can be called successfully when none of the callees in the call have accepted
const callID = 'xxxx';
const invitees = []; // List of invitees' IDs
const config: ZIMCallCancelConfig = { extendedData: 'xxxx' };
zim.callCancel(invitees, callID, config)
.then(res => {
// Operation successful
})
.catch(err => {
// Operation failed
})
// Cancel userIdA and userIdB separately
const callID = 'xxxx';
const invitees = ['userIdA','userIdB']; // List of invitees' IDs
const config: ZIMCallCancelConfig = { extendedData: 'xxxx' };
zim.callCancel(invitees, callID, config)
.then(res => {
// Operation successful
})
.catch(err => {
// Operation failed
})
// Cancel the entire call invitation, can be called successfully when none of the callees in the call have accepted
const callID = 'xxxx';
const invitees = []; // List of invitees' IDs
const config: ZIMCallCancelConfig = { extendedData: 'xxxx' };
zim.callCancel(invitees, callID, config)
.then(res => {
// Operation successful
})
.catch(err => {
// Operation failed
})
Usage in version 2.16.0
// Cancel userIdA and userIdB separately
var callID = 'xxxx';
var invitees = ['userIdA','userIdB']; // List of invitees' IDs
var config = { extendedData: 'xxxx' };
zim.callCancel(invitees, callID, config)
.then(res => {
// Operation successful
})
.catch(err => {
// Operation failed
})
// Cancel the entire call invitation, can be called successfully when none of the callees in the call have accepted
var callID = 'xxxx';
var invitees = []; // List of invitees' IDs
var config = { extendedData: 'xxxx' };
zim.callCancel(invitees, callID, config)
.then(res => {
// Operation successful
})
.catch(err => {
// Operation failed
})
// Cancel userIdA and userIdB separately
var callID = 'xxxx';
var invitees = ['userIdA','userIdB']; // List of invitees' IDs
var config = { extendedData: 'xxxx' };
zim.callCancel(invitees, callID, config)
.then(res => {
// Operation successful
})
.catch(err => {
// Operation failed
})
// Cancel the entire call invitation, can be called successfully when none of the callees in the call have accepted
var callID = 'xxxx';
var invitees = []; // List of invitees' IDs
var config = { extendedData: 'xxxx' };
zim.callCancel(invitees, callID, config)
.then(res => {
// Operation successful
})
.catch(err => {
// Operation failed
})