CosyVoice speech synthesis Java SDK
Synthesize speech with CosyVoice using the DashScope Java SDK.
User guide: For model introduction and selection recommendations, see Speech synthesis.
Service endpoints
By default, the SDK connects to the Beijing region endpoint. To use a different region, set Constants.baseWebsocketApiUrl before initializing the SDK.
Singapore
wss://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/api-ws/v1/inference
Replace {WorkspaceId} with your actual workspace ID.
China (Beijing)
wss://{WorkspaceId}.cn-beijing.maas.aliyuncs.com/api-ws/v1/inference
Replace {WorkspaceId} with your actual workspace ID.
Switch to the Singapore region:
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";
Alibaba Cloud Model Studio has released workspace-specific domains for the China (Beijing) and Singapore regions. The new dedicated domains deliver superior performance and higher stability for inference requests. We recommend migrating to the new domains:
China (Beijing): from
dashscope.aliyuncs.comto{WorkspaceId}.cn-beijing.maas.aliyuncs.comSingapore: from
dashscope-intl.aliyuncs.comto{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com
Replace {WorkspaceId} with your actual Workspace ID. The existing domains remain fully functional.
SpeechSynthesizer
Package: com.alibaba.dashscope.audio.ttsv2.SpeechSynthesizer
Constructor
public SpeechSynthesizer(SpeechSynthesisParam param, ResultCallback<SpeechSynthesisResult> callback)
Parameters:
-
param: Speech synthesis parameters, built with SpeechSynthesisParam.builder() -
callback: Callback for streaming calls. Pass null for non-streaming calls.
call() - Non-streaming/unidirectional streaming synthesis
Method signature:
public ByteBuffer call(String text)
Parameters:
|
Parameter |
Type |
Required |
Description |
|
text |
String |
Yes |
Text to synthesize. Maximum length: 20,000 characters. |
Return value: ByteBuffer or null. For non-streaming calls, returns the complete audio data. For unidirectional streaming calls, this method returns null; audio is delivered through the callback.
streamingCall() - Bidirectional streaming synthesis
Method signature:
public void streamingCall(String text)
Parameters:
|
Parameter |
Type |
Required |
Description |
|
text |
String |
Yes |
Text to synthesize. Maximum length: 20,000 characters. You can call this method multiple times to append text. |
streamingComplete() - End bidirectional streaming
Method signature:
public void streamingComplete()
Ends the bidirectional streaming call and notifies the server that all text has been sent.
callAsFlowable() - Unidirectional streaming synthesis (reactive)
Method signature:
public Flowable<SpeechSynthesisResult> callAsFlowable(String text)
Parameters:
|
Parameter |
Type |
Required |
Description |
|
text |
String |
Yes |
Text to synthesize. |
Return value: Flowable<SpeechSynthesisResult> reactive stream.
streamingCallAsFlowable() - Bidirectional streaming synthesis (reactive)
Method signature:
public Flowable<SpeechSynthesisResult> streamingCallAsFlowable(Flowable<String> textStream)
Parameters:
|
Parameter |
Type |
Required |
Description |
|
textStream |
Flowable<String> |
Yes |
Reactive stream of text. |
Return value: Flowable<SpeechSynthesisResult> reactive stream.
getDuplexApi().close() - Close WebSocket connection
Method signature:
public boolean getDuplexApi().close(int code, String reason)
Parameters:
|
Parameter |
Type |
Required |
Description |
|
code |
int |
Yes |
Close code. |
|
reason |
String |
Yes |
Close reason. |
Return value: boolean. Returns true if the connection was closed successfully, false otherwise.
getLastRequestId() - Get request ID
Method signature:
public String getLastRequestId()
Return value: String, the request ID.
getFirstPackageDelay() - Get first-packet latency
Method signature:
public long getFirstPackageDelay()
Return value: long. The first-packet latency in milliseconds, measured from sending the first text segment to receiving the first audio packet.
SpeechSynthesisParam
Package: com.alibaba.dashscope.audio.ttsv2.SpeechSynthesisParam
Example:
SpeechSynthesisParam param = SpeechSynthesisParam.builder()
.model("cosyvoice-v3-flash") // Model
.voice("longanyang") // Voice
.format(SpeechSynthesisAudioFormat.WAV_8000HZ_MONO_16BIT) // Audio encoding format and sample rate
.volume(50) // Volume. Value range: [0, 100]
.speechRate(1.0f) // Speech rate. Value range: [0.5, 2]
.pitchRate(1.0f) // Pitch. Value range: [0.5, 2]
.build();
Builder methods
|
Method |
Parameter type |
Required |
Description |
|
|
String |
Yes |
The model name. |
|
|
String |
Yes |
voice The voice used for speech synthesis.
|
|
|
enum |
No |
Audio encoding format and sample rate. Default: SpeechSynthesisAudioFormat.MP3_22050HZ_MONO_256KBPS. SpeechSynthesisAudioFormat package: |
|
|
int |
No |
The volume level. Default value: 50. Valid values: [0, 100]. |
|
|
float |
No |
The speech rate. Default value: 1.0. Valid values: [0.5, 2.0]. |
|
|
float |
No |
The pitch. Default value: 1.0. Valid values: [0.5, 2.0]. |
|
|
boolean |
No |
Specifies whether to enable word-level timestamps. Default value: false. Available only in streaming output mode. Supported voices: cloned voices of cosyvoice-v3.5-plus, cosyvoice-v3.5-flash, cosyvoice-v3-flash, cosyvoice-v3-plus, and cosyvoice-v2, and system voices marked as supported in CosyVoice Voice list. Cloned voices of other models do not support this feature. |
|
|
int |
No |
A random seed for controlling variation in the synthesis output. When the model version, text, voice, and other parameters are unchanged, using the same seed produces identical results. Default value: 0. Valid values: [0, 65535]. For SDK versions earlier than 2.21.7, set |
|
|
List<String> |
No |
Important
Specifies the target language for speech synthesis to improve output quality. When digit pronunciation, abbreviation expansion, symbol reading, or minority-language synthesis doesn't meet expectations, use this parameter. For example:
Valid values:
|
|
|
String |
No |
Controls synthesis characteristics such as dialect, emotion, or speaking style. For usage details, see Instruction-based control. |
|
|
ParamHotFix |
No |
Configures pronunciation corrections and text replacements applied before synthesis. This feature isn't supported by cosyvoice-v2. Parameters:
Example:
|
|
|
String, Object |
No |
Sets Additional parameters. |
|
|
Map |
No |
Sets Additional parameters. |
Additional parameters
Set through parameter() or parameters().
Example:
SpeechSynthesisParam param = SpeechSynthesisParam.builder()
.model("cosyvoice-v3-flash")
.voice("longanyang")
.parameter("enable_markdown_filter", true)
.build();
|
Parameter |
Type |
Required |
Description |
|
|
integer |
No |
The audio bit rate in kbps. When the audio format is opus, use Default value: 32. Valid values: [6, 510]. |
|
|
boolean |
No |
Specifies whether to embed an AIGC watermark in the generated audio. When set to true, the watermark is embedded in audio files of supported formats (wav/mp3/opus). Default value: false. Only cosyvoice-v3-flash, cosyvoice-v3-plus, and cosyvoice-v2 support this feature. |
|
|
String |
No |
Sets the Default value: Alibaba Cloud UID. Only cosyvoice-v3-flash, cosyvoice-v3-plus, and cosyvoice-v2 support this feature. |
|
|
String |
No |
Sets the Default value: The request ID of the current speech synthesis request. Only cosyvoice-v3-flash, cosyvoice-v3-plus, and cosyvoice-v2 support this feature. |
|
|
boolean |
No |
Important
Only cloned voices of cosyvoice-v3-flash support this feature. Specifies whether to enable Markdown filtering. When enabled, the system automatically strips Markdown markup symbols from the input text before synthesis, preventing them from being read aloud. Default value: false. Valid values:
|
ResultCallback
Package: com.alibaba.dashscope.common.ResultCallback
onEvent() - Receive audio data
Method signature:
public void onEvent(SpeechSynthesisResult result)
Parameters:
|
Parameter |
Type |
Required |
Description |
|
result |
Yes |
Triggered when a synthesis event is received. Contains the audio frame, timestamp information, and output information (event type, original text, etc.). |
onComplete() - Synthesis complete
Method signature:
public void onComplete()
Triggered when speech synthesis completes.
onError() - Error handling
Method signature:
public void onError(Exception e)
Parameters:
|
Parameter |
Type |
Required |
Description |
|
e |
Exception |
Yes |
Triggered when an error occurs. Contains the exception information. |
SpeechSynthesisResult
Package: com.alibaba.dashscope.audio.tts.SpeechSynthesisResult
getAudioFrame() - Get audio data frame
Method signature:
public ByteBuffer getAudioFrame()
Return value: ByteBuffer, the audio data frame.
getTimestamp() - Get timestamp information
Method signature:
public Sentence getTimestamp()
Return value: Sentence, the timestamp information.
getOutput() - Get output information
Method signature:
public JsonObject getOutput()
Return value: com.google.gson.JsonObject, the output information of the synthesis event, containing event type and text content. Requires SDK version >= 2.22.0.
Sentence-level timestamp information (Sentence)
Sentence encapsulates sentence-level timestamp information.
getBeginTime() - Get sentence start time
Method signature:
public int getBeginTime()
Return value: Sentence start time in milliseconds.
getEndTime() - Get sentence end time
Method signature:
public int getEndTime()
Return value: Sentence end time in milliseconds.
getWords() - Get word-level timestamps
Method signature:
public List<Word> getWords()
Return value: A List of Word objects containing word-level timestamp information. May be empty.
Word-level timestamp information (Word)
Word encapsulates word-level timestamp information.
getBeginTime() - Get word start time
Method signature:
public int getBeginTime()
Return value: Word start time in milliseconds.
getEndTime() - Get word end time
Method signature:
public int getEndTime()
Return value: Word end time in milliseconds.
getText() - Get text
Method signature:
public String getText()
Return value: String, the text content.
getPhonemes() - Get phoneme-level timestamps
Method signature:
public List<Phoneme> getPhonemes()
Return value: A List of Phoneme objects containing phoneme-level timestamp information. May be empty.
Phoneme-level timestamp information (Phoneme)
Phoneme encapsulates phoneme-level timestamp information.
getBeginTime() - Get phoneme start time
Method signature:
public int getBeginTime()
Return value: Phoneme start time in milliseconds.
getEndTime() - Get phoneme end time
Method signature:
public int getEndTime()
Return value: Phoneme end time in milliseconds.
getText() - Get text
Method signature:
public String getText()
Return value: String, the text content.
getTone() - Get tone
Method signature:
public int getTone()
Return value: The tone value.
-
In English, 0, 1, and 2 represent unstressed, primary stress, and secondary stress respectively.
-
In Chinese pinyin, 1, 2, 3, 4, and 5 represent the first, second, third, fourth, and neutral tones respectively.
Output information (output)
getOutput() returns a JsonObject that encapsulates synthesis event output information. Retrieve it in the onEvent callback or the Flowable stream. It contains the following fields:
|
Field |
Type |
Description |
|
type |
String |
Event type. Possible values: |
|
original_text |
String |
Original text of the current sentence. Returned in |
|
sentence |
JsonObject |
Sentence information, containing the sentence index ( |
Sample code
The SDK supports the following synthesis modes:
-
Non-streaming: A blocking call that sends the complete text at once and returns the full audio directly. Best suited for short-text speech synthesis.
-
Unidirectional streaming: A non-blocking call that sends the complete text at once and delivers audio data (potentially in chunks) through a callback function. Best suited for short-text scenarios that require low latency.
-
Bidirectional streaming: A non-blocking call that sends text in multiple segments and delivers incrementally synthesized audio through a callback function in real time. Best suited for long-text scenarios that require low latency.
Non-streaming calls
The text length per request must not exceed 20,000 characters.
Reinitialize the SpeechSynthesizer instance before each call to the call method.
import com.alibaba.dashscope.audio.ttsv2.SpeechSynthesisParam;
import com.alibaba.dashscope.audio.ttsv2.SpeechSynthesizer;
import com.alibaba.dashscope.utils.Constants;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
public class Main {
// Model
private static String model = "cosyvoice-v3-flash";
// Voice
private static String voice = "longanyang";
public static void streamAudioDataToSpeaker() {
// Request parameters
SpeechSynthesisParam param =
SpeechSynthesisParam.builder()
// The API Keys for the Singapore and Beijing regions are different. Get an API Key: https://www.alibabacloud.com/help/en/model-studio/get-api-key
// If the environment variable is not configured, replace the following line with your Model Studio API Key: .apiKey("sk-xxx")
.apiKey(System.getenv("DASHSCOPE_API_KEY"))
.model(model) // Model
.voice(voice) // Voice
.build();
// Synchronous mode: disable callback (second parameter is null)
SpeechSynthesizer synthesizer = new SpeechSynthesizer(param, null);
ByteBuffer audio = null;
try {
// Block until audio is returned
audio = synthesizer.call("What's the weather like today?");
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
// Close the WebSocket connection after the task is completed
synthesizer.getDuplexApi().close(1000, "bye");
}
if (audio != null) {
// Save the audio data to a local file "output.mp3"
File file = new File("output.mp3");
// The first text transmission requires establishing a WebSocket connection, so the first packet latency includes the connection setup time
System.out.println(
"[Metric] requestId: "
+ synthesizer.getLastRequestId()
+ ", first packet latency (ms): "
+ synthesizer.getFirstPackageDelay());
try (FileOutputStream fos = new FileOutputStream(file)) {
fos.write(audio.array());
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
public static void main(String[] args) {
// The following configuration is for the Singapore region. Replace "{WorkspaceId}" with your actual workspace ID. The configuration varies by region.
Constants.baseWebsocketApiUrl = "wss://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/api-ws/v1/inference";
streamAudioDataToSpeaker();
System.exit(0);
}
}Unidirectional streaming calls
The text length per request must not exceed 20,000 characters.
Reinitialize the SpeechSynthesizer instance before each call to the call method.
import com.alibaba.dashscope.audio.tts.SpeechSynthesisResult;
import com.alibaba.dashscope.audio.ttsv2.SpeechSynthesisParam;
import com.alibaba.dashscope.audio.ttsv2.SpeechSynthesizer;
import com.alibaba.dashscope.common.ResultCallback;
import com.alibaba.dashscope.utils.Constants;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.CountDownLatch;
class TimeUtils {
private static final DateTimeFormatter formatter =
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
public static String getTimestamp() {
return LocalDateTime.now().format(formatter);
}
}
public class Main {
// Model
private static String model = "cosyvoice-v3-flash";
// Voice
private static String voice = "longanyang";
public static void streamAudioDataToSpeaker() {
CountDownLatch latch = new CountDownLatch(1);
// Implement the ResultCallback interface
ResultCallback<SpeechSynthesisResult> callback = new ResultCallback<SpeechSynthesisResult>() {
@Override
public void onEvent(SpeechSynthesisResult result) {
if (result.getAudioFrame() != null) {
// Implement the logic to save audio data locally here
System.out.println(TimeUtils.getTimestamp() + " Audio received");
}
// Get output information, including event type and original text
if (result.getOutput() != null && result.getOutput().has("type")) {
System.out.println("Event type: " + result.getOutput().get("type").getAsString()
+ ", Original text: " + (result.getOutput().has("original_text") ? result.getOutput().get("original_text").getAsString() : ""));
}
}
@Override
public void onComplete() {
System.out.println(TimeUtils.getTimestamp() + " Complete received, speech synthesis finished");
latch.countDown();
}
@Override
public void onError(Exception e) {
System.out.println("Exception occurred: " + e.toString());
latch.countDown();
}
};
// Request parameters
SpeechSynthesisParam param =
SpeechSynthesisParam.builder()
// The API Keys for the Singapore and Beijing regions are different. Get an API Key: https://www.alibabacloud.com/help/en/model-studio/get-api-key
// If the environment variable is not configured, replace the following line with your Model Studio API Key: .apiKey("sk-xxx")
.apiKey(System.getenv("DASHSCOPE_API_KEY"))
.model(model) // Model
.voice(voice) // Voice
.build();
// Passing "callback" as the second parameter enables asynchronous mode
SpeechSynthesizer synthesizer = new SpeechSynthesizer(param, callback);
// Non-blocking call that returns null immediately (actual results are delivered asynchronously via the callback interface). Binary audio is received in real time through the onEvent method of the callback interface
try {
synthesizer.call("What's the weather like today?");
// Wait for synthesis to complete
latch.await();
// Wait for playback thread to finish playing
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
// Close the WebSocket connection after the task is completed
synthesizer.getDuplexApi().close(1000, "bye");
}
// The first text transmission requires establishing a WebSocket connection, so the first packet latency includes the connection setup time
System.out.println(
"[Metric] requestId: "
+ synthesizer.getLastRequestId()
+ ", first packet latency (ms): "
+ synthesizer.getFirstPackageDelay());
}
public static void main(String[] args) {
// The following configuration is for the Singapore region. Replace "{WorkspaceId}" with your actual workspace ID. The configuration varies by region.
Constants.baseWebsocketApiUrl = "wss://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/api-ws/v1/inference";
streamAudioDataToSpeaker();
System.exit(0);
}
}Bidirectional streaming calls
The text length per individual call must not exceed 20,000 characters, and the cumulative text length across all calls must not exceed 200,000 characters.
-
During streaming input, call
streamingCallmultiple times to submit text segments in order. The server automatically splits received text into sentences:-
Complete sentences are synthesized immediately.
-
Incomplete sentences are buffered until they form a complete sentence.
When
streamingCompleteis called, the server force-synthesizes all received but unprocessed text segments, including incomplete sentences. -
-
The interval between consecutive text segments must not exceed 23 seconds; exceeding this limit triggers a "request timeout after 23 seconds" exception.
If no text is pending, call
streamingCompletepromptly to end the task.ImportantAlways call the
streamingCompletemethod. Otherwise, trailing text segments may not be converted to speech.The server enforces a 23-second timeout that cannot be changed on the client side.
import com.alibaba.dashscope.audio.tts.SpeechSynthesisResult;
import com.alibaba.dashscope.audio.ttsv2.SpeechSynthesisAudioFormat;
import com.alibaba.dashscope.audio.ttsv2.SpeechSynthesisParam;
import com.alibaba.dashscope.audio.ttsv2.SpeechSynthesizer;
import com.alibaba.dashscope.common.ResultCallback;
import com.alibaba.dashscope.utils.Constants;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
class TimeUtils {
private static final DateTimeFormatter formatter =
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
public static String getTimestamp() {
return LocalDateTime.now().format(formatter);
}
}
public class Main {
private static String[] textArray = {"Streaming text-to-speech SDK, ",
"can convert input text ", "into audio binary data. ", "Compared to non-streaming speech synthesis, ",
"streaming synthesis offers better real-time performance. ", "While users input text, ",
"they can hear nearly synchronous audio output, ", "greatly enhancing the interactive experience ",
"and reducing user wait time. ", "It is suitable for calling large-scale ", "language models (LLMs) to ",
"perform speech synthesis ", "with streaming text input."};
private static String model = "cosyvoice-v3-flash"; // Model
private static String voice = "longanyang"; // Voice
public static void streamAudioDataToSpeaker() {
// Configure the callback function
ResultCallback<SpeechSynthesisResult> callback = new ResultCallback<SpeechSynthesisResult>() {
@Override
public void onEvent(SpeechSynthesisResult result) {
// System.out.println("Message received: " + result);
if (result.getAudioFrame() != null) {
// Implement the logic to process audio data here
System.out.println(TimeUtils.getTimestamp() + " Audio received");
}
}
@Override
public void onComplete() {
System.out.println(TimeUtils.getTimestamp() + " Complete received, speech synthesis finished");
}
@Override
public void onError(Exception e) {
System.out.println("Exception occurred: " + e.toString());
}
};
// Request parameters
SpeechSynthesisParam param =
SpeechSynthesisParam.builder()
// The API Keys for the Singapore and Beijing regions are different. Get an API Key: https://www.alibabacloud.com/help/en/model-studio/get-api-key
// If the environment variable is not configured, replace the following line with your Model Studio API Key: .apiKey("sk-xxx")
.apiKey(System.getenv("DASHSCOPE_API_KEY"))
.model(model)
.voice(voice)
.format(SpeechSynthesisAudioFormat
.PCM_22050HZ_MONO_16BIT) // Use PCM or MP3 for streaming synthesis
.build();
SpeechSynthesizer synthesizer = new SpeechSynthesizer(param, callback);
// The call method with Callback will not block the current thread
try {
for (String text : textArray) {
// Send text fragments and receive binary audio in real time through the onEvent method of the callback interface
synthesizer.streamingCall(text);
}
// Wait for streaming speech synthesis to finish
synthesizer.streamingComplete();
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
// Close the WebSocket connection after the task is completed
synthesizer.getDuplexApi().close(1000, "bye");
}
// The first text transmission requires establishing a WebSocket connection, so the first packet latency includes the connection setup time
System.out.println(
"[Metric] requestId: "
+ synthesizer.getLastRequestId()
+ ", first packet latency (ms): "
+ synthesizer.getFirstPackageDelay());
}
public static void main(String[] args) {
// The following configuration is for the Singapore region. Replace "{WorkspaceId}" with your actual workspace ID. The configuration varies by region.
Constants.baseWebsocketApiUrl = "wss://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/api-ws/v1/inference";
streamAudioDataToSpeaker();
System.exit(0);
}
}Flowable-based calls
Flowable is an RxJava type representing a reactive stream that supports backpressure. For more information, see RxJava Flowable documentation.
Before using Flowable, make sure the RxJava library is integrated and you understand the basics of reactive programming.
The text length per individual call must not exceed 20,000 characters, and the cumulative text length across all calls must not exceed 200,000 characters.
Unidirectional streaming calls
The following example shows how to use the blockingForEach interface of a Flowable object to retrieve each streamed SpeechSynthesisResult object in a blocking manner.
import com.alibaba.dashscope.audio.ttsv2.SpeechSynthesisParam;
import com.alibaba.dashscope.audio.ttsv2.SpeechSynthesizer;
import com.alibaba.dashscope.exception.NoApiKeyException;
import com.alibaba.dashscope.utils.Constants;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
class TimeUtils {
private static final DateTimeFormatter formatter =
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
public static String getTimestamp() {
return LocalDateTime.now().format(formatter);
}
}
public class Main {
private static String model = "cosyvoice-v3-flash"; // Model
private static String voice = "longanyang"; // Voice
public static void streamAudioDataToSpeaker() throws NoApiKeyException {
// Request parameters
SpeechSynthesisParam param =
SpeechSynthesisParam.builder()
// The API Keys for the Singapore and Beijing regions are different. Get an API Key: https://www.alibabacloud.com/help/en/model-studio/get-api-key
// If the environment variable is not configured, replace the following line with your Model Studio API Key: .apiKey("sk-xxx")
.apiKey(System.getenv("DASHSCOPE_API_KEY"))
.model(model) // Model
.voice(voice) // Voice
.build();
SpeechSynthesizer synthesizer = new SpeechSynthesizer(param, null);
synthesizer.callAsFlowable("What's the weather like today?").blockingForEach(result -> {
if (result.getAudioFrame() != null) {
// Implement the logic to process audio data here
System.out.println(TimeUtils.getTimestamp() + " Audio received");
}
// Get output information, including event type and original text
if (result.getOutput() != null && result.getOutput().has("type")) {
System.out.println("Event type: " + result.getOutput().get("type").getAsString()
+ ", Original text: " + (result.getOutput().has("original_text") ? result.getOutput().get("original_text").getAsString() : ""));
}
});
// Close the WebSocket connection after the task is completed
synthesizer.getDuplexApi().close(1000, "bye");
// The first text transmission requires establishing a WebSocket connection, so the first packet latency includes the connection setup time
System.out.println(
"[Metric] requestId: "
+ synthesizer.getLastRequestId()
+ ", first packet latency (ms): "
+ synthesizer.getFirstPackageDelay());
}
public static void main(String[] args) throws NoApiKeyException {
// The following configuration is for the Singapore region. Replace "{WorkspaceId}" with your actual workspace ID. The configuration varies by region.
Constants.baseWebsocketApiUrl = "wss://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/api-ws/v1/inference";
streamAudioDataToSpeaker();
System.exit(0);
}
}
Bidirectional streaming calls
The following example shows how to use a Flowable object as an input parameter for text streaming, and use the blockingForEach interface of the returned Flowable object to retrieve each streamed SpeechSynthesisResult object in a blocking manner.
import com.alibaba.dashscope.audio.ttsv2.SpeechSynthesisParam;
import com.alibaba.dashscope.audio.ttsv2.SpeechSynthesizer;
import com.alibaba.dashscope.exception.NoApiKeyException;
import com.alibaba.dashscope.utils.Constants;
import io.reactivex.BackpressureStrategy;
import io.reactivex.Flowable;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
class TimeUtils {
private static final DateTimeFormatter formatter =
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
public static String getTimestamp() {
return LocalDateTime.now().format(formatter);
}
}
public class Main {
private static String[] textArray = {"Streaming text-to-speech SDK, ",
"can convert input text ", "into audio binary data. ", "Compared to non-streaming speech synthesis, ",
"streaming synthesis offers better real-time performance. ", "While users input text, ",
"they can hear nearly synchronous audio output, ", "greatly enhancing the interactive experience ",
"and reducing user wait time. ", "It is suitable for calling large-scale ", "language models (LLMs) to ",
"perform speech synthesis ", "with streaming text input."};
private static String model = "cosyvoice-v3-flash";
private static String voice = "longanyang";
public static void streamAudioDataToSpeaker() throws NoApiKeyException {
// Simulate streaming input
Flowable<String> textSource = Flowable.create(emitter -> {
new Thread(() -> {
for (int i = 0; i < textArray.length; i++) {
emitter.onNext(textArray[i]);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
emitter.onComplete();
}).start();
}, BackpressureStrategy.BUFFER);
// Request parameters
SpeechSynthesisParam param =
SpeechSynthesisParam.builder()
// The API Keys for the Singapore and Beijing regions are different. Get an API Key: https://www.alibabacloud.com/help/en/model-studio/get-api-key
// If the environment variable is not configured, replace the following line with your Model Studio API Key: .apiKey("sk-xxx")
.apiKey(System.getenv("DASHSCOPE_API_KEY"))
.model(model) // Model
.voice(voice) // Voice
.build();
SpeechSynthesizer synthesizer = new SpeechSynthesizer(param, null);
synthesizer.streamingCallAsFlowable(textSource).blockingForEach(result -> {
if (result.getAudioFrame() != null) {
// Implement the logic to play audio here
System.out.println(
TimeUtils.getTimestamp() +
" Binary audio size: " + result.getAudioFrame().capacity());
}
// Get output information, including event type and original text
if (result.getOutput() != null && result.getOutput().has("type")) {
System.out.println("Event type: " + result.getOutput().get("type").getAsString()
+ ", Original text: " + (result.getOutput().has("original_text") ? result.getOutput().get("original_text").getAsString() : ""));
}
});
synthesizer.getDuplexApi().close(1000, "bye");
// The first text transmission requires establishing a WebSocket connection, so the first packet latency includes the connection setup time
System.out.println(
"[Metric] requestId: "
+ synthesizer.getLastRequestId()
+ ", first packet latency (ms): "
+ synthesizer.getFirstPackageDelay());
}
public static void main(String[] args) throws NoApiKeyException {
// The following configuration is for the Singapore region. Replace "{WorkspaceId}" with your actual workspace ID. The configuration varies by region.
Constants.baseWebsocketApiUrl = "wss://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/api-ws/v1/inference";
streamAudioDataToSpeaker();
System.exit(0);
}
}
High-concurrency calls
The DashScope Java SDK uses OkHttp3 connection pooling to reduce the overhead of repeatedly establishing connections. For more information, see High-concurrency best practices.