Skill 寫法圖鑑

rtms

Anthropic | Agent 與工作流 | 原文 | Apache-2.0

用 Zoom RTMS 在後端接收即時音訊、視訊和逐字稿串流

中文翻譯

---
name: zoom-rtms
description: Zoom RTMS 的參考 skill。在已經導向 live-media 工作流程之後,處理即時音訊、視訊、聊天、逐字稿、螢幕分享或客服中心語音串流時使用。
user-invocable: false
triggers:
  - "real-time media"
  - "rtms"
  - "live audio stream"
  - "live video stream"
  - "meeting transcription"
  - "raw audio"
  - "raw video"
  - "websocket media"
  - "live transcript"
  - "streaming audio"
  - "streaming video"
  - "meeting bot media"
  - "contact center voice media"
  - "participant video on"
  - "participant video off"
  - "single individual video stream"
---

# Zoom 即時媒體串流(RTMS)

即時 Zoom 媒體 pipeline 的背景參考。請先用 `build-zoom-bot`,再用這個 skill 查串流類型、能力,以及 RTMS 特有的實作限制。

# Zoom 即時媒體串流(RTMS)

專家指引:即時存取 Zoom 會議、網路研討會、Video SDK session 和 Zoom Contact Center Voice 的音訊、視訊、逐字稿、聊天和螢幕分享資料。RTMS 使用基於 WebSocket 的協定,採開放標準,而且不需要會議機器人(bot)就能擷取媒體層。

## 先讀這段(關鍵)

RTMS 基本上是一個**後端的媒體擷取服務**。

- 你的後端接收並處理即時媒體:**音訊、視訊、螢幕分享、聊天、逐字稿**。
- RTMS 本身不是前端 UI SDK。
- 處理是**事件觸發**的:後端要等到 RTMS 開始的 webhook 事件,才開始處理串流。

選用的架構(常見):

- 加一個 **Zoom App SDK** 前端,提供 client 內的 UI/控制項。
- 透過 **WebSocket**(或 SSE、gRPC、queue worker 等)把後端 RTMS 的輸出串流給前端。

用 RTMS 處理媒體/資料層,用前端框架/Zoom Apps 處理呈現和使用者互動。

**官方文件**:https://developers.zoom.us/docs/rtms/
**SDK 參考(JS)**:https://zoom.github.io/rtms/js/
**SDK 參考(Python)**:https://zoom.github.io/rtms/py/
**範例 Repository**:https://github.com/zoom/rtms-samples

## 快速連結

**剛接觸 RTMS?照這個順序走:**

1. **[Connection Architecture](concepts/connection-architecture.md)** - 兩階段 WebSocket 設計
2. **[SDK Quickstart](examples/sdk-quickstart.md)** - 接收媒體最快的方式(建議)
3. **[Manual WebSocket](examples/manual-websocket.md)** - 不用 SDK、完整掌控協定
4. **[Media Types](references/media-types.md)** - 音訊、視訊、逐字稿、聊天、螢幕分享

**完整實作:**
- **[RTMS Bot](examples/rtms-bot.md)** - 端到端的 bot 實作指南

**參考:**
- **[Lifecycle Flow](concepts/lifecycle-flow.md)** - 從 webhook 到串流的完整流程
- **[Data Types](references/data-types.md)** - 所有 enum 和常數
- **[Webhooks](references/webhooks.md)** - 事件訂閱的細節
- **[Environment Variables](references/environment-variables.md)** - 憑證模式和執行期參數
- **[Quickstart Notes](references/quickstart.md)** - 次要的快速入門指南
- **Integrated Index** - 見本檔案下方的區段

**遇到問題?**
- 連線失敗 -> [Common Issues](troubleshooting/common-issues.md)
- 重複連線 -> [Webhook Gotchas](troubleshooting/common-issues.md#webhook-response-timing)
- 沒有音訊/視訊 -> [Media Configuration](references/media-types.md)
- 先做 preflight 檢查 -> [5-Minute Runbook](RUNBOOK.md)

## 支援的產品

| 產品 | Webhook 事件 | Payload ID | App 類型 |
|---------|--------------|------------|----------|
| **Meetings** | `meeting.rtms_started` / `meeting.rtms_stopped` | `meeting_uuid` | General App |
| **Webinars** | `webinar.rtms_started` / `webinar.rtms_stopped` | `meeting_uuid`(一樣!) | General App |
| **Video SDK** | `session.rtms_started` / `session.rtms_stopped` | `session_id` | Video SDK App |
| **Zoom Contact Center Voice** | 各產品專屬的 RTMS/ZCC Voice 事件 | 各產品專屬的串流/session 識別碼 | Contact Center / 已核准的 RTMS 整合 |

連線之後,核心的 signaling/media socket 模型在各產品之間是共用的。Meetings、webinars 和 Video SDK session 用大家熟悉的 start/stop webhook。Zoom Contact Center Voice 加上它自己的 RTMS/ZCC Voice 事件系列,應該視為同一個傳輸模型,只是事件 payload 因產品而異。

## RTMS 概覽

RTMS 是一條資料 pipeline,讓你的 app 能存取 Zoom 會議、網路研討會和 Video SDK session 的即時媒體,**不需要參與者 bot**。不用讓自動化的 client 加入會議,而是用 RTMS 直接從 Zoom 的基礎設施蒐集媒體資料。

### RTMS 提供什麼

| 媒體類型 | 格式 | 使用情境 |
|------------|--------|-----------|
| **Audio** | PCM (L16)、G.711、G.722、Opus | 轉錄、語音分析、錄製 |
| **Video** | H.264、JPG、PNG | 錄製、AI 視覺、縮圖、活躍參與者選擇 |
| **Screen Share** | H.264、JPG、PNG | 內容擷取、投影片擷取 |
| **Transcript** | JSON 文字 | 會議記錄、搜尋、合規 |
| **Chat** | JSON 文字 | 封存、情緒分析 |

### 2026 年 3 月的協定變更

- **Zoom Contact Center Voice 支援**:RTMS 現在涵蓋 Contact Center Voice 的音訊和逐字稿情境。
- **逐字稿語言辨識(Language Identification)控制**:逐字稿媒體 handshake 現在支援 `src_language` 和 `enable_lid`。預設行為是啟用 LID。設定 `enable_lid: false` 可以強制使用固定語言。
- **單一個人視訊串流訂閱**:當 `data_opt` 設為 `VIDEO_SINGLE_INDIVIDUAL_STREAM` 時,RTMS 現在可以一次只串流一位參與者的鏡頭畫面。
- **client 發起的優雅關閉**:後端可以透過 signaling socket 送出 `STREAM_CLOSE_REQ`,然後等待 `STREAM_CLOSE_RESP`。
- **媒體 keep-alive 容忍度提高**:media socket 的 keep-alive 逾時現在是 **65 秒**,不是 35 秒。

### 兩種做法

| 做法 | 適合 | 複雜度 |
|----------|----------|------------|
| **SDK**(`@zoom/rtms`) | 大多數使用情境 | 低:幫你處理 WebSocket 的複雜度 |
| **Manual WebSocket** | 自訂協定、其他語言 | 高:要實作完整的協定 |

## 先決條件

- **Node.js 20.3.0+**(建議 24 LTS),給 JavaScript SDK 用
- **Python 3.10+**,給 Python SDK 用
- Zoom General App(給會議/網路研討會)或 Video SDK App(給 Video SDK),並啟用 RTMS 功能
- 接收 RTMS 事件的 webhook endpoint
- 接收 WebSocket 串流的伺服器

> **需要 RTMS 存取權限?** 到 [Zoom Developer Forum](https://devforum.zoom.us/) 發文,附上你的使用情境,申請 RTMS 存取權限。

## 快速開始(SDK,建議)

```javascript
import rtms from "@zoom/rtms";

// All RTMS start/stop events across products
const RTMS_EVENTS = ["meeting.rtms_started", "webinar.rtms_started", "session.rtms_started"];

// Handle webhook events
rtms.onWebhookEvent(({ event, payload }) => {
  if (!RTMS_EVENTS.includes(event)) return;

  const client = new rtms.Client();

  client.onAudioData((data, timestamp, metadata) => {
    console.log(`Audio from ${metadata.userName}: ${data.length} bytes`);
  });

  client.onTranscriptData((data, timestamp, metadata) => {
    const text = data.toString('utf8');
    console.log(`${metadata.userName}: ${text}`);
  });

  client.onJoinConfirm((reason) => {
    console.log(`Joined session: ${reason}`);
  });

  // SDK handles all WebSocket connections automatically
  // Accepts both meeting_uuid and session_id transparently
  client.join(payload);
});
```

## 快速開始(Manual WebSocket)

想完整掌控,或使用沒有 SDK 的語言,就要實作兩階段的 WebSocket 協定:

```javascript
const WebSocket = require('ws');
const crypto = require('crypto');

const RTMS_EVENTS = ['meeting.rtms_started', 'webinar.rtms_started', 'session.rtms_started'];

// 1. Generate signature
// For meetings/webinars: uses meeting_uuid. For Video SDK: uses session_id.
function generateSignature(clientId, idValue, streamId, clientSecret) {
  const message = `${clientId},${idValue},${streamId}`;
  return crypto.createHmac('sha256', clientSecret).update(message).digest('hex');
}

// 2. Handle webhook
app.post('/webhook', (req, res) => {
  res.status(200).send();  // CRITICAL: Respond immediately!
  
  const { event, payload } = req.body;
  if (RTMS_EVENTS.includes(event)) {
    connectToRTMS(payload);
  }
});

// 3. Connect to signaling WebSocket
function connectToRTMS(payload) {
  const { server_urls, rtms_stream_id } = payload;
  // meeting_uuid for meetings/webinars, session_id for Video SDK
  const idValue = payload.meeting_uuid || payload.session_id;
  const signature = generateSignature(CLIENT_ID, idValue, rtms_stream_id, CLIENT_SECRET);
  
  const signalingWs = new WebSocket(server_urls);
  
  signalingWs.on('open', () => {
    signalingWs.send(JSON.stringify({
      msg_type: 1,  // Handshake request
      protocol_version: 1,
      meeting_uuid: idValue,
      rtms_stream_id,
      signature,
      media_type: 9  // AUDIO(1) | TRANSCRIPT(8)
    }));
  });
  
  // ... handle responses, connect to media WebSocket
}
```

**參見**:完整實作請看 [Manual WebSocket Guide](examples/manual-websocket.md)。

## 媒體類型 Bitmask

用位元運算 OR 組合各類型:

| 類型 | 值 | 說明 |
|------|-------|-------------|
| Audio | 1 | PCM 音訊樣本 |
| Video | 2 | H.264/JPG 視訊影格 |
| Screen Share | 4 | **跟視訊是分開的!** |
| Transcript | 8 | 即時語音轉文字 |
| Chat | 16 | 會議中的聊天訊息 |
| All | 32 | 所有媒體類型 |

**範例**:Audio + Transcript = `1 | 8` = `9`

## 關鍵陷阱

| 問題 | 解法 |
|-------|----------|
| **只允許 1 條連線** | 新連線會把既有的踢掉。要追蹤活躍的 session! |
| **立刻回 200** | 如果 webhook 延遲,Zoom 會重試,造成重複連線 |
| **Heartbeat 是強制的** | 收到 msg_type 12 要回 msg_type 13,否則連線會斷 |
| **重新連線是你的工作** | RTMS 不會自動重連。媒體 keep-alive 容忍度現在約 **65 秒**;signaling 則維持約 **60 秒** |
| **逐字稿語言飄移** | 想要固定語言的轉錄、而不是自動切換語言時,用 `src_language` 加 `enable_lid: false` |
| **只支援單一參與者視訊** | `VIDEO_SINGLE_INDIVIDUAL_STREAM` 一次只支援一位參與者。新的 `VIDEO_SUBSCRIPTION_REQ` 會覆蓋先前的選擇 |
| **優雅關閉現在是明確的** | 後端想要乾淨地結束串流時,用 `STREAM_CLOSE_REQ` / `STREAM_CLOSE_RESP` |

## 環境變數

### SDK 環境變數

```bash
# Required - Authentication
ZM_RTMS_CLIENT=your_client_id          # Zoom OAuth Client ID
ZM_RTMS_SECRET=your_client_secret      # Zoom OAuth Client Secret

# Optional - Webhook server
ZM_RTMS_PORT=8080                      # Default: 8080
ZM_RTMS_PATH=/webhook                  # Default: /

# Optional - Logging
ZM_RTMS_LOG_LEVEL=info                 # error, warn, info, debug, trace
ZM_RTMS_LOG_FORMAT=progressive         # progressive or json
ZM_RTMS_LOG_ENABLED=true
```

### 手動實作用的變數

```bash
ZOOM_CLIENT_ID=your_client_id
ZOOM_CLIENT_SECRET=your_client_secret
ZOOM_SECRET_TOKEN=your_webhook_token   # For webhook validation
```

## Zoom App 設定

### 給 Meetings 和 Webinars(General App)

1. 前往 [marketplace.zoom.us](https://marketplace.zoom.us) -> Develop -> Build App
2. 選擇 **General App** -> **User-Managed**
3. Features -> Access -> **Enable Event Subscription**
4. Add Events -> 搜尋「rtms」-> 選取:
   - `meeting.rtms_started`
   - `meeting.rtms_stopped`
   - `webinar.rtms_started`(如果用 webinar)
   - `webinar.rtms_stopped`(如果用 webinar)
5. Scopes -> Add Scopes -> 搜尋「rtms」-> 新增:
   - `meeting:read:meeting_audio`
   - `meeting:read:meeting_video`
   - `meeting:read:meeting_transcript`
   - `meeting:read:meeting_chat`
   - `webinar:read:webinar_audio`(如果用 webinar)
   - `webinar:read:webinar_video`(如果用 webinar)
   - `webinar:read:webinar_transcript`(如果用 webinar)
   - `webinar:read:webinar_chat`(如果用 webinar)

### 給 Video SDK(Video SDK App)

1. 前往 [marketplace.zoom.us](https://marketplace.zoom.us) -> Develop -> Build App
2. 選擇 **Video SDK App**
3. 使用你的 SDK Key 和 SDK Secret(不是 OAuth Client ID/Secret)
4. Add Events:
   - `session.rtms_started`
   - `session.rtms_stopped`

## 範例 Repository

### 官方範例

| Repository | 說明 |
|------------|-------------|
| [rtms-samples](https://github.com/zoom/rtms-samples) | RTMSManager、樣板、AI 範例 |
| [rtms-quickstart-js](https://github.com/zoom/rtms-quickstart-js) | JavaScript SDK 快速入門 |
| [rtms-quickstart-py](https://github.com/zoom/rtms-quickstart-py) | Python SDK 快速入門 |
| [rtms-sdk-cpp](https://github.com/zoom/rtms-sdk-cpp) | C++ SDK |
| [zoom-rtms](https://github.com/zoom/rtms) | SDK 主要 repository |

### AI 整合範例

| 範例 | 說明 |
|--------|-------------|
| [rtms-meeting-assistant-starter-kit](https://github.com/zoom/rtms-meeting-assistant-starter-kit) | 附摘要功能的 AI 會議助理 |
| [arlo-meeting-assistant](https://github.com/zoom/arlo-meeting-assistant) | 附資料庫的正式環境會議助理 |
| [videosdk-rtms-transcribe-audio](https://github.com/zoom/videosdk-rtms-transcribe-audio) | Whisper 轉錄 |

## 完整文件

### 概念
- **[Connection Architecture](concepts/connection-architecture.md)** - 兩階段 WebSocket 設計
- **[Lifecycle Flow](concepts/lifecycle-flow.md)** - 從 webhook 到串流的流程

### 範例
- **[SDK Quickstart](examples/sdk-quickstart.md)** - 使用 @zoom/rtms SDK
- **[Manual WebSocket](examples/manual-websocket.md)** - 原始協定實作
- **[RTMS Bot](examples/rtms-bot.md)** - 完整的 bot 實作指南
- **[AI Integration](examples/ai-integration.md)** - 轉錄與分析的模式

### 參考
- **[Media Types](references/media-types.md)** - 音訊、視訊、逐字稿、聊天、螢幕分享
- **[Data Types](references/data-types.md)** - 所有 enum 和常數
- **[Connection](references/connection.md)** - WebSocket 協定細節
- **[Webhooks](references/webhooks.md)** - 事件訂閱

### 疑難排解
- **[Common Issues](troubleshooting/common-issues.md)** - FAQ 和解法

## 資源

- **官方文件**:https://developers.zoom.us/docs/rtms/
- **資料類型**:https://developers.zoom.us/docs/rtms/data-types/
- **媒體參數**:https://developers.zoom.us/docs/rtms/media-parameter-definition/
- **開發者論壇**:https://devforum.zoom.us/

---

**需要協助?** 先看下面的 Integrated Index 區段,裡面有完整的導覽。

---

## Integrated Index

_這個區段是從 `SKILL.md` 搬過來的。_

RTMS 提供即時存取 Zoom 會議、網路研討會和 Video SDK session 的音訊、視訊、逐字稿、聊天和螢幕分享。

## 關鍵定位

把 RTMS 當成接收並處理媒體串流的**後端服務**。

- 後端的角色:擷取音訊/視訊/分享/聊天/逐字稿,執行 AI/分析,持久化/轉送資料。
- 選用的前端角色:Zoom App SDK 或網頁 dashboard,透過後端的傳輸管道(WebSocket/SSE/其他)取用處理過的串流資料。
- 啟動模型:後端等待 RTMS 開始的 webhook 事件,然後開始處理串流。

不要把 RTMS 當成純前端的 SDK 來設計。

## 快速上手路徑

**如果你剛接觸 RTMS,照這個順序:**

1. **先跑 preflight 檢查** -> [RUNBOOK.md](RUNBOOK.md)
2. **理解架構** -> [concepts/connection-architecture.md](concepts/connection-architecture.md)
   - 兩階段 WebSocket:Signaling + Media
   - 為什麼 RTMS 不用 bot

3. **選擇你的做法** -> SDK 或 Manual
   - SDK(建議):[examples/sdk-quickstart.md](examples/sdk-quickstart.md)
   - Manual WebSocket:[examples/manual-websocket.md](examples/manual-websocket.md)

4. **理解生命週期** -> [concepts/lifecycle-flow.md](concepts/lifecycle-flow.md)
   - Webhook -> Signaling -> Media -> Streaming

5. **設定媒體類型** -> [references/media-types.md](references/media-types.md)
   - 音訊、視訊、逐字稿、聊天、螢幕分享

6. **排查問題** -> [troubleshooting/common-issues.md](troubleshooting/common-issues.md)
   - 連線問題、重複的 webhook、資料遺失

---

## 文件結構

```
rtms/
├── SKILL.md                           # Main skill overview
├── SKILL.md                           # This file - navigation guide
│
├── concepts/                          # Core architectural patterns
│   ├── connection-architecture.md     # Two-phase WebSocket design
│   └── lifecycle-flow.md              # Webhook to streaming flow
│
├── examples/                          # Complete working code
│   ├── sdk-quickstart.md              # Using @zoom/rtms SDK
│   ├── manual-websocket.md            # Raw protocol implementation
│   ├── rtms-bot.md                    # Complete RTMS bot implementation
│   └── ai-integration.md              # Transcription and analysis
│
├── references/                        # Reference documentation
│   ├── media-types.md                 # Audio, video, transcript, chat, share
│   ├── data-types.md                  # All enums and constants
│   ├── connection.md                  # WebSocket protocol details
│   └── webhooks.md                    # Event subscription
│
└── troubleshooting/                   # Problem solving guides
    └── common-issues.md               # FAQ and solutions
```

---

## 依使用情境

### 我想取得會議逐字稿
1. [SDK Quickstart](examples/sdk-quickstart.md) - 最快的做法
2. [Media Types](references/media-types.md#transcript) - 逐字稿設定
3. [AI Integration](examples/ai-integration.md) - Whisper、Deepgram、AssemblyAI

### 我想錄製會議
1. [Media Types](references/media-types.md) - 音訊 + 視訊設定
2. [SDK Quickstart](examples/sdk-quickstart.md) - 接收媒體
3. [AI Integration](examples/ai-integration.md#audio-recording) - 補齊空缺的錄製

### 我想做 AI 會議助理
1. [AI Integration](examples/ai-integration.md) - 完整的模式
2. [SDK Quickstart](examples/sdk-quickstart.md) - 媒體擷取
3. [Lifecycle Flow](concepts/lifecycle-flow.md) - 事件處理

### 我想做完整的 RTMS bot
1. [RTMS Bot](examples/rtms-bot.md) - **完整的實作指南**
2. [Lifecycle Flow](concepts/lifecycle-flow.md) - 從 webhook 到串流的流程
3. [Connection Architecture](concepts/connection-architecture.md) - 兩階段設計

### 我需要完整掌控協定
1. [Manual WebSocket](examples/manual-websocket.md) - **從這裡開始**
2. [Connection Architecture](concepts/connection-architecture.md) - 兩階段設計
3. [Data Types](references/data-types.md) - 所有訊息類型和 enum
4. [Connection](references/connection.md) - 協定細節

### 我遇到連線錯誤
1. [Common Issues](troubleshooting/common-issues.md) - 診斷檢查清單
2. [Connection Architecture](concepts/connection-architecture.md) - 驗證流程
3. [Webhooks](references/webhooks.md) - 驗證與時間點

### 我想理解架構
1. [Connection Architecture](concepts/connection-architecture.md) - 兩階段 WebSocket
2. [Lifecycle Flow](concepts/lifecycle-flow.md) - 完整流程圖
3. [Data Types](references/data-types.md) - 協定常數

---

## 依產品

### 我在做 Zoom Meetings
- 標準的 RTMS 設定。Webhook 事件:`meeting.rtms_started`。使用有 OAuth 的 General App。
- 從 [SDK Quickstart](examples/sdk-quickstart.md) 或 [Manual WebSocket](examples/manual-websocket.md) 開始。

### 我在做 Zoom Webinars
- 跟會議一樣,但 webhook 事件是 `webinar.rtms_started`。Payload 仍然用 `meeting_uuid`(不是 `webinar_uuid`)。
- 加上 webinar 的 scope 和事件訂閱。見 [Webhooks](references/webhooks.md)。
- 只有 **panelist** 的串流確認可用。與會者(attendee)的串流可能不是個別的。

### 我在做 Zoom Video SDK
- Webhook 事件:`session.rtms_started`。Payload 用 `session_id`(不是 `meeting_uuid`)。
- 需要有 SDK Key/Secret 的 **Video SDK App**(不是 OAuth Client ID/Secret)。
- 連線之後,協定跟會議**完全相同**。
- Payload 細節見 [Webhooks](references/webhooks.md)。

---

## 關鍵文件

### 1. Connection Architecture(關鍵)
**[concepts/connection-architecture.md](concepts/connection-architecture.md)**

RTMS 使用**兩條獨立的 WebSocket 連線**:
- **Signaling WebSocket**:認證、控制、heartbeat
- **Media WebSocket**:實際的音訊/視訊/逐字稿資料

### 2. SDK vs Manual(決策點)
**[examples/sdk-quickstart.md](examples/sdk-quickstart.md)** vs **[examples/manual-websocket.md](examples/manual-websocket.md)**

| SDK | Manual |
|-----|--------|
| 處理 WebSocket 的複雜度 | 完整掌控協定 |
| 自動重連 | 自己做重連 |
| 程式碼較少 | 程式碼較多 |
| 最適合大多數使用情境 | 最適合自訂需求 |

### 3. 關鍵陷阱(最常見的問題)
**[troubleshooting/common-issues.md](troubleshooting/common-issues.md)**

1. **立刻回 200**:webhook 回應延遲會造成重複
2. **每個串流只有 1 條連線**:新連線會把既有的踢掉
3. **需要 heartbeat**:必須回應 keep-alive,否則連線會斷
4. **追蹤活躍的 session**:避免重複的加入嘗試

---

## 關鍵心得

### 重要發現:

1. **兩階段 WebSocket 設計**
   - Signaling:控制層(handshake、heartbeat、start/stop)
   - Media:資料層(音訊、視訊、逐字稿、聊天、分享)
   - 見:[Connection Architecture](concepts/connection-architecture.md)

2. **Webhook 回應時間**
   - 一定要在做任何處理**之前**先回 200
   - 延遲回應 -> Zoom 重試 -> 重複連線
   - 見:[Common Issues](troubleshooting/common-issues.md#webhook-response-timing)

3. **Heartbeat 是強制的**
   - Signaling:收到 msg_type 12,回 msg_type 13
   - Media:同樣的模式
   - 沒回應 = 連線被關閉
   - 見:[Connection](references/connection.md#heartbeat)

4. **簽章產生**
   - 格式:`HMAC-SHA256(clientSecret, "clientId,meetingUuid,streamId")`
   - Video SDK 用 `session_id` 取代 `meetingUuid`
   - Webinar 仍然用 `meeting_uuid`(不是 `webinar_uuid`)
   - signaling 和 media 的 handshake 都需要
   - 見:[Manual WebSocket](examples/manual-websocket.md#signature-generation)

5. **媒體類型是 bitmask**
   - Audio=1、Video=2、Share=4、Transcript=8、Chat=16、All=32
   - 用 OR 組合:Audio+Transcript = 1|8 = 9
   - 見:[Media Types](references/media-types.md)

6. **螢幕分享跟視訊是分開的**
   - 不同的 msg_type(16 vs 15)
   - 不同的媒體旗標(4 vs 2)
   - 必須分別訂閱
   - 見:[Media Types](references/media-types.md#screen-share)

---

## 快速參考

### 「連線失敗」
-> [Common Issues](troubleshooting/common-issues.md)

### 「重複連線」
-> [Webhook timing](troubleshooting/common-issues.md#webhook-response-timing)

### 「沒有音訊/視訊資料」
-> [Media Types](references/media-types.md) - 檢查設定

### 「我要怎麼手動實作?」
-> [Manual WebSocket](examples/manual-websocket.md)

### 「有哪些訊息類型?」
-> [Data Types](references/data-types.md)

### 「我要怎麼整合 AI?」
-> [AI Integration](examples/ai-integration.md)

---

## 文件版本

根據 **Zoom RTMS SDK v1.x** 和截至 2026 年的官方文件。

---

**祝寫程式愉快!**

記得:想走最快的路徑就從 [SDK Quickstart](examples/sdk-quickstart.md) 開始,需要完整掌控的話就用 [Manual WebSocket](examples/manual-websocket.md)。

英文原文

---
name: zoom-rtms
description: Reference skill for Zoom RTMS. Use after routing to a live-media workflow when processing real-time audio, video, chat, transcripts, screen share, or contact-center voice streams.
user-invocable: false
triggers:
  - "real-time media"
  - "rtms"
  - "live audio stream"
  - "live video stream"
  - "meeting transcription"
  - "raw audio"
  - "raw video"
  - "websocket media"
  - "live transcript"
  - "streaming audio"
  - "streaming video"
  - "meeting bot media"
  - "contact center voice media"
  - "participant video on"
  - "participant video off"
  - "single individual video stream"
---

# Zoom Realtime Media Streams (RTMS)

Background reference for live Zoom media pipelines. Prefer `build-zoom-bot` first, then use this skill for stream types, capabilities, and RTMS-specific implementation constraints.

# Zoom Realtime Media Streams (RTMS)

Expert guidance for accessing live audio, video, transcript, chat, and screen share data from Zoom meetings, webinars, Video SDK sessions, and Zoom Contact Center Voice in real-time. RTMS uses a WebSocket-based protocol with open standards and does not require a meeting bot to capture the media plane.

## Read This First (Critical)

RTMS is primarily a **backend media ingestion service**.

- Your backend receives and processes live media: **audio, video, screen share, chat, transcript**.
- RTMS is not a frontend UI SDK by itself.
- Processing is **event-triggered**: backend waits for RTMS start webhook events before stream handling begins.

Optional architecture (common):

- Add a **Zoom App SDK** frontend for in-client UI/controls.
- Stream backend RTMS outputs to frontend via **WebSocket** (or SSE, gRPC, queue workers, etc.).

Use RTMS for media/data plane, and use frontend frameworks/Zoom Apps for presentation + user interactions.

**Official Documentation**: https://developers.zoom.us/docs/rtms/
**SDK Reference (JS)**: https://zoom.github.io/rtms/js/
**SDK Reference (Python)**: https://zoom.github.io/rtms/py/
**Sample Repository**: https://github.com/zoom/rtms-samples

## Quick Links

**New to RTMS? Follow this path:**

1. **[Connection Architecture](concepts/connection-architecture.md)** - Two-phase WebSocket design
2. **[SDK Quickstart](examples/sdk-quickstart.md)** - Fastest way to receive media (recommended)
3. **[Manual WebSocket](examples/manual-websocket.md)** - Full protocol control without SDK
4. **[Media Types](references/media-types.md)** - Audio, video, transcript, chat, screen share

**Complete Implementation:**
- **[RTMS Bot](examples/rtms-bot.md)** - End-to-end bot implementation guide

**Reference:**
- **[Lifecycle Flow](concepts/lifecycle-flow.md)** - Complete webhook-to-streaming flow
- **[Data Types](references/data-types.md)** - All enums and constants
- **[Webhooks](references/webhooks.md)** - Event subscription details
- **[Environment Variables](references/environment-variables.md)** - credential modes and runtime knobs
- **[Quickstart Notes](references/quickstart.md)** - Secondary quickstart guide
- **Integrated Index** - see the section below in this file

**Having issues?**
- Connection fails -> [Common Issues](troubleshooting/common-issues.md)
- Duplicate connections -> [Webhook Gotchas](troubleshooting/common-issues.md#webhook-response-timing)
- No audio/video -> [Media Configuration](references/media-types.md)
- Start with preflight checks -> [5-Minute Runbook](RUNBOOK.md)

## Supported Products

| Product | Webhook Event | Payload ID | App Type |
|---------|--------------|------------|----------|
| **Meetings** | `meeting.rtms_started` / `meeting.rtms_stopped` | `meeting_uuid` | General App |
| **Webinars** | `webinar.rtms_started` / `webinar.rtms_stopped` | `meeting_uuid` (same!) | General App |
| **Video SDK** | `session.rtms_started` / `session.rtms_stopped` | `session_id` | Video SDK App |
| **Zoom Contact Center Voice** | Product-specific RTMS/ZCC Voice events | Product-specific stream/session identifiers | Contact Center / approved RTMS integration |

Once connected, the core signaling/media socket model is shared across products. Meetings, webinars, and Video SDK sessions use the familiar start/stop webhooks. Zoom Contact Center Voice adds its own RTMS/ZCC Voice event family and should be treated as the same transport model with product-specific event payloads.

## RTMS Overview

RTMS is a data pipeline that gives your app access to live media from Zoom meetings, webinars, and Video SDK sessions **without participant bots**. Instead of having automated clients join meetings, use RTMS to collect media data directly from Zoom's infrastructure.

### What RTMS Provides

| Media Type | Format | Use Cases |
|------------|--------|-----------|
| **Audio** | PCM (L16), G.711, G.722, Opus | Transcription, voice analysis, recording |
| **Video** | H.264, JPG, PNG | Recording, AI vision, thumbnails, active participant selection |
| **Screen Share** | H.264, JPG, PNG | Content capture, slide extraction |
| **Transcript** | JSON text | Meeting notes, search, compliance |
| **Chat** | JSON text | Archive, sentiment analysis |

### March 2026 Protocol Changes

- **Zoom Contact Center Voice support**: RTMS now covers Contact Center Voice audio and transcript scenarios.
- **Transcript Language Identification control**: transcript media handshakes now support `src_language` and `enable_lid`. Default behavior is LID enabled. Set `enable_lid: false` to force a fixed language.
- **Single individual video stream subscription**: RTMS can now stream one participant's camera feed at a time when `data_opt` is set to `VIDEO_SINGLE_INDIVIDUAL_STREAM`.
- **Graceful client-initiated shutdown**: backends can send `STREAM_CLOSE_REQ` over the signaling socket and wait for `STREAM_CLOSE_RESP`.
- **Media keep-alive tolerance increased**: media socket keep-alive timeout is now **65 seconds**, not 35.

### Two Approaches

| Approach | Best For | Complexity |
|----------|----------|------------|
| **SDK** (`@zoom/rtms`) | Most use cases | Low - handles WebSocket complexity |
| **Manual WebSocket** | Custom protocols, other languages | High - full protocol implementation |

## Prerequisites

- **Node.js 20.3.0+** (24 LTS recommended) for JavaScript SDK
- **Python 3.10+** for Python SDK
- Zoom General App (for meetings/webinars) or Video SDK App (for Video SDK) with RTMS feature enabled
- Webhook endpoint for RTMS events
- Server to receive WebSocket streams

> **Need RTMS access?** Post in [Zoom Developer Forum](https://devforum.zoom.us/) requesting RTMS access with your use case.

## Quick Start (SDK - Recommended)

```javascript
import rtms from "@zoom/rtms";

// All RTMS start/stop events across products
const RTMS_EVENTS = ["meeting.rtms_started", "webinar.rtms_started", "session.rtms_started"];

// Handle webhook events
rtms.onWebhookEvent(({ event, payload }) => {
  if (!RTMS_EVENTS.includes(event)) return;

  const client = new rtms.Client();

  client.onAudioData((data, timestamp, metadata) => {
    console.log(`Audio from ${metadata.userName}: ${data.length} bytes`);
  });

  client.onTranscriptData((data, timestamp, metadata) => {
    const text = data.toString('utf8');
    console.log(`${metadata.userName}: ${text}`);
  });

  client.onJoinConfirm((reason) => {
    console.log(`Joined session: ${reason}`);
  });

  // SDK handles all WebSocket connections automatically
  // Accepts both meeting_uuid and session_id transparently
  client.join(payload);
});
```

## Quick Start (Manual WebSocket)

For full control or non-SDK languages, implement the two-phase WebSocket protocol:

```javascript
const WebSocket = require('ws');
const crypto = require('crypto');

const RTMS_EVENTS = ['meeting.rtms_started', 'webinar.rtms_started', 'session.rtms_started'];

// 1. Generate signature
// For meetings/webinars: uses meeting_uuid. For Video SDK: uses session_id.
function generateSignature(clientId, idValue, streamId, clientSecret) {
  const message = `${clientId},${idValue},${streamId}`;
  return crypto.createHmac('sha256', clientSecret).update(message).digest('hex');
}

// 2. Handle webhook
app.post('/webhook', (req, res) => {
  res.status(200).send();  // CRITICAL: Respond immediately!
  
  const { event, payload } = req.body;
  if (RTMS_EVENTS.includes(event)) {
    connectToRTMS(payload);
  }
});

// 3. Connect to signaling WebSocket
function connectToRTMS(payload) {
  const { server_urls, rtms_stream_id } = payload;
  // meeting_uuid for meetings/webinars, session_id for Video SDK
  const idValue = payload.meeting_uuid || payload.session_id;
  const signature = generateSignature(CLIENT_ID, idValue, rtms_stream_id, CLIENT_SECRET);
  
  const signalingWs = new WebSocket(server_urls);
  
  signalingWs.on('open', () => {
    signalingWs.send(JSON.stringify({
      msg_type: 1,  // Handshake request
      protocol_version: 1,
      meeting_uuid: idValue,
      rtms_stream_id,
      signature,
      media_type: 9  // AUDIO(1) | TRANSCRIPT(8)
    }));
  });
  
  // ... handle responses, connect to media WebSocket
}
```

**See**: [Manual WebSocket Guide](examples/manual-websocket.md) for complete implementation.

## Media Type Bitmask

Combine types with bitwise OR:

| Type | Value | Description |
|------|-------|-------------|
| Audio | 1 | PCM audio samples |
| Video | 2 | H.264/JPG video frames |
| Screen Share | 4 | **Separate from video!** |
| Transcript | 8 | Real-time speech-to-text |
| Chat | 16 | In-meeting chat messages |
| All | 32 | All media types |

**Example**: Audio + Transcript = `1 | 8` = `9`

## Critical Gotchas

| Issue | Solution |
|-------|----------|
| **Only 1 connection allowed** | New connections kick out existing ones. Track active sessions! |
| **Respond 200 immediately** | If webhook delays, Zoom retries creating duplicate connections |
| **Heartbeat mandatory** | Respond to msg_type 12 with msg_type 13, or connection dies |
| **Reconnection is YOUR job** | RTMS doesn't auto-reconnect. Media keep-alive tolerance is now about **65s**; signaling remains around **60s** |
| **Transcript language drift** | Use `src_language` plus `enable_lid: false` when you want fixed-language transcription instead of automatic language switching |
| **Single participant video only** | `VIDEO_SINGLE_INDIVIDUAL_STREAM` supports one participant at a time. A new `VIDEO_SUBSCRIPTION_REQ` overrides the previous selection |
| **Graceful close is explicit now** | Use `STREAM_CLOSE_REQ` / `STREAM_CLOSE_RESP` when your backend wants to terminate the stream cleanly |

## Environment Variables

### SDK Environment Variables

```bash
# Required - Authentication
ZM_RTMS_CLIENT=your_client_id          # Zoom OAuth Client ID
ZM_RTMS_SECRET=your_client_secret      # Zoom OAuth Client Secret

# Optional - Webhook server
ZM_RTMS_PORT=8080                      # Default: 8080
ZM_RTMS_PATH=/webhook                  # Default: /

# Optional - Logging
ZM_RTMS_LOG_LEVEL=info                 # error, warn, info, debug, trace
ZM_RTMS_LOG_FORMAT=progressive         # progressive or json
ZM_RTMS_LOG_ENABLED=true
```

### Manual Implementation Variables

```bash
ZOOM_CLIENT_ID=your_client_id
ZOOM_CLIENT_SECRET=your_client_secret
ZOOM_SECRET_TOKEN=your_webhook_token   # For webhook validation
```

## Zoom App Setup

### For Meetings and Webinars (General App)

1. Go to [marketplace.zoom.us](https://marketplace.zoom.us) -> Develop -> Build App
2. Choose **General App** -> **User-Managed**
3. Features -> Access -> **Enable Event Subscription**
4. Add Events -> Search "rtms" -> Select:
   - `meeting.rtms_started`
   - `meeting.rtms_stopped`
   - `webinar.rtms_started` (if using webinars)
   - `webinar.rtms_stopped` (if using webinars)
5. Scopes -> Add Scopes -> Search "rtms" -> Add:
   - `meeting:read:meeting_audio`
   - `meeting:read:meeting_video`
   - `meeting:read:meeting_transcript`
   - `meeting:read:meeting_chat`
   - `webinar:read:webinar_audio` (if using webinars)
   - `webinar:read:webinar_video` (if using webinars)
   - `webinar:read:webinar_transcript` (if using webinars)
   - `webinar:read:webinar_chat` (if using webinars)

### For Video SDK (Video SDK App)

1. Go to [marketplace.zoom.us](https://marketplace.zoom.us) -> Develop -> Build App
2. Choose **Video SDK App**
3. Use your SDK Key and SDK Secret (not OAuth Client ID/Secret)
4. Add Events:
   - `session.rtms_started`
   - `session.rtms_stopped`

## Sample Repositories

### Official Samples

| Repository | Description |
|------------|-------------|
| [rtms-samples](https://github.com/zoom/rtms-samples) | RTMSManager, boilerplates, AI samples |
| [rtms-quickstart-js](https://github.com/zoom/rtms-quickstart-js) | JavaScript SDK quickstart |
| [rtms-quickstart-py](https://github.com/zoom/rtms-quickstart-py) | Python SDK quickstart |
| [rtms-sdk-cpp](https://github.com/zoom/rtms-sdk-cpp) | C++ SDK |
| [zoom-rtms](https://github.com/zoom/rtms) | Main SDK repository |

### AI Integration Samples

| Sample | Description |
|--------|-------------|
| [rtms-meeting-assistant-starter-kit](https://github.com/zoom/rtms-meeting-assistant-starter-kit) | AI meeting assistant with summaries |
| [arlo-meeting-assistant](https://github.com/zoom/arlo-meeting-assistant) | Production meeting assistant with DB |
| [videosdk-rtms-transcribe-audio](https://github.com/zoom/videosdk-rtms-transcribe-audio) | Whisper transcription |

## Complete Documentation

### Concepts
- **[Connection Architecture](concepts/connection-architecture.md)** - Two-phase WebSocket design
- **[Lifecycle Flow](concepts/lifecycle-flow.md)** - Webhook to streaming flow

### Examples
- **[SDK Quickstart](examples/sdk-quickstart.md)** - Using @zoom/rtms SDK
- **[Manual WebSocket](examples/manual-websocket.md)** - Raw protocol implementation
- **[RTMS Bot](examples/rtms-bot.md)** - Complete bot implementation guide
- **[AI Integration](examples/ai-integration.md)** - Transcription and analysis patterns

### References
- **[Media Types](references/media-types.md)** - Audio, video, transcript, chat, screen share
- **[Data Types](references/data-types.md)** - All enums and constants
- **[Connection](references/connection.md)** - WebSocket protocol details
- **[Webhooks](references/webhooks.md)** - Event subscription

### Troubleshooting
- **[Common Issues](troubleshooting/common-issues.md)** - FAQ and solutions

## Resources

- **Official docs**: https://developers.zoom.us/docs/rtms/
- **Data types**: https://developers.zoom.us/docs/rtms/data-types/
- **Media params**: https://developers.zoom.us/docs/rtms/media-parameter-definition/
- **Developer forum**: https://devforum.zoom.us/

---

**Need help?** Start with Integrated Index section below for complete navigation.

---

## Integrated Index

_This section was migrated from `SKILL.md`._

RTMS provides real-time access to live audio, video, transcript, chat, and screen share from Zoom meetings, webinars, and Video SDK sessions.

## Critical Positioning

Treat RTMS as a **backend service** for receiving and processing media streams.

- Backend role: ingest audio/video/share/chat/transcript, run AI/analytics, persist/forward data.
- Optional frontend role: Zoom App SDK or web dashboard that consumes processed stream data from backend transport (WebSocket/SSE/other).
- Kickoff model: backend waits for RTMS start webhook events, then starts stream processing.

Do not model RTMS as a frontend-only SDK.

## Quick Start Path

**If you're new to RTMS, follow this order:**

1. **Run preflight checks first** -> [RUNBOOK.md](RUNBOOK.md)
2. **Understand the architecture** -> [concepts/connection-architecture.md](concepts/connection-architecture.md)
   - Two-phase WebSocket: Signaling + Media
   - Why RTMS doesn't use bots

3. **Choose your approach** -> SDK or Manual
   - SDK (recommended): [examples/sdk-quickstart.md](examples/sdk-quickstart.md)
   - Manual WebSocket: [examples/manual-websocket.md](examples/manual-websocket.md)

4. **Understand the lifecycle** -> [concepts/lifecycle-flow.md](concepts/lifecycle-flow.md)
   - Webhook -> Signaling -> Media -> Streaming

5. **Configure media types** -> [references/media-types.md](references/media-types.md)
   - Audio, video, transcript, chat, screen share

6. **Troubleshoot issues** -> [troubleshooting/common-issues.md](troubleshooting/common-issues.md)
   - Connection problems, duplicate webhooks, missing data

---

## Documentation Structure

```
rtms/
├── SKILL.md                           # Main skill overview
├── SKILL.md                           # This file - navigation guide
│
├── concepts/                          # Core architectural patterns
│   ├── connection-architecture.md     # Two-phase WebSocket design
│   └── lifecycle-flow.md              # Webhook to streaming flow
│
├── examples/                          # Complete working code
│   ├── sdk-quickstart.md              # Using @zoom/rtms SDK
│   ├── manual-websocket.md            # Raw protocol implementation
│   ├── rtms-bot.md                    # Complete RTMS bot implementation
│   └── ai-integration.md              # Transcription and analysis
│
├── references/                        # Reference documentation
│   ├── media-types.md                 # Audio, video, transcript, chat, share
│   ├── data-types.md                  # All enums and constants
│   ├── connection.md                  # WebSocket protocol details
│   └── webhooks.md                    # Event subscription
│
└── troubleshooting/                   # Problem solving guides
    └── common-issues.md               # FAQ and solutions
```

---

## By Use Case

### I want to get meeting transcripts
1. [SDK Quickstart](examples/sdk-quickstart.md) - Fastest approach
2. [Media Types](references/media-types.md#transcript) - Transcript configuration
3. [AI Integration](examples/ai-integration.md) - Whisper, Deepgram, AssemblyAI

### I want to record meetings
1. [Media Types](references/media-types.md) - Audio + Video configuration
2. [SDK Quickstart](examples/sdk-quickstart.md) - Receiving media
3. [AI Integration](examples/ai-integration.md#audio-recording) - Gap-filled recording

### I want to build an AI meeting assistant
1. [AI Integration](examples/ai-integration.md) - Complete patterns
2. [SDK Quickstart](examples/sdk-quickstart.md) - Media ingestion
3. [Lifecycle Flow](concepts/lifecycle-flow.md) - Event handling

### I want to build a complete RTMS bot
1. [RTMS Bot](examples/rtms-bot.md) - **Complete implementation guide**
2. [Lifecycle Flow](concepts/lifecycle-flow.md) - Webhook to streaming flow
3. [Connection Architecture](concepts/connection-architecture.md) - Two-phase design

### I need full protocol control
1. [Manual WebSocket](examples/manual-websocket.md) - **START HERE**
2. [Connection Architecture](concepts/connection-architecture.md) - Two-phase design
3. [Data Types](references/data-types.md) - All message types and enums
4. [Connection](references/connection.md) - Protocol details

### I'm getting connection errors
1. [Common Issues](troubleshooting/common-issues.md) - Diagnostic checklist
2. [Connection Architecture](concepts/connection-architecture.md) - Verify flow
3. [Webhooks](references/webhooks.md) - Validation and timing

### I want to understand the architecture
1. [Connection Architecture](concepts/connection-architecture.md) - Two-phase WebSocket
2. [Lifecycle Flow](concepts/lifecycle-flow.md) - Complete flow diagram
3. [Data Types](references/data-types.md) - Protocol constants

---

## By Product

### I'm building for Zoom Meetings
- Standard RTMS setup. Webhook event: `meeting.rtms_started`. Uses General App with OAuth.
- Start with [SDK Quickstart](examples/sdk-quickstart.md) or [Manual WebSocket](examples/manual-websocket.md).

### I'm building for Zoom Webinars
- Same as meetings, but webhook event is `webinar.rtms_started`. Payload still uses `meeting_uuid` (NOT `webinar_uuid`).
- Add webinar scopes and event subscriptions. See [Webhooks](references/webhooks.md).
- Only **panelist** streams are confirmed available. Attendee streams may not be individual.

### I'm building for Zoom Video SDK
- Webhook event: `session.rtms_started`. Payload uses `session_id` (NOT `meeting_uuid`).
- Requires a **Video SDK App** with SDK Key/Secret (not OAuth Client ID/Secret).
- Once connected, the protocol is **identical** to meetings.
- See [Webhooks](references/webhooks.md) for payload details.

---

## Key Documents

### 1. Connection Architecture (CRITICAL)
**[concepts/connection-architecture.md](concepts/connection-architecture.md)**

RTMS uses **two separate WebSocket connections**:
- **Signaling WebSocket**: Authentication, control, heartbeats
- **Media WebSocket**: Actual audio/video/transcript data

### 2. SDK vs Manual (DECISION POINT)
**[examples/sdk-quickstart.md](examples/sdk-quickstart.md)** vs **[examples/manual-websocket.md](examples/manual-websocket.md)**

| SDK | Manual |
|-----|--------|
| Handles WebSocket complexity | Full protocol control |
| Automatic reconnection | DIY reconnection |
| Less code | More code |
| Best for most use cases | Best for custom requirements |

### 3. Critical Gotchas (MOST COMMON ISSUES)
**[troubleshooting/common-issues.md](troubleshooting/common-issues.md)**

1. **Respond 200 immediately** - Delayed webhook responses cause duplicates
2. **Only 1 connection per stream** - New connections kick out existing
3. **Heartbeat required** - Must respond to keep-alive or connection dies
4. **Track active sessions** - Prevent duplicate join attempts

---

## Key Learnings

### Critical Discoveries:

1. **Two-Phase WebSocket Design**
   - Signaling: Control plane (handshake, heartbeat, start/stop)
   - Media: Data plane (audio, video, transcript, chat, share)
   - See: [Connection Architecture](concepts/connection-architecture.md)

2. **Webhook Response Timing**
   - MUST respond 200 BEFORE any processing
   - Delayed response -> Zoom retries -> duplicate connections
   - See: [Common Issues](troubleshooting/common-issues.md#webhook-response-timing)

3. **Heartbeat is Mandatory**
   - Signaling: Receive msg_type 12, respond with msg_type 13
   - Media: Same pattern
   - Failure to respond = connection closed
   - See: [Connection](references/connection.md#heartbeat)

4. **Signature Generation**
   - Format: `HMAC-SHA256(clientSecret, "clientId,meetingUuid,streamId")`
   - For Video SDK, use `session_id` in place of `meetingUuid`
   - Webinars still use `meeting_uuid` (not `webinar_uuid`)
   - Required for both signaling and media handshakes
   - See: [Manual WebSocket](examples/manual-websocket.md#signature-generation)

5. **Media Types are Bitmasks**
   - Audio=1, Video=2, Share=4, Transcript=8, Chat=16, All=32
   - Combine with OR: Audio+Transcript = 1|8 = 9
   - See: [Media Types](references/media-types.md)

6. **Screen Share is SEPARATE from Video**
   - Different msg_type (16 vs 15)
   - Different media flag (4 vs 2)
   - Must subscribe separately
   - See: [Media Types](references/media-types.md#screen-share)

---

## Quick Reference

### "Connection fails"
-> [Common Issues](troubleshooting/common-issues.md)

### "Duplicate connections"
-> [Webhook timing](troubleshooting/common-issues.md#webhook-response-timing)

### "No audio/video data"
-> [Media Types](references/media-types.md) - Check configuration

### "How do I implement manually?"
-> [Manual WebSocket](examples/manual-websocket.md)

### "What message types exist?"
-> [Data Types](references/data-types.md)

### "How do I integrate AI?"
-> [AI Integration](examples/ai-integration.md)

---

## Document Version

Based on **Zoom RTMS SDK v1.x** and official documentation as of 2026.

---

**Happy coding!**

Remember: Start with [SDK Quickstart](examples/sdk-quickstart.md) for the fastest path, or [Manual WebSocket](examples/manual-websocket.md) if you need full control.