Skip to main content

Java SDK

このトピックでは、DashScope Java SDK を使用して Qwen-TTS-Realtime シリーズのモデルを呼び出す際の、主要なインターフェースとリクエストパラメーターを説明します。

前提条件

DashScope Java SDK 2.22.7 以降が必要です。

クイックスタート

  • サーバーコミットモード
  • コミットモード
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;

    // リアルタイムPCMオーディオプレーヤー
    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();

        // オーディオフォーマットとオーディオラインを初期化します。
        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);
                            // オーディオデータを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();
        }

        // オーディオチャンクを再生し、再生が完了するまでブロックします。
        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);
            // バッファリングされたオーディオの再生が完了するまで待機します。
            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();

            // 完全なオーディオファイルを保存します。
            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()
                .model("qwen3-tts-flash-realtime")
                // シンガポールリージョン
                .url("wss://dashscope-intl.aliyuncs.com/api-ws/v1/realtime")
                // API キーはシンガポールと中国 (北京) で異なります。https://www.alibabacloud.com/help/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);

        // リアルタイムオーディオプレーヤーのインスタンスを作成します。
        RealtimePcmPlayer audioPlayer = new RealtimePcmPlayer(24000);

        QwenTtsRealtime qwenTtsRealtime = new QwenTtsRealtime(param, new QwenTtsRealtimeCallback() {
            @Override
            public void onOpen() {
                // 接続の確立を処理します。
            }
            @Override
            public void onEvent(JsonObject message) {
                String type = message.get("type").getAsString();
                switch(type) {
                    case "session.created":
                        // セッション作成を処理します。
                        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();
                        // オーディオをリアルタイムで再生します。
                        audioPlayer.write(recvAudioB64);
                        break;
                    case "response.done":
                        // 応答完了を処理します。
                        break;
                    case "session.finished":
                        // セッション終了を処理します。
                        completeLatch.get().countDown();
                    default:
                        break;
                }
            }
            @Override
            public void onClose(int code, String reason) {
                // 接続のクローズを処理します。
            }
        });
        qwenTtsRef.set(qwenTtsRealtime);
        try {
            qwenTtsRealtime.connect();
        } catch (NoApiKeyException e) {
            throw new RuntimeException(e);
        }
        QwenTtsRealtimeConfig config = QwenTtsRealtimeConfig.builder()
                .voice("Cherry")
                .responseFormat(ttsFormat)
                .mode("server_commit")
                .build();
        qwenTtsRealtime.updateSession(config);
        for (String text:textToSynthesize) {
            qwenTtsRealtime.appendText(text);
            Thread.sleep(100);
        }
        qwenTtsRealtime.finish();
        completeLatch.get().await();
        qwenTtsRealtime.close();

        // オーディオ再生が完了するまで待機し、その後プレーヤーをシャットダウンします。
        audioPlayer.waitForComplete();
        audioPlayer.shutdown();
        System.exit(0);
    }
}
その他のサンプルについては、「GitHub リポジトリ」をご参照ください。

リクエストパラメーター

QwenTtsRealtimeParam オブジェクトのメソッドチェーンまたはセッターを使用して以下のリクエストパラメーターを設定し、そのオブジェクトを QwenTtsRealtime コンストラクターに渡します。

パラメーター

タイプ

必須

説明

model

文字列

はい

モデル名 (「サポートされているモデル」をご参照ください)。

url

文字列

はい

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

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

QwenTtsRealtimeConfig オブジェクトのメソッドチェーンまたはセッターを使用して以下のリクエストパラメーターを設定し、そのオブジェクトを updateSession メソッドに渡します。

パラメーター

タイプ

必須

説明

voice

文字列

はい

音声合成に使用する音声です。詳細については、「Qwen-TTS ボイスリスト」をご参照ください。

languageType

文字列

いいえ

合成オーディオの言語です。デフォルト値は Auto です。

  • Auto:テキストの言語が不明な場合や、複数の言語が混在している場合に使用します。モデルはテキスト内の異なる言語セグメントに対して自動的に発音をマッチングしますが、完全な精度は保証できません。

  • 特定の言語:単一言語のテキストに使用します。言語を指定することで合成品質が大幅に向上し、通常は Auto よりも優れた結果が得られます。有効な値は以下のとおりです。

    • Chinese

    • English

    • German

    • Italian

    • Portuguese

    • Spanish

    • Japanese

    • Korean

    • French

    • Russian

mode

文字列

いいえ

インタラクションパターンです。有効な値は以下のとおりです。

  • server_commit (デフォルト):サーバーが自動的に合成タイミングを判断し、レイテンシと品質のバランスを取ります。ほとんどのシナリオでこのパターンを推奨します。

  • commit:クライアントが手動で合成をトリガーします。このパターンは最低のレイテンシを実現しますが、文の整合性を管理する必要があります。

format

文字列

いいえ

モデルからのオーディオ出力フォーマットです。

サポートされるフォーマット:

  • pcm (デフォルト)

  • wav

  • mp3

  • opus

sampleRate

int

いいえ

モデルからのオーディオ出力のサンプルレート (Hz) です。

サポートされるサンプルレート:

  • 8000

  • 16000

  • 24000 (デフォルト)

  • 48000

speechRate

float

いいえ

オーディオの話速です。1.0 が通常速度です。1.0 未満は低速、1.0 より大きい値は高速になります。

デフォルト値:1.0

有効範囲:[0.5, 2.0]

volume

int

いいえ

オーディオのボリュームです。

有効範囲:[0, 100]

pitchRate

float

いいえ

合成オーディオのピッチです。

デフォルト値:1.0

有効範囲:[0.5, 2.0]

bitRate

int

いいえ

ビットレート (kbps) です。ビットレートが高いほどオーディオ品質が向上し、ファイルサイズも大きくなります。このパラメーターは、オーディオフォーマット (response_format) が opus に設定されている場合にのみ使用できます。

デフォルト値:128

有効範囲:[6, 510]

主要なインターフェイス

QwenTtsRealtime クラス

インポート:
import com.alibaba.dashscope.audio.qwen_tts_realtime.QwenTtsRealtime;
メソッドシグネチャサーバー イベント説明
connect
public void connect() throws NoApiKeyException, InterruptedException
session.created
セッションが作成されました
session.updated
セッション設定が更新されました
サーバーへの WebSocket 接続を開きます。
updateSession
public void updateSession(QwenTtsRealtimeConfig config)
session.updated
セッション設定が更新されました
セッション設定を更新します。リクエストパラメーターをご参照ください。接続後、サーバーはセッションのデフォルトの入力および出力設定を返します。デフォルト値をオーバーライドするには、connect() の直後にこのメソッドを呼び出してください。サーバーは、session.update イベントを受信するとパラメーターを検証します。パラメーターが無効な場合、サーバーはエラーを返します。それ以外の場合は、サーバーサイドでセッション設定を更新します。
appendText
public void appendText(String text)
なしテキストセグメントをサーバーサイドの入力バッファーに追加します。バッファーは、コミットされるまでテキストを保持します。
  • server_commit モードでは、サーバーがバッファリングされたテキストをコミットして合成するタイミングを決定します。
  • commit モードでは、クライアントが commit を呼び出して合成をトリガーする必要があります。
clearAppendedText
public void clearAppendedText()
input_text_buffer.cleared
サーバーが受信したテキストがクリアされました
サーバーサイドの入力バッファー内のすべてのテキストをクリアします。
commit
public void commit()
input_text_buffer.committed
テキストがコミットされ、音声合成がトリガーされました
response.output_item.added
応答に新しい出力コンテンツが表示されました
response.content_part.added
アシスタントメッセージアイテムに新しい出力コンテンツが追加されました
response.audio.delta
モデルがオーディオを段階的に生成しました
response.audio.done
オーディオ生成が完了しました
response.content_part.done
アシスタントメッセージのオーディオコンテンツのストリーミングが完了しました
response.output_item.done
アシスタントメッセージの出力アイテム全体のストリーミングが完了しました
response.done
応答が完了しました
以前にサーバーサイドのバッファーに追加されたテキストをコミットし、すべてのテキストを直ちに合成します。バッファーが空の場合はエラーを返します。
  • server_commit モードでは、クライアントはこのメソッドを呼び出す必要はありません。サーバーが自動的にコミットします。
  • commit モードでは、クライアントが commit を呼び出して合成をトリガーする必要があります。
finish
public void finish()
session.finished
セッションが終了しました
現在のタスクを停止します。
close
public void close()
なし接続を閉じます。
getSessionId
public String getSessionId()
なし現在のタスクのセッション ID を返します。
getResponseId
public String getResponseId()
なし最新の応答のレスポンス ID を返します。
getFirstAudioDelay
public long getFirstAudioDelay()
なし最初のオーディオパケットのレイテンシーをミリ秒単位で返します。

コールバックインターフェイス (QwenTtsRealtimeCallback)

メソッドパラメーター戻り値説明
public void onOpen()
なしなしWebSocket 接続が確立された直後に呼び出されます。
public abstract void onEvent(JsonObject message)
message:サーバーサイドの応答イベント。なしサーバーがイベントを送信したときに呼び出されます。API 呼び出しの応答やモデルが生成したオーディオが含まれます。「サーバーサイド イベント」をご参照ください。
public abstract void onClose(int code, String reason)
code:WebSocket 終了ステータスコード。reason:終了理由。なしサーバーが接続を閉じた後に呼び出されます。