Java SDK

更新时间:
复制 MD 格式

This topic explains how to use the Java SDK for Intelligent Speech Interaction short-phrase speech recognition, covering installation and code examples.

Usage notes

  • Before you use the SDK, read the API reference.

  • Starting from version 2.1.0, nls-sdk-short-asr is renamed to nls-sdk-recognizer. When upgrading, remove nls-sdk-short-asr and add the corresponding callback methods as indicated by the compiler prompts.

Download and install

  1. Download the latest SDK from the Maven repository.

    <dependency>
        <groupId>com.alibaba.nls</groupId>
        <artifactId>nls-sdk-recognizer</artifactId>
        <version>2.2.1</version>
    </dependency>

    Unzip the file and run mvn package in the pom directory. This generates an executable JAR file named nls-example-recognizer-2.0.0-jar-with-dependencies.jar in the target directory. Copy this JAR package to your target server to quickly validate the service or run performance tests.

  2. Validate the service.

    Run the following command and provide the required parameters when prompted. A log file named nls.log is generated in the logs directory where the command was executed.

    java -cp nls-example-recognizer-2.0.0-jar-with-dependencies.jar com.alibaba.nls.client.SpeechRecognizerDemo
  3. Run a performance test.

    Run the following command and provide the required parameters when prompted. The Alibaba Cloud service URL is wss://nls-gateway-cn-shanghai.aliyuncs.com/ws/v1 . Use a PCM audio file with a 16 kHz sample rate. Select a concurrency level based on your purchased plan.

    java -jar nls-example-recognizer-2.0.0-jar-with-dependencies.jar
    Important

    Running a test with a concurrency of more than 2 will incur charges.

Key interfaces

  • NlsClient: The voice processing client. Use this client for short-phrase speech recognition, real-time speech recognition, and speech synthesis. This client is thread-safe. We recommend creating only one global instance.

  • SpeechRecognizer: Handles short-phrase speech recognition. Use this class to set request parameters and send audio data. This class is not thread-safe.

  • SpeechRecognizerListener: Listens for recognition results. This class is not thread-safe.

For more information, see the Java API reference.

Important

Notes on using the SDK:

  • Creating an NlsClient object is resource-intensive, but the instance is reusable. We recommend aligning the lifecycle of the NlsClient instance with your application's lifecycle.

  • A SpeechRecognizer object is not reusable. You must create a new SpeechRecognizer object for each recognition task. For example, processing N audio files requires N SpeechRecognizer objects.

  • Do not reuse a SpeechRecognizerListener instance across multiple SpeechRecognizer objects, as this makes it impossible to distinguish between recognition tasks.

  • If your application also uses Netty, ensure its version is 4.1.17.Final or later.

Code example

Note
  • Download nls-sample-16k.wav.

    The audio file in the example uses a 16000 Hz sample rate. For accurate results, go to the console and set the model for the project associated with your AppKey to the General model. If you use a different audio file, select a model that supports its scenario. For more information about model settings, see Manage projects.

  • The example uses the SDK's built-in default public endpoint URL for the short-phrase speech recognition service. If you are using an Alibaba Cloud ECS instance in the China (Shanghai) region and want to use the internal endpoint URL, set the internal URL when you create the NlsClient object:

    client = new NlsClient("ws://nls-gateway-cn-shanghai-internal.aliyuncs.com/ws/v1", accessToken);
  • Before calling the API, you must configure environment variables for your access credentials. For Intelligent Speech Interaction, the environment variable names for the AccessKey ID, AccessKey Secret, and AppKey are ALIYUN_AK_ID, ALIYUN_AK_SECRET, and NLS_APP_KEY, respectively.

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import com.alibaba.nls.client.protocol.InputFormatEnum;
import com.alibaba.nls.client.protocol.NlsClient;
import com.alibaba.nls.client.protocol.SampleRateEnum;
import com.alibaba.nls.client.protocol.asr.SpeechRecognizer;
import com.alibaba.nls.client.protocol.asr.SpeechRecognizerListener;
import com.alibaba.nls.client.protocol.asr.SpeechRecognizerResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
 * This example demonstrates how to:
 *      - Call the API for short-phrase speech recognition.
 *      - Dynamically obtain an access token. For details, see https://help.aliyun.com/document_detail/450514.html
 *      - Simulate sending a real-time stream from a local file.
 *      - Calculate the recognition latency.
 */
public class SpeechRecognizerDemo {
    private static final Logger logger = LoggerFactory.getLogger(SpeechRecognizerDemo.class);
    private String appKey;
    NlsClient client;
    public SpeechRecognizerDemo(String appKey, String id, String secret, String url) {
        this.appKey = appKey;
        // Create a global NlsClient instance. By default, it connects to the public Alibaba Cloud service endpoint.
        // Obtain an access token. In a production environment, make sure to get a new token before it expires.
        AccessToken accessToken = new AccessToken(id, secret);
        try {
            accessToken.apply();
            System.out.println("get token: " + accessToken.getToken() + ", expire time: " + accessToken.getExpireTime());
            if(url.isEmpty()) {
                client = new NlsClient(accessToken.getToken());
            }else {
                client = new NlsClient(url, accessToken.getToken());
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    private static SpeechRecognizerListener getRecognizerListener(int myOrder, String userParam) {
        SpeechRecognizerListener listener = new SpeechRecognizerListener() {
            // This callback is fired when an intermediate recognition result is available.
            // It is triggered only if setEnableIntermediateResult is set to true.
            @Override
            public void onRecognitionResultChanged(SpeechRecognizerResponse response) {
                // getName() gets the event name, getStatus() gets the status code, and getRecognizedText() gets the transcribed text.
                System.out.println("name: " + response.getName() + ", status: " + response.getStatus() + ", result: " + response.getRecognizedText());
            }
            // This callback is fired when the recognition is complete.
            @Override
            public void onRecognitionCompleted(SpeechRecognizerResponse response) {
                // getName() gets the event name, getStatus() gets the status code, and getRecognizedText() gets the transcribed text.
                System.out.println("name: " + response.getName() + ", status: " + response.getStatus() + ", result: " + response.getRecognizedText());
            }
            @Override
            public void onStarted(SpeechRecognizerResponse response) {
                System.out.println("myOrder: " + myOrder + "; myParam: " + userParam + "; task_id: " + response.getTaskId());
            }
            @Override
            public void onFail(SpeechRecognizerResponse response) {
                // The task_id is a unique identifier for the communication between the client and the server. Provide this task_id when reporting issues.
                System.out.println("task_id: " + response.getTaskId() + ", status: " + response.getStatus() + ", status_text: " + response.getStatusText());
            }
        };
        return listener;
    }
    // Calculates the audio duration equivalent to a given binary data size.
    // The sample rate must be 8000 or 16000.
    public static int getSleepDelta(int dataSize, int sampleRate) {
        // Only 16-bit sampling is supported.
        int sampleBytes = 16;
        // Only single-channel audio is supported.
        int soundChannel = 1;
        return (dataSize * 10 * 8000) / (160 * sampleRate);
    }
    public void process(String filepath, int sampleRate) {
        SpeechRecognizer recognizer = null;
        try {
            // Pass a custom user parameter.
            String myParam = "user-param";
            int myOrder = 1234;
            SpeechRecognizerListener listener = getRecognizerListener(myOrder, myParam);
            recognizer = new SpeechRecognizer(client, listener);
            recognizer.setAppKey(appKey);
            // Set the audio encoding format. For OPUS files, set this to InputFormatEnum.OPUS.
            recognizer.setFormat(InputFormatEnum.PCM);
            // Set the audio sample rate.
            if(sampleRate == 16000) {
                recognizer.setSampleRate(SampleRateEnum.SAMPLE_RATE_16K);
            } else if(sampleRate == 8000) {
                recognizer.setSampleRate(SampleRateEnum.SAMPLE_RATE_8K);
            }
            // Set whether to return intermediate recognition results.
            recognizer.setEnableIntermediateResult(true);
            // Set whether to enable voice activity detection (VAD).
   recognizer.addCustomedParam("enable_voice_detection",true);
            // This method serializes the preceding parameters into JSON, sends them to the server, and waits for confirmation.
            long now = System.currentTimeMillis();
            recognizer.start();
            logger.info("ASR start latency : " + (System.currentTimeMillis() - now) + " ms");
            File file = new File(filepath);
            FileInputStream fis = new FileInputStream(file);
            byte[] b = new byte[3200];
            int len;
            while ((len = fis.read(b)) > 0) {
                logger.info("send data pack length: " + len);
                recognizer.send(b, len);
                // This example simulates a real-time audio stream by reading from a local file.
                // A sleep is added because reading from a file is faster than real-time audio capture.
                // No sleep is needed when capturing audio in real time.
                // In getSleepDelta, use 8000 for 8 kHz audio.
                int deltaSleep = getSleepDelta(len, sampleRate);
                Thread.sleep(deltaSleep);
            }
            // Notify the server that audio data transmission is complete and wait for the server to finish processing.
            now = System.currentTimeMillis();
            // Calculate the actual latency. The recognition result is typically returned after the stop() method completes.
            logger.info("ASR wait for complete");
            recognizer.stop();
            logger.info("ASR stop latency : " + (System.currentTimeMillis() - now) + " ms");
            fis.close();
        } catch (Exception e) {
            System.err.println(e.getMessage());
        } finally {
            // Close the connection.
            if (null != recognizer) {
                recognizer.close();
            }
        }
    }
    public void shutdown() {
        client.shutdown();
    }
    public static void main(String[] args) throws Exception {
        String appKey = System.getenv().get("NLS_APP_KEY");
        String id = System.getenv().get("ALIYUN_AK_ID");
        String secret = System.getenv().get("ALIYUN_AK_SECRET");
        String url = System.getenv().getOrDefault("NLS_GATEWAY_URL", "wss://nls-gateway-cn-shanghai.aliyuncs.com/ws/v1");
        SpeechRecognizerDemo demo = new SpeechRecognizerDemo(appKey, id, secret, url);
        // This example uses a local file to simulate sending real-time streaming data.
        demo.process("./nls-sample-16k.wav", 16000);
        //demo.process("./nls-sample.opus", 16000);
        demo.shutdown();
    }
}

FAQ

Using SpeechRecognizer.stop()

  1. Normally, you do not need to call stop() because the SDK calls it automatically. If the service does not receive audio data for 10 seconds, it returns error 41010120. When continuously streaming audio, the server performs recognition uninterruptedly. You can get real-time results by setting the enable_intermediate_result=true parameter.

  2. When a phrase ends, you can also manually call stop() to stop sending data and get the final recognition result.

Uploading audio files

As shown in the sample, the SDK simulates a real-time audio stream by sending data from a local file. To upload an audio file for recognition by using a RESTful API, see Short-phrase recognition Java SDK.

SpeechRecognizerDemo demo = new SpeechRecognizerDemo(appKey, id, secret, url);
// This example uses a local file to simulate sending real-time streaming data.
demo.process("./nls-sample-16k.wav", 16000);
//demo.process("./nls-sample.opus", 16000);
demo.shutdown();

send() method parameters

In Java, the SDK for short-phrase and real-time speech recognition provides three overloaded send() methods:

public void send(InputStream ins);
public void send(InputStream ins, int batchSize, int sleepInterval);
public void send(byte[] data);

When using any of these methods, ensure that audio data is sent to the server continuously and in real time.

The demo simulates a real-time audio stream by sending data from a file. Typically, you send a chunk of audio data every 100 ms or 200 ms (sleepInterval). The chunk size (batchSize) depends on the sample rate. If the sending interval is too long, it can cause high latency and disconnections. If the interval is too short, it consumes excessive server and network resources. We recommend experimenting to find the optimal values for your use case.

In the second method, ins is the simulated audio stream, and you must control the sending rate. For 16 kHz audio, send 3,200 bytes from the ins stream every 100 ms. Example:

public void send(ins, 3200, 100); // 16 kHz audio

In the third method, data is the chunk of data to send in a single call. You must control the interval between loop calls. Example:

recognizer.send(data); // 100 ms of audio data
try {
 Thread.sleep(100);
} catch (InterruptedException e) {
 e.printStackTrace();
}

Latency analysis with logs

The following examples use logs from the Java SDK.

  • For short-phrase speech recognition, latency is the time from when a phrase ends to when the final recognition result is received.

    In the logs, search for the keywords StopRecognition and RecognitionCompleted to find the log entries that mark the end of audio transmission and the completion of recognition, respectively. The time difference between these two entries is the end-to-end latency recorded by the SDK. In the following log, 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":"北京的天气。","duration":2959}}
  • For speech synthesis, the key metric is first-packet latency, which is the time from when the synthesis request is sent to when the first audio packet is received.

    In the logs, search for the keyword send to find the request log entry and the entry for the first received audio packet. The time difference between them is the first-packet latency recorded by the SDK. In the following log, 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":"国家是由领土、人民、文化和政府四个要素组成的,国家也是政治地理学名词。从广义的角度,国家是指拥有共同的语言、文化、血统、领土、政府或者历史等的社会群体。从狭义的角度,国家是一定范围内的人群所形成的共同体形式。"},"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 the real-time speech recognition SDK are similar to those for short-phrase speech recognition. You can calculate the end-of-speech latency from the logs by using the keywords StopTranscription and TranscriptionCompleted.

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

Alibaba Cloud SDK installation

To install the Alibaba Cloud SDK for Java, see V1.0 Java SDK.

org.json.JSONArray.iterator() error

Ensure all required dependencies are included. Add the following two dependencies:

<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>