通过一句话识别Java SDK发送音频流并接收识别结果。本文提供SDK安装、客户端初始化和完整调用示例,以及发送音频、结束识别和排查依赖问题的说明。
使用前准备
安装SDK
在Maven项目的pom.xml中添加以下依赖。示例使用Java SDK 2.2.1。
<dependency>
<groupId>com.alibaba.nls</groupId>
<artifactId>nls-sdk-recognizer</artifactId>
<version>2.2.1</version>
</dependency>
<!-- JDK 9及以上版本还需添加以下依赖。 -->
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.1</version>
</dependency>
从2.1.0起,nls-sdk-short-asr更名为nls-sdk-recognizer。从旧版本升级时,移除nls-sdk-short-asr依赖,并按编译提示补齐回调方法。如果项目已依赖Netty,使用4.1.17.Final或更高版本。
代码示例
下载nls-sample-16k.wav,放到程序的工作目录。该文件为单声道、16 kHz WAV音频;项目中需选择与音频语种和采样率匹配的模型。使用其他音频时,同步调整代码中的文件名、编码格式和采样率。
配置以下环境变量。AccessKey与Appkey需属于用于调用服务的账号。
|
环境变量 |
含义 |
|
|
AccessKey ID,用于申请NLS Token。 |
|
|
AccessKey Secret,用于申请NLS Token。 |
|
|
智能语音交互项目的Appkey。 |
AccessKey用于身份认证,避免将其硬编码在程序中或写入日志。NLS Token有有效期,长期运行的应用需在到期前重新获取Token,并通过NlsClient.setToken()更新客户端。
import com.alibaba.nls.client.AccessToken;
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 java.io.FileInputStream;
import java.io.InputStream;
public class SpeechRecognizerDemo {
public static void main(String[] args) throws Exception {
String appKey = requireEnv("NLS_APP_KEY");
String accessKeyId = requireEnv("ALIYUN_AK_ID");
String accessKeySecret = requireEnv("ALIYUN_AK_SECRET");
String audioFile = "nls-sample-16k.wav";
// 获取NLS Token;在有效期结束前重新获取并更新客户端。
AccessToken accessToken = new AccessToken(accessKeyId, accessKeySecret);
accessToken.apply();
NlsClient client = new NlsClient(
"wss://nls-gateway-cn-shanghai.aliyuncs.com/ws/v1", accessToken.getToken());
SpeechRecognizer recognizer = null;
try {
recognizer = new SpeechRecognizer(client, createListener());
recognizer.setAppKey(appKey);
// 编码格式和采样率须与音频文件及项目模型一致。
recognizer.setFormat(InputFormatEnum.WAV);
recognizer.setSampleRate(SampleRateEnum.SAMPLE_RATE_16K);
recognizer.setEnableIntermediateResult(true);
recognizer.addCustomedParam("enable_voice_detection", true);
recognizer.start();
try (InputStream audio = new FileInputStream(audioFile)) {
// 从文件模拟实时音频:每次发送3200字节,间隔100毫秒。
recognizer.send(audio, 3200, 100);
}
recognizer.stop();
} finally {
if (recognizer != null) {
recognizer.close();
}
client.shutdown();
}
}
private static SpeechRecognizerListener createListener() {
return new SpeechRecognizerListener() {
@Override
public void onStarted(SpeechRecognizerResponse response) {
System.out.println("Task ID: " + response.getTaskId());
}
@Override
public void onRecognitionResultChanged(SpeechRecognizerResponse response) {
System.out.println("RecognitionResultChanged: " + response.getRecognizedText());
}
@Override
public void onRecognitionCompleted(SpeechRecognizerResponse response) {
System.out.println("RecognitionCompleted: " + response.getRecognizedText());
}
@Override
public void onFail(SpeechRecognizerResponse response) {
System.err.println("Task ID: " + response.getTaskId()
+ ", status: " + response.getStatus()
+ ", message: " + response.getStatusText());
}
};
}
private static String requireEnv(String name) {
String value = System.getenv(name);
if (value == null || value.isEmpty()) {
throw new IllegalArgumentException("Missing environment variable: " + name);
}
return value;
}
}
识别结果通过onRecognitionResultChanged和onRecognitionCompleted回调返回;请求失败时,通过onFail获取任务ID、状态码和错误信息。
在阿里云上海地域ECS上通过内网访问时,将创建NlsClient时的服务地址替换为ws://nls-gateway-cn-shanghai-internal.aliyuncs.com/ws/v1。
关键接口
|
接口 |
用途与生命周期 |
|
|
语音处理客户端,支持一句话识别、实时语音识别和语音合成。线程安全,建议全局复用一个实例,在应用退出时调用 |
|
|
设置一句话识别参数、发送音频和结束识别。非线程安全,每个识别任务创建一个对象,不重复用于其他任务;任务结束后调用 |
|
|
接收开始、中间结果、完成和失败事件。非线程安全,与 |
NlsClient使用Netty,创建实例会消耗时间和资源。客户端的创建和关闭可与应用生命周期保持一致;识别任务则分别创建和关闭SpeechRecognizer。更多方法,请参见Java API接口说明。
运行完整示例包
也可以下载完整示例工程,使用其中的调用程序和压测程序。
解压后,在工程根目录运行mvn package。生成的可执行文件位于nls-example-recognizer/target/nls-example-recognizer-2.0.0-jar-with-dependencies.jar。将JAR包和配套音频复制到目标服务器后,运行以下命令,并按提示提供Appkey、NLS Token和可选的服务地址。程序会在工作目录生成logs/nls.log。
java -cp nls-example-recognizer-2.0.0-jar-with-dependencies.jar com.alibaba.nls.client.SpeechRecognizerDemo
需要压测时,使用以下命令,并按提示设置并发数:
java -jar nls-example-recognizer-2.0.0-jar-with-dependencies.jar
服务地址为wss://nls-gateway-cn-shanghai.aliyuncs.com/ws/v1。
压测使用16 kHz PCM音频,并发数需在已开通服务的并发额度内。压测调用同样适用服务的计费规则,运行前确认服务版本、计费方式和并发额度。
常见问题
何时调用stop()?
音频发送完成后,调用recognizer.stop()发送StopRecognition指令,并等待识别完成。开启语音检测(VAD)时,服务端也可以在检测到语音结束后返回RecognitionCompleted事件。
语音发送期间需保持连续、实时的数据流;长时间未发送数据会触发空闲超时。需要中间结果时,在start()前调用setEnableIntermediateResult(true)。
如何识别本地音频文件?
本页示例从本地文件读取音频,并按实时速度发送给服务端。也可以通过RESTful API上传音频文件,调用方式请参见一句话识别RESTful API。
如何使用send()发送音频?
一句话识别提供以下四个send()重载:
public void send(byte[] data);
public void send(byte[] data, int length);
public void send(InputStream ins);
public void send(InputStream ins, int batchSize, int sleepInterval);
send(byte[])、send(byte[], int)和send(InputStream)按数据到达或读取的速度发送,不自动按音频时长设置间隔。实时采集音频时,按采集速度连续发送;从文件模拟实时流时,可使用带batchSize和sleepInterval的方法控制发送速度。
16位、单声道PCM音频在16 kHz采样率下,每100毫秒对应3200字节;8 kHz时,3200字节对应200毫秒。其他编码格式需按压缩后的数据量调整每批字节数和发送间隔。发送间隔过大可能增加延迟或导致断连,过小会增加服务端和网络资源消耗。
基于前面的完整示例,发送16 kHz音频文件流可使用:
recognizer.send(audio, 3200, 100);
自行循环读取文件时,也可以使用send(byte[], int),或为完整的100毫秒音频数据调用send(byte[]):
recognizer.send(data);
Thread.sleep(100);
上述data表示16 kHz、16位、单声道PCM的3200字节音频;最后一批不足3200字节时,使用send(data, length)传入实际长度。
如何通过日志分析延迟?
一句话识别的结束延迟,可以用发送StopRecognition到收到RecognitionCompleted的时间差计算。例如,两条日志的时间分别为14:24:44.844和14:24:44.984,对应延迟为140毫秒。
同样的方法也适用于其他语音处理任务:
实时语音识别使用
StopTranscription和TranscriptionCompleted的时间差。语音合成的首包延迟使用发送
StartSynthesis到收到首个音频包的时间差。例如,14:32:13.813到14:32:14.035对应222毫秒。
完整示例包已配置日志。自行集成SDK时,按应用的日志框架配置日志输出。通过RESTful API调用时,可在客户端记录请求和响应时间来计算延迟。
找不到com.alibaba的JAR包怎么办?
通过Alibaba Cloud SDK for Java获取Token时,需安装相应依赖。安装方法,请参见V1.0 Java SDK。
org.json.JSONArray.iterator()报错怎么办?
旧工程通过Alibaba Cloud SDK for Java获取客户端或Token时,若出现org.json.JSONArray.iterator()Ljava/util/Iterator方法不存在的错误,检查运行时加载的JSON库与SDK所需版本是否一致,并排除重复依赖。检查org.json:json和com.google.code.gson:gson等相关依赖是否完整,使用与当前Alibaba Cloud SDK兼容的版本。