CTICloud JS SDK 实时语音流开发指南
1 概述
1.1 功能介绍
CTICloud JS SDK 提供实时语音流(Real-time Audio Stream)能力,可在 WebRTC 通话过程中实时获取本地音频(座席麦克风)和远端音频(通常为客户),并通过 WebSocket 与业务方自建 Processor 服务建立连接,实现实时音频分析与处理。
开发者可基于该能力快速构建实时语音识别(ASR)、AI Agent、实时质检、情绪分析、座席辅助、声音美化、AI 变声、语音降噪、实时翻译等业务场景,而无需关注浏览器媒体采集、远端媒体接收、WebRTC 音频注入、连接管理及协议交互等底层实现。
整个语音流处理过程中:
-
CTICloud JS SDK 负责座席麦克风采集、远端媒体接收、WebSocket 会话管理、协议交互及音频注入。
-
Processor 服务 负责接收指定来源的实时音频,并根据业务需求进行分析或处理;对于本地音频
sendrecvProcessor,可将处理后的音频实时返回 SDK。
1.2 功能特性
媒体能力
-
支持 WebRTC 座席麦克风实时采集
-
支持远端音频实时获取
-
支持实时 PCM 音频流传输
-
支持处理后音频实时回传
-
支持音频格式动态协商
网络能力
-
支持 WebSocket 双向通信
-
支持 TLS 安全传输(
wss://) -
支持连接异常自动重连
-
支持多通话并发连接
SDK 能力
-
支持多个语音处理器(Processor)同时运行
-
支持按音频来源选择本地音频或远端音频
-
支持运行时动态更新配置
-
支持完整的会话生命周期管理
-
支持丰富的事件通知机制
1.3 典型应用场景
| 场景 | Source | Mode | 是否回传音频 | 说明 |
|---|---|---|---|---|
| 座席语音识别(ASR) | local | sendonly | 否 | 将座席语音实时推送至语音识别服务 |
| 客户语音识别(ASR) | remote | sendonly | 否 | 将客户语音实时推送至语音识别服务 |
| 实时质检 | local / remote | sendonly | 否 | 对指定一侧的音频进行实时分析 |
| 客户情绪分析 | remote | sendonly | 否 | 对客户语音进行情绪识别和意图分析 |
| 座席辅助 | remote | sendonly | 否 | 获取客户语音,为座席提供实时提示 |
| AI Agent | local / remote | sendonly | 否 | 获取指定一侧语音进行实时推理 |
| 声音美化 | local | sendrecv | 是 | 对座席声音进行实时美化 |
| AI 变声 | local | sendrecv | 是 | 使用处理后的声音替换座席麦克风声音 |
| AI 降噪 | local | sendrecv | 是 | 对本地音频(座席麦克风)进行实时降噪 |
| 实时翻译 | local | sendrecv | 是 | 将翻译后的语音发送给通话对端 |
说明当前版本仅支持本地音频使用
sendrecv。远端音频仅支持sendonly,不支持通过 Processor 回传并替换远端音频。
1.4 系统架构
实时语音流整体架构如下图所示。
flowchart LR Local["本地音频(座席麦克风)"] Remote["远端音频(通常为客户)"] SDK["CTICloud JS SDK"] Processor["Processor 服务"] Media["CTICloud 媒体服务器"] Peer["通话对端"] Local --> SDK Media -->|WebRTC 远端音频| SDK SDK -->|WebSocket:local/remote 音频| Processor Processor -->|处理后本地音频(仅 local + sendrecv)| SDK SDK -->|WebRTC 本地音频| Media Media --> Peer
各组件职责如下:
| 组件 | 职责 |
|---|---|
| CTICloud JS SDK | 采集本地音频、接收远端音频、建立 WebSocket 会话、分发指定来源的音频流,并在本地音频 sendrecv 模式下注入处理后的音频 |
| Processor 服务 | 接收 SDK 推送的本地音频或远端音频,完成语音识别、质检、声音处理或 AI 推理,并根据配置决定是否返回处理后的本地音频 |
| CTICloud 媒体服务器 | 负责 WebRTC 媒体传输及与通话对端建立音频连接 |
1.5 工作流程
在通话过程中,SDK 会自动建立语音流会话,并与Processor 服务进行实时音频交互。
sequenceDiagram participant SDK as CTICloud JS SDK participant Service as Processor 服务 SDK->>Service: 建立 WebSocket 连接 SDK->>Service: 建立语音流会话 loop 通话期间 SDK->>Service: 推送指定来源音频(local/remote) opt Mode = sendrecv Service->>SDK: 返回处理后的本地音频 end end SDK->>Service: 结束语音流会话
语音流处理过程如下:
-
SDK 在通话建立后自动创建语音流会话。
-
SDK 根据 Processor 的
source配置,获取本地音频或远端音频。 -
SDK 将指定来源的音频实时发送至Processor 服务。
-
Processor 服务完成语音分析或音频处理。
-
当
source为local且mode为sendrecv时,Processor 服务将处理后的本地音频实时返回 SDK。 -
SDK 将处理后的音频替换座席麦克风输入,并通过 WebRTC 发送给通话对端。
-
通话结束后,SDK 自动关闭语音流会话。
说明SDK 支持同时配置多个语音处理器(Processor)。每个 Processor 通过
source选择local或remote音频。可同时配置多个sendonlyProcessor,但同一时间最多只能配置一个sendrecvProcessor,且该 Processor 的source必须为local。
1.6 适用范围
本文档适用于以下产品及环境:
| 项目 | 说明 |
|---|---|
| SDK | CTICloud JS SDK |
| 座席类型 | WebRTC 座席 |
| 浏览器 | Chrome、Edge、Electron 等支持 WebRTC 的浏览器 |
| 语音处理服务 | 业务方自建 WebSocket 服务 |
1.7 名词说明
| 名词 | 说明 |
|---|---|
| SDK | CTICloud JS SDK。 |
| 座席端 | 集成 CTICloud JS SDK 的浏览器页面,也是 local / remote 的观察视角。 |
| Processor | 一个独立的语音处理服务实例,通过 WebSocket 与 SDK 建立会话,并通过 source 和 mode 指定音频来源及处理方式。 |
| Processor 服务 | 业务方自行开发并部署的 Processor 服务。 |
| 本地音频 | SDK 从当前座席浏览器麦克风采集的音频,对应 source: "local"。 |
| 远端音频 | SDK 从 WebRTC 远端媒体轨道接收的通话对端音频,通常为客户,对应 source: "remote"。 |
| 上行音频 | SDK 发送给 Processor 的实时音频,来源由 source 决定。 |
| 下行音频 | Processor 返回给 SDK 的处理后本地音频,仅适用于 source: "local" 且 mode: "sendrecv"。 |
| Session | SDK 与Processor 服务之间建立的一次语音流会话。 |
| PCM | 原始音频数据,不包含 WAV、MP3 等文件头。 |
1.8 前置条件
开始接入前,请确认已满足以下条件:
-
已开通 CTICloud WebRTC 能力。
-
已完成 CTICloud JS SDK 集成。
-
页面通过 HTTPS 访问,并已获取浏览器麦克风权限。
-
已部署可访问的 WebSocket 服务。
-
WebSocket 服务支持 TLS(
wss://)。 -
WebSocket 服务支持二进制消息处理。
2 快速开始
本章节介绍如何快速完成实时语音流能力接入。
完成本章节后,CTICloud JS SDK 将能够与Processor 服务建立 WebSocket 连接,并开始推送本地音频或远端音频流。
整个接入过程分为以下四个步骤:
-
配置 CTICloud JS SDK
-
部署语音处理服务
-
实现 WebSocket 协议
-
发起通话并验证接入
2.1 接入流程
完成实时语音流接入需要以下五个步骤:
| 步骤 | 说明 |
|---|---|
| 步骤一 | 配置 CTICloud JS SDK。 |
| 步骤二 | 部署 Processor 服务。 |
| 步骤三 | 实现 WebSocket 协议。 |
| 步骤四 | 发起 WebRTC 通话。 |
| 步骤五 | 验证语音流处理结果。 |
2.2 配置 SDK
通过 CTILink.setup() 开启实时语音流能力。
CTILink.setup({
webrtc: true,
media: {
audio: {
processors: [
{
id: "voice-service",
source: "local",
mode: "sendrecv",
transport: {
protocol: "websocket",
url: "wss://voice.example.com/ws"
}
}
]
}
}
});配置完成后,SDK 会在每次 WebRTC 通话建立时自动创建对应的 Processor Session。
说明如未配置
media.audio.processors,SDK 不会建立语音流连接。
2.3 Processor 配置说明
一个 Processor 表示一个独立的语音处理服务。
SDK 支持同时配置多个 Processor。
processors: [
{
id: "asr",
source: "remote",
mode: "sendonly",
transport: {
protocol: "websocket",
url: "wss://asr.example.com/ws"
}
},
{
id: "voice",
source: "local",
mode: "sendrecv",
transport: {
protocol: "websocket",
url: "wss://voice.example.com/ws"
}
}
]配置规则如下:
| 配置项 | 说明 |
|---|---|
| 可配置多个 Processor | ✔ |
可配置多个 sendonly | ✔ |
可配置多个 sendrecv | ✘(最多一个) |
| Processor 独立建立 WebSocket 会话 | ✔ |
每个 Processor 根据 source 接收对应的本地音频或远端音频。配置相同 source 的多个 sendonly Processor 会接收到同一份来源音频。
source: "local" 且 mode: "sendrecv" 的 Processor 返回的处理后音频将作为最终发送给通话对端的本地音频。
2.4 部署语音处理服务
业务方需部署符合 WebSocket 协议规范的语音处理服务。
服务需满足以下要求:
-
支持 WebSocket(
wss://) -
支持二进制消息
-
支持处理会话控制消息
-
支持实时接收 PCM 音频
-
在
sendrecv模式下支持实时返回处理后的 PCM 音频
WebSocket 协议规范请参见《WebSocket 协议》章节。
2.5 发起通话
完成 SDK 配置后,正常登录 CTICloud,并发起 WebRTC 通话。
SDK 将自动完成以下操作:
-
建立 WebSocket 连接
-
创建语音流会话
-
根据 source 推送本地音频(座席麦克风)或远端音频(通常为客户)
-
在 local + sendrecv 模式下接收处理后的音频
-
通话结束后关闭语音流会话
整个过程无需业务代码参与。
2.6 验证接入
接入成功后,可通过以下方式验证:
浏览器控制台
确认 SDK 已成功建立 WebSocket 连接。
网络请求
浏览器开发者工具中应能够看到与语音处理服务建立的 WebSocket 长连接。
服务端日志
语音处理服务应能够收到:
-
会话建立请求
-
持续的音频数据
-
通话结束通知
通话验证
对于:
-
sendonly模式,可验证服务端是否持续收到source指定的音频。 -
sendrecv模式,可验证通话对端是否能够听到处理后的声音。
3 SDK API
本章节介绍 CTICloud JS SDK 提供的实时语音流相关接口,包括初始化配置、Processor 配置及事件监听。
3.1 CTILink.setup()
通过 CTILink.setup() 初始化 CTICloud JS SDK,并开启实时语音流能力。
示例
CTILink.setup({
webrtc: true,
media: {
audio: {
processors: [
{
id: "voice",
source: "local",
mode: "sendrecv",
transport: {
protocol: "websocket",
url: "wss://voice.example.com/ws"
}
}
]
}
}
});3.2 media.audio.processors
processors 用于配置一个或多个语音处理器(Processor)。
SDK 为每个 Processor 建立独立的 WebSocket 连接,并自动管理其生命周期。
示例
media: {
audio: {
processors: [
{
id: "asr",
source: "remote",
mode: "sendonly",
transport: {
protocol: "websocket",
url: "wss://asr.example.com/ws"
}
},
{
id: "voice",
source: "local",
mode: "sendrecv",
transport: {
protocol: "websocket",
url: "wss://voice.example.com/ws"
}
}
]
}
}Processor 配置项
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
| id | String | 是 | - | Processor 唯一标识,同一 SDK 实例内必须唯一。 |
| source | String | 否 | local | 音频来源,可选值为 local、remote。 |
| mode | String | 否 | sendonly | Processor 工作模式。 |
| transport | Object | 是 | - | Processor 连接配置。 |
source
定义 Processor 接收的音频来源。local 和 remote 均以 CTICloud JS SDK 所在的座席浏览器为观察视角。
| 值 | 中文名称 | 说明 |
|---|---|---|
local | 本地音频 | SDK 从当前浏览器麦克风采集的音频,即座席语音。 |
remote | 远端音频 | SDK 从 WebRTC 远端媒体轨道接收的音频,即通话对端语音,通常为客户。 |
限制
remote当前仅支持sendonly。如配置source: "remote"与mode: "sendrecv",SDK 应判定为无效配置并触发processorError。
mode
定义 Processor 的工作模式。
| 参数 | 说明 |
|---|---|
sendonly | SDK 将指定来源的音频发送给 Processor,不接收处理后的音频。适用于 ASR、实时质检、情绪分析、AI Agent 等场景。 |
sendrecv | SDK 将本地音频发送给 Processor,同时接收处理后的音频,并替换座席麦克风输入。仅支持 source: "local"。 |
说明一个 SDK 实例可同时配置多个
sendonlyProcessor,但最多只能配置一个sendrecvProcessor,且该 Processor 的source必须为local。
transport
定义 SDK 与 Processor 的连接方式。
目前仅支持 WebSocket。
示例
transport: {
protocol: "websocket",
url: "wss://voice.example.com/ws"
}transport 配置项
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
| protocol | String | 否 | websocket | 传输协议,目前仅支持 websocket。 |
| url | String | 是 | - | Processor WebSocket 地址,仅支持 wss://。 |
transport 鉴权
Processor WebSocket 服务由客户提供,SDK 不限制鉴权方式,推荐采用以下方式:
| 方式 | 说明 |
|---|---|
| Query Token | URL 携带短期有效 Token。 |
| URL 签名 | 时间戳 + 随机数 + 签名。 |
| API 网关 | 统一鉴权、限流及访问控制。 |
| IP 白名单 | 控制访问来源。 |
建议 Token 使用短有效期,并在 SessionStart 中再次校验企业及会话信息。
3.3 Processor 生命周期
SDK 自动管理 Processor 生命周期。
stateDiagram-v2 [*] --> NotCreated NotCreated --> Connecting : 通话建立 Connecting --> Ready : Session Ready Ready --> Streaming : 开始传输音频 Streaming --> Closed : 通话结束 Closed --> [*]
开发者无需主动创建或关闭 Processor。
SDK 会在以下时机自动完成生命周期管理:
-
通话建立时创建 Processor。
-
建立 WebSocket 连接。
-
创建 Processor Session。
-
通话结束后自动关闭 Processor。
3.4 注册事件
CTICloud JS SDK 通过 CTILink.event() 注册事件回调。
示例
CTILink.event("processorReady", handleProcessorReady);
CTILink.event("processorError", handleProcessorError);
CTILink.event("processorClosed", handleProcessorClosed);3.5 Processor 事件
SDK 仅对外提供业务需要关注的事件。
processorReady
Processor Session 创建成功。
收到该事件后,表示 Processor 已开始正常处理语音流。
回调参数
| 字段 | 类型 | 说明 |
|---|---|---|
| processorId | String | Processor 唯一标识。 |
| sessionId | String | Processor Session ID。 |
| uniqueId | String | 通话唯一标识。 |
processorError
Processor 运行过程中发生异常。
回调参数
| 字段 | 类型 | 说明 |
|---|---|---|
| processorId | String | Processor 唯一标识。 |
| sessionId | String | Processor Session ID。 |
| uniqueId | String | 通话唯一标识。 |
| code | Number | 错误码。 |
| message | String | 错误描述。 |
processorClosed
Processor Session 已关闭。
以下情况会触发该事件:
-
通话结束;
-
SDK 主动关闭 Processor;
-
Processor 主动结束 Session。
回调参数
| 字段 | 类型 | 说明 |
|---|---|---|
| processorId | String | Processor 唯一标识。 |
| sessionId | String | Processor Session ID。 |
| uniqueId | String | 通话唯一标识。 |
3.6 配置规则
Processor 配置需满足以下规则。
| 规则 | 说明 |
|---|---|
| Processor ID 唯一 | ✔ |
source 支持 local、remote | ✔ |
支持多个 sendonly Processor | ✔ |
最多一个 sendrecv Processor | ✔,且仅支持 source: "local" |
| 每个 Processor 建立独立 WebSocket 连接 | ✔ |
| SDK 自动管理 Processor 生命周期 | ✔ |
| SDK 自动完成异常重连 | ✔ |
3.7 资源消耗
启用 Processor 后,CTICloud JS SDK 会复制一份指定来源的 PCM 数据,并通过独立 WebSocket 连接发送至对应的 Processor。
每增加一个 Processor,将增加一条独立的 WebSocket 音频流。
网络带宽
默认音频格式:
| 参数 | 值 |
|---|---|
| Sample Rate | 16000 Hz |
| Channels | 1 |
| Sample Bits | 16 bit |
| Encoding | pcm_s16le |
单路原始 PCM 数据码率约为 256 kbps(约 32 KB/s)。
考虑 WebSocket、TLS 及网络协议开销后,单路音频流的实际带宽约为 280~320 kbps(35~40 KB/s)。
| Processor 配置 | 浏览器上行带宽 | 浏览器下行带宽 | 双向合计 |
|---|---|---|---|
source: "local" + sendonly | 约 280~320 kbps | 极低 | 约 300 kbps |
source: "remote" + sendonly | 约 280~320 kbps | 极低 | 约 300 kbps |
source: "local" + sendrecv | 约 280~320 kbps | 约 280~320 kbps | 约 600 kbps |
如同时配置一个local的 sendonly Processor 和一个remote的 sendonly Processor,浏览器到 Processor 服务的总上行带宽约为 600 kbps。
容量估算
以下数据按每个座席配置单个 Processor 估算:
| 在线座席 | 单路 sendonly | 单路 sendrecv |
|---|---|---|
| 100 | 约 30 Mbps | 约 60 Mbps |
| 500 | 约 150 Mbps | 约 300 Mbps |
| 1000 | 约 300 Mbps | 约 600 Mbps |
若每个座席同时推送 local 和 remote 两路 sendonly 音频,上行带宽约为单路 sendonly 的两倍。
以上数据仅包含浏览器与 Processor 之间的 WebSocket 音频流,不包含 WebRTC RTP 媒体流及业务信令。
CPU 消耗
浏览器仅负责音频数据复制、WebSocket 收发及本地音频 sendrecv 模式下的音频注入,不进行 AI 推理,因此 CPU 增量通常较低。
实际资源消耗取决于 Processor 数量、音频来源数量、浏览器性能和网络状况。
推荐配置
-
支持配置多个
source: "local"或source: "remote"的sendonlyProcessor。 -
同一 SDK 实例最多配置一个
sendrecvProcessor,且仅支持本地音频。 -
推荐单座席 Processor 总数不超过 5 个。
-
如多个业务需要消费同一来源音频,建议优先由服务端进行分发,减少浏览器侧重复连接和带宽消耗。
Processor 语音流与 WebRTC 通话媒体流相互独立。启用 Processor 不会改变浏览器与媒体服务器之间的 WebRTC 音频编码码率,只会增加浏览器与 Processor 之间的 WebSocket 音频流。
3.8 最佳实践
建议遵循以下配置方式:
-
座席或客户侧 ASR、实时质检、情绪分析、AI Agent 使用
sendonly。 -
AI 变声、声音美化、语音降噪使用
source: "local"和sendrecv。 -
一个 Processor 仅负责一种业务能力,避免多个能力共用同一 Processor。
-
processorReady表示 Processor 已可以正常处理语音。 -
processorError用于处理业务异常或记录日志。 -
processorClosed用于资源释放或业务状态更新。
4 WebSocket 协议
本章节介绍 CTICloud JS SDK 与 Processor 之间的 WebSocket 通信协议。
SDK 为每个 Processor 建立独立的 WebSocket 连接,并通过该连接完成 Processor Session 的创建、音频传输、状态同步及会话关闭。
4.1 协议概述
SDK 为每个 Processor 建立独立的 WebSocket 连接,并创建独立的 Processor Session。
每个 Processor Session 负责一次完整的语音处理过程,包括会话创建、实时音频传输及会话关闭。
消息的数据结构、消息类型及数据模型请参见《5 数据模型》章节。
4.2 消息交互流程
一次完整的 Processor Session 如下图所示。
sequenceDiagram participant SDK as CTICloud JS SDK participant Processor SDK->>Processor: Control(SessionStart) Processor-->>SDK: Session(Ready) loop Streaming SDK->>Processor: Audio(Uplink, source=local/remote) opt Mode = sendrecv Processor-->>SDK: Audio(Downlink, source=local) end end SDK->>Processor: Control(SessionEnd)
消息交互过程如下:
-
SDK 建立 WebSocket 连接。
-
SDK 发送
Control(SessionStart)创建 Processor Session。 -
Processor 返回
Session(Ready)。 -
SDK 开始持续发送
source指定的本地音频或远端音频。 -
当
source为local且mode为sendrecv时,Processor 持续返回处理后的本地音频。 -
通话结束后,SDK 发送
Control(SessionEnd)。 -
SDK 关闭 Processor Session。
4.3 Processor Session 生命周期
Processor Session 生命周期如下图所示。
stateDiagram-v2 [*] --> Disconnected Disconnected --> Connected : WebSocket Connected Connected --> Opening : SessionStart Opening --> Ready : Session Ready Ready --> Streaming Streaming --> Closing : SessionEnd Closing --> Closed Closed --> [*]
各状态说明如下:
| 状态 | 说明 |
|---|---|
| Disconnected | 未建立 WebSocket 连接。 |
| Connected | WebSocket 已建立。 |
| Opening | 正在创建 Processor Session。 |
| Ready | Processor Session 创建成功。 |
| Streaming | 正在传输实时音频。 |
| Closing | 正在关闭 Processor Session。 |
| Closed | Processor Session 已结束。 |
4.4 WebSocket 连接
SDK 为每个 Processor 建立独立的 WebSocket 连接。
WebRTC Call
│
┌───────────────┼───────────────┐
│ │ │
▼ ▼ ▼
Processor(ASR) Processor(QA) Processor(Voice)
│ │ │
▼ ▼ ▼
WebSocket #1 WebSocket #2 WebSocket #3连接管理规则如下:
-
每个 Processor 建立一个独立的 WebSocket 连接。
-
每个连接对应一个独立的 Processor Session。
-
各 Processor Session 相互独立,互不影响。
-
SDK 自动管理所有连接生命周期,开发者无需自行维护连接。
4.5 重连机制
当 WebSocket 连接异常断开时,SDK 将自动重新建立连接,并重新创建 Processor Session。
flowchart LR A[WebSocket 连接断开] --> B[重新建立 WebSocket] --> C[重新创建 Processor Session] --> D[恢复音频传输]
重连完成后:
-
SDK 将重新发送
Control(SessionStart)。 -
Processor 应创建新的 Processor Session。
-
不应继续使用断开前的 Session 状态。
-
后续音频数据将在新的 Processor Session 中继续传输。
5 数据模型
本章节定义 WebSocket 协议的数据模型及消息格式。
所有消息均采用统一的消息封装(Message Envelope),SDK 与 Processor 使用一致的消息结构进行通信。
5.1 Message Envelope
所有 WebSocket 消息均采用统一格式。
+------------------------+
| Header Length (4 Bytes)|
+------------------------+
| Header (JSON UTF-8) |
+------------------------+
| Payload (Binary/JSON) |
+------------------------+字段说明:
| 字段 | 说明 |
|---|---|
| Header Length | Header 长度,4 字节无符号整数(Big Endian)。 |
| Header | UTF-8 编码 JSON。 |
| Payload | 消息体。其数据类型由 Header.type 决定:Control 与 Session 为 JSON,Audio 为 PCM Binary。 |
SDK 首先读取 Header Length,然后解析 Header,再根据 Header.type 解析对应的 Payload。
5.2 Header
所有消息均包含统一 Header。
Header 数据结构
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| type | String | 是 | 消息类型。 |
| action | String | 否 | Control 消息动作。 |
| event | String | 否 | Session 消息事件。 |
| sessionId | String | 否 | Processor Session ID。 |
| direction | String | 否 | Audio 消息方向。 |
| source | String | 否 | 音频来源,取值为 local 或 remote,Audio 消息使用。 |
type
| 值 | 说明 |
|---|---|
| Control | 生命周期控制消息。 |
| Session | Session 状态消息。 |
| Audio | 音频数据消息。 |
5.3 ProcessorSession
ProcessorSession 表示一次 SDK 与 Processor 建立的语音处理会话。
数据结构
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| sessionId | String | 是 | Session 唯一标识。 |
| processorId | String | 是 | Processor ID。 |
| source | String | 是 | 音频来源,取值为 local 或 remote。 |
| mode | String | 是 | 处理模式,取值为 sendonly 或 sendrecv。 |
| uniqueId | String | 是 | 通话唯一标识。 |
| enterpriseId | String | 是 | 企业 ID。 |
| cno | String | 是 | 座席工号。 |
| customerNumber | String | 否 | 客户号码。 |
| callType | Integer | 是 | 通话类型。 |
| protocolVersion | String | 是 | 协议版本。 |
| uplinkFormat | AudioFormat | 是 | 上行音频格式。 |
| downlinkFormat | AudioFormat | 否 | 下行音频格式。 |
示例
{
"sessionId": "7db32cf6-17a6-4f58-8c09-d5d0db0ef871",
"processorId": "voice",
"source": "local",
"mode": "sendrecv",
"uniqueId": "sip-1-166514362901.12",
"enterpriseId": "60000001",
"cno": "8001",
"customerNumber": "13800138000",
"callType": 1,
"protocolVersion": "1.0",
"uplinkFormat": {
"sampleRate": 16000,
"channels": 1,
"sampleBits": 16,
"encoding": "pcm_s16le"
},
"downlinkFormat": {
"sampleRate": 16000,
"channels": 1,
"sampleBits": 16,
"encoding": "pcm_s16le"
}
}5.4 音频格式声明与确认
描述音频格式。
数据结构
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| sampleRate | Integer | 是 | 采样率(Hz)。 |
| channels | Integer | 是 | 声道数。 |
| sampleBits | Integer | 是 | 采样位数。 |
| encoding | String | 是 | 编码格式。 |
当前支持:
| 参数 | 值 |
|---|---|
| sampleRate | 16000 |
| channels | 1 |
| sampleBits | 16 |
| encoding | pcm_s16le |
音频格式协商
SDK 在创建 Processor Session 时,通过 SessionStart 携带 uplinkFormat 和(sendrecv 模式下)downlinkFormat。
当前版本支持:
-
Encoding:
pcm_s16le -
Sample Rate:
16000 Hz -
Channels:
1 -
Sample Bits:
16
Processor 支持该格式时返回 Session(Ready);否则返回 Session(Error),错误码 1102 UnsupportedFormat。
5.5 Control Message
Control 消息用于管理 Processor Session 生命周期。
SessionStart
Header:
{
"type": "Control",
"action": "SessionStart"
}Payload:
{
"session": {
...
}
}Payload 字段:
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| session | ProcessorSession | 是 | Session 信息。 |
SessionEnd
Header:
{
"type": "Control",
"action": "SessionEnd"
}Payload:
{
"sessionId": "7db32cf6-17a6-4f58-8c09-d5d0db0ef871"
}5.6 Session Message
Session 消息用于同步 Session 状态。
Ready
Header:
{
"type": "Session",
"event": "Ready"
}Payload:
{
"sessionId": "7db32cf6-17a6-4f58-8c09-d5d0db0ef871",
"result": 1000,
"description": "Success"
}Error
Header:
{
"type": "Session",
"event": "Error"
}Payload:
{
"sessionId": "7db32cf6-17a6-4f58-8c09-d5d0db0ef871",
"result": 1105,
"description": "Internal Error"
}5.7 Audio Message
Audio 消息用于传输实时 PCM 音频。
direction 始终以 SDK 与 Processor 之间的 WebSocket 传输方向为准,与 WebRTC 通话媒体方向无关:
-
Uplink:SDK → Processor;
-
Downlink:Processor → SDK。
Uplink
SDK 根据 Processor 配置中的 source 推送对应音频。
-
source: "local":本地音频(座席麦克风)。 -
source: "remote":远端音频。
Header:
{
"type": "Audio",
"direction": "Uplink",
"source": "local",
"sessionId": "7db32cf6-17a6-4f58-8c09-d5d0db0ef871"
}Payload:
PCM BinaryDownlink
仅 source: "local" 且 mode: "sendrecv" 的 Processor 可以发送 Downlink Audio。
Header:
{
"type": "Audio",
"direction": "Downlink",
"source": "local",
"sessionId": "7db32cf6-17a6-4f58-8c09-d5d0db0ef871"
}Payload:
PCM Binary要求:
-
不包含 WAV Header。
-
音频格式应与对应来源的 AudioFormat 保持一致。
-
音频数据应连续发送。
-
建议实时返回,不缓存整段音频。
音频帧频率与包大小
SDK 默认按约 60 ms 一帧发送 Audio Message。
| 帧时长 | PCM 大小 |
|---|---|
| 20 ms | 640 bytes |
| 40 ms | 1280 bytes |
| 60 ms(默认) | 1920 bytes |
| 100 ms | 3200 bytes |
Processor 建议保持与 SDK 相同或接近的回包频率。
| 项目 | 建议 |
|---|---|
| 回包周期 | 20~60 ms |
| 回包大小 | 640~1920 bytes |
| 最大建议 | 不超过 100 ms / 3200 bytes |
sendrecv 模式下应连续返回 PCM 数据,不建议缓存整段音频后一次发送。
5.8 ErrorCode
| Code | 名称 | 说明 |
|---|---|---|
| 1000 | Success | 成功。 |
| 1100 | InvalidRequest | 请求格式错误。 |
| 1101 | InvalidSession | Session 无效。 |
| 1102 | UnsupportedFormat | 不支持的音频格式。 |
| 1103 | UnsupportedMode | 不支持的处理模式。 |
| 1104 | AuthenticationFailed | 鉴权失败。 |
| 1105 | InternalError | Processor 内部异常。 |
5.9 数据模型关系
classDiagram
class Header {
type
action
event
sessionId
direction
source
}
class ProcessorSession {
sessionId
processorId
source
mode
uniqueId
enterpriseId
cno
}
class AudioFormat {
sampleRate
channels
sampleBits
encoding
}
Header --> ProcessorSession
ProcessorSession --> AudioFormat
6 Processor 开发指南
本章节介绍如何开发符合 CTICloud 协议规范的 Processor。
Processor 负责接收 CTICloud JS SDK 推送的本地或远端实时语音流,并根据业务需求完成语音识别、AI 推理、质检、情绪分析或声音处理等能力。
6.1 Processor 架构
一个典型的 Processor 包括以下模块:
flowchart LR WS["WebSocket Server"] --> Session["Session Manager"] Session --> Audio["Audio Pipeline"] Audio --> Engine["AI / DSP Engine"] Engine --> Output["Audio Output"] Output --> WS
各模块职责如下:
| 模块 | 职责 |
|---|---|
| WebSocket Server | 建立 WebSocket 连接,收发协议消息。 |
| Session Manager | 管理 Processor Session 生命周期。 |
| Audio Pipeline | 接收、缓存及调度音频流。 |
| AI / DSP Engine | 执行语音识别、声音处理、AI 推理等业务逻辑。 |
| Audio Output | 将处理后的音频返回 SDK(仅 sendrecv 模式)。 |
6.2 Processor 生命周期
建议 Processor 按以下流程管理 Session。
stateDiagram-v2 [*] --> Idle Idle --> Connected : WebSocket Connected Connected --> Ready : SessionStart Ready --> Processing : Audio Processing --> Closing : SessionEnd Closing --> Idle
生命周期说明:
-
建立 WebSocket 连接。
-
接收
SessionStart。 -
创建 Processor Session。
-
接收实时音频。
-
执行业务处理。
-
返回处理后的音频(可选)。
-
接收
SessionEnd后释放资源。
6.3 音频处理流程
Processor 收到音频后,应立即进入处理流程。
flowchart LR PCM["PCM Audio"] --> Buffer["Jitter Buffer"] --> Process["AI / DSP"] --> Output["PCM Audio"] --> SDK["CTICloud JS SDK"]
推荐处理流程:
-
接收
source指定的 PCM 音频。 -
根据业务需要进行缓冲或重采样。
-
调用 AI 或 DSP 引擎处理。
-
sendrecv模式下实时返回处理后的 PCM 音频。
6.4 sendonly 模式
sendonly 模式仅接收指定来源的音频,不返回处理后的音频。
适用于以下场景:
-
实时语音识别(ASR)
-
AI Agent
-
实时质检
-
情绪分析
-
VAD 检测
Processor 无需发送 Audio Message。
6.5 sendrecv 模式
sendrecv 模式需要返回处理后的本地音频,当前仅支持 source: "local"。
适用于以下场景:
-
AI 变声
-
声音美化
-
语音降噪
-
实时翻译
要求:
-
返回连续 PCM 数据。
-
音频格式与 Session 协商结果保持一致。
-
不得返回 WAV Header。
-
保持实时输出,避免一次返回大段音频。
6.6 Session 管理
建议每个 Processor Session 独立管理。
推荐维护以下信息:
| 字段 | 说明 |
|---|---|
| sessionId | Session 唯一标识。 |
| uniqueId | 通话唯一标识。 |
| processorId | Processor 标识。 |
| source | 音频来源。 |
| mode | 处理模式。 |
| createTime | Session 创建时间。 |
| lastAudioTime | 最近一次收到音频时间。 |
一个 Session 不应同时处理多个通话。
6.7 性能建议
为保证实时语音体验,建议遵循以下原则。
低延迟处理
-
收到音频后立即处理。
-
避免长时间缓存。
-
尽量采用流式处理。
异步处理
建议将网络收发与 AI 推理解耦。
WebSocket IO
│
▼
Audio Queue
│
▼
AI Worker
│
▼
Output Queue
│
▼
WebSocket Send并发处理
每个 Session 独立处理。
避免多个 Session 共用同一处理线程。
6.8 异常处理
建议 Processor 正确处理以下异常:
| 场景 | 建议处理方式 |
|---|---|
| Session 不存在 | 返回 Session.Error。 |
| 音频格式错误 | 返回 UnsupportedFormat。 |
| AI 引擎异常 | 返回 InternalError。 |
| WebSocket 断开 | 立即释放 Session。 |
| 长时间无音频 | 自动关闭 Session。 |
6.9 最佳实践
建议遵循以下实践:
-
一个 Processor 仅负责一种业务能力。
-
每个 Session 独立管理资源。
-
使用无锁队列或 RingBuffer 传递音频。
-
AI 推理与 WebSocket IO 分离。
-
避免阻塞 WebSocket 收发线程。
-
返回音频保持连续,避免明显抖动。
-
通话结束后及时释放 Session 资源。
7 Processor 示例
本章节通过一个 Echo Processor 示例,演示如何实现符合 CTICloud 协议规范的 Processor。
Echo Processor 不对音频进行任何处理,而是将收到的音频原样返回,可用于快速验证 SDK 接入及协议实现是否正确。
7.1 Processor 实现流程
一个典型 Processor 的处理流程如下。
flowchart LR A[启动 WebSocket 服务] --> B[等待 SDK 建立连接] --> C[接收 SessionStart] --> D[创建 Processor Session] --> E[接收 Audio] --> F[处理音频] --> G[返回 Audio] --> H[接收 SessionEnd] --> I[释放资源]
7.2 Processor 生命周期
sequenceDiagram participant SDK participant Processor SDK->>Processor: 建立 WebSocket SDK->>Processor: Control(SessionStart) Processor-->>SDK: Session(Ready) loop Audio Streaming SDK->>Processor: Audio(Uplink, source=local/remote) Processor-->>SDK: Audio(Downlink, source=local) end SDK->>Processor: Control(SessionEnd)
7.3 Echo Processor
Echo Processor 是最简单的 Processor。
收到音频后立即原样返回。
处理流程如下:
收到 Audio
↓
无需处理
↓
立即发送 Audio适用于:
-
SDK 联调
-
网络验证
-
音频格式验证
-
延迟测试
7.4 Processor 处理逻辑
Processor 建议按照如下流程实现。
Control
收到:
SessionStart处理:
-
创建 Session。
-
保存 Session 信息。
-
返回
Session(Ready)。
收到:
SessionEnd处理:
-
释放 Session。
-
清理缓存。
-
关闭 AI Engine。
Audio
收到 Audio 后:
PCM
↓
缓存(可选)
↓
AI/DSP
↓
PCM
↓
返回 SDK对于:
sendonly
无需返回 Audio。
对于:
sendrecv
应持续返回处理后的 PCM。
7.5 推荐线程模型
建议网络收发与 AI 推理解耦。
flowchart LR WS["WebSocket IO"] --> Queue["Audio Queue"] Queue --> Worker["AI Worker"] Worker --> Output["Output Queue"] Output --> Sender["WebSocket Sender"]
各模块职责:
| 模块 | 职责 |
|---|---|
| WebSocket IO | 接收协议消息。 |
| Audio Queue | 音频缓冲。 |
| AI Worker | AI 推理或 DSP 处理。 |
| Output Queue | 等待发送音频。 |
| WebSocket Sender | 返回 Audio。 |
7.6 Session 管理
建议每个 Session 独立维护状态。
推荐维护:
| 字段 | 说明 |
|---|---|
| sessionId | Session ID |
| processorId | Processor ID |
| uniqueId | 通话唯一标识 |
| createTime | 创建时间 |
| lastAudioTime | 最近收到 Audio 时间 |
建议:
-
一个 Session 对应一个通话。
-
一个 Session 不共享状态。
-
Session 结束立即释放资源。
7.7 性能建议
建议:
-
使用流式处理。
-
不缓存整段音频。
-
AI 推理与 WebSocket IO 分离。
-
使用无锁队列传递音频。
-
控制内存占用。
-
Session 超时自动释放。
建议端到端处理延迟不超过:
| 指标 | 建议值 |
|---|---|
| 单帧处理时间 | ≤20 ms |
| Processor 平均处理延迟 | ≤100 ms |
| 最大处理延迟 | ≤300 ms |
7.8 联调建议
建议按照以下步骤进行联调。
-
完成 SDK 配置。
-
启动 Echo Processor。
-
建立 WebRTC 通话。
-
确认收到
SessionStart。 -
确认持续收到 Audio。
-
Echo 返回 Audio。
-
通话结束收到
SessionEnd。
如果以上步骤均正常,则说明:
-
SDK 配置正确;
-
WebSocket 协议正确;
-
Audio 格式正确;
-
Processor 可以正常工作。
7.9 示例工程
为帮助开发者快速完成 Processor 开发,CTICloud 提供了示例工程。
目前提供以下示例:
| 示例 | 说明 |
|---|---|
| echo-processor-python | Python 实现的 Echo Processor,用于快速验证 SDK 接入及 WebSocket 协议。 |
示例工程地址:
echo-processor-python (暂未开放,后续发布)
示例工程包含以下能力:
-
WebSocket Server
-
Processor Session 管理
-
SessionStart / SessionEnd 处理
-
Audio Message 接收
-
Echo 音频回传
-
sendrecv 模式实现
-
日志输出
8 常见问题
8.1 WebSocket 无法建立连接
请检查以下配置:
-
Processor 地址是否正确。
-
是否使用
wss://。 -
HTTPS 页面是否允许建立 WebSocket。
-
WebSocket 服务是否正常启动。
-
网络、防火墙或代理是否阻止连接。
8.2 收不到 SessionStart
请确认:
-
已成功发起 WebRTC 通话。
-
已正确配置
media.audio.processors。 -
Processor 已成功建立 WebSocket 连接。
8.3 收不到 Audio
请检查:
-
浏览器是否已授权麦克风权限。
-
座席是否正常发送语音。
-
Processor Session 是否已进入 Ready 状态。
-
AudioFormat 是否协商成功。
8.4 sendrecv 模式没有声音
请确认:
-
Processor 已持续返回 Audio Message。
-
返回音频格式与 Session 协商一致。
-
返回音频不包含 WAV Header。
-
返回的是连续 PCM 数据,而不是整段录音。
8.5 Processor 收到异常关闭
Processor Session 可能因以下原因关闭:
-
通话结束。
-
浏览器关闭。
-
WebSocket 连接断开。
-
SDK 主动关闭 Processor。
收到 SessionEnd 后,应及时释放 Session 资源。
8.6 Processor 自动重连
当 WebSocket 连接异常断开时,SDK 将自动重新建立连接并创建新的 Processor Session。
Processor 不应继续使用旧 Session,应重新初始化相关资源。
8.7 如何选择 Source
| 业务需求 | Source |
|---|---|
| 处理本地音频(座席麦克风) | local |
| 处理远端音频 | remote |
| 同时处理本地与远端两路音频 | 分别配置两个 sendonly Processor,或由服务端对两路音频进行关联处理 |
当前版本不提供 mixed 音频源。需要本地与远端音频混音时,建议由 Processor 服务根据同一 uniqueId 关联两路 Processor Session,并在服务端完成混音。
8.8 如何选择 Mode
建议根据业务场景选择:
| 场景 | Source | Mode |
|---|---|---|
| 座席语音识别(ASR) | local | sendonly |
| 客户语音识别(ASR) | remote | sendonly |
| AI Agent | local / remote | sendonly |
| 实时质检 | local / remote | sendonly |
| AI 变声 | local | sendrecv |
| 声音美化 | local | sendrecv |
| 语音降噪 | local | sendrecv |
| 实时翻译 | local | sendrecv |
8.9 一个通话可以配置几个 Processor
支持同时配置多个 Processor。
限制如下:
-
支持多个
sendonlyProcessor。 -
同一时间最多只能配置一个
sendrecvProcessor。
各 Processor 独立建立 WebSocket 连接,互不影响。
8.10 Audio Message 是否支持 WAV
不支持。
Audio Message 仅支持原始 PCM 数据。
请勿发送:
-
WAV
-
MP3
-
AAC
-
Opus
等包含文件头或压缩编码的数据。
8.11 如何降低处理延迟
建议:
-
使用流式处理。
-
避免缓存整段音频。
-
AI 推理与 WebSocket IO 分离。
-
保持连续输出。
-
单帧处理时间建议不超过 20 ms。
9 诊断与联调
本章节提供 Processor 联调及问题定位建议。
9.1 消息时序
一次正常会话建议按以下顺序完成。
| 序号 | 消息 | 方向 |
|---|---|---|
| 1 | WebSocket Connected | SDK → Processor |
| 2 | Control(SessionStart) | SDK → Processor |
| 3 | Session(Ready) | Processor → SDK |
| 4 | Audio(Uplink, source=local/remote) | SDK → Processor |
| 5 | Audio(Downlink, source=local,可选) | Processor → SDK |
| 6 | Control(SessionEnd) | SDK → Processor |
9.2 联调检查项
建议按以下顺序排查:
| 检查项 | 说明 |
|---|---|
| WebSocket 是否建立 | 检查网络、TLS、鉴权。 |
| SessionStart 是否收到 | 检查 SDK 配置及 Processor 日志。 |
| Session(Ready) 是否返回 | 检查 Session 创建逻辑。 |
| Audio 是否持续接收 | 检查麦克风及 AudioFormat。 |
| Audio 是否持续回传 | sendrecv 模式检查回包频率及大小。 |
| SessionEnd 是否收到 | 检查资源释放逻辑。 |
9.3 建议监控指标
| 指标 | 建议值 |
|---|---|
| WebSocket RTT | < 100 ms |
| Processor 平均处理延迟 | < 100 ms |
| 单帧处理时间 | ≤ 20 ms |
| Audio 连续回包 | 无明显间断 |
| Session 创建成功率 | ≥ 99.9% |
9.4 建议日志
建议记录以下日志:
-
WebSocket 建立与关闭
-
SessionStart / SessionEnd
-
Session Error
-
Audio 收发统计
-
Processor 异常及堆栈
-
平均处理耗时