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

12 KiB
Raw Blame History

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 首期填 app_id,表示仅 App ID 鉴权。
agora_enabled 是否启用声网通话,建议测试环境先设为 true。
agora_uid_mode 建议先用 int,客户端加入频道时使用数字 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_third_party 分组,IM Server 通过现有 store.ThirdPartyConfig.Get("im_third_party", ...) 读取,并受 Kafka third_party.updated 或 cache.third_party.invalidate 事件清理进程内缓存。

4. 后端与声网 API 对接

4.1 首期不调用声网 REST API

只使用 app_id 的调试模式下,IM Server 不需要向声网发起服务端请求。后端只需要读取后台配置,把 app_id、频道名、UID 和空 Token 返回给客户端。

首期后端返回:

{
  "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 只返回给当前登录用户,不能存日志,不能返回给非通话参与人。

正式后端返回:

{
  "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 鉴权:

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 消息:

{
  "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"
    }
  }
}

服务端返回:

{
  "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 获取声网入会配置

建议新增产品接口:

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:

{
  "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,用于审计和风控。

成功响应:

{
  "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 客户端发起通话流程

用户点击语音/视频通话
-> 客户端生成 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 客户端接听通话流程

收到 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 发送:

{
  "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_auth_mode=app_id /v1/im/calls/rtc-join 返回 App ID、频道名、UID,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. 参考文档