WebSocket协议说明

更新时间:
复制 MD 格式

通过 WebSocket 协议向 CosyVoice 大模型分段发送文本,并接收流式合成音频。适用于不使用 SDK、直接开发语音合成客户端的场景。

交互流程

客户端通过文本帧发送 JSON 指令,服务端通过文本帧返回 JSON 事件,通过二进制帧返回音频。

  1. 携带 Token 建立 WebSocket 连接。

  2. 发送 StartSynthesis,配置音色和音频格式。

  3. 收到 SynthesisStarted 后,通过一次或多次 RunSynthesis 发送文本,并持续接收事件和音频。

  4. 文本发送完毕后,发送 StopSynthesis。服务端继续合成缓存中的文本。

  5. 收到 SynthesisCompleted 后,结束本次任务的音频接收。

有关服务交互方式,请参见CosyVoice 大模型语音合成。

鉴权与连接

服务端使用临时 Token 鉴权。获取方法请参见获取Token。

访问类型

使用条件

URL

外网访问

通过公网连接北京地域的服务。

wss://nls-gateway-cn-beijing.aliyuncs.com/ws/v1

ECS 内网访问

使用华北 2(北京)地域 VPC 内的 ECS。经典网络不支持此访问方式。

ws://nls-gateway-cn-beijing-internal.aliyuncs.com:80/ws/v1

说明

使用内网访问方式,不产生 ECS 实例的公网流量费用。

在连接 URL 中添加 token 查询参数,例如:

wss://nls-gateway-cn-beijing.aliyuncs.com/ws/v1?token=<token>

请求指令

请求使用 JSON 文本帧。header 标识任务和指令,payload 携带对应指令的参数。以下 JSON 为请求结构示例;实际调用时替换 Appkey,并为每条消息生成唯一 ID。

Header 格式

参数

类型

必选

说明

header.appkey

String

是

在智能语音交互控制台创建的项目 Appkey。

header.message_id

String

是

当前消息的唯一 ID,长度为 32 位。

header.task_id

String

是

当前合成任务的唯一 ID,长度为 32 位。同一任务的所有指令使用相同值。

header.namespace

String

是

固定为 FlowingSpeechSynthesizer。

header.name

String

是

指令名称:StartSynthesis、RunSynthesis 或 StopSynthesis。

StartSynthesis 指令

开始合成任务并设置音色和输出格式。

参数

类型

必选

说明

payload.voice

String

否

音色,默认值:longxiaochun。示例使用 longxiaochun_v2。

payload.format

String

否

音频格式:pcm、wav 或 mp3。默认值:pcm。

payload.sample_rate

Integer

否

音频采样率,单位:Hz。默认值:16000。

payload.volume

Integer

否

音量,取值范围:0~100。默认值:50。

payload.speech_rate

Integer

否

语速,取值范围:-500~500。默认值:0。-500、0、500 分别对应 0.5、1、2 倍速。

payload.pitch_rate

Integer

否

语调,取值范围:-500~500。默认值:0。

payload.enable_ssml

Boolean

否

是否开启 SSML。标签用法请参见SSML 标记语言。

payload.enable_subtitle

Boolean

否

使用 longxiaochun_v2 时,设置为 true 可获取字级时间戳。longxiaochun 在相同设置下不返回字级时间戳。

以下参数用于配置 AIGC 隐性标识:

参数

类型

必选

说明

payload.enable_aigc_tag

Boolean

否

是否在生成的音频中添加AIGC隐性标识。设置为true时,会将隐性标识嵌入到支持格式(wav/mp3/opus)的音频中。

默认值:false。

payload.aigc_propagator

String

否

设置AIGC隐性标识中的 ContentPropagator 字段,用于标识内容的传播者。仅在 enable_aigc_tag 为 true 时生效。

默认值:阿里云UID。

payload.aigc_propagate_id

String

否

设置AIGC隐性标识中的 PropagateID 字段,用于唯一标识一次具体的传播行为。仅在 enable_aigc_tag 为 true 时生效。

默认值:本次语音合成请求Task ID。

{
  "header": {
    "message_id": "05450bf69c53413f8d88aed1ee600001",
    "task_id": "640bc797bb684bd69601856513070001",
    "namespace": "FlowingSpeechSynthesizer",
    "name": "StartSynthesis",
    "appkey": "<appkey>"
  },
  "payload": {
    "voice": "longxiaochun_v2",
    "format": "wav",
    "sample_rate": 16000,
    "volume": 50,
    "speech_rate": 0,
    "pitch_rate": 0,
    "enable_ssml": true
  }
}

RunSynthesis 指令

收到 SynthesisStarted 后发送文本。同一任务中可多次调用。

参数

类型

必选

说明

payload.text

String

是

本次发送的待合成文本。

{
  "header": {
    "message_id": "05450bf69c53413f8d88aed1ee600002",
    "task_id": "640bc797bb684bd69601856513070001",
    "namespace": "FlowingSpeechSynthesizer",
    "name": "RunSynthesis",
    "appkey": "<appkey>"
  },
  "payload": {
    "text": "今天阳光很好。"
  }
}

StopSynthesis 指令

文本发送完毕后,发送此指令结束输入。服务端合成剩余缓存文本,返回剩余音频后发送 SynthesisCompleted。不要把此指令理解为立即丢弃剩余文本或中断音频输出。该指令不需要 payload。

{
  "header": {
    "message_id": "05450bf69c53413f8d88aed1ee600003",
    "task_id": "640bc797bb684bd69601856513070001",
    "namespace": "FlowingSpeechSynthesizer",
    "name": "StopSynthesis",
    "appkey": "<appkey>"
  }
}

响应事件

事件使用 JSON 文本帧。header.name 标识事件,header.status 为状态码,header.status_text 为状态描述。成功状态码为 20000000。以下 JSON 为结构示例,仅展示相关字段。

SynthesisStarted 事件

表示合成任务已开始,可以发送 RunSynthesis。

{
  "header": {
    "namespace": "FlowingSpeechSynthesizer",
    "name": "SynthesisStarted",
    "status": 20000000,
    "status_text": "Gateway:SUCCESS:Success."
  }
}

Sentence 系列事件

根据 payload.index 关联同一合成分段的事件。序号从 0 开始。不要将 RunSynthesis 的调用次数或输入文本的标点数量直接作为输出分段数量。

事件

payload 字段

说明

SentenceBegin

index

分段开始。

SentenceSynthesis

index、subtitles

合成过程中的分段信息。不要假设每个分段固定返回一次此事件。

SentenceEnd

index、subtitles

分段结束。

subtitles 为时间戳数组。longxiaochun_v2 开启 enable_subtitle 后可返回字级文本及 begin_time、end_time;未开启时可返回空数组。时间戳支持情况取决于音色,longxiaochun 在相同开关下仍返回空数组。

SynthesisCompleted 事件

表示本次任务的音频已经全部下发。文本发送完毕后必须发送 StopSynthesis,再等待此事件;一直不结束输入可能触发空闲超时。

{
  "header": {
    "namespace": "FlowingSpeechSynthesizer",
    "name": "SynthesisCompleted",
    "status": 20000000,
    "status_text": "Gateway:SUCCESS:Success."
  },
  "payload": {
    "measureType": "TextLengthHD",
    "measureLength": 57
  }
}

TaskFailed 事件

表示任务失败。记录 header.status、header.status_text 和 header.task_id 排查问题。例如,未结束输入且连接长时间空闲时,可返回 40000004 和 Gateway:IDLE_TIMEOUT 状态描述。

下行数据处理

将文本帧解析为事件,将二进制帧按接收顺序保存为音频。以下代码仅展示 websocket-client 的消息回调,不包含连接和发送指令的流程。创建 WebSocketApp 时,将该函数作为 on_message 传入;每次任务开始前创建新的 audio_data。

import json

audio_data = bytearray()

def on_message(ws, message):
    if isinstance(message, str):
        # 解析服务端事件。
        try:
            event = json.loads(message)
        except json.JSONDecodeError:
            print("Invalid JSON event")
            return
        header = event.get("header", {})
        print(header.get("name"), header.get("status"))
    elif isinstance(message, (bytes, bytearray)):
        # 将音频数据按接收顺序追加到同一缓冲区。
        audio_data.extend(message)

WebSocket 接口定义请参见WebSocket 标准。

音频保存与播放

音频从发送 RunSynthesis 后开始返回,直到 SynthesisCompleted 前完成下发。

  • 按接收顺序将所有二进制帧写入同一个音频文件,或交给支持对应格式和流式输入的播放器。

  • 不要将每个 WebSocket 二进制帧视为独立音频文件分别解码。帧边界不等于音频文件边界。

  • WAV 等带文件头的音频流包含文件头信息,后续二进制帧可能只包含连续音频数据。保存时不要为每一帧重复添加文件头。

JavaScript 示例代码

参考长文本语音合成JS播放示例实现浏览器中的流式语音合成和播放。

打开 index.html 前,替换 app.js 中的 appkey 和 token,并将 voice 改为 CosyVoice 音色,例如 longxiaochun。在示例目录启动 HTTP 服务后,访问 http://localhost:8000。

python -m http.server 8000

页面提供以下按钮:

  • StartSynthesis:建立连接并开始任务。

  • RunSynthesis:发送文本框中的文本片段。同一任务可多次单击。

  • StopSynthesis:结束文本输入,等待剩余音频和完成事件。

    流式播放器说明

    audio_player.js 使用 Web Audio API 实现 PCMAudioPlayer,将 16 位 PCM 采样点转换为浮点数后写入 AudioBuffer,在上一段音频的 onended 回调中播放下一段。

    重要
    • 如果使用 MediaSource,先检查目标浏览器和音频格式的支持情况。兼容性信息请参见MediaSource。

    • 使用 openai-realtime-console 中的 wavtools 时,注意移动端和 Safari 可能出现的播放噪声,接入前应在目标设备验证播放效果。

测试工具

使用NlsStreamInputTtsMockServer.py在本地模拟语音合成服务。脚本依赖 websockets,并读取运行目录中的 test.wav;运行前准备该音频文件。

pip install websockets
python NlsStreamInputTtsMockServer.py

脚本默认监听 ws://127.0.0.1:12345。模拟服务用于调试消息交互,不能用于验证云端音色、时间戳或其他模型能力。最终应连接云端服务验证。