项目文件夹

文件
2026-07-13 12:20:06 +08:00

7.1 KiB

Command Channel

Complete working code for custom command messaging between participants on Web.


Overview

The command channel enables custom data exchange between participants within the same session. Use cases:

  • Application-specific signaling
  • Session transfer / waiting room coordination
  • Real-time collaboration data
  • Custom control messages
+-------------------------------------------------------------------+
|                    COMMAND CHANNEL FLOW (Web)                      |
+-------------------------------------------------------------------+
|  Setup:                                                           |
|    client.join() -> client.getCommandClient()                     |
|                                                                   |
|  Sender:                                                          |
|    cmdClient.send(message)           [broadcast to all]           |
|    cmdClient.send(message, userId)   [targeted]                   |
|                                                                   |
|  Receiver:                                                        |
|    client.on('command-channel-message', callback)                 |
|                                                                   |
|  IMPORTANT: Command channel is SESSION-SCOPED.                    |
|  It does NOT span across different sessions.                      |
+-------------------------------------------------------------------+

Key difference from native SDKs: Web uses getCommandClient() (NOT getCmdChannel() like Linux/Windows native SDKs).


Limitations

Limit Value
Max message rate 60 messages/second
Max message size ~1KB recommended
Reliability Best effort (not guaranteed)
Scope Same session only

Note: Commands are not persisted - late joiners won't receive previous commands.


Setup Order (Critical)

You MUST call getCommandClient() and register listeners AFTER client.join(). The command channel subsystem is not active until after joining a session.

// CORRECT: Everything after join
await client.join(topic, jwt, userName);
const cmdClient = client.getCommandClient();
client.on('command-channel-status', (status) => { /* ... */ });
client.on('command-channel-message', (payload) => { /* ... */ });
// WRONG: Registering before join — command channel not active yet
await client.init('en-US', 'Global', { patchJsMedia: true });
client.on('command-channel-message', handler);  // WILL NOT RECEIVE MESSAGES
await client.join(topic, jwt, userName);

Without calling getCommandClient() after join, the command channel may never connect and command-channel-status will never fire.


Complete Working Example

import ZoomVideo from '@zoom/videosdk';

const client = ZoomVideo.createClient();

async function joinAndSetupCommandChannel(topic, jwt, userName) {
    // 1. Initialize
    await client.init('en-US', 'Global', { patchJsMedia: true });

    // 2. Join session
    await client.join(topic, jwt, userName);

    // 3. Activate command channel (MUST be after join)
    const cmdClient = client.getCommandClient();

    // 4. Listen for connection status
    client.on('command-channel-status', (status) => {
        console.log('Command channel status:', status);
        if (status === true) {
            console.log('Command channel connected - ready to send');
        }
    });

    // 5. Listen for incoming commands
    client.on('command-channel-message', (payload) => {
        try {
            const data = JSON.parse(payload.text);
            console.log('Command received:', data);
            handleCommand(data);
        } catch (e) {
            console.log('Raw command received:', payload.text);
        }
    });

    return cmdClient;
}

// Send a command (broadcast to all participants in session)
function sendCommand(cmdClient, type, data) {
    const message = JSON.stringify({ type, data });
    cmdClient.send(message);
}

// Send to a specific participant
function sendCommandToUser(cmdClient, userId, type, data) {
    const message = JSON.stringify({ type, data });
    cmdClient.send(message, userId);
}

// Handle incoming commands
function handleCommand(data) {
    switch (data.type) {
        case 'ping':
            console.log('Received ping');
            break;
        case 'transfer':
            console.log('Transfer info:', data);
            break;
        default:
            console.log('Unknown command type:', data.type);
    }
}

Events Reference

command-channel-status

Fires when the command channel connection status changes.

client.on('command-channel-status', (status) => {
    // status: boolean - true when connected, false when disconnected
    if (status) {
        // Safe to send commands now
    }
});

command-channel-message

Fires when a command is received from another participant.

client.on('command-channel-message', (payload) => {
    // payload.text: string - the command message content
    // payload.senderId: number - user ID of the sender
    const message = payload.text;
    console.log('Received:', message);
});

Cross-Platform Compatibility

When sending commands between Web and Linux/Windows native SDKs:

Property Web SDK Linux SDK Windows SDK
Get channel getCommandClient() getCmdChannel() getCmdChannel()
Send broadcast cmdClient.send(msg) sendCommand(nullptr, msg) sendCommand(NULL, msg)
Send targeted cmdClient.send(msg, userId) sendCommand(user, msg) sendCommand(user, msg)
String type JavaScript string const char* (UTF-8) const wchar_t* (wide)
Receive event command-channel-message onCommandReceived callback onCommandReceived callback

Use JSON strings as the message format for cross-platform compatibility.


Common Issues

Commands Not Received

Cause: getCommandClient() not called after join, or listeners registered before join

Fix: Ensure setup order is correct — join first, then getCommandClient(), then register listeners.

command-channel-status Never Fires

Cause: getCommandClient() was not called

Fix: You must explicitly call client.getCommandClient() after join to activate the channel.

Cross-SDK Messages Not Arriving

Cause: Version mismatch or timing issues between different SDK platforms

Fix: Add a server-side polling fallback:

const pollTimer = setInterval(async () => {
    const res = await fetch(`/api/status/${sessionName}`);
    const data = await res.json();
    if (data.ready) {
        clearInterval(pollTimer);
        handleData(data);
    }
}, 3000);