
# 实时语音识别
#### 前提条件
- 确保已按照[配置Java环境](https://support.huaweicloud.com/sdkreference-sis/sis_05_0041.html)配置完毕。
- 确保已存在待识别的音频文件。如果需要请在下载的SDK压缩包中获取示例音频。
- 请参考[SDK（websocket）](https://support.huaweicloud.com/sdkreference-sis/sis_05_0004.html)获取最新版本SDK包。
 
#### 初始化Client
初始化RasrClient，其参数包括AuthInfo、RasrListener、SisConfig。
RasrListener需要用户自定义实现监听逻辑，请参见[表1]和[表2]。
 表1AuthInfo 
| 参数名称      | 是否必选 | 参数类型   | 描述                                                                                     |
|:---|:---|:---|:---|
| ak        | 是    | String | 用户的ak，可参考[AK/SK认证](https://support.huaweicloud.com/sdkreference-sis/sis_05_0003.html)。 |
| sk        | 是    | String | 用户的sk，可参考[AK/SK认证](https://support.huaweicloud.com/sdkreference-sis/sis_05_0003.html)。 |
| region    | 是    | String | 区域，如cn-north-4，参考[终端节点](https://support.huaweicloud.com/api-sis/sis_03_0004.html)。     |
| projectId | 是    | String | 项目ID，同region一一对应，参考[获取项目ID](https://support.huaweicloud.com/api-sis/sis_03_0008.html)。 |
| endpoint  | 否    | String | 终端节点，参考[终端节点](https://support.huaweicloud.com/api-sis/sis_03_0004.html)。一般使用默认即可。      |
   
 表2SisConfig 
| 参数名称              | 是否必选 | 参数类型    | 描述                 |
|:---|:---|:---|:---|
| connectionTimeout | 否    | Integer | 连接超时，默认10000，单位ms。 |
| readTimeout       | 否    | Integer | 读取超时，默认10000，单位ms。 |
   
#### 请求参数
请求类为RasrRequest，详见[表3]。
 表3RasrRequest 
| 参数名称               | 是否必选 | 参数类型    | 描述                                                                                                                                   |
|:---|:---|:---|:---|
| audioFormat        | 是    | String  | 音频格式，支持pcm，alaw，ulaw等，如pcm8k16bit，参见《API参考》中[开始识别](https://support.huaweicloud.com/api-sis/sis_03_0030.html)章节。                      |
| property           | 是    | String  | 属性字符串，language_sampleRate_domain， 如chinese_16k_general，参见《API参考》中[开始识别](https://support.huaweicloud.com/api-sis/sis_03_0030.html)章节。 |
| punc               | 否    | String  | 表示是否在识别结果中添加标点，取值为yes 、 no，默认no。                                                                                                     |
| digitNorm          | 否    | String  | 表示是否将语音中的数字识别为阿拉伯数字，取值为yes 、 no，默认为yes。                                                                                              |
| vadHead            | 否    | Integer | 头部最大静音时间，\[0, 60000\]，默认10000ms，详见[开始识别](https://support.huaweicloud.com/api-sis/sis_03_0030.html)。                                  |
| vadTail            | 否    | Integer | 尾部最大静音时间，\[0, 3000\]，默认500ms，详见[开始识别](https://support.huaweicloud.com/api-sis/sis_03_0030.html)。                                     |
| maxSeconds         | 否    | Integer | 音频最长持续时间， \[1, 60\]，默认30s，详见[开始识别](https://support.huaweicloud.com/api-sis/sis_03_0030.html)。                                        |
| intermediateResult | 否    | String  | 是否显示中间结果，yes 或 no，默认no。例如分3次发送音频，选择no结果一次性返回，选择yes分三次返回。                                                                             |
| vocabularyId       | 否    | String  | 热词表id，若没有则不填。                                                                                                                        |
| needWordInfo       | 否    | String  | 表示是否在识别结果中输出分词结果信息，取值为"yes"和"no"，默认为"no"。对于中文，是按照字级别进行分词；对于英文是按照子词（BPE）级别进行分词。                                                       |
| needSmooth         | 否    | String  | 是否需要对识别结果进行顺滑（过滤语气词或者吞吐词），取值为"yes"和"no"。仅支持中文ASR的顺滑。                                                                                 |
   
#### 响应参数
状态响应类为StateResponse，详见[表4]。
结果响应类为RasrResponse，详见[表5]。
调用失败处理方法请参见[错误码](https://support.huaweicloud.com/api-sis/sis_03_0045.html)。
 表4StateResponse 
| 参数名称        | 是否必选 | 参数类型   | 描述                     |
|:---|:---|:---|:---|
| state       | 是    | String | 识别状态，包括start、end、fail。 |
| traceId     | 是    | String | 用于日志问题追溯。              |
| description | 是    | String | 状态描述。                  |
   
 表5RasrResponse 
| 参数名      | 参数类型             | 说明                                                                                                |
|:---|:---|:---|
| respType | String           | 参数值为RESULT，表示识别结果响应。                                                                              |
| traceId  | String           | 服务内部的令牌，可用于在日志中追溯具体流程。                                                                            |
| segments | Array of objects | 多句结果。 请参考[表6]。 |
   
 表6Segment 
| 参数名       | 参数类型    | 说明                                                                                               |
|:---|:---|:---|
| startTime | Integer | 一句的起始时间戳，单位为ms。                                                                                  |
| endTime   | Integer | 一句的结束时间戳，单位为ms。                                                                                  |
| isFinal   | Boolean | true表示是最终结果， false表示为中间临时结果。                                                                     |
| result    | Object  | 调用成功表示识别结果，调用失败时无此字段。 请参考[表7]。 |
   
 表7Result 
| 参数名      | 参数类型            | 说明                                                                                                                                    |
|:---|:---|:---|
| text     | String          | 识别结果。                                                                                                                                 |
| score    | Float           | 识别结果的置信度，取值范围：0\~1。此值仅会在最终结果时被赋值，在中间结果时统一置为"0.0"。 说明： 目前置信度作用不是太大，请勿过多依赖此值。 |
| wordInfo | Array of Object | 分词输出列表。                                                                                                                               |
   
表8Word_info 数据结构 
| 参数名       | 是否必选 | 参数类型    | 说明   |
|:---|:---|:---|:---|
| startTime | 否    | Integer | 起始时间 |
| endTime   | 否    | Integer | 结束时间 |
| word      | 否    | String  | 分词   |
   
#### 示例代码
如下示例仅供参考，最新代码请前往[SDK（websocket）](https://support.huaweicloud.com/sdkreference-sis/sis_05_0004.html)章节获取并运行。
```
import com.huawei.sis.bean.AuthInfo;
import com.huawei.sis.bean.SisConfig;
import com.huawei.sis.bean.SisConstant;
import com.huawei.sis.bean.request.RasrRequest;
import com.huawei.sis.bean.response.RasrResponse;
import com.huawei.sis.bean.response.StateResponse;
import com.huawei.sis.client.RasrClient;
import com.huawei.sis.bean.RasrListener;
import com.huawei.sis.util.JsonUtils;
/**
 * 实时语音识别demo
 *
 * Copyright 2021 Huawei Technologies Co.,Ltd.
 */
public class RasrDemo {
  private static final int DEFAULT_HEAD_SILENCE_TIME = 1000;
  private static final int DEFAULT_TAIL_SILENCE_TIME = 500;
  private static final int DEFAULT_CONTINUE_SECONDS = 30;
  // 认证用的ak和sk硬编码到代码中或者明文存储都有很大的安全风险，建议在配置文件或者环境变量中密文存放，使用时解密，确保安全；
  // 本示例以ak和sk保存在环境变量中来实现身份验证为例，运行本示例前请先在本地环境中设置环境变量HUAWEICLOUD_SDK_AK和HUAWEICLOUD_SDK_SK。
  private String ak = System.getenv("HUAWEICLOUD_SDK_AK");
  private String sk = System.getenv("HUAWEICLOUD_SDK_SK");
  private String region = "";         // 区域，如cn-north-1、cn-north-4
  private String projectId = "";      // 项目id。登录管理控制台，鼠标移动到右上角的用户名上，在下拉列表中选择我的凭证，在项目列表中查看项目id。多项目时，展开“所属区域”，从“项目ID”列获取子项目ID。
  private String path = "";           // 本地音频路径，如D:/test.wav, 也可将音频文件、音频流转换为byte数组后进行传送。
  private String audioFormat = "";    // 音频格式，如pcm16k16bit
  private String property = "chinese_16k_general";       // 属性字符串，language_sampleRate_domain，16模型推荐使用chinese_16k_general
  /**
   * 实时语音识别参数设置，所有参数设置均为可选，均有默认值。用户根据需求设置参数。
   *
   * @param request request请求，包含各种参数
   */
  private void setParameters(RasrRequest request) {
    // 1. 设置是否添加标点符号，yes 或 no， 默认"no"
    request.setAddPunc("yes");
    // 2. 设置头部的最大静音时间，[0,60000], 默认10000ms
    request.setVadHead(DEFAULT_HEAD_SILENCE_TIME);
    // 3. 设置尾部最大静音时间，[0, 3000], 默认500ms，
    request.setVadTail(DEFAULT_TAIL_SILENCE_TIME);
    // 4. 设置最长持续时间，仅在continue-stream，sentence-stream模式下起作用，[1, 60], 默认30s
    request.setMaxSeconds(DEFAULT_CONTINUE_SECONDS);
    // 5. 设置是否显示中间结果，yes或no，默认“no”。例如分3次发送音频，选择no结果一次性返回，选择yes分三次返回。
    request.setIntermediateResult("no");
    // 6. 设置热词表id, 若没有则设置，否则会报错。
    // request.setVocabularyId("");
    // 7. 设置是否将音频中数字转写为阿拉伯数字，yes or no，默认yes
    request.setDigitNorm("no");
    // 8. 设置是否需要word_info，yes or no, 默认no
    request.setNeedWordInfo("no");
  }
  /**
   * 定义config，所有参数可选，设置超时时间等。
   *
   * @return SisConfig
   */
  private SisConfig getConfig() {
    SisConfig config = new SisConfig();
    // 设置连接超时，默认10000ms
    config.setConnectionTimeout(SisConstant.DEFAULT_CONNECTION_TIMEOUT);
    // 设置读取超时，默认10000ms
    config.setReadTimeout(SisConstant.DEFAULT_READ_TIMEOUT);
    // 设置pingInterval，默认5000ms，当并发较大时，建议把此值设置大一些。如果不需要ping，可设置为-1
    // config.setPingInterval(-1);
    // 设置代理, 一定要确保代理可用才启动此设置。 代理初始化也可用不加密的代理，new ProxyHostInfo(host, port);
    // ProxyHostInfo proxy = new ProxyHostInfo(host, port, username, password);
    // config.setProxy(proxy);
    return config;
  }
  /**
   * 获取监听器，监听器的监听函数。
   *
   * @return RasrListener，用于监听实时语音识别的开始、识别结果、结束以及失败响应
   */
  private RasrListener getRasrListener() {
    RasrListener rasrListener = new RasrListener() {
      @Override
      /**
       * 连接成功回调
       */
      public void onTranscriptionConnect() {
        System.out.println("websocket connected");
      }
      @Override
      /**
       * 断开连接回调
       */
      public void onTranscriptionClose() {
        System.out.println("websocket closed");
      }
      @Override
      /**
       * 响应结果回调
       */
      public void onTranscriptionResponse(RasrResponse response) {
        printResponse(response);
      }
      @Override
      /**
       * 识别开始回调
       */
      public void onTranscriptionBegin(StateResponse response) {
        printResponse(response);
      }
      @Override
      /**
       * 识别结束回调
       */
      public void onSTranscriptionEnd(StateResponse response) {
        printResponse(response);
      }
      @Override
      /**
       * 识别出错回调
       */
      public void onTranscriptionFail(StateResponse response) {
        printResponse(response);
      }
      @Override
      public void onVoiceStart() {
        log.info("voice start event");
      }
      @Override
      public void onVoiceEnd() {
        log.info("voice end event");
      }
      @Override
      public void onExcceededSilence() {
        log.error("exceeded silence event");
      }
      @Override
      public void onExceededAudio() {
        log.error("exceeded audio event");
      }
      @Override
      public void onEvent(String event) {
        log.warn("receive event {}", event);
      }
    };
    return rasrListener;
  }
  private void printResponse(Object response) {
    try {
      System.out.println(JsonUtils.obj2Str(response, true));
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
  /**
   * 实时语音识别SDK的工作流程
   */
  private void process() {
    // 1. 实现监听器接口RasrListener，用户自定义收到响应的处理逻辑。
    RasrListener rasrListener = getRasrListener();
    // 2. 初始化RasrClient
    AuthInfo authInfo = new AuthInfo(ak, sk, region, projectId);
    RasrClient rasrClient = new RasrClient(authInfo, rasrListener, getConfig());
    try {
      // 3. 配置参数
      // audioFormat为支持格式、property为属性字符串
      RasrRequest request = new RasrRequest(audioFormat, property);
      setParameters(request);
      // 4 选择连接模式，目前实时语音识别提供三种接口，流式一句话、实时语音识别连续模式、实时语音识别单句模式
      // 选择1 流式一句话连接
      // rasrClient.shortStreamConnect(request);
      // 选择2，实时语音识别单句模式
      // rasrClient.sentenceStreamConnect(request);
      // 选择3，实时语音识别连续模式
      rasrClient.continueStreamConnect(request);
      // 设置企业id, 可选
      // Map<String, String> headers = OKHttpClientUtils.getJsonHeaders();
      // headers.put(SisConstant.ENTERPRISE_PROJECT_ID_KEY, "your enterprise_id");
      // rasrClient.continueStreamConnect(headers, request);
      // 5. 发送开始请求、发送音频、发送end请求
      // 发送开始请求，即将开始请求连带配置发送至服务端
      rasrClient.sendStart();
      // 发送数据，在实时语音连续模式下可多次发送。识别结果可以通过监听器获取
      // 可以自己控制发送速率.byteLen为每次发送大小，sleepTime为每次发送后睡眠时间(ms)，一些非持续获取音频场景不需要睡眠，可设置为0.
      rasrClient.sendAudio(path, 3200, 200);
      // rasrClient.sendAudio(path);
      // 可直接发送byte流,即byte数组
      // byte[] data = IOUtils.getFileData(path);
      // rasrClient.sendByte(data);
      // rasrClient.sendByte(data, byteLen, sleepTime);
      // 发送结尾请求
      rasrClient.sendEnd();
    } catch (Exception e) {
      e.printStackTrace();
    
    } finally {
      // 6. 关闭客户端。发送完毕后，此步一定要实施，否则服务端因为20s没有接收任何消息而报异常。
      rasrClient.close();
    }
  }
  public static void main(String[] args) {
    RasrDemo rasrDemo = new RasrDemo();
    rasrDemo.process();
  }
}
```
