> ## Documentation Index
> Fetch the complete documentation index at: https://docs.senseaudio.cn/llms.txt
> Use this file to discover all available pages before exploring further.

# 语音合成 WebSocket (TTS)

> 基于 WebSocket 的实时 TTS 合成协议参考

## 说明

基于 WebSocket 的实时文本到语音合成接口，支持增量式文本输入与流式音频输出，适用于实时对话、在线客服、边生成边播报等低延迟场景。单次连接支持多次合成任务，最大文本长度 10000 字符。

* **接入地址**：`wss://api.senseaudio.cn/ws/v1/t2a_v2`
* **鉴权方式**：Bearer Token，格式 `Authorization: Bearer SENSEAUDIO_API_KEY`
* **消息格式**：`application/json`，音频仅返回 hex 编码字符串
* **计费单位**：按合成字符数计费，详见 [计费说明](/guides/account/billing)
* **音色入参**：`voice_id` 必须为当前账号可用音色，参考 [音色列表](/guides/voice/catalog)
* **标准 HTTP 合成**：参考 [语音合成 HTTP](/api-reference/endpoint/tts/synthesize)
* **SSE 合成**：参考 [语音合成 HTTP 流式](/api-reference/endpoint/tts/synthesize-stream)

<Warning>
  - WebSocket 接口只支持返回 **hex 格式** 的音频数据。
  - 当最后一次收到服务端返回结果后超过 **120 秒** 没有发送新事件时，WebSocket 连接自动断开。
  - 音色模型名称：**senseaudio-tts-1.5-260319**。
</Warning>

## 请求头 (Request Headers)

| 参数名               | 必填 | 说明                                      | 示例                  |
| :---------------- | :- | :-------------------------------------- | :------------------ |
| **Authorization** | 是  | 鉴权 Token。格式：Bearer SENSEAUDIO\_API\_KEY | Bearer sk-123456... |
| **Content-Type**  | 是  | 内容类型。固定为 application/json               | application/json    |

***

## 通信流程

```
1. 客户端建立 WebSocket 连接
   ↓
2. 服务端返回 connected_success 事件
   ↓
3. 客户端发送 task_start 事件（包含音色、音频格式等配置）
   ↓
4. 服务端返回 task_started 事件
   ↓
5. 客户端发送 task_continue 事件（发送待合成文本）
   ↓
6. 服务端返回音频数据（可多次发送 task_continue）
   ↓
7. 客户端发送 task_finish 事件
   ↓
8. 服务端返回 task_finished 事件并关闭连接
```

```mermaid theme={null}
sequenceDiagram
    participant Client as 客户端
    participant Server as 服务端

    Note over Client, Server: 1. 建立连接
    Client->>Server: WebSocket Connect (带 Auth Header)
    Server-->>Client: JSON: {"event": "connected_success", ...}

    Note over Client, Server: 2. 开启任务
    Client->>Server: JSON: {"event": "task_start", "model": "...", "voice_setting": {...}}
    Server-->>Client: JSON: {"event": "task_started", ...}

    Note over Client, Server: 3. 文本合成 (循环)
    loop 分段合成
        Client->>Server: JSON: {"event": "task_continue", "text": "..."}
        Server-->>Client: JSON: {"event": "task_continued", "data": {"audio": "..."}}
    end

    Note over Client, Server: 4. 结束任务
    Client->>Server: JSON: {"event": "task_finish"}
    Server-->>Client: JSON: {"event": "task_finished", ...}
    Server-->>Client: Close Connection
```

***

## 客户端事件

### 1. task\_start - 开始任务

发送此事件正式开始合成任务。当服务端返回 **task\_started** 事件时，标志着任务已成功开始。只有在接收到该事件后，才能向服务器发送 **task\_continue** 或 **task\_finish** 事件。

**请求参数**

| 参数名                             | 类型      | 必填 | 默认值    | 说明                                                    |
| ------------------------------- | ------- | -- | ------ | ----------------------------------------------------- |
| **event**                       | string  | 是  | 无      | 固定值：**task\_start**                                   |
| **model**                       | string  | 是  | 无      | 模型名称，示例值：**senseaudio-tts-1.5-260319**                |
| **voice\_setting**              | object  | 是  | 无      | 声音设置                                                  |
| **voice\_setting.voice\_id**    | string  | 是  | 无      | 主音色名称                                                 |
| **voice\_setting.speed**        | float   | 否  | 1.0    | 语速，取值范围 \[0.5, 2.0]                                   |
| **voice\_setting.vol**          | float   | 否  | 1.0    | 音量，取值范围 \[0.01, 10.0]                                 |
| **voice\_setting.pitch**        | int     | 否  | 0      | 音调，取值范围 \[-12, 12]，0 表示保持原始音调                         |
| **voice\_setting.latex\_read**  | boolean | 否  | false  | 数学公式朗读，支持 LaTeX、MathML、Unicode 数学符号等格式。（会产生额外的性能损耗）   |
| **audio\_setting**              | object  | 否  | 无      | 音频格式设置                                                |
| **audio\_setting.sample\_rate** | int     | 否  | 32000  | 音频采样率，取值范围 \[8000, 16000, 22050, 24000, 32000, 44100] |
| **audio\_setting.bitrate**      | int     | 否  | 128000 | 音频码率，取值范围 \[32000, 64000, 128000, 256000]             |
| **audio\_setting.format**       | string  | 否  | mp3    | 输出格式：mp3、wav、pcm、flac                                 |
| **audio\_setting.channel**      | int     | 否  | 2      | 音频声道，1：单声道，2：双声道                                      |

**请求示例**

```json theme={null}
{
  "event": "task_start",
  "model": "senseaudio-tts-1.5-260319",
  "voice_setting": {
    "voice_id": "male_0004_a",
    "speed": 1,
    "vol": 1,
    "pitch": 0,
    "latex_read": false
  },
  "audio_setting": {
    "sample_rate": 32000,
    "bitrate": 128000,
    "format": "mp3",
    "channel": 1
  }
}
```

**响应参数**

| 参数名                         | 类型      | 说明      |
| --------------------------- | ------- | ------- |
| **session\_id**             | string  | 会话 ID   |
| **event**                   | string  | 事件类型    |
| **trace\_id**               | string  | 链路追踪 ID |
| **base\_resp**              | object  | 请求状态信息  |
| **base\_resp.status\_code** | integer | 状态码     |
| **base\_resp.status\_msg**  | string  | 状态详情    |

**响应示例**

```json theme={null}
{
  "session_id": "69c20e38c8761996a85d57881fe4d817",
  "event": "task_started",
  "trace_id": "69c20e38c8761996a85d57881fe4d817",
  "base_resp": { "status_code": 0, "status_msg": "success" }
}
```

### 2. task\_continue - 任务继续

当收到服务端返回的 **task\_started** 事件后，任务正式开始，可通过发送 **task\_continue** 事件发送要合成的文本。支持顺序发送多个 **task\_continue** 事件，实现分段文本合成。

**请求参数**

| 参数名            | 类型     | 必填 | 说明                                           | 示例                                                |
| -------------- | ------ | -- | -------------------------------------------- | ------------------------------------------------- |
| **event**      | string | 是  | 固定值：**task\_continue**                       |                                                   |
| **text**       | string | 是  | 合成文本内容，支持中英文；支持 `<break>` 停顿符，详见下方停顿符说明      |                                                   |
| **dictionary** | array  | 否  | 多音字配置列表（**模型必须为 senseaudio-tts-1.5-260319**） | `[{"original": "好干净","replacement": "[hao4]干净"}]` |

#### LaTeX 公式说明

控制是否朗读 latex 公式，默认为 false。

* 请求中的公式需要在公式的首尾加上 `$$`。
* 请求中公式若有 `\`，需转义成 `\\`。

示例：动能公式

<img src="https://mintcdn.com/sa-5efeb1e4/SmblJrxAg49EHVsz/images/tts/latex-read-example.png?fit=max&auto=format&n=SmblJrxAg49EHVsz&q=85&s=e825aaf59af0924df97a82b6a3b4ed3b" alt="动能公式" width="128" data-path="images/tts/latex-read-example.png" />

表示为：`$$E_k = \\frac{1}{2} m v^2$$`

```json theme={null}
{
  "event": "task_continue",
  "text": "$$E_k = \\frac{1}{2} m v^2$$"
}
```

#### `<break>` 停顿符说明

**`<break>`** 用于在语音合成中插入停顿。

```xml theme={null}
<break time=500>
```

* **time** 单位为毫秒（ms）
* **500** 表示停顿 500 毫秒
* **最小值为 100 毫秒，最大值无限制**

示例：

```json theme={null}
{
  "event": "task_continue",
  "text": "你好，这是来自 <break time=5000> SenseAudio 的第一条语音"
}
```

#### dictionary (多音字纠正)

| 参数名             | 类型     | 必填 | 描述     | 默认值 | 示例        |
| :-------------- | :----- | :- | :----- | :-- | :-------- |
| **original**    | string | 是  | 原始文本。  | 无   | 好干净       |
| **replacement** | string | 是  | 多音字配置。 | 无   | \[hao4]干净 |

**请求示例**

```json theme={null}
{
  "event": "task_continue",
  "text": "好干净",
  "dictionary": [
    { "original": "好干净", "replacement": "[hao4]干净" }
  ]
}
```

**响应参数**

| 参数名                                 | 类型      | 说明                                          |
| ----------------------------------- | ------- | ------------------------------------------- |
| **session\_id**                     | string  | 会话 ID                                       |
| **event**                           | string  | 事件类型                                        |
| **trace\_id**                       | string  | 链路追踪 ID                                     |
| **is\_final**                       | boolean | 当前 `task_continue` 语音合成任务是否结束               |
| **base\_resp**                      | object  | 请求状态信息                                      |
| **base\_resp.status\_code**         | integer | 状态码                                         |
| **base\_resp.status\_msg**          | string  | 状态详情                                        |
| **data**                            | object  | 返回的合成数据对象（可能为 null）                         |
| **data.audio**                      | string  | 合成后的音频数据（hex 编码）                            |
| **data.status**                     | integer | 音频流状态：1 表示合成中，2 表示合成结束                      |
| **extra\_info**                     | object  | 音频附加信息（流式返回时只有最后一个 chunk 会返回）               |
| **extra\_info.audio\_length**       | integer | 音频时长（毫秒）                                    |
| **extra\_info.audio\_sample\_rate** | integer | 音频采样率                                       |
| **extra\_info.audio\_size**         | integer | 音频文件大小（字节）                                  |
| **extra\_info.bitrate**             | integer | 音频比特率                                       |
| **extra\_info.audio\_format**       | string  | 音频格式，取值范围 \[mp3, pcm, flac, wav]            |
| **extra\_info.audio\_channel**      | integer | 音频声道数，1：单声道，2：双声道                           |
| **extra\_info.word\_count**         | integer | 字数统计（按字素簇 grapheme cluster 统计，排除纯空白/标点/控制符） |
| **extra\_info.usage\_characters**   | integer | 字符数统计（按 Unicode 码点统计）                       |

**响应示例**

```json theme={null}
{
  "session_id": "69c20e38c8761996a85d57881fe4d817",
  "event": "task_continued",
  "trace_id": "69c20e38c8761996a85d57881fe4d817",
  "is_final": false,
  "data": { "audio": "hex编码的音频数据...", "status": 1 },
  "base_resp": { "status_code": 0, "status_msg": "success" }
}
```

### 3. task\_finish - 结束任务

服务端收到此事件后，会等待当前队列中所有合成任务完成后，关闭 WebSocket 连接并结束任务。

**请求参数**

| 参数名       | 类型     | 必填 | 说明                   |
| --------- | ------ | -- | -------------------- |
| **event** | string | 是  | 固定值：**task\_finish** |

**请求示例**

```json theme={null}
{ "event": "task_finish" }
```

**响应示例**

```json theme={null}
{
  "session_id": "69c20e38c8761996a85d57881fe4d817",
  "event": "task_finished",
  "trace_id": "69c20e38c8761996a85d57881fe4d817",
  "base_resp": { "status_code": 0, "status_msg": "success" }
}
```

***

## 服务端事件

### connected\_success - 连接建立成功

初次请求接口时，表示 WebSocket 连接建立成功。

```json theme={null}
{
  "session_id": "xxxx",
  "event": "connected_success",
  "trace_id": "xxx",
  "base_resp": { "status_code": 0, "status_msg": "success" }
}
```

### task\_started - 任务已开始

标志任务已成功开始，客户端可以开始发送 **task\_continue** 事件。

```json theme={null}
{
  "session_id": "xxxx",
  "event": "task_started",
  "trace_id": "xxxxx",
  "base_resp": { "status_code": 0, "status_msg": "success" }
}
```

### task\_finished - 任务已结束

标志任务已结束，WebSocket 连接即将关闭。

```json theme={null}
{
  "session_id": "xxxx",
  "event": "task_finished",
  "trace_id": "xxxx",
  "base_resp": { "status_code": 0, "status_msg": "success" }
}
```

### task\_failed - 任务失败

标志任务失败，`base_resp.status_msg` 中包含错误信息。

```json theme={null}
{
  "session_id": "xxxx",
  "event": "task_failed",
  "trace_id": "xxxxx",
  "base_resp": { "status_code": 1004, "status_msg": "具体错误信息" }
}
```

***

## 使用示例

<Tabs>
  <Tab title="Node.js">
    依赖：**npm install ws**

    ```javascript theme={null}
    const fs = require('fs')
    const WebSocket = require('ws')

    const WS_URL = 'wss://api.senseaudio.cn/ws/v1/t2a_v2'
    const API_KEY = process.env.SENSEAUDIO_API_KEY
    if (!API_KEY) throw new Error('Missing env: SENSEAUDIO_API_KEY')

    const output = fs.createWriteStream('output.mp3')
    const ws = new WebSocket(WS_URL, {
      headers: {
        Authorization: `Bearer ${API_KEY}`,
        'Content-Type': 'application/json',
      },
    })

    ws.on('open', () => console.log('WebSocket 连接已建立'))

    ws.on('message', (data) => {
      const response = JSON.parse(data.toString())
      console.log('收到服务端事件:', response.event)

      if (response.event === 'connected_success') {
        ws.send(JSON.stringify({
          event: 'task_start',
          model: 'senseaudio-tts-1.5-260319',
          voice_setting: { voice_id: 'male_0004_a', speed: 1.0, vol: 1.0, pitch: 0, latex_read: false },
          audio_setting: { sample_rate: 32000, bitrate: 128000, format: 'mp3', channel: 1 },
        }))
        return
      }

      if (response.event === 'task_started') {
        ws.send(JSON.stringify({ event: 'task_continue', text: '道可道，非常道。名可名，非常名。无名天地之始，有名万物之母。' }))
        ws.send(JSON.stringify({ event: 'task_continue', text: '故常无欲，以观其妙；常有欲，以观其徼。' }))
        ws.send(JSON.stringify({ event: 'task_finish' }))
        return
      }

      if (response?.data?.audio) {
        output.write(Buffer.from(response.data.audio, 'hex'))
      }

      if (response.event === 'task_finished') { output.end(); ws.close() }
      if (response.event === 'task_failed') {
        console.error('任务失败:', response?.base_resp?.status_msg)
        output.end(); ws.close()
      }
    })

    ws.on('error', (err) => console.error('WebSocket 错误:', err))
    ws.on('close', () => console.log('WebSocket 连接已关闭'))
    ```
  </Tab>

  <Tab title="Python">
    依赖：**pip install websocket-client**

    ```python theme={null}
    import json
    import os

    import websocket

    WS_URL = "wss://api.senseaudio.cn/ws/v1/t2a_v2"
    API_KEY = os.getenv("SENSEAUDIO_API_KEY")
    if not API_KEY:
      raise RuntimeError("Missing env: SENSEAUDIO_API_KEY")

    output_file = open("output.mp3", "wb")

    def on_open(ws):
      print("WebSocket 连接已建立")

    def on_message(ws, message: str):
      resp = json.loads(message)
      event = resp.get("event")
      print("收到服务端事件:", event)

      if event == "connected_success":
        ws.send(json.dumps({
          "event": "task_start",
          "model": "senseaudio-tts-1.5-260319",
          "voice_setting": {"voice_id": "male_0004_a", "speed": 1.0, "vol": 1.0, "pitch": 0, "latex_read": False},
          "audio_setting": {"sample_rate": 32000, "bitrate": 128000, "format": "mp3", "channel": 1}
        }))
        return

      if event == "task_started":
        ws.send(json.dumps({"event": "task_continue", "text": "道可道，非常道。名可名，非常名。无名天地之始，有名万物之母。"}))
        ws.send(json.dumps({"event": "task_continue", "text": "故常无欲，以观其妙；常有欲，以观其徼。"}))
        ws.send(json.dumps({"event": "task_finish"}))
        return

      data = resp.get("data") or {}
      audio_hex = data.get("audio")
      if audio_hex:
        output_file.write(bytes.fromhex(audio_hex))

      if event in ("task_finished", "task_failed"):
        if event == "task_failed":
          print("任务失败:", (resp.get("base_resp") or {}).get("status_msg"))
        output_file.close(); ws.close()

    def on_error(ws, err): print("WebSocket 错误:", err)
    def on_close(ws, status_code, msg): print("WebSocket 连接已关闭:", status_code, msg)

    ws = websocket.WebSocketApp(
      WS_URL,
      header=[f"Authorization: Bearer {API_KEY}", "Content-Type: application/json"],
      on_open=on_open, on_message=on_message, on_error=on_error, on_close=on_close,
    )
    ws.run_forever()
    ```
  </Tab>

  <Tab title="Go">
    依赖：**go get github.com/gorilla/websocket**

    ```go theme={null}
    package main

    import (
      "encoding/hex"
      "encoding/json"
      "log"
      "net/http"
      "os"

      "github.com/gorilla/websocket"
    )

    const wsURL = "wss://api.senseaudio.cn/ws/v1/t2a_v2"

    func mustMarshal(v any) []byte { b, err := json.Marshal(v); if err != nil { panic(err) }; return b }

    func main() {
      apiKey := os.Getenv("SENSEAUDIO_API_KEY")
      if apiKey == "" { log.Fatal("Missing env: SENSEAUDIO_API_KEY") }

      header := http.Header{}
      header.Set("Authorization", "Bearer "+apiKey)
      header.Set("Content-Type", "application/json")

      c, _, err := websocket.DefaultDialer.Dial(wsURL, header)
      if err != nil { log.Fatal("dial:", err) }
      defer c.Close()

      out, err := os.Create("output.mp3")
      if err != nil { log.Fatal(err) }
      defer out.Close()

      for {
        _, msg, err := c.ReadMessage()
        if err != nil { log.Fatal("read:", err) }
        var resp map[string]any
        if err := json.Unmarshal(msg, &resp); err != nil { log.Fatal(err) }

        event, _ := resp["event"].(string)
        log.Println("收到服务端事件:", event)

        switch event {
        case "connected_success":
          _ = c.WriteMessage(websocket.TextMessage, mustMarshal(map[string]any{
            "event": "task_start",
            "model": "senseaudio-tts-1.5-260319",
            "voice_setting": map[string]any{"voice_id": "male_0004_a", "speed": 1.0, "vol": 1.0, "pitch": 0, "latex_read": false},
            "audio_setting": map[string]any{"sample_rate": 32000, "bitrate": 128000, "format": "mp3", "channel": 1},
          }))
        case "task_started":
          _ = c.WriteMessage(websocket.TextMessage, mustMarshal(map[string]any{"event": "task_continue", "text": "道可道，非常道。名可名，非常名。无名天地之始，有名万物之母。"}))
          _ = c.WriteMessage(websocket.TextMessage, mustMarshal(map[string]any{"event": "task_continue", "text": "故常无欲，以观其妙；常有欲，以观其徼。"}))
          _ = c.WriteMessage(websocket.TextMessage, mustMarshal(map[string]any{"event": "task_finish"}))
        case "task_failed", "task_finished":
          if event == "task_failed" {
            if baseResp, ok := resp["base_resp"].(map[string]any); ok {
              if msg, ok := baseResp["status_msg"].(string); ok { log.Println("任务失败:", msg) }
            }
          }
          return
        }

        if data, ok := resp["data"].(map[string]any); ok {
          if audioHex, ok := data["audio"].(string); ok && audioHex != "" {
            b, err := hex.DecodeString(audioHex)
            if err != nil { log.Fatal(err) }
            if _, err := out.Write(b); err != nil { log.Fatal(err) }
          }
        }
      }
    }
    ```
  </Tab>

  <Tab title="Java">
    依赖：OkHttp + Jackson

    ```java theme={null}
    import com.fasterxml.jackson.databind.JsonNode;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import okhttp3.*;
    import okio.ByteString;

    import java.io.FileOutputStream;
    import java.util.HashMap;
    import java.util.Map;

    public class SenseAudioTtsWsExample {
      private static final String WS_URL = "wss://api.senseaudio.cn/ws/v1/t2a_v2";

      public static void main(String[] args) throws Exception {
        String apiKey = System.getenv("SENSEAUDIO_API_KEY");
        if (apiKey == null || apiKey.isEmpty()) throw new RuntimeException("Missing env: SENSEAUDIO_API_KEY");

        OkHttpClient client = new OkHttpClient();
        ObjectMapper mapper = new ObjectMapper();

        Request request = new Request.Builder()
          .url(WS_URL)
          .addHeader("Authorization", "Bearer " + apiKey)
          .addHeader("Content-Type", "application/json")
          .build();

        FileOutputStream out = new FileOutputStream("output.mp3");

        client.newWebSocket(request, new WebSocketListener() {
          @Override public void onOpen(WebSocket webSocket, Response response) { System.out.println("WebSocket 连接已建立"); }

          @Override public void onMessage(WebSocket webSocket, String text) {
            try {
              JsonNode resp = mapper.readTree(text);
              String event = resp.path("event").asText();
              System.out.println("收到服务端事件: " + event);

              if ("connected_success".equals(event)) {
                Map<String, Object> payload = new HashMap<>();
                payload.put("event", "task_start");
                payload.put("model", "senseaudio-tts-1.5-260319");

                Map<String, Object> voice = new HashMap<>();
                voice.put("voice_id", "male_0004_a"); voice.put("speed", 1.0); voice.put("vol", 1.0);
                voice.put("pitch", 0); voice.put("latex_read", false);
                payload.put("voice_setting", voice);

                Map<String, Object> audio = new HashMap<>();
                audio.put("sample_rate", 32000); audio.put("bitrate", 128000);
                audio.put("format", "mp3"); audio.put("channel", 1);
                payload.put("audio_setting", audio);

                webSocket.send(mapper.writeValueAsString(payload));
                return;
              }

              if ("task_started".equals(event)) {
                webSocket.send(mapper.writeValueAsString(Map.of("event", "task_continue", "text", "道可道，非常道。名可名，非常名。无名天地之始，有名万物之母。")));
                webSocket.send(mapper.writeValueAsString(Map.of("event", "task_continue", "text", "故常无欲，以观其妙；常有欲，以观其徼。")));
                webSocket.send(mapper.writeValueAsString(Map.of("event", "task_finish")));
                return;
              }

              JsonNode audioHex = resp.path("data").path("audio");
              if (!audioHex.isMissingNode() && !audioHex.isNull()) {
                byte[] bytes = ByteString.decodeHex(audioHex.asText()).toByteArray();
                out.write(bytes);
              }

              if ("task_finished".equals(event) || "task_failed".equals(event)) {
                if ("task_failed".equals(event)) System.err.println("任务失败: " + resp.path("base_resp").path("status_msg").asText());
                out.close(); webSocket.close(1000, "done");
              }
            } catch (Exception e) { e.printStackTrace(); webSocket.close(1001, "error"); }
          }

          @Override public void onFailure(WebSocket webSocket, Throwable t, Response response) {
            t.printStackTrace();
            try { out.close(); } catch (Exception ignored) {}
          }
        });

        Thread.sleep(60_000);
        client.dispatcher().executorService().shutdown();
      }
    }
    ```
  </Tab>
</Tabs>

***

## 技术规格

* **模型名称**：**senseaudio-tts-1.5-260319**
* **最大文本长度**：10000 字符
* **连接超时**：最后一次收到服务端返回后 120 秒无新事件时自动断开

### 音频参数范围

| 参数      | 取值范围                                         | 默认值    | 说明        |
| ------- | -------------------------------------------- | ------ | --------- |
| **语速**  | \[0.5, 2.0]                                  | 1.0    | 数值越大语速越快  |
| **音量**  | \[0.01, 10.0]                                | 1.0    | 数值越大音量越大  |
| **音调**  | \[-12, 12]                                   | 0      | 正值提高，负值降低 |
| **采样率** | 8000, 16000, 22050, 24000, 32000, 44100 (Hz) | 32000  | 推荐 32000  |
| **码率**  | 32000, 64000, 128000, 256000 (bps)           | 128000 | 仅 MP3 格式  |
| **声道**  | 1 (单声道), 2 (双声道)                             | 2      | -         |

### 支持的音频格式

* **MP3**：推荐，压缩率高，兼容性好。
* **WAV**：无损音质，文件较大。
* **PCM**：原始音频数据。
* **FLAC**：无损压缩。

***

## 错误码说明

| 状态码  | 说明   | 解决方案          |
| ---- | ---- | ------------- |
| 0    | 成功   | -             |
| 1001 | 参数错误 | 检查请求参数格式和取值范围 |

***

## 注意事项

1. **音频数据格式**：WebSocket 接口只支持返回 hex 编码的音频数据，需要在客户端将 hex 字符串转换为二进制数据；音频格式由 `audio_setting.format` 决定。
2. **连接超时机制**：最后一次收到服务端返回后 120 秒内无新事件发送时连接自动断开；建议在任务完成后主动发送 `task_finish`，长时间无操作时可发送心跳保持连接。
3. **事件发送顺序**：必须按照 `task_start → task_continue → task_finish` 顺序发送；只有在收到 `task_started` 后才能发送 `task_continue`；可以发送多个 `task_continue` 事件。

## 相关资源

<CardGroup cols={2}>
  <Card title="语音合成 HTTP" icon="waveform-lines" href="/api-reference/endpoint/tts/synthesize">
    标准 HTTP 合成接口参数详解。
  </Card>

  <Card title="语音合成 HTTP 流式" icon="bolt" href="/api-reference/endpoint/tts/synthesize-stream">
    流式 HTTP 合成接口参数详解。
  </Card>

  <Card title="语音合成介绍" icon="book-open" href="/guides/tts/overview">
    TTS 核心特性与音色生态。
  </Card>

  <Card title="音色列表" icon="list" href="/guides/voice/catalog">
    系统音色清单与 `voice_id` 规则。
  </Card>
</CardGroup>


## AsyncAPI

````yaml api-reference/endpoint/tts/websocket.asyncapi.json tts
id: tts
title: 语音合成 WebSocket
description: 实时 TTS 合成通道，客户端与服务端通过 JSON 消息交换事件。
servers: []
address: /ws/v1/t2a_v2
parameters: []
bindings: []
operations:
  - &ref_3
    id: sendTaskStart
    title: 开始合成任务
    description: 开始合成任务
    type: receive
    messages:
      - &ref_7
        id: taskStart
        contentType: application/json
        payload:
          - name: task_start
            description: 开始合成任务
            type: object
            properties:
              - name: event
                type: string
                description: 固定值：task_start
                required: true
              - name: model
                type: string
                description: 模型名称
                required: true
              - name: voice_setting
                type: object
                description: 声音设置
                required: true
                properties:
                  - name: voice_id
                    type: string
                    description: 主音色名称
                    required: true
                  - name: speed
                    type: number
                    description: 语速
                    required: false
                  - name: vol
                    type: number
                    description: 音量
                    required: false
                  - name: pitch
                    type: integer
                    description: 音调，0 表示原始音调
                    required: false
                  - name: latex_read
                    type: boolean
                    description: 数学公式朗读（会产生额外性能损耗）
                    required: false
              - name: audio_setting
                type: object
                description: 音频格式设置
                required: false
                properties:
                  - name: sample_rate
                    type: integer
                    description: 采样率
                    enumValues:
                      - 8000
                      - 16000
                      - 22050
                      - 24000
                      - 32000
                      - 44100
                    required: false
                  - name: bitrate
                    type: integer
                    description: 码率
                    enumValues:
                      - 32000
                      - 64000
                      - 128000
                      - 256000
                    required: false
                  - name: format
                    type: string
                    description: 输出格式
                    enumValues:
                      - mp3
                      - wav
                      - pcm
                      - flac
                    required: false
                  - name: channel
                    type: integer
                    description: 声道数
                    enumValues:
                      - 1
                      - 2
                    required: false
        headers: []
        jsonPayloadSchema:
          type: object
          required:
            - event
            - model
            - voice_setting
          properties:
            event:
              type: string
              const: task_start
              description: 固定值：task_start
              x-parser-schema-id: <anonymous-schema-1>
            model:
              type: string
              description: 模型名称
              example: senseaudio-tts-1.5-260319
              x-parser-schema-id: <anonymous-schema-2>
            voice_setting:
              type: object
              description: 声音设置
              required:
                - voice_id
              properties:
                voice_id:
                  type: string
                  description: 主音色名称
                  example: male_0004_a
                  x-parser-schema-id: <anonymous-schema-4>
                speed:
                  type: number
                  format: float
                  minimum: 0.5
                  maximum: 2
                  default: 1
                  description: 语速
                  x-parser-schema-id: <anonymous-schema-5>
                vol:
                  type: number
                  format: float
                  minimum: 0.01
                  maximum: 10
                  default: 1
                  description: 音量
                  x-parser-schema-id: <anonymous-schema-6>
                pitch:
                  type: integer
                  minimum: -12
                  maximum: 12
                  default: 0
                  description: 音调，0 表示原始音调
                  x-parser-schema-id: <anonymous-schema-7>
                latex_read:
                  type: boolean
                  default: false
                  description: 数学公式朗读（会产生额外性能损耗）
                  x-parser-schema-id: <anonymous-schema-8>
              x-parser-schema-id: <anonymous-schema-3>
            audio_setting:
              type: object
              description: 音频格式设置
              properties:
                sample_rate:
                  type: integer
                  enum:
                    - 8000
                    - 16000
                    - 22050
                    - 24000
                    - 32000
                    - 44100
                  default: 32000
                  description: 采样率
                  x-parser-schema-id: <anonymous-schema-10>
                bitrate:
                  type: integer
                  enum:
                    - 32000
                    - 64000
                    - 128000
                    - 256000
                  default: 128000
                  description: 码率
                  x-parser-schema-id: <anonymous-schema-11>
                format:
                  type: string
                  enum:
                    - mp3
                    - wav
                    - pcm
                    - flac
                  default: mp3
                  description: 输出格式
                  x-parser-schema-id: <anonymous-schema-12>
                channel:
                  type: integer
                  enum:
                    - 1
                    - 2
                  default: 2
                  description: 声道数
                  x-parser-schema-id: <anonymous-schema-13>
              x-parser-schema-id: <anonymous-schema-9>
          x-parser-schema-id: TaskStartPayload
        title: task_start
        description: 开始合成任务
        example: |-
          {
            "event": "<string>",
            "model": "<string>",
            "voice_setting": {
              "voice_id": "<string>",
              "speed": 123,
              "vol": 123,
              "pitch": 123,
              "latex_read": true
            },
            "audio_setting": {
              "sample_rate": 123,
              "bitrate": 123,
              "format": "<string>",
              "channel": 123
            }
          }
        bindings: []
        extensions:
          - id: x-parser-unique-object-id
            value: taskStart
    bindings: []
    extensions: &ref_0
      - id: x-parser-unique-object-id
        value: tts
  - &ref_4
    id: sendTaskContinue
    title: 发送待合成文本
    description: 发送待合成文本
    type: receive
    messages:
      - &ref_8
        id: taskContinue
        contentType: application/json
        payload:
          - name: task_continue
            description: 发送待合成文本
            type: object
            properties:
              - name: event
                type: string
                description: 固定值：task_continue
                required: true
              - name: text
                type: string
                description: 合成文本内容，支持 <break time=500> 停顿符
                required: true
              - name: dictionary
                type: array
                description: 多音字配置列表
                required: false
                properties:
                  - name: original
                    type: string
                    description: 原始文本
                    required: true
                  - name: replacement
                    type: string
                    description: 多音字配置
                    required: true
        headers: []
        jsonPayloadSchema:
          type: object
          required:
            - event
            - text
          properties:
            event:
              type: string
              const: task_continue
              description: 固定值：task_continue
              x-parser-schema-id: <anonymous-schema-14>
            text:
              type: string
              description: 合成文本内容，支持 <break time=500> 停顿符
              x-parser-schema-id: <anonymous-schema-15>
            dictionary:
              type: array
              description: 多音字配置列表
              items:
                type: object
                required:
                  - original
                  - replacement
                properties:
                  original:
                    type: string
                    description: 原始文本
                    x-parser-schema-id: <anonymous-schema-18>
                  replacement:
                    type: string
                    description: 多音字配置
                    x-parser-schema-id: <anonymous-schema-19>
                x-parser-schema-id: <anonymous-schema-17>
              x-parser-schema-id: <anonymous-schema-16>
          x-parser-schema-id: TaskContinuePayload
        title: task_continue
        description: 发送待合成文本
        example: |-
          {
            "event": "<string>",
            "text": "<string>",
            "dictionary": {
              "original": "<string>",
              "replacement": "<string>"
            }
          }
        bindings: []
        extensions:
          - id: x-parser-unique-object-id
            value: taskContinue
    bindings: []
    extensions: *ref_0
  - &ref_5
    id: sendTaskFinish
    title: 结束合成任务
    description: 结束合成任务
    type: receive
    messages:
      - &ref_9
        id: taskFinish
        contentType: application/json
        payload:
          - name: task_finish
            description: 结束合成任务
            type: object
            properties:
              - name: event
                type: string
                description: 固定值：task_finish
                required: true
        headers: []
        jsonPayloadSchema:
          type: object
          required:
            - event
          properties:
            event:
              type: string
              const: task_finish
              description: 固定值：task_finish
              x-parser-schema-id: <anonymous-schema-20>
          x-parser-schema-id: TaskFinishPayload
        title: task_finish
        description: 结束合成任务
        example: |-
          {
            "event": "<string>"
          }
        bindings: []
        extensions:
          - id: x-parser-unique-object-id
            value: taskFinish
    bindings: []
    extensions: *ref_0
  - &ref_6
    id: receiveServerEvents
    title: 接收服务端事件
    description: 接收服务端事件
    type: send
    messages:
      - &ref_10
        id: connectedSuccess
        contentType: application/json
        payload:
          - name: connected_success
            description: 连接建立成功
            type: object
            properties:
              - name: session_id
                type: string
                description: 会话 ID
                required: false
              - name: event
                type: string
                description: 事件类型
                required: false
              - name: trace_id
                type: string
                description: 链路追踪 ID
                required: false
              - name: base_resp
                type: object
                required: false
                properties:
                  - name: status_code
                    type: integer
                    description: 状态码，0 表示成功
                    required: false
                  - name: status_msg
                    type: string
                    description: 状态详情
                    required: false
        headers: []
        jsonPayloadSchema: &ref_1
          type: object
          properties:
            session_id:
              type: string
              description: 会话 ID
              x-parser-schema-id: <anonymous-schema-21>
            event:
              type: string
              description: 事件类型
              x-parser-schema-id: <anonymous-schema-22>
            trace_id:
              type: string
              description: 链路追踪 ID
              x-parser-schema-id: <anonymous-schema-23>
            base_resp:
              type: object
              properties:
                status_code:
                  type: integer
                  format: int64
                  description: 状态码，0 表示成功
                  x-parser-schema-id: <anonymous-schema-24>
                status_msg:
                  type: string
                  description: 状态详情
                  x-parser-schema-id: <anonymous-schema-25>
              x-parser-schema-id: BaseResp
          x-parser-schema-id: BaseServerEvent
        title: connected_success
        description: 连接建立成功
        example: |-
          {
            "session_id": "<string>",
            "event": "<string>",
            "trace_id": "<string>",
            "base_resp": {
              "status_code": 123,
              "status_msg": "<string>"
            }
          }
        bindings: []
        extensions:
          - id: x-parser-unique-object-id
            value: connectedSuccess
      - &ref_11
        id: taskStarted
        contentType: application/json
        payload:
          - name: task_started
            description: 任务已开始
            type: object
            properties:
              - name: session_id
                type: string
                description: 会话 ID
                required: false
              - name: event
                type: string
                description: 事件类型
                required: false
              - name: trace_id
                type: string
                description: 链路追踪 ID
                required: false
              - name: base_resp
                type: object
                required: false
                properties:
                  - name: status_code
                    type: integer
                    description: 状态码，0 表示成功
                    required: false
                  - name: status_msg
                    type: string
                    description: 状态详情
                    required: false
        headers: []
        jsonPayloadSchema: *ref_1
        title: task_started
        description: 任务已开始
        example: |-
          {
            "session_id": "<string>",
            "event": "<string>",
            "trace_id": "<string>",
            "base_resp": {
              "status_code": 123,
              "status_msg": "<string>"
            }
          }
        bindings: []
        extensions:
          - id: x-parser-unique-object-id
            value: taskStarted
      - &ref_12
        id: taskContinued
        contentType: application/json
        payload:
          - allOf: &ref_2
              - *ref_1
              - type: object
                properties:
                  is_final:
                    type: boolean
                    description: 当前 task_continue 语音合成任务是否结束
                    x-parser-schema-id: <anonymous-schema-27>
                  data:
                    type: object
                    nullable: true
                    description: 返回的合成数据对象
                    properties:
                      audio:
                        type: string
                        description: 合成后的音频数据（hex 编码）
                        x-parser-schema-id: <anonymous-schema-29>
                      status:
                        type: integer
                        format: int64
                        description: 音频流状态：1 合成中，2 合成结束
                        x-parser-schema-id: <anonymous-schema-30>
                    x-parser-schema-id: <anonymous-schema-28>
                  extra_info:
                    type: object
                    description: 音频附加信息，流式返回时仅最后一个 chunk 携带
                    properties:
                      audio_length:
                        type: integer
                        format: int64
                        description: 音频时长（毫秒）
                        x-parser-schema-id: <anonymous-schema-32>
                      audio_sample_rate:
                        type: integer
                        format: int64
                        description: 音频采样率
                        x-parser-schema-id: <anonymous-schema-33>
                      audio_size:
                        type: integer
                        format: int64
                        description: 音频文件大小（字节）
                        x-parser-schema-id: <anonymous-schema-34>
                      bitrate:
                        type: integer
                        format: int64
                        description: 音频比特率
                        x-parser-schema-id: <anonymous-schema-35>
                      audio_format:
                        type: string
                        enum:
                          - mp3
                          - pcm
                          - flac
                          - wav
                        description: 音频格式
                        x-parser-schema-id: <anonymous-schema-36>
                      audio_channel:
                        type: integer
                        description: 音频声道数
                        x-parser-schema-id: <anonymous-schema-37>
                      word_count:
                        type: integer
                        format: int64
                        description: 字数统计（按 grapheme cluster 统计）
                        x-parser-schema-id: <anonymous-schema-38>
                      usage_characters:
                        type: integer
                        format: int64
                        description: 字符数统计（按 Unicode 码点）
                        x-parser-schema-id: <anonymous-schema-39>
                    x-parser-schema-id: <anonymous-schema-31>
                x-parser-schema-id: <anonymous-schema-26>
            x-parser-schema-id: TaskContinuedPayload
            name: task_continued
            description: 音频分片返回
        headers: []
        jsonPayloadSchema:
          allOf: *ref_2
          x-parser-schema-id: TaskContinuedPayload
        title: task_continued
        description: 音频分片返回
        example: '{}'
        bindings: []
        extensions:
          - id: x-parser-unique-object-id
            value: taskContinued
      - &ref_13
        id: taskFinished
        contentType: application/json
        payload:
          - name: task_finished
            description: 任务已结束
            type: object
            properties:
              - name: session_id
                type: string
                description: 会话 ID
                required: false
              - name: event
                type: string
                description: 事件类型
                required: false
              - name: trace_id
                type: string
                description: 链路追踪 ID
                required: false
              - name: base_resp
                type: object
                required: false
                properties:
                  - name: status_code
                    type: integer
                    description: 状态码，0 表示成功
                    required: false
                  - name: status_msg
                    type: string
                    description: 状态详情
                    required: false
        headers: []
        jsonPayloadSchema: *ref_1
        title: task_finished
        description: 任务已结束
        example: |-
          {
            "session_id": "<string>",
            "event": "<string>",
            "trace_id": "<string>",
            "base_resp": {
              "status_code": 123,
              "status_msg": "<string>"
            }
          }
        bindings: []
        extensions:
          - id: x-parser-unique-object-id
            value: taskFinished
      - &ref_14
        id: taskFailed
        contentType: application/json
        payload:
          - name: task_failed
            description: 任务失败
            type: object
            properties:
              - name: session_id
                type: string
                description: 会话 ID
                required: false
              - name: event
                type: string
                description: 事件类型
                required: false
              - name: trace_id
                type: string
                description: 链路追踪 ID
                required: false
              - name: base_resp
                type: object
                required: false
                properties:
                  - name: status_code
                    type: integer
                    description: 状态码，0 表示成功
                    required: false
                  - name: status_msg
                    type: string
                    description: 状态详情
                    required: false
        headers: []
        jsonPayloadSchema: *ref_1
        title: task_failed
        description: 任务失败
        example: |-
          {
            "session_id": "<string>",
            "event": "<string>",
            "trace_id": "<string>",
            "base_resp": {
              "status_code": 123,
              "status_msg": "<string>"
            }
          }
        bindings: []
        extensions:
          - id: x-parser-unique-object-id
            value: taskFailed
    bindings: []
    extensions: *ref_0
sendOperations:
  - *ref_3
  - *ref_4
  - *ref_5
receiveOperations:
  - *ref_6
sendMessages:
  - *ref_7
  - *ref_8
  - *ref_9
receiveMessages:
  - *ref_10
  - *ref_11
  - *ref_12
  - *ref_13
  - *ref_14
extensions:
  - id: x-parser-unique-object-id
    value: tts
securitySchemes:
  - id: bearerAuth
    name: bearerAuth
    type: http
    description: 'Bearer Token 鉴权，格式 `Authorization: Bearer <SENSEAUDIO_API_KEY>`'
    scheme: bearer
    extensions: []

````