> For the complete documentation index, see [llms.txt](https://anxiang1836.gitbook.io/magic-tts/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://anxiang1836.gitbook.io/magic-tts/api/yoyo-tts/wss-shuang-xiang-liu-shi-he-cheng.md).

# WSS-双向流式合成

<mark style="background-color:$success;">wss</mark> `/v1/magictts/wss`

{% hint style="info" icon="sparkle" %}
基于WebSocket的双向流式 TTS 接口，支持文本流式输入、音频流式输出，低时延，适用于实时交互场景，服务内部，维护多句合成间的合成音频缓存，保证多句间合成一致性。
{% endhint %}

## 1. 消息结构体

**请求**和**响应**，全都统一序列化为bytes数组（1 byte = 8 bits），参考火山的消息体格式；

具体结构如下：

```
    bytes  0                                   1                                   2
    bits   |  0   1   2   3  |  4   5   6   7  |  0   1   2   3  |  4   5   6   7  |
           +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
           |     MsgType     |      Flags      |  Serialization  |    HeaderSize   |
           |    (4 bits)     |    (4 bits)     |    (4 bits)     |     (4 bits)    |
           +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
           |              Reserved             |     Optional Header Extensions    |
           |              (8 bits)             |        (if Header Size > 1)       |
           +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
           |                                Payload                                |
           |                           (variable length)                           |
           +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
```

### 1.1. 基本信息

对应字段值定义：

{% columns %}
{% column %}
**MsgType**

```python

FullClientRequest    = 0b0001
FullServerResponse   = 0b1001

AudioOnlyClient      = 0b0010
AudioOnlyServer      = 0b1011

Error                = 0b1111
```

{% endcolumn %}

{% column %}
**Flags**

```python
# Non-terminal packet with no seq
NoSeq       = 0b0000
# Non-terminal packet with seq > 0
PositiveSeq = 0b0001
# Last packet with no seq
LastNoSeq   = 0b0010
# Last packet with seq < 0
NegativeSeq = 0b0011
# Payload contains event num(int32)
WithEvent   = 0b0100
```

{% endcolumn %}
{% endcolumns %}

{% columns %}
{% column %}
**Serialization**

```python
Raw    = 0b0000
JSON   = 0b0001
Thrift = 0b0011
Custom = 0b1111
```

{% endcolumn %}

{% column %}
**HeaderSize**

```python
HeaderSize4  = 0b0001
HeaderSize8  = 0b0010
HeaderSize12 = 0b0011
HeaderSize16 = 0b0100
```

{% endcolumn %}
{% endcolumns %}

***

### 1.2. Payload

{% hint style="info" %}
作为消息体第2层，主要封装消息详细内容，包括：

1. client的请求参数(含请求文本/ASR音频)
2.

{% endhint %}

**EventType类型**定义：

{% code lineNumbers="true" expandable="true" %}

```py
    None_ = 0  # Default event

    # 1 ~ 49 Upstream Connection events
    StartConnection = 1
    StartTask = 1  # Alias of StartConnection
    FinishConnection = 2
    FinishTask = 2  # Alias of FinishConnection

    # 50 ~ 99 Downstream Connection events
    ConnectionStarted = 50  # Connection established successfully
    TaskStarted = 50  # Alias of ConnectionStarted
    ConnectionFailed = 51  # Connection failed (possibly due to authentication failure)
    TaskFailed = 51  # Alias of ConnectionFailed
    ConnectionFinished = 52  # Connection ended
    TaskFinished = 52  # Alias of ConnectionFinished

    # 100 ~ 149 Upstream Session events
    StartSession = 100
    CancelSession = 101
    FinishSession = 102

    # 150 ~ 199 Downstream Session events
    SessionStarted = 150
    SessionCanceled = 151
    SessionFinished = 152
    SessionFailed = 153
    UsageResponse = 154  # Usage response
    ChargeData = 154  # Alias of UsageResponse

    # 200 ~ 249 Upstream general events
    TaskRequest = 200
    UpdateConfig = 201

    # 250 ~ 299 Downstream general events
    AudioMuted = 250

    # 300 ~ 349 Upstream TTS events
    SayHello = 300

    # 350 ~ 399 Downstream TTS events
    TTSSentenceStart = 350
    TTSSentenceEnd = 351
    TTSResponse = 352
    TTSSubtitle = 364
    TTSEnded = 359
    PodcastRoundStart = 360
    PodcastRoundResponse = 361
    PodcastRoundEnd = 362

    # 450 ~ 499 Downstream ASR events
    ASRInfo = 450
    ASRResponse = 451
    ASREnded = 459

    # 500 ~ 549 Upstream dialogue events
    ChatTTSText = 500  # (Ground-Truth-Alignment) text for speech synthesis

    # 550 ~ 599 Downstream dialogue events
    ChatResponse = 550
    ChatEnded = 559

    # 650 ~ 699 Downstream dialogue events
    # Events for source (original) language subtitle
    SourceSubtitleStart = 650
    SourceSubtitleResponse = 651
    SourceSubtitleEnd = 652
    # Events for target (translation) language subtitle
    TranslationSubtitleStart = 653
    TranslationSubtitleResponse = 654
    TranslationSubtitleEnd = 655
```

{% endcode %}

```
MsgType in (FullClientRequest, FullServerResponse, AudioOnlyClient, AudioOnlyServer)
Flags   in (PositiveSeq, NegativeSeq)
```

```
    bytes 0           4             8          8+N
          +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
          |   SeqId   | ContentSize |  Content  |
          | (4 bytes) |  (4 bytes)  | (N bytes) |
          +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
```

```
MsgType in (FullClientRequest, FullServerResponse)
Flags   in (WithEvent, )
```

```
bytes 0               4             4+X
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      | EventTypeSize |   EventType   |
      |   (4 bytes)   |   (X bytes)   |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      | SessionIdSize |   SessionId   |
      |   (4 bytes)   |   (Y bytes)   |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      | ConnectIdSize |   ConnectId   |
      |   (4 bytes)   |   (Z bytes)   |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |  ContentSize  |    Content    |
      |   (4 bytes)   |   (N bytes)   |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
```

```
MsgType in (Error, )
Flags   in (WithEvent, )
```

```
bytes 0               4             4+X
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      | ErrorCodeSize |   ErrorCode   |
      |   (4 bytes)   |   (X bytes)   |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      | EventTypeSize |   EventType   |
      |   (4 bytes)   |   (X bytes)   |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      | SessionIdSize |   SessionId   |
      |   (4 bytes)   |   (Y bytes)   |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      | ConnectIdSize |   ConnectId   |
      |   (4 bytes)   |   (Z bytes)   |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |  ContentSize  |    Content    |
      |   (4 bytes)   |   (N bytes)   |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
```

### 1.3. 请求超参

TODO

## 事件

{% stepper %}
{% step %}

### 建立连接

{% tabs %}
{% tab title="clinet请求" %}
**消息体-基本信息：**

```
Version       = Version1
HeaderSize    = HeaderSize4
MsgType       = FullClientRequest
Flags         = WithEvent   
Serialization = JSON
Compression   = None_
```

**消息体-Payload：**

```
EventType = StartConnection
ConnectIdSize = 
```

{% endtab %}

{% tab title="server响应" %}
**消息体-基本信息：**

```
Version       = Version1
HeaderSize    = HeaderSize4
MsgType       = FullServerResponse
Flags         = WithEvent   
Serialization = JSON
Compression   = None_
```

**消息体-bytes示例：**

```
    0                                   1                                   2
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    |    Version      |   HeaderSize    |     MsgType     |      Flags      |
    |  0   0   0   1  |  0   0   0   1  |  1   0   0   1  |  0   1   0   0  |
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    |  Serialization  |   Compression   |           Reserved                |
    |  0   0   0   1  |  0   0   0   0  |  0   0   0   0  |  0   0   0   0  |
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    |                                Payload                                |
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
```

**消息体-Payload：**

```
EventType = 
```

{% endtab %}
{% endtabs %}
{% endstep %}

{% step %}

### 创建会话

{% tabs %}
{% tab title="clinet请求" %}
**消息体-基本信息：**

```
Version       = Version1
HeaderSize    = HeaderSize4
MsgType       = FullClientRequest
Flags         = WithEvent   
Serialization = JSON
Compression   = None_
```

**消息体-Payload：**

```
{
    "req_params":{
        "audio_params": {
            "format": "pcm",
            "sample_rate": 24000,
            "style": null,
            "language": null
        },
        "speaker": {
            "spk_id": null,
            "prompt_text": null,
            "prompt_llm_speech_tokens": null,
            "prompt_flow_spk_emb": null,
            "prompt_flow_speech_tokens": null,
            "prompt_flow_speech_fbank": null,
            "addition": null
        }
    }
}
```

{% endtab %}
{% endtabs %}
{% endstep %}

{% step %}

### 发送请求

{% endstep %}

{% step %}

### 取消会话

{% endstep %}

{% step %}

### 结束会话

{% endstep %}

{% step %}

### 结束连接

{% endstep %}
{% endstepper %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://anxiang1836.gitbook.io/magic-tts/api/yoyo-tts/wss-shuang-xiang-liu-shi-he-cheng.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
