# 语音合成 WebSocket 双向流（火山原生协议透传，边生成边合成）

**WebSocket 端点，非普通 HTTP**：`wss://api.xrtoken.net/v1/audio/speech/bidirection?model=seed-tts-2.0`。

建连后走火山 SAMI 双向语音合成二进制协议，适合 LLM **边生成文本边合成语音** 的低延迟
场景：`StartConnection` → `StartSession` → `TaskRequest`（可发送 N 次，每次追加一段
增量文本）→ `FinishSession` → `FinishConnection`；也支持 `CancelSession` 中途打断。
**帧格式与火山官方完全一致，仅需更换域名与鉴权 key**，可直接复用火山官方 Demo 客户端
代码对接。

**鉴权**：服务端用 `Authorization: Bearer <tr-key>` 或 `X-Api-Key: <tr-key>`；浏览器
无法带 header 时用 `Sec-WebSocket-Protocol: ["xrtoken.bearer", "<tr-key>"]` 携带，
不走 URL query。

**选模型**：`?model=` 优先；`X-Api-Resource-Id` header 兜底。

**计费**：按文本字符数计费（含标点），`context_texts` 语音指令不计费，结算以上游
返回的 `usage.text_words` 为准（未回传时按客户端实发文本字符数兜底）。

**并发**：单 key 最多 10 路并发流。

## GET /v1/audio/speech/bidirection

> TTS WebSocket bidirectional stream (Volcengine native protocol passthrough, synthesize while generating)

**WebSocket endpoint, not plain HTTP**:
`wss://api.xrtoken.net/v1/audio/speech/bidirection?model=seed-tts-2.0`.

After the handshake, the connection speaks Volcengine's SAMI bidirectional
TTS binary protocol — built for the low-latency case of synthesizing speech
while an LLM is still generating text:
`StartConnection` → `StartSession` → `TaskRequest` (send as many times as
needed, each carrying an incremental chunk of text) → `FinishSession` →
`FinishConnection`. `CancelSession` is also supported for mid-stream
interruption. **The frame format is identical to Volcengine's own — only the
domain and the auth key change**, so official Volcengine demo client code
can be reused directly.

**Auth**: server-side clients use `Authorization: Bearer <tr-key>` or
`X-Api-Key: <tr-key>`; browsers that can't set headers use
`Sec-WebSocket-Protocol: ["xrtoken.bearer", "<tr-key>"]` instead — not the
URL query string.

**Model selection**: `?model=` takes priority; `X-Api-Resource-Id` header is
the fallback.

**Billing**: charged per text character (punctuation included);
`context_texts` instruction text is not billed; settlement uses the
`usage.text_words` returned upstream (falls back to the client's own sent
character count if upstream never returns usage).

**Concurrency**: max 10 concurrent streams per key.

### Authentication

`Authorization: Bearer tr-xxx`

### Query Parameters

- **model** `string`  
  TTS model / channel ID

### Error Codes

- `101`: WebSocket upgrade succeeded; subsequent frames are the SAMI bidirectional event stream
- `401`: 
- `402`: 
- `429`: Concurrent stream limit per key exceeded
- `502`:
