From 97298b76f988cc6db60f375fab4c6868dae750a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AD=99=E5=B0=8F=E4=BA=91?= Date: Tue, 9 Dec 2025 15:04:17 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=A0=E9=99=A4=E6=97=A0=E6=95=88=E5=A4=87?= =?UTF-8?q?=E4=BB=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docker/docker-compose.yml | 1 - reademe/ZLM/ZLM_API_GUIDE.md | 561 +++++++++++++++++++++++++++++++++++ reademe/ZLM/ZLM_Protocols.md | 499 +++++++++++++++++++++++++++++++ 3 files changed, 1060 insertions(+), 1 deletion(-) create mode 100644 reademe/ZLM/ZLM_API_GUIDE.md create mode 100644 reademe/ZLM/ZLM_Protocols.md diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index fb07470..d30b662 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -1,4 +1,3 @@ -version: '3' services: polaris-redis: image: ${REGISTRY}redis:latest # 使用官方Redis镜像 diff --git a/reademe/ZLM/ZLM_API_GUIDE.md b/reademe/ZLM/ZLM_API_GUIDE.md new file mode 100644 index 0000000..087e7ec --- /dev/null +++ b/reademe/ZLM/ZLM_API_GUIDE.md @@ -0,0 +1,561 @@ +# ZLMediaKit API 核心概念与使用指南 + +## 一、核心概念解析 + +### 1. 流(Stream)的概念 +在 ZLMediaKit 中,**流**是指一个媒体数据源,由四元组唯一标识: +- **schema**: 协议类型(rtsp/rtmp/rtc等) +- **vhost**: 虚拟主机(通常是 `__defaultVhost__`) +- **app**: 应用名(如 live、rtp) +- **stream**: 流ID(如 test、camera01) + +**完整流标识**: `schema://vhost/app/stream` +例如: `rtsp://__defaultVhost__/live/test` + +### 2. Session(会话) +**Session** 是指客户端与服务器之间的 **TCP/UDP 连接**。 +- 每个播放器连接、推流连接都会创建一个 Session +- Session 包含:连接ID、本地端口、对端IP、协议类型等信息 +- 通过 `getAllSession` 可以查看所有活跃连接 +- 通过 `kick_session` 可以断开指定连接 + +**Session 与 Stream 的关系**: +- 一个 Stream 可以有多个 Session(多个播放器观看同一个流) +- 一个 Session 只对应一个 Stream + +### 3. 拉流代理(StreamProxy) +**拉流代理**是指 ZLMediaKit 作为客户端,从远程服务器拉取流,然后在本地提供服务。 + +**使用场景**: +- 从其他流媒体服务器拉取流到本地 +- 协议转换(拉取 RTMP 流,提供 RTSP/HLS 等多协议播放) +- 流的中转和分发 + +**API**: `addStreamProxy` +``` +GET /index/api/addStreamProxy? + secret=xxx& + vhost=__defaultVhost__& + app=live& + stream=test& + url=rtmp://remote.server.com/live/stream +``` + +**工作原理**: +``` +远程服务器 --拉流--> ZLMediaKit --提供多协议--> 播放器 +(RTMP源) (代理) (RTSP/RTMP/HLS/FLV等) +``` + +### 4. FFmpeg 拉流代理(FFmpegSource) +**FFmpeg 代理**是通过调用 FFmpeg 进程来拉取流,支持更多格式和协议。 + +**与普通拉流代理的区别**: +- **StreamProxy**: 使用 ZLMediaKit 内置播放器,性能高,但支持协议有限 +- **FFmpegSource**: 使用 FFmpeg,支持任意协议/格式,但性能较低,占用资源多 + +**使用场景**: +- 拉取 ZLMediaKit 不支持的协议(如某些特殊 HLS、DASH) +- 需要 FFmpeg 的转码能力 +- 拉取文件流 + +**API**: `addFFmpegSource` +``` +GET /index/api/addFFmpegSource? + secret=xxx& + src_url=http://example.com/live.m3u8& + dst_url=rtmp://127.0.0.1/live/stream& + timeout_ms=10000 +``` + +### 5. 推流代理(StreamPusherProxy) +**推流代理**是指将 ZLMediaKit 上的流推送到其他流媒体服务器。 + +**使用场景**: +- 将本地流推送到 CDN +- 多平台分发(同时推送到多个平台) +- 流的备份 + +**API**: `addStreamPusherProxy` +``` +GET /index/api/addStreamPusherProxy? + secret=xxx& + schema=rtmp& + vhost=__defaultVhost__& + app=live& + stream=test& + dst_url=rtmp://cdn.server.com/live/push +``` + +### 6. 断流(close_stream) +**断流**是指关闭一个媒体流源,而不是断开客户端连接。 + +**断流的含义**: +- 停止流的源头(推流端或拉流代理) +- 所有观看该流的播放器会断开 +- 流从服务器上移除 + +**与 kick_session 的区别**: +- `close_stream`: 关闭流源,影响所有观看者 +- `kick_session`: 只断开某个客户端连接,不影响流本身 + +### 7. RTP 服务器 +**RTP 服务器**用于接收 GB28181 设备推送的 RTP 流。 + +**工作流程**: +1. `openRtpServer`: 创建 RTP 接收端口 +2. GB28181 设备推送 RTP 流到该端口 +3. ZLMediaKit 自动将 RTP 流转换为标准流 +4. 可通过 RTSP/RTMP/HLS 等协议播放 + +--- + +## 二、完整使用流程示例 + +### 场景 1: GB28181 设备推流 +```bash +# 1. 创建 RTP 服务器(监听端口接收 GB28181 推流) +GET /index/api/openRtpServer? + secret=xxx& + port=10000& + tcp_mode=1& + stream_id=camera01 + +# 返回: {"code":0, "port":10000} + +# 2. GB28181 设备推流到 10000 端口(设备端配置) + +# 3. 查看流是否在线 +GET /index/api/isMediaOnline? + secret=xxx& + schema=rtsp& + vhost=__defaultVhost__& + app=rtp& + stream=camera01 + +# 4. 获取流信息(包含所有播放地址) +GET /index/api/getMediaInfo? + secret=xxx& + schema=rtsp& + vhost=__defaultVhost__& + app=rtp& + stream=camera01 + +# 返回包含: +# - RTSP: rtsp://server:554/rtp/camera01 +# - RTMP: rtmp://server:1935/rtp/camera01 +# - HTTP-FLV: http://server:80/rtp/camera01.live.flv +# - HLS: http://server:80/rtp/camera01/hls.m3u8 +# - WebRTC: webrtc://server/rtp/camera01 +``` + +### 场景 2: RTMP 推流 +```bash +# 1. 使用 OBS 或 FFmpeg 推流 +ffmpeg -re -i input.mp4 -c copy -f flv rtmp://server:1935/live/mystream + +# 推流地址格式: rtmp://服务器IP:端口/app/stream +# - app: 应用名(如 live) +# - stream: 流ID(如 mystream) + +# 2. 查看流列表 +GET /index/api/getMediaList?secret=xxx + +# 返回所有在线流,包含: +# { +# "code": 0, +# "data": [{ +# "app": "live", +# "stream": "mystream", +# "vhost": "__defaultVhost__", +# "schema": "rtmp", +# "readerCount": 0, // 观看人数 +# "totalReaderCount": 0, +# "originType": 0, // 0=推流,1=拉流代理,2=点播 +# "originUrl": "", +# "createStamp": 1234567890 +# }] +# } + +# 3. 获取该流的详细信息和播放地址 +GET /index/api/getMediaInfo? + secret=xxx& + schema=rtmp& + vhost=__defaultVhost__& + app=live& + stream=mystream + +# 4. 播放地址: +# - RTSP: rtsp://server:554/live/mystream +# - RTMP: rtmp://server:1935/live/mystream +# - HTTP-FLV: http://server:80/live/mystream.live.flv +# - HLS: http://server:80/live/mystream/hls.m3u8 +# - WebSocket-FLV: ws://server:80/live/mystream.live.flv +``` + +### 场景 3: 录制流 +```bash +# 1. 开始录制(MP4 格式) +GET /index/api/startRecord? + secret=xxx& + type=1& # 0=HLS, 1=MP4 + vhost=__defaultVhost__& + app=live& + stream=mystream& + max_second=3600 # 每小时切片 + +# 2. 检查是否正在录制 +GET /index/api/isRecording? + secret=xxx& + type=1& + vhost=__defaultVhost__& + app=live& + stream=mystream + +# 3. 获取录像文件列表 +GET /index/api/getMp4RecordFile? + secret=xxx& + vhost=__defaultVhost__& + app=live& + stream=mystream& + period=2025-12-09 # 指定日期 + +# 返回: +# { +# "code": 0, +# "data": { +# "paths": [ +# "/path/to/record/live/mystream/2025-12-09/10-30-00.mp4", +# "/path/to/record/live/mystream/2025-12-09/11-30-00.mp4" +# ], +# "rootPath": "/path/to/record" +# } +# } + +# 4. 停止录制 +GET /index/api/stopRecord? + secret=xxx& + type=1& + vhost=__defaultVhost__& + app=live& + stream=mystream +``` + +### 场景 4: 截图 +```bash +# 1. 获取实时截图 +GET /index/api/getSnap? + secret=xxx& + url=rtsp://server/live/mystream& + timeout_sec=10& + expire_sec=60 # 缓存时间 + +# 返回: JPEG 图片数据 + +# 2. 如果配置了定时截图,查看截图列表 +# 截图通常保存在配置的 snap 目录下 +# 目录结构: /snap/vhost/app/stream/timestamp.jpg + +# 3. 删除截图 +GET /index/api/deleteSnapDirectory? + secret=xxx& + vhost=__defaultVhost__& + app=live& + stream=mystream& + file=1234567890.jpg # 可选,不指定则删除整个目录 +``` + +### 场景 5: 下载录像文件 +```bash +# 1. 获取录像文件列表(见场景3) +GET /index/api/getMp4RecordFile? + secret=xxx& + vhost=__defaultVhost__& + app=live& + stream=mystream& + period=2025-12-09 + +# 2. 下载指定文件 +GET /index/api/downloadFile? + file_path=/path/to/record/live/mystream/2025-12-09/10-30-00.mp4& + save_name=mystream_20251209_103000.mp4 + +# 浏览器会直接下载该文件 +``` + +--- + +## 三、API 分类与关系图 + +### 1. 流管理类 +``` +getMediaList # 获取所有流列表 +getMediaInfo # 获取单个流详细信息 +isMediaOnline # 检查流是否在线 +close_stream # 关闭单个流 +close_streams # 批量关闭流 +getMediaPlayerList # 获取流的播放者列表 +``` + +### 2. 连接管理类 +``` +getAllSession # 获取所有TCP/UDP连接 +kick_session # 断开单个连接 +kick_sessions # 批量断开连接 +``` + +### 3. 代理管理类 +``` +# 拉流代理 +addStreamProxy # 添加拉流代理 +delStreamProxy # 删除拉流代理 +listStreamProxy # 列出所有拉流代理 +getProxyInfo # 获取代理详细信息 + +# 推流代理 +addStreamPusherProxy # 添加推流代理 +delStreamPusherProxy # 删除推流代理 +listStreamPusherProxy # 列出所有推流代理 +getProxyPusherInfo # 获取推流代理信息 + +# FFmpeg 代理 +addFFmpegSource # 添加 FFmpeg 拉流 +delFFmpegSource # 删除 FFmpeg 拉流 +listFFmpegSource # 列出所有 FFmpeg 拉流 +``` + +### 4. RTP/GB28181 类 +``` +openRtpServer # 创建 RTP 接收端口 +closeRtpServer # 关闭 RTP 端口 +connectRtpServer # TCP 主动连接模式 +listRtpServer # 列出所有 RTP 服务器 +getRtpInfo # 获取 RTP 推流信息 +updateRtpServerSSRC # 更新 SSRC 过滤 +pauseRtpCheck # 暂停超时检查 +resumeRtpCheck # 恢复超时检查 +``` + +### 5. RTP 推流类 +``` +startSendRtp # 主动模式推送 RTP +startSendRtpPassive # 被动模式推送 RTP +startSendRtpTalk # 双向对讲 +stopSendRtp # 停止推送 RTP +listRtpSender # 列出 RTP 发送器 +``` + +### 6. 录制类 +``` +startRecord # 开始录制 +stopRecord # 停止录制 +isRecording # 检查录制状态 +getMp4RecordFile # 获取录像文件列表 +deleteRecordDirectory # 删除录像目录 +setRecordSpeed # 设置录像播放速度 +seekRecordStamp # 设置录像播放位置 +startRecordTask # 事件录制(前后录制) +``` + +### 7. 截图类 +``` +getSnap # 获取实时截图 +deleteSnapDirectory # 删除截图目录 +``` + +### 8. 文件类 +``` +loadMP4File # 点播 MP4 文件 +downloadFile # 下载文件 +``` + +### 9. 系统管理类 +``` +getApiList # 获取 API 列表 +getServerConfig # 获取服务器配置 +setServerConfig # 设置服务器配置 +restartServer # 重启服务器 +getStatistic # 获取统计信息 +getThreadsLoad # 获取网络线程负载 +getWorkThreadsLoad # 获取后台线程负载 +version # 获取版本信息 +``` + +--- + +## 四、关键流程图 + +### 流的生命周期 +``` +┌─────────────────────────────────────────────────────────┐ +│ 流的来源 │ +├─────────────────────────────────────────────────────────┤ +│ 1. 推流: RTMP/RTSP/WebRTC 推流 │ +│ 2. 拉流代理: addStreamProxy │ +│ 3. FFmpeg 代理: addFFmpegSource │ +│ 4. GB28181: openRtpServer + 设备推流 │ +│ 5. 点播: loadMP4File │ +└─────────────────────────────────────────────────────────┘ + ↓ +┌─────────────────────────────────────────────────────────┐ +│ 流在 ZLMediaKit 中 │ +├─────────────────────────────────────────────────────────┤ +│ - 唯一标识: vhost/app/stream │ +│ - 自动协议转换: RTSP/RTMP/HLS/FLV/WebRTC 等 │ +│ - 可被多个客户端同时播放 │ +│ - 可被录制、截图、转推 │ +└─────────────────────────────────────────────────────────┘ + ↓ +┌─────────────────────────────────────────────────────────┐ +│ 流的消费 │ +├─────────────────────────────────────────────────────────┤ +│ 1. 播放: 多协议播放地址 │ +│ 2. 录制: startRecord │ +│ 3. 截图: getSnap │ +│ 4. 转推: addStreamPusherProxy │ +│ 5. RTP 推送: startSendRtp │ +└─────────────────────────────────────────────────────────┘ + ↓ +┌─────────────────────────────────────────────────────────┐ +│ 流的结束 │ +├─────────────────────────────────────────────────────────┤ +│ 1. 推流端断开 │ +│ 2. 主动关闭: close_stream │ +│ 3. 无人观看超时(配置决定) │ +│ 4. 删除代理: delStreamProxy/delFFmpegSource │ +└─────────────────────────────────────────────────────────┘ +``` + +### GB28181 完整流程 +``` +1. 创建 RTP 服务器 + openRtpServer(port=10000, stream_id=camera01) + ↓ +2. 配置 GB28181 设备推流到 10000 端口 + ↓ +3. 流自动注册为: rtsp://__defaultVhost__/rtp/camera01 + ↓ +4. 查看流信息 + getMediaInfo(schema=rtsp, app=rtp, stream=camera01) + ↓ +5. 获取所有播放地址并播放 + - RTSP: rtsp://server:554/rtp/camera01 + - RTMP: rtmp://server:1935/rtp/camera01 + - HTTP-FLV: http://server/rtp/camera01.live.flv + - HLS: http://server/rtp/camera01/hls.m3u8 + ↓ +6. 录制/截图/转推 + startRecord(app=rtp, stream=camera01) + getSnap(url=rtsp://server/rtp/camera01) + addStreamPusherProxy(app=rtp, stream=camera01, dst_url=...) + ↓ +7. 关闭流 + closeRtpServer(stream_id=camera01) +``` + +--- + +## 五、常见问题 + +### Q1: 如何知道流的 stream_id? +**A**: +- **推流时**: stream_id 由推流端指定(推流地址的最后一部分) +- **GB28181**: 在 `openRtpServer` 时指定 +- **拉流代理**: 在 `addStreamProxy` 时指定 +- **查询**: 使用 `getMediaList` 查看所有在线流 + +### Q2: 流的各种播放地址如何获取? +**A**: 使用 `getMediaInfo` 接口,返回结果包含所有协议的播放地址。 + +### Q3: 录像文件保存在哪里? +**A**: +- 默认路径在配置文件中设置(通常是 `./www/record`) +- 目录结构: `record/vhost/app/stream/日期/时间.mp4` +- 可通过 `getMp4RecordFile` 查询 + +### Q4: 如何实现多平台推流? +**A**: 使用 `addStreamPusherProxy`,同一个流可以添加多个推流代理(不同 dst_url)。 + +### Q5: 拉流代理和 FFmpeg 代理如何选择? +**A**: +- **优先使用拉流代理**: 性能高,资源占用少 +- **使用 FFmpeg 代理的场景**: + - 源协议 ZLMediaKit 不支持 + - 需要转码 + - 需要 FFmpeg 的特殊功能 + +### Q6: 如何实现按需拉流? +**A**: 配置 `on_play` hook,当有人播放时才调用 `addStreamProxy` 拉取源流。 + +--- + +## 六、最佳实践 + +### 1. 流命名规范 +``` +app: 按业务分类(live, record, vod, gb28181) +stream: 使用有意义的ID(camera_01, user_123_live) +``` + +### 2. 录制策略 +``` +- 重要流: 实时录制(startRecord) +- 事件流: 使用 startRecordTask(前后录制) +- 定时录制: 通过配置文件设置 +``` + +### 3. 性能优化 +``` +- 使用拉流代理而非 FFmpeg 代理 +- 合理设置录制切片时间 +- 使用 HLS 时注意切片数量 +- 监控 getThreadsLoad 和 getWorkThreadsLoad +``` + +### 4. 安全建议 +``` +- 修改默认 secret +- 启用推流鉴权(on_publish hook) +- 启用播放鉴权(on_play hook) +- 限制 API 访问 IP +``` + +--- + +## 七、快速参考 + +### 推流地址格式 +``` +RTMP: rtmp://server:1935/app/stream +RTSP: rtsp://server:554/app/stream (需要服务器支持 RTSP 推流) +``` + +### 播放地址格式 +``` +RTSP: rtsp://server:554/app/stream +RTMP: rtmp://server:1935/app/stream +HTTP-FLV: http://server:80/app/stream.live.flv +WebSocket-FLV: ws://server:80/app/stream.live.flv +HLS: http://server:80/app/stream/hls.m3u8 +HTTP-TS: http://server:80/app/stream.live.ts +HTTP-fMP4: http://server:80/app/stream.live.mp4 +WebRTC: webrtc://server/app/stream +``` + +### 常用 API 速查 +```bash +# 查看所有流 +curl "http://server:80/index/api/getMediaList?secret=xxx" + +# 查看流信息 +curl "http://server:80/index/api/getMediaInfo?secret=xxx&schema=rtsp&vhost=__defaultVhost__&app=live&stream=test" + +# 开始录制 +curl "http://server:80/index/api/startRecord?secret=xxx&type=1&vhost=__defaultVhost__&app=live&stream=test" + +# 获取截图 +curl "http://server:80/index/api/getSnap?secret=xxx&url=rtsp://server/live/test&timeout_sec=10" -o snap.jpg + +# 关闭流 +curl "http://server:80/index/api/close_stream?secret=xxx&schema=rtsp&vhost=__defaultVhost__&app=live&stream=test" +``` diff --git a/reademe/ZLM/ZLM_Protocols.md b/reademe/ZLM/ZLM_Protocols.md new file mode 100644 index 0000000..4fb9da0 --- /dev/null +++ b/reademe/ZLM/ZLM_Protocols.md @@ -0,0 +1,499 @@ +# WebRTC 与传统流媒体协议对比详解 + +## 一、协议类型说明 + +### 1. Schema(协议类型)在 ZLMediaKit 中的含义 + +在 ZLMediaKit 中,**schema** 是指流的**传输协议标识**,用于区分同一个流的不同协议版本。 + +``` +完整流标识 = schema://vhost/app/stream + +例如: +- rtsp://__defaultVhost__/live/test +- rtmp://__defaultVhost__/live/test +- rtc://__defaultVhost__/live/test ← WebRTC 的 schema 标识 +``` + +**注意**: `rtc` 是 ZLMediaKit 中 WebRTC 协议的 schema 标识。 + +--- + +## 二、WebRTC vs 传统协议核心区别 + +### 对比表格 + +| 特性 | RTSP | RTMP | HLS | WebRTC (RTC) | +|------|------|------|-----|--------------| +| **传输协议** | TCP/UDP | TCP | HTTP | UDP (SRTP/DTLS) | +| **延迟** | 1-3秒 | 3-5秒 | 10-30秒 | 100-500毫秒 | +| **浏览器支持** | ❌ 需插件 | ❌ 需插件 | ✅ 原生支持 | ✅ 原生支持 | +| **NAT穿透** | ❌ 困难 | ❌ 困难 | ✅ 简单(HTTP) | ✅ 内置(ICE/STUN/TURN) | +| **双向通信** | ❌ 单向 | ❌ 单向 | ❌ 单向 | ✅ 双向 | +| **加密** | 可选(RTSPS) | 可选(RTMPS) | 可选(HTTPS) | ✅ 强制(DTLS-SRTP) | +| **带宽自适应** | ❌ | ❌ | ✅ 切换码率 | ✅ 实时调整 | +| **使用场景** | 监控/录像 | 直播推流 | 点播/直播 | 实时通信/低延迟直播 | + +--- + +## 三、详细对比 + +### 1. RTSP (Real Time Streaming Protocol) + +**特点**: +- 专为流媒体设计的应用层协议 +- 支持 TCP 和 UDP 传输 +- 常用于视频监控、IPTV + +**优点**: +- 延迟低(1-3秒) +- 支持精确的流控制(暂停、快进、定位) +- 带宽占用小 + +**缺点**: +- 浏览器不支持(需要插件或转码) +- NAT 穿透困难(特别是 UDP 模式) +- 防火墙不友好 + +**典型应用**: +```bash +# 推流(需要支持 RTSP 推流的客户端) +rtsp://server:554/live/camera01 + +# 播放(VLC、FFplay 等) +ffplay rtsp://server:554/live/camera01 +``` + +--- + +### 2. RTMP (Real-Time Messaging Protocol) + +**特点**: +- Adobe 开发,基于 TCP +- 曾是直播行业标准 +- Flash 时代的主流协议 + +**优点**: +- 延迟较低(3-5秒) +- 推流稳定 +- 生态成熟(OBS、FFmpeg 等支持) + +**缺点**: +- 浏览器不再支持(Flash 已淘汰) +- 只能单向传输 +- 需要转码才能在浏览器播放 + +**典型应用**: +```bash +# 推流(OBS、FFmpeg) +rtmp://server:1935/live/stream + +# 播放(需要转为 HTTP-FLV 或 HLS) +# 浏览器: http://server/live/stream.live.flv +``` + +--- + +### 3. HLS (HTTP Live Streaming) + +**特点**: +- Apple 开发,基于 HTTP +- 将流切片为小文件(.ts 或 .m4s) +- 通过 .m3u8 索引文件播放 + +**优点**: +- 浏览器原生支持 +- CDN 友好(HTTP 缓存) +- 自适应码率 + +**缺点**: +- 延迟高(10-30秒,取决于切片大小) +- 不适合实时互动 +- 服务器需要存储切片文件 + +**典型应用**: +```bash +# 播放地址 +http://server/live/stream/hls.m3u8 + +# 浏览器中使用 + +``` + +--- + +### 4. WebRTC (Web Real-Time Communication) + +**特点**: +- Google 主导的开放标准 +- 专为实时通信设计 +- 基于 UDP,使用 SRTP 加密 + +**核心技术栈**: +``` +应用层: WebRTC API (getUserMedia, RTCPeerConnection) + ↓ +信令层: SDP (会话描述) + ICE (连接协商) + ↓ +传输层: SRTP (加密的 RTP) + DTLS (密钥交换) + ↓ +网络层: UDP + ICE/STUN/TURN (NAT 穿透) +``` + +**优点**: +- ✅ **超低延迟**(100-500ms,最低可达 100ms) +- ✅ **浏览器原生支持**(无需插件) +- ✅ **双向通信**(音视频通话、屏幕共享) +- ✅ **强制加密**(DTLS-SRTP) +- ✅ **NAT 穿透**(ICE/STUN/TURN) +- ✅ **带宽自适应**(实时调整码率) +- ✅ **抗丢包**(FEC、NACK、JitterBuffer) + +**缺点**: +- ❌ 服务器实现复杂(需要信令服务器) +- ❌ 带宽消耗较大(UDP 开销) +- ❌ 不适合大规模单向直播(推荐用 HLS/FLV) +- ❌ 需要 HTTPS(浏览器安全限制) + +**典型应用**: +```javascript +// 浏览器播放 WebRTC 流 +const pc = new RTCPeerConnection(); + +// 1. 获取 Offer(从信令服务器) +const offer = await fetch('http://server/webrtc/offer?app=live&stream=test'); + +// 2. 设置远端描述 +await pc.setRemoteDescription(new RTCSessionDescription(offer)); + +// 3. 创建 Answer +const answer = await pc.createAnswer(); +await pc.setLocalDescription(answer); + +// 4. 发送 Answer 到服务器 +await fetch('http://server/webrtc/answer', { + method: 'POST', + body: JSON.stringify(answer) +}); + +// 5. 接收媒体流 +pc.ontrack = (event) => { + videoElement.srcObject = event.streams[0]; +}; +``` + +--- + +## 四、ZLMediaKit 中的 Schema 使用 + +### 1. Schema 的作用 + +在 ZLMediaKit 中,**同一个流可以同时以多种协议提供服务**,schema 用于区分: + +```bash +# 同一个流的不同协议版本 +rtsp://__defaultVhost__/live/test # RTSP 协议 +rtmp://__defaultVhost__/live/test # RTMP 协议 +rtc://__defaultVhost__/live/test # WebRTC 协议 + +# 它们共享同一个媒体源,只是传输协议不同 +``` + +### 2. API 中的 Schema 参数 + +```bash +# 查询流信息时需要指定 schema +GET /index/api/getMediaInfo? + secret=xxx& + schema=rtsp& # 指定协议类型 + vhost=__defaultVhost__& + app=live& + stream=test + +# 不同 schema 返回的信息可能不同: +# - rtsp: 返回 RTSP 相关信息(RTP 统计等) +# - rtmp: 返回 RTMP 相关信息(chunk size 等) +# - rtc: 返回 WebRTC 相关信息(ICE 状态、DTLS 等) +``` + +### 3. 关闭流时的 Schema + +```bash +# 关闭特定协议的流 +GET /index/api/close_stream? + secret=xxx& + schema=rtsp& # 只关闭 RTSP 协议 + vhost=__defaultVhost__& + app=live& + stream=test + +# 注意:关闭一个 schema 会影响所有协议 +# 因为它们共享同一个媒体源 +``` + +--- + +## 五、WebRTC 在 ZLMediaKit 中的特殊性 + +### 1. WebRTC 的双重身份 + +WebRTC 在 ZLMediaKit 中既是**协议**,也是**技术栈**: + +``` +作为协议 (schema=rtc): + - 用于标识 WebRTC 传输的流 + - 在 API 中使用 schema=rtc 查询 + +作为技术栈: + - 包含信令、ICE、DTLS、SRTP 等完整实现 + - 需要特殊的 API 端点(/index/api/webrtc) +``` + +### 2. WebRTC 专用 API + +ZLMediaKit 为 WebRTC 提供了专门的 API: + +```bash +# 1. 播放 WebRTC 流(浏览器端) +POST /index/api/webrtc? + app=live& + stream=test& + type=play + +# 请求体: SDP Offer +# 返回: SDP Answer + +# 2. 推流到 WebRTC(浏览器端) +POST /index/api/webrtc? + app=live& + stream=test& + type=push + +# 3. WebRTC 信令服务器相关 +addWebrtcRoomKeeper # 注册到信令服务器 +delWebrtcRoomKeeper # 从信令服务器注销 +listWebrtcRoomKeepers # 查看注册信息 +listWebrtcRooms # 查看房间信息 + +# 4. 广播消息(DataChannel) +broadcastMessage # 向所有 WebRTC 播放器广播消息 +``` + +### 3. WebRTC 流的生命周期 + +``` +┌─────────────────────────────────────────────────────┐ +│ WebRTC 推流(浏览器 → 服务器) │ +├─────────────────────────────────────────────────────┤ +│ 1. 浏览器创建 RTCPeerConnection │ +│ 2. 生成 SDP Offer │ +│ 3. POST /index/api/webrtc?type=push │ +│ 4. 服务器返回 SDP Answer │ +│ 5. ICE 候选交换 │ +│ 6. DTLS 握手 + SRTP 密钥协商 │ +│ 7. 媒体流传输(UDP/SRTP) │ +│ 8. 流注册为: rtc://__defaultVhost__/live/test │ +└─────────────────────────────────────────────────────┘ + ↓ +┌─────────────────────────────────────────────────────┐ +│ 协议自动转换(ZLMediaKit 核心能力) │ +├─────────────────────────────────────────────────────┤ +│ WebRTC 推流后,自动提供多协议播放: │ +│ - rtc://server/live/test (WebRTC) │ +│ - rtsp://server/live/test (RTSP) │ +│ - rtmp://server/live/test (RTMP) │ +│ - http://server/live/test.flv (HTTP-FLV) │ +│ - http://server/live/test/hls.m3u8 (HLS) │ +└─────────────────────────────────────────────────────┘ + ↓ +┌─────────────────────────────────────────────────────┐ +│ WebRTC 播放(服务器 → 浏览器) │ +├─────────────────────────────────────────────────────┤ +│ 1. 浏览器创建 RTCPeerConnection │ +│ 2. 生成 SDP Offer │ +│ 3. POST /index/api/webrtc?type=play │ +│ 4. 服务器返回 SDP Answer │ +│ 5. ICE 候选交换 │ +│ 6. DTLS 握手 + SRTP 密钥协商 │ +│ 7. 接收媒体流(UDP/SRTP) │ +│ 8. 渲染到