Files
kra-new/docs/LIVE.md
T
2026-09-23 17:42:55 +08:00

158 lines
8.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Go WebRTC Live
直播功能使用 Pion WebRTC,在现有 GVA WebSocket 和 JWT 用户体系上实现单主播、多观众的 SFU 转发。
## WebSocket
连接现有 WebSocket 地址(后端默认 `/ws`,生产反向代理地址为 `/api/ws`)。观看直播允许匿名握手;PC 登录后的 HttpOnly Cookie 会随同源握手自动发送,分享链接中不携带凭证。非浏览器客户端也可携带 GVA JWT:
```text
wss://host/ws?token=<x-token>
```
连接后发送:
```json
{"type":"Join","payload":{"role":"publisher","streamId":"room-1"}}
```
角色支持 `publisher`、`subscriber`、`observer`。`subscriber` 可匿名加入正在直播的房间;离线录播直接使用 HTTP 视频地址,不创建 WebRTC 观众连接。`publisher` 必须登录且只能发布自己绑定的启用直播间,分类也必须启用;允许从未开播状态开始推流。主播和观众完成 Join 后,浏览器发送 SDP offer:
```json
{"type":"Offer","payload":{"type":"offer","sdp":"v=0..."}}
```
服务端返回 `Answer`。主播使用发送方向的 transceiver,观众使用接收方向的 transceiver。媒体轨道由 Pion 在服务端复制给同一房间的所有观众。
其他消息:
- `Heartbeat` / `HeartbeatAck`
- `PublisherStatus`
- `NewProducer`
- `ProducerClosed`
- `NewSubscriber`
- `SubscriberLeft`
- `StreamListUpdate`
- `Kicked`
- `ChatMessage`:普通聊天广播
- `GiftMessage`:送礼成功后的礼物广播
发送聊天消息:
```json
{"type":"ChatSend","payload":{"content":"大家好"}}
```
聊天只允许已经以主播或观众身份加入该房间的登录用户发送,内容最多 50 个字符。消息只保存在当前服务进程内,每个房间最多 100 条;加入房间不会回放进入前的消息,开播、关播或服务重启都会清空该房间聊天。
主播和观众 45 秒没有心跳会被清理,直播房间最多 20 个;同一用户在同一房间重复观看时,旧连接会收到 `Kicked`。
## HTTP
公开列表接口:
```text
GET /live/streams
GET /live/streams/:streamId
GET /live/categories
GET /live/rooms?page=1&pageSize=20&categoryId=1&orderBy=viewer_count_desc
GET /live/rooms/:id
POST /live/rooms/:id/like
GET /live/rooms/:id/messages?limit=100
GET /live/gifts
GET /live/recharge/providers
GET /live/recharge/plans
```
`/live/rooms` 默认返回所有公开启用的房间,包括直播中、配置录播的离线房间、尚未开播的房间。停用房间、停用或已删除分类下的房间不公开。接口按在线人数倒序排列,再分页;支持 `categoryId`、`page`、`pageSize`、`orderBy`,显式传入 `status=live` 或 `status=offline` 时才限制直播状态。
`/live/categories` 的返回记录就是 PC 分类来源,客户端只额外增加“全部”,按分类 ID 筛选,不依赖固定分类名称。列表直接展示接口的 `viewerCountText`(如 `5.1k`、`1.0w`)。
`GET /live/rooms/:id` 同样允许访问公开的离线房间,并返回 `replayUrl`;未开播不再返回 `LIVE_ROOM_NOT_LIVE`。客户端在 `status=live` 时使用直播流或 WebRTC,离线时使用 `replayUrl`,未配置录播则显示封面和未开播状态。停用房间返回 `LIVE_ROOM_DISABLED`,停用分类返回 `LIVE_CATEGORY_DISABLED`。
聊天历史 HTTP 接口保留用于客户端契约兼容,但验证房间后始终返回空列表,不会向新进入用户泄露此前聊天。
PC 客户端账号接口:
```text
POST /live/client/auth/register
POST /live/client/auth/login
POST /live/client/auth/logout
GET /live/client/me
GET /live/client/balance
PUT /live/client/me
PUT /live/client/me/password
```
客户端账号使用系统的 `sys_users` 表。注册昵称可选,未填写时使用用户名,填写时限制为 2–16 个字符;新账号创建普通直播角色并初始化 100 钻石,历史账号缺少钱包时也补建 100 钻石。注册和修改密码都会返回新的 JWT 登录态。
登录后可调用:
```text
GET /live/rooms/:id/follow
POST /live/rooms/:id/follow
DELETE /live/rooms/:id/follow
POST /live/rooms/:id/gifts
POST /live/recharge/orders
GET /live/recharge/orders/:orderNo
GET /live/recharge/orders/:orderNo/status
```
点赞不要求登录,但仅允许正在直播的公开房间;服务端点赞数在当前进程的直播运行态中累加。PC 保留本次访问的点赞状态,不生成随机点赞。关注关系按直播用户和房间保存,登录后可查询、关注或取消关注。
创建充值订单直接接入 KRA 通用支付订单,请求使用支付模块的渠道标识:
```json
{
"planId": 1,
"provider": "wechat-v3",
"notifyUrl": "https://example.com/api/payment/callback/wechat-v3",
"returnUrl": "https://example.com/recharge/result"
}
```
充值档位、用户和钻石数量保存在直播业务订单中;渠道交易号、支付状态、回调、退款状态和事件流水统一保存在 KRA 的 `pay_orders` / `pay_events`。支付确认后由通用支付发货流程幂等增加钻石余额。
礼物数量允许 `1..9999`,礼物接口返回的 `tiers` 仅作为快捷数量。服务端会拒绝向未开播房间送礼;扣款、礼物流水和钱包余额在同一事务内完成,余额不会小于 0。余额不足时返回 `required`、`balance` 和 `missing`,供客户端打开充值流程;成功后通过 `GiftMessage` 广播给房间内在线用户。
PC 只展示接口返回的礼物,不补造礼物 ID、价格或随机聊天。赠送按钮在请求期间防止重复提交。充值只有确认 `creditedAt` 并刷新余额后才视为到账;余额足够时继续原先选择的礼物一次,仍不足则显示差额并允许继续充值。关闭充值弹窗、离开房间、切换账号或关播会取消尚未执行的赠送意图,迟到的响应不会重新打开弹窗或自动扣款。已提交支付的真实到账结果仍以服务端订单和钱包为准。
全站设置继续保存在 `live_settings`。字典用于稳定的枚举和下拉选项,不适合承载站点名称、公告、功能开关、兑换比例等需要类型校验和运行时读取的配置。
直播状态和在线连接是进程内状态,行为与旧项目一致;服务重启后房间自动清空。
## PC 与后台
- PC 观众页:`/#/live/:id`。
- PC 主播页:`/#/studio/:id`,使用房间绑定的主播账号登录。提供设备预览、摄像头和麦克风选择、音视频开关、开始与停止直播。
- 后台保存房间后立即展示可复制链接,房间列表也可复制主播或观众链接。默认 PC 在域名根路径,后台位于 `/admin/`;独立域名或开发端口使用后台构建变量 `VITE_LIVE_CLIENT_URL`。
- 链接不含 token。后台不再保留观众送礼页面;后台直播诊断和管理详情使用管理接口,不受房间是否正在直播的限制。
- 摄像头需要 HTTPS 或 localhost;播放和推流失败时显示错误并释放失效会话,后续可重新连接。
- API 返回的相对媒体路径默认经 `/api` 加载,已带 `/api` 的路径不会重复拼接;绝对 CDN 地址保持不变。独立文件服务可设置 PC 构建变量 `VITE_FILE_BASE`。
`frontend/` 是独立 Git 仓库,主仓库中的 `web/` 是管理后台。发布本次修复时需要分别更新 PC、后台与 Go 服务,不能只发布其中一个。
## 本地验收
`tmp/live_acceptance/` 包含可复跑的隔离接口验收程序,固定访问 `127.0.0.1:18080`,仅操作 `.tmp-live-acceptance/acceptance.db`。测试配置、账号、模拟支付密钥和报告都保存在被忽略的 `.tmp-live-acceptance/` 下,不写入生产配置,也不删除已有业务数据库。
在隔离服务和本地支付模拟服务运行后执行:
```text
go run ./tmp/live_acceptance verify
```
验收覆盖后台管理、注册登录、权限、双用户实时聊天、60 秒以上连接保活、送礼事务、余额不足、充值订单归属、签名回调与重复回调,并直接核对 SQLite 钱包、礼物流水、充值记录和不持久化的聊天表。支付模拟仅用于本地验证,不代表实际商户渠道或公网跨网络 WebRTC 已验收。
## 网络配置
默认使用 Pion 主机候选。生产环境可以配置:
```text
KRA_LIVE_STUN_URL=stun:stun.example.com:3478
KRA_LIVE_UDP_MIN_PORT=40000
KRA_LIVE_UDP_MAX_PORT=49999
```
配置 UDP 端口范围后,需要在防火墙或容器网络中放行对应端口。