本文介绍非实时语音合成CosyVoice的Java SDK调用方法,支持非流式和流式两种调用模式。
用户指南:参见非实时语音合成。
本文描述的功能仅在华北2(北京)地域可用。
阿里云百炼为华北2(北京)地域推出了业务空间专属域名,能够为推理请求提供卓越的性能和更高的稳定性,建议从 dashscope.aliyuncs.com 迁移至 {WorkspaceId}.cn-beijing.maas.aliyuncs.com。
{WorkspaceId}需要替换为真实的Workspace ID。现有域名仍可正常使用。
前提条件
HttpSpeechSynthesizer 类
包路径:com.alibaba.dashscope.audio.http_tts.HttpSpeechSynthesizer
功能:基于HTTP的语音合成,支持非流式和流式两种调用方式。
构造方法
public HttpSpeechSynthesizer()
创建HttpSpeechSynthesizer实例,使用默认配置。SDK会自动从环境变量DASHSCOPE_API_KEY或Constants.apiKey获取API Key。
callAndReturnAudio() - 非流式调用(返回音频数据)
方法签名:
public ByteBuffer callAndReturnAudio(HttpSpeechSynthesisParam param) throws ApiException, NoApiKeyException, InputRequiredException
参数说明:
|
参数 |
类型 |
说明 |
|
param |
语音合成参数对象,包含模型、文本、音色等配置。 |
返回值:ByteBuffer,包含完整的音频数据。可通过remaining()获取音频大小(字节)。
call() - 非流式调用(返回音频URL)
方法签名:
public HttpSpeechSynthesisResult call(HttpSpeechSynthesisParam param) throws ApiException, NoApiKeyException, InputRequiredException
参数说明:
|
参数 |
类型 |
说明 |
|
param |
语音合成参数对象。 |
返回值:HttpSpeechSynthesisResult对象,通过getAudioInfo().getUrl()获取音频下载URL,URL有效期有限,可通过getAudioInfo().getExpiresAt()获取过期时间。
streamCall() - 流式调用
方法签名:
public void streamCall(HttpSpeechSynthesisParam param, ResultCallback<HttpSpeechSynthesisResult> callback) throws ApiException, NoApiKeyException, InputRequiredException
参数说明:
|
参数 |
类型 |
说明 |
|
param |
语音合成参数对象。 |
|
|
callback |
ResultCallback<HttpSpeechSynthesisResult> |
回调对象,需实现 |
该方法为异步调用,音频数据通过回调函数分片返回,适用于对首包延迟有要求的场景。
ResultCallback 回调方法:
com.alibaba.dashscope.common.ResultCallback是DashScope SDK提供的通用回调接口,需实现以下三个方法:
|
方法 |
参数 |
说明 |
|
onEvent |
HttpSpeechSynthesisResult result |
每接收到一个音频分片时触发。通过 |
|
onComplete |
无 |
语音合成完成时触发,表示所有音频分片已接收完毕。 |
|
onError |
Exception e |
合成过程中发生错误时触发,可通过 |
HttpSpeechSynthesisParam 类
包路径:com.alibaba.dashscope.audio.http_tts.HttpSpeechSynthesisParam
通过Builder模式构建参数对象。
部分参数没有专用的Builder方法,需要通过继承自父类的parameter(String key, Object value)方法或parameters(Map<String, Object>)方法进行设置,详见下表中的说明。
|
方法 |
类型 |
必填 |
说明 |
|
model(String) |
String |
是 |
语音合成模型。 取值范围:
|
|
text(String) |
String |
是 |
待合成文本。 支持 SSML 和 LaTeX 格式输入。将待合成文本替换为对应格式即可。
|
|
voice(String) |
String |
是 |
音色。 取值范围:
|
|
format(String) |
String |
否 |
音频编码格式。 默认值:mp3。 取值范围:
|
|
sampleRate(int) |
int |
否 |
音频采样率(Hz)。 取值范围:8000, 16000, 22050(默认), 24000, 44100, 48000。 |
|
volume(int) |
int |
否 |
音量。 默认值:50。 取值范围:[0, 100]。 |
|
rate(float) |
float |
否 |
语速。 默认值:1.0。 取值范围:[0.5, 2.0]。 |
|
pitch(float) |
float |
否 |
音调。 默认值:1.0。 取值范围:[0.5, 2.0]。 |
|
enable_ssml |
boolean |
否 |
是否开启SSML功能。设置为 默认值:false。 说明
通过parameter设置
通过parameters设置
|
|
word_timestamp_enabled |
boolean |
否 |
是否开启字级别时间戳。 默认值:false。 仅在流式输出模式下可用。支持的音色范围:cosyvoice-v3.5-plus、cosyvoice-v3.5-flash、cosyvoice-v3-flash、cosyvoice-v3-plus和cosyvoice-v2模型的复刻音色,以及CosyVoice音色列表中标记为支持的系统音色。其他模型的复刻音色不支持此功能。 说明
通过parameter设置
通过parameters设置
|
|
seed |
int |
否 |
生成时使用的随机数种子,使合成的效果产生变化。在模型版本、文本、音色及其他参数均相同的前提下,使用相同的seed可复现相同的合成结果。 默认值0。 取值范围:[0, 65535]。 说明
通过parameter设置
通过parameters设置
|
|
language_hints |
List |
否 |
重要
指定语音合成的目标语言,提升合成效果。 当数字、缩写、符号等朗读方式或者小语种合成效果不符合预期时使用,例如:
取值范围:
说明
通过parameter设置
通过parameters设置
|
|
instruction |
String |
否 |
设置指令,用于控制方言、情感或角色等合成效果。 具体用法请参见非实时语音合成。 说明
通过parameter设置
通过parameters设置
|
|
bit_rate |
int |
否 |
音频码率(单位:kbps)。 默认值:32。 取值范围:[6, 510]。 重要
仅在 说明
通过parameter设置
通过parameters设置
|
|
enable_aigc_tag |
boolean |
否 |
是否在生成的音频中添加AIGC隐性标识。设置为true时,会将隐性标识嵌入到支持格式(wav/mp3/opus)的音频中。 默认值:false。 仅cosyvoice-v3-flash、cosyvoice-v3-plus、cosyvoice-v2支持该功能。 说明
通过parameter设置
通过parameters设置
|
|
aigc_propagator |
String |
否 |
设置AIGC隐性标识中的 默认值:阿里云UID。 仅cosyvoice-v3-flash、cosyvoice-v3-plus、cosyvoice-v2支持该功能。 说明
通过parameter设置
通过parameters设置
|
|
aigc_propagate_id |
String |
否 |
设置AIGC隐性标识中的 默认值:本次语音合成请求Request ID。 仅cosyvoice-v3-flash、cosyvoice-v3-plus、cosyvoice-v2支持该功能。 说明
通过parameter设置
通过parameters设置
|
|
hot_fix |
Map |
否 |
文本热修复配置,用于自定义指定词语的发音或对待合成文本进行替换。 cosyvoice-v2不支持该功能。 参数介绍:
示例:
说明
通过parameter设置
通过parameters设置
|
|
enable_markdown_filter |
boolean |
否 |
重要
仅cosyvoice-v3-flash复刻音色支持该功能。 是否启用 Markdown 过滤。启用该功能后,系统在合成语音前自动过滤输入文本中的 Markdown 标记符号,避免将其朗读为文字内容。 默认值:false。 取值范围:
说明
通过parameter设置
通过parameters设置
|
示例代码
以下示例展示CosyVoice语音合成的非流式和流式调用方式。运行前请确保已设置环境变量DASHSCOPE_API_KEY。
不同模型版本需使用对应版本的音色。例如cosyvoice-v3-flash和cosyvoice-v3-plus使用longanyang等音色,cosyvoice-v2使用longxiaochun_v2等音色。更换模型时请同步更换为对应版本的音色。此外,每个音色支持的语言不同,合成非中文语言时,需选择支持对应语言的音色。具体的模型与音色对应关系,请参见CosyVoice音色列表。
非流式调用
非流式调用会等待服务端合成完成后一次性返回结果。根据返回类型的不同,提供以下两种方式:
-
callAndReturnAudio():返回音频二进制数据(ByteBuffer),适用于直接保存或处理音频的场景。 -
call():返回音频URL,适用于需要通过URL下载音频的场景。
import com.alibaba.dashscope.audio.http_tts.AudioInfo;
import com.alibaba.dashscope.audio.http_tts.HttpSpeechSynthesisParam;
import com.alibaba.dashscope.audio.http_tts.HttpSpeechSynthesisResult;
import com.alibaba.dashscope.audio.http_tts.HttpSpeechSynthesizer;
import com.alibaba.dashscope.exception.ApiException;
import com.alibaba.dashscope.exception.InputRequiredException;
import com.alibaba.dashscope.exception.NoApiKeyException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
public class CosyVoiceSyncExample {
static {
// 以下为华北2(北京)地域的配置,调用时请将"{WorkspaceId}"替换为真实的业务空间ID,各地域的配置不同。
Constants.baseHttpApiUrl = "https://{WorkspaceId}.cn-beijing.maas.aliyuncs.com/api/v1";
}
/**
* 非流式调用示例一:返回音频数据(ByteBuffer)
* 调用callAndReturnAudio方法,阻塞等待合成完成后返回完整音频数据。
*/
public static void syncCallReturnAudio() {
HttpSpeechSynthesizer synthesizer = new HttpSpeechSynthesizer();
HttpSpeechSynthesisParam param =
HttpSpeechSynthesisParam.builder()
.model("cosyvoice-v3-flash") // 更换模型时,需同步更换为对应版本的音色
.text("我家的后面有一个很大的花园。")
.voice("longanyang") // 该音色适用于cosyvoice-v3系列,cosyvoice-v2请使用longxiaochun_v2等v2音色
.format("wav")
.sampleRate(24000)
// 未配置环境变量时,将下行替换为:apiKey("sk-xxx"),即替换为实际的API Key
.apiKey(System.getenv("DASHSCOPE_API_KEY"))
// 通过parameter方法设置额外参数
// .parameter("seed", 1234)
// .parameter("enable_ssml", true)
.build();
try {
ByteBuffer audioData = synthesizer.callAndReturnAudio(param);
if (audioData != null && audioData.hasRemaining()) {
byte[] bytes = new byte[audioData.remaining()];
audioData.get(bytes);
try (FileOutputStream fos = new FileOutputStream("sync_output.wav")) {
fos.write(bytes);
System.out.println("Audio saved to sync_output.wav, size: " + bytes.length + " bytes");
} catch (IOException e) {
System.err.println("Failed to save audio: " + e.getMessage());
}
}
} catch (ApiException | NoApiKeyException | InputRequiredException e) {
System.err.println("Synthesis failed: " + e.getMessage());
}
System.exit(0);
}
/**
* 非流式调用示例二:返回音频URL
* 调用call方法,返回包含音频URL的结果对象,可通过URL下载音频文件。
*/
public static void syncCallReturnUrl() {
HttpSpeechSynthesizer synthesizer = new HttpSpeechSynthesizer();
HttpSpeechSynthesisParam param =
HttpSpeechSynthesisParam.builder()
.model("cosyvoice-v3-flash") // 更换模型时,需同步更换为对应版本的音色
.text("我家的后面有一个很大的花园。")
.voice("longanyang") // 该音色适用于cosyvoice-v3系列,cosyvoice-v2请使用longxiaochun_v2等v2音色
.format("wav")
.sampleRate(24000)
// 未配置环境变量时,将下行替换为:apiKey("sk-xxx"),即替换为实际的API Key
.apiKey(System.getenv("DASHSCOPE_API_KEY"))
.build();
try {
HttpSpeechSynthesisResult result = synthesizer.call(param);
System.out.println("Request ID: " + result.getRequestId());
if (result.hasAudioUrl()) {
AudioInfo audioInfo = result.getAudioInfo();
System.out.println("Audio URL: " + audioInfo.getUrl());
System.out.println("Expires At: " + audioInfo.getExpiresAt());
System.out.println("Remaining Time: " + audioInfo.getRemainingSeconds() + " seconds");
}
} catch (ApiException | NoApiKeyException | InputRequiredException e) {
System.err.println("Synthesis failed: " + e.getMessage());
}
}
public static void main(String[] args) {
// 非流式调用示例一:返回音频数据(ByteBuffer)
// syncCallReturnAudio();
// 非流式调用示例二:返回音频URL
syncCallReturnUrl();
}
}
流式调用
流式调用通过回调函数分片返回音频数据,无需等待合成完成即可开始处理,适用于对首包延迟有要求的实时播放场景。
import com.alibaba.dashscope.audio.http_tts.HttpSpeechSynthesisParam;
import com.alibaba.dashscope.audio.http_tts.HttpSpeechSynthesisResult;
import com.alibaba.dashscope.audio.http_tts.HttpSpeechSynthesizer;
import com.alibaba.dashscope.common.ResultCallback;
import com.alibaba.dashscope.exception.ApiException;
import com.alibaba.dashscope.exception.InputRequiredException;
import com.alibaba.dashscope.exception.NoApiKeyException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.concurrent.CountDownLatch;
public class CosyVoiceStreamExample {
static {
// 以下为华北2(北京)地域的配置,调用时请将"{WorkspaceId}"替换为真实的业务空间ID,各地域的配置不同。
Constants.baseHttpApiUrl = "https://{WorkspaceId}.cn-beijing.maas.aliyuncs.com/api/v1";
}
public static void streamCallWithCallback() {
HttpSpeechSynthesizer synthesizer = new HttpSpeechSynthesizer();
HttpSpeechSynthesisParam param =
HttpSpeechSynthesisParam.builder()
.model("cosyvoice-v3-flash") // 更换模型时,需同步更换为对应版本的音色
.text("今天天气真好,适合出去玩。")
.voice("longanyang") // 该音色适用于cosyvoice-v3系列,cosyvoice-v2请使用longxiaochun_v2等v2音色
.format("wav")
.sampleRate(24000)
// 未配置环境变量时,将下行替换为:apiKey("sk-xxx"),即替换为实际的API Key
.apiKey(System.getenv("DASHSCOPE_API_KEY"))
.build();
CountDownLatch latch = new CountDownLatch(1);
// 新增:创建输出文件流
try (FileOutputStream fos = new FileOutputStream("output.wav")) {
synthesizer.streamCall(param,
new ResultCallback<HttpSpeechSynthesisResult>() {
private int chunkCount = 0;
@Override
public void onEvent(HttpSpeechSynthesisResult result) {
chunkCount++;
if (result.hasAudioData()) {
System.out.println("Received chunk #" + chunkCount
+ ", size: " + result.getAudioDataSize() + " bytes");
try {
fos.write(result.getAudioData());
} catch (IOException e) {
System.err.println("Failed to write audio data: " + e.getMessage());
}
}
if (result.getRequestId() != null) {
System.out.println("Request ID: " + result.getRequestId());
}
}
@Override
public void onComplete() {
System.out.println("Synthesis completed, total chunks: " + chunkCount);
System.out.println("Audio saved to output.wav");
latch.countDown();
}
@Override
public void onError(Exception e) {
System.err.println("Error during synthesis: " + e.getMessage());
latch.countDown();
}
});
latch.await();
} catch (ApiException | NoApiKeyException | InputRequiredException | InterruptedException e) {
System.err.println("Failed: " + e.getMessage());
} catch (IOException e) {
System.err.println("Failed to create output file: " + e.getMessage());
}
}
public static void main(String[] args) {
streamCallWithCallback();
System.exit(0);
}
}