核心概念与领域模型
Project / Channel / Participant / Task / Callback 的字段与不变量,以及两种凭证家族。
这一页把文档里反复出现的名词、字段和不变量集中说明一次。字段名以 接口定义 为准:平台 API(/v1/*)使用 camelCase 线上字段,声网兼容接口使用 snake_case 别名。
两种凭证家族
| 凭证 | 形态 | 用途 | 存放位置 |
|---|---|---|---|
| 项目凭证 | Authorization: Basic base64(customerId:customerSecret) | 服务端到服务端:签 Token、频道管理、录制/推流、遥测上报 | 只在你的后端 |
| 控制台会话 | Authorization: Bearer ses_* | 控制台 BFF:项目、密钥轮换、服务开通、回调配置、审计 | 控制台页面(12 小时 TTL) |
| App ID | 32 位十六进制 | 客户端初始化与路径参数(/dev/v1/channel/{appid}) | 客户端可见 |
| App Certificate | 64 位十六进制 | 签发/校验 Token 的 HMAC 密钥 | 只在服务端,或只以 secret-manager 引用形式出现 |
Project(项目)
| 字段 | 说明 |
|---|---|
id | prj_*,项目主键 |
appId | 32 hex,客户端可见的项目标识 |
customerId / customerSecretHash | Basic 用户名;密码只存 校验值 |
appCertificate | Token 签名密钥(存哈希/受控存储,明文只返回一次) |
authMode | token(默认,客户端带 Token)或 appid |
status | active / suspended;非 active 一律 403 app_disabled |
tokenTtlSeconds | Token 生命周期策略上限(默认 3600) |
privilegeTtlSeconds | 权限窗口上限(默认 3600),实际取 min(ttl, 该值) |
services | { recording, streaming, analytics } 服务开关 |
quotas | { recordingConcurrent, streamingConcurrent, maxChannels },默认 5 / 5 / 0(0 = 不限频道数) |
Channel(频道)与 Participant(参与者)
- 频道名:1–128,字符集
[A-Za-z0-9_-],大小写敏感,项目内唯一。 - 媒体面房间名带 App ID 命名空间:
<appId>:<channelName>(services/room-name.ts),避免多租户撞名。 profile取communication或live,决定声网兼容接口返回users还是broadcasters/audience。- Participant 是「某用户在某频道内的一次在线」:
uid(1..2147483647)、可选的userId(IM 身份)、role、platform、joinedAt/leftAt、leaveReason、audioMuted/videoMuted、publishing.{audio,video,screen}。
平台编码(platform)与声网一致:0 其他、1 Android、2 iOS、5 Windows、6 Linux、7 Web、8 macOS。
离开原因(leaveReason / 回调 reason)映射:1 正常/其他、2 超时、3 被踢或被禁、5 重复登录/切换、10 网络断开。
Task(任务)
录制与推流都是任务形资源,有独立状态机:
starting → running → stopping → stopped
↘ failed
↘ expired(仅推流:idleTimeout 触发)- 每次状态变化都先落库再进 Outbox,然后才投递回调(事务性 Outbox),所以「回调丢失」不会导致状态回滚,只会导致重投。
RecordingTask额外带layout、storage、subscribeAudioUids/subscribeVideoUids、files[]、usageSeconds、queueWaitMs、idempotencyKey。StreamingTask额外带entryPoint、streamName、rtmpUrl、hlsUrl、idleTimeoutSeconds、lastActiveAt。
UsageEvent 与 QualitySample
- 用量按「分钟」计费,类型:
audio/video/recording/streaming/transcoding;每条事件带idempotencyKey,Webhook 与对账两条通道重复观测不会重复计费。 - 质量样本是每用户每分钟聚合值:
videoFreezeMs/audioFreezeMs/networkDelayMs是原始卡顿时长与延迟时长,阈值在服务端应用(见 水晶球)。 - 六个分析维度:
region、networkType、osType、sdkVersion、deviceType、channelSize。
CallbackEnvelope(回调信封)
| 字段 | 说明 |
|---|---|
noticeId | 每次事件唯一的通知 id,可用于幂等 |
productId | 固定 1(RTC) |
eventType | 数字事件码(101–112、201–203),见 回调事件 |
notifyMs | 事件产生时间(epoch 毫秒) |
sid | 事件会话 id |
payload | 事件专属字段 |
平台 API 与声网兼容 API
同一份业务事实,两种信封:
| 维度 | 平台 API(/v1/*) | 声网兼容(/dev/v1/*、/v1/apps/*、/v1/projects/*) |
|---|---|---|
| 字段命名 | camelCase | snake_case(channel_name、user_count、cname、resourceId…) |
| 列表信封 | { total, pageNo, pageSize, channels } | { success: true, data: { channels, total_size } } |
| 任务结果 | 完整任务资源(状态机、文件、队列诊断) | { resourceId, sid, serverResponse } |
| 错误 | { code, message, reason, sdkCode } | 同左(两种读取习惯都能拿到原因) |
| 适用 | 我们的 SDK / 控制台 / 新接入方 | 从声网迁移、需要改路径最少 |
关键不变量
rtcUid ∈ [1, 2147483647],永不为 0(声网语义里 0 表示「服务端随机分配」);同一(appId, userId)在会话期内稳定。- 频道名项目内唯一;SFU 房间名 =
<appId>:<channelName>。 - Token 绑定
(appId, channelName, uid, role, privilegeExpireAt, tokenExpireAt);通配 Token 的频道为*。 - 每个任务状态变更先持久化、再入 Outbox、最后投递回调。
join_channel封禁同时作用于两处:签发 Token(403banned)与在线会话(踢下线,离开原因 3)。- 用量事件按
(projectId, idempotencyKey)幂等;Webhook 与对账双通道写同一幂等路径。 - 回调同时带 SHA1(
Agora-Signature)与 SHA256(Agora-Signature-V2)签名,覆盖原始请求体字节。