Qwen-Audio-3.0-ASR-Flash-Streaming/Fun-ASR-Realtime Java SDK provides interfaces for synchronous and streaming speech recognition

更新时间:
复制 MD 格式

This topic describes the parameters and interfaces of the Java SDK for Qwen-Audio-3.0-ASR-Flash-Streaming/Fun-ASR-Realtime real-time speech recognition.

Important

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.com to {WorkspaceId}.cn-beijing.maas.aliyuncs.com

  • Singapore: from dashscope-intl.aliyuncs.com to {WorkspaceId}.ap-southeast-1.maas.aliyuncs.com

Replace {WorkspaceId} with your actual Workspace ID. The existing domains remain fully functional.

User guide: For an introduction to the models and guidance on model selection, see Speech-to-text.

Prerequisites

Quick start

The Recognition class provides interfaces for both synchronous calls and bidirectional streaming calls. Choose the approach that fits your needs:

  • Synchronous call: recognizes a local file and returns the complete result at once. Best for processing pre-recorded audio.

  • Bidirectional streaming call: recognizes an audio stream directly and returns results in real time. The audio stream can come from an external device, such as a microphone, or be read from a local file. Best for scenarios that require immediate feedback.

Synchronous call

Submit a single real-time speech recognition task and get the recognition result synchronously by passing in a local file. The call blocks until the result is returned.

Instantiate The Recognition class, and call the call method to bind Request parameters and the file to recognize. The method performs recognition and returns the final result.

Click to view the full example

import com.alibaba.dashscope.audio.asr.recognition.Recognition;
import com.alibaba.dashscope.audio.asr.recognition.RecognitionParam;
import com.alibaba.dashscope.utils.Constants;

import java.io.File;

public class Main {
    public static void main(String[] args) {
        // The following is the configuration for the China (Beijing) region. When calling, replace "{WorkspaceId}" with your real workspace ID. Configurations differ by region.
        Constants.baseWebsocketApiUrl = "wss://{WorkspaceId}.cn-beijing.maas.aliyuncs.com/api-ws/v1/inference";
        // Create a Recognition instance
        Recognition recognizer = new Recognition();
        // Create RecognitionParam
        RecognitionParam param =
                RecognitionParam.builder()
                        .model("qwen-audio-3.0-asr-flash-streaming")
                        // The API Key differs between the Singapore and Beijing regions. Get an API Key: https://help.aliyun.com/zh/model-studio/get-api-key
                        // If you have not configured the environment variable, replace the following line with your Model Studio API Key: .apiKey("sk-xxx")
                        .apiKey(System.getenv("DASHSCOPE_API_KEY"))
                        .format("wav")
                        .sampleRate(16000)
                        //.parameter("language_hints", new String[]{"zh"})
                        .build();

        try {
            System.out.println("Recognition result: " + recognizer.call(param, new File("{YOUR_AUDIO_FILE}")));
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // Close the WebSocket connection after the task is complete
            recognizer.getDuplexApi().close(1000, "bye");
        }
        System.out.println(
                "[Metric] requestId: "
                        + recognizer.getLastRequestId()
                        + ", first package delay ms: "
                        + recognizer.getFirstPackageDelay()
                        + ", last package delay ms: "
                        + recognizer.getLastPackageDelay());
        System.exit(0);
    }
}

Bidirectional streaming call: callback-based

Submit a single real-time speech recognition task and stream the real-time recognition results by implementing a callback interface.

  1. Start streaming speech recognition

    Instantiate The Recognition class, and call the call method to bind Request parameters and The callback interface (ResultCallback) and start streaming speech recognition.

  2. Stream the audio

    Call the sendAudioFrame method of The Recognition class in a loop to send the binary audio stream to the server in segments. Read the audio from a local file or a device such as a microphone.

    While the audio data is being sent, the server returns recognition results to the client in real time through the onEvent method of The callback interface (ResultCallback).

    Send about 100 ms of audio per frame, keeping each payload between 1 KB and 16 KB.

  3. End the process

    Call the stop method of The Recognition class to end speech recognition.

    This method blocks the current thread until the onComplete or onError callback of The callback interface (ResultCallback) is triggered, at which point the thread is released.

Click to view the full example

Recognize speech from a microphone

import com.alibaba.dashscope.audio.asr.recognition.Recognition;
import com.alibaba.dashscope.audio.asr.recognition.RecognitionParam;
import com.alibaba.dashscope.audio.asr.recognition.RecognitionResult;
import com.alibaba.dashscope.common.ResultCallback;
import com.alibaba.dashscope.utils.Constants;

import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.TargetDataLine;

import java.nio.ByteBuffer;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class Main {
    public static void main(String[] args) throws InterruptedException {
        // The following is the configuration for the China (Beijing) region. When calling, replace "{WorkspaceId}" with your real workspace ID. Configurations differ by region.
        Constants.baseWebsocketApiUrl = "wss://{WorkspaceId}.cn-beijing.maas.aliyuncs.com/api-ws/v1/inference";
        ExecutorService executorService = Executors.newSingleThreadExecutor();
        executorService.submit(new RealtimeRecognitionTask());
        executorService.shutdown();
        executorService.awaitTermination(1, TimeUnit.MINUTES);
        System.exit(0);
    }
}

class RealtimeRecognitionTask implements Runnable {
    @Override
    public void run() {
        RecognitionParam param = RecognitionParam.builder()
                .model("qwen-audio-3.0-asr-flash-streaming")
                // The API Key differs between the Singapore and Beijing regions. Get an API Key: https://help.aliyun.com/zh/model-studio/get-api-key
                // If you have not configured the environment variable, replace the following line with your Model Studio API Key: .apiKey("sk-xxx")
                .apiKey(System.getenv("DASHSCOPE_API_KEY"))
                .format("pcm")
                .sampleRate(16000)
                .build();
        Recognition recognizer = new Recognition();

        ResultCallback<RecognitionResult> callback = new ResultCallback<RecognitionResult>() {
            @Override
            public void onEvent(RecognitionResult result) {
                if (result.isSentenceEnd()) {
                    System.out.println("Final Result: " + result.getSentence().getText());
                } else {
                    System.out.println("Intermediate Result: " + result.getSentence().getText());
                }
            }

            @Override
            public void onComplete() {
                System.out.println("Recognition complete");
            }

            @Override
            public void onError(Exception e) {
                System.out.println("RecognitionCallback error: " + e.getMessage());
            }
        };
        try {
            recognizer.call(param, callback);
            // Create the audio format
            AudioFormat audioFormat = new AudioFormat(16000, 16, 1, true, false);
            // Match the default recording device based on the format
            TargetDataLine targetDataLine =
                    AudioSystem.getTargetDataLine(audioFormat);
            targetDataLine.open(audioFormat);
            // Start recording
            targetDataLine.start();
            ByteBuffer buffer = ByteBuffer.allocate(1024);
            long start = System.currentTimeMillis();
            // Record for 50s and perform real-time transcription
            while (System.currentTimeMillis() - start < 50000) {
                int read = targetDataLine.read(buffer.array(), 0, buffer.capacity());
                if (read > 0) {
                    buffer.limit(read);
                    // Send the recorded audio data to the streaming recognition service
                    recognizer.sendAudioFrame(buffer);
                    buffer = ByteBuffer.allocate(1024);
                    // The recording rate is limited; sleep for a short while to prevent excessive CPU usage
                    Thread.sleep(20);
                }
            }
            recognizer.stop();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // Close the WebSocket connection after the task is complete
            recognizer.getDuplexApi().close(1000, "bye");
        }

        System.out.println(
                "[Metric] requestId: "
                        + recognizer.getLastRequestId()
                        + ", first package delay ms: "
                        + recognizer.getFirstPackageDelay()
                        + ", last package delay ms: "
                        + recognizer.getLastPackageDelay());
    }
}

Recognize a local audio file

import com.alibaba.dashscope.api.GeneralApi;
import com.alibaba.dashscope.audio.asr.recognition.Recognition;
import com.alibaba.dashscope.audio.asr.recognition.RecognitionParam;
import com.alibaba.dashscope.audio.asr.recognition.RecognitionResult;
import com.alibaba.dashscope.base.HalfDuplexParamBase;
import com.alibaba.dashscope.common.GeneralListParam;
import com.alibaba.dashscope.common.ResultCallback;
import com.alibaba.dashscope.protocol.GeneralServiceOption;
import com.alibaba.dashscope.protocol.HttpMethod;
import com.alibaba.dashscope.protocol.Protocol;
import com.alibaba.dashscope.protocol.StreamingMode;
import com.alibaba.dashscope.utils.Constants;

import java.io.FileInputStream;
import java.nio.ByteBuffer;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

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 {
    public static void main(String[] args) throws InterruptedException {
        // The following is the configuration for the China (Beijing) region. When calling, replace "{WorkspaceId}" with your real workspace ID. Configurations differ by region.
        Constants.baseWebsocketApiUrl = "wss://{WorkspaceId}.cn-beijing.maas.aliyuncs.com/api-ws/v1/inference";
        // In real applications, this method only needs to be executed once at the very beginning of the program; there is no need to execute it multiple times.
        warmUp();

        ExecutorService executorService = Executors.newSingleThreadExecutor();
        executorService.submit(new RealtimeRecognitionTask(Paths.get(System.getProperty("user.dir"), "{YOUR_AUDIO_FILE}")));
        executorService.shutdown();

        // wait for all tasks to complete
        executorService.awaitTermination(1, TimeUnit.MINUTES);
        System.exit(0);
    }

    public static void warmUp() {
        try {
            // Lightweight GET request to establish connection
            GeneralServiceOption warmupOption = GeneralServiceOption.builder()
                    .protocol(Protocol.HTTP)
                    .httpMethod(HttpMethod.GET)
                    .streamingMode(StreamingMode.OUT)
                    .path("assistants")
                    .build();

            warmupOption.setBaseHttpUrl(Constants.baseHttpApiUrl);
            GeneralApi<HalfDuplexParamBase> api = new GeneralApi<>();
            api.get(GeneralListParam.builder().limit(1L).build(), warmupOption);
        } catch (Exception e) {
            // Reset flag to allow retry if pre-warming failed
        }
    }
}

class RealtimeRecognitionTask implements Runnable {
    private Path filepath;

    public RealtimeRecognitionTask(Path filepath) {
        this.filepath = filepath;
    }

    @Override
    public void run() {
        RecognitionParam param = RecognitionParam.builder()
                .model("qwen-audio-3.0-asr-flash-streaming")
                // The API Key differs between the Singapore and Beijing regions. Get an API Key: https://help.aliyun.com/zh/model-studio/get-api-key
                // If you have not configured the environment variable, replace the following line with your Model Studio API Key: .apiKey("sk-xxx")
                .apiKey(System.getenv("DASHSCOPE_API_KEY"))
                .format("wav")
                .sampleRate(16000)
                .build();
        Recognition recognizer = new Recognition();

        String threadName = Thread.currentThread().getName();

        ResultCallback<RecognitionResult> callback = new ResultCallback<RecognitionResult>() {
            @Override
            public void onEvent(RecognitionResult message) {
                if (message.isSentenceEnd()) {

                    System.out.println(TimeUtils.getTimestamp()+" "+
                            "[process " + threadName + "] Final Result:" + message.getSentence().getText());
                } else {
                    System.out.println(TimeUtils.getTimestamp()+" "+
                            "[process " + threadName + "] Intermediate Result: " + message.getSentence().getText());
                }
            }

            @Override
            public void onComplete() {
                System.out.println(TimeUtils.getTimestamp()+" "+"[" + threadName + "] Recognition complete");
            }

            @Override
            public void onError(Exception e) {
                System.out.println(TimeUtils.getTimestamp()+" "+
                        "[" + threadName + "] RecognitionCallback error: " + e.getMessage());
            }
        };

        try {
            recognizer.call(param, callback);
            // Please replace the path with your audio file path
            System.out.println(TimeUtils.getTimestamp()+" "+"[" + threadName + "] Input file_path is: " + this.filepath);
            // Read file and send audio by chunks
            FileInputStream fis = new FileInputStream(this.filepath.toFile());
            byte[] allData = new byte[fis.available()];
            int ret = fis.read(allData);
            fis.close();

            int sendFrameLength = 3200;
            for (int i = 0; i * sendFrameLength < allData.length; i ++) {
                int start = i * sendFrameLength;
                int end = Math.min(start + sendFrameLength, allData.length);
                ByteBuffer byteBuffer = ByteBuffer.wrap(allData, start, end - start);
                recognizer.sendAudioFrame(byteBuffer);
                Thread.sleep(100);
            }

            System.out.println(TimeUtils.getTimestamp()+" "+LocalDateTime.now());
            recognizer.stop();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // Close the WebSocket connection after the task is complete
            recognizer.getDuplexApi().close(1000, "bye");
        }

        System.out.println(
                "["
                        + threadName
                        + "][Metric] requestId: "
                        + recognizer.getLastRequestId()
                        + ", first package delay ms: "
                        + recognizer.getFirstPackageDelay()
                        + ", last package delay ms: "
                        + recognizer.getLastPackageDelay());
    }
}

Bidirectional streaming call: Flowable-based

Submit a single real-time speech recognition task and stream the real-time recognition results by implementing a workflow (Flowable).

Flowable is an open-source framework for workflow and business process management, released under the Apache 2.0 license. For how to use Flowable, see Flowable API details.

Click to view the full example

Call the streamCall method of The Recognition class directly to start recognition.

The streamCall method returns a Flowable<RecognitionResult> instance. Use methods of the Flowable instance, such as blockingForEach or subscribe, to process the recognition results. Each result is wrapped in a RecognitionResult.

The streamCall method takes two parameters:

  • RecognitionParam instance (Request parameters): use it to set the model, sample rate, audio format, and other parameters required for speech recognition.

  • Flowable<ByteBuffer> instance: create an instance of type Flowable<ByteBuffer> and implement the audio-stream parsing logic in it.

import com.alibaba.dashscope.audio.asr.recognition.Recognition;
import com.alibaba.dashscope.audio.asr.recognition.RecognitionParam;
import com.alibaba.dashscope.exception.NoApiKeyException;
import com.alibaba.dashscope.utils.Constants;
import io.reactivex.BackpressureStrategy;
import io.reactivex.Flowable;

import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.TargetDataLine;
import java.nio.ByteBuffer;

public class Main {
    public static void main(String[] args) throws NoApiKeyException {
        // The following is the configuration for the China (Beijing) region. When calling, replace "{WorkspaceId}" with your real workspace ID. Configurations differ by region.
        Constants.baseWebsocketApiUrl = "wss://{WorkspaceId}.cn-beijing.maas.aliyuncs.com/api-ws/v1/inference";
        // Create a Flowable<ByteBuffer>
        Flowable<ByteBuffer> audioSource =
                Flowable.create(
                        emitter -> {
                            new Thread(
                                    () -> {
                                        try {
                                            // Create the audio format
                                            AudioFormat audioFormat = new AudioFormat(16000, 16, 1, true, false);
                                            // Match the default recording device based on the format
                                            TargetDataLine targetDataLine =
                                                    AudioSystem.getTargetDataLine(audioFormat);
                                            targetDataLine.open(audioFormat);
                                            // Start recording
                                            targetDataLine.start();
                                            ByteBuffer buffer = ByteBuffer.allocate(1024);
                                            long start = System.currentTimeMillis();
                                            // Record for 50s and perform real-time transcription
                                            while (System.currentTimeMillis() - start < 50000) {
                                                int read = targetDataLine.read(buffer.array(), 0, buffer.capacity());
                                                if (read > 0) {
                                                    buffer.limit(read);
                                                    // Send the recorded audio data to the streaming recognition service
                                                    emitter.onNext(buffer);
                                                    buffer = ByteBuffer.allocate(1024);
                                                    // The recording rate is limited; sleep for a short while to prevent excessive CPU usage
                                                    Thread.sleep(20);
                                                }
                                            }
                                            // Notify that transcription has ended
                                            emitter.onComplete();
                                        } catch (Exception e) {
                                            emitter.onError(e);
                                        }
                                    })
                                    .start();
                        },
                        BackpressureStrategy.BUFFER);

        // Create the Recognizer
        Recognition recognizer = new Recognition();
        // Create RecognitionParam and pass the Flowable<ByteBuffer> created above into the audioFrames parameter
        RecognitionParam param = RecognitionParam.builder()
                .model("qwen-audio-3.0-asr-flash-streaming")
                // The API Key differs between the Singapore and Beijing regions. Get an API Key: https://help.aliyun.com/zh/model-studio/get-api-key
                // If you have not configured the environment variable, replace the following line with your Model Studio API Key: .apiKey("sk-xxx")
                .apiKey(System.getenv("DASHSCOPE_API_KEY"))
                .format("pcm")
                .sampleRate(16000)
                .build();

        // Streaming call interface
        recognizer
                .streamCall(param, audioSource)
                .blockingForEach(
                        result -> {
                            // Subscribe to the output result
                            if (result.isSentenceEnd()) {
                                System.out.println("Final Result: " + result.getSentence().getText());
                            } else {
                                System.out.println("Intermediate Result: " + result.getSentence().getText());
                            }
                        });
        // Close the WebSocket connection after the task is complete
        recognizer.getDuplexApi().close(1000, "bye");
        System.out.println(
                "[Metric] requestId: "
                        + recognizer.getLastRequestId()
                        + ", first package delay ms: "
                        + recognizer.getFirstPackageDelay()
                        + ", last package delay ms: "
                        + recognizer.getLastPackageDelay());
        System.exit(0);
    }
}

High-concurrency calls

The DashScope Java SDK uses the connection pooling of OkHttp3 to reduce the overhead of repeatedly establishing connections. For details, see Optimize Paraformer real-time speech recognition for high concurrency.

Request parameters

Use the chained methods of RecognitionParam to configure the model, sample rate, audio format, and other parameters. Pass the configured parameter object to the call/streamCall method of The Recognition class.

Click to view the example

RecognitionParam param = RecognitionParam.builder()
  .model("qwen-audio-3.0-asr-flash-streaming")
  .format("pcm")
  .sampleRate(16000)
  //.parameter("language_hints", new String[]{"zh"})
  .build();

Parameter

Type

Required

Description

model

String

Yes

The model name. The Qwen-Audio-3.0-ASR-Flash-Streaming and Fun-ASR-Realtime model series are supported. For details, see Supported models and regions.

sampleRate

Integer

Yes

The sample rate, in Hz.

Valid values: 8 kHz models support only 8000 Hz; other models support any sample rate.

format

String

Yes

The audio format.

Valid values:

  • pcm

  • wav

  • mp3

  • opus

  • speex

  • aac

  • amr

Important

opus/speex: Must use Ogg encapsulation.

wav: Must use PCM encoding.

amr: Only the AMR-NB type is supported.

vocabularyId

String

No

The ID of a precompiled hot word list.

Generate this ID in advance by calling the create hot word list API. Pass the ID during recognition to use the hot words in the list.

Suitable for scenarios where the vocabulary is known and relatively stable, and where you need to reuse the same word list across requests.

For usage details, see Precompiled hotwords.

vocabulary

Map<String, Integer>

No

Instant hot words.

Passed as key-value pairs, where the key is the hot word text (string) and the value is the hot word weight (integer). No hot word list needs to be created in advance. The weight ranges from [1, 5] or is set to 50: a value in [1, 5] makes the model more likely to output the word as the value increases; a value of 50 designates a super hot word, which greatly improves recall, but the number of super hot words cannot exceed 50.

Suitable for temporary, session-level hot word optimization.

When configured together with precompiled hot words, only the instant hot words take effect. For usage details, see Instant hotwords.

Important

Only qwen-audio-3.0-asr-flash-streaming supports instant hot words.

Note

Set vocabulary through the parameter method or the parameters method of the RecognitionParam instance:

Set through parameter

Map<String, Integer> vocab = new HashMap<>();
vocab.put("John Smith", 5);
vocab.put("Jane Doe", 5);

RecognitionParam param = RecognitionParam.builder()
        .model("qwen-audio-3.0-asr-flash-streaming")
        .format("pcm")
        .sampleRate(16000)
        .parameter("vocabulary", vocab)
        .build();

Set through parameters

Map<String, Integer> vocab = new HashMap<>();
vocab.put("John Smith", 5);
vocab.put("Jane Doe", 5);

Map<String, Object> parameters = new HashMap<>();
parameters.put("vocabulary", vocab);

RecognitionParam param = RecognitionParam.builder()
        .model("qwen-audio-3.0-asr-flash-streaming")
        .format("pcm")
        .sampleRate(16000)
        .parameters(parameters)
        .build();

semantic_punctuation_enabled

boolean

No

Whether to enable semantic segmentation.

Default value: false.

  • true: Enables semantic segmentation and disables VAD segmentation.

  • false (default): Enables VAD segmentation and disables semantic segmentation.

Semantic segmentation is more accurate and is better suited to meeting transcription scenarios. VAD (Voice Activity Detection) segmentation has lower latency and is better suited to interactive scenarios.

Note

Set semantic_punctuation_enabled through the parameter method or the parameters method of the RecognitionParam instance:

Set through parameter

RecognitionParam param = RecognitionParam.builder()
 .model("qwen-audio-3.0-asr-flash-streaming")
 .format("pcm")
 .sampleRate(16000)
 .parameter("semantic_punctuation_enabled", true)
 .build();

Set through parameters

RecognitionParam param = RecognitionParam.builder()
 .model("qwen-audio-3.0-asr-flash-streaming")
 .format("pcm")
 .sampleRate(16000)
 .parameters(Collections.singletonMap("semantic_punctuation_enabled", true))
 .build();

max_sentence_silence

Integer

No

The VAD silence threshold for segmentation, in ms. When the silence after a segment of speech exceeds this threshold, the system determines that the sentence has ended. When semantic_punctuation_enabled is set to true, this parameter is not used as the criterion for returning sentence_end, but setting it too low may affect recognition performance.

Default value: 1300.

Valid values: [200, 6000].

Note

Set max_sentence_silence through the parameter method or the parameters method of the RecognitionParam instance:

Set through parameter

RecognitionParam param = RecognitionParam.builder()
 .model("qwen-audio-3.0-asr-flash-streaming")
 .format("pcm")
 .sampleRate(16000)
 .parameter("max_sentence_silence", 800)
 .build();

Set through parameters

RecognitionParam param = RecognitionParam.builder()
 .model("qwen-audio-3.0-asr-flash-streaming")
 .format("pcm")
 .sampleRate(16000)
 .parameters(Collections.singletonMap("max_sentence_silence", 800))
 .build();

multi_threshold_mode_enabled

boolean

No

Important

Takes effect only when semantic_punctuation_enabled is false.

Whether to enable multi-threshold mode. When enabled, this prevents VAD segments from becoming too long.

Default value: false.

Note

Set multi_threshold_mode_enabled through the parameter method or the parameters method of the RecognitionParam instance:

Set through parameter

RecognitionParam param = RecognitionParam.builder()
 .model("qwen-audio-3.0-asr-flash-streaming")
 .format("pcm")
 .sampleRate(16000)
 .parameter("multi_threshold_mode_enabled", true)
 .build();

Set through parameters

RecognitionParam param = RecognitionParam.builder()
 .model("qwen-audio-3.0-asr-flash-streaming")
 .format("pcm")
 .sampleRate(16000)
 .parameters(Collections.singletonMap("multi_threshold_mode_enabled", true))
 .build();

punctuation_prediction_enabled

boolean

No

Sets whether to automatically add punctuation to the recognition results:

  • true (default): yes. This value cannot be changed.

Note

Set punctuation_prediction_enabled through the parameter method or the parameters method of the RecognitionParam instance:

Set through parameter

RecognitionParam param = RecognitionParam.builder()
 .model("qwen-audio-3.0-asr-flash-streaming")
 .format("pcm")
 .sampleRate(16000)
 .parameter("punctuation_prediction_enabled", false)
 .build();

Set through parameters

RecognitionParam param = RecognitionParam.builder()
 .model("qwen-audio-3.0-asr-flash-streaming")
 .format("pcm")
 .sampleRate(16000)
 .parameters(Collections.singletonMap("punctuation_prediction_enabled", false))
 .build();

heartbeat

boolean

No

Whether to enable heartbeat packets.

Default value: false.

  • true: Keeps the connection to the server alive even when silent audio is sent continuously.

  • false (default): The connection is disconnected due to timeout after 60 seconds, even if silent audio is sent continuously.

Silent audio refers to content in an audio file or data stream that contains no sound signal. You can generate silent audio in several ways, such as using audio editing software like Audacity or Adobe Audition, or using a command-line tool like FFmpeg.

Note

To use this field, the SDK version must be 2.19.1 or later.

Set heartbeat through the parameter method or the parameters method of the RecognitionParam instance:

Set through parameter

RecognitionParam param = RecognitionParam.builder()
 .model("qwen-audio-3.0-asr-flash-streaming")
 .format("pcm")
 .sampleRate(16000)
 .parameter("heartbeat", true)
 .build();

Set through parameters

RecognitionParam param = RecognitionParam.builder()
 .model("qwen-audio-3.0-asr-flash-streaming")
 .format("pcm")
 .sampleRate(16000)
 .parameters(Collections.singletonMap("heartbeat", true))
 .build();

language_hints

String[]

No

The language of the audio to recognize. There is no default value; if not set, the model detects the language automatically.

For the Qwen-Audio-3.0-ASR-Flash-Streaming model series, you can set up to 4 values; if you set more than 4, only the first 4 take effect. For the Fun-ASR-Realtime model series, you can set only 1 value; if you set multiple values, only the first one takes effect.

Click to view the supported language codes

  • qwen-audio-3.0-asr-flash-streaming, fun-asr-realtime, fun-asr-realtime-2025-11-07:

    • zh: Chinese

    • en: English

    • ja: Japanese

    • ko: Korean

    • vi: Vietnamese

    • th: Thai

    • id: Indonesian

    • ms: Malay

    • tl: Filipino

    • hi: Hindi

    • ar: Arabic

    • fr: French

    • de: German

    • es: Spanish

    • pt: Portuguese

    • ru: Russian

    • it: Italian

    • nl: Dutch

    • sv: Swedish

    • da: Danish

    • fi: Finnish

    • no: Norwegian

    • el: Greek

    • pl: Polish

    • cs: Czech

    • hu: Hungarian

    • ro: Romanian

    • bg: Bulgarian

    • hr: Croatian

    • sk: Slovak

  • fun-asr-realtime-2026-02-28:

    • zh: Chinese

    • en: English

    • ja: Japanese

  • fun-asr-realtime-2025-09-15:

    • zh: Chinese

    • en: English

  • fun-asr-flash-8k-realtime, fun-asr-flash-8k-realtime-2026-01-28:

    • zh: Chinese

Note

Set language_hints through the parameter method or the parameters method of the RecognitionParam instance:

Set through parameter

RecognitionParam param = RecognitionParam.builder()
 .model("qwen-audio-3.0-asr-flash-streaming")
 .format("pcm")
 .sampleRate(16000)
 .parameter("language_hints", new String[]{"zh"})
 .build();

Set through parameters

RecognitionParam param = RecognitionParam.builder()
 .model("qwen-audio-3.0-asr-flash-streaming")
 .format("pcm")
 .sampleRate(16000)
 .parameters(Collections.singletonMap("language_hints", new String[]{"zh"}))
 .build();

speech_noise_threshold

float

No

The threshold for distinguishing speech from noise, used to adjust the sensitivity of Voice Activity Detection (VAD).

Valid values: [-1.0, 1.0].

Value descriptions:

  • The closer the value is to -1: The noise threshold decreases, so noise is more likely to be recognized as speech, which may cause more noise to be transcribed.

  • The closer the value is to +1: The noise threshold increases, so speech is more likely to be misjudged as noise, which may cause some speech to be filtered out.

This is an advanced configuration parameter. Adjusting it can significantly affect recognition results. Recommendations:

  • Thoroughly test and verify the results before adjusting.

  • Adjust in small increments based on the actual audio environment (a step of 0.1 is recommended).

Note

Set speech_noise_threshold through the parameter method or the parameters method of the RecognitionParam instance:

Set through parameter

RecognitionParam param = RecognitionParam.builder()
 .model("qwen-audio-3.0-asr-flash-streaming")
 .format("pcm")
 .sampleRate(16000)
 .parameter("speech_noise_threshold", -0.5)
 .build();

Set through parameters

RecognitionParam param = RecognitionParam.builder()
 .model("qwen-audio-3.0-asr-flash-streaming")
 .format("pcm")
 .sampleRate(16000)
 .parameters(Collections.singletonMap("speech_noise_threshold", -0.5))
 .build();

special_word_filter

String

No

Specifies the sensitive words to process during speech recognition, and supports setting different processing methods for different sensitive words. For details, see Sensitive word filtering.

Note

Set special_word_filter through the parameter method or the parameters method of the RecognitionParam instance:

Set through parameter

// 1. Build the outermost object
JSONObject root = new JSONObject();
root.put("system_reserved_filter", true);

// 2. Build the "remove completely from results" configuration
JSONObject root1 = new JSONObject();
JSONArray array1 = new JSONArray();
array1.put("start");
array1.put("proceed");
root1.put("word_list", array1);

// 3. Build the "replace with equal-length *" configuration
JSONObject root2 = new JSONObject();
JSONArray array2 = new JSONArray();
array2.put("test");
root2.put("word_list", array2);

// 4. Assemble
root.put("filter_with_empty", root1);
root.put("filter_with_signed", root2);

RecognitionParam param = RecognitionParam.builder()
 .model("qwen-audio-3.0-asr-flash-streaming")
 .format("pcm")
 .sampleRate(16000)
 .parameter("special_word_filter", root.toString())
 .build();

Set through parameters

// 1. Build the outermost object
JSONObject root = new JSONObject();
root.put("system_reserved_filter", true);

// 2. Build the "remove completely from results" configuration
JSONObject root1 = new JSONObject();
JSONArray array1 = new JSONArray();
array1.put("start");
array1.put("proceed");
root1.put("word_list", array1);

// 3. Build the "replace with equal-length *" configuration
JSONObject root2 = new JSONObject();
JSONArray array2 = new JSONArray();
array2.put("test");
root2.put("word_list", array2);

// 4. Assemble
root.put("filter_with_empty", root1);
root.put("filter_with_signed", root2);

RecognitionParam param = RecognitionParam.builder()
 .model("qwen-audio-3.0-asr-flash-streaming")
 .format("pcm")
 .sampleRate(16000)
 .parameters(Collections.singletonMap("special_word_filter", root.toString()))
 .build();

input

Map<String, Object>

No

Input object that passes in the conversation context. The context helps recognition and improves the recognition accuracy of proper terms. For usage, see Quick start.

Important

Only the qwen-audio-3.0-asr-flash-streaming, fun-asr-realtime, and fun-asr-realtime-2025-11-07 models support the context parameter.

The Map must contain a context key whose value is a message array of type List<Map<String, Object>>. Each message contains the following fields:

  • role (String, required): the message role. user indicates the recognition result of the user's speech from previous rounds or a domain-specific word list. assistant indicates the large language model's replies from previous rounds.

  • content (List<Map>, required): the message content list. Each element contains type (String; set to input_text when role is user, and text when role is assistant) and text (String, the text content).

Important

Limits: context messages of the input_text and text types are limited to 5 each; the most recent 5 are kept when the limit is exceeded. The total text length per round of context cannot exceed 400 characters, and any excess is truncated from the end.

Important

When you pass in context, the messages in context must follow a specific order: context messages must be arranged by conversation round, and within each round the user message (input_text type) must precede the corresponding assistant message (text type).

Note

To use this field, the SDK version must be 2.22.23 or later.

Set input through the input method of the RecognitionParam instance:

// 1. Build the input struct
      Map<String, Object> userContent = new HashMap<>();
      userContent.put("type", "input_text");
      userContent.put("text", "Hello there");

      Map<String, Object> assistantContent = new HashMap<>();
      assistantContent.put("type", "text");
      assistantContent.put("text", "Hello, I am Qwen. How can I help you?");

      Map<String, Object> userMessage = new HashMap<>();
      userMessage.put("role", "user");
      userMessage.put("content", Arrays.asList(userContent));

      Map<String, Object> assistantMessage = new HashMap<>();
      assistantMessage.put("role", "assistant");
      assistantMessage.put("content", Arrays.asList(assistantContent));

      Map<String, Object> input = new HashMap<>();
      input.put("context", Arrays.asList(userMessage, assistantMessage));

      // 2. Pass it in through the input method
      RecognitionParam param = RecognitionParam.builder()
       .model("qwen-audio-3.0-asr-flash-streaming")
       .format("pcm")
       .sampleRate(16000)
       .input(input)
       .build();

apiKey

String

No

Your API key.

Key interfaces

The Recognition class

Import Recognition with import com.alibaba.dashscope.audio.asr.recognition.Recognition;. Its key interfaces are as follows:

Interface/Method

Parameter

Return value

Description

public void call(RecognitionParam param, final ResultCallback<RecognitionResult> callback)

None

Callback-based streaming real-time recognition. This method does not block the current thread.

public String call(RecognitionParam param, File file)

The recognition result.

Non-streaming recognition of a local file. This method blocks the current thread until the entire audio file is read. The file must be readable.

public Flowable<RecognitionResult> streamCall(RecognitionParam param, Flowable<ByteBuffer> audioFrame)

Flowable<RecognitionResult>

Flowable-based streaming real-time recognition.

public void sendAudioFrame(ByteBuffer audioFrame)
  • audioFrame: A binary audio stream of type ByteBuffer.

None

Sends audio. Keep each pushed audio chunk within a reasonable size. A recommended chunk holds about 100 ms of audio and is 1 KB to 16 KB in size.

Recognition results are delivered through the onEvent method of the The callback interface (ResultCallback).

public void stop()

None

None

Stops real-time recognition.

This method blocks the current thread until the ResultCallback callback's onComplete or onError is called.

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

code: The WebSocket close code.

reason: The reason for closing.

For guidance on setting these two parameters, see The WebSocket Protocol.

true

After a task ends, always close the WebSocket connection, whether or not an exception occurred, to avoid connection leaks. To reuse connections for better efficiency, see Optimize Paraformer real-time speech recognition for high concurrency.

public String getLastRequestId()

None

requestId

Gets the requestId of the current task. Available after a new task starts with call or streamingCall.

Note

This method is available only in SDK version 2.18.0 and later.

public long getFirstPackageDelay()

None

The first-packet latency.

Gets the first-packet latency, that is, the delay from sending the first audio packet to receiving the first recognition result. Use it after the task completes.

Note

This method is available only in SDK version 2.18.0 and later.

public long getLastPackageDelay()

None

The last-packet latency.

Gets the last-packet latency, that is, the time from sending the stop command to receiving the final recognition result. Use it after the task completes.

Note

This method is available only in SDK version 2.18.0 and later.

The callback interface (ResultCallback)

During bidirectional streaming calls, the server returns key process information and data to the client through callbacks. Implement the callback methods to handle the information or data returned by the server.

Implement the callback methods by extending the abstract class ResultCallback. When you extend this class, you can set the generic type to RecognitionResult. RecognitionResult wraps the data structure returned by the server.

Because Java supports connection reuse, there is no onClose or onOpen.

Example

ResultCallback<RecognitionResult> callback = new ResultCallback<RecognitionResult>() {
    @Override
    public void onEvent(RecognitionResult result) {
        System.out.println("RequestId: " + result.getRequestId());
        // Add your logic to process the speech recognition result here.
    }

    @Override
    public void onComplete() {
        System.out.println("Task complete");
    }

    @Override
    public void onError(Exception e) {
        System.out.println("Task failed: " + e.getMessage());
    }
};

Interface/Method

Parameter

Return value

Description

public void onEvent(RecognitionResult result)

result: Real-time recognition result (RecognitionResult)

None

Called when the server sends a response.

public void onComplete()

None

None

Called after the task completes.

public void onError(Exception e)

e: The exception information.

None

Called when an exception occurs.

Response

Real-time recognition result (RecognitionResult)

RecognitionResult represents the result of a single real-time recognition.

Interface/Method

Parameter

Return value

Description

public String getRequestId()

None

requestId

Gets the requestId.

public boolean isSentenceEnd()

None

Whether a complete sentence has been formed, that is, whether a sentence boundary was detected.

Determines whether the given sentence has ended.

public Sentence getSentence()

None

Sentence information (Sentence)

Gets the sentence information, including timestamps and text.

Sentence information (Sentence)

Interface/Method

Parameter

Return value

Description

public Long getBeginTime()

None

The sentence start time, in ms.

Returns the sentence start time.

public Long getEndTime()

None

The sentence end time, in ms.

Returns the sentence end time.

public String getText()

None

The recognized text.

Returns the recognized text.

public List<Word> getWords()

None

A List of Word-level timestamp information (Word) objects.

Returns word-level timestamp information.

Word-level timestamp information (Word)

Interface/Method

Parameter

Return value

Description

public long getBeginTime()

None

The word start time, in ms.

Returns the word start time.

public long getEndTime()

None

The word end time, in ms.

Returns the word end time.

public String getText()

None

The word.

Returns the recognized word.

public String getPunctuation()

None

The punctuation.

Returns the punctuation.

Error codes

If you encounter errors, see Error codes for troubleshooting.

If the issue persists, join the developer community to report your issue and provide the Request ID for further investigation.

FAQ

Features

Q: How do I keep the connection to the server alive during long periods of silence?

Set the request parameter heartbeat to true, and keep sending silent audio to the server.

Silent audio is audio that contains no sound signal in the file or data stream. You can generate silent audio in several ways, for example, by using audio editing software such as Audacity or Adobe Audition, or a command-line tool such as FFmpeg.

Q: How do I convert audio to a supported format?

Use the FFmpeg tool. For more usage, see the FFmpeg official website.

# Basic conversion command (universal template)
# -i, purpose: input file path, example values: audio.wav
# -c:a, purpose: audio encoder, example values: aac, libmp3lame, pcm_s16le
# -b:a, purpose: bitrate (audio quality control), example values: 192k, 320k
# -ar, purpose: sample rate, example values: 44100 (CD), 48000, 16000
# -ac, purpose: number of channels, example values: 1 (mono), 2 (stereo)
# -y, purpose: overwrite an existing file (no value needed)
ffmpeg -i input_audio.ext -c:a encoder_name -b:a bitrate -ar sample_rate -ac channels output.ext

# Example: WAV -> MP3 (preserve original quality)
ffmpeg -i input.wav -c:a libmp3lame -q:a 0 output.mp3
# Example: MP3 -> WAV (16-bit PCM standard format)
ffmpeg -i input.mp3 -c:a pcm_s16le -ar 44100 -ac 2 output.wav
# Example: M4A -> AAC (extract/convert Apple audio)
ffmpeg -i input.m4a -c:a copy output.aac  # Extract directly without re-encoding
ffmpeg -i input.m4a -c:a aac -b:a 256k output.aac  # Re-encode for higher quality
# Example: FLAC lossless -> Opus (high compression)
ffmpeg -i input.flac -c:a libopus -b:a 128k -vbr on output.opus

Q: How do I recognize a local file (a recording)?

There are two ways to recognize a local file:

  • Pass in the local file path directly: this approach returns the complete recognition result only after recognition finishes, so it isn't suitable for scenarios that need immediate feedback.

    See Synchronous call, and pass the file path to the call method of the The Recognition class to recognize the recording directly.

  • Convert the local file to a binary stream for recognition: this approach recognizes the file and streams results at the same time, which suits scenarios that need immediate feedback.

Troubleshooting

Q: Why can't the speech be recognized (no recognition result)?

  1. Check that the audio format (format) and sample rate (sampleRate/sample_rate) in the request parameters are correct and meet the parameter constraints. Common mistakes include:

    • The audio file has a .wav extension but is actually in MP3 format, while the request parameter format is set to mp3 (incorrect parameter setting).

    • The audio sample rate is 3600 Hz, but the request parameter sampleRate/sample_rate is set to 48000 (incorrect parameter setting).

    Use the ffprobe tool to get the container, codec, sample rate, channels, and other information about the audio:

    ffprobe -v error -show_entries format=format_name -show_entries stream=codec_name,sample_rate,channels -of default=noprint_wrappers=1 input.xxx
  2. Check that the language set in language_hints matches the actual language of the audio.

    For example, the audio is actually in Chinese, but language_hints is set to en (English).

  3. If none of the checks above reveal a problem, configure custom hotwords to improve recognition of specific terms.