【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; } } }
注:灵云的离线语音能力,第一次使用的时候也是需要有一个联网授权的过程,授权成功以后,即可在授权期内使用离线语音能力。
相关文章推荐
- 【Android】灵云手写离线识别使用说明
- Android平台使用PocketSphinx做离线语音识别,小范围语音99%识别率
- 【Android】灵云在线语音识别使用说明
- Android平台使用PocketSphinx做离线语音识别,小范围语音99%识别率
- Android平台使用PocketSphinx做离线语音识别,小范围语音99%识别率
- android语音识别方法一:使用intent调用语音识别程序
- android语音识别之科大讯飞语音API的使用
- Android离线语音识别-中英文,小范围,高准确率
- android语音识别之科大讯飞语音API的使用
- Android离线语音识别demo调试(Ubuntu12.04)
- Android下PocketSphinx的离线语音识别
- android语音识别之科大讯飞语音API的使用
- 转:android语音识别之科大讯飞语音API的使用
- android 开发:讯飞的离线命令识别器官方demo使用及demo下载
- Android下通过pocketsphinx实现离线语音识别的环境搭建和demo运行(续)--实现Windows下的语音识别
- 转载 android语音识别之科大讯飞语音API的使用
- android语音识别之科大讯飞语音API的使用
- android离线语音识别demo
- Android下通过pocketsphinx实现离线语音识别的环境搭建和demo运行(续)--实现Windows下的语音识别
- android语音识别方法一:使用intent调用语音识别程序