Skip to main content
Qwen-TTS-Realtime

Java SDK

Antarmuka utama dan parameter permintaan untuk sintesis suara real-time Qwen pada DashScope Java SDK.

Panduan pengguna: Untuk informasi mengenai model dan rekomendasi pemilihan, lihat Sintesis suara real-time – Qwen atau Sintesis suara – Qwen.

Prasyarat

Diperlukan DashScope Java SDK versi 2.22.7 atau lebih baru.

Mulai menggunakan

  • Mode server commit
  • Mode commit
appendText()
import com.alibaba.dashscope.audio.qwen_tts_realtime.*;
import com.alibaba.dashscope.exception.NoApiKeyException;
import com.google.gson.JsonObject;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.SourceDataLine;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.AudioSystem;
import java.io.*;
import java.util.Base64;
import java.util.Queue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicBoolean;

public class Main {
    static String[] textToSynthesize = {
            "Right? I really love this kind of supermarket.",
            "Especially during the Chinese New Year.",
            "Going to the supermarket.",
            "It just makes me feel.",
            "Super, super happy!",
            "I want to buy so many things!"
    };
    public static QwenTtsRealtimeAudioFormat ttsFormat = QwenTtsRealtimeAudioFormat.PCM_24000HZ_MONO_16BIT;

    // Real-time PCM audio player
    public static class RealtimePcmPlayer {
        private int sampleRate;
        private SourceDataLine line;
        private AudioFormat audioFormat;
        private Thread decoderThread;
        private Thread playerThread;
        private AtomicBoolean stopped = new AtomicBoolean(false);
        private Queue<String> b64AudioBuffer = new ConcurrentLinkedQueue<>();
        private Queue<byte[]> RawAudioBuffer = new ConcurrentLinkedQueue<>();
        private ByteArrayOutputStream totalAudioStream = new ByteArrayOutputStream();

        // Initialize the audio format and audio line.
        public RealtimePcmPlayer(int sampleRate) throws LineUnavailableException {
            this.sampleRate = sampleRate;
            this.audioFormat = new AudioFormat(this.sampleRate, 16, 1, true, false);
            DataLine.Info info = new DataLine.Info(SourceDataLine.class, audioFormat);
            line = (SourceDataLine) AudioSystem.getLine(info);
            line.open(audioFormat);
            line.start();
            decoderThread = new Thread(new Runnable() {
                @Override
                public void run() {
                    while (!stopped.get()) {
                        String b64Audio = b64AudioBuffer.poll();
                        if (b64Audio != null) {
                            byte[] rawAudio = Base64.getDecoder().decode(b64Audio);
                            RawAudioBuffer.add(rawAudio);
                            // Write audio data to totalAudioStream.
                            try {
                                totalAudioStream.write(rawAudio);
                            } catch (IOException e) {
                                throw new RuntimeException(e);
                            }
                        } else {
                            try {
                                Thread.sleep(100);
                            } catch (InterruptedException e) {
                                throw new RuntimeException(e);
                            }
                        }
                    }
                }
            });
            playerThread = new Thread(new Runnable() {
                @Override
                public void run() {
                    while (!stopped.get()) {
                        byte[] rawAudio = RawAudioBuffer.poll();
                        if (rawAudio != null) {
                            try {
                                playChunk(rawAudio);
                            } catch (IOException e) {
                                throw new RuntimeException(e);
                            } catch (InterruptedException e) {
                                throw new RuntimeException(e);
                            }
                        } else {
                            try {
                                Thread.sleep(100);
                            } catch (InterruptedException e) {
                                throw new RuntimeException(e);
                            }
                        }
                    }
                }
            });
            decoderThread.start();
            playerThread.start();
        }

        // Play an audio chunk and block until playback completes.
        private void playChunk(byte[] chunk) throws IOException, InterruptedException {
            if (chunk == null || chunk.length == 0) return;

            int bytesWritten = 0;
            while (bytesWritten < chunk.length) {
                bytesWritten += line.write(chunk, bytesWritten, chunk.length - bytesWritten);
            }
            int audioLength = chunk.length / (this.sampleRate*2/1000);
            // Wait for the buffered audio to finish playing.
            Thread.sleep(audioLength - 10);
        }

        public void write(String b64Audio) {
            b64AudioBuffer.add(b64Audio);
        }

        public void cancel() {
            b64AudioBuffer.clear();
            RawAudioBuffer.clear();
        }

        public void waitForComplete() throws InterruptedException {
            while (!b64AudioBuffer.isEmpty() || !RawAudioBuffer.isEmpty()) {
                Thread.sleep(100);
            }
            line.drain();
        }

        public void shutdown() throws InterruptedException, IOException {
            stopped.set(true);
            decoderThread.join();
            playerThread.join();

            // Save the complete audio file.
            File file = new File("TotalAudio_"+ttsFormat.getSampleRate()+"."+ttsFormat.getFormat());
            try (FileOutputStream fos = new FileOutputStream(file)) {
                fos.write(totalAudioStream.toByteArray());
            }

            if (line != null && line.isRunning()) {
                line.drain();
                line.close();
            }
        }
    }

    public static void main(String[] args) throws InterruptedException, LineUnavailableException, IOException {
        QwenTtsRealtimeParam param = QwenTtsRealtimeParam.builder()
                // To use instruction control, replace the model with qwen3-tts-instruct-flash-realtime.
                .model("qwen3-tts-flash-realtime")
                // China (Beijing) region
                .url("wss://dashscope-intl.aliyuncs.com/api-ws/v1/realtime")
                // API keys differ between Singapore and China (Beijing). See https://www.alibabacloud.com/help/en/model-studio/get-api-key.
                .apikey(System.getenv("DASHSCOPE_API_KEY"))
                .build();
        AtomicReference<CountDownLatch> completeLatch = new AtomicReference<>(new CountDownLatch(1));
        final AtomicReference<QwenTtsRealtime> qwenTtsRef = new AtomicReference<>(null);

        // Create a real-time audio player instance.
        RealtimePcmPlayer audioPlayer = new RealtimePcmPlayer(24000);

        QwenTtsRealtime qwenTtsRealtime = new QwenTtsRealtime(param, new QwenTtsRealtimeCallback() {
            @Override
            public void onOpen() {
                // Handle connection establishment.
            }
            @Override
            public void onEvent(JsonObject message) {
                String type = message.get("type").getAsString();
                switch(type) {
                    case "session.created":
                        // Handle session creation.
                        if (message.has("session")) {
                            String eventId = message.get("event_id").getAsString();
                            String sessionId = message.get("session").getAsJsonObject().get("id").getAsString();
                            System.out.println("[onEvent] session.created, session_id: "
                                    + sessionId + ", event_id: " + eventId);
                        }
                        break;
                    case "response.audio.delta":
                        String recvAudioB64 = message.get("delta").getAsString();
                        // Play audio in real time.
                        audioPlayer.write(recvAudioB64);
                        break;
                    case "response.done":
                        // Handle response completion.
                        break;
                    case "session.finished":
                        // Handle session termination.
                        completeLatch.get().countDown();
                    default:
                        break;
                }
            }
            @Override
            public void onClose(int code, String reason) {
                // Handle connection closure.
            }
        });
        qwenTtsRef.set(qwenTtsRealtime);
        try {
            qwenTtsRealtime.connect();
        } catch (NoApiKeyException e) {
            throw new RuntimeException(e);
        }
        QwenTtsRealtimeConfig config = QwenTtsRealtimeConfig.builder()
                .voice("Cherry")
                .responseFormat(ttsFormat)
                .mode("server_commit")
                // To use instruction control, uncomment the following lines and replace the model with qwen3-tts-instruct-flash-realtime.
                // .instructions("")
                // .optimizeInstructions(true)
                .build();
        qwenTtsRealtime.updateSession(config);
        for (String text:textToSynthesize) {
            qwenTtsRealtime.appendText(text);
            Thread.sleep(100);
        }
        qwenTtsRealtime.finish();
        completeLatch.get().await();
        qwenTtsRealtime.close();

        // Wait for audio playback to complete, then shut down the player.
        audioPlayer.waitForComplete();
        audioPlayer.shutdown();
        System.exit(0);
    }
}
Untuk contoh lainnya, lihat repositori GitHub.

Parameter permintaan

Konfigurasikan parameter permintaan berikut menggunakan metode chaining atau setter dari objek QwenTtsRealtimeParam, lalu teruskan objek tersebut ke konstruktor QwenTtsRealtime.

Parameter

Tipe

Wajib

Deskripsi

model

String

Ya

Nama model (lihat Model yang didukung).

url

String

Ya

China (Beijing): wss://dashscope.aliyuncs.com/api-ws/v1/realtime

Singapura: wss://dashscope-intl.aliyuncs.com/api-ws/v1/realtime

Konfigurasikan parameter permintaan berikut menggunakan metode chaining atau setter dari objek QwenTtsRealtimeConfig, lalu teruskan objek tersebut ke metode updateSession.

Parameter

Type

Wajib

Deskripsi

voice

String

Ya

Voice untuk sintesis suara. Untuk informasi selengkapnya, lihat Voice yang didukung.

Voice sistem dan voice kustom didukung:

  • Voice sistem: Hanya tersedia untuk seri model Qwen3-TTS-Instruct-Flash-Realtime, Qwen3-TTS-Flash-Realtime, dan Qwen-TTS-Realtime. Untuk contoh voice, lihat Voice yang didukung.

  • Custom Voice

    • Voice yang dikustomisasi melalui fitur Voice Cloning (Qwen): Hanya tersedia untuk seri model Qwen3-TTS-VC-Realtime.

    • Voice yang dikustomisasi melalui fitur Voice Design (Qwen): Hanya tersedia untuk seri model Qwen3-TTS-VD-Realtime.

languageType

String

Tidak

Menentukan bahasa audio hasil sintesis. Nilai default adalah Auto.

  • Auto: Gunakan nilai ini ketika bahasa teks tidak pasti atau mengandung beberapa bahasa. Model secara otomatis mencocokkan pelafalan untuk segmen bahasa berbeda dalam teks, tetapi tidak dapat menjamin akurasi sempurna.

  • Bahasa tertentu: Gunakan ini untuk teks satu bahasa. Menentukan bahasa secara signifikan meningkatkan kualitas sintesis dan biasanya menghasilkan hasil yang lebih baik daripada Auto. Nilai yang valid meliputi:

    • Chinese

    • English

    • German

    • Italian

    • Portuguese

    • Spanish

    • Japanese

    • Korean

    • French

    • Russian

mode

String

Tidak

Mode interaksi. Nilai yang valid:

  • server_commit (default): Server secara otomatis menentukan kapan harus mensintesis suara, menyeimbangkan latensi dan kualitas. Mode ini direkomendasikan untuk sebagian besar skenario.

  • commit: Klien secara manual memicu sintesis. Mode ini memiliki latensi terendah, tetapi Anda harus mengelola integritas kalimat sendiri.

format

String

Tidak

Format output audio dari model.

Format yang didukung:

  • pcm (default)

  • wav

  • mp3

  • opus

Qwen-TTS-Realtime (lihat Model yang didukung) hanya mendukung pcm.

sampleRate

int

Tidak

Laju sampel output audio dari model, dalam Hz.

Laju sampel yang didukung:

  • 8000

  • 16000

  • 24000 (default)

  • 48000

Qwen-TTS-Realtime (lihat Model yang didukung) hanya mendukung 24000.

speechRate

float

Tidak

Kecepatan bicara audio. Nilai 1.0 adalah kecepatan normal. Nilai kurang dari 1.0 lebih lambat, dan nilai lebih dari 1.0 lebih cepat.

Nilai default: 1.0.

Rentang valid: [0.5, 2.0].

Qwen-TTS-Realtime (lihat Model yang didukung) tidak mendukung parameter ini.

volume

int

Tidak

Volume audio.

Nilai default: 50.

Rentang valid: [0, 100].

Qwen-TTS-Realtime (lihat Model yang didukung) tidak mendukung parameter ini.

pitchRate

float

Tidak

Nada audio hasil sintesis.

Nilai default: 1.0.

Rentang valid: [0.5, 2.0].

Qwen-TTS-Realtime (lihat Model yang didukung) tidak mendukung parameter ini.

bitRate

int

Tidak

Menentukan bitrate audio dalam kbps. Bitrate yang lebih tinggi menghasilkan kualitas audio lebih baik dan ukuran file lebih besar. Parameter ini hanya tersedia ketika format audio (response_format) diatur ke opus.

Nilai default: 128.

Rentang valid: [6, 510].

Qwen-TTS-Realtime (lihat Model yang didukung) tidak mendukung parameter ini.

instructions

String

Tidak

Mengatur instruksi. Untuk informasi selengkapnya, lihat Sintesis suara real-time - Qwen.

Nilai default: Tidak ada. Parameter tidak aktif jika tidak diatur.

Batas panjang: Panjang tidak boleh melebihi 1600 token.

Bahasa yang didukung: Hanya bahasa Mandarin dan Inggris.

Cakupan: Fitur ini hanya tersedia untuk seri model Qwen3-TTS-Instruct-Flash-Realtime.

optimizeInstructions

boolean

Tidak

Menentukan apakah akan mengoptimalkan instructions untuk meningkatkan naturalitas dan ekspresivitas sintesis suara.

Nilai default: false.

Perilaku: Ketika diatur ke true, sistem meningkatkan dan menulis ulang konten instructions untuk menghasilkan instruksi internal yang lebih sesuai untuk sintesis suara.

Skenario: Direkomendasikan untuk skenario yang membutuhkan ekspresi suara berkualitas tinggi dan detail halus.

Ketergantungan: Parameter ini bergantung pada parameter instructions yang telah diatur. Jika instructions kosong, parameter ini tidak berpengaruh.

Cakupan: Fitur ini hanya tersedia untuk seri model Qwen3-TTS-Instruct-Flash-Realtime.

Antarmuka utama

Kelas QwenTtsRealtime

Untuk mengimpor:
import com.alibaba.dashscope.audio.qwen_tts_realtime.QwenTtsRealtime;
MetodeSignatureEvent serverDeskripsi
connect
public void connect() throws NoApiKeyException, InterruptedException
session.created
Sesi dibuat
session.updated
Konfigurasi sesi diperbarui
Membuka koneksi WebSocket ke server.
updateSession
public void updateSession(QwenTtsRealtimeConfig config)
session.updated
Konfigurasi sesi diperbarui
Memperbarui konfigurasi sesi. Lihat Parameter permintaan.Setelah terhubung, server mengembalikan konfigurasi input dan output default untuk sesi. Panggil metode ini segera setelah connect() untuk mengganti nilai default.Server memvalidasi parameter saat menerima event session.update. Jika ada parameter yang tidak valid, server mengembalikan error. Jika tidak, server memperbarui konfigurasi sesi di sisi server.
appendText
public void appendText(String text)
Tidak adaMenambahkan segmen teks ke buffer input sisi server. Buffer menyimpan teks hingga Anda mengirimkannya.
  • Dalam mode server_commit, server menentukan kapan harus melakukan commit dan mensintesis teks yang dibuffer.
  • Dalam mode commit, klien harus memicu sintesis dengan memanggil commit.
clearAppendedText
public void clearAppendedText()
input_text_buffer.cleared
Menghapus teks yang diterima oleh server
Menghapus semua teks dalam buffer input sisi server.
commit
public void commit()
input_text_buffer.committed
Commit teks dan picu sintesis suara
response.output_item.added
Konten output baru muncul dalam respons
response.content_part.added
Konten output baru ditambahkan ke item pesan asisten
response.audio.delta
Model menghasilkan audio secara inkremental
response.audio.done
Generasi audio selesai
response.content_part.done
Streaming konten audio untuk pesan asisten selesai
response.output_item.done
Streaming seluruh item output untuk pesan asisten selesai
response.done
Respons selesai
Commit teks yang sebelumnya ditambahkan ke buffer sisi server dan langsung mensintesis semua teks. Mengembalikan error jika buffer kosong.
  • Dalam mode server_commit, klien tidak perlu memanggil metode ini. Server melakukan commit secara otomatis.
  • Dalam mode commit, klien harus memanggil commit untuk memicu sintesis.
finish
public void finish()
session.finished
Respons selesai
Menghentikan tugas saat ini.
close
public void close()
Tidak adaMenutup koneksi.
getSessionId
public String getSessionId()
Tidak adaMengembalikan ID sesi dari tugas saat ini.
getResponseId
public String getResponseId()
Tidak adaMengembalikan ID respons dari respons terbaru.
getFirstAudioDelay
public long getFirstAudioDelay()
Tidak adaMengembalikan latensi paket audio pertama dalam milidetik.

Antarmuka callback (QwenTtsRealtimeCallback)

MetodeParameterNilai kembaliDeskripsi
public void onOpen()
Tidak adaTidak adaDipanggil segera setelah koneksi WebSocket terbentuk.
public abstract void onEvent(JsonObject message)
message: event respons sisi server.Tidak adaDipanggil ketika server mengirim event, termasuk respons panggilan API dan audio yang dihasilkan model. Lihat Event sisi server.
public abstract void onClose(int code, String reason)
code: kode status penutupan WebSocket.reason: alasan penutupan.Tidak adaDipanggil setelah server menutup koneksi.
Pembuatan Gambar
  • FAQ
Video Generation
Model Dunia
Audio
  • Pembuatan audio
Realtime API
Penyematan Teks
TokenPlan
Model production