Files
im_server/docs/third/IM-声网音视频通话完整调用流程.md
T

318 lines
9.8 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 系统接入声网 RTC 后,一次音视频通话从后台配置、客户端发起、服务端校验、声网入会到挂断结束的完整调用链路。
首期调试环境只使用声网 `app_id`,客户端入会时 `token` 为空。正式环境启用 App 证书后,由 IM Server 使用 `app_certificate` 生成 RTC Token,再返回给客户端。
## 2. 整体链路
```text
后台配置声网参数
-> 客户端 A 发起通话
-> IM Server 校验业务权限并生成 call_id/channel/uid
-> IM WebSocket 通知客户端 B
-> A、B 分别向 IM Server 获取声网入会参数
-> A、B 使用声网 SDK 加入同一频道
-> 音视频媒体流走声网 RTC
-> 挂断/拒接/超时通过 IM 信令结束
-> IM Server 记录通话状态和通话记录
```
## 3. 后台配置流程
### 3.1 调试模式
调试模式只需要准备声网项目的 `app_id`。
后台配置建议:
| 配置项 | 示例 | 说明 |
| --- | --- | --- |
| `agora_enabled` | `true` | 是否启用声网音视频。 |
| `agora_auth_mode` | `token` | 正式模式,服务端生成 RTC Token。 |
| `agora_app_id` | `xxxxxxxx` | 声网项目 App ID,允许返回给客户端。 |
| `agora_channel_prefix` | `call_` | 服务端生成声网频道名前缀。 |
| `agora_uid_mode` | `string` | 建议使用 `usr...` 作为声网 user account,避免 BIGINT 用户 ID 超过声网数字 UID 范围。 |
### 3.2 正式模式
正式模式需要启用 App 证书,由后端生成 RTC Token。
后台配置建议:
| 配置项 | 说明 |
| --- | --- |
| `agora_auth_mode=token` | 开启 Token 鉴权模式。 |
| `agora_app_certificate` | 声网 App 证书,只能后端保存和使用。 |
| `agora_token_ttl_seconds` | Token 有效期,建议 3600 秒。 |
### 3.3 声网控制台 REST API 配置
声网 REST API 的 `customer_id/customer_secret` 只用于后端调用声网控制台 API,例如创建项目、查询项目、启用/禁用项目、启用/重置证书。它不是客户端入会参数,也不是每次通话必须调用的接口。
后台配置建议:
| 配置项 | 说明 |
| --- | --- |
| `agora_rest_customer_id` | 声网 REST API 客户 ID。 |
| `agora_rest_customer_secret` | 声网 REST API 客户密钥,必须脱敏展示。 |
| `agora_rest_primary_domain` | 国内建议 `https://api.sd-rtn.com`。 |
| `agora_rest_backup_domain` | 备用建议 `https://api.agora.io`。 |
## 4. 后端和声网 API 对接流程
### 4.1 调试阶段
调试阶段后端不需要请求声网服务端 API。IM Server 只负责读取后台配置,并把客户端入会需要的参数返回给当前登录用户。
返回给客户端的字段:
| 字段 | 说明 |
| --- | --- |
| `provider` | 固定 `agora`。 |
| `auth_mode` | 调试模式为 `app_id`。 |
| `app_id` | 声网 App ID。 |
| `channel_name` | 服务端生成的频道名。 |
| `uid` | 当前 IM 用户映射到声网的 UID。 |
| `token` | 调试模式为空字符串。 |
| `token_expires_at` | 调试模式为 `null`。 |
### 4.2 正式 Token 阶段
正式阶段后端仍然不需要每次请求声网 REST API。IM Server 使用本地保存的 `app_id`、`app_certificate`、`channel_name`、`uid` 和有效期生成 RTC Token。
生成完成后只把 Token 返回给当前通话参与人。`app_certificate` 不允许返回客户端,不允许写入普通日志。
### 4.3 控制台 REST API 阶段
只有后台需要自动管理声网项目时,才调用声网控制台 REST API。
常用接口:
| 场景 | 声网 API |
| --- | --- |
| 创建项目 | `POST /dev/v1/project` |
| 查询指定项目 | `GET /dev/v1/project?id=&name=` |
| 查询全部项目 | `GET /dev/v1/projects` |
| 启用/禁用项目 | `POST /dev/v1/project_status` |
| 启用/禁用主要 App 证书 | `POST /dev/v1/signkey` |
| 重置主要 App 证书 | `POST /dev/v1/reset_signkey` |
声网 REST API 使用 Basic Auth:
```text
Authorization: Basic base64(customer_id + ":" + customer_secret)
Content-Type: application/json
```
## 5. 前端和后端对接流程
### 5.1 发起方流程
```text
用户 A 点击语音/视频通话
-> 客户端 A 生成 call_id
-> 客户端 A 通过 IM WebSocket 发送 call started
-> IM Server 校验 A 和 B 的关系、黑名单、账号状态、租户状态
-> IM Server 写入或更新通话记录
-> IM Server 返回 Topic seq
-> 客户端 A 调用入会接口获取声网参数
-> 客户端 A 使用声网 SDK 加入频道
-> IM Server 通过 WebSocket 把来电消息推送给客户端 B
```
WebSocket 发起通话示例:
```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": "video",
"audio": true,
"video": true,
"provider": "agora"
}
}
}
```
### 5.2 被叫方流程
```text
客户端 B 收到 IM WebSocket 来电消息
-> 展示来电页面
-> 用户 B 点击接听
-> 客户端 B 调用入会接口获取声网参数
-> IM Server 校验 B 是否为本次通话参与人
-> IM Server 返回同一个 channel_name 和 B 自己的 uid/token
-> 客户端 B 使用声网 SDK 加入频道
-> 客户端 B 通过 IM WebSocket 发送 call accept
-> 双方开始音视频通话
```
### 5.3 获取声网入会参数
建议接口:
```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": "video",
"role": "caller"
}
```
成功响应:
```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"
}
```
正式 Token 模式下,`auth_mode` 返回 `token`,`token` 不为空,`token_expires_at` 返回具体过期时间。
### 5.4 客户端加入声网频道
客户端拿到后端返回参数后调用声网 RTC SDK:
```text
初始化 RTC SDK: app_id
加入频道: channel_name
用户标识: uid
入会凭证: token
```
调试模式下 `token` 为空。正式环境下 `token` 必须由后端生成并返回。
音视频媒体流不经过 IM Server,客户端加入声网频道后由声网 RTC 负责音视频传输、音频路由、摄像头采集、网络切换和断线重连等能力。
## 6. 通话结束流程
### 6.1 主动挂断
```text
任意一方点击挂断
-> 客户端离开声网频道
-> 客户端通过 IM WebSocket 发送 hang-up
-> IM Server 更新通话记录状态和通话时长
-> IM Server 推送通话结束消息给另一方
-> 另一方客户端关闭通话页面并离开声网频道
```
挂断信令示例:
```json
{
"note": {
"topic": "p2p...",
"what": "call",
"event": "hang-up",
"seq": 30,
"payload": {
"callId": "call_01K...",
"reason": "finished"
}
}
}
```
### 6.2 取消、拒接和超时
| 场景 | 处理 |
| --- | --- |
| 发起方取消 | IM Server 标记为 `cancelled` 或 `missed`,被叫端关闭来电页面。 |
| 被叫方拒接 | IM Server 标记为 `declined`,发起方关闭等待页面。 |
| 被叫方超时未接 | IM Server 标记为 `missed`,双方客户端退出通话状态。 |
| 网络异常断开 | 客户端根据声网 SDK 回调提示重连;业务最终状态以 IM Server 的结束事件为准。 |
## 7. Token 续期流程
正式环境启用 Token 后,客户端需要监听声网 SDK 的 Token 即将过期或已过期回调。
```text
声网 SDK 提示 Token 即将过期
-> 客户端调用 /v1/im/calls/rtc-join 或续期接口
-> IM Server 校验当前通话仍有效
-> IM Server 重新生成 RTC Token
-> 客户端调用声网 SDK renewToken
```
调试模式不涉及 Token 续期。
## 8. 安全边界
| 数据 | 是否返回客户端 | 说明 |
| --- | --- | --- |
| `app_id` | 是 | 客户端初始化声网 SDK 必须使用。 |
| `channel_name` | 是 | 服务端生成,客户端不能自定义任意频道。 |
| `uid` | 是 | 当前用户对应的声网 UID。 |
| `token` | 是 | 正式环境返回,仅当前通话参与人可获取。 |
| `app_certificate` | 否 | 后端生成 RTC Token 使用。 |
| `customer_id` | 否 | 后端调用声网控制台 REST API 使用。 |
| `customer_secret` | 否 | 后端调用声网控制台 REST API 使用。 |
## 9. 异常处理
| reason | 场景 |
| --- | --- |
| `AGORA_DISABLED` | 后台未启用声网通话。 |
| `AGORA_CONFIG_MISSING` | 缺少 `app_id`,或 Token 模式缺少 `app_certificate`。 |
| `CALL_NOT_FOUND` | `call_id/topic/seq` 不匹配或通话不存在。 |
| `CALL_NOT_ALLOWED` | 当前用户不是通话参与人,或被权限策略拦截。 |
| `CALL_STATE_INVALID` | 通话已结束、已超时或当前状态不允许入会。 |
| `VALIDATION_FAILED` | 请求参数非法。 |
## 10. 联调顺序建议
1. 后台配置 `agora_enabled=true`、`agora_auth_mode=token`、`agora_app_id`、`agora_app_certificate`。
2. 客户端集成声网 RTC SDK,并使用后端返回的 RTC Token 入会。
3. A 发起语音通话,确认 B 能收到 IM 来电信令。
4. A、B 分别调用 `/v1/im/calls/rtc-join`,确认返回同一个 `channel_name`。
5. A、B 使用各自 `uid` 加入声网频道,确认音频可通。
6. 切换视频通话,确认视频流可通。
7. 测试取消、拒接、挂断、超时、网络断开。
8. 验证 Token 入会和 Token 续期。
9. 后续再接入声网控制台 REST API 的项目管理能力。