Java SDK

更新时间:
复制 MD 格式

This topic describes how to use the Java software development kit (SDK) for Alibaba Cloud Voice Service. It includes installation instructions and code examples.

Usage notes

  • Before you use the SDK, read the API reference. For more information, see API reference.

  • To use the long text-to-speech service, you must update the SDK to version 2.1.1 or later.

Download and installation

  1. Download the latest SDK version from the Maven server.

    The dependency files are as follows:

    <dependency>
        <groupId>com.alibaba.nls</groupId>
        <artifactId>nls-sdk-tts</artifactId>
        <version>2.2.14</version>
    </dependency>
    <dependency>
        <groupId>com.alibaba.nls</groupId>
        <artifactId>nls-sdk-common</artifactId>
        <version>2.2.14</version>
    </dependency>
    Important

    Starting from Java SDK version 2.1.7, the unit of the timeout period for the waitForComplete interface is changed from seconds to milliseconds.

    Unzip the ZIP file and run mvn package in the pom directory. An executable JAR file named nls-example-long-tts-2.0.0-jar-with-dependencies.jar is generated in the target directory. You can copy this JAR file to the destination server for quick verification and stress testing.

  2. Verify the service.

    Run the following code and provide the required parameters as prompted. After the command runs, the logs/nls.log file is generated in the directory where you run the command.

     java -cp nls-example-long-tts-2.0.0-jar-with-dependencies.jar com.alibaba.nls.client.SpeechSynthesizerDemo
  3. Perform stress testing.

    Run the following code and provide the required parameters as prompted. The Alibaba Cloud service URL is wss://nls-gateway-cn-shanghai.aliyuncs.com/ws/v1 . Select the number of concurrent connections based on your purchase.

    java -jar nls-example-long-tts-2.0.0-jar-with-dependencies.jar

    Important

    If you perform stress testing with more than two concurrent connections, you will incur fees.

Key interfaces

  • NlsClient: The client for voice processing. You can use this client to perform tasks such as short sentence recognition, real-time speech recognition, and speech synthesis. This client is thread-safe. Create only one global instance.

  • SpeechSynthesizer: The class for speech synthesis. It is used to set request parameters and send requests. This class is not thread-safe.

  • SpeechSynthesizerListener: The listener class for speech synthesis. It listens for returned results. This class is not thread-safe. You must implement the following two abstract methods:

      /**
       * Receives binary data for speech synthesis.
       */
      abstract public void onMessage(ByteBuffer message);
      /**
       * Notifies when the speech synthesis is complete.
       */
      abstract public void onComplete(SpeechSynthesizerResponse response);

Important

Notes on SDK calls:

  • NlsClient uses the Netty framework. Creating an NlsClient object is time-consuming and resource-intensive. After an object is created, it can be reused. Align the creation and shutdown of the NlsClient object with the lifecycle of your program.

  • SpeechSynthesizer objects cannot be reused. Each speech synthesis task corresponds to one SpeechSynthesizer object. For example, to perform N speech synthesis tasks for N texts, you must create N SpeechSynthesizer objects.

  • SpeechSynthesizerListener objects and SpeechSynthesizer objects have a one-to-one relationship. Do not assign one SpeechSynthesizerListener object to multiple SpeechSynthesizer objects. Otherwise, you cannot distinguish between the speech synthesis tasks.

  • The Java SDK depends on the Netty network library. If your application also depends on Netty, you must update Netty to version 4.1.17.Final or later.

Code example

Note

  • The example uses the default public endpoint of the speech synthesis service that is built into the SDK. If you use an Alibaba Cloud ECS instance in the China (Shanghai) region and need to access the service over an internal network, set the internal endpoint when you create the NlsClient object:

    client = new NlsClient("ws://nls-gateway-cn-shanghai-internal.aliyuncs.com/ws/v1", accessToken);
  • The example saves the synthesized audio to a file. If you have high requirements for real-time performance, use streaming playback. Play the audio data as you receive it to reduce latency.

package com.alibaba.nls.client;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import com.alibaba.nls.client.protocol.NlsClient;
import com.alibaba.nls.client.protocol.OutputFormatEnum;
import com.alibaba.nls.client.protocol.SampleRateEnum;
import com.alibaba.nls.client.protocol.tts.SpeechSynthesizer;
import com.alibaba.nls.client.protocol.tts.SpeechSynthesizerListener;
import com.alibaba.nls.client.protocol.tts.SpeechSynthesizerResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
 * This demo shows:
 *      How to call the long text-to-speech API (setLongText).
 *      Streaming text-to-speech (TTS) synthesis.
 *      How to calculate the first-packet latency.
 *
 * Note: This demo is different from SpeechSynthesizerLongTextDemo in nls-example-tts. Long text-to-speech is a separate feature where a long string of text is sent directly to the server for synthesis.
 * In contrast, SpeechSynthesizerLongTextDemo shows how to split a long text on the client side and then call the speech synthesis API for each segment.
 */
public class SpeechLongSynthesizerDemo {
    private static final Logger logger = LoggerFactory.getLogger(SpeechLongSynthesizerDemo.class);
    private static long startTime;
    private String appKey;
    NlsClient client;
    public SpeechLongSynthesizerDemo(String appKey, String token, String url) {
        this.appKey = appKey;
        // Create only one global NlsClient instance. Its lifecycle can be the same as that of the application. The default endpoint is the online service endpoint of Alibaba Cloud.
        if(url.isEmpty()) {
            client = new NlsClient(token);
        } else {
            client = new NlsClient(url, token);
        }
    }
    private static SpeechSynthesizerListener getSynthesizerListener() {
        SpeechSynthesizerListener listener = null;
        try {
            listener = new SpeechSynthesizerListener() {
                File f=new File("ttsForLongText.wav");
                FileOutputStream fout = new FileOutputStream(f);
                private boolean firstRecvBinary = true;
                // Speech synthesis is complete.
                @Override
                public void onComplete(SpeechSynthesizerResponse response) {
                    // When onComplete is called, it indicates that all TTS data has been received. This is the latency for the entire synthesis process. This latency may be long and may not be suitable for real-time scenarios.
                    System.out.println("name: " + response.getName() + ", status: " + response.getStatus()+", output file :"+f.getAbsolutePath());
                }
                // Binary voice data from speech synthesis.
                @Override
                public void onMessage(ByteBuffer message) {
                    try {
                        if(firstRecvBinary) {
                            // Calculate the first-packet latency of the audio stream here. You can start playing the audio as soon as the first packet is received. This improves the response speed, especially in real-time interactive scenarios.
                            firstRecvBinary = false;
                            long now = System.currentTimeMillis();
                            logger.info("tts first latency : " + (now - SpeechLongSynthesizerDemo.startTime) + " ms");
                        }
                        byte[] bytesArray = new byte[message.remaining()];
                        message.get(bytesArray, 0, bytesArray.length);
                        //System.out.println("write array:" + bytesArray.length);
                        fout.write(bytesArray);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                @Override
                public void onFail(SpeechSynthesizerResponse response){
                    // The task_id is the unique identifier for the communication between the client and the server. If you encounter a problem, provide this task_id for troubleshooting.
                    System.out.println(
                        "task_id: " + response.getTaskId() +
                            // Status code
                            ", status: " + response.getStatus() +
                            // Error message
                            ", status_text: " + response.getStatusText());
                }
            };
        } catch (Exception e) {
            e.printStackTrace();
        }
        return listener;
    }
    public void process(String text) {
        SpeechSynthesizer synthesizer = null;
        try {
            // Create an instance and establish a connection.
            synthesizer = new SpeechSynthesizer(client, getSynthesizerListener());
            synthesizer.setAppKey(appKey);
            // Set the encoding format of the returned audio.
            synthesizer.setFormat(OutputFormatEnum.WAV);
            // Set the sample rate of the returned audio.
            synthesizer.setSampleRate(SampleRateEnum.SAMPLE_RATE_16K);
            // The voice. Note that the Java SDK does not support ultra-high definition voices such as "zhiqi". To use these voices, call the RESTful API.
            synthesizer.setVoice("siyue");
            // The pitch. The range is -500 to 500. This parameter is optional. The default value is 0.
            synthesizer.setPitchRate(0);
            // The speech rate. The range is -500 to 500. The default value is 0.
            synthesizer.setSpeechRate(0);
            // Set the text for speech synthesis.
            // The setLongText interface is called here. The original speech synthesis interface is setText.
            synthesizer.setLongText(text);
            // This method serializes the preceding parameters into a JSON string, sends it to the server, and waits for the server to respond.
            long start = System.currentTimeMillis();
            synthesizer.start();
            logger.info("tts start latency " + (System.currentTimeMillis() - start) + " ms");
            SpeechLongSynthesizerDemo.startTime = System.currentTimeMillis();
            // Wait for the speech synthesis to complete.
            synthesizer.waitForComplete();
            logger.info("tts stop latency " + (System.currentTimeMillis() - start) + " ms");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // Close the connection.
            if (null != synthesizer) {
                synthesizer.close();
            }
        }
    }
    public void shutdown() {
        client.shutdown();
    }
    public static void main(String[] args) throws Exception {
        String appKey = "";
        String token = "your_token";
        // Use the default URL.
        String url = "wss://nls-gateway-cn-shanghai.aliyuncs.com/ws/v1";
        if (args.length == 2) {
            appKey   = args[0];
            token    = args[1];
        } else if (args.length == 3) {
            appKey   = args[0];
            token    = args[1];
            url      = args[2];
        } else {
            System.err.println("Run error. Required parameters (URL is optional): " + "<app-key> <token> [url]");
            System.exit(-1);
        }
        String ttsTextLong = "From Baicao Garden to Sanwei Study by Lu Xun \n" +
            "Behind my house was a large garden, known as the Baicao Garden. It has long since been sold, along with the house, to the descendants of Zhu Wengong. It has been seven or eight years since I last saw it. It seems there were only weeds there then, but at that time, it was my paradise.\n" +
            "Needless to say, there were green vegetable plots, smooth stone well railings, tall soapberry trees, and purplish-red mulberries. Nor need I mention the cicadas singing in the leaves, the fat wasps on the vegetable flowers, or the nimble larks suddenly soaring from the grass into the sky.\n" +
            "Just along the base of the short mud wall, there was endless fun. Tree crickets chirped softly, and field crickets played their tunes. Turning over a broken brick, you might sometimes find a centipede. There were also blister beetles. If you pressed its back with your finger, it would let out a puff of smoke from its rear with a pop.\n" +
            "The vines of fleeceflower and manglietia intertwined. The manglietia had fruit like a lotus pod, and the fleeceflower had swollen roots. Some said that the fleeceflower root could be shaped like a human, and eating it would grant immortality. So I often pulled them up, one after another, sometimes damaging the mud wall in the process, but I never saw a root that looked like a person! If you were not afraid of thorns, you could also pick raspberries, which looked like little balls of tiny coral beads. They were sour and sweet, and their color and taste were far better than mulberries...";
        SpeechLongSynthesizerDemo demo = new SpeechLongSynthesizerDemo(appKey, token, url);
        demo.process(ttsTextLong);
        demo.shutdown();
    }
}

FAQ

How can I use SDK logs to analyze latency issues?

Take the Java SDK logs as an example.

  • The latency of short sentence recognition is the time that elapses from when a sentence is finished to when the final recognition result is received.

    Search for the keywords StopRecognition and RecognitionCompleted in the logs to find the log entry for when the voice data has been sent and the log entry for when the short sentence recognition is complete. The time difference is the latency recorded by the SDK. In the following logs, the latency is 984 - 844 = 140 ms.

    14:24:44.844 DEBUG [main] [c.a.n.c.transport.netty4.NettyConnection] thread:1,send:{"header":{"namespace":"SpeechRecognizer","name":"StopRecognition","message_id":"bccac69b505f4e2897d12940e5b38953","appkey":"FWpPCaVYDRp6J1rO","task_id":"8c5c28d9a40c4a229a5345c09bc9c968"}}
    14:24:44.984 DEBUG [ntLoopGroup-2-1] [c.a.n.c.p.asr.SpeechRecognizerListener] on message:{"header":{"namespace":"SpeechRecognizer","name":"RecognitionCompleted","status":20000000,"message_id":"2869e93427b9429190206123b7a3d397","task_id":"8c5c28d9a40c4a229a5345c09bc9c968","status_text":"Gateway:SUCCESS:Success."},"payload":{"result":"The weather in Beijing.","duration":2959}}
  • For speech synthesis, the key metric is first-packet latency. This is the time that elapses from when the synthesis request is sent to when the first audio packet is received.

    Search for the keyword send in the logs to find the log entry for sending the request and the subsequent log entry for receiving an audio packet. The time difference is the first-packet latency recorded by the SDK. In the following logs, the latency is 1035 - 813 = 222 ms.

    14:32:13.813 DEBUG [main] [c.a.n.c.transport.netty4.NettyConnection] thread:1,send:{"payload":{"volume":50,"voice":"Ruoxi","sample_rate":8000,"format":"wav","text":"A country is composed of four elements: territory, people, culture, and government. The term country is also a term in political geography. In a narrow sense, a country is a community formed by a group of people within a certain range."},"context":{"sdk":{"name":"nls-sdk-java","version":"2.1.0"},"network":{"upgrade_cost":160,"connect_cost":212}},"header":{"namespace":"SpeechSynthesizer","name":"StartSynthesis","message_id":"6bf2a84444434c0299974d8242380d6c","appkey":"FWpPCaVYDRp6J1rO","task_id":"affa5c90986e4378907fbf49eddd283a"}}
    14:32:14.035  INFO [ntLoopGroup-2-1] [  c.a.n.c.protocol.tts.SpeechSynthesizer] write array:6896
  • The logs for real-time speech recognition are similar to those for short sentence recognition. You can calculate the end-of-speech latency from the logs. The keywords are StopTranscription and TranscriptionCompleted.

  • When you use RESTful APIs, the client-side logs do not show latency. You must write your own code to measure it or check the server-side logs.

The Java SDK cannot find the com.alibaba JAR package. How do I install the Alibaba Cloud SDK for Java?

For more information about how to install the Alibaba Cloud SDK for Java, see V1.0 Java SDK.

When I call the Alibaba Cloud Java SDK by passing the AccessKey ID and AccessKey secret of my Alibaba Cloud account, the client reports the error "org.json.JSONArray.iterator()Ljava/util/Iterator". How do I resolve this issue?

Confirm that all required dependency packages are present, and add the following two dependency JAR packages.

<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20170516</version>
</dependency>

<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.2</version>
</dependency>