关于 zoom-rtms
zoom-rtms 是面向开发者的技术参考技能,用于构建接收 Zoom 会议、网络研讨会、Video SDK 会话及 Contact Center Voice 实时媒体的后端管道,介绍 SDK、WebSocket、事件和实现限制。
主要功能
- 01实时音频、视频、转录、聊天与屏幕共享流
- 02由 Webhook 触发的流生命周期
- 03SDK 与手动 WebSocket 接入方式
- 04支持会议、网络研讨会、Video SDK 和 Contact Center Voice
- 05连接、心跳与重连指引
适用场景
- 01接收会议音频和转录以供分析
- 02采集屏幕共享与视频帧
- 03构建 Zoom 会话后端媒体管道
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ anthropics/ knowledge-work-plugins --skill zoom-rtms安装后在 Claude Code 中输入/zoom-rtms确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
RUNBOOK.mdconcepts/connection-architecture.mdlifecycle-flow.mdexamples/ai-integration.mdmanual-websocket.mdrtms-bot.mdsdk-quickstart.mdreferences/connection.mddata-types.mdenvironment-variables.mdmedia-types.mdquickstart.mdwebhooks.mdtroubleshooting/common-issues.md详细介绍
Zoom 实时媒体流(RTMS)
本文档是 Zoom 实时媒体管线的背景参考资料。请先使用 build-zoom-bot,再根据需要使用本 skill 了解流类型、能力以及 RTMS 特定的实现约束。
Zoom 实时媒体流(RTMS)
提供实时访问 Zoom 会议、网络研讨会、Video SDK 会话以及 Zoom 联络中心语音中音频、视频、转录、聊天和屏幕共享数据的专业指导。RTMS 采用基于 WebSocket 的协议,遵循开放标准,捕获媒体平面时无需会议机器人。
请先阅读(重要)
RTMS 主要是一项后端媒体接入服务。
- 你的后端接收并处理实时媒体:音频、视频、屏幕共享、聊天、转录。
- RTMS 本身并不是前端 UI SDK。
- 处理是事件触发的:后端需等待 RTMS 开始 webhook 事件,之后才开始流处理。
可选架构(常见做法):
- 添加 Zoom App SDK 前端,用于客户端内的 UI 和控件。
- 通过 WebSocket(或 SSE、gRPC、队列 worker 等)将后端 RTMS 输出推送到前端。
将 RTMS 用于媒体/数据平面,并使用前端框架或 Zoom App 负责展示和用户交互。
官方文档:https://developers.zoom.us/docs/rtms/ SDK 参考(JS):https://zoom.github.io/rtms/js/ SDK 参考(Python):https://zoom.github.io/rtms/py/ 示例仓库:https://github.com/zoom/rtms-samples
快速链接
初次使用 RTMS?请按以下路径操作:
- 连接架构 - 两阶段 WebSocket 设计
- SDK 快速入门 - 接收媒体最快的方式(推荐)
- 手动 WebSocket - 不使用 SDK,完全控制协议
- 媒体类型 - 音频、视频、转录、聊天、屏幕共享
完整实现:
- RTMS 机器人 - 端到端机器人实现指南
参考资料:
- 生命周期流程 - 从 webhook 到流传输的完整流程
- 数据类型 - 所有枚举和常量
- Webhooks - 事件订阅详情
- 环境变量 - 凭据模式和运行时配置项
- 快速入门补充说明 - 次要快速入门指南
- 集成索引 - 见本文件下方的章节
遇到问题?
- 连接失败 -> 常见问题
- 重复连接 -> Webhook 注意事项
- 没有音频/视频 -> 媒体配置
- 先进行预检 -> 5 分钟运行手册
支持的产品
| 产品 | Webhook 事件 | Payload ID | 应用类型 |
|---|---|---|---|
| 会议 | meeting.rtms_started / meeting.rtms_stopped | meeting_uuid | 通用应用 |
| 网络研讨会 | webinar.rtms_started / webinar.rtms_stopped | meeting_uuid(相同!) | 通用应用 |
| Video SDK | session.rtms_started / session.rtms_stopped | session_id | Video SDK 应用 |
| Zoom 联络中心语音 | 产品特定的 RTMS/ZCC Voice 事件 | 产品特定的流/会话标识符 | 联络中心 / 已获批准的 RTMS 集成 |
连接建立后,核心信令/媒体 socket 模型在各产品之间是共享的。会议、网络研讨会和 Video SDK 会话使用熟悉的开始/停止 webhook。Zoom 联络中心语音则有自己的 RTMS/ZCC Voice 事件体系,应视为采用相同的传输模型,但事件载荷因产品而异。
RTMS 概述
RTMS 是一个数据管道,可让你的应用访问 Zoom 会议、网络研讨会和 Video SDK 会话中的实时媒体,无需参会机器人。无需让自动化客户端加入会议,而是直接从 Zoom 基础设施收集媒体数据。
RTMS 提供的功能
| 媒体类型 | 格式 | 使用场景 |
|---|---|---|
| 音频 | PCM (L16)、G.711、G.722、Opus | 转录、语音分析、录制 |
| 视频 | H.264、JPG、PNG | 录制、AI 视觉、缩略图、活跃参会者选择 |
| 屏幕共享 | H.264、JPG、PNG | 内容捕获、幻灯片提取 |
| 转录文本 | JSON 文本 | 会议纪要、搜索、合规 |
| 聊天 | JSON 文本 | 存档、情感分析 |
2026 年 3 月协议变更
- Zoom Contact Center Voice 支持:RTMS 现已覆盖 Contact Center Voice 的音频和转录文本场景。
- 转录语言识别控制:转录媒体握手现已支持
src_language和enable_lid。默认行为为启用 LID。设置enable_lid: false可强制使用固定语言。 - 单个参会者视频流订阅:当
data_opt设置为VIDEO_SINGLE_INDIVIDUAL_STREAM时,RTMS 现可一次推送一位参会者的摄像头画面。 - 客户端主动优雅关闭:后端可通过信令套接字发送
STREAM_CLOSE_REQ,并等待STREAM_CLOSE_RESP。 - 媒体保活容忍度提高:媒体套接字保活超时现为 65 秒,不再是 35 秒。
两种方式
| 方式 | 适用场景 | 复杂度 |
|---|---|---|
SDK(@zoom/rtms) | 大多数场景 | 低,已处理 WebSocket 的复杂性 |
| 手动 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 端点
- 用于接收 WebSocket 流的服务器
需要 RTMS 访问权限? 请在 Zoom Developer Forum 发帖,说明你的使用场景并申请 RTMS 访问权限。
快速开始(SDK,推荐)
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);
});
快速开始(手动 WebSocket)
如需完全控制或使用非 SDK 语言,请实现两阶段 WebSocket 协议:
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
}
参见:手动 WebSocket 指南,获取完整实现。
媒体类型位掩码
使用按位或组合类型:
| 类型 | 值 | 说明 |
|---|---|---|
| 音频 | 1 | PCM 音频采样 |
| 视频 | 2 | H.264/JPG 视频帧 |
| 屏幕共享 | 4 | 与视频分开! |
| 转录文本 | 8 | 实时语音转文字 |
| 聊天 | 16 | 会议内聊天消息 |
| 全部 | 32 | 所有媒体类型 |
示例:音频 + 转录文本 = 1 | 8 = 9
关键注意事项
| 问题 | 解决方案 |
|---|---|
| 仅允许 1 个连接 | 新连接会踢掉已有连接。务必跟踪活跃会话! |
| 立即返回 200 | 如果 Webhook 延迟响应,Zoom 会重试,从而产生重复连接 |
| 必须发送心跳 | 收到 msg_type 12 时须回复 msg_type 13,否则连接会断开 |
| 重连需自行处理 | RTMS 不会自动重连。媒体保活容忍度现约为 65 秒;信令约为 60 秒 |
| 转录语言漂移 | 当你需要固定语言转录而非自动切换语言时,请同时使用 src_language 和 enable_lid: false |
| 仅支持单个参会者视频 | VIDEO_SINGLE_INDIVIDUAL_STREAM 一次仅支持一位参会者。新的 VIDEO_SUBSCRIPTION_REQ 会覆盖之前的选择 |
| 优雅关闭需显式调用 | 当后端需要干净地终止流时,请使用 STREAM_CLOSE_REQ / STREAM_CLOSE_RESP |
环境变量
SDK 环境变量
# 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
手动实现变量
ZOOM_CLIENT_ID=your_client_id
ZOOM_CLIENT_SECRET=your_client_secret
ZOOM_SECRET_TOKEN=your_webhook_token # For webhook validation
Zoom 应用设置
会议与网络研讨会(通用应用)
- 访问 marketplace.zoom.us -> Develop -> Build App
- 选择 General App -> User-Managed
- Features -> Access -> 开启 Enable Event Subscription
- Add Events -> 搜索 "rtms" -> 选择:
meeting.rtms_startedmeeting.rtms_stoppedwebinar.rtms_started(如使用网络研讨会)webinar.rtms_stopped(如使用网络研讨会)
- Scopes -> Add Scopes -> 搜索 "rtms" -> 添加:
meeting:read:meeting_audiomeeting:read:meeting_videomeeting:read:meeting_transcriptmeeting:read:meeting_chatwebinar:read:webinar_audio(如使用网络研讨会)webinar:read:webinar_video(如使用网络研讨会)webinar:read:webinar_transcript(如使用网络研讨会)webinar:read:webinar_chat(如使用网络研讨会)
Video SDK(Video SDK 应用)
- 访问 marketplace.zoom.us -> Develop -> Build App
- 选择 Video SDK App
- 使用你的 SDK Key 和 SDK Secret(而非 OAuth Client ID/Secret)
- Add Events:
session.rtms_startedsession.rtms_stopped
示例仓库
官方示例
| 仓库 | 描述 |
|---|---|
| rtms-samples | RTMSManager、项目模板、AI 示例 |
| rtms-quickstart-js | JavaScript SDK 快速入门 |
| rtms-quickstart-py | Python SDK 快速入门 |
| rtms-sdk-cpp | C++ SDK |
| zoom-rtms | 主 SDK 仓库 |
AI 集成示例
| 示例 | 描述 |
|---|---|
| rtms-meeting-assistant-starter-kit | 带摘要功能的 AI 会议助手 |
| arlo-meeting-assistant | 带数据库的生产级会议助手 |
| videosdk-rtms-transcribe-audio | Whisper 转录 |
完整文档
概念
示例
- SDK 快速入门 - 使用 @zoom/rtms SDK
- 手动 WebSocket - 原始协议实现
- RTMS 机器人 - 完整的机器人实现指南
- AI 集成 - 转录与分析模式
参考
故障排查
- 常见问题 - 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/
需要帮助? 请从下方的综合索引部分开始浏览完整导航。
综合索引
本节内容迁移自 SKILL.md。
RTMS 提供对 Zoom 会议、网络研讨会和 Video SDK 会话中实时音频、视频、转录、聊天及屏幕共享内容的实时访问。
关键定位
将 RTMS 视为用于接收和处理媒体流的后端服务。
- 后端角色:接收音频/视频/共享屏幕/聊天/转录内容,运行 AI/分析,持久化或转发数据。
- 可选前端角色:Zoom App SDK 或 Web 仪表板,从后端传输层(WebSocket/SSE/其他)获取已处理的流数据。
- 启动方式:后端等待 RTMS 开始 webhook 事件,然后开始处理流。
请勿将 RTMS 建模为纯前端 SDK。
快速入门路径
如果你是 RTMS 新手,请按以下顺序操作:
-
先运行预检 -> RUNBOOK.md
-
了解架构 -> concepts/connection-architecture.md
- 两阶段 WebSocket:信令 + 媒体
- 为什么 RTMS 不使用机器人
-
选择你的方式 -> SDK 或手动
- SDK(推荐):examples/sdk-quickstart.md
- 手动 WebSocket:examples/manual-websocket.md
-
了解生命周期 -> concepts/lifecycle-flow.md
- Webhook -> 信令 -> 媒体 -> 流式传输
-
配置媒体类型 -> references/media-types.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
按使用场景
我想获取会议转录
我想录制会议
我想构建 AI 会议助手
我想构建完整的 RTMS 机器人
我需要完全掌控协议
- 手动 WebSocket - 从这里开始
- 连接架构 - 两阶段设计
- 数据类型 - 所有消息类型和枚举
- 连接 - 协议细节
我遇到连接错误
我想了解架构
按产品
我正在为 Zoom Meetings 开发
- 标准 RTMS 设置。Webhook 事件:
meeting.rtms_started。使用带 OAuth 的 General App。 - 从 SDK 快速入门 或 手动 WebSocket 开始。
我正在为 Zoom Webinars 开发
- 与会议相同,但 webhook 事件为
webinar.rtms_started。负载仍使用meeting_uuid(而非webinar_uuid)。 - 添加 webinar 权限范围和事件订阅。参见 Webhooks。
- 目前只确认**主讲人(panelist)**流可用。参会者流可能无法单独获取。
我正在为 Zoom Video SDK 开发
- Webhook 事件:
session.rtms_started。负载使用session_id(而非meeting_uuid)。 - 需要一个带有 SDK Key/Secret 的 Video SDK App(而非 OAuth Client ID/Secret)。
- 连接之后,协议与会议完全相同。
- 负载详情请参阅 Webhooks。
核心文档
1. 连接架构(关键)
concepts/connection-architecture.md
RTMS 使用两个独立的 WebSocket 连接:
- 信令 WebSocket:身份验证、控制、心跳
- 媒体 WebSocket:实际的音频、视频、转录数据
2. SDK 与手动实现(决策点)
examples/sdk-quickstart.md 对比 examples/manual-websocket.md
| SDK | 手动 |
|---|---|
| 处理 WebSocket 的复杂性 | 完全掌控协议 |
| 自动重连 | 需自行实现重连 |
| 代码更少 | 代码更多 |
| 适合大多数场景 | 适合定制需求 |
3. 关键陷阱(最常见问题)
troubleshooting/common-issues.md
- 立即返回 200 - 延迟的 Webhook 响应会导致重复连接
- 每个流只允许 1 个连接 - 新连接会踢掉已有连接
- 必须发送心跳 - 必须响应保活消息,否则连接会断开
- 跟踪活跃会话 - 防止重复的加入尝试
关键经验
重要发现:
-
双阶段 WebSocket 设计
- 信令:控制平面(握手、心跳、启动/停止)
- 媒体:数据平面(音频、视频、转录、聊天、共享)
- 参见:连接架构
-
Webhook 响应时机
- 必须在进行任何处理之前返回 200
- 响应延迟 -> Zoom 重试 -> 重复连接
- 参见:常见问题
-
心跳是强制性的
- 信令:收到 msg_type 12,回复 msg_type 13
- 媒体:相同模式
- 未响应则连接关闭
- 参见:连接
-
签名生成
- 格式:
HMAC-SHA256(clientSecret, "clientId,meetingUuid,streamId") - 对于 Video SDK,使用
session_id代替meetingUuid - 研讨会仍使用
meeting_uuid(而非webinar_uuid) - 信令和媒体握手均需要
- 参见:手动 WebSocket
- 格式:
-
媒体类型为位掩码
- Audio=1、Video=2、Share=4、Transcript=8、Chat=16、All=32
- 使用按位或组合:Audio+Transcript = 1|8 = 9
- 参见:媒体类型
-
屏幕共享与视频是分开的
- 不同的 msg_type(16 与 15)
- 不同的媒体标志(4 与 2)
- 必须单独订阅
- 参见:媒体类型
快速参考
"连接失败"
-> 常见问题
"重复连接"
-> Webhook 时机
"没有音频/视频数据"
-> 媒体类型 - 检查配置
"如何手动实现?"
-> 手动 WebSocket
"有哪些消息类型?"
-> 数据类型
"如何集成 AI?"
-> AI 集成
文档版本
基于 Zoom RTMS SDK v1.x 以及截至 2026 年的官方文档。
编码愉快!
请记住:如需最快上手,请从 SDK 快速入门 开始;如需完全掌控,请选择 手动 WebSocket。