Tous les produits
Search
Centre de documentation

Alibaba Cloud Model Studio:Qwen-Audio-TTS/CosyVoice speech synthesis Java SDK

Dernière mise à jour :Sep 07, 2026

Synthétisez de la parole avec Qwen-Audio-TTS/CosyVoice à l'aide du SDK Java DashScope.

Guide d'utilisation : Pour une présentation des modèles et des recommandations de sélection, consultez la rubrique Synthèse vocale.

Points de terminaison du service

Par défaut, le SDK se connecte au point de terminaison de la région de Pékin. Pour utiliser une autre région, définissez Constants.baseWebsocketApiUrl avant d'initialiser le SDK.

Singapore

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

Remplacez {WorkspaceId} par votre ID d'espace de travail réel.

China (Beijing)

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

Remplacez {WorkspaceId} par votre ID d'espace de travail réel.

Basculer vers la région de Singapour :

import com.alibaba.dashscope.utils.Constants;

// Set this before any SDK initialization
Constants.baseWebsocketApiUrl = "wss://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/api-ws/v1/inference";

ImportantAlibaba Cloud Model Studio a publié des domaines spécifiques aux espaces de travail pour les régions Chine (Pékin) et Singapour. Ces nouveaux domaines dédiés offrent de meilleures performances et une stabilité accrue pour les requêtes d'inférence. Nous vous recommandons de migrer vers ces nouveaux domaines :

  • Chine (Pékin) : passez de dashscope.aliyuncs.com à {WorkspaceId}.cn-beijing.maas.aliyuncs.com
  • Singapour : passez de dashscope-intl.aliyuncs.com à {WorkspaceId}.ap-southeast-1.maas.aliyuncs.com

Remplacez {WorkspaceId} par votre ID d'espace de travail réel. Les domaines existants restent entièrement fonctionnels.

SpeechSynthesizer

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

Constructeur

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

Paramètres :

  • param : Paramètres de synthèse vocale, construits avec SpeechSynthesisParam.builder()
  • callback : Rappel pour les appels en streaming. Transmettez la valeur null pour les appels sans streaming.

call() - Synthèse sans streaming ou en streaming unidirectionnel

Signature de la méthode :

public ByteBuffer call(String text)

Paramètres :

Paramètre

Type

Obligatoire

Description

text

String

Oui

Texte à synthétiser. Longueur maximale : 20 000 caractères.

Valeur de retour : ByteBuffer ou null. Pour les appels sans streaming, renvoie les données audio complètes. Pour les appels en streaming unidirectionnel, cette méthode renvoie null ; l'audio est transmis via le rappel.

streamingCall() - Synthèse en streaming bidirectionnel

Signature de la méthode :

public void streamingCall(String text)

Paramètres :

Paramètre

Type

Obligatoire

Description

text

String

Oui

Texte à synthétiser. Longueur maximale : 20 000 caractères. Vous pouvez appeler cette méthode plusieurs fois pour ajouter du texte.

streamingComplete() - Terminer le streaming bidirectionnel

Signature de la méthode :

public void streamingComplete()

Met fin à l'appel en streaming bidirectionnel et notifie au serveur que tout le texte a été envoyé.

streamingCancel() - Annuler le streaming bidirectionnel

Signature de la méthode :

public void streamingCancel()

Description : Annule la tâche de synthèse vocale en streaming bidirectionnel en cours. Après avoir appelé cette méthode, le SDK met immédiatement fin à la tâche actuelle. Vous pouvez démarrer une nouvelle tâche de synthèse sur la même connexion sans réinitialiser l'instance SpeechSynthesizer.

ImportantExigence de version : Cette fonctionnalité nécessite le SDK Java 2.22.26 ou une version ultérieure.

ImportantLimitations du modèle :

  • Chine (Pékin) : Tous les modèles Qwen-Audio-TTS prennent en charge cette fonctionnalité. Les modèles CosyVoice nécessitent la version v2 ou ultérieure.
  • Singapour : Tous les modèles Qwen-Audio-TTS prennent en charge cette fonctionnalité. Les modèles CosyVoice ne prennent pas en charge cette fonctionnalité.

callAsFlowable() - Synthèse en streaming unidirectionnel (réactif)

Signature de la méthode :

public Flowable<SpeechSynthesisResult> callAsFlowable(String text)

Paramètres :

Paramètre

Type

Obligatoire

Description

text

String

Oui

Texte à synthétiser.

Valeur de retour : Flux réactif Flowable<SpeechSynthesisResult>.

streamingCallAsFlowable() - Synthèse en streaming bidirectionnel (réactif)

Signature de la méthode :

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

Paramètres :

Paramètre

Type

Obligatoire

Description

textStream

Flowable<String>

Oui

Flux réactif de texte.

Valeur de retour : Flux réactif Flowable<SpeechSynthesisResult>.

getDuplexApi().close() - Fermer la connexion WebSocket

Signature de la méthode :

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

Paramètres :

Paramètre

Type

Obligatoire

Description

code

int

Oui

Code de fermeture.

reason

String

Oui

Motif de fermeture.

Valeur de retour : boolean. Renvoie true si la connexion a été fermée avec succès, false dans le cas contraire.

getLastRequestId() - Obtenir l'ID de requête

Signature de la méthode :

public String getLastRequestId()

Valeur de retour : String, l'ID de requête.

getFirstPackageDelay() - Obtenir la latence du premier paquet

Signature de la méthode :

public long getFirstPackageDelay()

Valeur de retour : long. La latence du premier paquet en millisecondes, mesurée entre l'envoi du premier segment de texte et la réception du premier paquet audio.

SpeechSynthesisParam

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

Exemple :

SpeechSynthesisParam param = SpeechSynthesisParam.builder()
    .model("qwen-audio-3.0-tts-flash") // Model
    .voice("longanhuan_v3.6") // 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();

Méthodes de construction

MéthodeType de paramètreObligatoireDescription

model(String)

String

Oui

Le nom du modèle.

voice(String)

String

Oui

voicestring(obligatoire)

La voix utilisée pour la synthèse vocale.

  • Voix système : consultez la liste des voix Qwen-Audio-TTS et la liste des voix CosyVoice
  • Voix clonées : voix personnalisées créées par clonage vocal
  • Voix personnalisées : voix personnalisées créées via la conception vocale

format(SpeechSynthesisAudioFormat)

enum

Non

Format d'encodage audio et fréquence d'échantillonnage.

Valeur par défaut : SpeechSynthesisAudioFormat.MP3_22050HZ_MONO_256KBPS.

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

volume(int)

int

Non

Le niveau de volume.

Valeur par défaut : 50.

Plage de valeurs valides : [0, 100].

speechRate(float)

float

Non

La vitesse de parole.

Valeur par défaut : 1,0.

Plage de valeurs valides : [0,5, 2,0].

pitchRate(float)

float

Non

La hauteur tonale.

Valeur par défaut : 1,0.

Plage de valeurs valides : [0,5, 2,0].

enableWordTimestamp(boolean)

boolean

Non

Indique s'il faut activer les horodatages au niveau des mots.

Valeur par défaut : false.

Disponible uniquement en mode de sortie en continu (streaming). Voix prises en charge : voix clonées de qwen-audio-3,0-tts-plus, qwen-audio-3,0-tts-flash, cosyvoice-v3.5-plus, cosyvoice-v3.5-flash, cosyvoice-v3-flash, cosyvoice-v3-plus et cosyvoice-v2, ainsi que les voix système indiquées comme prises en charge dans la liste des voix Qwen-Audio-TTS et la liste des voix CosyVoice. Les voix clonées d'autres modèles ne prennent pas en charge cette fonctionnalité.

seed(int)

int

Non

Une graine aléatoire permettant de contrôler la variation dans le résultat de la synthèse. Lorsque la version du modèle, le texte, la voix et les autres paramètres restent inchangés, l'utilisation de la même graine produit des résultats identiques.

Valeur par défaut : 0.

Plage de valeurs valides : [0, 65535].

Pour les versions du SDK antérieures à la 2.21.7, définissez seed via des paramètres supplémentaires.

languageHints(List<String>)

List<String>

Non

Important

  • Ce paramètre est un tableau, mais la version actuelle ne traite que le premier élément. Transmettez une seule valeur.
  • Ce paramètre spécifie la langue cible pour la synthèse vocale. Il n'est pas lié à la langue de l'échantillon audio utilisé lors du clonage vocal. Pour définir la langue source d'une tâche de clonage, consultez la référence de l'API de clonage vocal.

Spécifie la langue cible de la synthèse vocale afin d'améliorer la qualité du résultat.

Utilisez ce paramètre lorsque la prononciation des chiffres, le développement des abréviations, la lecture des symboles ou la synthèse dans des langues minoritaires ne donnent pas le résultat escompté. Par exemple :

  • Prononciation inattendue des chiffres : « hello, this is 110 » est lu « hello, this is one zero » au lieu de la prononciation chinoise attendue
  • Prononciation imprécise des symboles : « @ » est lu avec son équivalent chinois au lieu de « at »
  • Qualité médiocre de la synthèse dans les langues minoritaires, avec des résultats peu naturels

Valeurs valides :

  • zh : chinois
  • en : anglais
  • fr : français
  • de : allemand
  • ja : japonais
  • ko : coréen
  • ru : russe
  • pt : portugais
  • th : thaï
  • id : indonésien
  • vi : vietnamien
  • es : espagnol
  • it : italien
  • ms : malais
  • fil : philippin
  • ar : arabe

instruction(String)

String

Non

Contrôle les caractéristiques de la synthèse, telles que le dialecte, l'émotion ou le style d'élocution.

Pour plus de détails sur l'utilisation, consultez la section Contrôle par instruction.

hotFix(ParamHotFix)

ParamHotFix

Non

Configure les corrections de prononciation et les remplacements de texte appliqués avant la synthèse.

Cette fonctionnalité n'est pas prise en charge par qwen-audio-3,0-tts-plus, qwen-audio-3,0-tts-flash ni cosyvoice-v2.

Paramètres :

  • pronunciation : Prononciation personnalisée. Spécifie les annotations phonétiques (pinyin) pour les mots afin de corriger les prononciations par défaut incorrectes.
  • replace : Remplacement de texte. Remplace les mots spécifiés par le texte cible avant la synthèse. Le texte remplacé sert d'entrée réelle pour la synthèse.

Exemple :

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("qwen-audio-3,0-tts-flash") // Model
                        .voice("longanhuan_v3.6") // Voice
                        .hotFix(paramHotFix)
                        .build();

parameter(String key, Object value)

String, Object

Non

Définit les paramètres supplémentaires.

parameters(Map<String, Object>)

Map

Non

Définit les paramètres supplémentaires.

Paramètres supplémentaires

Définissez ces paramètres via parameter() ou parameters().

Exemple :

SpeechSynthesisParam param = SpeechSynthesisParam.builder()
  .model("qwen-audio-3.0-tts-flash")
  .voice("longanhuan_v3.6")
  .parameter("enable_markdown_filter", true)
  .build();
ParameterTypeRequiredDescription

bit_rate

integer

No

Débit binaire audio en kbps. Lorsque le format audio est mp3 ou opus, utilisez bit_rate pour ajuster le débit.

Valeur par défaut : 32.

Valeurs valides : [6, 510].

enable_aigc_tag

boolean

No

Indique s'il faut intégrer un filigrane AIGC dans l'audio généré. Lorsqu'elle est définie sur true, cette option intègre le filigrane dans les fichiers audio aux formats pris en charge (wav/mp3/opus).

Valeur par défaut : false.

Seuls qwen-audio-3,0-tts-plus, qwen-audio-3,0-tts-flash, cosyvoice-v3-flash, cosyvoice-v3-plus et cosyvoice-v2 prennent en charge cette fonctionnalité.

aigc_propagator

String

No

Définit le champ ContentPropagator du filigrane AIGC, qui identifie le propagateur de contenu. Ce paramètre n'est effectif que si enable_aigc_tag est défini sur true.

Valeur par défaut : UID Alibaba Cloud.

Seuls qwen-audio-3,0-tts-plus, qwen-audio-3,0-tts-flash, cosyvoice-v3-flash, cosyvoice-v3-plus et cosyvoice-v2 prennent en charge cette fonctionnalité.

aigc_propagate_id

String

No

Définit le champ PropagateID du filigrane AIGC, qui identifie de manière unique une action de propagation spécifique. Ce paramètre n'est effectif que si enable_aigc_tag est défini sur true.

Valeur par défaut : ID de la demande de synthèse vocale actuelle.

Seuls qwen-audio-3,0-tts-plus, qwen-audio-3,0-tts-flash, cosyvoice-v3-flash, cosyvoice-v3-plus et cosyvoice-v2 prennent en charge cette fonctionnalité.

enable_markdown_filter

boolean

No

ImportantSeules les voix clonées de cosyvoice-v3-flash prennent en charge cette fonctionnalité.

Indique s'il faut activer le filtrage Markdown. Lorsque cette option est activée, le système supprime automatiquement les symboles de balisage Markdown du texte d'entrée avant la synthèse, afin d'éviter qu'ils ne soient lus à haute voix.

Valeur par défaut : false.

Valeurs valides :

  • true : active le filtrage Markdown
  • false : désactive le filtrage Markdown

ResultCallback

Package : com.alibaba.dashscope.common.ResultCallback

onEvent() - Réception des données audio

Signature de la méthode :

public void onEvent(SpeechSynthesisResult result)

Paramètres :

Paramètre

Type

Obligatoire

Description

result

SpeechSynthesisResult

Oui

Déclenché à la réception d'un événement de synthèse. Contient la trame audio, les informations d'horodatage et les données de sortie (type d'événement, texte original, etc.).

onComplete() - Fin de la synthèse

Signature de la méthode :

public void onComplete()

Déclenché lorsque la synthèse vocale est terminée.

onError() - Gestion des erreurs

Signature de la méthode :

public void onError(Exception e)

Paramètres :

Paramètre

Type

Obligatoire

Description

e

Exception

Oui

Déclenché en cas d'erreur. Contient les informations relatives à l'exception.

SpeechSynthesisResult

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

getAudioFrame() - Obtention d'une trame audio

Signature de la méthode :

public ByteBuffer getAudioFrame()

Valeur de retour : ByteBuffer, la trame de données audio.

getTimestamp() - Obtention des informations d'horodatage

Signature de la méthode :

public Sentence getTimestamp()

Valeur de retour : Sentence, les informations d'horodatage.

getOutput() - Obtention des informations de sortie

Signature de la méthode :

public JsonObject getOutput()

Valeur de retour : com.google.gson.JsonObject, les informations de sortie de l'événement de synthèse, contenant le type d'événement et le contenu textuel. Nécessite une version du SDK >= 2.22.0.

Informations d'horodatage au niveau de la phrase (Sentence)

Sentence encapsule les informations d'horodatage au niveau de la phrase.

getBeginTime() - Obtention de l'heure de début de la phrase

Signature de la méthode :

public int getBeginTime()

Valeur de retour : Heure de début de la phrase, en millisecondes.

getEndTime() - Obtention de l'heure de fin de la phrase

Signature de la méthode :

public int getEndTime()

Valeur de retour : Heure de fin de la phrase, en millisecondes.

getWords() - Obtention des horodatages au niveau des mots

Signature de la méthode :

public List<Word> getWords()

Valeur de retour : Une List d'objets Word contenant les informations d'horodatage au niveau des mots. Peut être vide.

Informations d'horodatage au niveau du mot (Word)

Word encapsule les informations d'horodatage au niveau du mot.

getBeginTime() - Obtention de l'heure de début du mot

Signature de la méthode :

public int getBeginTime()

Valeur de retour : Heure de début du mot, en millisecondes.

getEndTime() - Obtention de l'heure de fin du mot

Signature de la méthode :

public int getEndTime()

Valeur de retour : Heure de fin du mot, en millisecondes.

getText() - Obtention du texte

Signature de la méthode :

public String getText()

Valeur de retour : String, le contenu textuel.

getPhonemes() - Obtention des horodatages au niveau des phonèmes

Signature de la méthode :

public List<Phoneme> getPhonemes()

Valeur de retour : Une List d'objets Phoneme contenant les informations d'horodatage au niveau des phonèmes. Peut être vide.

Informations d'horodatage au niveau du phonème (Phoneme)

Phoneme encapsule les informations d'horodatage au niveau du phonème.

getBeginTime() - Obtention de l'heure de début du phonème

Signature de la méthode :

public int getBeginTime()

Valeur de retour : Heure de début du phonème, en millisecondes.

getEndTime() - Obtention de l'heure de fin du phonème

Signature de la méthode :

public int getEndTime()

Valeur de retour : Heure de fin du phonème, en millisecondes.

getText() - Obtention du texte

Signature de la méthode :

public String getText()

Valeur de retour : String, le contenu textuel.

getTone() - Obtention du ton

Signature de la méthode :

public int getTone()

Valeur de retour : La valeur du ton.

  • En anglais, 0, 1 et 2 représentent respectivement l'absence d'accentuation, l'accentuation primaire et l'accentuation secondaire.
  • En pinyin chinois, 1, 2, 3, 4 et 5 représentent respectivement les premier, deuxième, troisième, quatrième tons et le ton neutre.

Informations de sortie (output)

getOutput() renvoie un JsonObject qui encapsule les informations de sortie de l'événement de synthèse. Récupérez-le dans le rappel onEvent ou dans le flux Flowable. Il contient les champs suivants :

Champ

Type

Description

type

String

Type d'événement. Valeurs possibles : sentence-begin (début de phrase ; renvoie le texte à synthétiser), sentence-synthesis (synthèse audio en cours ; renvoie un fragment de données audio), sentence-end (fin de phrase ; renvoie le contenu textuel et les horodatages au niveau des mots).

original_text

String

Texte original de la phrase actuelle. Renvoyé dans les événements sentence-begin et sentence-end.

sentence

JsonObject

Informations sur la phrase, contenant l'index de la phrase (index) et les horodatages au niveau des mots (words). L'événement sentence-end inclut les informations complètes d'horodatage au niveau des mots.

Exemples de code

Le SDK prend en charge les modes de synthèse suivants :

  • Non streaming : appel bloquant qui transmet l'intégralité du texte en une seule fois et renvoie directement le fichier audio complet. Cette méthode convient particulièrement à la synthèse vocale de textes courts.
  • Streaming unidirectionnel : appel non bloquant qui transmet l'intégralité du texte en une seule fois et fournit les données audio (potentiellement par blocs) via une fonction de rappel. Plus adapté aux scénarios de textes courts nécessitant une faible latence.
  • Streaming bidirectionnel : appel non bloquant qui envoie le texte en plusieurs segments et délivre l'audio synthétisé de manière incrémentielle via une fonction de rappel en temps réel. Conçu pour les scénarios de textes longs exigeant une faible latence.

Appels non streaming

image

La longueur du texte par requête ne doit pas dépasser 20 000 caractères.

ImportantRéinitialisez l'instance SpeechSynthesizer avant chaque appel à la méthode 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 = "qwen-audio-3.0-tts-flash";
    // Voice
    private static String voice = "longanhuan_v3.6";

    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);
    }
}

Appels en streaming unidirectionnel

image

La longueur du texte par requête ne doit pas dépasser 20 000 caractères.

ImportantRéinitialisez l'instance SpeechSynthesizer avant chaque appel à la méthode 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 = "qwen-audio-3.0-tts-flash";
    // Voice
    private static String voice = "longanhuan_v3.6";

    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);
    }
}

Appels en streaming bidirectionnel

image

La longueur du texte pour chaque appel individuel ne doit pas dépasser 20 000 caractères, et la longueur cumulée du texte sur l'ensemble des appels ne doit pas excéder 200 000 caractères.

  • Pendant l'entrée en streaming, appelez streamingCall plusieurs fois pour soumettre les segments de texte dans l'ordre. Le serveur divise automatiquement le texte reçu en phrases :

    • Les phrases complètes sont synthétisées immédiatement.
    • Les phrases incomplètes sont mises en mémoire tampon jusqu'à ce qu'elles forment une phrase complète.

    Lorsque streamingComplete est appelé, le serveur force la synthèse de tous les segments de texte reçus mais non traités, y compris les phrases incomplètes.

  • L'intervalle entre deux segments de texte consécutifs ne doit pas dépasser 23 secondes ; le dépassement de cette limite déclenche une exception « request timeout after 23 seconds ».

    S'il n'y a aucun texte en attente, appelez streamingComplete rapidement pour terminer la tâche.

    ImportantAppelez toujours la méthode streamingComplete. Sinon, les derniers segments de texte risquent de ne pas être convertis en parole.

    Le serveur applique un délai d'expiration de 23 secondes qui ne peut pas être modifié côté client.

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 = "qwen-audio-3.0-tts-flash"; // Model
    private static String voice = "longanhuan_v3.6"; // 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);
    }
}

Appels basés sur Flowable

Flowable est un type RxJava représentant un flux réactif compatible avec la contre-pression (backpressure). Pour plus d'informations, consultez la documentation RxJava Flowable.

Avant d'utiliser Flowable, assurez-vous que la bibliothèque RxJava est intégrée et que vous maîtrisez les bases de la programmation réactive.

La longueur du texte pour chaque appel individuel ne doit pas dépasser 20 000 caractères, et la longueur cumulative du texte pour l'ensemble des appels ne doit pas excéder 200 000 caractères.

Appels en streaming unidirectionnel

L'exemple suivant illustre l'utilisation de l'interface blockingForEach d'un objet Flowable pour récupérer chaque objet SpeechSynthesisResult diffusé en streaming, de manière bloquante.

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 = "qwen-audio-3.0-tts-flash"; // Model
    private static String voice = "longanhuan_v3.6"; // 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);
    }
}

Appels en streaming bidirectionnel

L'exemple ci-dessous montre comment utiliser un objet Flowable comme paramètre d'entrée pour la diffusion de texte en streaming, puis exploiter l'interface blockingForEach de l'objet Flowable renvoyé afin de récupérer chaque objet SpeechSynthesisResult transmis, de manière bloquante.

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 = "qwen-audio-3.0-tts-flash";
    private static String voice = "longanhuan_v3.6";

    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);
    }
}

Appels à forte concurrence

Le SDK Java DashScope s'appuie sur le pool de connexions OkHttp3 pour réduire la surcharge liée à l'établissement répété de connexions. Pour en savoir plus, reportez-vous aux bonnes pratiques pour les appels à forte concurrence.