Setting the file. One moment.
Session Join Pattern · Video Sdk/linux · anthropics/knowledge-work-plugins · Skills Docs
ContentsBack to the top of the page 22
Validate Data
Tech Debt
62
Recruiting Pipeline
71
Vendor Check
125
Zoom Meeting SDK Web
88
Vendor Review
181
Create An Asset
⋯
examples/10 files
This guide provides a complete, working example of joining a Zoom Video SDK session on Linux, including JWT generation, session configuration, event handling, and cleanup.
CRITICAL : You need a JWT token to join sessions. Generate from your SDK credentials.
IMPORTANT : The SDK internally uses Qt/GLib for event dispatching. You MUST use a GLib main loop — a while (running) { sleep(); } loop will NOT dispatch SDK events, and callbacks like onSessionJoin will never fire. See Common Issues for details.
Solution : You MUST use a GLib main loop (g_main_loop_run). A while/sleep loop does not dispatch SDK events. See the main.cpp example above and Common Issues .
Invalid JWT token
Session name doesn’t match JWT tpc claim
Wrong SDK credentials
Expired token
Solution : Verify JWT payload and regenerate token.
Solution : Check SDK_KEY and SDK_SECRET in JWT generation.
Solution : Use virtual audio speaker:
examples/session-join-pattern.md
{
return
running_; }
void stop () { running_ = false ; }
// Session events
virtual void onSessionJoin () override ;
virtual void onSessionLeave () override ;
virtual void onError ( ZoomVideoSDKErrors errorCode , int detailErrorCode ) override ;
// User events
virtual void onUserJoin ( IZoomVideoSDKUserHelper * pUserHelper ,
IVideoSDKVector < IZoomVideoSDKUser * > * userList ) override ;
virtual void onUserLeave ( IZoomVideoSDKUserHelper * pUserHelper ,
IVideoSDKVector < IZoomVideoSDKUser * > * userList ) override ;
virtual void onUserVideoStatusChanged ( IZoomVideoSDKVideoHelper * pVideoHelper ,
IVideoSDKVector < IZoomVideoSDKUser * > * userList ) override ;
virtual void onUserAudioStatusChanged ( IZoomVideoSDKAudioHelper * pAudioHelper ,
IVideoSDKVector < IZoomVideoSDKUser * > * userList ) override ;
// Password events
virtual void onSessionNeedPassword ( IZoomVideoSDKPasswordHandler * handler ) override ;
virtual void onSessionPasswordWrong ( IZoomVideoSDKPasswordHandler * handler ) override ;
// Host/manager events
virtual void onUserHostChanged ( IZoomVideoSDKUserHelper * pUserHelper ,
IZoomVideoSDKUser * pUser ) override ;
virtual void onUserManagerChanged ( IZoomVideoSDKUser * pUser ) override ;
virtual void onUserNameChanged ( IZoomVideoSDKUser * pUser ) override ;
// Audio raw data (optional)
virtual void onMixedAudioRawDataReceived ( AudioRawData * data_ ) override ;
virtual void onOneWayAudioRawDataReceived ( AudioRawData * data_ ,
IZoomVideoSDKUser * pUser ) override ;
// Minimal stubs for required callbacks
virtual void onUserShareStatusChanged ( IZoomVideoSDKShareHelper * , IZoomVideoSDKUser * ,
IZoomVideoSDKShareAction * ) override {}
virtual void onLiveStreamStatusChanged ( IZoomVideoSDKLiveStreamHelper * ,
ZoomVideoSDKLiveStreamStatus ) override {}
virtual void onCloudRecordingStatus ( RecordingStatus , IZoomVideoSDKRecordingConsentHandler * ) override {}
virtual void onHostAskUnmute () override {}
virtual void onUserActiveAudioChanged ( IZoomVideoSDKAudioHelper * , IVideoSDKVector < IZoomVideoSDKUser * > * ) override {}
virtual void onSessionNeedPassword ( IZoomVideoSDKPasswordHandler * ) override {}
virtual void onSessionPasswordWrong ( IZoomVideoSDKPasswordHandler * ) override {}
virtual void onMixedAudioRawDataReceived ( AudioRawData * ) override {}
virtual void onOneWayAudioRawDataReceived ( AudioRawData * , IZoomVideoSDKUser * ) override {}
virtual void onShareAudioRawDataReceived ( AudioRawData * ) override {}
virtual void onUserRecordingConsent ( IZoomVideoSDKUser * ) override {}
virtual void onCommandReceived ( IZoomVideoSDKUser * , const zchar_t * ) override {}
virtual void onCommandChannelConnectResult ( bool ) override {}
virtual void onChatNewMessageNotify ( IZoomVideoSDKChatHelper * , IZoomVideoSDKChatMessage * ) override {}
virtual void onChatMsgDeleteNotification ( IZoomVideoSDKChatHelper * , const zchar_t * ,
ZoomVideoSDKChatMessageDeleteType ) override {}
virtual void onShareContentChanged ( IZoomVideoSDKShareHelper * , IZoomVideoSDKUser * ,
IZoomVideoSDKShareAction * ) override {}
virtual void onLiveTranscriptionStatus ( ZoomVideoSDKLiveTranscriptionStatus ) override {}
virtual void onLiveTranscriptionMsgReceived ( const zchar_t * , IZoomVideoSDKUser * ,
ZoomVideoSDKLiveTranscriptionOperationType ) override {}
virtual void onLiveTranscriptionMsgInfoReceived ( ILiveTranscriptionMessageInfo * ) override {}
virtual void onLiveTranscriptionMsgError ( ILiveTranscriptionLanguage * ,
ILiveTranscriptionLanguage * ) override {}
virtual void onOriginalLanguageMsgReceived ( ILiveTranscriptionMessageInfo * ) override {}
virtual void onInviteByPhoneStatus ( PhoneStatus , PhoneFailedReason ) override {}
virtual void onCalloutJoinSuccess ( IZoomVideoSDKUser * , const zchar_t * ) override {}
virtual void onCameraControlRequestResult ( IZoomVideoSDKUser * , bool ) override {}
virtual void onCameraControlRequestReceived ( IZoomVideoSDKUser * , ZoomVideoSDKCameraControlRequestType ,
IZoomVideoSDKCameraControlRequestHandler * ) override {}
virtual void onProxyDetectComplete () override {}
virtual void onProxySettingNotification ( IZoomVideoSDKProxySettingHandler * ) override {}
virtual void onSSLCertVerifiedFailNotification ( IZoomVideoSDKSSLCertificateInfo * ) override {}
virtual void onVideoAlphaChannelStatusChanged ( bool ) override {}
virtual void onMultiCameraStreamStatusChanged ( ZoomVideoSDKMultiCameraStreamStatus ,
IZoomVideoSDKUser * , IZoomVideoSDKRawDataPipe * ) override {}
virtual void onUserVideoNetworkStatusChanged ( ZoomVideoSDKNetworkStatus , IZoomVideoSDKUser * ) override {}
virtual void onChatPrivilegeChanged ( IZoomVideoSDKChatHelper * , ZoomVideoSDKChatPrivilegeType ) override {}
virtual void onVideoCanvasSubscribeFail ( ZoomVideoSDKSubscribeFailReason , IZoomVideoSDKUser * , void* ) override {}
virtual void onShareCanvasSubscribeFail ( ZoomVideoSDKSubscribeFailReason , IZoomVideoSDKUser * , void* ) override {}
private:
std :: atomic < bool > running_;
};
#endif // BOT_DELEGATE_H
, session->
getSessionID
());
// Get myself
IZoomVideoSDKUser * myself = session-> getMyself ();
if (myself) {
printf ( " My Name: %s\n " , myself-> getUserName ());
printf ( " Is Host: %s\n " , myself-> isHost () ? "Yes" : "No" );
}
}
// Start audio
IZoomVideoSDKAudioHelper * audio = video_sdk_obj-> getAudioHelper ();
if (audio) {
ZoomVideoSDKErrors err = audio-> startAudio ();
if (err == ZoomVideoSDKErrors_Success) {
printf ( " Audio started \n " );
// Subscribe to raw audio (optional)
audio-> subscribe ();
} else {
printf ( " Failed to start audio: %d\n " , err);
}
}
}
void BotDelegate :: onSessionLeave () {
printf ( "[EVENT] Session left \n " );
running_ = false ;
}
void BotDelegate :: onError ( ZoomVideoSDKErrors errorCode , int detailErrorCode ) {
printf ( "[ERROR] Error occurred: %d , Detail: %d\n " , errorCode, detailErrorCode);
// Common errors
switch (errorCode) {
case ZoomVideoSDKErrors_Auth_Error:
printf ( " Authentication failed - check JWT token \n " );
break ;
case ZoomVideoSDKErrors_Auth_Wrong_Key_or_Secret:
printf ( " Wrong SDK key or secret \n " );
break ;
case ZoomVideoSDKErrors_Session_Join_Failed:
printf ( " Failed to join session \n " );
break ;
case ZoomVideoSDKErrors_Session_Need_Password:
printf ( " Session requires password \n " );
break ;
case ZoomVideoSDKErrors_Session_Password_Wrong:
printf ( " Wrong session password \n " );
break ;
default :
break ;
}
}
void BotDelegate :: onUserJoin ( IZoomVideoSDKUserHelper * pUserHelper ,
IVideoSDKVector < IZoomVideoSDKUser * > * userList ) {
if ( ! userList) return ;
int count = userList-> GetCount ();
printf ( "[EVENT] %d user(s) joined \n " , count);
for ( int i = 0 ; i < count; i ++ ) {
IZoomVideoSDKUser * user = userList-> GetItem (i);
if (user) {
printf ( " User: %s\n " , user-> getUserName ());
}
}
}
void BotDelegate :: onUserLeave ( IZoomVideoSDKUserHelper * pUserHelper ,
IVideoSDKVector < IZoomVideoSDKUser * > * userList ) {
if ( ! userList) return ;
int count = userList-> GetCount ();
printf ( "[EVENT] %d user(s) left \n " , count);
for ( int i = 0 ; i < count; i ++ ) {
IZoomVideoSDKUser * user = userList-> GetItem (i);
if (user) {
printf ( " User: %s\n " , user-> getUserName ());
}
}
}
void BotDelegate :: onUserVideoStatusChanged ( IZoomVideoSDKVideoHelper * pVideoHelper ,
IVideoSDKVector < IZoomVideoSDKUser * > * userList ) {
if ( ! userList) return ;
int count = userList-> GetCount ();
for ( int i = 0 ; i < count; i ++ ) {
IZoomVideoSDKUser * user = userList-> GetItem (i);
if (user) {
printf ( "[EVENT] Video status changed for: %s\n " , user-> getUserName ());
// Subscribe to video here if needed
}
}
}
void BotDelegate :: onUserAudioStatusChanged ( IZoomVideoSDKAudioHelper * pAudioHelper ,
IVideoSDKVector < IZoomVideoSDKUser * > * userList ) {
if ( ! userList) return ;
int count = userList-> GetCount ();
for ( int i = 0 ; i < count; i ++ ) {
IZoomVideoSDKUser * user = userList-> GetItem (i);
if (user) {
IZoomVideoSDKAudioStatus * audioStatus = user-> getAudioStatus ();
if (audioStatus) {
printf ( "[EVENT] Audio status for %s : Muted= %s\n " ,
user-> getUserName (),
audioStatus-> isMuted () ? "Yes" : "No" );
}
}
}
}
void BotDelegate :: onSessionNeedPassword ( IZoomVideoSDKPasswordHandler * handler ) {
printf ( "[EVENT] Session requires password \n " );
// Provide password if available
// handler->inputSessionPassword("password");
// Or leave without password
// handler->leaveSessionIgnorePassword();
}
void BotDelegate :: onSessionPasswordWrong ( IZoomVideoSDKPasswordHandler * handler ) {
printf ( "[EVENT] Wrong session password \n " );
// Retry with correct password or leave
// handler->inputSessionPassword("correct-password");
// handler->leaveSessionIgnorePassword();
}
void BotDelegate :: onUserHostChanged ( IZoomVideoSDKUserHelper * pUserHelper ,
IZoomVideoSDKUser * pUser ) {
if (pUser) {
printf ( "[EVENT] Host changed to: %s\n " , pUser-> getUserName ());
}
}
void BotDelegate :: onUserManagerChanged ( IZoomVideoSDKUser * pUser ) {
if (pUser) {
printf ( "[EVENT] Manager changed: %s (Is Manager: %s ) \n " ,
pUser-> getUserName (),
pUser-> isManager () ? "Yes" : "No" );
}
}
void BotDelegate :: onUserNameChanged ( IZoomVideoSDKUser * pUser ) {
if (pUser) {
printf ( "[EVENT] User name changed to: %s\n " , pUser-> getUserName ());
}
}
void BotDelegate :: onMixedAudioRawDataReceived ( AudioRawData * data_ ) {
// Process mixed audio (all participants)
// char* buffer = data_->GetBuffer();
// unsigned int len = data_->GetBufferLen();
// unsigned int sampleRate = data_->GetSampleRate();
}
void BotDelegate :: onOneWayAudioRawDataReceived ( AudioRawData * data_ ,
IZoomVideoSDKUser * pUser ) {
// Process per-user audio
// if (pUser) {
// printf("Audio from: %s\n", pUser->getUserName());
// }
}
) {
BotDelegate * del = static_cast< BotDelegate *> (data);
if ( ! del-> isRunning ()) {
g_main_loop_quit (g_loop);
return FALSE; // Remove this timeout source
}
return TRUE; // Keep checking
}
void signalHandler ( int signum ) {
printf ( " \n Received signal %d , cleaning up... \n " , signum);
if (delegate) {
delegate-> stop ();
}
if (g_loop) {
g_main_loop_quit (g_loop);
}
}
int main ( int argc , char* argv []) {
// Check arguments
if (argc < 4 ) {
printf ( "Usage: %s <session_name> <user_name> <jwt_token> [session_password] \n " , argv[ 0 ]);
return 1 ;
}
const char* sessionName = argv[ 1 ];
const char* userName = argv[ 2 ];
const char* jwtToken = argv[ 3 ];
const char* sessionPassword = (argc >= 5 ) ? argv[ 4 ] : "" ;
// Setup signal handlers
signal (SIGINT, signalHandler);
signal (SIGTERM, signalHandler);
printf ( "Zoom Video SDK Bot \n " );
printf ( "================== \n " );
printf ( "Session: %s\n " , sessionName);
printf ( "User: %s\n " , userName);
printf ( " \n " );
// 1. Create SDK object
video_sdk_obj = CreateZoomVideoSDKObj ();
if ( ! video_sdk_obj) {
printf ( "Failed to create SDK object \n " );
return 1 ;
}
// 2. Initialize SDK
ZoomVideoSDKInitParams init_params;
init_params.domain = "https://zoom.us" ;
init_params.enableLog = true ;
init_params.logFilePrefix = "bot" ;
init_params.videoRawDataMemoryMode = ZoomVideoSDKRawDataMemoryModeHeap;
init_params.shareRawDataMemoryMode = ZoomVideoSDKRawDataMemoryModeHeap;
init_params.audioRawDataMemoryMode = ZoomVideoSDKRawDataMemoryModeHeap;
init_params.enableIndirectRawdata = false ;
ZoomVideoSDKErrors err = video_sdk_obj-> initialize (init_params);
if (err != ZoomVideoSDKErrors_Success) {
printf ( "Failed to initialize SDK: %d\n " , err);
DestroyZoomVideoSDKObj ();
return 1 ;
}
printf ( "SDK initialized \n " );
// 3. Add delegate
delegate = new BotDelegate ();
video_sdk_obj-> addListener (delegate);
// 4. Configure session context
ZoomVideoSDKSessionContext session_context;
session_context.sessionName = sessionName;
session_context.sessionPassword = sessionPassword;
session_context.userName = userName;
session_context.token = jwtToken;
session_context.sessionIdleTimeoutMins = 40 ;
session_context.autoLoadMutliStream = true ;
session_context.videoOption.localVideoOn = false ; // Headless bot
session_context.audioOption.connect = true ;
session_context.audioOption.mute = false ;
// For headless Linux: Virtual audio speaker
// Uncomment if you have implemented VirtualSpeaker class
// session_context.virtualAudioSpeaker = new VirtualSpeaker();
// 5. Join session
printf ( "Joining session... \n " );
IZoomVideoSDKSession * session = video_sdk_obj-> joinSession (session_context);
if ( ! session) {
printf ( "Failed to join session \n " );
video_sdk_obj-> cleanup ();
DestroyZoomVideoSDKObj ();
delete delegate;
return 1 ;
}
// 6. GLib main loop - REQUIRED for SDK event dispatching
// A while/sleep loop does NOT work — SDK callbacks will never fire without GLib.
printf ( "Bot is running. Press Ctrl+C to exit. \n\n " );
g_loop = g_main_loop_new ( NULL , FALSE);
g_timeout_add ( 100 , glib_timeout_callback, delegate);
g_main_loop_run (g_loop); // Blocks here, SDK events dispatch on this thread
g_main_loop_unref (g_loop);
// 7. Cleanup
printf ( " \n Cleaning up... \n " );
if (video_sdk_obj-> isInSession ()) {
video_sdk_obj-> leaveSession ( false );
// Wait a bit for leave to complete
std :: this_thread :: sleep_for ( std :: chrono :: milliseconds ( 500 ));
}
video_sdk_obj-> cleanup ();
DestroyZoomVideoSDKObj ();
delete delegate;
printf ( "Goodbye! \n " );
return 0 ;
}