您的位置:首页 > 移动开发 > Android开发

【Android】灵云离线语音识别使用说明

2016-12-27 10:30 489 查看

注册

使用灵云的语音识别功能需要先在官网上进行注册应用。官网地址

注册比较简单,就不做过多介绍了,注册完应用以后,在后台创建自己的应用,创建完应用以后需要给应用开通对应的语音能力。



capKey说明:

asr.cloud.freetalk 云端自由说识别功能

asr.cloud.dialog 云端自由说+语义理解功能

asr.cloud.grammar 云端语法识别功能

asr.local.grammar.v4 本地的语法识别功能

使用asr.cloud.dialog功能时,需要勾选对应的领域,以下示例按照百科领域进行测试。



集成

下载灵云的Android版本语音识别功能,下载地址

如果使用在线功能,下载对应的SDK,里面有jar包和so,就可以满足需求了。如果要使用离线的语音功能,还需要下载灵云资源文件

源码

Github

灵云离线语音识别功能

需要加入的so和jar包有:

libhci_curl.so

libhci_sys.so

libhci_sys_jni.so

libhci_asr.so

libhci_asr_jni.so

libhci_asr_local_recog.so

libstlport_shared.so

libiSpeakGrmDNNLite.so

libgrm_decoder.conf.so

libispk_aux.dat.so

libispk_dnn.dat.so

libispk_g2p.dat.so

hcicloud-5.0.jar

hcicloud_recorder-5.0.jar

需要使用的权限

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>


加载配置类

package com.miao.test.util;

/**
* 灵云配置信息
* Created by 10048 on 2016/12/3.
*/
public class ConfigUtil {
/**
* 灵云APP_KEY
*/
public static final String APP_KEY = "c85d54f1";

/**
* 开发者密钥
*/
public static final String DEVELOPER_KEY = "712ddd892cf9163e6383aa169e0454e3";

/**
* 灵云云服务的接口地址
*/
public static final String CLOUD_URL = "test.api.hcicloud.com:8888";

/**
* 需要运行的灵云能力
*/
// 云端自由说
public static final String CAP_KEY_ASR_CLOUD_FREETALK = "asr.cloud.freetalk";

// 云端语音识别+语义
public static final String CAP_KEY_ASR_CLOUD_DIALOG = "asr.cloud.dialog";

// 离线命令词
public static final String CAP_KEY_ASR_LOCAL_GRAMMAR = "asr.local.grammar.v4";

// 在线命令词
public static final String CAP_KEY_ASR_CLOUD_GRAMMAR = "asr.cloud.grammar";
}


封装灵云系统的初始化功能

package com.example.sinovoice.util;

import android.content.Context;
import android.os.Environment;
import android.util.Log;

import com.sinovoice.hcicloudsdk.api.HciCloudSys;
import com.sinovoice.hcicloudsdk.common.AuthExpireTime;
import com.sinovoice.hcicloudsdk.common.HciErrorCode;
import com.sinovoice.hcicloudsdk.common.InitParam;

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;

/**
* Created by miaochangchun on 2016/11/28.
*/
public class HciCloudSysHelper {
private static final String TAG = HciCloudSysHelper.class.getSimpleName();
private static HciCloudSysHelper mHciCloudSysHelper = null;

private HciCloudSysHelper(){
}

public static HciCloudSysHelper getInstance() {
if (mHciCloudSysHelper == null) {
return  new HciCloudSysHelper();
}
return  mHciCloudSysHelper;
}

/**
* 初始化函数
* @param context
* @return
*/
public int init(Context context){
//配置串参数
String strConfig = getInitParam(context);
int errCode = HciCloudSys.hciInit(strConfig, context);
if (errCode != HciErrorCode.HCI_ERR_NONE){
Log.e(TAG, "hciInit Failed and return errcode = " + errCode);
return errCode;
}

errCode = checkAuthAndUpdateAuth();
if (errCode != HciErrorCode.HCI_ERR_NONE) {
Log.e(TAG, "checkAuthAndUpdateAuth Failed and return errcode = " + errCode);
return errCode;
}
return HciErrorCode.HCI_ERR_NONE;
}

/**
* 获取授权
* @return
*/
private int checkAuthAndUpdateAuth() {
// 获取系统授权到期时间
AuthExpireTime objExpireTime = new AuthExpireTime();
int initResult = HciCloudSys.hciGetAuthExpireTime(objExpireTime);
if (initResult == HciErrorCode.HCI_ERR_NONE) {
// 显示授权日期,如用户不需要关注该值,此处代码可忽略
Date date = new Date(objExpireTime.getExpireTime() * 1000);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd", Locale.CHINA);
Log.i(TAG, "expire time: " + sdf.format(date));

if (objExpireTime.getExpireTime() * 1000 > System.currentTimeMillis()) {
// 已经成功获取了授权,并且距离授权到期有充足的时间(>7天)
Log.i(TAG, "checkAuth success");
return initResult;
}
}

// 获取过期时间失败或者已经过期
initResult = HciCloudSys.hciCheckAuth();
if (initResult == HciErrorCode.HCI_ERR_NONE) {
Log.i(TAG, "checkAuth success");
return initResult;
} else {
Log.e(TAG, "checkAuth failed: " + initResult);
return initResult;
}
}

/**
* 获取配置传参数
* @param context
* @return
*/
private String getInitParam(Context context) {
InitParam initParam = new InitParam();
//灵云云服务的接口地址,此项必填
initParam.addParam(InitParam.AuthParam.PARAM_KEY_APP_KEY, ConfigUtil.APP_KEY);
//灵云云服务的接口地址,此项必填
initParam.addParam(InitParam.AuthParam.PARAM_KEY_DEVELOPER_KEY, ConfigUtil.DEVELOPER_KEY);
//灵云云服务的接口地址,此项必填
initParam.addParam(InitParam.AuthParam.PARAM_KEY_CLOUD_URL, ConfigUtil.CLOUD_URL);

String authPath = context.getFilesDir().getAbsolutePath();
//授权文件所在路径,此项必填
initParam.addParam(InitParam.AuthParam.PARAM_KEY_AUTH_PATH, authPath);

//日志数目,默认保留多少个日志文件,超过则覆盖最旧的日志
initParam.addParam(InitParam.LogParam.PARAM_KEY_LOG_FILE_COUNT, "5");
String logPath = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator
+ "sinovoice" + File.separator
+ context.getPackageName() + File.separator
+ "log" + File.separator;
File file = new File(logPath);
if (!file.exists()) {
file.mkdirs();
}
//日志的路径,可选,如果不传或者为空则不生成日志
initParam.addParam(InitParam.LogParam.PARAM_KEY_LOG_FILE_PATH, logPath);
Log.d(TAG, "logPath = " + logPath);
//日志大小,默认一个日志文件写多大,单位为K
initParam.addParam(InitParam.LogParam.PARAM_KEY_LOG_FILE_SIZE, "1024");
//日志等级,0=无,1=错误,2=警告,3=信息,4=细节,5=调试,SDK将输出小于等于logLevel的日志信息
initParam.addParam(InitParam.LogParam.PARAM_KEY_LOG_LEVEL, "5");

return initParam.getStringConfig();
}

/**
* 反初始化
* @return
*/
public int release(){
return HciCloudSys.hciRelease();
}
}


封装灵云语音识别功能

package com.example.sinovoice.util;

import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;

import com.sinovoice.hcicloudsdk.android.asr.recorder.ASRRecorder;
import com.sinovoice.hcicloudsdk.common.asr.AsrConfig;
import com.sinovoice.hcicloudsdk.common.asr.AsrInitParam;
import com.sinovoice.hcicloudsdk.common.asr.AsrRecogResult;
import com.sinovoice.hcicloudsdk.recorder.ASRRecorderListener;
import com.sinovoice.hcicloudsdk.recorder.RecorderEvent;

/**
* Created by miaochangchun on 2016/11/28.
*/

public class HciCloudAsrHelper {
private static final String TAG = HciCloudAsrHelper.class.getSimpleName();
public static final int RECORDER_STATE = 3;
public static final int RECORDER_ERROR = 2;
public static final int RECORDER_RESULT = 1;
public static final int RECORDER_GRAMMAR = 4;
private static HciCloudAsrHelper mHciCloudAsrHelper = null;
private ASRRecorder mASRRecorder;
private Handler myHander;
//    private String voicePath;   //音频文件保存路径

//    public void setVoicePath(String voicePath) {
//        this.voicePath = voicePath;
//    }

//    public String getVoicePath() {
//        return voicePath;
//    }

private HciCloudAsrHelper() {
}

public static HciCloudAsrHelper getInstance() {
if (mHciCloudAsrHelper == null) {
return new HciCloudAsrHelper();
}
return mHciCloudAsrHelper;
}

public Handler getMyHander() {
return myHander;
}

public void setMyHander(Handler myHander) {
this.myHander = myHander;
}

/**
* 录音机初始化
*
* @param context     上下文
* @param grammarConfigString   语法配置参数
* @param grammarData   添加的grammar语法内容
* @param initCapkeys 初始化录音机时设置的capkey,可以设置为多个
* @return true录音机初始化成功,false录音机初始化失敗
*/
public boolean initAsrRecorder(Context context, String grammarConfigString, String grammarData, String initCapkeys) {
mASRRecorder = new ASRRecorder();
String strConfig = getAsrI
e449
nitParam(context, initCapkeys);
//更新grammar的UI
Message message = new Message();
message.arg1 = RECORDER_GRAMMAR;
Bundle bundle = new Bundle();
bundle.putString("grammar", "语法:" + grammarData);
message.setData(bundle);
myHander.sendMessage(message);
mASRRecorder.init(strConfig, grammarConfigString, grammarData, new ASRRecorderCallback());

if (mASRRecorder.getRecorderState() == ASRRecorder.RECORDER_STATE_IDLE) {
return true;
} else {
return false;
}
}

/**
* 获取初始化时的参数配置
*
* @param context     上下文
* @param initCapkeys 需要初始化的capkey,可以设置为多个
* @return
*/
private String getAsrInitParam(Context context, String initCapkeys) {
AsrInitParam asrInitParam = new AsrInitParam();
asrInitParam.addParam(AsrInitParam.PARAM_KEY_INIT_CAP_KEYS, initCapkeys);
asrInitParam.addParam(AsrInitParam.PARAM_KEY_FILE_FLAG, "android_so");
String dataPath = context.getFilesDir().getAbsolutePath().replace("files", "lib");
asrInitParam.addParam(AsrInitParam.PARAM_KEY_DATA_PATH, dataPath);
return asrInitParam.getStringConfig();
}

/**
* 开启录音机识别
*
* @param capkey 开启录音机时使用的capkey
* @param domain 设置识别的领域,没有特殊设置,domain=common
*/
public void startAsrRecorder(String capkey, String domain) {
if (mASRRecorder.getRecorderState() == ASRRecorder.RECORDER_STATE_IDLE) {
String strConfig = getAsrConfigParam(capkey, domain);
mASRRecorder.start(strConfig);
}
}

/**
* 获取asr识别时的配置参数
*
* @param capkey 录音机识别是的配置参数capkey
* @param domain 设置的领域值
* @return
*/
private String getAsrConfigParam(String capkey, String domain) {
AsrConfig asrConfig = new AsrConfig();
asrConfig.addParam(AsrConfig.AudioConfig.PARAM_KEY_AUDIO_FORMAT, "pcm16k16bit");
asrConfig.addParam(AsrConfig.AudioConfig.PARAM_KEY_ENCODE, "speex");
asrConfig.addParam(AsrConfig.SessionConfig.PARAM_KEY_CAP_KEY, capkey);
asrConfig.addParam(AsrConfig.SessionConfig.PARAM_KEY_REALTIME, "yes");
asrConfig.addParam(AsrConfig.ResultConfig.PARAM_KEY_ADD_PUNC, "yes");
asrConfig.addParam(AsrConfig.ResultConfig.PARAM_KEY_DOMAIN, domain);
return asrConfig.getStringConfig();
}

/**
* 录音机release接口
*/
public void releaseAsrRecorder() {
if (mASRRecorder != null) {
mASRRecorder.release();
}
}

/**
* ASR录音机回调类
*/
private class ASRRecorderCallback implements ASRRecorderListener {
String result = "";
@Override
public void onRecorderEventStateChange(RecorderEvent recorderEvent) {
String state = "初始状态";
if (recorderEvent == RecorderEvent.RECORDER_EVENT_BEGIN_RECORD) {
state = "开始录音";
} else if (recorderEvent == RecorderEvent.RECORDER_EVENT_BEGIN_RECOGNIZE) {
state = "开始识别";
} else if (recorderEvent == RecorderEvent.RECORDER_EVENT_NO_VOICE_INPUT) {
state = "无音频输入";
} else if (recorderEvent == RecorderEvent.RECORDER_EVENT_HAVING_VOICE) {
state = "录音中";
} else if (recorderEvent == RecorderEvent.RECORDER_EVENT_END_RECORD) {
state = "录音结束";
} else if (recorderEvent == RecorderEvent.RECORDER_EVENT_RECOGNIZE_COMPLETE) {
state = "识别结束";
} else if (recorderEvent == RecorderEvent.RECORDER_EVENT_VOICE_BUFFER_FULL) {
state = "缓冲满";
}

//把录音机状态传递到Activity上
Message message = new Message();
message.arg1 = RECORDER_STATE;
Bundle bundle = new Bundle();
bundle.putString("state", "录音机状态:" + state);
message.setData(bundle);
myHander.sendMessage(message);
}

@Override
public void onRecorderEventRecogFinsh(RecorderEvent recorderEvent, AsrRecogResult asrRecogResult) {
if (asrRecogResult != null) {
if (asrRecogResult.getRecogItemList().size() > 0) {
//识别结果
result = asrRecogResult.getRecogItemList().get(0).getRecogResult();
//置信度
int score = asrRecogResult.getRecogItemList().get(0).getScore();

//把识别结果传递到Activity上
Message message = new Message();
message.arg1 = RECORDER_RESULT;
Bundle bundle = new Bundle();
bundle.putString("result", "识别结果是:" + result + "\t置信度:" + score);
message.setData(bundle);
myHander.sendMessage(message);
}
}
}

@Override
public void onRecorderEventRecogProcess(RecorderEvent recorderEvent, AsrRecogResult asrRecogResult) {
}

@Override
public void onRecorderEventError(RecorderEvent recorderEvent, int i) {
String error = "" + i;

//把错误信息传递到Activity上
Message message = new Message();
message.arg1 = RECORDER_ERROR;
Bundle bundle = new Bundle();
bundle.putString("error", "错误码:" + error);
message.setData(bundle);
myHander.sendMessage(message);
}

@Override
public void onRecorderRecording(byte[] bytes, int i) {
//            File file = new File(voicePath);
//            if (!file.exists()) {
//                file.getParentFile().mkdirs();
//                try {
//                    file.createNewFile();
//                } catch (IOException e) {
//                    e.printStackTrace();
//                }
//            }
//            try {
//                FileOutputStream outputStream = new FileOutputStream(file);
//                outputStream.write(bytes);
//                outputStream.close();
//            } catch (FileNotFoundException e) {
//                e.printStackTrace();
//            } catch (IOException e) {
//                e.printStackTrace();
//            }
}
}
}


在MainActivity中使用语音识别的功能

package com.example.sinovoice.asrgrammarsample;

import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

import com.example.sinovoice.util.ConfigUtil;
import com.example.sinovoice.util.HciCloudAsrHelper;
import com.example.sinovoice.util.HciCloudSysHelper;
import com.sinovoice.hcicloudsdk.common.HciErrorCode;

import java.io.UnsupportedEncodingException;

public class MainActivity extends AppCompatActivity implements View.OnClickListener{
private Button btnStart;
private TextView tvState;
private TextView tvError;
private TextView tvResult;
private HciCloudSysHelper mHciCloudSysHelper;
private HciCloudAsrHelper mHciCloudAsrHelper;
private TextView tvGrammar;

private class MyHandler extends Handler {

@Override
public void handleMessage(Message msg) {
switch (msg.arg1) {
case HciCloudAsrHelper.RECORDER_RESULT: //显示识别结果
Bundle resultBundle = msg.getData();
String result = resultBundle.getString("result");
tvResult.setText(result);
break;
case HciCloudAsrHelper.RECORDER_ERROR:  //显示错误信息
Bundle errorBundle = msg.getData();
String error = errorBundle.getString("error");
System.out.print(error);
if (error.equals("0")) {
tvError.setVisibility(View.GONE);
} else {
tvError.setText(error);
}
break;
case HciCloudAsrHelper.RECORDER_STATE:  //显示录音机的状态
Bundle stateBundle = msg.getData();
String state = stateBundle.getString("state");
tvState.setText(state);
break;
case HciCloudAsrHelper.RECORDER_GRAMMAR:
Bundle grammarBundle = msg.getData();
String grammar = grammarBundle.getString("grammar");
tvGrammar.setText(grammar);
break;
default:
break;
}
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();

initSinovoice();
}

private void initSinovoice() {
mHciCloudSysHelper = HciCloudSysHelper.getInstance();
mHciCloudAsrHelper = HciCloudAsrHelper.getInstance();
int errorCode = mHciCloudSysHelper.init(this);
if (errorCode != HciErrorCode.HCI_ERR_NONE) {
Toast.makeText(this, "系统初始化失败,错误码=" + errorCode, Toast.LENGTH_SHORT).show();
return;
}
mHciCloudAsrHelper.setMyHander(new MyHandler());
String grammarData = "#JSGF V1.0;\n" +
"\n" +
"grammar stock_1001;\n" +
"\n" +
"public <stock_1001> =     万东医疗 |\n" +
"                          三峡水利 |\n" +
"                          上海机场 |\n" +
"                          上海梅林 |\n" +
"                          上海汽车 |\n" +
"                          上港集箱 |\n" +
"                          东北高速 |\n" +
"                          东方航空 |\n" +
"                          东湖高新 |\n" +
"                          东风汽车 |\n" +
"                          东风科技 |\n" +
"                          中国国贸 |\n" +
"                          中国泛旅 |\n" +
"                          中技贸易 |\n" +
"                          中纺投资 |\n" +
"                          中视股份 |\n" +
"                          乐凯胶片 |\n" +
"                          云天化 |\n" +
"                          亚盛集团 |\n" +
"                          人福科技 |\n" +
"                          光彩建设;" ;
String grammarConfigString = "capkey=" + ConfigUtil.CAP_KEY_ASR_LOCAL_GRAMMAR + ",isFile=no,grammarType=jsgf";
boolean bool = false;
try {
bool = mHciCloudAsrHelper.initAsrRecorder(this, grammarConfigString, new String(grammarData.getBytes(), "utf-8"), ConfigUtil.CAP_KEY_ASR_LOCAL_GRAMMAR);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
if (bool == false) {
Toast.makeText(this, "录音机初始化失败", Toast.LENGTH_SHORT).show();
return;
}else{      //隐藏错误码的状态栏
Message message = new Message();
message.arg1 = HciCloudAsrHelper.RECORDER_ERROR;
Bundle bundle = new Bundle();
bundle.putString("error", "0");
message.setData(bundle);
new MyHandler().sendMessage(message);
}
}

private void initView() {
btnStart = (Button) findViewById(R.id.btn_start);
tvState = (TextView) findViewById(R.id.tv_state);
tvError = (TextView) findViewById(R.id.tv_error);
tvResult = (TextView) findViewById(R.id.tv_result);
tvGrammar = (TextView) findViewById(R.id.tv_grammar);

btnStart.setOnClickListener(this);
}

@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_start:
mHciCloudAsrHelper.startAsrRecorder(ConfigUtil.CAP_KEY_ASR_LOCAL_GRAMMAR, "common");
break;
default:
break;
}
}
}


注:灵云的离线语音能力,第一次使用的时候也是需要有一个联网授权的过程,授权成功以后,即可在授权期内使用离线语音能力。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: