本文档介绍如何使用 DashScope Java SDK 调用实时语音识别(Qwen-ASR-Realtime)模型。
重要阿里云百炼为华北2(北京)、新加坡地域推出了业务空间专属域名,能够为推理请求提供卓越的性能和更高的稳定性,建议迁移至新域名:
- 华北2(北京)地域:从
dashscope.aliyuncs.com迁移至{WorkspaceId}.cn-beijing.maas.aliyuncs.com - 新加坡地域:从
dashscope-intl.aliyuncs.com迁移至{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com
{WorkspaceId}需要替换为真实的Workspace ID。现有域名仍可正常使用。
前提条件
- 安装SDK,确保DashScope SDK版本不低于2.22.5。
- 获取与配置 API Key。
- 了解WebSocket API。
完整示例
说明示例代码读取 your_audio_file.pcm(PCM16、16 kHz、单声道)。如仅有 MP3/WAV 等格式,可使用 ffmpeg 转换:
ffmpeg -i your_audio.mp3 -ar 16000 -ac 1 -f s16le your_audio_file.pcm
import com.alibaba.dashscope.audio.omni.*;
import com.alibaba.dashscope.exception.NoApiKeyException;
import com.google.gson.JsonObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.sound.sampled.LineUnavailableException;
import java.io.File;
import java.io.FileInputStream;
import java.util.Base64;
import java.util.Collections;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicReference;
public class Qwen3AsrRealtimeUsage {
private static final Logger log = LoggerFactory.getLogger(Qwen3AsrRealtimeUsage.class);
private static final int AUDIO_CHUNK_SIZE = 1024; // Audio chunk size in bytes
private static final int SLEEP_INTERVAL_MS = 30; // Sleep interval in milliseconds
public static void main(String[] args) throws InterruptedException, LineUnavailableException {
CountDownLatch finishLatch = new CountDownLatch(1);
OmniRealtimeParam param = OmniRealtimeParam.builder()
.model("qwen3-asr-flash-realtime")
// 以下为华北2(北京)地域的配置,调用时请将"{WorkspaceId}"替换为真实的业务空间ID,各地域的配置不同。
.url("wss://{WorkspaceId}.cn-beijing.maas.aliyuncs.com/api-ws/v1/realtime")
// 新加坡和北京地域的API Key不同。获取API Key:https://help.aliyun.com/zh/model-studio/get-api-key
// 若没有配置环境变量,请用阿里云百炼API Key将下行替换为:.apikey("sk-xxx")
.apikey(System.getenv("DASHSCOPE_API_KEY"))
.build();
OmniRealtimeConversation conversation = null;
final AtomicReference<OmniRealtimeConversation> conversationRef = new AtomicReference<>(null);
conversation = new OmniRealtimeConversation(param, new OmniRealtimeCallback() {
@Override
public void onOpen() {
System.out.println("connection opened");
}
@Override
public void onEvent(JsonObject message) {
String type = message.get("type").getAsString();
switch(type) {
case "session.created":
System.out.println("start session: " + message.get("session").getAsJsonObject().get("id").getAsString());
break;
case "conversation.item.input_audio_transcription.completed":
System.out.println("transcription: " + message.get("transcript").getAsString());
finishLatch.countDown();
break;
case "input_audio_buffer.speech_started":
System.out.println("======VAD Speech Start======");
break;
case "input_audio_buffer.speech_stopped":
System.out.println("======VAD Speech Stop======");
break;
case "conversation.item.input_audio_transcription.text":
System.out.println("transcription: " + message.get("text").getAsString() + message.get("stash").getAsString());
break;
default:
break;
}
}
@Override
public void onClose(int code, String reason) {
System.out.println("connection closed code: " + code + ", reason: " + reason);
}
});
conversationRef.set(conversation);
try {
conversation.connect();
} catch (NoApiKeyException e) {
throw new RuntimeException(e);
}
OmniRealtimeTranscriptionParam transcriptionParam = new OmniRealtimeTranscriptionParam();
transcriptionParam.setLanguage("zh");
transcriptionParam.setInputAudioFormat("pcm");
transcriptionParam.setInputSampleRate(16000);
OmniRealtimeConfig config = OmniRealtimeConfig.builder()
.modalities(Collections.singletonList(OmniRealtimeModality.TEXT))
.transcriptionConfig(transcriptionParam)
.build();
conversation.updateSession(config);
String filePath = "your_audio_file.pcm";
File audioFile = new File(filePath);
if (!audioFile.exists()) {
log.error("Audio file not found: {}", filePath);
return;
}
try (FileInputStream audioInputStream = new FileInputStream(audioFile)) {
byte[] audioBuffer = new byte[AUDIO_CHUNK_SIZE];
int bytesRead;
int totalBytesRead = 0;
log.info("Starting to send audio data from: {}", filePath);
// Read and send audio data in chunks
while ((bytesRead = audioInputStream.read(audioBuffer)) != -1) {
totalBytesRead += bytesRead;
byte[] chunk = new byte[bytesRead];
System.arraycopy(audioBuffer, 0, chunk, 0, bytesRead);
String audioB64 = Base64.getEncoder().encodeToString(chunk);
// Send audio chunk to conversation
conversation.appendAudio(audioB64);
// Add small delay to simulate real-time audio streaming
Thread.sleep(SLEEP_INTERVAL_MS);
}
log.info("Finished sending audio data. Total bytes sent: {}", totalBytesRead);
} catch (Exception e) {
log.error("Error sending audio from file: {}", filePath, e);
}
//send session.finish and wait for finish and close
conversation.endSession();
log.info("task finished");
System.exit(0);
}
}
请求参数
-
以下参数通过
OmniRealtimeParam的链式方法设置。点击查看示例代码
OmniRealtimeParam param = OmniRealtimeParam.builder() .model("qwen3-asr-flash-realtime") // 以下为华北2(北京)地域的配置,调用时请将"{WorkspaceId}"替换为真实的业务空间ID,各地域的配置不同。 .url("wss://{WorkspaceId}.cn-beijing.maas.aliyuncs.com/api-ws/v1/realtime") // 新加坡和北京地域的API Key不同。获取API Key:https://help.aliyun.com/zh/model-studio/get-api-key // 若没有配置环境变量,请用百炼API Key将下行替换为:.apikey("sk-xxx") .apikey(System.getenv("DASHSCOPE_API_KEY")) .build();参数
类型
是否必须
说明
modelString是
指定要使用的模型名称。
urlString是
语音识别服务地址:
华北2(北京)地域:
wss://{WorkspaceId}.cn-beijing.maas.aliyuncs.com/api-ws/v1/realtime。调用时请将{WorkspaceId}替换为真实的Workspace ID。新加坡地域:
wss://{WorkspaceId}.ap-southeast-1.maas.aliyuncs.com/api-ws/v1/realtime。调用时请将{WorkspaceId}替换为真实的业务空间ID。
apikeyString否
设置API Key。
-
以下参数通过
OmniRealtimeConfig的链式方法设置。点击查看示例代码
OmniRealtimeTranscriptionParam transcriptionParam = new OmniRealtimeTranscriptionParam(); transcriptionParam.setLanguage("zh"); transcriptionParam.setInputSampleRate(16000); transcriptionParam.setInputAudioFormat("pcm"); OmniRealtimeConfig config = OmniRealtimeConfig.builder() .modalities(Collections.singletonList(OmniRealtimeModality.TEXT)) .enableTurnDetection( true) .turnDetectionType("server_vad") .turnDetectionThreshold(0.0f) .turnDetectionSilenceDurationMs(400) .transcriptionConfig(transcriptionParam) .build();参数
类型
是否必须
说明
modalitiesList<OmniRealtimeModality>是
模型输出模态,固定为
[OmniRealtimeModality.TEXT]。enableTurnDetectionboolean否
是否开启服务端语音活动检测(VAD)。关闭后,需手动调用
commit()方法触发识别。默认值:
true。取值范围:
true:开启false:关闭
turnDetectionTypeString否
服务端VAD类型,固定为
server_vad。turnDetectionThresholdfloat否
VAD检测阈值。推荐将该值设为
0.0。默认值:
0.5。取值范围:
[-1, 1]。较低的阈值会提高 VAD 的灵敏度,可能将背景噪音误判为语音。较高的阈值则降低灵敏度,有助于在嘈杂环境中减少误触发。
turnDetectionSilenceDurationMsint否
VAD断句检测阈值(ms)。静音持续时长超过该阈值将被认为是语句结束。推荐将该值设为
400。默认值:
800。取值范围:
[200, 6000]。较低的值(如 300ms)可使模型更快响应,但可能导致在自然停顿处发生不合理的断句。较高的值(如 1200ms)可更好地处理长句内的停顿,但会增加整体响应延迟。
transcriptionConfigOmniRealtimeTranscriptionParam否
语音识别相关配置。
-
以下参数通过
OmniRealtimeTranscriptionParam的setter方法设置。点击查看示例代码
OmniRealtimeTranscriptionParam transcriptionParam = new OmniRealtimeTranscriptionParam(); transcriptionParam.setLanguage("zh"); transcriptionParam.setInputSampleRate(16000); transcriptionParam.setInputAudioFormat("pcm");参数
类型
是否必须
说明
languageString否
音频源语言。
zh:中文(普通话、四川话、闽南语、吴语)
yue:粤语
en:英文
ja:日语
de:德语
ko:韩语
ru:俄语
fr:法语
pt:葡萄牙语
ar:阿拉伯语
it:意大利语
es:西班牙语
hi:印地语
id:印尼语
th:泰语
tr:土耳其语
uk:乌克兰语
vi:越南语
cs:捷克语
da:丹麦语
fil:菲律宾语
fi:芬兰语
is:冰岛语
ms:马来语
no:挪威语
pl:波兰语
sv:瑞典语
inputSampleRateint否
音频采样率(Hz)。支持
16000和8000。默认值:
16000。设置为
8000时,服务端会先升采样到16000Hz再进行识别,可能引入微小延迟。建议仅在源音频为8000Hz(如电话线路)时使用。inputAudioFormatString否
音频格式。支持
pcm和opus。默认值:
pcm。
关键接口
OmniRealtimeConversation类
OmniRealtimeConversation通过import com.alibaba.dashscope.audio.omni.OmniRealtimeConversation;方法引入。
| 方法签名 | 服务端响应事件(通过回调下发) | 说明 |
|---|---|---|
| 无 | 构造方法。 |
|
| 和服务端创建连接。 |
|
| 用于更新会话配置,建议在连接建立后首先调用该方法进行设置。若未调用该方法,系统将使用默认配置。只需关注请求参数中的涉及到的参数。 |
| 无 | 将Base64编码后的音频数据片段追加到云端输入音频缓冲区。 |
|
| 提交之前通过append添加到云端缓冲区的音视频,如果输入的音频缓冲区为空将产生错误。 禁用场景:请求参数 |
|
| 通知服务端结束会话,服务端收到会话结束通知后将完成最后的语音识别。 调用时机:
|
| 无 | 终止任务,并关闭连接。 |
| 无 | 获取当前任务的session_id。 |
| 无 | 获取最近一次response的response_id。 |
回调接口(OmniRealtimeCallback)
服务端会通过回调的方式,将服务端响应事件和数据返回给客户端。
继承此类并实现相应方法以处理服务端事件。
通过import com.alibaba.dashscope.audio.omni.OmniRealtimeCallback;引入。
| 方法签名 | 参数 | 说明 |
|---|---|---|
| 无 | WebSocket连接成功建立时触发。 |
| message:服务端事件 | 收到服务端事件时触发。 |
| code:状态码 reason:WebSocket连接关闭时的日志信息 | WebSocket连接关闭时触发。 |