All Products
Search
Document Center

Alibaba Cloud Model Studio:CosyVoice speech synthesis Java SDK

Last Updated:Jul 03, 2026

Sintesis suara dengan CosyVoice menggunakan DashScope Java SDK.

Panduan pengguna: Untuk pengenalan model dan rekomendasi pemilihan, lihat Speech synthesis.

Titik akhir layanan

Secara default, SDK terhubung ke titik akhir Wilayah Beijing. Untuk menggunakan wilayah lain, atur Constants.baseWebsocketApiUrl sebelum menginisialisasi SDK.

Singapore

wss://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/api-ws/v1/inference

Ganti {WorkspaceId} dengan workspace ID Anda yang sebenarnya.

China (Beijing)

wss://{WorkspaceId}.cn-beijing.maas.aliyuncs.com/api-ws/v1/inference

Ganti {WorkspaceId} dengan workspace ID Anda yang sebenarnya.

Beralih ke wilayah Singapura:

import com.alibaba.dashscope.utils.Constants;

// Atur ini sebelum inisialisasi SDK apa pun
Constants.baseWebsocketApiUrl = "wss://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/api-ws/v1/inference";
Penting

Alibaba Cloud Model Studio telah merilis domain khusus ruang kerja untuk wilayah China (Beijing) dan Singapura. Domain khusus baru ini memberikan performa lebih unggul dan stabilitas lebih tinggi untuk permintaan inferensi. Kami merekomendasikan migrasi ke domain baru berikut:

  • China (Beijing): dari dashscope.aliyuncs.com ke {WorkspaceId}.cn-beijing.maas.aliyuncs.com

  • Singapura: dari dashscope-intl.aliyuncs.com ke {WorkspaceId}.ap-southeast-1.maas.aliyuncs.com

Ganti {WorkspaceId} dengan Workspace ID Anda yang sebenarnya. Domain lama tetap berfungsi penuh.

SpeechSynthesizer

Package: com.alibaba.dashscope.audio.ttsv2.SpeechSynthesizer

Konstruktor

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

Parameter:

  • param: Parameter sintesis suara, dibuat dengan SpeechSynthesisParam.builder()

  • callback: Callback untuk panggilan streaming. Berikan null untuk panggilan non-streaming.

call() - Sintesis non-streaming/unidirectional streaming

Tanda tangan metode:

public ByteBuffer call(String text)

Parameter:

Parameter

Tipe

Wajib

Deskripsi

text

String

Ya

Teks yang akan disintesis. Panjang maksimum: 20.000 karakter.

Nilai kembalian: ByteBuffer atau null. Untuk panggilan non-streaming, mengembalikan seluruh data audio. Untuk panggilan unidirectional streaming, metode ini mengembalikan null; audio dikirimkan melalui callback.

streamingCall() - Sintesis bidirectional streaming

Tanda tangan metode:

public void streamingCall(String text)

Parameter:

Parameter

Tipe

Wajib

Deskripsi

text

String

Ya

Teks yang akan disintesis. Panjang maksimum: 20.000 karakter. Anda dapat memanggil metode ini beberapa kali untuk menambahkan teks.

streamingComplete() - Mengakhiri bidirectional streaming

Tanda tangan metode:

public void streamingComplete()

Mengakhiri panggilan bidirectional streaming dan memberi tahu server bahwa seluruh teks telah dikirim.

callAsFlowable() - Sintesis unidirectional streaming (reaktif)

Tanda tangan metode:

public Flowable<SpeechSynthesisResult> callAsFlowable(String text)

Parameter:

Parameter

Tipe

Wajib

Deskripsi

text

String

Ya

Teks yang akan disintesis.

Nilai kembalian: Flowable<SpeechSynthesisResult> aliran reaktif.

streamingCallAsFlowable() - Sintesis bidirectional streaming (reaktif)

Tanda tangan metode:

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

Parameter:

Parameter

Tipe

Wajib

Deskripsi

textStream

Flowable<String>

Ya

Aliran reaktif teks.

Nilai kembalian: Flowable<SpeechSynthesisResult> aliran reaktif.

getDuplexApi().close() - Menutup koneksi WebSocket

Tanda tangan metode:

public boolean getDuplexApi().close(int code, String reason)

Parameter:

Parameter

Tipe

Wajib

Deskripsi

code

int

Ya

Kode penutupan.

reason

String

Ya

Alasan penutupan.

Nilai kembalian: boolean. Mengembalikan true jika koneksi berhasil ditutup, false jika tidak.

getLastRequestId() - Mendapatkan ID permintaan

Tanda tangan metode:

public String getLastRequestId()

Nilai kembalian: String, ID permintaan.

getFirstPackageDelay() - Mendapatkan latensi paket pertama

Tanda tangan metode:

public long getFirstPackageDelay()

Nilai kembalian: long. Latensi paket pertama dalam milidetik, diukur dari pengiriman segmen teks pertama hingga menerima paket audio pertama.

SpeechSynthesisParam

Package: com.alibaba.dashscope.audio.ttsv2.SpeechSynthesisParam

Contoh:

SpeechSynthesisParam param = SpeechSynthesisParam.builder()
    .model("cosyvoice-v3-flash") // Model
    .voice("longanyang") // Voice
    .format(SpeechSynthesisAudioFormat.WAV_8000HZ_MONO_16BIT) // Audio encoding format and sample rate
    .volume(50) // Volume. Value range: [0, 100]
    .speechRate(1.0f) // Speech rate. Value range: [0.5, 2]
    .pitchRate(1.0f) // Pitch. Value range: [0.5, 2]
    .build();

Metode builder

Metode

Tipe parameter

Wajib

Deskripsi

model(String)

String

Ya

Nama model.

voice(String)

String

Ya

voice string (required)

Voice yang digunakan untuk sintesis suara.

  • System voices: Lihat CosyVoice Voice list

  • Cloned voices: Voice kustom yang dibuat melalui voice cloning

  • Custom voices: Voice kustom yang dibuat melalui voice design

format(SpeechSynthesisAudioFormat)

enum

Tidak

Audio encoding format dan sample rate.

Default: SpeechSynthesisAudioFormat.MP3_22050HZ_MONO_256KBPS.

Package SpeechSynthesisAudioFormat: com.alibaba.dashscope.audio.ttsv2.SpeechSynthesisAudioFormat.

volume(int)

int

Tidak

Tingkat volume.

Nilai default: 50.

Nilai valid: [0, 100].

speechRate(float)

float

Tidak

Kecepatan bicara.

Nilai default: 1.0.

Nilai valid: [0.5, 2.0].

pitchRate(float)

float

Tidak

Lapangan.

Nilai default: 1.0.

Nilai valid: [0.5, 2.0].

enableWordTimestamp(boolean)

boolean

Tidak

Menentukan apakah akan mengaktifkan timestamp tingkat kata.

Nilai default: false.

Hanya tersedia dalam mode keluaran streaming. Voice yang didukung: cloned voices dari cosyvoice-v3.5-plus, cosyvoice-v3.5-flash, cosyvoice-v3-flash, cosyvoice-v3-plus, dan cosyvoice-v2, serta system voices yang ditandai sebagai didukung dalam CosyVoice Voice list. Cloned voices dari model lain tidak mendukung fitur ini.

seed(int)

int

Tidak

Seed acak untuk mengontrol variasi dalam output sintesis. Ketika versi model, teks, voice, dan parameter lainnya tidak berubah, menggunakan seed yang sama menghasilkan hasil identik.

Nilai default: 0.

Nilai valid: [0, 65535].

Untuk versi SDK sebelum 2.21.7, atur seed melalui parameter tambahan.

languageHints(List<String>)

List<String>

Tidak

Penting
  • Parameter ini berupa array, tetapi versi saat ini hanya memproses elemen pertama. Berikan satu nilai saja.

  • Parameter ini menentukan bahasa target untuk sintesis suara. Tidak terkait dengan bahasa sampel audio yang digunakan dalam voice cloning. Untuk mengatur bahasa sumber pada tugas cloning, lihat referensi API voice cloning.

Menentukan bahasa target untuk sintesis suara guna meningkatkan kualitas output.

Ketika pelafalan angka, ekspansi singkatan, pembacaan simbol, atau sintesis bahasa minoritas tidak sesuai ekspektasi, gunakan parameter ini. Contohnya:

  • Pelafalan angka tidak sesuai: "hello, this is 110" dibaca sebagai "hello, this is one zero" alih-alih pelafalan Mandarin yang diharapkan

  • Pelafalan simbol tidak akurat: "@" dibaca sebagai ekuivalen Mandarin alih-alih "at"

  • Kualitas sintesis bahasa minoritas buruk dengan hasil tidak alami

Nilai valid:

  • zh: Tiongkok

  • en: Inggris

  • fr: Prancis

  • de: Jerman

  • ja: Jepang

  • ko: Korea

  • ru: Rusia

  • pt: Portugis

  • th: Bahasa Thai

  • id: Bahasa Indonesia

  • vi: Vietnam

instruction(String)

String

Tidak

Mengontrol karakteristik sintesis seperti dialek, emosi, atau gaya berbicara.

Untuk detail penggunaan, lihat Instruction-based control.

hotFix(ParamHotFix)

ParamHotFix

Tidak

Mengonfigurasi koreksi pelafalan dan penggantian teks yang diterapkan sebelum sintesis.

Fitur ini tidak didukung oleh cosyvoice-v2.

Parameter:

  • pronunciation: Pelafalan kustom. Menentukan anotasi pinyin untuk kata-kata guna memperbaiki pelafalan default yang tidak akurat.

  • replace: Penggantian teks. Mengganti kata-kata tertentu dengan teks target sebelum sintesis. Teks yang diganti digunakan sebagai input sintesis aktual.

Contoh:

List<ParamHotFix.PronunciationItem> pronunciationItems = new ArrayList<>();
pronunciationItems.add(new ParamHotFix.PronunciationItem("weather", "tian1 qi4"));

List<ParamHotFix.ReplaceItem> replaceItems = new ArrayList<>();
replaceItems.add(new ParamHotFix.ReplaceItem("today", "gold day"));

ParamHotFix paramHotFix = new ParamHotFix();
paramHotFix.setPronunciation(pronunciationItems);
paramHotFix.setReplace(replaceItems);

SpeechSynthesisParam param = SpeechSynthesisParam.builder()
                        .model("cosyvoice-v3-flash") // Model
                        .voice("your_voice") // Replace with a cosyvoice-v3-flash cloned voice
                        .hotFix(paramHotFix)
                        .build();

parameter(String key, Object value)

String, Object

Tidak

Mengatur Parameter tambahan.

parameters(Map<String, Object>)

Map

Tidak

Mengatur Parameter tambahan.

Parameter tambahan

Diatur melalui parameter() atau parameters().

Contoh:

SpeechSynthesisParam param = SpeechSynthesisParam.builder()
  .model("cosyvoice-v3-flash")
  .voice("longanyang")
  .parameter("enable_markdown_filter", true)
  .build();

Parameter

Tipe

Wajib

Deskripsi

bit_rate

integer

Tidak

Laju bit audio dalam kbps. Ketika format audio adalah opus, gunakan bit_rate untuk menyesuaikan laju bit.

Nilai default: 32.

Nilai valid: [6, 510].

enable_aigc_tag

boolean

Tidak

Menentukan apakah akan menyematkan watermark AIGC dalam audio yang dihasilkan. Ketika diatur ke true, watermark disematkan dalam file audio dengan format yang didukung (wav/mp3/opus).

Nilai default: false.

Hanya cosyvoice-v3-flash, cosyvoice-v3-plus, dan cosyvoice-v2 yang mendukung fitur ini.

aigc_propagator

String

Tidak

Mengatur bidang ContentPropagator dalam watermark AIGC, mengidentifikasi propagator konten. Hanya berlaku ketika enable_aigc_tag bernilai true.

Nilai default: UID Alibaba Cloud.

Hanya cosyvoice-v3-flash, cosyvoice-v3-plus, dan cosyvoice-v2 yang mendukung fitur ini.

aigc_propagate_id

String

Tidak

Mengatur bidang PropagateID dalam watermark AIGC, mengidentifikasi secara unik aksi propagasi tertentu. Hanya berlaku ketika enable_aigc_tag bernilai true.

Nilai default: ID permintaan dari permintaan sintesis suara saat ini.

Hanya cosyvoice-v3-flash, cosyvoice-v3-plus, dan cosyvoice-v2 yang mendukung fitur ini.

enable_markdown_filter

boolean

Tidak

Penting

Hanya cloned voices dari cosyvoice-v3-flash yang mendukung fitur ini.

Menentukan apakah akan mengaktifkan penyaringan Markdown. Ketika diaktifkan, sistem secara otomatis menghapus simbol markup Markdown dari teks input sebelum sintesis, sehingga simbol tersebut tidak terbaca.

Nilai default: false.

Nilai valid:

  • true: Aktifkan penyaringan Markdown

  • false: Nonaktifkan penyaringan Markdown

ResultCallback

Package: com.alibaba.dashscope.common.ResultCallback

onEvent() - Menerima audio data

Tanda tangan metode:

public void onEvent(SpeechSynthesisResult result)

Parameter:

Parameter

Tipe

Wajib

Deskripsi

result

SpeechSynthesisResult

Ya

Dipicu ketika event sintesis diterima. Berisi frame audio, informasi timestamp, dan informasi output (tipe event, teks asli, dll.).

onComplete() - Sintesis selesai

Tanda tangan metode:

public void onComplete()

Dipicu ketika sintesis suara selesai.

onError() - Penanganan error

Tanda tangan metode:

public void onError(Exception e)

Parameter:

Parameter

Tipe

Wajib

Deskripsi

e

Exception

Ya

Dipicu ketika terjadi error. Berisi informasi exception.

SpeechSynthesisResult

Package: com.alibaba.dashscope.audio.tts.SpeechSynthesisResult

getAudioFrame() - Mendapatkan frame data audio

Tanda tangan metode:

public ByteBuffer getAudioFrame()

Nilai kembalian: ByteBuffer, frame data audio.

getTimestamp() - Mendapatkan informasi timestamp

Tanda tangan metode:

public Sentence getTimestamp()

Nilai kembalian: Sentence, informasi timestamp.

getOutput() - Mendapatkan informasi output

Tanda tangan metode:

public JsonObject getOutput()

Nilai kembalian: com.google.gson.JsonObject, informasi output dari event sintesis, berisi tipe event dan konten teks. Memerlukan versi SDK >= 2.22.0.

Informasi timestamp tingkat kalimat (Sentence)

Sentence mengenkapsulasi informasi timestamp tingkat kalimat.

getBeginTime() - Mendapatkan waktu mulai kalimat

Tanda tangan metode:

public int getBeginTime()

Nilai kembalian: Waktu mulai kalimat dalam milidetik.

getEndTime() - Mendapatkan waktu akhir kalimat

Tanda tangan metode:

public int getEndTime()

Nilai kembalian: Waktu akhir kalimat dalam milidetik.

getWords() - Mendapatkan timestamp tingkat kata

Tanda tangan metode:

public List<Word> getWords()

Nilai kembalian: List objek Word yang berisi informasi timestamp tingkat kata. Bisa jadi kosong.

Informasi timestamp tingkat kata (Word)

Word mengenkapsulasi informasi timestamp tingkat kata.

getBeginTime() - Mendapatkan waktu mulai kata

Tanda tangan metode:

public int getBeginTime()

Nilai kembalian: Waktu mulai kata dalam milidetik.

getEndTime() - Mendapatkan waktu akhir kata

Tanda tangan metode:

public int getEndTime()

Nilai kembalian: Waktu akhir kata dalam milidetik.

getText() - Mendapatkan teks

Tanda tangan metode:

public String getText()

Nilai kembalian: String, konten teks.

getPhonemes() - Mendapatkan timestamp tingkat fonem

Tanda tangan metode:

public List<Phoneme> getPhonemes()

Nilai kembalian: List objek Phoneme yang berisi informasi timestamp tingkat fonem. Bisa jadi kosong.

Informasi timestamp tingkat fonem (Phoneme)

Phoneme mengenkapsulasi informasi timestamp tingkat fonem.

getBeginTime() - Mendapatkan waktu mulai fonem

Tanda tangan metode:

public int getBeginTime()

Nilai kembalian: Waktu mulai fonem dalam milidetik.

getEndTime() - Mendapatkan waktu akhir fonem

Tanda tangan metode:

public int getEndTime()

Nilai kembalian: Waktu akhir fonem dalam milidetik.

getText() - Mendapatkan teks

Tanda tangan metode:

public String getText()

Nilai kembalian: String, konten teks.

getTone() - Mendapatkan nada

Tanda tangan metode:

public int getTone()

Nilai kembalian: Nilai nada.

  • Dalam bahasa Inggris, 0, 1, dan 2 masing-masing merepresentasikan unstressed, primary stress, dan secondary stress.

  • Dalam pinyin Mandarin, 1, 2, 3, 4, dan 5 masing-masing merepresentasikan nada pertama, kedua, ketiga, keempat, dan netral.

Informasi output (output)

getOutput() mengembalikan JsonObject yang mengenkapsulasi informasi output event sintesis. Ambil informasi ini dalam callback onEvent atau aliran Flowable. Informasi ini berisi bidang-bidang berikut:

Bidang

Tipe

Deskripsi

type

String

Tipe event. Nilai yang mungkin: sentence-begin (awal kalimat; mengembalikan teks yang akan disintesis), sentence-synthesis (sedang dalam proses sintesis audio; mengembalikan chunk data audio), sentence-end (akhir kalimat; mengembalikan konten teks dan timestamp tingkat kata).

original_text

String

Teks asli dari kalimat saat ini. Dikembalikan dalam event sentence-begin dan sentence-end.

sentence

JsonObject

Informasi kalimat, berisi indeks kalimat (index) dan timestamp tingkat kata (words). Event sentence-end mencakup informasi timestamp tingkat kata lengkap.

Kode contoh

SDK mendukung mode sintesis berikut:

  • Non-streaming: Panggilan blocking yang mengirimkan seluruh teks sekaligus dan langsung mengembalikan audio lengkap. Paling cocok untuk sintesis suara teks pendek.

  • Unidirectional streaming: Panggilan non-blocking yang mengirimkan seluruh teks sekaligus dan mengirimkan data audio (mungkin dalam potongan) melalui fungsi callback. Paling cocok untuk skenario teks pendek yang memerlukan latensi rendah.

  • Bidirectional streaming: Panggilan non-blocking yang mengirimkan teks dalam beberapa segmen dan mengirimkan audio yang disintesis secara inkremental melalui fungsi callback secara real time. Paling cocok untuk skenario teks panjang yang memerlukan latensi rendah.

Panggilan non-streaming

Panjang teks per permintaan tidak boleh melebihi 20.000 karakter.

Penting

Inisialisasi ulang instans SpeechSynthesizer sebelum setiap pemanggilan metode call.

import com.alibaba.dashscope.audio.ttsv2.SpeechSynthesisParam;
import com.alibaba.dashscope.audio.ttsv2.SpeechSynthesizer;
import com.alibaba.dashscope.utils.Constants;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;

public class Main {
    // Model
    private static String model = "cosyvoice-v3-flash";
    // Voice
    private static String voice = "longanyang";

    public static void streamAudioDataToSpeaker() {
        // Request parameters
        SpeechSynthesisParam param =
                SpeechSynthesisParam.builder()
                        // The API Keys for the Singapore and Beijing regions are different. Get an API Key: https://www.alibabacloud.com/help/en/model-studio/get-api-key
                        // If the environment variable is not configured, replace the following line with your Model Studio API Key: .apiKey("sk-xxx")
                        .apiKey(System.getenv("DASHSCOPE_API_KEY"))
                        .model(model) // Model
                        .voice(voice) // Voice
                        .build();

        // Synchronous mode: disable callback (second parameter is null)
        SpeechSynthesizer synthesizer = new SpeechSynthesizer(param, null);
        ByteBuffer audio = null;
        try {
            // Block until audio is returned
            audio = synthesizer.call("What's the weather like today?");
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            // Close the WebSocket connection after the task is completed
            synthesizer.getDuplexApi().close(1000, "bye");
        }
        if (audio != null) {
            // Save the audio data to a local file "output.mp3"
            File file = new File("output.mp3");
            // The first text transmission requires establishing a WebSocket connection, so the first packet latency includes the connection setup time
            System.out.println(
                    "[Metric] requestId: "
                            + synthesizer.getLastRequestId()
                            + ", first packet latency (ms): "
                            + 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) {
        // The following configuration is for the Singapore region. Replace "{WorkspaceId}" with your actual workspace ID. The configuration varies by region.
        Constants.baseWebsocketApiUrl = "wss://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/api-ws/v1/inference";
        streamAudioDataToSpeaker();
        System.exit(0);
    }
}

Panggilan unidirectional streaming

Panjang teks per permintaan tidak boleh melebihi 20.000 karakter.

Penting

Inisialisasi ulang instans SpeechSynthesizer sebelum setiap pemanggilan metode call.

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 com.alibaba.dashscope.utils.Constants;

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 {
    // Model
    private static String model = "cosyvoice-v3-flash";
    // Voice
    private static String voice = "longanyang";

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

        // Implement the ResultCallback interface
        ResultCallback<SpeechSynthesisResult> callback = new ResultCallback<SpeechSynthesisResult>() {
            @Override
            public void onEvent(SpeechSynthesisResult result) {
                if (result.getAudioFrame() != null) {
                    // Implement the logic to save audio data locally here
                    System.out.println(TimeUtils.getTimestamp() + " Audio received");
                }
                // Get output information, including event type and original text
                if (result.getOutput() != null && result.getOutput().has("type")) {
                    System.out.println("Event type: " + result.getOutput().get("type").getAsString()
                            + ", Original text: " + (result.getOutput().has("original_text") ? result.getOutput().get("original_text").getAsString() : ""));
                }
            }

            @Override
            public void onComplete() {
                System.out.println(TimeUtils.getTimestamp() + " Complete received, speech synthesis finished");
                latch.countDown();
            }

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

        // Request parameters
        SpeechSynthesisParam param =
                SpeechSynthesisParam.builder()
                        // The API Keys for the Singapore and Beijing regions are different. Get an API Key: https://www.alibabacloud.com/help/en/model-studio/get-api-key
                        // If the environment variable is not configured, replace the following line with your Model Studio API Key: .apiKey("sk-xxx")
                        .apiKey(System.getenv("DASHSCOPE_API_KEY"))
                        .model(model) // Model
                        .voice(voice) // Voice
                        .build();
        // Passing "callback" as the second parameter enables asynchronous mode
        SpeechSynthesizer synthesizer = new SpeechSynthesizer(param, callback);
        // Non-blocking call that returns null immediately (actual results are delivered asynchronously via the callback interface). Binary audio is received in real time through the onEvent method of the callback interface
        try {
            synthesizer.call("What's the weather like today?");
            // Wait for synthesis to complete
            latch.await();
            // Wait for playback thread to finish playing
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            // Close the WebSocket connection after the task is completed
            synthesizer.getDuplexApi().close(1000, "bye");
        }
        // The first text transmission requires establishing a WebSocket connection, so the first packet latency includes the connection setup time
        System.out.println(
                "[Metric] requestId: "
                        + synthesizer.getLastRequestId()
                        + ", first packet latency (ms): "
                        + synthesizer.getFirstPackageDelay());
    }

    public static void main(String[] args) {
        // The following configuration is for the Singapore region. Replace "{WorkspaceId}" with your actual workspace ID. The configuration varies by region.
        Constants.baseWebsocketApiUrl = "wss://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/api-ws/v1/inference";
        streamAudioDataToSpeaker();
        System.exit(0);
    }
}

Panggilan bidirectional streaming

Panjang teks per panggilan individu tidak boleh melebihi 20.000 karakter, dan panjang teks kumulatif dari semua panggilan tidak boleh melebihi 200.000 karakter.

  • Saat input streaming, panggil streamingCall beberapa kali untuk mengirimkan segmen teks secara berurutan. Server secara otomatis membagi teks yang diterima menjadi kalimat:

    • Kalimat lengkap langsung disintesis.

    • Kalimat tidak lengkap disimpan dalam buffer hingga membentuk kalimat lengkap.

    Ketika streamingComplete dipanggil, server memaksa mensintesis semua segmen teks yang diterima namun belum diproses, termasuk kalimat yang tidak lengkap.

  • Interval antara segmen teks berturut-turut tidak boleh melebihi 23 detik; melebihi batas ini akan memicu exception "request timeout after 23 seconds".

    Jika tidak ada teks yang tertunda, segera panggil streamingComplete untuk mengakhiri tugas.

    Penting

    Selalu panggil metode streamingComplete. Jika tidak, segmen teks akhir mungkin tidak dikonversi menjadi suara.

    Server menerapkan timeout 23 detik yang tidak dapat diubah di sisi klien.
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.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 = {"Streaming text-to-speech SDK, ",
            "can convert input text ", "into audio binary data. ", "Compared to non-streaming speech synthesis, ",
            "streaming synthesis offers better real-time performance. ", "While users input text, ",
            "they can hear nearly synchronous audio output, ", "greatly enhancing the interactive experience ",
            "and reducing user wait time. ", "It is suitable for calling large-scale ", "language models (LLMs) to ",
            "perform speech synthesis ", "with streaming text input."};
    private static String model = "cosyvoice-v3-flash"; // Model
    private static String voice = "longanyang"; // Voice

    public static void streamAudioDataToSpeaker() {
        // Configure the callback function
        ResultCallback<SpeechSynthesisResult> callback = new ResultCallback<SpeechSynthesisResult>() {
            @Override
            public void onEvent(SpeechSynthesisResult result) {
                // System.out.println("Message received: " + result);
                if (result.getAudioFrame() != null) {
                    // Implement the logic to process audio data here
                    System.out.println(TimeUtils.getTimestamp() + " Audio received");
                }
            }

            @Override
            public void onComplete() {
                System.out.println(TimeUtils.getTimestamp() + " Complete received, speech synthesis finished");
            }

            @Override
            public void onError(Exception e) {
                System.out.println("Exception occurred: " + e.toString());
            }
        };

        // Request parameters
        SpeechSynthesisParam param =
                SpeechSynthesisParam.builder()
                        // The API Keys for the Singapore and Beijing regions are different. Get an API Key: https://www.alibabacloud.com/help/en/model-studio/get-api-key
                        // If the environment variable is not configured, replace the following line with your Model Studio API Key: .apiKey("sk-xxx")
                        .apiKey(System.getenv("DASHSCOPE_API_KEY"))
                        .model(model)
                        .voice(voice)
                        .format(SpeechSynthesisAudioFormat
                                .PCM_22050HZ_MONO_16BIT) // Use PCM or MP3 for streaming synthesis
                        .build();
        SpeechSynthesizer synthesizer = new SpeechSynthesizer(param, callback);
        // The call method with Callback will not block the current thread
        try {
            for (String text : textArray) {
                // Send text fragments and receive binary audio in real time through the onEvent method of the callback interface
                synthesizer.streamingCall(text);
            }
            // Wait for streaming speech synthesis to finish
            synthesizer.streamingComplete();
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            // Close the WebSocket connection after the task is completed
            synthesizer.getDuplexApi().close(1000, "bye");
        }

        // The first text transmission requires establishing a WebSocket connection, so the first packet latency includes the connection setup time
        System.out.println(
                "[Metric] requestId: "
                        + synthesizer.getLastRequestId()
                        + ", first packet latency (ms): "
                        + synthesizer.getFirstPackageDelay());
    }

    public static void main(String[] args) {
        // The following configuration is for the Singapore region. Replace "{WorkspaceId}" with your actual workspace ID. The configuration varies by region.
        Constants.baseWebsocketApiUrl = "wss://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/api-ws/v1/inference";
        streamAudioDataToSpeaker();
        System.exit(0);
    }
}

Panggilan berbasis Flowable

Flowable adalah tipe RxJava yang merepresentasikan aliran reaktif yang mendukung backpressure. Untuk informasi lebih lanjut, lihat dokumentasi RxJava Flowable.

Sebelum menggunakan Flowable, pastikan library RxJava telah diintegrasikan dan Anda memahami dasar-dasar pemrograman reaktif.

Panjang teks per panggilan individu tidak boleh melebihi 20.000 karakter, dan panjang teks kumulatif dari semua panggilan tidak boleh melebihi 200.000 karakter.

Panggilan unidirectional streaming

Contoh berikut menunjukkan cara menggunakan antarmuka blockingForEach dari objek Flowable untuk mengambil setiap objek SpeechSynthesisResult yang distream secara blocking.

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

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-v3-flash"; // Model
    private static String voice = "longanyang"; // Voice

    public static void streamAudioDataToSpeaker() throws NoApiKeyException {
        // Request parameters
        SpeechSynthesisParam param =
                SpeechSynthesisParam.builder()
                        // The API Keys for the Singapore and Beijing regions are different. Get an API Key: https://www.alibabacloud.com/help/en/model-studio/get-api-key
                        // If the environment variable is not configured, replace the following line with your Model Studio API Key: .apiKey("sk-xxx")
                        .apiKey(System.getenv("DASHSCOPE_API_KEY"))
                        .model(model) // Model
                        .voice(voice) // Voice
                        .build();
        SpeechSynthesizer synthesizer = new SpeechSynthesizer(param, null);
        synthesizer.callAsFlowable("What's the weather like today?").blockingForEach(result -> {
            if (result.getAudioFrame() != null) {
                // Implement the logic to process audio data here
                System.out.println(TimeUtils.getTimestamp() + " Audio received");
            }
            // Get output information, including event type and original text
            if (result.getOutput() != null && result.getOutput().has("type")) {
                System.out.println("Event type: " + result.getOutput().get("type").getAsString()
                        + ", Original text: " + (result.getOutput().has("original_text") ? result.getOutput().get("original_text").getAsString() : ""));
            }
        });
        // Close the WebSocket connection after the task is completed
        synthesizer.getDuplexApi().close(1000, "bye");
        // The first text transmission requires establishing a WebSocket connection, so the first packet latency includes the connection setup time
        System.out.println(
                "[Metric] requestId: "
                        + synthesizer.getLastRequestId()
                        + ", first packet latency (ms): "
                        + synthesizer.getFirstPackageDelay());
    }

    public static void main(String[] args) throws NoApiKeyException {
        // The following configuration is for the Singapore region. Replace "{WorkspaceId}" with your actual workspace ID. The configuration varies by region.
        Constants.baseWebsocketApiUrl = "wss://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/api-ws/v1/inference";
        streamAudioDataToSpeaker();
        System.exit(0);
    }
}

Panggilan bidirectional streaming

Contoh berikut menunjukkan cara menggunakan objek Flowable sebagai parameter input untuk streaming teks, dan menggunakan antarmuka blockingForEach dari objek Flowable yang dikembalikan untuk mengambil setiap objek SpeechSynthesisResult yang distream secara blocking.

import com.alibaba.dashscope.audio.ttsv2.SpeechSynthesisParam;
import com.alibaba.dashscope.audio.ttsv2.SpeechSynthesizer;
import com.alibaba.dashscope.exception.NoApiKeyException;
import com.alibaba.dashscope.utils.Constants;
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 = {"Streaming text-to-speech SDK, ",
            "can convert input text ", "into audio binary data. ", "Compared to non-streaming speech synthesis, ",
            "streaming synthesis offers better real-time performance. ", "While users input text, ",
            "they can hear nearly synchronous audio output, ", "greatly enhancing the interactive experience ",
            "and reducing user wait time. ", "It is suitable for calling large-scale ", "language models (LLMs) to ",
            "perform speech synthesis ", "with streaming text input."};
    private static String model = "cosyvoice-v3-flash";
    private static String voice = "longanyang";

    public static void streamAudioDataToSpeaker() throws NoApiKeyException {
        // Simulate streaming input
        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);

        // Request parameters
        SpeechSynthesisParam param =
                SpeechSynthesisParam.builder()
                        // The API Keys for the Singapore and Beijing regions are different. Get an API Key: https://www.alibabacloud.com/help/en/model-studio/get-api-key
                        // If the environment variable is not configured, replace the following line with your Model Studio API Key: .apiKey("sk-xxx")
                        .apiKey(System.getenv("DASHSCOPE_API_KEY"))
                        .model(model) // Model
                        .voice(voice) // Voice
                        .build();
        SpeechSynthesizer synthesizer = new SpeechSynthesizer(param, null);
        synthesizer.streamingCallAsFlowable(textSource).blockingForEach(result -> {
            if (result.getAudioFrame() != null) {
                // Implement the logic to play audio here
                System.out.println(
                        TimeUtils.getTimestamp() +
                                " Binary audio size: " + result.getAudioFrame().capacity());
            }
            // Get output information, including event type and original text
            if (result.getOutput() != null && result.getOutput().has("type")) {
                System.out.println("Event type: " + result.getOutput().get("type").getAsString()
                        + ", Original text: " + (result.getOutput().has("original_text") ? result.getOutput().get("original_text").getAsString() : ""));
            }
        });
        synthesizer.getDuplexApi().close(1000, "bye");
        // The first text transmission requires establishing a WebSocket connection, so the first packet latency includes the connection setup time
        System.out.println(
                "[Metric] requestId: "
                        + synthesizer.getLastRequestId()
                        + ", first packet latency (ms): "
                        + synthesizer.getFirstPackageDelay());
    }

    public static void main(String[] args) throws NoApiKeyException {
        // The following configuration is for the Singapore region. Replace "{WorkspaceId}" with your actual workspace ID. The configuration varies by region.
        Constants.baseWebsocketApiUrl = "wss://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/api-ws/v1/inference";
        streamAudioDataToSpeaker();
        System.exit(0);
    }
}

Panggilan konkurensi tinggi

DashScope Java SDK menggunakan pooling koneksi OkHttp3 untuk mengurangi overhead pembentukan koneksi berulang. Untuk informasi lebih lanjut, lihat Praktik terbaik konkurensi tinggi.