Manage in-meeting annotation

The code on this page works with either the default UI or the custom UI.

When users start sharing their screens, others can annotate on top of the shared video feed. Through the SDK, you can manage many settings related to the appearance and availability of annotation.

Annotation settings

Before starting to annotate, check the meeting settings in the web portal to confirm that it is currently enabled. Check synchronously through the annotation controller, or receive updates asynchronously through the ZoomSDKASControllerDelegate.

If you are using custom UI, you will also need to conform to the ZoomSDKCustomizedAnnotationDelegate and ZoomSDKCustomizedAnnotationCtrlDelegate to receive callbacks of its annotation events.

var customizedAnnotation: ZoomSDKCustomizedAnnotation? = nil
var shareElement: ZoomSDKShareElement? = nil // shareElement is needed to annotate on the remote user's screen share. Or to annotation on your own share, keep this nil.
// In your ViewController, you need to add the ZoomSDKASControllerDelegate to receive share-related callbacks and also ZoomSDKCustomizedAnnotationCtrlDelegate to receive its annotation callback
if let annotationShareController = ZoomSDK.shared().getMeetingService()?.getASController(), let customizedAnnotationCtr = annotationShareController.getCustomizedAnnotationCtr() {
    annotationShareController.delegate = self
    customizedAnnotationCtr.delegate = self
   /*
    To annotate on the local user's screen sharing:
    1. customizedAnnotation must be nil
    2. shareElement must be nil OR create a shareElement with sharingID = 0
   */
    if customizedAnnotationCtr.createCustomizedAnnotation(&customizedAnnotation, shareElement: &shareElement) == ZoomSDKError_Success, let customizedAnnotation = customizedAnnotation {
        customizedAnnotation.delegate = self
    }
    /*
     OR
     To annotate on a remote user's screen share, you must have first already created the ZoomSDKShareElement that you are subscribing to. The steps are similar to how screen sharing works:
     1. Identify the remote user's screen share through its shareSourceID. This can be obtained in the onSharingStatusChanged(_ shareInfo: ZoomSDKSharingSourceInfo)'s callback and using the shareInfo.shareSourceID
     2. Create a ZoomSDKShareElement based on the subscribed screen CGRect size, sharingID = shareSourceID, viewMode and etc. Then, add the ZoomSDKShareElement shareView to your own view.
     4. Continue with the steps below for annotation
     */
    if let shareElement = shareElement {
        if customizedAnnotationCtr.createCustomizedAnnotation(&customizedAnnotation, shareElement: shareElement) == ZoomSDKError_Success, let customizedAnnotation = customizedAnnotation {
            customizedAnnotation.delegate = self
        }
    }
}
// Conform your ViewController to the ZoomSDKCustomizedAnnotationCtrlDelegate and ZoomSDKCustomizedAnnotationDelegate protocol. Conform to the ZoomSDKASControllerDelegate if you also want to receive share-related callbacks.
extension ViewController: ZoomSDKCustomizedAnnotationCtrlDelegate, ZoomSDKCustomizedAnnotationDelegate {
    func onAnnotationSupportPropertyChanged(forCustom isSupportAnnotation: Bool, shareSourceID: UInt32) {
        if isSupportAnnotation {
            // Annotations are enabled
        }
        // currentShareID = shareSourceID
    }
    func onAnnotationCleanUp(_ annotation: ZoomSDKCustomizedAnnotation) {
    }
    func onAnnotationStatusChanged(_ element: ZoomSDKShareElement?, status: AnnotationStatus) {
    }
    func onAnnotationToolChanged(_ tool: AnnotationToolType) {
    }
}
// To determine if annotations can be performed manually
if let customizedAnnotationCtr = ZoomSDK.shared().getMeetingService()?.getASController().getCustomizedAnnotationCtr() {
    var canDoAnno = ObjCBool(true)
    if let customizedAnnotation = customizedAnnotation, customizedAnnotationCtr.canDo(customizedAnnotation, canAnnotate: &canDoAnno) == ZoomSDKError_Success, canDoAnno.boolValue {
        // Annotations can be performed
    }
}
// In your ViewController.h, you need to conform it to the ZoomSDKASControllerDelegate protocol
@interface ViewController : NSWindowController <ZoomSDKASControllerDelegate, ZoomSDKCustomizedAnnotationDelegate, ZoomSDKCustomizedAnnotationCtrlDelegate> {
}
// In your ViewController.m, you need to add the relevant delegates callbacks first to receive the callback later
ZoomSDKCustomizedAnnotation *customizedAnnotation = nil;
ZoomSDKShareElement  = nil; // shareElement is needed to annotate on remote user's screen share. Or to annotation on your own share, keep this nil.
ZoomSDKASController *annotationShareController =
    [[[ZoomSDK sharedSDK] getMeetingService] getASController];
if (annotationShareController) {
    ZoomSDKCustomizedAnnotationCtr *customizedAnnotationCtr =
        [annotationShareController getCustomizedAnnotationCtr];
    if (customizedAnnotationCtr) {
        annotationShareController.delegate = self;
        customizedAnnotationCtr.delegate = self;
        // To annotate on the local user's screen sharing - customizedAnnotation and shareElement must be nil
        ZoomSDKError error =
            [customizedAnnotationCtr createCustomizedAnnotation:&customizedAnnotation
                                                   ShareElement:shareElement];
        if (error == ZoomSDKError_Success && customizedAnnotation) {
            customizedAnnotation.delegate = self;
        }
        /*
         OR
         To annotate on a remote user's screen share, you must have first already created the ZoomSDKShareElement that you are subscribing to. The steps are similar to how screen sharing works:
         1. Identify the remote user's screen share through its shareSourceID. This can be obtained in the onSharingStatusChanged(_ shareInfo: ZoomSDKSharingSourceInfo)'s callback and using the shareInfo.shareSourceID
         2. Create a ZoomSDKShareElement based on the subscribed screen CGRect size, sharingID = shareSourceID, viewMode and etc. Then, add the ZoomSDKShareElement shareView to your own view.
         4. Continue with the steps below for annotation
         */
        if (shareElement != nil) {
            ZoomSDKError error =
                [customizedAnnotationCtr createCustomizedAnnotation:&customizedAnnotation
                                                       ShareElement:shareElement];
            if (error == ZoomSDKError_Success && customizedAnnotation) {
                customizedAnnotation.delegate = self;
            }
        }
    }
}
- (void)onAnnotationSupportPropertyChangedForCustom:(BOOL)isSupportAnnotation shareSourceID:(unsigned int)shareSourceID {
    if (isSupportAnnotation) {
        // Annotations are enabled
    }
    // currentShareID = shareSourceID;
}
- (void)onAnnotationCleanUp:(ZoomSDKCustomizedAnnotation *)annotation {
}
- (void)onAnnotationStatusChanged:(ZoomSDKShareElement *)element Status:(AnnotationStatus)status {
}
- (void)onAnnotationToolChanged:(AnnotationToolType)tool {
}
// To determine if annotations can be performed manually
ZoomSDKCustomizedAnnotationCtr *customizedAnnotationCtr =
    [[[[ZoomSDK sharedSDK] getMeetingService] getASController] getCustomizedAnnotationCtr];
if (customizedAnnotationCtr) {
    BOOL canDoAnno = NO;
    if (customizedAnnotation && [customizedAnnotationCtr canDoAnnotation:customizedAnnotation canAnnotate:&canDoAnno] == ZoomSDKError_Success && canDoAnno) {
        // Annotations can be performed
    }
}

If the current user is sharing their screen, they can enable or disable viewers to annotate the shared screen.

if let customizedAnnotation = customizedAnnotation {
    var canDisableAnnotation = ObjCBool(false)
    if customizedAnnotationCtr.canDisableViewerAnnotation(customizedAnnotation, canDisabled: &canDisableAnnotation) == ZoomSDKError_Success && canDisableAnnotation.boolValue {
        var isAnnotationLocked = ObjCBool(true)
        if customizedAnnotationCtr.isViewerAnnotationLocked(customizedAnnotation, isLocked: &isAnnotationLocked) == ZoomSDKError_Success && isAnnotationLocked.boolValue {
            // Depending on the isAnnotationLocked's Bool value, then disable/enable viewer annotation
            customizedAnnotationCtr.disableViewerAnnotation(customizedAnnotation, disable: false) // Or true
        }
    }
}
if (customizedAnnotation) {
    BOOL canDisableAnnotation = NO;
    if ([customizedAnnotationCtr canDisableViewerAnnotation:customizedAnnotation canDisabled:&canDisableAnnotation] == ZoomSDKError_Success && canDisableAnnotation) {
        BOOL isAnnotationLocked;
        if ([customizedAnnotationCtr isViewerAnnotationLocked:customizedAnnotation isLocked:&isAnnotationLocked] == ZoomSDKError_Success && isAnnotationLocked) {
            // Depending on the isAnnotationLocked's Bool value, then disable/enable viewer annotation
            [customizedAnnotationCtr disableViewerAnnotation:customizedAnnotation disable:NO]; // Or YES
        }
    }
}

Control annotation properties

In custom UI mode, you need to create your own annotation toolbar that best suits your use case.

To start annotating, call startAnnotation. When annotation is finished, use stopAnnotation.

if annotationShareController.startAnnotation(ScreenType_First) == ZoomSDKError_Success {
    // You can begin using the annotation tool
}
annotationShareController.stopAnnotation(ScreenType_First)
if ([annotationShareController startAnnotation:ScreenType_First] == ZoomSDKError_Success) {
    // You can begin using the annotation tool
}
[annotationShareController stopAnnotation:ScreenType_First];

Optionally, after verifying that annotation started based on the return value of startAnnotation, modify the annotation appearance programmatically.

customizedAnnotation.setColor(Color(red: 1, green: 1, blue: 1)) // color: Color (0-255)
customizedAnnotation.setTool(AnnotationToolType_Pen) // toolType: AnnotationToolType
customizedAnnotation.setLineWidth(1) // lineWidth: Int
Color color;
color.red = 1; // 0-255
color.green = 1;
color.blue = 1;
[customizedAnnotation setColor:color];
[customizedAnnotation setTool:AnnotationToolType_Pen];
[customizedAnnotation setLineWidth:1];

Interact with annotations that users create by undoing, redoing or clearing annotations.

customizedAnnotation.undo()
customizedAnnotation.redo()
customizedAnnotation.clear(AnnotationClearType_All) // AnnotationClearType: All, self, others.
[customizedAnnotation undo];
[customizedAnnotation redo];
[customizedAnnotation clear:AnnotationClearType_All];

In custom UI mode, when the meeting no longer needs annotation, remove the listener. This is not required for the default UI mode.

// Only for custom UI mode
customizedAnnotationCtr.delegate = nil
// Only for custom UI mode
customizedAnnotationCtr.delegate = nil;