Remote control

The remote control feature allows someone to take control of another user's screen in a session when given permission. A user can either request remote control of another user's screen or the other user can give it to them. Once given permission, a user can control the other user's mouse and keyboard, and even copy text from their screen.

Note: Since this enables remote control of a user's screen, it is your responsibility as the developer to inform the user of the permission they're giving to the person who can remote control their screen. This includes all notices, consents, and a well-defined user experience.

Prerequisites

  • Set up screen sharing. You must configure screen sharing in order for remote control to work.
  • Turn on remote control on the web portal. Go to Account Settings, In Session (Basic), and toggle the Remote control option on. Optionally select the Allow remote controlling user to share clipboard option.
  • Before starting, check whether controllers can request (canRequestControl) and users can start remote control.

Remote Control Flow

  1. On the requester side, identify the remote user (ZMVideoSDKUser) to have remote control over, check for request access, and request for access.

    let user: ZMVideoSDKUser; // Get the user you want to remote control of
    let shareActionList = user.getShareActionList()
    // The shareActionList can contain 0 to multiple shares coming from the selected user
    if let shareActionList = shareActionList, shareActionList.count > 0 {
        // Get the share you want - Example the first share
        let shareAction = shareActionList[0]
        if shareAction.getRemoteControlHelper().canRequestControl() {
            shareAction.getRemoteControlHelper().requestRemoteControl()
        }
    }
    
    ZMVideoSDKUser* user; // Get the user you want to remote control of
    NSArray* shareActionList = [user getShareActionList];
    // The shareActionList can contain 0 to multiple share coming from the selected user
    if (shareActionList.count > 0) {
        // Get the share you want - Example the first share
        ZMVideoSDKShareAction* shareAction = [shareActionList objectAtIndex:0];
        if ([[shareAction getRemoteControlHelper] canRequestControl]) {
            [[shareAction getRemoteControlHelper] requestRemoteControl];
        }
    }
    
  2. The requester will then get the onRemoteControlRequestReceived callback within the ZMVideoSDKDelegate class. From this callback, the approver will get the user requesting for remote control access and also the ZMVideoSDKRemoteControlRequestHandler, which the SDK will use to either approve or deny the request. If the approver denied the request, the requester can request again.

    Note: For macOS, the approver must give their application access in the Accessibility tab in the Privacy and Security preferences of their Mac.

    func onRemoteControlRequestReceived(user: ZMVideoSDKUser, handler: ZMVideoSDKRemoteControlRequestHandler) {
        handler.approve() // OR
        handler.deny()
    }
    
    - (void)onRemoteControlRequestReceived:(ZMVideoSDKUser *)user shareAction:(ZMVideoSDKShareAction *)shareAction handler:(ZMVideoSDKRemoteControlRequestHandler *)handler
    {
        [handler approve]; // OR
        [handler deny];
    }
    
  3. Both the requestor and approver will receive an onRemoteControlStatus callback under the ZMVideoSDKDelegate class on the request status. With a CanRequestControl callback status on the requestor side, check if canRemoteControl is true and isRemoteControlling is false before starting remote control.

    let remoteControlHelper = shareAction.getRemoteControlHelper()
    if remoteControlHelper.canRemoteControl() && !remoteControlHelper.isRemoteControlling() {
        remoteControlHelper.enterRemoteControl()
    }
    
    ZMVideoSDKRemoteControlHelper* remoteControlHelper = [shareAction getRemoteControlHelper];
    if ([remoteControlHelper canRemoteControl] && ![remoteControlHelper isRemoteControlling]) {
        [remoteControlHelper enterRemoteControl];
    }
    
  4. After entering remote control status, the requestor can choose to temporarily pause remote control using leaveRemoteControl and enter again later on with enterRemoteControl, or to end it with endRemoteControl. Whereas the approver can also choose to get the list of approved users using getRemoteControlApprovedUserList or to revoke all the approved user using revokeRemoteControl.

    // Requestor
    remoteControlHelper.leaveRemoteControl()
    remoteControlHelper.endRemoteControl()
    // Approver - These methods are only available for the local user themselves.
    shareAction.getRemoteControlApprovedUserList()
    shareAction.revokeRemoteControl()
    
    // Requestor
    [remoteControlHelper leaveRemoteControl];
    [remoteControlHelper endRemoteControl];
    // Approver - These methods are only available for the local user themselves.
    [shareAction getRemoteControlApprovedUserList]
    [shareAction revokeRemoteControl];
    

Callbacks

There are 2 callbacks related to remote control access under the ZMVideoSDKDelegate class.

  1. onRemoteControlRequestReceived: Triggered when a remote user requests to remote control the local user.

    func onRemoteControlRequestReceived(user: ZMVideoSDKUser, shareAction: ZMVideoSDKShareAction, handler: ZMVideoSDKRemoteControlRequestHandler) {
        handler.approve() // OR
        handler.deny()
    }
    
    - (void)onRemoteControlRequestReceived:(ZMVideoSDKUser *)user handler:(ZMVideoSDKRemoteControlRequestHandler *)handler
    {
        [handler approve]; // OR
        [handler deny];
    }
    
  2. onRemoteControlStatus: Triggered when the remote control status changes. This applies to the local user either requesting remote control, controlling the remote user, or is being controlled by a remote user.

    ZMVideoSDKRemoteControlStatus Enum

    None // For initialization
    CanRequestControl // Local user can enable the remote control
    RequestDenied // Local user have received a refused of remote control
    GotControl // Local user got control when remote control begins
    LostControl // Local user lost control when remote control ends
    ControlStart // Local user start controlling remotely another user
    ControlStop // Local user stop controlling remotely another user
    GiveControlTo // Local user gave remote control access to an user
    ControlRevoked // Local user revoked remote control access to an user
    ControlledBy // Local user is being remotely controlled by an user
    NotControlled // Local user is not remotely controlled by an user
    
    func onRemoteControlStatus(status: ZMVideoSDKRemoteControlStatus, user: ZMVideoSDKUser, shareAction: ZMVideoSDKShareAction) {}
    
    - (void)onRemoteControlStatus:(ZMVideoSDKRemoteControlStatus)status user:(ZMVideoSDKUser *)user shareAction:(ZMVideoSDKShareAction *)shareAction