跳转到主要内容
实时

Fun-ASR realtime Java SDK

实时语音识别 Java SDK

使用指南: 模型概述和选型请参见实时语音识别

快速开始

Recognition 类提供三种调用方式:
  • 非流式调用:一次性返回完整结果,适用于预录制音频。
  • 双向流式调用:边输入音频边实时返回结果,适用于麦克风采集或需要即时反馈的场景。

非流式调用

传入本地文件,同步获取转写结果。此调用会阻塞当前线程。 实例化 Recognition 类,调用 call 方法并传入请求参数和音频文件。
示例中使用的音频文件为 asr_example.wav
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) {
    Constants.baseWebsocketApiUrl = "wss://dashscope.aliyuncs.com/api-ws/v1/inference";
    // 创建 Recognition 实例
    Recognition recognizer = new Recognition();
    // 创建 RecognitionParam
    RecognitionParam param =
        RecognitionParam.builder()
            .model("fun-asr-realtime")
            // 如果未配置环境变量,请将下行替换为您的 API Key:.apiKey("sk-xxx")
            .apiKey(System.getenv("DASHSCOPE_API_KEY"))
            .format("wav")
            .sampleRate(16000)
            .parameter("language_hints", new String[]{"zh", "en"})
            .build();

    try {
      System.out.println("Recognition result: " + recognizer.call(param, new File("asr_example.wav")));
    } catch (Exception e) {
      e.printStackTrace();
    } finally {
      // 任务完成后关闭 WebSocket 连接
      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);
  }
}

双向流式调用: 基于回调

通过实现回调接口实时接收识别结果。
1

启动流式识别

实例化 Recognition 类,调用 call 方法并传入请求参数回调接口 (ResultCallback)
2

发送音频流

反复调用 sendAudioFrame 发送音频片段(来自文件或麦克风)。服务端通过 onEvent 回调返回识别结果。每次发送约 100 ms 时长的音频片段,大小为 1-16 KB。
3

结束识别

调用 stop 结束识别。此方法会阻塞直到 onCompleteonError 被调用。
  • 从麦克风识别语音
  • 识别本地音频文件
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 {
    Constants.baseWebsocketApiUrl = "wss://dashscope.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("fun-asr-realtime")
        // 如果未配置环境变量,请将下行替换为您的 API Key:.apiKey("sk-xxx")
        .apiKey(System.getenv("DASHSCOPE_API_KEY"))
        .format("wav")
        .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);
      // 创建音频格式
      AudioFormat audioFormat = new AudioFormat(16000, 16, 1, true, false);
      // 根据格式匹配默认录音设备
      TargetDataLine targetDataLine =
          AudioSystem.getTargetDataLine(audioFormat);
      targetDataLine.open(audioFormat);
      // 开始录音
      targetDataLine.start();
      ByteBuffer buffer = ByteBuffer.allocate(1024);
      long start = System.currentTimeMillis();
      // 录制 50 秒并实时转写
      while (System.currentTimeMillis() - start < 50000) {
        int read = targetDataLine.read(buffer.array(), 0, buffer.capacity());
        if (read > 0) {
          buffer.limit(read);
          // 将录制的音频数据发送给流式识别服务
          recognizer.sendAudioFrame(buffer);
          buffer = ByteBuffer.allocate(1024);
          // 录音速率有限,短暂休眠以避免 CPU 占用过高
          Thread.sleep(20);
        }
      }
      recognizer.stop();
    } catch (Exception e) {
      e.printStackTrace();
    } finally {
      // 任务完成后关闭 WebSocket 连接
      recognizer.getDuplexApi().close(1000, "bye");
    }

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

双向流式调用: 基于 Flowable

使用 Flowable 工作流实时接收识别结果。 Flowable 是 RxJava 提供的响应式流类型,支持背压机制。详见 Flowable API 参考
调用 streamCall 启动识别,返回 Flowable<RecognitionResult>。使用 blockingForEachsubscribe 处理结果。streamCall 需要以下参数:
  • RecognitionParam:模型、采样率和音频格式
  • Flowable<ByteBuffer>:音频流
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 {
    Constants.baseWebsocketApiUrl = "wss://dashscope.aliyuncs.com/api-ws/v1/inference";
    // 创建 Flowable<ByteBuffer>
    Flowable<ByteBuffer> audioSource =
        Flowable.create(
            emitter -> {
              new Thread(
                  () -> {
                    try {
                      // 创建音频格式
                      AudioFormat audioFormat = new AudioFormat(16000, 16, 1, true, false);
                      // 根据格式匹配默认录音设备
                      TargetDataLine targetDataLine =
                          AudioSystem.getTargetDataLine(audioFormat);
                      targetDataLine.open(audioFormat);
                      // 开始录音
                      targetDataLine.start();
                      ByteBuffer buffer = ByteBuffer.allocate(1024);
                      long start = System.currentTimeMillis();
                      // 录制 50 秒并实时转写
                      while (System.currentTimeMillis() - start < 50000) {
                        int read = targetDataLine.read(buffer.array(), 0, buffer.capacity());
                        if (read > 0) {
                          buffer.limit(read);
                          // 将录制的音频数据发送给流式识别服务
                          emitter.onNext(buffer);
                          buffer = ByteBuffer.allocate(1024);
                          // 录音速率有限,短暂休眠以避免 CPU 占用过高
                          Thread.sleep(20);
                        }
                      }
                      // 通知转写完成
                      emitter.onComplete();
                    } catch (Exception e) {
                      emitter.onError(e);
                    }
                  })
                  .start();
            },
            BackpressureStrategy.BUFFER);

    // 创建 Recognition 实例
    Recognition recognizer = new Recognition();
    // 创建 RecognitionParam,通过 audioFrame 参数传入 Flowable<ByteBuffer>
    RecognitionParam param = RecognitionParam.builder()
        .model("fun-asr-realtime")
        // 如果未配置环境变量,请将下行替换为您的 API Key:.apiKey("sk-xxx")
        .apiKey(System.getenv("DASHSCOPE_API_KEY"))
        .format("pcm")
        .sampleRate(16000)
        .build();

    // 调用流式接口
    recognizer
        .streamCall(param, audioSource)
        .blockingForEach(
            result -> {
              // 订阅输出结果
              if (result.isSentenceEnd()) {
                System.out.println("Final Result: " + result.getSentence().getText());
              } else {
                System.out.println("Intermediate Result: " + result.getSentence().getText());
              }
            });
    // 任务完成后关闭 WebSocket 连接
    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);
  }
}

高并发调用

SDK 使用 OkHttp3 连接池来减少开销。详见高并发管理

请求参数

使用 RecognitionParam 的构建器方法配置模型、采样率和音频格式,然后将配置好的对象传给 callstreamCall
RecognitionParam param = RecognitionParam.builder()
  .model("fun-asr-realtime")
  .format("pcm")
  .sampleRate(16000)
  .parameter("language_hints", new String[]{"zh", "en"})
  .build();
参数类型默认值必选说明
modelString-实时语音识别模型。
sampleRateInteger-音频采样率,单位 Hz。fun-asr-realtime 支持 16000 Hz。
formatString-音频格式。支持:pcm、wav、mp3、opus、speex、aac、amr。
注意: opus/speex 必须使用 Ogg 封装。wav 必须为 PCM 编码。amr 仅支持 AMR-NB。
vocabularyIdString-自定义词表 ID。参见自定义热词。默认不设置。
semantic_punctuation_enabledbooleanfalse标点模式。true:语义标点(精度更高,适用于会议场景)。false(默认):VAD 标点(延迟更低,适用于交互场景)。
max_sentence_silenceInteger1300VAD 标点模式下的静音断句阈值,单位毫秒。语音后的静音时长超过此值时,句子结束。取值范围:200 到 6000 ms。仅在 semantic_punctuation_enabledfalse 时生效。
multi_threshold_mode_enabledbooleanfalse防止 VAD 过早切分长句。仅在 semantic_punctuation_enabledfalse 时生效。
punctuation_prediction_enabledbooleantrue自动为识别结果添加标点符号,固定为 true,不支持修改。
heartbeatbooleanfalse静音时保持持久连接。true:连接保持存活。false(默认):即使发送静音音频,60 秒后也会断开连接。
需要 SDK 2.19.1 或更高版本。
language_hintsString[]-识别语言代码。不设置则自动检测。支持的语言代码:zh(中文)、en(英文)、ja(日文)。
speech_noise_thresholdfloat-VAD 灵敏度。取值范围:[-1.0, 1.0]。接近 -1:更多噪音被识别为语音。接近 +1:部分语音被过滤为噪音。
注意: 高级参数,调整会显著影响识别质量。请充分测试,并根据音频环境小幅调整(步长 0.1)。
apiKeyString-您的 API Key。
对于 RecognitionParam 构建器中未直接提供的参数(如 semantic_punctuation_enabledheartbeatlanguage_hints),请使用 parameterparameters 方法:
  • 使用 parameter 方法设置
  • 使用 parameters 方法设置
RecognitionParam param = RecognitionParam.builder()
  .model("fun-asr-realtime")
  .format("pcm")
  .sampleRate(16000)
  .parameter("semantic_punctuation_enabled", true)
  .build();

核心接口

Recognition

导入:import com.alibaba.dashscope.audio.asr.recognition.Recognition;
接口/方法参数返回值说明
public void call(RecognitionParam param, final ResultCallback<RecognitionResult> callback)param请求参数
callback回调接口 (ResultCallback)
基于回调的流式识别,不阻塞当前线程。
public String call(RecognitionParam param, File file)param请求参数
file:待识别的音频文件
识别结果非流式调用,传入本地文件。阻塞直到处理完成。文件必须可读。
public Flowable<RecognitionResult> streamCall(RecognitionParam param, Flowable<ByteBuffer> audioFrame)param请求参数
audioFrameFlowable<ByteBuffer> 实例
Flowable<RecognitionResult>基于 Flowable 的流式识别。
public void sendAudioFrame(ByteBuffer audioFrame)audioFrame:二进制音频流 (ByteBuffer)发送一个音频片段。每个数据包约 100 ms 时长,大小 1-16 KB。结果通过 ResultCallbackonEvent 方法返回。
public void stop()停止识别。阻塞直到 onCompleteonError 被调用。
boolean getDuplexApi().close(int code, String reason)code:WebSocket 关闭码
reason:关闭原因
参见 The WebSocket Protocol
true每个任务完成后关闭 WebSocket 连接以防止泄漏(异常情况下也需关闭)。先通过 getDuplexApi() 获取连接对象后调用 close。如需复用连接,请参见高并发管理
public String getLastRequestId()requestId获取当前任务的请求 ID。需在 callstreamCall 启动任务后调用。
需要 SDK 2.18.0 或更高版本。
public long getFirstPackageDelay()首包延迟获取从发送第一个音频包到收到第一个结果的延迟。需在任务完成后调用。
需要 SDK 2.18.0 或更高版本。
public long getLastPackageDelay()尾包延迟获取从发送 stop 到最后一个结果返回的时间。需在任务完成后调用。
需要 SDK 2.18.0 或更高版本。

回调接口 (ResultCallback)

双向流式调用中,实现回调方法来处理服务端返回的结果。 继承 ResultCallback<RecognitionResult> 并实现其方法。RecognitionResult 封装了服务端响应。 SDK 支持连接复用,因此没有 onCloseonOpen 方法。

示例

ResultCallback<RecognitionResult> callback = new ResultCallback<RecognitionResult>() {
  @Override
  public void onEvent(RecognitionResult result) {
    System.out.println("RequestId is: " + result.getRequestId());
    // 在此处实现语音识别结果的处理逻辑
  }

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

  @Override
  public void onError(Exception e) {
    System.out.println("Task failed: " + e.getMessage());
  }
};
接口/方法参数返回值说明
public void onEvent(RecognitionResult result)result实时识别结果 (RecognitionResult)服务端返回结果时调用。
public void onComplete()识别成功完成时调用。
public void onError(Exception e)e:异常信息发生错误时调用。

响应结果

实时识别结果 (RecognitionResult)

RecognitionResult 表示单条识别结果。
接口/方法参数返回值说明
public String getRequestId()requestId获取请求 ID。
public boolean isSentenceEnd()句子是否结束返回当前句子是否已结束(最终结果)。
public Sentence getSentence()Sentence获取包含时间戳和文本的句子信息。

句子信息 (Sentence)

接口/方法参数返回值说明
public Long getBeginTime()句子开始时间,单位毫秒返回句子的开始时间。
public Long getEndTime()句子结束时间,单位毫秒返回句子的结束时间。
public String getText()识别文本返回识别出的文本。
public List<Word> getWords()词时间戳信息 (Word) 列表返回词级时间戳信息。

词时间戳信息 (Word)

接口/方法参数返回值说明
public long getBeginTime()词开始时间,单位毫秒返回词的开始时间。
public long getEndTime()词结束时间,单位毫秒返回词的结束时间。
public String getText()返回识别出的词。
public String getPunctuation()标点返回标点符号。