すべてのプロダクト
Search
ドキュメントセンター

Alibaba Cloud Model Studio:CosyVoice 音声合成 Java SDK

最終更新日:Jul 03, 2026

DashScope Java SDK を使用して、CosyVoice で音声合成を行います。

ユーザーガイド: モデルの紹介および選択に関する推奨事項については、「音声合成」をご参照ください。

サービスエンドポイント

デフォルトでは、SDK は 中国 (北京) リージョンのエンドポイントに接続します。他のリージョンを使用するには、SDK の初期化前に Constants.baseWebsocketApiUrl を設定してください。

シンガポール

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

{WorkspaceId} は、実際の ワークスペース ID に置き換えてください。

中国 (北京)

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

{WorkspaceId} は、実際の ワークスペース ID に置き換えてください。

シンガポールリージョンへの切り替え:

import com.alibaba.dashscope.utils.Constants;

// SDK 初期化前にこの設定を行ってください
Constants.baseWebsocketApiUrl = "wss://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/api-ws/v1/inference";
重要

Alibaba Cloud Model Studio は、中国 (北京) およびシンガポールリージョン向けにワークスペース専用ドメインをリリースしました。新しい専用ドメインは、推論リクエストに対して優れたパフォーマンスと高い安定性を提供します。以下の新しいドメインへの移行を推奨します。

  • 中国 (北京): dashscope.aliyuncs.com から {WorkspaceId}.cn-beijing.maas.aliyuncs.com

  • シンガポール: dashscope-intl.aliyuncs.com から {WorkspaceId}.ap-southeast-1.maas.aliyuncs.com

{WorkspaceId} は、実際の ワークスペース ID に置き換えてください。既存のドメインは引き続き完全に機能します。

SpeechSynthesizer

パッケージ: com.alibaba.dashscope.audio.ttsv2.SpeechSynthesizer

コンストラクター

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

パラメーター:

  • param: 音声合成パラメーター。SpeechSynthesisParam.builder() で構築します。

  • callback: ストリーミング呼び出し用のコールバック関数です。非ストリーミング呼び出しの場合は null を渡します。

call() - 非ストリーミング / 単方向ストリーミング合成

メソッドシグネチャー:

public ByteBuffer call(String text)

パラメーター:

パラメーター

必須

説明

text

String

はい

合成するテキスト。最大長: 20,000 文字。

戻り値: ByteBuffer または null。非ストリーミング呼び出しの場合、完全なオーディオデータを返します。単方向ストリーミング呼び出しの場合、このメソッドは null を返し、オーディオはコールバックを通じて配信されます。

streamingCall() - 双方向ストリーミング合成

メソッドシグネチャー:

public void streamingCall(String text)

パラメーター:

パラメーター

必須

説明

text

String

はい

合成するテキスト。最大長: 20,000 文字。複数回呼び出してテキストを追加できます。

streamingComplete() - 双方向ストリーミングの終了

メソッドシグネチャー:

public void streamingComplete()

双方向ストリーミング呼び出しを終了し、サーバーにすべてのテキストが送信されたことを通知します。

callAsFlowable() - 単方向ストリーミング合成 (リアクティブ)

メソッドシグネチャー:

public Flowable<SpeechSynthesisResult> callAsFlowable(String text)

パラメーター:

パラメーター

必須

説明

text

String

はい

合成するテキスト。

戻り値: Flowable<SpeechSynthesisResult> リアクティブストリーム。

streamingCallAsFlowable() - 双方向ストリーミング合成 (リアクティブ)

メソッドシグネチャー:

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

パラメーター:

パラメーター

必須

説明

textStream

Flowable<String>

はい

テキストのリアクティブストリーム。

戻り値: Flowable<SpeechSynthesisResult> リアクティブストリーム。

getDuplexApi().close() - WebSocket 接続のクローズ

メソッドシグネチャー:

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

パラメーター:

パラメーター

必須

説明

code

int

はい

コードを閉じる。

reason

String

はい

クローズ理由。

戻り値: boolean。接続が正常にクローズされた場合は true、それ以外の場合は false を返します。

getLastRequestId() - リクエスト ID の取得

メソッドシグネチャー:

public String getLastRequestId()

戻り値: String。リクエスト ID です。

getFirstPackageDelay() - 初期パケット遅延の取得

メソッドシグネチャー:

public long getFirstPackageDelay()

戻り値: long。最初のテキストセグメントを送信してから最初のオーディオパケットを受信するまでの初期パケット遅延(ミリ秒単位)です。

SpeechSynthesisParam

パッケージ: com.alibaba.dashscope.audio.ttsv2.SpeechSynthesisParam

:

SpeechSynthesisParam param = SpeechSynthesisParam.builder()
    .model("cosyvoice-v3-flash") // モデル
    .voice("longanyang") // 音声
    .format(SpeechSynthesisAudioFormat.WAV_8000HZ_MONO_16BIT) // オーディオエンコード形式およびサンプルレート
    .volume(50) // ボリューム。値の範囲: [0, 100]
    .speechRate(1.0f) // 音声速度。値の範囲: [0.5, 2]
    .pitchRate(1.0f) // ピッチ。値の範囲: [0.5, 2]
    .build();

ビルダーメソッド

メソッド

パラメーター型

必須

説明

model(String)

String

はい

モデル名。

voice(String)

String

はい

voice string (必須)

音声合成に使用する音声。

  • システム音声: 「CosyVoice 音声リスト」をご参照ください。

  • クローン音声: 音声クローニングによって作成されたカスタム音声

  • カスタム音声: 音声デザインによって作成されたカスタム音声

format(SpeechSynthesisAudioFormat)

enum

いいえ

オーディオエンコード形式およびサンプルレート。

デフォルト: SpeechSynthesisAudioFormat.MP3_22050HZ_MONO_256KBPS。

SpeechSynthesisAudioFormat パッケージ: com.alibaba.dashscope.audio.ttsv2.SpeechSynthesisAudioFormat

volume(int)

int

いいえ

ボリュームレベル。

デフォルト値: 50。

有効値: [0, 100]。

speechRate(float)

float

いいえ

音声速度。

デフォルト値: 1.0。

有効値: [0.5, 2.0]。

pitchRate(float)

float

いいえ

ピッチ。

デフォルト値: 1.0。

有効値: [0.5, 2.0]。

enableWordTimestamp(boolean)

boolean

いいえ

単語レベルのタイムスタンプを有効にするかどうかを指定します。

デフォルト値: false。

ストリーミング出力モードでのみ利用可能です。サポート対象の音声: cosyvoice-v3.5-plus、cosyvoice-v3.5-flash、cosyvoice-v3-flash、cosyvoice-v3-plus、および cosyvoice-v2 のクローン音声、および「CosyVoice 音声リスト」でサポート済みとしてマークされたシステム音声。その他のモデルのクローン音声はこの機能をサポートしていません。

seed(int)

int

いいえ

合成出力のバリエーションを制御するためのランダムシード。モデルバージョン、テキスト、音声、およびその他のパラメーターが変更されない場合、同じシードを使用すると同一の結果が得られます。

デフォルト値: 0。

有効値: [0, 65535]。

2.21.7 より前の SDK バージョンでは、追加パラメーターを通じて seed を設定します。

languageHints(List<String>)

List<String>

いいえ

重要
  • このパラメーターは配列ですが、現在のバージョンでは最初の要素のみが処理されます。単一の値を渡してください。

  • このパラメーターは、音声合成のターゲット言語を指定します。音声クローニングで使用されるオーディオサンプルの言語とは無関係です。クローニングタスクのソース言語を設定するには、音声クローニング API リファレンスをご参照ください。

音声合成のターゲット言語を指定して、出力品質を向上させます。

数字の発音、略語の展開、記号の読み上げ、または少数言語の合成が期待どおりでない場合に、このパラメーターを使用します。例:

  • 予期しない数字の発音: 「hello, this is 110」が「hello, this is one zero」と読まれるが、中国語での発音が期待されている場合

  • 不正確な記号の発音: 「@」が中国語相当の読みではなく「at」と読まれるべき場合

  • 少数言語の合成品質が低く、不自然な結果になる場合

有効値:

  • zh: 中国語

  • en: 英語

  • fr: フランス語

  • de: ドイツ語

  • ja: 日本語

  • ko: 韓国語

  • ru: ロシア語

  • pt: ポルトガル語

  • th: タイ語

  • id: インドネシア語

  • vi: ベトナム語

instruction(String)

String

いいえ

方言、感情、話し方などの合成特性を制御します。

使用方法の詳細については、「命令による制御」をご参照ください。

hotFix(ParamHotFix)

ParamHotFix

いいえ

合成前に適用される発音修正およびテキスト置換を構成します。

この機能は cosyvoice-v2 ではサポートされていません。

パラメーター:

  • pronunciation: カスタム発音。単語のピンイン注釈を指定して、デフォルトの不正確な発音を修正します。

  • replace: テキスト置換。合成前に指定された単語をターゲットテキストに置き換えます。置き換えられたテキストが実際の合成入力として使用されます。

例:

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") // モデル
                        .voice("your_voice") // cosyvoice-v3-flash のクローン音声に置き換えてください
                        .hotFix(paramHotFix)
                        .build();

parameter(String key, Object value)

String, Object

いいえ

追加パラメーターを設定します。

parameters(Map<String, Object>)

Map

いいえ

追加パラメーターを設定します。

追加パラメーター

parameter() または parameters() を通じて設定します。

:

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

パラメーター

必須

説明

bit_rate

integer

いいえ

オーディオビットレート(kbps 単位)。オーディオ形式が opus の場合、bit_rate を使用してビットレートを調整します。

デフォルト値: 32。

有効値: [6, 510]。

enable_aigc_tag

boolean

いいえ

生成されたオーディオに AIGC ウォーターマークを埋め込むかどうかを指定します。true に設定すると、サポートされている形式(wav/mp3/opus)のオーディオファイルにウォーターマークが埋め込まれます。

デフォルト値: false。

cosyvoice-v3-flash、cosyvoice-v3-plus、および cosyvoice-v2 のみがこの機能をサポートしています。

aigc_propagator

String

いいえ

AIGC ウォーターマーク内の ContentPropagator フィールドを設定し、コンテンツプロパゲーターを識別します。enable_aigc_tagtrue の場合にのみ有効です。

デフォルト値: Alibaba Cloud UID。

cosyvoice-v3-flash、cosyvoice-v3-plus、および cosyvoice-v2 のみがこの機能をサポートしています。

aigc_propagate_id

String

いいえ

AIGC ウォーターマーク内の PropagateID フィールドを設定し、特定のプロパゲーション操作を一意に識別します。enable_aigc_tagtrue の場合にのみ有効です。

デフォルト値: 現在の音声合成リクエストのリクエスト ID。

cosyvoice-v3-flash、cosyvoice-v3-plus、および cosyvoice-v2 のみがこの機能をサポートしています。

enable_markdown_filter

boolean

いいえ

重要

cosyvoice-v3-flash のクローン音声のみがこの機能をサポートしています。

Markdown フィルタリングを有効にするかどうかを指定します。有効にすると、合成前に入力テキストから Markdown マークアップ記号が自動的に削除され、読み上げられることを防ぎます。

デフォルト値: false。

有効値:

  • true: Markdown フィルタリングを有効化

  • false: Markdown フィルタリングを無効化

ResultCallback

パッケージ: com.alibaba.dashscope.common.ResultCallback

onEvent() - オーディオデータの受信

メソッドシグネチャー:

public void onEvent(SpeechSynthesisResult result)

パラメーター:

パラメーター

必須

説明

result

SpeechSynthesisResult

はい

合成イベントを受信したときにトリガーされます。オーディオフレーム、タイムスタンプ情報、出力情報(イベントタイプ、元のテキストなど)を含みます。

onComplete() - 合成完了

メソッドシグネチャー:

public void onComplete()

音声合成が完了したときにトリガーされます。

onError() - エラー処理

メソッドシグネチャー:

public void onError(Exception e)

パラメーター:

パラメーター

必須

説明

e

Exception

はい

エラーが発生したときにトリガーされます。例外情報を含みます。

SpeechSynthesisResult

パッケージ: com.alibaba.dashscope.audio.tts.SpeechSynthesisResult

getAudioFrame() - オーディオデータフレームの取得

メソッドシグネチャー:

public ByteBuffer getAudioFrame()

戻り値: ByteBuffer。オーディオデータフレームです。

getTimestamp() - タイムスタンプ情報の取得

メソッドシグネチャー:

public Sentence getTimestamp()

戻り値: Sentence。タイムスタンプ情報です。

getOutput() - 出力情報の取得

メソッドシグネチャー:

public JsonObject getOutput()

戻り値: com.google.gson.JsonObject。合成イベントの 出力情報 で、イベントタイプおよびテキスト内容を含みます。SDK バージョン >= 2.22.0 が必要です。

文レベルのタイムスタンプ情報 (Sentence)

Sentence は、文レベルのタイムスタンプ情報をカプセル化します。

getBeginTime() - 文の開始時刻の取得

メソッドシグネチャー:

public int getBeginTime()

戻り値: 文の開始時刻(ミリ秒単位)。

getEndTime() - 文の終了時刻の取得

メソッドシグネチャー:

public int getEndTime()

戻り値: 文の終了時刻(ミリ秒単位)。

getWords() - 単語レベルのタイムスタンプの取得

メソッドシグネチャー:

public List<Word> getWords()

戻り値: 単語レベルのタイムスタンプ情報を含む Word オブジェクトの List。空の場合があります。

単語レベルのタイムスタンプ情報 (Word)

Word は、単語レベルのタイムスタンプ情報をカプセル化します。

getBeginTime() - 単語の開始時刻の取得

メソッドシグネチャー:

public int getBeginTime()

戻り値: 単語の開始時刻(ミリ秒単位)。

getEndTime() - 単語の終了時刻の取得

メソッドシグネチャー:

public int getEndTime()

戻り値: 単語の終了時刻(ミリ秒単位)。

getText() - テキストの取得

メソッドシグネチャー:

public String getText()

戻り値: String。テキスト内容です。

getPhonemes() - 音素レベルのタイムスタンプの取得

メソッドシグネチャー:

public List<Phoneme> getPhonemes()

戻り値: 音素レベルのタイムスタンプ情報を含む Phoneme オブジェクトの List。空の場合があります。

音素レベルのタイムスタンプ情報 (Phoneme)

Phoneme は、音素レベルのタイムスタンプ情報をカプセル化します。

getBeginTime() - 音素の開始時刻の取得

メソッドシグネチャー:

public int getBeginTime()

戻り値: 音素の開始時刻(ミリ秒単位)。

getEndTime() - 音素の終了時刻の取得

メソッドシグネチャー:

public int getEndTime()

戻り値: 音素の終了時刻(ミリ秒単位)。

getText() - テキストの取得

メソッドシグネチャー:

public String getText()

戻り値: String。テキスト内容です。

getTone() - トーンの取得

メソッドシグネチャー:

public int getTone()

戻り値: トーン値。

  • 英語では、0、1、2 はそれぞれ非強勢、主強勢、副強勢を表します。

  • 中国語ピンインでは、1、2、3、4、5 はそれぞれ第1声、第2声、第3声、第4声、軽声を表します。

出力情報 (output)

getOutput() は、合成イベントの出力情報をカプセル化する JsonObject を返します。onEvent コールバックまたは Flowable ストリーム内で取得します。次のフィールドを含みます。

フィールド

説明

type

String

イベントタイプ。可能な値: sentence-begin(文の開始。合成するテキストを返す)、sentence-synthesis(オーディオ合成中。オーディオデータチャンクを返す)、sentence-end(文の終了。テキスト内容および単語レベルのタイムスタンプを返す)。

original_text

String

現在の文の元のテキスト。sentence-begin および sentence-end イベントで返されます。

sentence

JsonObject

文情報。文のインデックス(index)および単語レベルのタイムスタンプ(words)を含みます。sentence-end イベントには、完全な単語レベルのタイムスタンプ情報が含まれます。

サンプルコード

SDK は次の合成モードをサポートしています。

  • 非ストリーミング: 完全なテキストを一度に送信し、完全なオーディオを直接返すブロッキング呼び出し。短いテキストの音声合成に最適です。

  • 単方向ストリーミング: 完全なテキストを一度に送信し、コールバック関数を通じてオーディオデータ(チャンクの可能性あり)を配信するノンブロッキング呼び出し。低遅延が求められる短いテキストのシナリオに最適です。

  • 双方向ストリーミング: 複数のセグメントに分けてテキストを送信し、コールバック関数を通じてリアルタイムで増分的に合成されたオーディオを配信するノンブロッキング呼び出し。低遅延が求められる長いテキストのシナリオに最適です。

非ストリーミング呼び出し

1 回のリクエストあたりのテキスト長は 20,000 文字を超えてはなりません。

重要

call メソッドを呼び出す前に、SpeechSynthesizer インスタンスを再初期化してください。

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 {
    // モデル
    private static String model = "cosyvoice-v3-flash";
    // 音声
    private static String voice = "longanyang";

    public static void streamAudioDataToSpeaker() {
        // リクエストパラメーター
        SpeechSynthesisParam param =
                SpeechSynthesisParam.builder()
                        // シンガポールおよび中国 (北京) リージョンの API キーは異なります。API キーの取得: https://www.alibabacloud.com/help/en/model-studio/get-api-key
                        // 環境変数が設定されていない場合は、次の行をご利用の Model Studio API キーに置き換えてください: .apiKey("sk-xxx")
                        .apiKey(System.getenv("DASHSCOPE_API_KEY"))
                        .model(model) // モデル
                        .voice(voice) // 音声
                        .build();

        // 同期モード: コールバックを無効化(第 2 パラメーターは null)
        SpeechSynthesizer synthesizer = new SpeechSynthesizer(param, null);
        ByteBuffer audio = null;
        try {
            // オーディオが返されるまでブロック
            audio = synthesizer.call("What's the weather like today?");
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            // タスク完了後に WebSocket 接続をクローズ
            synthesizer.getDuplexApi().close(1000, "bye");
        }
        if (audio != null) {
            // オーディオデータをローカルファイル "output.mp3" に保存
            File file = new File("output.mp3");
            // 最初のテキスト送信には WebSocket 接続の確立が必要なため、初期パケット遅延には接続設定時間が含まれます
            System.out.println(
                    "[Metric] requestId: "
                            + synthesizer.getLastRequestId()
                            + ", 初期パケット遅延 (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) {
        // 次の構成はシンガポールリージョン用です。"{WorkspaceId}" は実際のワークスペース ID に置き換えてください。リージョンによって構成は異なります。
        Constants.baseWebsocketApiUrl = "wss://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/api-ws/v1/inference";
        streamAudioDataToSpeaker();
        System.exit(0);
    }
}

単方向ストリーミング呼び出し

1 回のリクエストあたりのテキスト長は 20,000 文字を超えてはなりません。

重要

call メソッドを呼び出す前に、SpeechSynthesizer インスタンスを再初期化してください。

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 {
    // モデル
    private static String model = "cosyvoice-v3-flash";
    // 音声
    private static String voice = "longanyang";

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

        // ResultCallback インターフェイスを実装
        ResultCallback<SpeechSynthesisResult> callback = new ResultCallback<SpeechSynthesisResult>() {
            @Override
            public void onEvent(SpeechSynthesisResult result) {
                if (result.getAudioFrame() != null) {
                    // オーディオデータをローカルに保存するロジックをここに実装
                    System.out.println(TimeUtils.getTimestamp() + " オーディオを受信");
                }
                // イベントタイプおよび元のテキストを含む出力情報を取得
                if (result.getOutput() != null && result.getOutput().has("type")) {
                    System.out.println("イベントタイプ: " + result.getOutput().get("type").getAsString()
                            + ", 元のテキスト: " + (result.getOutput().has("original_text") ? result.getOutput().get("original_text").getAsString() : ""));
                }
            }

            @Override
            public void onComplete() {
                System.out.println(TimeUtils.getTimestamp() + " 完了を受信、音声合成が終了しました");
                latch.countDown();
            }

            @Override
            public void onError(Exception e) {
                System.out.println("例外が発生しました: " + e.toString());
                latch.countDown();
            }
        };

        // リクエストパラメーター
        SpeechSynthesisParam param =
                SpeechSynthesisParam.builder()
                        // シンガポールおよび中国 (北京) リージョンの API キーは異なります。API キーの取得: https://www.alibabacloud.com/help/en/model-studio/get-api-key
                        // 環境変数が設定されていない場合は、次の行をご利用の Model Studio API キーに置き換えてください: .apiKey("sk-xxx")
                        .apiKey(System.getenv("DASHSCOPE_API_KEY"))
                        .model(model) // モデル
                        .voice(voice) // 音声
                        .build();
        // 第 2 パラメーターとして "callback" を渡すことで非同期モードを有効化
        SpeechSynthesizer synthesizer = new SpeechSynthesizer(param, callback);
        // ノンブロッキング呼び出しで即座に null を返します(実際の結果はコールバックインターフェイスを介して非同期で配信されます)。バイナリオーディオはコールバックインターフェイスの onEvent メソッドを通じてリアルタイムで受信
        try {
            synthesizer.call("What's the weather like today?");
            // 合成が完了するまで待機
            latch.await();
            // 再生スレッドが再生を終了するのを待機
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            // タスク完了後に WebSocket 接続をクローズ
            synthesizer.getDuplexApi().close(1000, "bye");
        }
        // 最初のテキスト送信には WebSocket 接続の確立が必要なため、初期パケット遅延には接続設定時間が含まれます
        System.out.println(
                "[Metric] requestId: "
                        + synthesizer.getLastRequestId()
                        + ", 初期パケット遅延 (ms): "
                        + synthesizer.getFirstPackageDelay());
    }

    public static void main(String[] args) {
        // 次の構成はシンガポールリージョン用です。"{WorkspaceId}" は実際のワークスペース ID に置き換えてください。リージョンによって構成は異なります。
        Constants.baseWebsocketApiUrl = "wss://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/api-ws/v1/inference";
        streamAudioDataToSpeaker();
        System.exit(0);
    }
}

双方向ストリーミング呼び出し

個別の呼び出しあたりのテキスト長は 20,000 文字を超えてはならず、すべての呼び出しにわたる累積テキスト長は 200,000 文字を超えてはなりません。

  • ストリーミング入力中は、streamingCall を複数回呼び出して、順番にテキストセグメントを送信します。サーバーは受信したテキストを自動的に文に分割します。

    • 完全な文はすぐに合成されます。

    • 不完全な文は、完全な文になるまでバッファリングされます。

    streamingComplete が呼び出されると、サーバーは未処理のすべての受信テキストセグメント(不完全な文を含む)を強制的に合成します。

  • 連続するテキストセグメント間の間隔は 23 秒を超えてはなりません。この制限を超えると、「23 秒後にリクエストがタイムアウトしました」という例外が発生します。

    保留中のテキストがない場合は、streamingComplete を速やかに呼び出してタスクを終了させてください。

    重要

    常に streamingComplete メソッドを呼び出してください。そうしないと、末尾のテキストセグメントが音声に変換されない可能性があります。

    サーバーはクライアント側で変更できない 23 秒のタイムアウトを適用します。
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"; // モデル
    private static String voice = "longanyang"; // 音声

    public static void streamAudioDataToSpeaker() {
        // コールバック関数を構成
        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() + " 完了を受信、音声合成が終了しました");
            }

            @Override
            public void onError(Exception e) {
                System.out.println("例外が発生しました: " + e.toString());
            }
        };

        // リクエストパラメーター
        SpeechSynthesisParam param =
                SpeechSynthesisParam.builder()
                        // シンガポールおよび中国 (北京) リージョンの API キーは異なります。API キーの取得: https://www.alibabacloud.com/help/en/model-studio/get-api-key
                        // 環境変数が設定されていない場合は、次の行をご利用の Model Studio API キーに置き換えてください: .apiKey("sk-xxx")
                        .apiKey(System.getenv("DASHSCOPE_API_KEY"))
                        .model(model)
                        .voice(voice)
                        .format(SpeechSynthesisAudioFormat
                                .PCM_22050HZ_MONO_16BIT) // ストリーミング合成には PCM または MP3 を使用
                        .build();
        SpeechSynthesizer synthesizer = new SpeechSynthesizer(param, callback);
        // コールバック付きの呼び出しメソッドは現在のスレッドをブロックしません
        try {
            for (String text : textArray) {
                // テキストフラグメントを送信し、コールバックインターフェイスの onEvent メソッドを通じてバイナリオーディオをリアルタイムで受信
                synthesizer.streamingCall(text);
            }
            // ストリーミング音声合成が終了するのを待機
            synthesizer.streamingComplete();
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            // タスク完了後に WebSocket 接続をクローズ
            synthesizer.getDuplexApi().close(1000, "bye");
        }

        // 最初のテキスト送信には WebSocket 接続の確立が必要なため、初期パケット遅延には接続設定時間が含まれます
        System.out.println(
                "[Metric] requestId: "
                        + synthesizer.getLastRequestId()
                        + ", 初期パケット遅延 (ms): "
                        + synthesizer.getFirstPackageDelay());
    }

    public static void main(String[] args) {
        // 次の構成はシンガポールリージョン用です。"{WorkspaceId}" は実際のワークスペース ID に置き換えてください。リージョンによって構成は異なります。
        Constants.baseWebsocketApiUrl = "wss://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/api-ws/v1/inference";
        streamAudioDataToSpeaker();
        System.exit(0);
    }
}

Flowable ベースの呼び出し

Flowable はバックプレッシャーをサポートするリアクティブストリームを表す RxJava 型です。詳細については、「RxJava Flowable ドキュメント」をご参照ください。

Flowable を使用する前に、RxJava ライブラリが統合されており、リアクティブプログラミングの基本を理解していることを確認してください。

個別の呼び出しあたりのテキスト長は 20,000 文字を超えてはならず、すべての呼び出しにわたる累積テキスト長は 200,000 文字を超えてはなりません。

単方向ストリーミング呼び出し

次の例は、Flowable オブジェクトの blockingForEach インターフェイスを使用して、ストリーミングされた各 SpeechSynthesisResult オブジェクトをブロッキング方式で取得する方法を示しています。

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"; // モデル
    private static String voice = "longanyang"; // 音声

    public static void streamAudioDataToSpeaker() throws NoApiKeyException {
        // リクエストパラメーター
        SpeechSynthesisParam param =
                SpeechSynthesisParam.builder()
                        // シンガポールおよび中国 (北京) リージョンの API キーは異なります。API キーの取得: https://www.alibabacloud.com/help/en/model-studio/get-api-key
                        // 環境変数が設定されていない場合は、次の行をご利用の Model Studio API キーに置き換えてください: .apiKey("sk-xxx")
                        .apiKey(System.getenv("DASHSCOPE_API_KEY"))
                        .model(model) // モデル
                        .voice(voice) // 音声
                        .build();
        SpeechSynthesizer synthesizer = new SpeechSynthesizer(param, null);
        synthesizer.callAsFlowable("What's the weather like today?").blockingForEach(result -> {
            if (result.getAudioFrame() != null) {
                // オーディオデータを処理するロジックをここに実装
                System.out.println(TimeUtils.getTimestamp() + " オーディオを受信");
            }
            // イベントタイプおよび元のテキストを含む出力情報を取得
            if (result.getOutput() != null && result.getOutput().has("type")) {
                System.out.println("イベントタイプ: " + result.getOutput().get("type").getAsString()
                        + ", 元のテキスト: " + (result.getOutput().has("original_text") ? result.getOutput().get("original_text").getAsString() : ""));
            }
        });
        // タスク完了後に WebSocket 接続をクローズ
        synthesizer.getDuplexApi().close(1000, "bye");
        // 最初のテキスト送信には WebSocket 接続の確立が必要なため、初期パケット遅延には接続設定時間が含まれます
        System.out.println(
                "[Metric] requestId: "
                        + synthesizer.getLastRequestId()
                        + ", 初期パケット遅延 (ms): "
                        + synthesizer.getFirstPackageDelay());
    }

    public static void main(String[] args) throws NoApiKeyException {
        // 次の構成はシンガポールリージョン用です。"{WorkspaceId}" は実際のワークスペース ID に置き換えてください。リージョンによって構成は異なります。
        Constants.baseWebsocketApiUrl = "wss://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/api-ws/v1/inference";
        streamAudioDataToSpeaker();
        System.exit(0);
    }
}

双方向ストリーミング呼び出し

次の例は、テキストストリーミングの入力パラメーターとして Flowable オブジェクトを使用し、返された Flowable オブジェクトの blockingForEach インターフェイスを使用して、ストリーミングされた各 SpeechSynthesisResult オブジェクトをブロッキング方式で取得する方法を示しています。

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 {
        // ストリーミング入力をシミュレート
        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 キーは異なります。API キーの取得: https://www.alibabacloud.com/help/en/model-studio/get-api-key
                        // 環境変数が設定されていない場合は、次の行をご利用の Model Studio API キーに置き換えてください: .apiKey("sk-xxx")
                        .apiKey(System.getenv("DASHSCOPE_API_KEY"))
                        .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());
            }
            // イベントタイプおよび元のテキストを含む出力情報を取得
            if (result.getOutput() != null && result.getOutput().has("type")) {
                System.out.println("イベントタイプ: " + result.getOutput().get("type").getAsString()
                        + ", 元のテキスト: " + (result.getOutput().has("original_text") ? result.getOutput().get("original_text").getAsString() : ""));
            }
        });
        synthesizer.getDuplexApi().close(1000, "bye");
        // 最初のテキスト送信には WebSocket 接続の確立が必要なため、初期パケット遅延には接続設定時間が含まれます
        System.out.println(
                "[Metric] requestId: "
                        + synthesizer.getLastRequestId()
                        + ", 初期パケット遅延 (ms): "
                        + synthesizer.getFirstPackageDelay());
    }

    public static void main(String[] args) throws NoApiKeyException {
        // 次の構成はシンガポールリージョン用です。"{WorkspaceId}" は実際のワークスペース ID に置き換えてください。リージョンによって構成は異なります。
        Constants.baseWebsocketApiUrl = "wss://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/api-ws/v1/inference";
        streamAudioDataToSpeaker();
        System.exit(0);
    }
}

高同時実行呼び出し

DashScope Java SDK は、繰り返し接続を確立するオーバーヘッドを削減するために OkHttp3 コネクションプーリングを使用します。詳細については、「高同時実行のベストプラクティス」をご参照ください。