700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > Android 科大讯飞语音评测SDK 踩坑实录

Android 科大讯飞语音评测SDK 踩坑实录

时间:2021-05-05 00:45:34

相关推荐

Android 科大讯飞语音评测SDK 踩坑实录

英语付费类APP大多都会对用户的发音进行评测的场景,一些大公司借住其高效的语音识别技术可以很轻松的实现。我司最开始接入的是腾讯云智聆SDK,但是用户反映普遍较为激烈,我们不堪其扰,于是在最新的版本中将其切换为科大讯飞SDK。

第一步,当然是登陆科大讯飞官网,开始注册账号,创建APP,本地记录下APPID,并下载相应的SDK。需要注意的是,必须下载appid对应的sdk,下载之后,需要将项目中的jar放在libs下,so库放在jniLibs下,避免出错。

第二部当然就是在本地运行科大讯飞所写的示例demo。这个时候,你会发现运行不起来。

不需要慌张,科大讯飞官网上有相应的帖子 /forum.php?mod=viewthread&tid=42878&extra=可以解决,根据帖子提示,在apply添加byildscript{}

第三步,我们可以去通过讯飞demo来初步体验语音评测了。

第四步,我们项目中已经成功接入了SDK,现在需要对录音评测的代码进行相关封装,方便多个地方的代码调用。这一步也是最为重要的一点。

4.1 SDK初始化

SpeechUtility.createUtility(this, SpeechConstant.APPID + "=APPID");SpeechEvaluator evaluator = SpeechEvaluator.createEvaluator(this, new InitListener() {@Overridepublic void onInit(int i) {}});KDflyUtils.init(evaluator);

注意,这一部分代码是放在应用启动时,我们创建了全局唯一的一个录音对象,并通过KDflyUtils(语音评测工具类)初始化,将录音对象传入工具类,方便后续调用

4.2 现在,我们来看一下封装的工具类。工具类里面我们需要具备几个作用:开始评测,结束评测,评测状态(是否正在评测),以及评测结果(成功/失败)的回调。

public static void init(SpeechEvaluator eva) {evaluator = eva;}/*** @return*/public static boolean isRecording() {return evaluator == null ? false : evaluator.isEvaluating();}private static void setParams() {if (evaluator == null) {LogUtils.i("初始化失败");return;}evaluator.setParameter(SpeechConstant.LANGUAGE, "en_us");evaluator.setParameter(SpeechConstant.ISE_CATEGORY, "read_sentence");evaluator.setParameter(SpeechConstant.TEXT_ENCODING, "utf-8");evaluator.setParameter(SpeechConstant.VAD_BOS, "5000");evaluator.setParameter(SpeechConstant.VAD_EOS, "18000");evaluator.setParameter(SpeechConstant.KEY_SPEECH_TIMEOUT, "-1");// evaluator.setParameter(SpeechConstant.RESULT_LEVEL, "complete");evaluator.setParameter(SpeechConstant.RESULT_LEVEL, "plain");evaluator.setParameter(SpeechConstant.AUDIO_FORMAT_AUE, "opus");// 设置音频保存路径,保存音频格式支持pcm、wav,设置路径为sd卡请注意WRITE_EXTERNAL_STORAGE权限evaluator.setParameter(SpeechConstant.AUDIO_FORMAT, "wav");evaluator.setParameter(SpeechConstant.ISE_AUDIO_PATH, path);}

init()方法即为我们在Application里嗲用过的初始化方法。isRecording用于判断是否正在录音,setParams()方法用于设定录音的相关参数,其中的path是我们在本地存放的录音的路径。

然后是开始录音的方法:方法极为简单,只需要传入一个需要评测的文本字符串,以及录音监听对象即可。

/***对录音过程进行监听*/ private static EvaluatorListener evaluatorListener = new EvaluatorListener() {@Overridepublic void onVolumeChanged(int i, byte[] bytes) {}@Overridepublic void onBeginOfSpeech() {LogUtils.i("onBeginOfSpeech:");}@Overridepublic void onEndOfSpeech() {LogUtils.i("onEndOfSpeech:");}@Overridepublic void onResult(EvaluatorResult result, boolean isLast) {if (isLast) {// 评测结束 解析结果}}@Overridepublic void onError(SpeechError speechError) {LogUtils.i("onError:" + speechError.getErrorDescription() + " ______" + speechError.toString());}@Overridepublic void onEvent(int i, int i1, int i2, Bundle bundle) {LogUtils.i("onEvent:" + i + "," + i1 + "," + i2);}}; /*** @param ecText 评测文本*/public static void startScore(String ecText) {//开始评测setParams();int i = evaluator.startEvaluating(ecText, null, evaluatorListener);LogUtils.i("语音评测:" + i);}

然后是结束录音的方法:

public static void stopRecording() {evaluator.stopEvaluating();}

再之后我们需要在监听里处理评测结果:onResult() 返回结果为xml格式的,因此我们通过Pull解析结果。获得评分,并保留2位小数。我写的回调方法是把录音文件转换为byte[],和评分结果返回。失败时,直接回调失败方法。

@Overridepublic void onResult(EvaluatorResult result, boolean isLast) {LogUtils.i("onResult:" + isLast + "," + result.getResultString() + "," + result.describeContents());if (isLast) {// 评测结束 解析结果 <?xml version="1.0" ?><FinalResult><ret value="0"/><total_score value="2.687397"/></FinalResult>XmlPullParser xmlPullParser = Xml.newPullParser();try {xmlPullParser.setInput(new ByteArrayInputStream(result.getResultString().getBytes()), "utf-8");int eventType = xmlPullParser.getEventType();while (eventType != XmlPullParser.END_DOCUMENT) {switch (eventType) {case XmlPullParser.START_TAG:String name = xmlPullParser.getName();if (name.equals("total_score")) {float v = Float.parseFloat(xmlPullParser.getAttributeValue(0));String format = new DecimalFormat("0.00").format(v);LogUtils.i("评测结果:" + format);RandomAccessFile r = null;try {r = new RandomAccessFile(path, "r");audioData = new byte[(int) r.length()];r.readFully(audioData);} catch (FileNotFoundException e) {e.printStackTrace();} catch (Exception e) {e.printStackTrace();} finally {if (r != null) {r.close();}}evaluateResult.onResultSuccess(audioData, Float.parseFloat(format));}break;}eventType = xmlPullParser.next();}} catch (Exception e) {e.printStackTrace();//发生异常evaluateResult.onResultFail("数据异常");}}}

最后看一下回调接口:

这样,整个公路类的封装就已经结束了,在代码中要如何调用呢?

/*** 新版科大讯飞语音评测*/private void hasPermiassionRecord() {if (!KDevaluateUtils.isRecording()) {//entitle 是需要评测的问题KDevaluateUtils.startScore(enTitle);KDevaluateUtils.setEvaluateResult(new EvaluateResult() {@Overridepublic void onResultSuccess(byte[] audioData, float score) {//评测成功}@Overridepublic void onResultFail(String errorMsg) {showInfo("网络异常,请切换网络试一下");}});} else {KDevaluateUtils.stopRecording();}}

很简单,是不是?

最后附上全部代码:

/*** 科大讯飞语音评测* Created by zhangyanpeng on /4/8*/public class KDflyUtils {private static SpeechEvaluator evaluator;private static EvaluateResult evaluateResult;public static void setEvaluateResult(EvaluateResult evaluateResult) {KDflyUtils.evaluateResult = evaluateResult;}// 本地文件路径private static String path = Environment.getExternalStorageDirectory() + "/AnnieRecord/annie.wav";private static EvaluatorListener evaluatorListener = new EvaluatorListener() {@Overridepublic void onVolumeChanged(int i, byte[] bytes) {}@Overridepublic void onBeginOfSpeech() {LogUtils.i("onBeginOfSpeech:");}@Overridepublic void onEndOfSpeech() {LogUtils.i("onEndOfSpeech:");}@Overridepublic void onResult(EvaluatorResult result, boolean isLast) {if (isLast) {LogUtils.i("onResult:" + isLast + "," + result.getResultString() + "," + result.describeContents());// 评测结束 解析结果XmlPullParser xmlPullParser = Xml.newPullParser();try {xmlPullParser.setInput(new ByteArrayInputStream(result.getResultString().getBytes()), "utf-8");int eventType = xmlPullParser.getEventType();while (eventType != XmlPullParser.END_DOCUMENT) {switch (eventType) {case XmlPullParser.START_TAG:String name = xmlPullParser.getName();if (name.equals("total_score")) {float v = Float.parseFloat(xmlPullParser.getAttributeValue(0));String format = new DecimalFormat("0.00").format(v);LogUtils.i("评测结果:" + format);evaluateResult.onResultSuccess(new byte[1024],Float.parseFloat(format));}break;case XmlPullParser.END_TAG:break;}eventType = xmlPullParser.next();}} catch (XmlPullParserException e) {e.printStackTrace();} catch (Exception e) {e.printStackTrace();}}}@Overridepublic void onError(SpeechError speechError) {LogUtils.i("onError:" + speechError.getErrorDescription() + " ______" + speechError.toString());}@Overridepublic void onEvent(int i, int i1, int i2, Bundle bundle) {LogUtils.i("onEvent:" + i + "," + i1 + "," + i2);}};public static void init(SpeechEvaluator eva) {evaluator = eva;}/*** @return*/public static boolean isRecording() {return evaluator == null ? false : evaluator.isEvaluating();}private static void setParams() {if (evaluator == null) {LogUtils.i("初始化失败");return;}evaluator.setParameter(SpeechConstant.LANGUAGE, "en_us");evaluator.setParameter(SpeechConstant.ISE_CATEGORY, "read_sentence");evaluator.setParameter(SpeechConstant.TEXT_ENCODING, "utf-8");evaluator.setParameter(SpeechConstant.VAD_BOS, "5000");evaluator.setParameter(SpeechConstant.VAD_EOS, "18000");evaluator.setParameter(SpeechConstant.KEY_SPEECH_TIMEOUT, "-1");// evaluator.setParameter(SpeechConstant.RESULT_LEVEL, "complete");evaluator.setParameter(SpeechConstant.RESULT_LEVEL, "plain");evaluator.setParameter(SpeechConstant.AUDIO_FORMAT_AUE, "opus");// 设置音频保存路径,保存音频格式支持pcm、wav,设置路径为sd卡请注意WRITE_EXTERNAL_STORAGE权限evaluator.setParameter(SpeechConstant.AUDIO_FORMAT, "wav");evaluator.setParameter(SpeechConstant.ISE_AUDIO_PATH, path);}// 开始评测public static void startScore(byte[] audio, String evText) {setParams();int ret = evaluator.startEvaluating(audio, null, evaluatorListener);if (ret != ErrorCode.SUCCESS) {LogUtils.i("识别失败,错误码:" + ret);} else {// 在startEvaluating接口调用之后,加入以下方法,即可通过直接//写入音频的方式进行评测业务try {if (audioData.length == 0) {file = new File(path);audioData = new byte[(int) file.length()];fileOutputStream = new FileOutputStream(path);fileOutputStream.write(audioData, 0, (int) file.length());}//防止写入音频过早导致失败try {new Thread().sleep(100);} catch (InterruptedException e) {LogUtils.i("文件读取失败");}evaluator.writeAudio(audioData, 0, audioData.length);evaluator.stopEvaluating();} catch (Exception e) {}}}private static FileOutputStream fileOutputStream;private static byte[] audioData;private static File file;public static void stopRecording() {evaluator.stopEvaluating();try {file = new File(path);audioData = new byte[(int) file.length()];fileOutputStream = new FileOutputStream(path);fileOutputStream.write(audioData, 0, (int) file.length());} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {}}/*** @param ecText 评测文本*/public static void startScore(String ecText) {//开始评测setParams();int i = evaluator.startEvaluating(ecText, null, evaluatorListener);LogUtils.i("语音评测:" + i);}}

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。