Skill 126 · Zoom Meeting SDK Windows
Subchapter 126.6
concepts/sdk-architecture-pattern.mdMarkdown20 KBView on GitHub
The Zoom Windows Meeting SDK follows a consistent architectural pattern that applies to EVERY feature. Once you understand this pattern, you can implement ANY feature just by reading the .h header files.
Every SDK feature follows this 3-step pattern:
// Pattern: meetingService->Get[Feature]Controller()
IMeetingAudioController* audioCtrl = meetingService->GetMeetingAudioController();
IMeetingChatController* chatCtrl = meetingService->GetMeetingChatController();
IMeetingVideoController* videoCtrl = meetingService->GetMeetingVideoController();// Pattern: I[Feature]Event or I[Feature]CtrlEvent
class MyAudioListener : public IMeetingAudioCtrlEvent {
void onUserAudioStatusChange(IList<IUserAudioStatus*>* lstAudioStatusChange) override {
// React to audio events
}
// ... implement all pure virtual methods
};// Pattern: controller->SetEvent(listener), then call methods
audioCtrl->SetEvent(new MyAudioListener());
audioCtrl->MuteAudio(userId, true); // Use featureTop-level services (created via global functions):
// Authentication Service (JWT, user login)
IAuthService* authService;
CreateAuthService(&authService);
// Meeting Service (join, leave, access features)
IMeetingService* meetingService;
CreateMeetingService(&meetingService);All controllers are accessed through IMeetingService->Get[Feature]Controller():
// Audio features
IMeetingAudioController* audioCtrl = meetingService->GetMeetingAudioController();
// Video features
IMeetingVideoController* videoCtrl = meetingService->GetMeetingVideoController();
// Chat features
IMeetingChatController* chatCtrl = meetingService->GetMeetingChatController();
// Participants management
IMeetingParticipantsController* participantsCtrl = meetingService->GetMeetingParticipantsController();
// Recording features
IMeetingRecordingController* recordingCtrl = meetingService->GetMeetingRecordingController();
// Screen sharing
IMeetingShareController* shareCtrl = meetingService->GetMeetingShareController();
// Waiting room
IMeetingWaitingRoomController* waitingRoomCtrl = meetingService->GetMeetingWaitingRoomController();
// Webinar features
IMeetingWebinarController* webinarCtrl = meetingService->GetMeetingWebinarController();
// Breakout rooms
IMeetingBOController* boCtrl = meetingService->GetMeetingBOController();
// AI Companion
IMeetingAICompanionController* aiCtrl = meetingService->GetMeetingAICompanionController();
// Q&A
IMeetingQAController* qaCtrl = meetingService->GetMeetingQAController();
// Polling
IMeetingPollingController* pollingCtrl = meetingService->GetMeetingPollingController();
// Whiteboard
IMeetingWhiteboardController* whiteboardCtrl = meetingService->GetMeetingWhiteboardController();
// Closed captions
IClosedCaptionController* captionCtrl = meetingService->GetMeetingClosedCaptionController();
// Live streaming
IMeetingLiveStreamController* liveStreamCtrl = meetingService->GetMeetingLiveStreamController();
// Emoji reactions
IEmojiReactionController* emojiCtrl = meetingService->GetMeetingEmojiReactionController();
// Interpretation
IMeetingInterpretationController* interpretCtrl = meetingService->GetMeetingInterpretationController();
// Remote support
IMeetingRemoteSupportController* remoteSupportCtrl = meetingService->GetMeetingRemoteSupportController();
// Encryption
IMeetingEncryptionController* encryptionCtrl = meetingService->GetInMeetingEncryptionController();
// ... and 15+ more controllers!Complete list (35 controllers as of SDK v6.7.2):
GetMeetingAudioController() - Audio mute/unmuteGetMeetingVideoController() - Video start/stopGetMeetingShareController() - Screen sharingGetMeetingChatController() - Meeting chatGetMeetingParticipantsController() - Participant managementGetMeetingRecordingController() - Recording/raw dataGetMeetingWaitingRoomController() - Waiting room managementGetMeetingWebinarController() - Webinar featuresGetMeetingBOController() - Breakout roomsGetMeetingAICompanionController() - AI featuresGetMeetingQAController() - Q&A managementGetMeetingPollingController() - Polls/surveysGetMeetingWhiteboardController() - WhiteboardGetMeetingClosedCaptionController() - CaptionsGetMeetingLiveStreamController() - Live streamingGetMeetingEmojiReactionController() - Emoji reactionsGetMeetingInterpretationController() - Language interpretationGetMeetingSignInterpretationController() - Sign languageGetMeetingRemoteSupportController() - Remote supportGetMeetingEncryptionController() - E2E encryptionGetMeetingRawArchivingController() - Raw archivingGetMeetingReminderController() - Meeting remindersGetMeetingSmartSummaryController() - Smart summary (deprecated)GetUIController() - UI controlsGetAnnotationController() - AnnotationsGetMeetingRemoteController() - Remote controlGetH323Helper() - H.323 supportGetMeetingPhoneHelper() - Phone dial-inGetMeetingRealNameAuthController() - Real name authGetMeetingAANController() - Auto Accept NotificationGetMeetingImmersiveController() - Immersive viewGetMeetingDocsController() - DocumentsGetMeetingIndicatorController() - Meeting indicatorsGetMeetingProductionStudioController() - Production studioLet’s implement audio mute/unmute to demonstrate the pattern:
Open SDK/x64/h/meeting_service_components/meeting_audio_interface.h:
// The event listener interface
class IMeetingAudioCtrlEvent {
public:
virtual void onUserAudioStatusChange(IList<IUserAudioStatus*>* lstAudioStatusChange) = 0;
virtual void onUserActiveAudioChange(IList<unsigned int>* plstActiveAudioUser) = 0;
// ... more callback methods
};
// The controller interface
class IMeetingAudioController {
public:
virtual SDKError SetEvent(IMeetingAudioCtrlEvent* pEvent) = 0;
virtual SDKError JoinVoip() = 0;
virtual SDKError MuteAudio(unsigned int userid, bool allowUnmuteBySelf = true) = 0;
virtual SDKError UnMuteAudio(unsigned int userid) = 0;
// ... more control methods
};AudioEventListener.h:
#pragma once
#include <windows.h>
#include <cstdint>
#include <meeting_service_components/meeting_audio_interface.h>
#include <iostream>
using namespace ZOOM_SDK_NAMESPACE;
class AudioEventListener : public IMeetingAudioCtrlEvent {
public:
// Implement ALL pure virtual methods from IMeetingAudioCtrlEvent
void onUserAudioStatusChange(IList<IUserAudioStatus*>* lstAudioStatusChange) override;
void onUserActiveAudioChange(IList<unsigned int>* plstActiveAudioUser) override;
void onHostRequestStartAudio(IRequestStartAudioHandler* handler) override;
void onMuteOnEntryStatusChange(bool bEnabled) override;
// ... implement all other required methods
};AudioEventListener.cpp:
#include "AudioEventListener.h"
void AudioEventListener::onUserAudioStatusChange(IList<IUserAudioStatus*>* lstAudioStatusChange) {
if (!lstAudioStatusChange) return;
int count = lstAudioStatusChange->GetCount();
for (int i = 0; i < count; i++) {
IUserAudioStatus* audioStatus = lstAudioStatusChange->GetItem(i);
unsigned int userId = audioStatus->GetUserId();
AudioStatus status = audioStatus->GetStatus();
std::cout << "[AUDIO] User " << userId << " status changed: " << status << std::endl;
}
}
void AudioEventListener::onUserActiveAudioChange(IList<unsigned int>* plstActiveAudioUser) {
if (!plstActiveAudioUser) return;
int count = plstActiveAudioUser->GetCount();
std::cout << "[AUDIO] Active speakers: " << count << std::endl;
}
void AudioEventListener::onHostRequestStartAudio(IRequestStartAudioHandler* handler) {
std::cout << "[AUDIO] Host requests unmute" << std::endl;
// Auto-accept or ignore based on your logic
if (handler) {
handler->Accept(); // or handler->Ignore()
}
}
void AudioEventListener::onMuteOnEntryStatusChange(bool bEnabled) {
std::cout << "[AUDIO] Mute on entry: " << (bEnabled ? "enabled" : "disabled") << std::endl;
}main.cpp:
void SetupAudioFeatures() {
// 1. Get the controller (singleton)
IMeetingAudioController* audioCtrl = meetingService->GetMeetingAudioController();
if (!audioCtrl) {
std::cerr << "Failed to get audio controller" << std::endl;
return;
}
// 2. Set event listener
audioCtrl->SetEvent(new AudioEventListener());
// 3. Use controller methods
// Join audio (connect to VoIP)
SDKError err = audioCtrl->JoinVoip();
if (err == SDKERR_SUCCESS) {
std::cout << "[AUDIO] Joined VoIP successfully" << std::endl;
}
// Mute yourself (userId = 0 or your own user ID)
audioCtrl->MuteAudio(0, true);
std::cout << "[AUDIO] Muted self" << std::endl;
// Unmute yourself
audioCtrl->UnMuteAudio(0);
std::cout << "[AUDIO] Unmuted self" << std::endl;
// Mute all participants (host only, userId = 0 for all)
audioCtrl->MuteAudio(0, false); // false = don't allow self-unmute
std::cout << "[AUDIO] Muted all participants" << std::endl;
}Step 1: Read header (meeting_chat_interface.h)
class IMeetingChatCtrlEvent {
virtual void onChatMsgNotification(IChatMsgInfo* chatMsg) = 0;
// ... more methods
};
class IMeetingChatController {
virtual SDKError SetEvent(IMeetingChatCtrlEvent* pEvent) = 0;
virtual SDKError SendChatTo(const wchar_t* receiver, const wchar_t* content) = 0;
// ... more methods
};Step 2: Implement listener
class ChatEventListener : public IMeetingChatCtrlEvent {
void onChatMsgNotification(IChatMsgInfo* chatMsg) override {
std::wcout << L"[CHAT] From: " << chatMsg->GetSenderDisplayName()
<< L", Message: " << chatMsg->GetContent() << std::endl;
}
};Step 3: Use it
IMeetingChatController* chatCtrl = meetingService->GetMeetingChatController();
chatCtrl->SetEvent(new ChatEventListener());
chatCtrl->SendChatTo(L"everyone", L"Hello from bot!");Step 1: Read header (meeting_sharing_interface.h)
class IMeetingShareCtrlEvent {
virtual void onSharingStatus(SharingStatus status, unsigned int userId) = 0;
};Step 2: Implement listener
class ShareEventListener : public IMeetingShareCtrlEvent {
void onSharingStatus(SharingStatus status, unsigned int userId) override {
if (status == Sharing_Self_Send_Begin) {
std::cout << "[SHARE] User " << userId << " started sharing" << std::endl;
} else if (status == Sharing_Self_Send_End) {
std::cout << "[SHARE] User " << userId << " stopped sharing" << std::endl;
}
}
};Step 3: Use it
IMeetingShareController* shareCtrl = meetingService->GetMeetingShareController();
shareCtrl->SetEvent(new ShareEventListener());Each controller is a singleton accessed through meetingService:
// Always returns the SAME instance
IMeetingAudioController* ctrl1 = meetingService->GetMeetingAudioController();
IMeetingAudioController* ctrl2 = meetingService->GetMeetingAudioController();
// ctrl1 == ctrl2 (same pointer)Why this matters: You can get the controller anywhere in your code without passing pointers around.
// SDK maintains the listener internally
audioCtrl->SetEvent(new AudioEventListener());
// SDK calls listener methods when events occur
// You don't call these methods yourself!Why this matters: The SDK manages listener lifecycle. Use new and let SDK handle cleanup.
Actions (change state):
audioCtrl->MuteAudio(userId, true); // DO something
chatCtrl->SendChatTo(L"user", L"hello"); // DO somethingQueries (get information):
bool isMuted = audioCtrl->IsAudioMuted(userId); // GET information
bool isHost = participantsCtrl->IsHost(userId); // GET informationSome features require specific permissions:
// Recording requires special SDK app type
IMeetingRecordingController* recordingCtrl = meetingService->GetMeetingRecordingController();
if (recordingCtrl) {
SDKError canRecord = recordingCtrl->CanStartRawRecording();
if (canRecord == SDKERR_SUCCESS) {
recordingCtrl->StartRawRecording();
} else {
// Not available (wrong app type, insufficient permissions)
}
}Find the header file:
SDK/x64/h/meeting_service_components/meeting_[feature]_interface.hmeeting_audio_interface.h, meeting_chat_interface.hIdentify the interfaces:
I[Feature]Event or I[Feature]CtrlEvent (for callbacks)I[Feature]Controller (for actions/queries)Implement the event listener:
I[Feature]EventGet the controller:
meetingService->Get[Feature]Controller()nullptr (might not be available)Register listener and use:
controller->SetEvent(new YourListener())Test incrementally:
This bot auto-mutes when joining and responds to host unmute requests:
#include <windows.h>
#include <cstdint>
#include <meeting_service_components/meeting_audio_interface.h>
#include <iostream>
using namespace ZOOM_SDK_NAMESPACE;
class MuteBotAudioListener : public IMeetingAudioCtrlEvent {
private:
IMeetingAudioController* audioCtrl;
public:
MuteBotAudioListener(IMeetingAudioController* ctrl) : audioCtrl(ctrl) {}
void onUserAudioStatusChange(IList<IUserAudioStatus*>* lstAudioStatusChange) override {
// Just log for debugging
std::cout << "[AUDIO] Audio status changed" << std::endl;
}
void onUserActiveAudioChange(IList<unsigned int>* plstActiveAudioUser) override {
// Not needed for this bot
}
void onHostRequestStartAudio(IRequestStartAudioHandler* handler) override {
std::cout << "[AUDIO] Host requested unmute - auto accepting" << std::endl;
if (handler) {
handler->Accept(); // Automatically accept host request
}
}
void onMuteOnEntryStatusChange(bool bEnabled) override {
std::cout << "[AUDIO] Mute on entry: " << bEnabled << std::endl;
}
};
void SetupMuteBot() {
// Get audio controller
IMeetingAudioController* audioCtrl = meetingService->GetMeetingAudioController();
if (!audioCtrl) return;
// Register event listener
audioCtrl->SetEvent(new MuteBotAudioListener(audioCtrl));
// Join VoIP
audioCtrl->JoinVoip();
// Mute self immediately
audioCtrl->MuteAudio(0, true);
std::cout << "[BOT] Mute bot active - will auto-accept host unmute requests" << std::endl;
}Real bots typically use multiple controllers:
void SetupAdvancedBot() {
// Audio: Auto-mute on join
IMeetingAudioController* audioCtrl = meetingService->GetMeetingAudioController();
audioCtrl->SetEvent(new AudioEventListener());
audioCtrl->JoinVoip();
audioCtrl->MuteAudio(0, true);
// Video: Keep video off
IMeetingVideoController* videoCtrl = meetingService->GetMeetingVideoController();
videoCtrl->SetEvent(new VideoEventListener());
// Video off by default when joining with isVideoOff = true
// Chat: Respond to commands
IMeetingChatController* chatCtrl = meetingService->GetMeetingChatController();
chatCtrl->SetEvent(new ChatCommandListener());
chatCtrl->SendChatTo(L"everyone", L"Bot is ready!");
// Participants: Track who joins/leaves
IMeetingParticipantsController* participantsCtrl = meetingService->GetMeetingParticipantsController();
participantsCtrl->SetEvent(new ParticipantsEventListener());
// Recording: Capture meeting
IMeetingRecordingController* recordingCtrl = meetingService->GetMeetingRecordingController();
if (recordingCtrl->CanStartRawRecording() == SDKERR_SUCCESS) {
recordingCtrl->StartRawRecording();
}
}IMeetingRecordingController* ctrl = meetingService->GetMeetingRecordingController();
if (ctrl) { // Controller exists
SDKError canUse = ctrl->CanStartRawRecording();
if (canUse == SDKERR_SUCCESS) { // Feature available
ctrl->StartRawRecording();
}
}audioCtrl->MuteAudio(0, true); // Mute self
audioCtrl->MuteAudio(userId, true); // Mute specific user// Some features work without event listener
IMeetingChatController* chatCtrl = meetingService->GetMeetingChatController();
// Don't need SetEvent() if you only send messages, don't receive
chatCtrl->SendChatTo(L"everyone", L"Hello");IList<unsigned int>* participantList = participantsCtrl->GetParticipantsList();
int count = participantList->GetCount();
for (int i = 0; i < count; i++) {
unsigned int userId = participantList->GetItem(i);
// Use userId...
}Cause: Feature not available in this SDK app type or meeting state
Solution:
MEETING_STATUS_INMEETING)Cause: Forgot Windows message loop
Solution: See Windows Message Loop Guide
Cause: Called at wrong time or insufficient permissions
Solution:
1. Read header file → Find I[Feature]Controller and I[Feature]Event
2. Implement event listener → Inherit I[Feature]Event, implement all methods
3. Get controller → meetingService->Get[Feature]Controller()
4. Register listener → controller->SetEvent(new YourListener())
5. Use features → Call controller methodsThis pattern works for ALL 35+ controllers!
SDK/x64/h/meeting_service_interface.h (lines 1103-1314)SDK/x64/h/meeting_service_components/Last Updated: Based on Zoom Windows Meeting SDK v6.7.2.26830
This file