Integrate the Meeting SDK into your Unreal project

When integrating with your Unreal project, you can integrate with either C++ or with Blueprints.

Integrate with C++

Currently, the Zoom plugin wraps many of the Meeting SDK interfaces and callbacks. However, not all the interfaces have been wrapped, and not all of the functions within the wrapped interfaces have been implemented. Learn how to wrap a new interface and its corresponding callback and override unimplemented functions of an interface that is already wrapped.

Create a new interface wrapper

Wrap this new interface within the plugin defined in the Meeting SDK for Windows' meeting_inmeeting_encryption_interface.h file.

class IMeetingEncryptionController {
public:
  virtual ~IMeetingEncryptionController() {}
  virtual void SetEvent(IMeetingEncryptionControllerEvent *pEvent) = 0;
  virtual EncryptionType GetEncryptionType() = 0;
  virtual const zchar_t *GetE2EEMeetingSecurityCode() = 0;
  virtual unsigned int GetE2EEMeetingSecurityCodePassedSeconds() = 0;
  virtual bool IsUnencryptedExceptionDataValid() = 0;
  virtual unsigned int GetUnencryptedExceptionCount() = 0;
  virtual const zchar_t *GetUnencryptedExceptionInfo() = 0;
};
  1. To wrap the previous interface, open your Unreal Engine project and launch Visual Studio.

  2. Create a new class in Unreal Engine by selecting Tools > New C++ Class….

  3. In the Choose Parent Class screen of the Add C++ Class dialog, choose the Common Classes tab as your default parent class and select None.

  4. Name your class MeetingEncryptionController and set the plugin runtime.

  5. Finally, select Create class.

  6. Reload Visual Studio to add the new header and source files to the project.

    Note: The plugin's sources are in <UEProjectFolder>\Plugins\ZoomMeetingSDK\Source\ZoomMeetingSDK. Header files are in <UEProjectFolder>\Plugins\ZoomMeetingSDK\Source\ZoomMeetingSDK\Public. Source files are in <UEProjectFolder>\Plugins\ZoomMeetingSDK\Source\ZoomMeetingSDK\Private.

  7. Update the default header and source files. All the wrapped functions are in the ZOOM_SDK_NAMESPACE::UE namespace, defined in the header ZoomUESDKDef.h.

    • Add all the methods defined in the interface that may be overridden.
    • Add a Create method to create an instance of the wrapper class. This is optional and can be replaced with a different method if needed.
    • Add a pointer to the interface IMeetingEncryptionController which will point to the instance created by the Meeting SDK after the SDK is initialized. Use this to redirect calls to the default behavior.
  8. Update the header file MeetingEncryptionController.h.

    // Copyright : All rights reserved by Zoom Video Communications 2022-
    #pragma once
    #include "ZoomUESDKDef.h"
    #include "meeting_service_components/meeting_inmeeting_encryption_interface.h"
    BEGIN_ZOOM_SDK_UE_NAMESPACE
    /**
     * Wrapper around IMeetingEncryptionController.
     */
    class ZOOMMEETINGSDK_API MeetingEncryptionController {
    public:
      ~MeetingEncryptionController() = delete;
     MeetingEncryptionController(const MeetingEncryptionController &other) =
          delete;
      MeetingEncryptionController(MeetingEncryptionController &&other) noexcept =
          delete;
      MeetingEncryptionController &
      operator=(const MeetingEncryptionController &other) = delete;
      MeetingEncryptionController &
      operator=(MeetingEncryptionController &&other) noexcept = delete;
      // Static function to create an object of IMeetingEncryptionController.
      static MeetingEncryptionController *Create();
      // Methods to override from the default behavior.
      EncryptionType GetEncryptionType();
      const zchar_t *GetE2EEMeetingSecurityCode();
      unsigned int GetE2EEMeetingSecurityCodePassedSeconds();
      bool IsUnencryptedExceptionDataValid();
      unsigned int GetUnencryptedExceptionCount();
      const zchar_t *GetUnencryptedExceptionInfo();
    private:
      MeetingEncryptionController() = default;
      // Initializes MeetingEncryptionController.
      //
      // Returns true if initialization was successful.
      bool Init();
      // Pointer to the encryption controller.
      IMeetingEncryptionController *m_meeting_encryption_ctrl = nullptr;
    };
    END_ZOOM_SDK_UE_NAMESPACE
    
  9. Update the source file MeetingEncryptionController.cpp.

    // Copyright : All rights reserved by Zoom Video Communications 2022-
    #include "MeetingEncryptionController.h"
    #include "SDKInterfaceWrap.h"
    BEGIN_ZOOM_SDK_UE_NAMESPACE
    MeetingEncryptionController *MeetingEncryptionController::Create() {
      TUniquePtr<MeetingEncryptionController> mec(
          new MeetingEncryptionController());
      if (mec->Init()) {
        return mec.Release();
      }
      return nullptr;
    }
    bool MeetingEncryptionController::Init() {
      m_meeting_encryption_ctrl =
          SDKInterfaceWrap::GetInst().GetMeetingEncryptionController();
      return (m_meeting_encryption_ctrl) ? true : false;
    }
    // Override the required methods.
    EncryptionType MeetingEncryptionController::GetEncryptionType() {
      EncryptionType type(EncryptionType::EncryptionType_None);
      // Add your code that overrides the default behavior.
      return type;
    }
    const zchar_t *MeetingEncryptionController::GetE2EEMeetingSecurityCode() {
      // Add your code that overrides the default behavior.
      return nullptr;
    }
    unsigned int
    MeetingEncryptionController::GetE2EEMeetingSecurityCodePassedSeconds() {
      // Add your code that overrides the default behavior.
      return 0;
    }
    // Methods with default behavior.
    bool MeetingEncryptionController::IsUnencryptedExceptionDataValid() {
      return m_meeting_encryption_ctrl->IsUnencryptedExceptionDataValid();
    }
    unsigned int MeetingEncryptionController::GetUnencryptedExceptionCount() {
      return m_meeting_encryption_ctrl->GetUnencryptedExceptionCount();
    }
    const zchar_t *MeetingEncryptionController::GetUnencryptedExceptionInfo() {
      return m_meeting_encryption_ctrl->GetUnencryptedExceptionInfo();
    }
    END_ZOOM_SDK_UE_NAMESPACE
    
  10. Get the Meeting SDK's instance of IMeetingEncryptionController, and then add the function declaration GetMeetingEncryptionController() in SDKInterfaceWrap.h and add the implementation in SDKInterfaceWrap.cpp.

    ```cpp
    #include "MeetingEncryptionController.h"
    BEGIN_ZOOM_SDK_UE_NAMESPACE
    class ZOOMMEETINGSDK_API SDKInterfaceWrap {
    public:
     ...
     // Returns a pointer to the IMeetingEncryptionController.
      //
      // Note: SDK needs to be initialized before calling this function.
      ZOOM_SDK_NAMESPACE::IMeetingEncryptionController *
      GetMeetingEncryptionController();
     ...
    };
    END_ZOOM_SDK_UE_NAMESPACE
    ```
    

When creating an instance of the interface, set the callback object if needed. The next code sample has more information about creating the callback in SDKInterfaceWrap.cpp.

#include "MeetingEncryptionControllerEvent.h"
BEGIN_ZOOM_SDK_UE_NAMESPACE
...
IMeetingEncryptionController *
SDKInterfaceWrap::GetMeetingEncryptionController() {
  if (!isInitialized()) {
    return nullptr;
  }
  IMeetingEncryptionController *mec =
      GetMeetingService()->GetInMeetingEncryptionController();
  if (mec) {
    // Set the callback event if need be.
    mec->SetEvent(MeetingEncryptionControllerEvent::Create());
  }
  return mec;
}
...
END_ZOOM_SDK_UE_NAMESPACE

Create the callback

To create the callback IMeetingEncryptionControllerEvent, create a new class in Unreal Engine MeetingEncryptionControllerEvent.h or 'MeetingEncryptionControllerEvent.cpp' like we did for the interface. Then update the default header and source.

Note:

  • For callbacks, inherit the callback interface and have an implementation for all the virtual methods defined within that callback interface.
  • The callback functions can either trigger a Blueprint callback event as shown in the next example, or can be left empty so it is ignored.

Trigger a Blueprint callback event in the MeetingEncryptionControllerEvent.h file.

// Copyright : All rights reserved by Zoom Video Communications 2022-
#pragma once
#include "ZoomUESDKDef.h"
#include "meeting_service_components/meeting_inmeeting_encryption_interface.h"
BEGIN_ZOOM_SDK_UE_NAMESPACE
/**
 * Wrapper that inherits IMeetingEncryptionControllerEvent.
 */
class ZOOMMEETINGSDK_API MeetingEncryptionControllerEvent
    : public IMeetingEncryptionControllerEvent {
public:
  ~MeetingEncryptionControllerEvent() = default;
  MeetingEncryptionControllerEvent(
      const MeetingEncryptionControllerEvent &other) = delete;
  MeetingEncryptionControllerEvent(
      MeetingEncryptionControllerEvent &&other) noexcept = delete;
  MeetingEncryptionControllerEvent &
  operator=(const MeetingEncryptionControllerEvent &other) = delete;
  MeetingEncryptionControllerEvent &
  operator=(MeetingEncryptionControllerEvent &&other) noexcept = delete;
  // Static function to create an object of IMeetingEncryptionControllerEvent.
  static IMeetingEncryptionControllerEvent *Create();
  // Functions to override.
  void onE2EEMeetingSecurityCodeChanged() override;
private:
  MeetingEncryptionControllerEvent() = default;
};
END_ZOOM_SDK_UE_NAMESPACE

Implement the callback in the MeetingEncryptionControllerEvent.cpp file.

// Copyright : All rights reserved by Zoom Video Communications 2022-
#include "MeetingEncryptionControllerEvent.h"
#include "ZoomMeetingSDKEventHandler.h"
BEGIN_ZOOM_SDK_UE_NAMESPACE
IMeetingEncryptionControllerEvent *MeetingEncryptionControllerEvent::Create() {
  // Create a static MeetingEncryptionControllerEvent.
  // We would ideally only need to create a single callback object.
  // If need be, remove the singleton and use new to create a new object.
  static MeetingEncryptionControllerEvent s_mrce;
  return &s_mrce;
}
void MeetingEncryptionControllerEvent::onE2EEMeetingSecurityCodeChanged() {
}
END_ZOOM_SDK_UE_NAMESPACE

Integrate with Blueprints

Integrate with Blueprints in a graphical user interface, or extend Blueprints' functionality using code.

Use Blueprints

A significant amount of Zoom functionality is exposed to the Blueprint layer for implementing behavior in Unreal's node-based editor.

Participants are identified to many of the Blueprint functions using a unique integer ID code. Using the Blueprint function GetUserByID lets you get a Blueprint struct FUEUserInfo containing helpful information like the participant's name by using the ID. Use GetParticipantsList to get a list of FUEUserInfo structs representing everyone in the Zoom call.

Not all Blueprints are direct wrappers of Meeting SDK functions. Some special nodes, such as SDK Init and Auth, are helper functions that combine multiple SDK components with additional logic to simplify the Blueprint building experience. In addition, the return type of many Blueprints in this toolkit is a boolean, while the C++ functions return an SDKError object. Working with booleans by folding down all of the errors makes it easier to do logic control at the Blueprint level. The underlying SDKError is printed to the logs. Finally there are some functions that use a different input type where the Blueprint implementation performs additional functions beyond a direct Meeting SDK call. In the case where a Blueprint function in the Zoom Meeting SDK for Unreal Engine is not a direct wrapper of an underlying Meeting SDK function, additional documentation is available describing the changes. See the SDK Reference section for more details.

Extend Blueprints

Use Blueprints to add your own functionality. This section shows two examples: creating a Blueprint C++ function, and creating a callback.

Create a Blueprint C++ function

Blueprint functions provide a way for Blueprint nodes from the Unreal Editor to interact with the Meeting SDK. Let's implement the Blueprint functions to interact with MeetingEncryptionController. The header file ZoomMeetingSDKBPLibrary.h has all the definitions for the Blueprint functions and the source file ZoomMeetingSDKBPLibrary.cpp has the implementation.

To implement the function to get the meeting encryption type GetEncryptionType, add a new UFUNCTION within the header file. The return type of the function is an enum defined within meeting_inmeeting_encryption_interface.h. Since we can't return this enum as is, define a BlueprintType enum that can be used by the Blueprint nodes. They are currently defined in the header file ZoomMeetingSDKBPDefine.h, but you can also create your own header to define them. Create a new enum of BlueprintType.

// Enum to Meeting Service Encryption Interface Valid for both ZOOM style and
// user custom interface mode.
UENUM(BlueprintType)
enum class MeetingEncryptionType : uint8 {
  MeetingEncryptionType_None UMETA(DisplayName = "None"),
  MeetingEncryptionType_Enhanced UMETA(DisplayName = "Enhanced"),
  MeetingEncryptionType_E2EE UMETA(DisplayName = "E2EE"),
};

Define the Blueprint function in the ZoomMeetingSDKBPLibrary.h file.

// Get meeting encryption type.
//
// Return encryption type.
UFUNCTION(
    BlueprintCallable,
    meta = (DisplayName = "GetEncryptionType",
            Keywords = "Get Encryption type"),
    Category = "Zoom Meeting SDK Plug-in | Utils | IMeetingEncryptionController")
  static MeetingEncryptionType GetEncryptionType();

Implement the function in the ZoomMeetingSDKBPLibrary.cpp file.

MeetingEncryptionType UZoomMeetingSDKBPLibrary::GetEncryptionType() {
  MeetingEncryptionType encyption_type(
      MeetingEncryptionType::MeetingEncryptionType_None);
  UE_LOG(BPZoomMeetingSDKLog, Display,
         TEXT("UZoomMeetingSDKBPLibrary::GetEncryptionType triggered"));
  TUniquePtr<MeetingEncryptionController> mec(
      MeetingEncryptionController::Create());
  if (!mec.Get()) {
    UE_LOG(BPZoomMeetingSDKLog, Display,
           TEXT("UZoomMeetingSDKBPLibrary::GetEncryptionType SDK not initialized."));
    return encyption_type;
  }
  // Convert the encryption type to a returnable value.
  switch (mec->GetEncryptionType()) {
  case ZOOM_SDK_NAMESPACE::EncryptionType::EncryptionType_None:
    encyption_type = MeetingEncryptionType::MeetingEncryptionType_None;
    break;
  case ZOOM_SDK_NAMESPACE::EncryptionType::EncryptionType_Enhanced:
    encyption_type = MeetingEncryptionType::MeetingEncryptionType_Enhanced;
    break;
  case ZOOM_SDK_NAMESPACE::EncryptionType::EncryptionType_E2EE:
    encyption_type = MeetingEncryptionType::MeetingEncryptionType_E2EE;
    break;
  }
  return encyption_type;
}

Create a callback function to Blueprint

All the callback functions' definitions and implementations are in the ZoomMeetingSDKEventHandler.h and ZoomMeetingSDKEventHandler.cpp files.

The IMeetingEncryptionControllerEvent has a callback function onE2EEMeetingSecurityCodeChanged. To receive this callback, update the ZoomMeetingSDKEventHandler.h file.

...
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnE2EEMeetingSecurityCodeChanged);
...
UPROPERTY(
    BlueprintAssignable,
    meta = (DisplayName = "OnE2EEMeetingSecurityCodeChanged",
            Keywords = "IMeetingEncryptionControllerEvent.OnE2EEMeetingSecurityCodeChanged"),
      Category = Zoom Meeting SDK Plug-in | Events | IMeetingEncryptionControllerEvent")
  FOnE2EEMeetingSecurityCodeChanged OnE2EEMeetingSecurityCodeChanged;
...
  // IMeetingEncryptionControllerEvent
  void onE2EEMeetingSecurityCodeChanged();

Add the implementation for the function in the ZoomMeetingSDKEventHandler.cpp file.

void UZoomMeetingSDKEventHandler::onE2EEMeetingSecurityCodeChanged() {
  UE_LOG(BPZoomMeetingSDKLog, Display,
         TEXT("ZoomMeetingSDKEventHandler::onE2EEMeetingSecurityCodeChanged triggered"));
  OnE2EEMeetingSecurityCodeChanged.Broadcast();
}

Now update the MeetingEncryptionControllerEvent.cpp file to call Blueprint event handler when the callback is triggered.

// Copyright : All rights reserved by Zoom Video Communications 2022-
#include "MeetingEncryptionControllerEvent.h"
#include "ZoomMeetingSDKEventHandler.h"
BEGIN_ZOOM_SDK_UE_NAMESPACE
IMeetingEncryptionControllerEvent *MeetingEncryptionControllerEvent::Create() {
  // Create a static MeetingEncryptionControllerEvent.
  // We would ideally only need to create a single callback object.
  // If needed, remove the singleton and use new to create a new object.
  static MeetingEncryptionControllerEvent s_mrce;
  return &s_mrce;
}
void MeetingEncryptionControllerEvent::onE2EEMeetingSecurityCodeChanged() {
  GetZMEventHandler()->onE2EEMeetingSecurityCodeChanged();
}
END_ZOOM_SDK_UE_NAMESPACE

To see the Blueprint functions and callbacks, do a clean compile. Delete the binaries and intermediate folders from .../Plugins/ZoomMeetingSDK/Binaries and .../Plugins/ZoomMeetingSDK/Intermediate and restart Unreal Engine if needed.

Open the Unreal Engine Blueprint editor to use the added Blueprint functions.

Integrate video

This section shows two examples of video integration with MSDK and Unreal: sending the video to the render targets, and sending the render targets to Zoom as cameras.

Send Zoom video to render targets

There's a special function in the Meeting SDK for Unreal called SubscribeVideo that lets you output a participant video feed to an Unreal Engine Render Target using the participant ID. To use this function, the Unreal Engine's Zoom meeting participant must have obtained recording or live streaming permission, or be in a role in Zoom that contains those privileges such as host or co-host. Helper functions for obtaining permissions and detecting role changes are available in the wrapper. The SubscribeVideo function also accepts a parameter that can specify the use of the participant video feed or the shared content feed.

See Use raw data in the Meeting SDK for more information.

Send the render target to the meeting as a camera

Use Render Targets to bring content from Unreal Engine back to Zoom as the camera source of the participant created by the Meeting SDK. The EnableVideoSource function takes a render target parameter and translates it to the camera feed in the Zoom client. The render target must have a minimum resolution of 360p and must have Render Target Format set to RTF RGBA8 SRGB.