
# 实时语音识别连续模式
#### 前提条件
- 确保已经按照配置好Android开发环境。
- 请参考[SDK（websocket）](https://support.huaweicloud.com/sdkreference-sis/sis_05_0004.html)获取最新版本SDK包。
 
#### 初始化Client
初始化RasrClient，其中参数包含AuthInfo,SisHttpCnfig,RasrResponseListener,RasrConnProcessListener
表1RasrClient 
| 参数名称                    | 是否必选 | 参数类型   | 描述                            |
|:---|:---|:---|:---|
| AuthInfo                | 是    | Object | 鉴权信息类。                        |
| SisHttpCnfig            | 是    | Object | 连接时网络的配置类。                    |
| RasrResponseListener    | 是    | Object | webSocket回调过程中，业务逻辑的Listener。 |
| RasrConnProcessListener | 否    | Object | webSocket生命周期的Listener。       |
   
表2AuthInfo 
| 参数名称            | 是否必选 | 参数类型   | 描述                                                                                     |
|:---|:---|:---|:---|
| 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)。 |
| serviceRegion   | 是    | 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)。 |
| serviceEndPoint | 否    | String | 终端节点，参考[终端节点](https://developer.huaweicloud.com/endpoint?SIS)。                         |
   
表3SisHttpConfig 
| 参数名称                 | 是否必选 | 参数类型          | 描述                               |
|:---|:---|:---|:---|
| connectionTimeout    | 否    | Integer       | 连接超时，默认10000，单位ms。               |
| readTimeout          | 否    | Integer       | 读取超时，默认10000，单位ms。               |
| websocketWaitTimeout | 否    | Integer       | webSocket返回数据时等待时间，默认20000，单位毫秒。 |
| ProxyHostInfo        | 否    | ProxyHostInfo | 代理类。                             |
   
表4ProxyHostInfo 
| 参数名称     | 是否必选 | 参数类型   | 描述                               |
|:---|:---|:---|:---|
| userName | 否    | String | 代理用户名（例：test）。                   |
| passWord | 否    | String | 代理密码（例：test）。                    |
| hostName | 否    | String | 代理地址（例："proxy.huaweicloud.com"）。 |
| port     | 否    | int    | 代理端口号（例：8080）。                   |
   
表5RasrResponseListener 
| 函数                                           | 描述                                                                                        |
|:---|:---|
| void onResponseBegin(AsrResponse response);  | 识别开始时回调。                                                                                  |
| void onResponseEnd(AsrResponse response);    | 识别结束时回调。                                                                                  |
| void onResponseError(AsrResponse response);  | 识别过程中出现异常，调用。                                                                             |
| void onResponseMessage(AsrResponse message); | 返回识别的结果。                                                                                  |
| void onVoiceStart();                         | 单句模式下，响应VOICE_START事件，表示检测到语音，此时IVR可以做打断（连续模式可忽略）。                                        |
| void onVoiceEnd();                           | 单句模式下，响应VOICE_END事件，表示一句话结束，后续的音频将被忽略，不会再进行识别（连续模式可忽略）。                                   |
| void onExcceededSilence();                   | 单句模式下，响应EXCEEDED_SILENCE事件，表示超过vad_head没有检测到声音，通常表示用户一直没有说话。此时后续的音频将被忽略，不会再进行识别（连续模式可忽略）。 |
   
表6RasrConnProcessListener 
| 函数                                          | 描述                   |
|:---|:---|
| void onTranscriptionConnect()               | webSocket连接建立后回调。    |
| void onTranscriptionClose();                | webSocket连接关闭后回调。    |
| void onTranscriptionFail(AsrResponse var1); | webSocket长连接连接失败时回调。 |
   
#### 请求参数
请求类为RasrRequest，其中参数详见下表
表7RasrRequest 
| 参数名称    | 是否必选 | 参数类型   | 描述                                           |
|:---|:---|:---|:---|
| command | 是    | String | 需设置为START，表示开始识别请求;发送END，表示识别结束请求。           |
| config  | 是    | Object | 配置信息，详见[表8]。 |
   
 表8Config 
| 参数名称               | 是否必选 | 参数类型    | 描述                                                                                                                                   |
|:---|:---|:---|:---|
| 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)章节。 |
| addPunc            | 否    | String  | 表示是否在识别结果中添加标点，取值为yes 、 no，默认no。                                                                                                     |
| digitNorm          | 否    | String  | 表示是否将语音中的数字识别为阿拉伯数字，取值为yes 、 no，默认为yes。                                                                                              |
| vadHead            | 否    | Integer | 头部最大静音时间，\[0, 60000\]，默认10000ms。                                                                                                     |
| vadTail            | 否    | Integer | 尾部最大静音时间，\[0, 3000\]，默认500ms。                                                                                                        |
| maxSeconds         | 否    | Integer | 音频最长持续时间， \[1, 60\]，默认30s。                                                                                                           |
| intermediateResult | 否    | String  | 是否显示中间结果，yes 或 no，默认no。例如分3次发送音频，选择no结果一次性返回，选择yes分三次返回。                                                                             |
| vocabularyId       | 否    | String  | 热词表id，若没有则不填。                                                                                                                        |
| needWordInfo       | 否    | String  | 表示是否在识别结果中输出分词结果信息，取值为"yes"和"no"，默认为"no"。                                                                                            |
   
#### 设置当前Client为连续模式
```
rasrClient.rasrContinueStreamConnect();
```
#### 建立连接
```
rasrClient.connect();
```
#### 发送开始识别指令和配置信息
```
rasrClient.sendStart(getStartRequest());
```
#### 发送识别数据
```
// data：发送byte数组
// byteSend :数组大小
// sleepTime : 休眠时间
rasrClient.sendByte(byte[] data, int byteSend, int sleepTime);
```
#### 发送结束指令
```
rasrClient.sendEnd();
```
#### 发送关闭连接请求
```
rasrClient.close();
```
#### 代码示例
如下示例仅供参考，最新代码请前往[SDK（websocket）](https://support.huaweicloud.com/sdkreference-sis/sis_05_0004.html)章节获取并运行。
```
/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2022-2022. All rights reserved.
 */
package com.huaweicloud.sis.android.demo.asr;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import com.huaweicloud.sis.android.demo.Config;
import com.huaweicloud.sis.android.demo.service.AudioRecordService;
import com.huaweicloud.sdk.core.utils.JsonUtils;
import com.huaweicloud.sis.android.demo.R;
import sis.android.sdk.RasrClient;
import sis.android.sdk.bean.AuthInfo;
import sis.android.sdk.bean.SisHttpConfig;
import sis.android.sdk.exception.SisException;
import sis.android.sdk.bean.request.RasrRequest;
import sis.android.sdk.bean.response.AsrResponse;
import sis.android.sdk.listeners.RasrResponseListener;
import sis.android.sdk.listeners.process.RasrConnProcessListener;
/**
 * 功能描述
 * 实时语音识别连续模式
 *
 * @since 2022-07-11
 */
public class RasrCsActivity extends AppCompatActivity {
    private TextView title;
    private TextView result;
    private Button startButton;
    private Button endButton;
    private RasrClient rasrClient;
    // 实时显示识别的结果
    private StringBuffer realTimeResult;
    private AudioRecordService audioRecordService;
    private AuthInfo authInfo;
    private RasrConnProcessListener rasrConnProcessListener = new RasrConnProcessListener() {
        /**
         * 连接关闭后回调
         */
        @Override
        public void onTranscriptionClose() {
            Log.i("info", "长连接关闭");
        }
        /**
         * 连接建立后回调
         */
        @Override
        public void onTranscriptionConnect() {
            Log.i("info", "长连接开始");
        }
        /**
         * 长连接连接失败时回调
         *
         * @param asrResponse 返回体
         */
        @Override
        public void onTranscriptionFail(AsrResponse asrResponse) {
            Log.i("info", "长连接异常");
            // 调用失败给用户提示
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    Toast.makeText(getApplicationContext(), "实时语音单句模式长连接失败" + JsonUtils.toJSON(asrResponse), Toast.LENGTH_SHORT).show();
                }
            });
            rasrClient.close();
        }
    };
    private RasrResponseListener rasrResponseListener = new RasrResponseListener() {
        /**
         * 检测到句子开始事件
         */
        @Override
        public void onVoiceStart() {
        }
        /**
         * 检测到句子结束事件
         */
        @Override
        public void onVoiceEnd() {
        }
        /**
         * 返回识别的信息
         * @param message
         */
        @Override
        public void onResponseMessage(AsrResponse message) {
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    for (int i = 0; i < message.getSegments().size(); i++) {
                        AsrResponse.Segment segment = message.getSegments().get(i);
                        // 实时语音识别连续模式 回调结果更新到界面UI中
                        result.setText(realTimeResult.toString() + segment.getResult().getText());
                        if (segment.getIsFinal()) {
                            realTimeResult.append(segment.getResult().getText());
                        }
                    }
                }
            });
        }
        /**
         *
         * 静音超长，即没有检测到声音。响应事件
         */
        @Override
        public void onExcceededSilence() {
        }
        /**
         * 返回识别的信息
         * @param response
         */
        @Override
        public void onResponseBegin(AsrResponse response) {
        }
        @Override
        public void onResponseEnd(AsrResponse response) {
        }
        @Override
        public void onResponseError(AsrResponse response) {
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    Toast.makeText(getApplicationContext(), "实时语音识别连续模式，错误响应:" + JsonUtils.toJSON(response), Toast.LENGTH_SHORT).show();
                }
            });
            rasrClient.close();
        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.rasr);
    }
    @Override
    protected void onStart() {
        super.onStart();
        initResources();
        initView();
    }
    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (rasrClient != null) {
            rasrClient.close();
        }
        if (audioRecordService != null && audioRecordService.getIsRecording().get()) {
            audioRecordService.stopAudioRecord();
            audioRecordService.releaseAudioRecord();
        }
    }
    /**
     * 初始化界面
     */
    private void initView() {
        result = findViewById(R.id.result);
        title = findViewById(R.id.title);
        title.setText("实时语音识别连续模式");
        startButton = findViewById(R.id.start);
        endButton = findViewById(R.id.end);
        // 定义开始按钮点击事件
        startButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                updateButtonState(startButton, false);
                updateButtonState(endButton, true);
                realTimeResult = realTimeResult.delete(0, realTimeResult.length());
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            rasrClient = new RasrClient(authInfo, rasrResponseListener, rasrConnProcessListener, new SisHttpConfig());
                            rasrClient.rasrContinueStreamConnect();
                            // 建立连接
                            rasrClient.connect();
                            rasrClient.sendStart(getStartRequest());
                            audioRecordService.startSendRecordingData(rasrClient);
                        } catch (SisException e) {
                            Log.e("error", e.getErrorCode() + e.getErrorMsg());
                        }
                    }
                }).start();
                Toast.makeText(getApplicationContext(), "正在进行录音中...", Toast.LENGTH_SHORT).show();
            }
        });
        // 结束按钮识别事件
        endButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                updateButtonState(startButton, true);
                updateButtonState(endButton, false);
                if (audioRecordService.getIsRecording().get()) {
                    audioRecordService.stopAudioRecord();
                    Toast.makeText(getApplicationContext(), "识别结束...", Toast.LENGTH_SHORT).show();
                }
                try {
                    rasrClient.sendEnd();
                } catch (SisException e) {
                    Log.e("error", e.getErrorCode() + e.getErrorMsg());
                }
                rasrClient.close();
            }
        });
        updateButtonState(startButton, true);
        updateButtonState(endButton, false);
    }
    /**
     * 初始化设置资源
     */
    private void initResources() {
        authInfo = new AuthInfo(this.getString(R.string.HUAWEICLOUD_SDK_AK), this.getString(R.string.HUAWEICLOUD_SDK_SK), 
Config.REGION, Config.PROJECT_ID);
        audioRecordService = new AudioRecordService(16000);
        realTimeResult = new StringBuffer();
    }
    /**
     * 开始请求
     *
     * @return 返回请求体内容
     */
    private RasrRequest getStartRequest() {
        RasrRequest rasrRequest = new RasrRequest();
        rasrRequest.setCommand("START");
        RasrRequest.Config config = new RasrRequest.Config();
        config.setAudioFormat("pcm16k16bit");
        config.setProperty("chinese_16k_general");
        config.setAddPunc("yes");
        config.setInterimResults("yes");
        rasrRequest.setConfig(config);
        return rasrRequest;
    }
    // 用于设置按钮的状态
    private void updateButtonState(final Button btn, final boolean state) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                btn.setEnabled(state);
            }
        });
    }
}
```
