WebSocket合成

WebSocket 流式语音合成

服务概述

  • 通过 WebSocket 长连接进行流式语音合成,客户端发送 JSON 文本帧,服务端返回任务初始化、音频分片、任务完成、文件持久化结果或错误事件。
  • WebSocket 接口适用于需要在同一连接内连续发送多条合成请求、并按任务 ID 归并返回事件的实时语音场景。

服务申请

语音合成 API 采用全流程自助申请模式。在云上曲率官网(https://www.ilivedata.com/) 注册并激活账号后,在控制台创建语音合成项目,即可获得 appId 和服务密钥。

如需开通更多服务,可在管理控制台-总览页面开通其他服务。

接入流程

  1. 调用 Token 签发接口,使用 appId 和 secretKey 完成 auth 鉴权,获取 WebSocket Token。
  2. 使用返回的 wsUrl 拼接 token 参数建立 WebSocket 连接。
  3. 建连成功后,客户端通过 WebSocket 发送合成请求 JSON。
  4. 服务端通过 WebSocket 返回 init、audio、done、file_ready、file_error、error 事件。

获取 WebSocket Token

请求 URL

https://tts.ilivedata.com/api/v2/speech/synthesis/ws-token

HTTP 请求头

请求头 值 描述
X-AppId 例:81900001 项目或应用的唯一标识符
X-TimeStamp 例:2024-07-01T07:59:59Z 请求的 UTC 时间戳。需要把时间戳按 W3C 标准格式化
Authorization 例:Njl86M/jY6zZaZoGhZdGO+GI/8+yGFECusGH1yQHUFE= 签名值

请求方法:GET

请求签名

当用户请求 Token 签发接口时,使用 appId 和 secretKey 对请求做签名。当 API 收到带签名信息的请求之后,将使用相同的算法验证签名。如果发现签名不一致,API 将会返回鉴权失败。

签名计算方法

签名计算规则请参考帮助中心的请求签名。Token 签发接口为 GET 请求,通常没有请求体,按 GET 无请求体场景计算签名。HTTPRequestURI 是请求 URI 的绝对路径,不包含请求串。

签名示例

GET
tts.ilivedata.com
/api/v1/speech/synthesis/ws-token
X-AppId:81900001
X-TimeStamp:2024-11-01T07:59:59Z

请求示例

curl -X GET 'https://tts.ilivedata.com/api/v1/speech/synthesis/ws-token' \
  -H 'X-AppId: 81900001' \
  -H 'X-TimeStamp: 2024-11-01T07:59:59Z' \
  -H 'Authorization: {signature}'

响应示例

{
  "token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
  "expiresIn": 60,
  "expiresAt": 1782359144,
  "wsUrl": "wss://tts.ilivedata.com/api/v1/speech/synthesis/ws"
}

响应字段说明

字段名 类型 描述
token String WebSocket JWT,签名算法为 RS256
expiresIn Number Token 有效期,单位秒。Token 需要在有效期内用于建立 WebSocket 连接
expiresAt Number Token 过期时间,Unix 秒
wsUrl String TTS WebSocket 连接地址,不含 token 参数

建立 WebSocket 连接

WebSocket 连接地址

wss://tts.ilivedata.com/api/v1/speech/synthesis/ws?token={token}

Token 只用于 WebSocket 握手鉴权。连接建立成功后,当前连接不会因为 Token 到期自动断开;如果连接断开后需要重连,应重新获取 Token。

TTS 服务会校验 JWT 的签名、过期时间、aud、iss、scope、path 和 appId。请求消息中的 appId 必须与 Token 中的 appId 一致。

WebSocket 请求参数

建连成功后,客户端通过 WebSocket 文本消息发送请求体 JSON。

顶层参数

参数 是否必需 类型 描述
appId 条件必需 Number 与 request.appId 二选一;服务端优先取顶层 appId
sessionId 可选 String 业务会话 ID;不传时同一 WebSocket 连接内复用连接级默认 sessionId
persist 可选 Boolean 是否将完整音频上传到对象存储,默认为 false
request 必需 Object 合成请求体,结构与 SynthesisRequest 一致

request

参数 是否必需 类型 描述
appId 条件必需 Number 与顶层 appId 二选一
text 必需 String 合成文本,去除首尾空白后不能为空。支持情绪标签,参照情绪控制
language 可选 String 文本内容所属语种,推荐传入此语言参数;不传则使用自动语种检测结果。支持语种请参考语种列表
voice 可选 VoiceSetting 合成声音相关配置
output 可选 OutputSetting 输出音频相关配置

VoiceSetting

参数 必需 类型 描述
name 可选 String 预置音色库或音色注册的音色名称
audio 可选 String 未指定音色名称时,可以通过此参数指定的音频文件进行音色克隆
emotion 可选 String 情感表达

OutputSetting

参数 必需 类型 描述
format 可选 String 选择输出合成音频格式,候选为 pcm、wav、mp3、opus,默认为 wav
loudnessLufs 可选 Number 模型目标响度,单位 LUFS,范围为 -30.0 到 -6.0;不传表示不处理
speed 可选 Number 模型语速/播放速度倍率;<=0 或 1.0 表示不变,其他有效范围为 0.5 到 2.0

情绪控制

模型支持通过情绪标签控制指定文本片段的合成情绪。

情绪值 描述
angry 愤怒
happy 开心
sad 悲伤
feared 恐惧
amazed 惊讶

在 text 中使用以下格式添加情绪标签,其中开始标签与结束标签的情绪值需保持一致: <#emotion:情绪值>文本内容</#emotion:情绪值> 使用示例:

<#emotion:happy>这是一个测试</#emotion:happy>
happy 可替换为 angry、happy、sad、feared 或 amazed。

请求体示例

{
  "appId": 81900001,
  "persist": false,
  "request": {
    "appId": 81900001,
    "text": "您好,这是一个 WebSocket 流式语音合成示例。",
    "language": "zh-CN",
    "voice": {
      "name": "juvenile"
    },
    "output": {
      "format": "mp3",
      "loudnessLufs": -18,
      "speed": 1.25
    }
  }
}

如果客户端需要自定义业务会话,可显式传入 sessionId:

{
  "appId": 81900001,
  "sessionId": "biz-session-001",
  "request": {
    "appId": 81900001,
    "text": "同一个业务会话内的第一条消息。",
    "voice": {
      "name": "juvenile"
    },
    "output": {
      "format": "mp3",
      "loudnessLufs": -18,
      "speed": 1.25
    }
  }
}

WebSocket 响应事件

响应中的 status 表示当前事件的文本状态,taskStatus 表示整个语音合成任务的状态码。taskStatus 取值如下:

值 枚举 描述
1 PENDING 任务等待处理
2 PROCESSING 任务处理中
3 FAILED 任务失败
4 SUCCEEDED 任务成功

init 事件

表示服务端已接受该任务,并返回任务标识信息。

字段名 类型 描述
event String 固定为 init
taskId String 任务 ID,由服务端生成
sessionId String 会话 ID;客户端未传时由服务端按连接生成
status String 固定为 init
taskStatus Number 任务状态
{
  "event": "init",
  "taskId": "bj_ws_1b3d21549d3841d3b4400829403a4fff",
  "sessionId": "bj_ws_5f45c8fa85814b159741c80620f705bf",
  "status": "init",
  "taskStatus": 1
}

audio 事件

表示一个音频分片。

字段名 类型 描述
event String 固定为 audio
taskId String 任务 ID
sessionId String 会话 ID
seq Number 音频分片序号
itemIndex Number 文本分片索引
itemDone Boolean 当前 itemIndex 是否完成
sampleRate Number 当前音频分片采样率
durationMs Number 当前音频分片时长,单位毫秒
audioBase64 String 音频二进制分片的 Base64 字符串
status String 固定为 streaming
taskStatus Number 固定为处理中状态 2
{
  "event": "audio",
  "taskId": "bj_ws_1b3d21549d3841d3b4400829403a4fff",
  "sessionId": "bj_ws_5f45c8fa85814b159741c80620f705bf",
  "seq": 12,
  "itemIndex": 0,
  "itemDone": false,
  "sampleRate": 22050,
  "durationMs": 120,
  "audioBase64": "...",
  "status": "streaming",
  "taskStatus": 2
}

done 事件

表示实时音频合成及所有音频分片发送完成。该事件不等待对象存储上传,也不包含文件 URL。

字段名 类型 描述
event String 固定为 done
taskId String 任务 ID
sessionId String 会话 ID
status String 固定为 done
taskStatus Number 固定为成功状态 4
{
  "event": "done",
  "taskId": "bj_ws_1b3d21549d3841d3b4400829403a4fff",
  "sessionId": "bj_ws_5f45c8fa85814b159741c80620f705bf",
  "status": "done",
  "taskStatus": 4
}

file_ready 事件

仅当请求设置 persist=true 时返回,表示完整音频文件已上传成功。

字段名 类型 描述
event String 固定为 file_ready
taskId String 任务 ID
sessionId String 会话 ID
status String 固定为 file_ready
taskStatus Number 固定为成功状态 4
url String 上传后的音频文件访问地址
{
  "event": "file_ready",
  "taskId": "bj_ws_1b3d21549d3841d3b4400829403a4fff",
  "sessionId": "bj_ws_5f45c8fa85814b159741c80620f705bf",
  "status": "file_ready",
  "taskStatus": 4,
  "url": "https://xxx.cos.accelerate.myqcloud.com/tts/.../bj_ws_1b3d21549d3841d3b4400829403a4fff.mp3"
}

file_error 事件

仅当请求设置 persist=true 时可能返回,表示语音合成已经成功,但完整文件上传失败。此时任务仍保持成功状态。

字段名 类型 描述
event String 固定为 file_error
taskId String 任务 ID
sessionId String 会话 ID
status String 固定为 file_error
taskStatus Number 固定为成功状态 4
errorCode Number 文件持久化错误码
errorMessage String 文件持久化错误信息
{
  "event": "file_error",
  "taskId": "bj_ws_1b3d21549d3841d3b4400829403a4fff",
  "sessionId": "bj_ws_5f45c8fa85814b159741c80620f705bf",
  "status": "file_error",
  "taskStatus": 4,
  "errorCode": 2,
  "errorMessage": "Unexpected result, contact LiveData technical staff please."
}

error 事件

表示任务失败。

字段名 类型 描述
event String 固定为 error
taskId String 任务 ID,若请求未进入任务初始化阶段可能为空
sessionId String 会话 ID,若请求未进入任务初始化阶段可能为空
status String 固定为 error
taskStatus Number 固定为失败状态 3
errorCode Number 错误码
errorMessage String 错误信息
{
  "event": "error",
  "taskId": "bj_ws_1b3d21549d3841d3b4400829403a4fff",
  "sessionId": "bj_ws_5f45c8fa85814b159741c80620f705bf",
  "status": "error",
  "taskStatus": 3,
  "errorCode": 3003,
  "errorMessage": "Invalid voice name."
}

taskId 与 sessionId 规则

  • 客户端不需要传 taskId。服务端会为每条消息生成新的唯一 taskId,并在该任务的所有响应事件中返回。
  • 如果客户端传入 taskId,服务端会忽略该字段,仍然使用服务端生成的 taskId。
  • 客户端不传 sessionId 时,服务端会在 WebSocket 建连时生成一个连接级默认 sessionId;同一连接内多条消息会返回相同 sessionId。
  • 客户端显式传入 sessionId 时,服务端优先使用客户端传入的 sessionId。

断线处理说明

  • WebSocket 断开后,客户端需要重新建立连接并重新发送合成请求。
  • 服务端不会使用客户端传入的 taskId 做任务级恢复。
  • 如果业务需要关联断线前后的请求,可由客户端传入同一个 sessionId 作为业务会话标识。

客户端处理建议

  • Token 有有效期,建议获取后立即建立 WebSocket 连接。
  • 收到 init 后可记录服务端返回的 taskId 和 sessionId,用于日志排查和业务侧事件归并。
  • audioBase64 需要 Base64 解码后再播放或缓存。
  • persist=false 时,事件序列为 init -> audio* -> done。
  • persist=true 时,成功序列为 init -> audio* -> done -> file_ready;收到 done 表示实时流已完成,需要从后续 file_ready 事件获取文件 URL。
  • persist=true 且文件上传失败时,服务端在 done 后返回 file_error,不影响语音合成任务的成功状态。
  • 若连接断开,需要重新建立 WebSocket 连接并重新发送请求;新的请求会生成新的 taskId。