Files
im_server/docs/third/IM-声网音视频通话接入文档.md
T

321 lines
13 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.
# IM 声网音视频通话接入文档
更新时间:2026-09-01
## 1. 接入目标
本次接入目标是把 IM 的一对一语音/视频通话媒体能力从原 WebRTC 直连方案切到声网 RTC。IM Server 继续负责账号、租户、好友/黑名单、通话状态、WebSocket 信令和通话记录;声网只负责音视频媒体频道、音视频流传输和后续可选的媒体质量能力。
首期按声网调试账号接入,只使用 `app_id`,不生成 RTC Token。正式上线时再启用 App 证书,由 IM Server 按频道和用户生成 RTC Token。
## 2. 系统边界
| 模块 | 责任 |
| --- | --- |
| IM Server | 校验登录态、租户、好友/黑名单和通话权限;生成 `call_id`、声网频道名、声网 UID;维护通话状态和通话记录;通过 WebSocket 下发邀请、接听、挂断等信令。 |
| 前端客户端 | 集成声网 RTC SDK;从 IM Server 获取声网入会配置;使用 `app_id/channel_name/uid/token` 加入声网频道;通过 IM WebSocket 发送通话业务事件。 |
| HotGo/Admin | 保存声网第三方配置;后续可提供项目、证书、开关等管理入口。 |
| 声网 RTC | 提供音视频实时媒体通道。 |
| 声网控制台 REST API | 可选,用于服务端创建项目、查询项目、启停项目、启停或重置主要 App 证书。首期不强依赖。 |
## 3. 声网账号与配置准备
### 3.1 调试模式必须准备
| 配置 | 说明 |
| --- | --- |
| `agora_app_id` | 声网项目 App ID,客户端初始化 RTC SDK 使用。 |
| `agora_auth_mode` | 当前建议填 `token`,由服务端生成 RTC Token。 |
| `agora_enabled` | 是否启用声网通话,建议测试环境先设为 `true`。 |
| `agora_uid_mode` | 建议用 `string`,客户端加入频道时使用 `usr...` 作为声网 user account,避免 BIGINT 用户 ID 超过声网数字 UID 范围。 |
| `agora_channel_prefix` | 建议 `call_`,最终频道名为 `call_{call_id}`。 |
### 3.2 正式模式后续准备
| 配置 | 说明 |
| --- | --- |
| `agora_app_certificate` | 声网 App 证书,服务端生成 RTC Token 使用,禁止下发客户端。 |
| `agora_token_ttl_seconds` | RTC Token 有效期,建议 3600 秒。 |
| `agora_rest_customer_id` | 声网 RESTful API 客户 ID,用于控制台 API。 |
| `agora_rest_customer_secret` | 声网 RESTful API 客户密钥,用于控制台 API,必须脱敏保存和展示。 |
| `agora_rest_primary_domain` | 国内建议 `https://api.sd-rtn.com`。 |
| `agora_rest_backup_domain` | 备用建议 `https://api.agora.io`。 |
配置建议存放在 HotGo `hg_sys_config` 的 `im_shengwang` 分组,IM Server 通过 `store.ThirdPartyConfig.Get("im_shengwang", ...)` 读取,并受 Kafka `third_party.updated` 或 `cache.third_party.invalidate` 事件清理进程内缓存。
## 4. 后端与声网 API 对接
### 4.1 首期不调用声网 REST API
只使用 `app_id` 的调试模式下,IM Server 不需要向声网发起服务端请求。后端只需要读取后台配置,把 `app_id`、频道名、UID 和空 Token 返回给客户端。
首期后端返回:
```json
{
"provider": "agora",
"auth_mode": "app_id",
"app_id": "声网 App ID",
"channel_name": "call_call_01K...",
"uid": 1565659909440147456,
"token": "",
"token_expires_at": null
}
```
### 4.2 正式 Token 模式
正式模式启用 App 证书后,IM Server 使用 `agora_app_id + agora_app_certificate + channel_name + uid + ttl` 在本地生成 RTC Token。Token 只返回给当前登录用户,不能存日志,不能返回给非通话参与人。
正式后端返回:
```json
{
"provider": "agora",
"auth_mode": "token",
"app_id": "声网 App ID",
"channel_name": "call_call_01K...",
"uid": 1565659909440147456,
"token": "007eJx...",
"token_expires_at": "2026-09-01T17:00:00+08:00"
}
```
客户端收到声网 SDK 的 Token 即将过期回调后,重新调用 IM Server 获取新 Token,再调用声网 SDK 的 `renewToken` 或等价接口更新。
### 4.3 声网控制台 REST API
控制台 REST API 是后台运维能力,不是每通电话的实时链路。需要自动化管理声网项目时再接入。
声网 REST API 鉴权:
```text
Authorization: Basic base64(customer_id + ":" + customer_secret)
Content-Type: application/json
```
常用接口:
| 能力 | 方法与路径 | 说明 |
| --- | --- | --- |
| 创建项目 | `POST /dev/v1/project` | Body `name, enable_sign_key`;返回 `vendor_key`,即 App ID。 |
| 查询指定项目 | `GET /dev/v1/project?id=&name=` | 按项目 ID 和名称查询。 |
| 查询全部项目 | `GET /dev/v1/projects` | 获取当前声网账号下项目列表。 |
| 启用/禁用项目 | `POST /dev/v1/project_status` | Body `id, status`,`1` 启用,`0` 禁用。 |
| 启用/禁用主要 App 证书 | `POST /dev/v1/signkey` | Body `id, enable`。 |
| 重置主要 App 证书 | `POST /dev/v1/reset_signkey` | Body `id`;证书未启用时会启用主要证书。 |
调用约束:
- 成功 HTTP 状态码为 `200` 或 `201`。
- 失败响应通常包含 `statusCode/error/message`。
- 每个声网账号 REST API QPS 默认 10 次/秒。
- 请求失败时日志记录声网响应 Header `X-Request-ID`、`X-Resource-ID`,但不能记录客户密钥、App 证书或 RTC Token。
- 国内服务优先 `api.sd-rtn.com`,失败时按退避策略切换 `api.agora.io` 或区域域名。
## 5. 前端与后端对接
### 5.1 WebSocket 通话信令
现有 IM WebSocket 仍是通话业务信令主链路。客户端发起通话时发布一条 `x-im-type=call` 的 Topic 消息:
```json
{
"pub": {
"id": "call-pub-1",
"topic": "p2p...",
"head": {
"mime": "application/json",
"webrtc": "started",
"x-im-type": "call",
"x-im-client-mid": "mid_call_1"
},
"content": {
"callId": "call_01K...",
"callType": "audio",
"audio": true,
"video": false,
"provider": "agora"
}
}
}
```
服务端返回:
```json
{
"ctrl": {
"id": "call-pub-1",
"code": 202,
"text": "accepted",
"params": {
"seq": 30
}
}
}
```
后续 `ringing/accept/hang-up` 继续走 `{note what="call"}`。切到声网后,`offer/answer/ice-candidate` 不再需要由客户端发送给 IM Server;媒体协商由声网 SDK 自己完成。为了兼容旧客户端,服务端可以继续接受这些事件,但新客户端应忽略旧 WebRTC SDP/ICE 流程。
### 5.2 获取声网入会配置
建议新增产品接口:
```http
POST /v1/im/calls/rtc-join
Authorization: Bearer <IM token>
X-MeetingIM-APIKey: <api_key>
X-IM-Schema: 1
X-Request-ID: <request_id>
Idempotency-Key: <idempotency_key>
Content-Type: application/json
```
请求 Body:
```json
{
"topic": "p2p...",
"call_id": "call_01K...",
"seq": 30,
"call_type": "audio",
"role": "caller"
}
```
字段说明:
| 字段 | 必填 | 说明 |
| --- | --- | --- |
| `topic` | 是 | P2P Topic。首期只支持一对一通话。 |
| `call_id` | 是 | 通话 ID,必须和 WebSocket call 消息一致。 |
| `seq` | 建议 | 通话消息 seq。发起方可在 `{pub}` 返回后传入;接听方从收到的 call 消息中取得。 |
| `call_type` | 是 | `audio` 或 `video`。 |
| `role` | 是 | `caller` 或 `callee`,用于审计和风控。 |
成功响应:
```json
{
"code": 0,
"data": {
"provider": "agora",
"auth_mode": "app_id",
"app_id": "声网 App ID",
"channel_name": "call_call_01K...",
"uid": 1565659909440147456,
"token": "",
"token_expires_at": null,
"call_id": "call_01K...",
"topic": "p2p...",
"seq": 30
},
"request_id": "req_01K...",
"server_time": "2026-09-01T16:00:00+08:00"
}
```
失败原因建议:
| reason | 场景 |
| --- | --- |
| `AGORA_DISABLED` | 后台未开启声网。 |
| `AGORA_CONFIG_MISSING` | 缺少 App ID,或正式模式缺少 App 证书。 |
| `CALL_NOT_FOUND` | `call_id/topic/seq` 不存在或不匹配。 |
| `CALL_NOT_ALLOWED` | 用户不是通话参与人,或被好友/黑名单/租户策略限制。 |
| `CALL_STATE_INVALID` | 通话已结束、已超时或状态不允许入会。 |
| `VALIDATION_FAILED` | 请求字段非法。 |
### 5.3 客户端发起通话流程
```text
用户点击语音/视频通话
-> 客户端生成 call_id
-> WS pub call started
-> 收到 ctrl 202 和 seq
-> 调 POST /v1/im/calls/rtc-join 获取声网入会参数
-> 使用声网 SDK joinChannel
-> 等待对方 ringing/accept
-> 通话中通过 IM note hang-up 结束业务状态
```
### 5.4 客户端接听通话流程
```text
收到 Topic call started data
-> 展示来电 UI
-> 用户点击接听
-> 调 POST /v1/im/calls/rtc-join 获取声网入会参数
-> 使用声网 SDK joinChannel
-> WS note call accept
-> 通话中通过 IM note hang-up 结束业务状态
```
### 5.5 客户端挂断/取消/拒接
客户端通过 IM WebSocket 发送:
```json
{
"note": {
"topic": "p2p...",
"what": "call",
"event": "hang-up",
"seq": 30,
"payload": {
"callId": "call_01K...",
"reason": "cancelled"
}
}
}
```
服务端按当前状态把原通话消息替换为 `finished/missed/declined/disconnected`,并更新 `im_call_records`。客户端以服务端下发的替换消息为准,不相信本地计算的最终时长。
## 6. 数据与安全要求
1. `agora_app_certificate`、`agora_rest_customer_secret`、RTC Token 都是敏感信息,不写普通日志、不下发给无关用户、不进入埋点。
2. 调试模式可以只用 App ID,但生产环境建议启用 App 证书和 RTC Token。
3. `channel_name` 必须由服务端规则生成,建议 `call_{call_id}`,客户端不能自定义任意声网频道。
4. `uid` 必须稳定,首期建议使用当前 IM 用户数据库 BIGINT ID;如果客户端 SDK 使用字符串 UID,后端和客户端必须同时切到 string 模式。
5. 入会接口必须校验当前用户属于该 P2P 通话双方之一。
6. 被拉黑、非好友、账号禁用、租户禁用、青少年模式限制等场景必须拒绝发起或接听。
## 7. 联调清单
| 编号 | 场景 | 预期 |
| --- | --- | --- |
| AGORA-01 | 后台配置 `agora_app_id`、`agora_app_certificate` 和 `agora_auth_mode=token` | `/v1/im/calls/rtc-join` 返回 App ID、频道名、UID 和 RTC Token。 |
| AGORA-02 | A 发起语音通话,B 接听 | 双方使用同一 `channel_name` 加入声网频道,IM 通话状态变为 `accepted`。 |
| AGORA-03 | A 发起视频通话,B 接听 | 双方可看到/听到媒体流,IM 通话记录为 `video`。 |
| AGORA-04 | B 拒接 | IM 替换原通话消息为 `declined`,双方退出声网频道。 |
| AGORA-05 | A 取消 | IM 替换原通话消息为 `missed` 或取消态,B 来电 UI 关闭。 |
| AGORA-06 | 通话中任一方挂断 | IM 以服务端计时生成 `finished` 和 `duration_ms`。 |
| AGORA-07 | 非参与人请求入会配置 | 返回 `CALL_NOT_ALLOWED`。 |
| AGORA-08 | 关闭 `agora_enabled` | 入会接口返回 `AGORA_DISABLED`。 |
| AGORA-09 | 正式 Token 模式缺少 App 证书 | 入会接口返回 `AGORA_CONFIG_MISSING`。 |
| AGORA-10 | Token 即将过期刷新 | 正式模式下客户端重新获取 Token 并成功 `renewToken`。 |
## 8. 后续增强
1. 接入 RTC Token 生成器,支持 App 证书正式模式。
2. 后台增加声网配置页和敏感字段脱敏。
3. 接入声网控制台 REST API,实现项目查询、证书启停和重置。
4. 记录声网频道、UID、入会时间、离会时间和错误码,便于排障。
5. 采集通话质量指标:建连耗时、首帧耗时、丢包、延迟、卡顿、断线重连。
6. 后续如需多人通话,单独设计会议房间和 SFU/RTC 房间状态,不复用 P2P `call_id` 状态机。
## 9. 参考文档
- 声网创建项目:https://doc.shengwang.cn/doc/console/general/console/operations/post-dev-v1-project
- 声网获取指定项目信息:https://doc.shengwang.cn/doc/console/general/console/operations/get-dev-v1-project
- 声网获取所有项目信息:https://doc.shengwang.cn/doc/console/general/console/operations/get-dev-v1-projects
- 声网启用或禁用项目:https://doc.shengwang.cn/doc/console/general/console/operations/post-dev-v1-project_status
- 声网启用或禁用主要 App 证书:https://doc.shengwang.cn/doc/console/general/console/operations/post-dev-v1-signkey
- 声网重置主要 App 证书:https://doc.shengwang.cn/doc/console/general/console/operations/post-dev-v1-reset_signkey
- 声网响应状态码:https://doc.shengwang.cn/doc/console/general/api/response-code
- 声网配额限制:https://doc.shengwang.cn/doc/console/general/api/quota
- 声网 REST 高可用:https://doc.shengwang.cn/doc/console/general/api/guarantee-rest
- 声网 RTC Token 鉴权:https://doc.shengwang.cn/doc/rtc/android/basic-features/token-authentication