项目文件夹

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

9.1 KiB

RTMS Connection Architecture

RTMS uses a two-phase WebSocket design to separate control plane from data plane.

Overview

Multi-Product Note: The two-phase WebSocket design described here is identical for all RTMS products (meetings, webinars, and Video SDK sessions). The only difference is the initial webhook event name and payload ID field. Once connected, the signaling and media protocols are the same.

┌─────────────────────────────────────────────────────────────┐
│                    Zoom Meeting                              │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│                    Zoom RTMS Backend                         │
│  ┌─────────────────────┐    ┌─────────────────────────────┐ │
│  │  Signaling Server   │    │     Media Server            │ │
│  │  (Control Plane)    │    │     (Data Plane)            │ │
│  └──────────┬──────────┘    └──────────────┬──────────────┘ │
└─────────────┼───────────────────────────────┼───────────────┘
              │                               │
              ▼                               ▼
┌─────────────────────────────────────────────────────────────┐
│                      Your Server                             │
│  ┌─────────────────────┐    ┌─────────────────────────────┐ │
│  │  Signaling Socket   │    │     Media Socket            │ │
│  │  - Handshake        │    │     - Audio data            │ │
│  │  - Start/Stop       │    │     - Video data            │ │
│  │  - Heartbeat        │    │     - Transcript            │ │
│  └─────────────────────┘    └─────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘

Two-Phase Design

Phase 1: Signaling WebSocket (Control Plane)

Purpose: Authentication, session control, heartbeats

Responsibility Description
Authentication Validate signature, establish session
Media Server Discovery Returns media server URL in handshake response
Stream Control Start/stop streaming commands
Heartbeat Keep connection alive (msg_type 12/13)
Event Notifications Participant join/leave, sharing start/stop

URL Source: From server_urls in webhook payload

Message Flow:

Client                          Signaling Server
  │                                    │
  │──── Handshake Request (1) ────────>│
  │<─── Handshake Response (2) ────────│  <- Contains media_server.server_urls
  │                                    │
  │──── Client Ready (7) ─────────────>│  <- After media handshake complete
  │                                    │
  │<─── Keep Alive Request (12) ───────│
  │──── Keep Alive Response (13) ─────>│
  │                                    │

Phase 2: Media WebSocket (Data Plane)

Purpose: Actual audio, video, transcript, chat, screen share data

Responsibility Description
Media Configuration Set audio/video parameters (codec, resolution, fps)
Media Streaming Receive binary media data
Heartbeat Keep connection alive (msg_type 12/13)

URL Source: From signaling handshake response (media_server.server_urls.all)

Message Flow:

Client                          Media Server
  │                                    │
  │──── Media Handshake Request (3) ──>│  <- With media_params
  │<─── Media Handshake Response (4) ──│
  │                                    │
  │<─── Audio Data (14) ───────────────│
  │<─── Video Data (15) ───────────────│
  │<─── Screen Share Data (16) ────────│
  │<─── Transcript Data (17) ──────────│
  │<─── Chat Data (18) ────────────────│
  │                                    │
  │<─── Keep Alive Request (12) ───────│
  │──── Keep Alive Response (13) ─────>│
  │                                    │

Why Two Connections?

Benefit Explanation
Separation of Concerns Control logic doesn't interfere with media streaming
Independent Scaling Signaling and media servers scale differently
Fault Isolation Media reconnection doesn't require re-auth
Split Mode Support Each media type can have its own connection

Connection Modes

Each media type gets its own dedicated WebSocket connection:

Signaling WS ─────┬───> Audio WS
                  ├───> Video WS
                  ├───> Transcript WS
                  └───> Screen Share WS

Advantages:

  • Independent reconnection per media type
  • Better reliability
  • Fault isolation

Unified Mode

One media WebSocket for all media types:

Signaling WS ─────> Media WS (all types)

When to use:

  • Real-time audio+video muxing where sync matters
  • Simpler implementation for small projects

Signature Generation

Both signaling and media handshakes require HMAC-SHA256 signature:

// For meetings and webinars: use meeting_uuid
const message = `${clientId},${meetingUuid},${streamId}`;
// For Video SDK: use session_id
const message = `${clientId},${sessionId},${streamId}`;

// Generic approach: use whichever ID is present
const idValue = payload.meeting_uuid || payload.session_id;
const message = `${clientId},${idValue},${streamId}`;
const signature = crypto.createHmac('sha256', clientSecret)
  .update(message)
  .digest('hex');

Important

: Webinars use meeting_uuid (not webinar_uuid). Video SDK uses session_id.

Components:

  • clientId: OAuth Client ID (General App) or SDK Key (Video SDK App)
  • meetingUuid / sessionId: From webhook payload (meeting_uuid for meetings/webinars, session_id for Video SDK)
  • streamId: From webhook payload (rtms_stream_id)
  • clientSecret: OAuth Client Secret (General App) or SDK Secret (Video SDK App)

Heartbeat Protocol

CRITICAL: Both connections require heartbeat responses.

When you receive msg_type: 12 (Keep Alive Request):

// Immediately respond with msg_type: 13
ws.send(JSON.stringify({
  msg_type: 13,
  timestamp: receivedMessage.timestamp
}));

Timeout:

  • Signaling: ~60 seconds without heartbeat response
  • Media: ~65 seconds without heartbeat response

Failure to respond = connection closed!

Reconnection

RTMS does NOT auto-reconnect. You must implement:

ws.on('close', (code, reason) => {
  console.log(`Connection closed: ${code} ${reason}`);
  
  // Implement exponential backoff
  setTimeout(() => {
    reconnect();
  }, retryDelay);
  
  retryDelay = Math.min(retryDelay * 2, 30000);
});

Timeouts:

Connection Reconnection Window
Signaling 60 seconds
Media 65 seconds

Server URL Geo-Routing

Server URLs contain region codes:

Code Location
sjc San Jose, California
iad Washington DC
sin Singapore
fra Frankfurt, Germany
syd Sydney, Australia

Example: wss://rtms-sjc1.zoom.us/...

For production, route to workers in the same region as the Zoom server for lower latency.

Next Steps