语音合成CosyVoice Java SDK

本文介绍语音合成CosyVoice Java SDK的使用。

前提条件

  • 已开通服务并获取API Key。请配置API Key到环境变量,而非硬编码在代码中,防范因代码泄露导致的安全风险。

    说明

    当您需要为第三方应用或用户提供临时访问权限,或者希望严格控制敏感数据访问、删除等高风险操作时,建议使用临时鉴权Token

    与长期有效的 API Key 相比,临时鉴权 Token 具备时效性短(60秒)、安全性高的特点,适用于临时调用场景,能有效降低API Key泄露的风险。

    使用方式:在代码中,将原本用于鉴权的 API Key 替换为获取到的临时鉴权 Token 即可。

  • 安装最新版DashScope SDK

语音合成文本限制与格式规范

文本长度限制

  • 非流式调用(同步调用异步调用Flowable非流式调用):单次发送文本长度不得超过 2000 字符。

  • 流式调用(流式调用Flowable流式调用):单次发送文本长度不得超过 2000 字符,且累计发送文本总长度不得超过 20 万字符。

字符计算规则

  • 汉字:2字符

  • 英文字母/数字/标点/空格:1字符

  • 计算文本长度时,SSML标签内容也包含在内

  • 示例:

    • "你好" → 2+2=4字符

    • "中A123" → 2+1+2+1+1+1=8字符

    • "中文。" → 2+2+1=5字符

    • "中 文。" → 2+1+2+1=6字符

    • "<speak>你好<speak/>" → 7+2+2+8=19字符

编码格式

需采用UTF-8编码。

数学表达式支持说明

当前数学表达式解析功能仅适用于cosyvoice-v2模型,支持识别中小学常见的数学表达式,包括但不限于基础运算、代数、几何等内容。

详情请参见Latex能力支持说明

SSML标记语言支持说明

当前SSML(Speech Synthesis Markup Language,语音合成标记语言)功能仅适用于cosyvoice-v2模型,使用时需满足以下条件:

快速开始

SpeechSynthesizer提供了语音合成的关键接口,支持以下几种调用方式:

  • 同步调用:提交文本后,服务端立即处理并返回完整的语音合成结果。整个过程是阻塞式的,客户端需要等待服务端完成处理后才能继续下一步操作。适合短文本语音合成场景。

  • 异步调用:将文本一次发送至服务端并实时接收语音合成结果,不允许将文本分段发送。适用于对实时性要求高的短文本语音合成场景。

  • 流式调用:将文本逐步发送到服务端并实时接收语音合成结果,允许将长文本分段发送,服务端在接收到部分文本后便立即开始处理。适合实时性要求高的长文本语音合成场景。

同步调用

同步提交语音合成任务,直接获取完整结果。

image

实例化SpeechSynthesizer绑定请求参数,调用call方法进行合成并获取二进制音频数据。

发送的文本长度不得超过2000字符(详情请参见SpeechSynthesizercall方法)。

点击查看完整示例

import com.alibaba.dashscope.audio.ttsv2.SpeechSynthesisParam;
import com.alibaba.dashscope.audio.ttsv2.SpeechSynthesizer;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;

public class Main {
    // 模型
    private static String model = "cosyvoice-v2";
    // 音色
    private static String voice = "longxiaochun_v2";

    public static void streamAudioDataToSpeaker() {
        // 请求参数
        SpeechSynthesisParam param =
                SpeechSynthesisParam.builder()
                        // 若没有将API Key配置到环境变量中,需将下面这行代码注释放开,并将your-api-key替换为自己的API Key
                        // .apiKey("your-api-key")
                        .model(model) // 模型
                        .voice(voice) // 音色
                        .build();

        // 同步模式:禁用回调(第二个参数为null)
        SpeechSynthesizer synthesizer = new SpeechSynthesizer(param, null);
        // 阻塞直至音频返回 
        ByteBuffer audio = synthesizer.call("今天天气怎么样?");
        // 将音频数据保存到本地文件“output.mp3”中
        File file = new File("output.mp3");
        System.out.println(
                "[Metric] requestId为:"
                        + synthesizer.getLastRequestId()
                        + "首包延迟(毫秒)为:"
                        + synthesizer.getFirstPackageDelay());
        try (FileOutputStream fos = new FileOutputStream(file)) {
            fos.write(audio.array());
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public static void main(String[] args) {
        streamAudioDataToSpeaker();
        System.exit(0);
    }
}

异步调用

异步提交语音合成任务,通过注册ResultCallback回调,逐帧接收实时语音分段数据。

image

实例化SpeechSynthesizer绑定请求参数回调接口(ResultCallback),调用call方法进行合成并通过回调接口(ResultCallback)onEvent方法实时获取合成结果。

发送的文本长度不得超过2000字符(详情请参见SpeechSynthesizercall方法)。

点击查看完整示例

以下示例,展示如何使用同步接口调用语音大模型CosyVoice的音色“龙小淳(longxiaochun)”,将文案“今天天气怎么样”合成采样率为22050Hz,音频格式为MP3的音频。

import com.alibaba.dashscope.audio.tts.SpeechSynthesisResult;
import com.alibaba.dashscope.audio.ttsv2.SpeechSynthesisParam;
import com.alibaba.dashscope.audio.ttsv2.SpeechSynthesizer;
import com.alibaba.dashscope.common.ResultCallback;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.CountDownLatch;

class TimeUtils {
    private static final DateTimeFormatter formatter =
            DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");

    public static String getTimestamp() {
        return LocalDateTime.now().format(formatter);
    }
}

public class Main {
    // 模型
    private static String model = "cosyvoice-v2";
    // 音色
    private static String voice = "longxiaochun_v2";

    public static void streamAudioDataToSpeaker() {
        CountDownLatch latch = new CountDownLatch(1);

        // 实现回调接口ResultCallback
        ResultCallback<SpeechSynthesisResult> callback = new ResultCallback<SpeechSynthesisResult>() {
            @Override
            public void onEvent(SpeechSynthesisResult result) {
                // System.out.println("收到消息: " + result);
                if (result.getAudioFrame() != null) {
                    // 此处实现保存音频数据到本地的逻辑
                    System.out.println(TimeUtils.getTimestamp() + " 收到音频");
                }
            }

            @Override
            public void onComplete() {
                System.out.println(TimeUtils.getTimestamp() + " 收到Complete,语音合成结束");
                latch.countDown();
            }

            @Override
            public void onError(Exception e) {
                System.out.println("出现异常:" + e.toString());
                latch.countDown();
            }
        };

        // 请求参数
        SpeechSynthesisParam param =
                SpeechSynthesisParam.builder()
                        // 若没有将API Key配置到环境变量中,需将下面这行代码注释放开,并将your-api-key替换为自己的API Key
                        // .apiKey("your-api-key")
                        .model(model) // 模型
                        .voice(voice) // 音色
                        .build();
        // 第二个参数“callback”传入回调即启用异步模式
        SpeechSynthesizer synthesizer = new SpeechSynthesizer(param, callback);
        // 非阻塞调用,立即返回null(实际结果通过回调接口异步传递),在回调接口的onEvent方法中实时获取二进制音频
        synthesizer.call("今天天气怎么样?");
        // 等待合成完成
        try {
            latch.await();
            // 等待播放线程全部播放完
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.out.println(
                "[Metric] requestId为:"
                        + synthesizer.getLastRequestId()
                        + ",首包延迟(毫秒)为:"
                        + synthesizer.getFirstPackageDelay());
    }

    public static void main(String[] args) {
        streamAudioDataToSpeaker();
        System.exit(0);
    }
}

流式调用

分多次提交文本,通过注册ResultCallback回调,逐帧接收实时语音分段数据。

说明
  • 流式输入时可多次调用streamingCall按顺序提交文本片段。服务端接收文本片段后自动进行分句:

    • 完整语句立即合成

    • 不完整语句缓存至完整后合成

    调用 streamingComplete 时,服务端会强制合成所有已接收但未处理的文本片段(包括未完成的句子)。

  • 发送文本片段的间隔不得超过23秒,否则触发“request timeout after 23 seconds”异常。

    若无待发送文本,需及时调用 streamingComplete结束任务。

    服务端强制设定23秒超时机制,客户端无法修改该配置。
image
  1. 实例化SpeechSynthesizer

    实例化SpeechSynthesizer绑定请求参数回调接口(ResultCallback)

  2. 流式传输

    多次调用SpeechSynthesizerstreamingCall方法分片提交待合成文本,将待合成文本分段发送至服务端。

    在发送文本的过程中,服务端会通过回调接口(ResultCallback)onEvent方法,将合成结果实时返回给客户端。

    每次调用streamingCall方法发送的文本片段(即text)长度不得超过2000字符,累计发送的文本总长度不得超过20万字符。

  3. 结束处理

    调用SpeechSynthesizerstreamingComplete方法结束语音合成。

    该方法会阻塞当前线程,直到回调接口(ResultCallback)onComplete或者onError回调触发后才会释放线程阻塞。

    请务必确保调用该方法,否则可能会导致结尾部分的文本无法成功转换为语音。

点击查看完整示例

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 java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.CountDownLatch;

class TimeUtils {
    private static final DateTimeFormatter formatter =
            DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");

    public static String getTimestamp() {
        return LocalDateTime.now().format(formatter);
    }
}


public class Main {
    private static String[] textArray = {"流式文本语音合成SDK,",
            "可以将输入的文本", "合成为语音二进制数据,", "相比于非流式语音合成,",
            "流式合成的优势在于实时性", "更强。用户在输入文本的同时",
            "可以听到接近同步的语音输出,", "极大地提升了交互体验,",
            "减少了用户等待时间。", "适用于调用大规模", "语言模型(LLM),以",
            "流式输入文本的方式", "进行语音合成的场景。"};
    private static String model = "cosyvoice-v2"; // 模型
    private static String voice = "longxiaochun_v2"; // 音色

    public static void streamAudioDataToSpeaker() {
        CountDownLatch latch = new CountDownLatch(1);

        // 配置回调函数
        ResultCallback<SpeechSynthesisResult> callback = new ResultCallback<SpeechSynthesisResult>() {
            @Override
            public void onEvent(SpeechSynthesisResult result) {
                // System.out.println("收到消息: " + result);
                if (result.getAudioFrame() != null) {
                    // 此处实现处理音频数据的逻辑
                    System.out.println(TimeUtils.getTimestamp() + " 收到音频");
                }
            }

            @Override
            public void onComplete() {
                System.out.println(TimeUtils.getTimestamp() + " 收到Complete,语音合成结束");
                latch.countDown();
            }

            @Override
            public void onError(Exception e) {
                System.out.println("出现异常:" + e.toString());
                latch.countDown();
            }
        };

        // 请求参数
        SpeechSynthesisParam param =
                SpeechSynthesisParam.builder()
                        // 若没有将API Key配置到环境变量中,需将下面这行代码注释放开,并将your-api-key替换为自己的API Key
                        // .apiKey("your-api-key")
                        .model(model)
                        .voice(voice)
                        .format(SpeechSynthesisAudioFormat
                                .PCM_22050HZ_MONO_16BIT) // 流式合成使用PCM或者MP3
                        .build();
        SpeechSynthesizer synthesizer = new SpeechSynthesizer(param, callback);
        // 带Callback的call方法将不会阻塞当前线程
        for (String text : textArray) {
            // 发送文本片段,在回调接口的onEvent方法中实时获取二进制音频
            synthesizer.streamingCall(text);
        }
        // 结束流式语音合成
        synthesizer.streamingComplete();
        System.out.println(
                "[Metric] requestId为:"
                        + synthesizer.getLastRequestId()
                        + ",首包延迟(毫秒)为:"
                        + synthesizer.getFirstPackageDelay());
        // 等待合成完成
        try {
            latch.await();
            // 等待播放线程全部播放完
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }

    public static void main(String[] args) {
        streamAudioDataToSpeaker();
        System.exit(0);
    }
}

通过Flowable调用

Flowable是一个用于工作流和业务流程管理的开源框架,它基于Apache 2.0许可证发布。关于Flowable的使用,请参见Flowable API详情

使用Flowable前需确保已集成RxJava库,并了解响应式编程基础概念。

非流式调用

以下示例展示了通过Flowable对象的blockingForEach接口,阻塞式地获取每次流式返回的SpeechSynthesisResult类型数据。

您也可以在Flowable的所有流式数据返回完成后,通过SpeechSynthesizergetAudioData来获取完整的合成结果。

点击查看完整示例

import com.alibaba.dashscope.audio.ttsv2.SpeechSynthesisParam;
import com.alibaba.dashscope.audio.ttsv2.SpeechSynthesizer;
import com.alibaba.dashscope.exception.NoApiKeyException;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

class TimeUtils {
    private static final DateTimeFormatter formatter =
            DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");

    public static String getTimestamp() {
        return LocalDateTime.now().format(formatter);
    }
}

public class Main {
    private static String model = "cosyvoice-v2"; // 模型
    private static String voice = "longxiaochun_v2"; // 音色

    public static void streamAudioDataToSpeaker() throws NoApiKeyException {
        // 请求参数
        SpeechSynthesisParam param =
                SpeechSynthesisParam.builder()
                        // 若没有将API Key配置到环境变量中,需将下面这行代码注释放开,并将your-api-key替换为自己的API Key
                        // .apiKey("your-api-key")
                        .model(model) // 模型
                        .voice(voice) // 音色
                        .build();
        SpeechSynthesizer synthesizer = new SpeechSynthesizer(param, null);
        synthesizer.callAsFlowable("今天天气怎么样?").blockingForEach(result -> {
            // System.out.println("收到消息: " + result);
            if (result.getAudioFrame() != null) {
                // 此处实现处理音频数据的逻辑
                System.out.println(TimeUtils.getTimestamp() + " 收到音频");
            }
        });
        System.out.println(
                "[Metric] requestId为:"
                        + synthesizer.getLastRequestId()
                        + "首包延迟(毫秒)为:"
                        + synthesizer.getFirstPackageDelay());
    }

    public static void main(String[] args) throws NoApiKeyException {
        streamAudioDataToSpeaker();
        System.exit(0);
    }
}

流式调用

以下示例展示了通过Flowable对象作为输入参数,输入文本流。并通过Flowable对象作为返回值,利用的blockingForEach接口,阻塞式地获取每次流式返回的SpeechSynthesisResult类型数据。

您也可以在Flowable的所有流式数据返回完成后,通过SpeechSynthesizergetAudioData来获取完整的合成结果。

点击查看完整示例

import com.alibaba.dashscope.audio.ttsv2.SpeechSynthesisParam;
import com.alibaba.dashscope.audio.ttsv2.SpeechSynthesizer;
import com.alibaba.dashscope.exception.NoApiKeyException;
import io.reactivex.BackpressureStrategy;
import io.reactivex.Flowable;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

class TimeUtils {
    private static final DateTimeFormatter formatter =
            DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");

    public static String getTimestamp() {
        return LocalDateTime.now().format(formatter);
    }
}

public class Main {
    private static String[] textArray = {"流式文本语音合成SDK,",
            "可以将输入的文本", "合成为语音二进制数据,", "相比于非流式语音合成,",
            "流式合成的优势在于实时性", "更强。用户在输入文本的同时",
            "可以听到接近同步的语音输出,", "极大地提升了交互体验,",
            "减少了用户等待时间。", "适用于调用大规模", "语言模型(LLM),以",
            "流式输入文本的方式", "进行语音合成的场景。"};
    private static String model = "cosyvoice-v2";
    private static String voice = "longxiaochun_v2";

    public static void streamAudioDataToSpeaker() throws NoApiKeyException {
        // 模拟流式输入
        Flowable<String> textSource = Flowable.create(emitter -> {
            new Thread(() -> {
                for (int i = 0; i < textArray.length; i++) {
                    emitter.onNext(textArray[i]);
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                }
                emitter.onComplete();
            }).start();
        }, BackpressureStrategy.BUFFER);

        // 请求参数
        SpeechSynthesisParam param =
                SpeechSynthesisParam.builder()
                        // 若没有将API Key配置到环境变量中,需将下面这行代码注释放开,并将apiKey替换为自己的API Key
                        // .apiKey("yourApikey")
                        .model(model) // 模型
                        .voice(voice) // 音色
                        .build();
        SpeechSynthesizer synthesizer = new SpeechSynthesizer(param, null);
        synthesizer.streamingCallAsFlowable(textSource).blockingForEach(result -> {
            if (result.getAudioFrame() != null) {
                // 此处实现播放音频的逻辑
                System.out.println(
                        TimeUtils.getTimestamp() +
                                " 二进制音频大小为:" + result.getAudioFrame().capacity());
            }
        });
        System.out.println(
                "[Metric] requestId为:"
                        + synthesizer.getLastRequestId()
                        + ",首包延迟(毫秒)为:"
                        + synthesizer.getFirstPackageDelay());
    }

    public static void main(String[] args) throws NoApiKeyException {
        streamAudioDataToSpeaker();
        System.exit(0);
    }
}

高并发调用

DashScope Java SDK中,采用了OkHttp3的连接池技术,以减少重复建立连接的开销。详情请参见高并发场景

请求参数

通过SpeechSynthesisParam的链式方法配置模型、音色等参数。配置完成的参数对象传入SpeechSynthesizer的构造函数中使用。

点击查看示例

SpeechSynthesisParam param = SpeechSynthesisParam.builder()
    .model("cosyvoice-v2") // 模型
    .voice("longxiaochun_v2") // 音色
    .format(SpeechSynthesisAudioFormat.WAV_8000HZ_MONO_16BIT) // 音频编码格式、采样率
    .volume(50) // 音量,取值范围:[0, 100]
    .speechRate(1.0) // 语速,取值范围:[0.5, 2]
    .pitchRate(1.0) // 语调,取值范围:[0.5, 2]
    .build();

参数

类型

默认值

是否必须

说明

model

String

-

指定模型,支持cosyvoice-v2(推荐)、cosyvoice-v1

v1 和 v2 在编码方式上相同,但使用时应确保 model 和 voice 参数匹配:v2模型只能搭配v2音色,v1模型只能搭配v1音色。

voice

String

-

指定语音合成所使用的音色。

支持如下两种音色:

format

enum

因音色而异

指定音频编码格式及采样率。

若未指定format,则合成音频采样率为22.05kHz,格式为mp3。

说明

默认采样率代表当前音色的最佳采样率,缺省条件下默认按照该采样率输出,同时支持降采样或升采样。

可指定的音频编码格式及采样率如下:

  • SpeechSynthesisAudioFormat.WAV_8000HZ_MONO_16BIT,代表音频格式为wav,采样率为8kHz

  • SpeechSynthesisAudioFormat.WAV_16000HZ_MONO_16BIT,代表音频格式为wav,采样率为16kHz

  • SpeechSynthesisAudioFormat.WAV_22050HZ_MONO_16BIT,代表音频格式为wav,采样率为22.05kHz

  • SpeechSynthesisAudioFormat.WAV_24000HZ_MONO_16BIT,代表音频格式为wav,采样率为24kHz

  • SpeechSynthesisAudioFormat.WAV_44100HZ_MONO_16BIT,代表音频格式为wav,采样率为44.1kHz

  • SpeechSynthesisAudioFormat.WAV_48000HZ_MONO_16BIT,代表音频格式为wav,采样率为48kHz

  • SpeechSynthesisAudioFormat.MP3_8000HZ_MONO_128KBPS,代表音频格式为mp3,采样率为8kHz

  • SpeechSynthesisAudioFormat.MP3_16000HZ_MONO_128KBPS,代表音频格式为mp3,采样率为16kHz

  • SpeechSynthesisAudioFormat.MP3_22050HZ_MONO_256KBPS,代表音频格式为mp3,采样率为22.05kHz

  • SpeechSynthesisAudioFormat.MP3_24000HZ_MONO_256KBPS,代表音频格式为mp3,采样率为24kHz

  • SpeechSynthesisAudioFormat.MP3_44100HZ_MONO_256KBPS,代表音频格式为mp3,采样率为44.1kHz

  • SpeechSynthesisAudioFormat.MP3_48000HZ_MONO_256KBPS,代表音频格式为mp3,采样率为48kHz

  • SpeechSynthesisAudioFormat.PCM_8000HZ_MONO_16BIT,代表音频格式为pcm,采样率为8kHz

  • SpeechSynthesisAudioFormat.PCM_16000HZ_MONO_16BIT,代表音频格式为pcm,采样率为16kHz

  • SpeechSynthesisAudioFormat.PCM_22050HZ_MONO_16BIT,代表音频格式为pcm,采样率为22.05kHz

  • SpeechSynthesisAudioFormat.PCM_24000HZ_MONO_16BIT,代表音频格式为pcm,采样率为24kHz

  • SpeechSynthesisAudioFormat.PCM_44100HZ_MONO_16BIT,代表音频格式为pcm,采样率为44.1kHz

  • SpeechSynthesisAudioFormat.PCM_48000HZ_MONO_16BIT,代表音频格式为pcm,采样率为48kHz

volume

int

50

指定音量,取值范围:0~100。

speechRate

float

1.0

指定语速,取值范围:0.5~2。

  • 0.5:表示默认语速的0.5倍速。

  • 1:表示默认语速。默认语速是指模型默认输出的合成语速,语速会因音色不同而略有不同。约每秒钟4个字。

  • 2:表示默认语速的2倍速。

pitchRate

float

1.0

指定语调,取值范围:0.5~2。

apiKey

String

-

指定用户API Key。

关键接口

SpeechSynthesizer

SpeechSynthesizer通过“import com.alibaba.dashscope.audio.ttsv2.SpeechSynthesizer;”方式引入,提供语音合成的关键接口。

接口/方法

参数

返回值

描述

public SpeechSynthesizer(SpeechSynthesisParam param, ResultCallback<SpeechSynthesisResult> callback)

SpeechSynthesizer实例

构造函数。

public ByteBuffer call(String text)

text:待合成文本(UTF-8)

ByteBuffernull

将整段文本(无论是纯文本还是包含SSML的文本)转换为语音。

在创建SpeechSynthesizer实例时,存在以下两种情况:

  • 没有指定ResultCallbackcall方法会阻塞当前线程直到语音合成完成。使用方法请参见同步调用

  • 指定了ResultCallbackcall方法会立刻返回null。合成结果通过回调接口(ResultCallback)onEvent方法获取。使用方法请参见异步调用

public void streamingCall(String text)

text:待合成文本(UTF-8)

流式发送待合成文本(不支持包含SSML的文本)。

您可以多次调用该接口,将待合成文本分多次发送给服务端。合成结果通过回调接口(ResultCallback)onEvent方法获取。

详细调用流程和参考示例请参见流式调用

public void streamingComplete() throws RuntimeException

结束流式语音合成。

该方法阻塞调用线程直至发生以下条件之一:

  • 服务端完成最终音频合成(成功)

  • 流式会话异常中断(失败)

  • 达到10分钟超时阈值(自动解除阻塞)

详细的调用流程和参考示例请参见流式调用

重要

流式调用时,请确保调用该方法,以免导致合成语音缺失。

public Flowable<SpeechSynthesisResult> callAsFlowable(String text)

text:待合成文本,须为UTF-8格式

合成结果,封装在 Flowable<SpeechSynthesisResult>

非流式文本(不支持包含SSML的文本)输入实时转换为流式语音输出,合成结果在flowable中流式返回。

详细的调用流程和参考示例请参见通过Flowable调用

public Flowable<SpeechSynthesisResult> streamingCallAsFlowable(Flowable<String> textStream)

textStream:封装了待合成文本的Flowable实例

合成结果,封装在 Flowable<SpeechSynthesisResult>

流式文本(不支持包含SSML的文本)输入实时转换为流式语音输出,合成结果在flowable中流式返回。

详细的调用流程和参考示例请参见通过Flowable调用

public String getLastRequestId()

上一个任务的Request ID

获取上一个任务的Request ID,在调用callstreamingCallcallAsFlowablestreamingCallAsFlowable开始新任务之后可以使用。

public long getFirstPackageDelay()

当前任务首包延迟

获取当前任务的首包延迟,任务结束后使用。

首包延迟是开始发送文本和接收第一个音频包之间的时间,单位为毫秒。

回调接口(ResultCallback

异步调用流式调用时,通过回调接口ResultCallback获取合成结果。通过“import com.alibaba.dashscope.common.ResultCallback;”方式引入。

点击查看示例

ResultCallback<SpeechSynthesisResult> callback = new ResultCallback<SpeechSynthesisResult>() {
    @Override
    public void onEvent(SpeechSynthesisResult result) {
        System.out.println("RequestId为:" + result.getRequestId());
        // 实时处理音频分片(如播放/写入缓冲)
    }

    @Override
    public void onComplete() {
        System.out.println("任务完成");
        // 处理合成结束逻辑(如释放播放器)
    }

    @Override
    public void onError(Exception e) {
        System.out.println("任务失败:" + e.getMessage());
        // 处理异常(网络错误/服务端错误码)
    }
};

接口/方法

参数

返回值

描述

public void onEvent(SpeechSynthesisResult result)

result:SpeechSynthesisResult实例

当服务端推送语音合成数据时被异步回调。

调用SpeechSynthesisResultgetAudioFrame方法能够获得二进制音频数据。

public void onComplete()

当所有合成数据全部返回(语音合成完成)后被异步回调。

public void onError(Exception e)

e:异常信息

发生异常时该接口被异步回调。

建议在onError方法中实现完整的异常日志记录和资源清理逻辑。

响应结果

服务器返回二进制音频数据:

  • 同步调用:对SpeechSynthesizercall方法返回的二进制音频数据进行处理。

  • 异步调用流式调用:对回调接口(ResultCallback)onEvent方法的参数(SpeechSynthesisResult类型)进行处理。

    SpeechSynthesisResult的关键接口如下:

    接口/方法

    参数

    返回值

    描述

    public ByteBuffer getAudioFrame()

    二进制音频数据

    返回当前流式合成片段的二进制音频数据,可能为空(当无新数据到达时)。

    您可以将二进制音频数据合成为一个完整的音频文件后使用播放器播放,也可以通过支持流式播放的播放器实时播放。

    重要
    • 流式语音合成中,音频分段传输,需使用流式播放器,不可逐帧播放,避免解码失败。

      支持流式播放的播放器:ffmpeg、pyaudio (Python)、AudioFormat (Java)、MediaSource (Javascript)等。
    • 将音频数据合成完整的音频文件时,应以追加模式写入同一文件。

    • 流式语音合成的wav/mp3 格式音频仅首帧包含头信息,后续帧为纯音频数据。

    public String getRequestId()

    任务的Request ID

    获取任务的Request ID。当调用getAudioFrame获取到二进制音频数据时,getRequestId方法的返回值为null

错误码

语音合成中常见错误码如下,如遇其他报错问题,请参见错误信息进行排查。

如果以上方法仍未解决问题,请提交阿里云工单或加入开发者群,并提供Request ID,以便我们为您进一步排查问题。

错误码(Code)

错误信息(Message)

说明

InvalidParameter

request timeout after 23 seconds

流式调用(流式调用Flowable流式调用)时,超过23秒未向服务端发送文本且服务端无任何音频返回。

请检查为什么长时间未发送文本,例如,长时间未收到大语言模型返回的文本,因此未能及时向CosyVoice模型发送文本。

如果长时间(超过23秒)不向服务端发送消息,请及时调用SpeechSynthesizerstreamingComplete方法结束任务。

[tts:]Engine return error code: 418

请按以下步骤检查请求参数 voice(音色)是否正确:

  1. 检查 voice 参数赋值:

    • 如果使用的是默认音色,请对照音色列表中的“voice参数”进行确认。

    • 如果使用的是声音复刻音色:

      • 检查音色状态:请通过查询指定音色接口,确认音色状态是否为“OK”。

      • 检查账号:声音复刻所使用的音色归属的账号,必须与语音合成时所使用的账号保持一致。

  2. 检查 model(模型)与 voice(音色)版本是否匹配:

    v2模型只能使用v2的音色,v1模型只能使用v1的音色,两者不可混用。

network error

InputRequiredException: Parameter invalid: text is null

此错误通常是由于未发送待合成文本引起的。

请根据以下可能原因进行排查:

  1. 参数遗漏:在调用语音合成接口时,可能忘记为 text 参数赋值。

  2. 代码异常:某些代码逻辑可能导致对 text 参数的赋值失败。

Throttling.RateQuota

Requests rate limit exceeded, please try again later.

调用接口频率过高,已超出语音合成大模型的并发限制,详情请参见限流

如需提升并发额度,请通过提交阿里云工单或加入开发者群进行申请。

InvalidApiKey

Invalid API-key provided.

API Key无效。

检查并确认API Key(在获取API Key的操作指引中可查看)是否正确,确保无多出空格或缺少字母等问题。

Model.AccessDenied

Model access denied.

出现该问题的原因是使用了子业务空间的API Key调用模型,请使用默认业务空间的API Key(参见获取API Key)进行调用。如果想使用子业务空间API Key,请参见子业务空间的模型调用,为API Key对应的子业务空间进行模型授权

更多示例

更多示例,请参见GitHub

音色列表

当前默认支持的音色如下表所示。若您需要更加个性化的音色,可通过声音复刻功能免费定制专属音色,详情请参见使用复刻的音色进行语音合成

  • cosyvoice-v2音色列表

    重要

    以下为cosyvoice-v2音色列表,使用时必须将请求参数model设置为cosyvoice-v2,否则将调用失败。

    cosyvoice-v1音色列表请参见cosyvoice-v1音色列表

    适用场景

    音色

    音色特质

    音频试听(右键保存音频)

    voice参数

    语言

    SSML

    客服

    龙应催

    严肃催收男

    longyingcui

    中、英

    支持

    龙应答

    开朗高音女

    longyingda

    中、英

    支持

    龙应静

    低调冷静女

    longyingjing

    中、英

    支持

    龙应严

    义正严辞女

    longyingyan

    中、英

    支持

    龙应甜

    温柔甜美女

    longyingtian

    中、英

    支持

    龙应冰

    尖锐强势女

    longyingbing

    中、英

    支持

    龙应桃

    温柔淡定女

    longyingtao

    中、英

    支持

    龙应聆

    温和共情女

    longyingling

    中、英

    支持

    语音助手

    YUMI

    正经青年女

    longyumi_v2

    中、英

    支持

    龙小淳

    知性积极女

    longxiaochun_v2

    中、英

    支持

    龙小夏

    沉稳权威女

    longxiaoxia_v2

    中、英

    支持

    直播

    龙安燃

    活泼质感女

    longanran

    中、英

    支持

    龙安宣

    经典直播女

    longanxuan

    中、英

    支持

    有声书

    龙三叔

    沉稳质感男

    longsanshu

    中、英

    支持

    龙修

    博才说书男

    longxiu_v2

    中、英

    支持

    龙妙

    抑扬顿挫女

    longmiao_v2

    中、英

    支持

    龙悦

    温暖磁性女

    longyue_v2

    中、英

    支持

    龙楠

    睿智青年男

    longnan_v2

    中、英

    支持

    龙媛

    温暖治愈女

    longyuan_v2

    中、英

    支持

    社交陪伴

    龙安柔

    温柔闺蜜女

    longanrou

    中、英

    支持

    龙嫱

    浪漫风情女

    longqiang_v2

    中、英

    支持

    龙寒

    温暖痴情男

    longhan_v2

    中、英

    支持

    龙星

    温婉邻家女

    longxing_v2

    中、英

    支持

    龙华

    元气甜美女

    longhua_v2

    中、英

    支持

    龙婉

    积极知性女

    longwan_v2

    中、英

    支持

    龙橙

    智慧青年男

    longcheng_v2

    中、英

    支持

    龙菲菲

    甜美娇气女

    longfeifei_v2

    中、英

    支持

    龙小诚

    磁性低音男

    longxiaocheng_v2

    中、英

    支持

    龙哲

    呆板大暖男

    longzhe_v2

    中、英

    支持

    龙颜

    温暖春风女

    longyan_v2

    中、英

    支持

    龙天

    磁性理智男

    longtian_v2

    中、英

    支持

    龙泽

    温暖元气男

    longze_v2

    中、英

    支持

    龙邵

    积极向上男

    longshao_v2

    中、英

    支持

    龙浩

    多情忧郁男

    longhao_v2

    中、英

    支持

    龙深

    实力歌手男

    kabuleshen_v2

    中、英

    支持

    童声

    龙杰力豆

    阳光顽皮男

    longjielidou_v2

    中、英

    支持

    龙铃

    稚气呆板女

    longling_v2

    中、英

    支持

    龙可

    懵懂乖乖女

    longke_v2

    中、英

    支持

    龙仙

    豪放可爱女

    longxian_v2

    中、英

    支持

    方言

    龙老铁

    东北直率男

    longlaotie_v2

    中(东北)、英

    支持

    龙嘉怡

    知性粤语女

    longjiayi_v2

    中(粤语)、英

    支持

    龙桃

    积极粤语女

    longtao_v2

    中(粤语)、英

    支持

    诗词朗诵

    龙飞

    热血磁性男

    longfei_v2

    中、英

    支持

    李白

    古代诗仙男

    libai_v2

    中、英

    支持

    龙津

    优雅温润男

    longjin_v2

    中、英

    支持

    新闻播报

    龙书

    沉稳青年男

    longshu_v2

    中、英

    支持

    Bella2.0

    精准干练女

    loongbella_v2

    中、英

    支持

    龙硕

    博才干练男

    longshuo_v2

    中、英

    支持

    龙小白

    沉稳播报女

    longxiaobai_v2

    中、英

    支持

    龙婧

    典型播音女

    longjing_v2

    中、英

    支持

    loongstella

    飒爽利落女

    loongstella_v2

    中、英

    支持

    出海营销

    loongeva

    知性英文女

    loongeva_v2

    英式英文

    不支持

    loongbrian

    沉稳英文男

    loongbrian_v2

    英式英文

    不支持

    loongluna

    英式英文女

    loongluna_v2

    英式英文

    不支持

    loongluca

    英式英文男

    loongluca_v2

    英式英文

    不支持

    loongemily

    英式英文女

    loongemily_v2

    英式英文

    不支持

    loongeric

    英式英文男

    loongeric_v2

    英式英文

    不支持

    loongabby

    美式英文女

    loongabby_v2

    美式英文

    不支持

    loongannie

    美式英文女

    loongannie_v2

    美式英文

    不支持

    loongandy

    美式英文男

    loongandy_v2

    美式英文

    不支持

    loongava

    美式英文女

    loongava_v2

    美式英文

    不支持

    loongbeth

    美式英文女

    loongbeth_v2

    美式英文

    不支持

    loongbetty

    美式英文女

    loongbetty_v2

    美式英文

    不支持

    loongcindy

    美式英文女

    loongcindy_v2

    美式英文

    不支持

    loongcally

    美式英文女

    loongcally_v2

    美式英文

    不支持

    loongdavid

    美式英文男

    loongdavid_v2

    美式英文

    不支持

    loongdonna

    美式英文女

    loongdonna_v2

    美式英文

    不支持

    loongkyong

    韩语女

    loongkyong_v2

    韩语

    不支持

    loongtomoka

    日语女

    loongtomoka_v2

    日语

    不支持

    loongtomoya

    日语男

    loongtomoya_v2

    日语

    不支持

  • cosyvoice-v1音色列表

    点击查看cosyvoice-v1音色列表

    相较于cosyvoice-v1,cosyvoice-v2效果更好,音色更丰富,且cosyvoice-v2大部分音色支持SSML功能,建议优先使用cosyvoice-v2音色体验更好的效果。

    重要
    • 使用v1音色时,必须将请求参数model设置为cosyvoice-v1,否则将调用失败。

    • 如果当前音色在“语言”列中未明确标注支持的口音,则表明该音色不区分具体口音。

    音色

    音频试听(右键保存音频)

    voice参数

    适用场景

    语言

    龙婉

    longwan

    语音助手、

    导航播报、

    聊天数字人

    中文普通话

    龙橙

    longcheng

    语音助手、

    导航播报、

    聊天数字人

    中文普通话

    龙华

    longhua

    语音助手、

    导航播报、

    聊天数字人

    中文普通话

    龙小淳

    longxiaochun

    语音助手、

    导航播报、

    聊天数字人

    中文普通话+英文

    龙小夏

    longxiaoxia

    语音助手、聊天数字人

    中文普通话

    龙小诚

    longxiaocheng

    语音助手、导航播报、聊天数字人

    中文普通话+英文

    龙小白

    longxiaobai

    聊天数字人、有声书、语音助手

    中文普通话

    龙老铁

    longlaotie

    新闻播报、有声书、语音助手、直播带货、导航播报

    中文东北口音

    龙书

    longshu

    有声书、语音助手、导航播报、新闻播报、智能客服

    中文普通话

    龙硕

    longshuo

    语音助手、导航播报、新闻播报、客服催收

    中文普通话

    龙婧

    longjing

    语音助手、导航播报、新闻播报、客服催收

    中文普通话

    龙妙

    longmiao

    客服催收、导航播报、有声书、语音助手

    中文普通话

    龙悦

    longyue

    语音助手、诗词朗诵、有声书朗读、导航播报、新闻播报、客服催收

    中文普通话

    龙媛

    longyuan

    有声书、语音助手、聊天数字人

    中文普通话

    龙飞

    longfei

    会议播报、新闻播报、有声书

    中文普通话

    龙杰力豆

    longjielidou

    新闻播报、有声书、聊天助手

    中文普通话+英文

    龙彤

    longtong

    有声书、导航播报、聊天数字人

    中文普通话

    龙祥

    longxiang

    新闻播报、有声书、导航播报

    中文普通话

    Stella

    loongstella

    语音助手、直播带货、导航播报、客服催收、有声书

    中文普通话+英文

    Bella

    loongbella

    语音助手、客服催收、新闻播报、导航播报

    中文普通话

常见问题

功能特性/计量计费/限流

Q:我想了解CosyVoice的功能特性、计量计费、限流等信息,应该去哪里查看?

以上信息可在语音合成-CosyVoice中查看。

Q:当遇到发音不准的情况时,有什么解决方案可以尝试?

通过SSML可以对语音合成效果进行个性化定制。

Q:当前RPS(Requests Per Second)无法满足实际业务需求,该怎么办?如何扩容?是否收费?

您可以选择提交阿里云工单或加入开发者群进行申请。扩容免费。

Q:cosyvoice-v1 和 cosyvoice-v2 有什么区别?计费方式是否不同?

v1 和 v2 在编码方式上相同,但使用时需注意请求参数 model 和 voice 的设置需匹配实际版本(如 v2 模型需使用 v2 音色,否则会报错)。

v1 和 v2 的计费方式完全一致。

故障排查

如遇代码报错问题,请根据错误码中的信息进行排查。

Q:如何获取Request ID

通过以下两种方式可以获取:

Q:为什么音频无法播放?

请根据以下场景逐一排查:

  1. 音频保存为完整文件(如xx.mp3)的情况

    1. 音频格式一致性:确保请求参数中设置的音频格式与文件后缀一致。例如,如果请求参数设置的音频格式为wav,但文件后缀为mp3,可能会导致播放失败。

    2. 播放器兼容性:确认使用的播放器是否支持该音频文件的格式和采样率。例如,某些播放器可能不支持高采样率或特定编码的音频文件。

  2. 流式播放音频的情况

    1. 将音频流保存为完整文件,尝试使用播放器播放。如果文件无法播放,请参考场景 1 的排查方法。

    2. 如果文件可以正常播放,则问题可能出在流式播放的实现上。请确认使用的播放器是否支持流式播放。

      常见的支持流式播放的工具和库包括:ffmpeg、pyaudio (Python)、AudioFormat (Java)、MediaSource (Javascript)等。

Q:为什么音频播放卡顿?

请根据以下场景逐一排查:

  1. 音频保存为完整文件(如xx.mp3)的情况

    请提交阿里云工单或加入开发者群,并提供Request ID,以便我们为您排查问题。

  2. 流式播放音频的情况

    1. 检查文本发送速度: 确保发送文本的间隔合理,避免前一句音频播放完毕后,下一句文本未能及时发送。

    2. 检查回调函数性能:

      • 检查回调函数中是否存在过多业务逻辑,导致阻塞。

      • 回调函数运行在 WebSocket 线程中,若被阻塞,可能会影响 WebSocket 接收网络数据包,进而导致音频接收卡顿。

      • 建议将音频数据写入一个独立的音频缓冲区(audio buffer),然后在其他线程中读取并处理,避免阻塞 WebSocket 线程。

    3. 检查网络稳定性: 确保网络连接稳定,避免因网络波动导致音频传输中断或延迟。

    4. 进一步排查: 如果以上方法仍未解决问题,请提交阿里云工单或加入开发者群,并提供Request ID,以便我们为您进一步排查问题。

Q:为什么没有返回语音?为什么结尾部分的文本没能成功转换成语音?(合成语音缺失)

请检查是否遗漏了调用SpeechSynthesizerstreamingComplete方法。在语音合成过程中,服务端会在缓存足够文本后才开始合成。如果未调用streamingComplete方法,可能会导致缓存中的结尾部分文本未能被合成为语音。

Q:运行代码报NoApiKeyException,提示“Can not find api-key”是什么原因?

出现该问题的原因是没有配置API Key到环境变量,且在请求参数中没有设置apiKey。您需要配置API Key到环境变量或在请求参数中设置apiKey

权限与认证

Q:我希望我的 API Key 仅用于 CosyVoice 语音合成服务,而不被百炼其他模型使用(权限隔离),我该如何做

可以通过新建业务空间并只授权特定模型来限制API Key的使用范围。详情请参见如何使用业务空间

Q:为什么运行代码后提示我Model.AccessDenied/Workspace.AccessDenied?该如何解决?

模型访问被拒绝。

出现该问题的原因是使用了子业务空间的API Key调用模型,请使用默认业务空间的API Key(参见获取API Key)进行调用。如果想使用子业务空间API Key,请参见子业务空间的模型调用,为API Key对应的子业务空间进行模型授权

Q:使用子业务空间的API Key是否可以调用CosyVoice模型?

对于默认业务空间,cosyvoice-v1cosyvoice-v2均可调用。

对于子业务空间:需要为API Key对应的子业务空间进行模型授权,详情请参见子业务空间的模型调用

更多问题

请参见GitHub QA