了解实时语音合成的模型特性、流式调用方法和合成效果优化方式。
功能介绍
实时语音合成支持分段输入文本、逐段返回音频,适合将大模型生成的文本实时转换为语音。
- 多语言与方言:根据目标语言选择模型和音色,也可通过指令指定方言。参见方言。
- 表现力控制:通过自然语言指令调整语速、情感等表达,或在文本中插入情感与富语言标签。参见指令控制和情感与富语言标签。
- 自定义音色:通过声音复刻从音频样本创建音色,或通过声音设计使用文字描述创建音色。
- 精细控制与公式朗读:使用 SSML 与 LaTeX控制停顿、发音等效果,或将公式转换为语音。
- 音频控制:可调节语速、语调、音量和码率,输出 PCM、WAV、MP3、Opus 等主流音频格式,最高支持 48 kHz 采样率。具体取值与支持范围以对应 API 参数说明为准。
说明各模型及音色支持的能力有所不同,使用前请核对对应功能的支持范围。
需要通过 HTTP 一次提交完整文本时,请参见非实时语音合成。
开始使用
- 获取 API Key并配置到环境变量
DASHSCOPE_API_KEY。使用与示例地域对应的 API Key。 - 使用业务空间专属域名时,将代码中的
{WorkspaceId}替换为该地域的业务空间 ID。 - 安装 DashScope SDK,选择 Python 或 Java 示例。
说明对延迟和弱网下音频传输稳定性要求较高的移动端应用,可使用 AOQ 协议。AOQ 的接入方式,以及 AOQ、WebRTC 和 WebSocket 的差异与模型支持范围,请参见 Realtime API 概述。
Qwen-Audio-TTS(推荐)
以下使用北京地域的 qwen-audio-3.1-tts-flash 和系统音色 longanhuan_v3.1,分段发送文本并将返回音频保存为 output.mp3。
import os
import dashscope
from dashscope.audio.tts_v2 import SpeechSynthesizer, ResultCallback, AudioFormat
dashscope.api_key = os.environ["DASHSCOPE_API_KEY"]
dashscope.base_websocket_api_url = "wss://{WorkspaceId}.cn-beijing.maas.aliyuncs.com/api-ws/v1/inference"
with open("output.mp3", "wb") as audio:
class Callback(ResultCallback):
def on_data(self, data: bytes):
audio.write(data)
def on_error(self, message):
print(f"Synthesis failed: {message}")
synthesizer = SpeechSynthesizer(
model="qwen-audio-3.1-tts-flash",
voice="longanhuan_v3.1",
format=AudioFormat.MP3_24000HZ_MONO_256KBPS,
callback=Callback(),
)
for text in ["你好,欢迎使用阿里云百炼。", "文本可以分段发送,音频会逐段返回。"]:
synthesizer.streaming_call(text)
synthesizer.streaming_complete()
import com.alibaba.dashscope.audio.tts.SpeechSynthesisResult;
import com.alibaba.dashscope.audio.ttsv2.SpeechSynthesisAudioFormat;
import com.alibaba.dashscope.audio.ttsv2.SpeechSynthesisParam;
import com.alibaba.dashscope.audio.ttsv2.SpeechSynthesizer;
import com.alibaba.dashscope.common.ResultCallback;
import com.alibaba.dashscope.utils.Constants;
import java.io.FileOutputStream;
import java.nio.ByteBuffer;
public class Main {
public static void main(String[] args) throws Exception {
Constants.baseWebsocketApiUrl = "wss://{WorkspaceId}.cn-beijing.maas.aliyuncs.com/api-ws/v1/inference";
try (FileOutputStream audio = new FileOutputStream("output.mp3")) {
SpeechSynthesisParam param = SpeechSynthesisParam.builder()
.apiKey(System.getenv("DASHSCOPE_API_KEY"))
.model("qwen-audio-3.1-tts-flash")
.voice("longanhuan_v3.1")
.format(SpeechSynthesisAudioFormat.MP3_24000HZ_MONO_256KBPS)
.build();
ResultCallback<SpeechSynthesisResult> callback = new ResultCallback<>() {
@Override
public void onEvent(SpeechSynthesisResult result) {
ByteBuffer buffer = result.getAudioFrame();
if (buffer != null) {
byte[] bytes = new byte[buffer.remaining()];
buffer.get(bytes);
try { audio.write(bytes); }
catch (Exception e) { throw new RuntimeException(e); }
}
}
@Override
public void onComplete() {}
public void onError(Exception e) { e.printStackTrace(); }
};
SpeechSynthesizer synthesizer = new SpeechSynthesizer(param, callback);
try {
for (String text : new String[]{"你好,欢迎使用阿里云百炼。", "文本可以分段发送,音频会逐段返回。"}) {
synthesizer.streamingCall(text);
}
synthesizer.streamingComplete(60000);
} finally {
synthesizer.getDuplexApi().close(1000, "done");
}
}
}
}
CosyVoice
以下使用北京地域的 cosyvoice-v3-flash 和系统音色 longanyang,分段发送文本并将返回音频保存为 output.mp3。
import os
import dashscope
from dashscope.audio.tts_v2 import SpeechSynthesizer, ResultCallback, AudioFormat
dashscope.api_key = os.environ["DASHSCOPE_API_KEY"]
dashscope.base_websocket_api_url = "wss://{WorkspaceId}.cn-beijing.maas.aliyuncs.com/api-ws/v1/inference"
with open("output.mp3", "wb") as audio:
class Callback(ResultCallback):
def on_data(self, data: bytes):
audio.write(data)
def on_error(self, message):
print(f"Synthesis failed: {message}")
synthesizer = SpeechSynthesizer(
model="cosyvoice-v3-flash",
voice="longanyang",
format=AudioFormat.MP3_24000HZ_MONO_256KBPS,
callback=Callback(),
)
for text in ["你好,欢迎使用阿里云百炼。", "文本可以分段发送,音频会逐段返回。"]:
synthesizer.streaming_call(text)
synthesizer.streaming_complete()
import com.alibaba.dashscope.audio.tts.SpeechSynthesisResult;
import com.alibaba.dashscope.audio.ttsv2.SpeechSynthesisAudioFormat;
import com.alibaba.dashscope.audio.ttsv2.SpeechSynthesisParam;
import com.alibaba.dashscope.audio.ttsv2.SpeechSynthesizer;
import com.alibaba.dashscope.common.ResultCallback;
import com.alibaba.dashscope.utils.Constants;
import java.io.FileOutputStream;
import java.nio.ByteBuffer;
public class Main {
public static void main(String[] args) throws Exception {
Constants.baseWebsocketApiUrl = "wss://{WorkspaceId}.cn-beijing.maas.aliyuncs.com/api-ws/v1/inference";
try (FileOutputStream audio = new FileOutputStream("output.mp3")) {
SpeechSynthesisParam param = SpeechSynthesisParam.builder()
.apiKey(System.getenv("DASHSCOPE_API_KEY"))
.model("cosyvoice-v3-flash")
.voice("longanyang")
.format(SpeechSynthesisAudioFormat.MP3_24000HZ_MONO_256KBPS)
.build();
ResultCallback<SpeechSynthesisResult> callback = new ResultCallback<>() {
@Override
public void onEvent(SpeechSynthesisResult result) {
ByteBuffer buffer = result.getAudioFrame();
if (buffer != null) {
byte[] bytes = new byte[buffer.remaining()];
buffer.get(bytes);
try { audio.write(bytes); }
catch (Exception e) { throw new RuntimeException(e); }
}
}
@Override
public void onComplete() {}
public void onError(Exception e) { e.printStackTrace(); }
};
SpeechSynthesizer synthesizer = new SpeechSynthesizer(param, callback);
try {
for (String text : new String[]{"你好,欢迎使用阿里云百炼。", "文本可以分段发送,音频会逐段返回。"}) {
synthesizer.streamingCall(text);
}
synthesizer.streamingComplete(60000);
} finally {
synthesizer.getDuplexApi().close(1000, "done");
}
}
}
}
合成效果优化
语言与发音
根据需要控制的内容,选择对应方式:
| 需求 | 使用方式 |
|---|---|
指定合成语音的目标语言 | 使用 |
修正特定词语的发音或替换文本 | 使用 |
精细控制停顿、数字读法或字词发音 | 使用 SSML 标签标记需要控制的文本,按标签设置停顿、读法和发音等效果。 |
朗读数学公式 | 使用 CosyVoice 的 LaTeX 公式朗读功能,将支持的数学公式转换为中文语音。 |
参数适用模型和配置方法请参见 Qwen-Audio-TTS API或 CosyVoice API;SSML 与 LaTeX 的适用模型、音色、接口及用法请参见 SSML 与 LaTeX。
说明使用 SSML 时,需要一次提交完整的 SSML 文本,再逐段接收音频,不支持分段输入。
指令控制
通过 instruction 参数,用自然语言描述语速、情感或说话方式,控制合成语音的表现。
说明如需创建具有特定性别、年龄或音色特质的新音色,或参考声音描述的编写建议与示例,请参见声音设计。
Qwen-Audio-TTS
qwen-audio-3.1-tts-flash、qwen-audio-3.0-tts-plus、qwen-audio-3.0-tts-flash 的系统音色、复刻音色和设计音色均支持在合成请求中通过 instruction 设置自然语言指令。
例如,将 instruction 设为以下内容,可放慢语速:
请用非常缓慢的语速说话,每个字都慢慢说。
CosyVoice
说明CosyVoice 的 instruction 长度不能超过 100 个字符。计数时,汉字(包括简体、繁体汉字、日文汉字和韩文汉字)按 2 个字符计算,其他字符(包括标点符号、字母、数字、假名和谚文)按 1 个字符计算。
| 模型 | 可使用的音色 | 指令要求 | 指令文本语言 |
|---|---|---|---|
| 复刻音色、设计音色 无系统音色。 | 自然语言指令。 | 中文、英文、法语、德语、日语、韩语、俄语、葡萄牙语、泰语、印尼语、越南语。 |
| 系统音色 | 按音色列表中的固定格式和内容填写。 复刻音色、设计音色不支持指令控制。 | 按音色列表指定的语言填写。 |
| 系统音色 | 按音色列表中的固定格式和内容填写。 | 中文。 |
复刻音色、设计音色 | 自然语言指令。 | 中文、英文、法语、德语、日语、韩语、俄语。 |
方言
通过方言功能,可将文本合成为河南话、四川话等中文方言语音。方言的选择方式取决于模型和音色类型。
Qwen-Audio-TTS
- 系统音色:从 Qwen-Audio-TTS 音色列表中选择支持目标方言的音色。直接支持该方言的音色无需额外设置;支持方言指令的音色使用
instruction指定。 - 复刻音色:通过
instruction指定方言,例如请用河南话表达。。
CosyVoice
- 系统音色:选择直接支持目标方言的音色,例如
longshange_v3;或选择支持方言指令的音色,例如longanhuan_v3,按音色列表的格式填写指令。 - 复刻音色:使用支持指令控制的模型,通过
instruction指定方言。 - 设计音色:暂不支持方言。
使用 CosyVoice 的 Python 开始使用示例时,将初始化与文本发送部分替换为以下内容,可使用 longanhuan_v3 输出河南话:
synthesizer = SpeechSynthesizer(
model="cosyvoice-v3-flash",
voice="longanhuan_v3",
instruction="请用河南话表达。",
format=AudioFormat.MP3_24000HZ_MONO_256KBPS,
callback=Callback(),
)
synthesizer.streaming_call("叫你去买盐,你买回来一袋面,这不是弄啥嘞吗!")
synthesizer.streaming_complete()
使用 Qwen3-TTS 时,请从 Qwen3-TTS 音色列表中选择支持目标方言的音色。
情感与富语言标签
说明适用于 qwen-audio-3.1-tts-flash、qwen-audio-3.0-tts-plus 和 qwen-audio-3.0-tts-flash。
情感与富语言标签可控制语音的情感和风格,并在指定位置加入笑声、叹息等拟声效果。将标签直接写入待合成文本 text,无需额外参数。
使用示例
以下文本先使用兴奋语气,在指定位置插入笑声后继续合成正文:
[excited]今天的天气真不错![laughing]我们一起出去玩吧!
以下文本在第二句切换为兴奋语气:
[serious]请注意安全事项。[excited]好了,现在让我们开始吧!
支持标签
控制类标签
控制类标签设置后续文本的情感或风格,直到出现下一个控制类标签;长句被自动切分时,作用范围以切分后的文本为界。
| 标签 | 说明 |
|---|---|
| 悲伤 |
| 惊叹 |
| 深沉大声呐喊 |
| 颤抖 |
| 愤怒 |
| 兴奋 |
| 讽刺 |
| 好奇 |
| 吸血鬼语气 |
| 无聊 |
| 疲倦 |
| 轻蔑 |
| 大喊 |
| ASMR 轻声 |
| 惊慌 |
| 调皮 |
| 共情 |
| 低声耳语 |
| 不情愿 |
| 哭泣 |
| 严肃 |
| 非常缓慢 |
| 非常快速 |
富语言类标签
富语言类标签在当前位置插入拟声效果,不改变前后文本的情感风格。
| 标签 | 说明 |
|---|---|
| 倒吸气 |
| 叹息 |
| 清嗓 |
| 咯咯笑 |
| 大笑 |
| 咳嗽 |
| 哼声、嗤笑 |
应用于生产环境
取消任务
使用 Qwen-Audio-TTS 或 CosyVoice 模型时,如需中断当前轮次合成,可发送取消指令。服务端会结束当前任务并返回 task-finished。
| 调用方式 | 版本要求 | 使用方法 |
|---|---|---|
Python SDK | 1.26.4 及以上版本 | 调用 |
Java SDK | 2.22.26 及以上版本 | 调用 |
WebSocket 原始协议 | 无需 SDK | 发送 |
WebSocket 连接复用
同一 WebSocket 连接可顺序处理多轮合成,各模型系列开启下一轮的方式如下:
| 模型系列 | 本轮结束信号 | 开启下一轮 |
|---|---|---|
Qwen-Audio-TTS、CosyVoice |
| 必须使用新的 说明使用 Python SDK 调用 Qwen-Audio-TTS 或 CosyVoice 时,直接创建的 |
Sambert |
| 必须使用新的 |
Qwen3-TTS |
| 在当前会话中继续发送 |
SDK 对象池的配置与完整示例请参见语音合成高并发最佳实践。Qwen3-TTS 的会话流程请参见 WebSocket API。
Qwen-Audio-TTS、CosyVoice、Sambert 任务结束后 60 秒内没有新任务时,连接会自动断开。连接已关闭或任务状态异常时,应重新建立连接。
模型限流
按对应模型的限流规则控制请求频率和并发数。限流条件、常见报错及处理方法请参见限流。
高并发最佳实践
通过对象池复用合成对象与连接,并按业务需求配置并发、预热和异常处理,具体请参见语音合成高并发最佳实践。
支持模型
华北2(北京)
- Qwen-Audio-TTS:qwen-audio-3.1-tts-flash、qwen-audio-3.0-tts-plus、qwen-audio-3.0-tts-flash
- CosyVoice:cosyvoice-v3.5-plus、cosyvoice-v3.5-flash、cosyvoice-v3-plus、cosyvoice-v3-flash、cosyvoice-v2
- Qwen3-TTS:qwen3-tts-flash-realtime
- Sambert:sambert-zhinan-v1、sambert-zhiqi-v1、sambert-zhichu-v1、sambert-zhide-v1、sambert-zhijia-v1、sambert-zhiru-v1、sambert-zhiqian-v1、sambert-zhixiang-v1、sambert-zhiwei-v1、sambert-zhihao-v1、sambert-zhijing-v1、sambert-zhiming-v1、sambert-zhimo-v1、sambert-zhina-v1、sambert-zhishu-v1、sambert-zhistella-v1、sambert-zhiting-v1、sambert-zhixiao-v1、sambert-zhiya-v1、sambert-zhiye-v1、sambert-zhiying-v1、sambert-zhiyuan-v1、sambert-zhiyue-v1、sambert-zhigui-v1、sambert-zhishuo-v1、sambert-zhimiao-emo-v1、sambert-zhimao-v1、sambert-zhilun-v1、sambert-zhifei-v1、sambert-zhida-v1、sambert-camila-v1、sambert-perla-v1、sambert-indah-v1、sambert-clara-v1、sambert-hanna-v1、sambert-beth-v1、sambert-betty-v1、sambert-cally-v1、sambert-cindy-v1、sambert-eva-v1、sambert-donna-v1、sambert-brian-v1、sambert-waan-v1,请参见Sambert模型列表
新加坡
- Qwen-Audio-TTS:qwen-audio-3.1-tts-flash、qwen-audio-3.0-tts-plus、qwen-audio-3.0-tts-flash
- CosyVoice:cosyvoice-v3-plus、cosyvoice-v3-flash
- Qwen3-TTS:qwen3-tts-flash-realtime
系统音色与试听分别参见 Qwen-Audio-TTS、CosyVoice、Qwen3-TTS 和 Sambert 音色列表。使用复刻或设计音色时,合成模型须与创建音色时指定的目标模型一致。
API 参考
通过 AOQ 接入的流程和示例,请参见AOQ 接入。支持的模型及版本请参见模型与协议支持范围。
WebSocket 原始协议的完整调用示例见以下文档。
常见问题
使用复刻音色生成的音频无声音如何排查?
确认 voice 为创建成功的音色 ID,创建音色时的 target_model 与合成时的 model 一致。音色状态、源音频要求及质量建议请参见声音复刻。
为什么语音合成的实际时长与 WAV 文件显示的时长不一致?
流式返回 WAV 时,文件头可能无法反映最终音频长度。如需准确的时长信息,可将 format 设为 pcm,接收完整音频后添加包含实际长度的 WAV 文件头。
为什么音频无法播放?
请按以下场景逐一排查:
-
音频保存为完整文件(如 xx.mp3)的情况
- 音频格式一致性:请求参数中的音频格式须与文件后缀一致(如参数为 wav 则文件须为 .wav)。
- 播放器兼容性:确认播放器支持该音频的格式和采样率。
-
流式播放音频的情况
- 将音频流保存为完整文件,尝试用播放器播放。如果文件无法播放,请参考场景 1 的排查方法。
- 如果文件可正常播放,则问题在流式播放实现。请确认播放器支持流式播放(如 ffmpeg、pyaudio、AudioFormat、MediaSource 等)。
为什么音频播放卡顿?
请按以下步骤逐一排查:
-
检查文本发送速度:确保发送间隔合理,避免上段音频播完后下段文本尚未到达。
-
检查回调函数性能:
- 确认回调函数中无阻塞性业务逻辑。
- 回调运行在 WebSocket 线程,阻塞会影响数据接收。建议将音频数据写入独立缓冲区,在其他线程中处理。
-
检查网络稳定性:网络波动可能导致音频传输中断或延迟。
语音合成耗时较长是什么原因?
分段输入时,过长的文本发送间隔会增加合成总时长;首次调用还包含 WebSocket 建连开销。高并发场景下的预热与耗时统计,请参见语音合成高并发最佳实践。
如何限制 API Key 仅用于语音合成服务(权限隔离)?
通过新建业务空间并仅授权特定模型,可限制 API Key 的使用范围。请参见业务空间管理。
子业务空间的 API Key 能否调用 Qwen-Audio-TTS/CosyVoice 模型?
默认业务空间下,所有模型均可调用。
子业务空间下,需要为 API Key 对应的子业务空间进行模型授权。请参见子业务空间的模型调用。