当前位置:   article > 正文

Unity2021接入讯飞语音听写(Android)_unity 语音听写 (流式版)

unity 语音听写 (流式版)

使用的引擎工具:

Unity2021.3.19

android-studio-2021.1.21

第一步:

新建一个Android项目(工程名字随便啦)

然后新建一个library

(同上,库名自己命名吧)

Android环境目前就算是初步建立好了。

第二步:

导包

libs文件夹里面放入这4个文件,arm64-v8a,armeabi-v7a,Msc.jar这三个文件是讯飞官网下载下来的demo项目里面的,直接复制到libs里面就好,classes.jar包是在下面这个路径下的

注:Classes.jar用mono还是IL2CPP得和Unity-PlayerSetting-ScriptBackend一致

第三步

倒入UnityPlayerActivity

最新版本Unity里面的classes.jar包文件里面以及不包含UnityPlayerActivity了,所以我们需要自己导入UnityPlayerActivity(或者自己编写一个也可以,回头可以再出一篇)

文件位置:

第四步

在AndroidStudio实现供unity调用的接口方法,直接上代码了(讯飞APPID自己填写)

  1. package com.example.mylibrary;
  2. import android.content.Context;
  3. import android.os.Bundle;
  4. import android.util.Log;
  5. import android.widget.Toast;
  6. import com.iflytek.cloud.ErrorCode;
  7. import com.iflytek.cloud.InitListener;
  8. import com.iflytek.cloud.RecognizerListener;
  9. import com.iflytek.cloud.RecognizerResult;
  10. import com.iflytek.cloud.SpeechConstant;
  11. import com.iflytek.cloud.SpeechError;
  12. import com.iflytek.cloud.SpeechRecognizer;
  13. import com.iflytek.cloud.SpeechUtility;
  14. import com.unity.upa.UnityPlayerActivity;
  15. import com.unity3d.player.UnityPlayer;
  16. import org.json.JSONException;
  17. import org.json.JSONObject;
  18. import java.util.HashMap;
  19. import java.util.LinkedHashMap;
  20. public class XunFeiSdk extends UnityPlayerActivity {
  21. private HashMap<String, String> mIatResults = new LinkedHashMap<String, String>();
  22. SpeechRecognizer mIAT;
  23. @Override
  24. protected void onCreate(Bundle savedInstanceState) {
  25. super.onCreate(savedInstanceState);
  26. SpeechUtility.createUtility(this, SpeechConstant.APPID + "=xxxxxx");//这里是你在讯飞官网上的APPID
  27. mIAT=SpeechRecognizer.createRecognizer(this,null);
  28. mIAT.setParameter(SpeechConstant.DOMAIN,"iat");
  29. // 语言
  30. mIAT.setParameter(SpeechConstant.LANGUAGE,"zh_cn");
  31. // 接收语言的类型
  32. mIAT.setParameter(SpeechConstant.ACCENT,"mandarin");
  33. // 使用什么引擎
  34. mIAT.setParameter(SpeechConstant.ENGINE_TYPE,SpeechConstant.TYPE_CLOUD);
  35. }
  36. public void StartListening() {
  37. mIAT.startListening(recognizerListener);
  38. }
  39. RecognizerListener recognizerListener = new RecognizerListener() {
  40. @Override
  41. public void onVolumeChanged(int i, byte[] bytes) {
  42. UnityPlayer.UnitySendMessage("XfManager","OnVolumeChanged","");
  43. }
  44. @Override
  45. public void onBeginOfSpeech() {
  46. UnityPlayer.UnitySendMessage("XfManager","OnBeginOfSpeech","");
  47. }
  48. @Override
  49. public void onEndOfSpeech() {
  50. UnityPlayer.UnitySendMessage("XfManager","OnEndOfSpeech","");
  51. }
  52. @Override
  53. public void onResult(RecognizerResult recognizerResult, boolean b) {
  54. printResult(recognizerResult);
  55. }
  56. @Override
  57. public void onError(SpeechError speechError) {
  58. UnityPlayer.UnitySendMessage("XfManager","OnError",speechError.getErrorDescription());
  59. }
  60. @Override
  61. public void onEvent(int i, int i1, int i2, Bundle bundle) {
  62. }
  63. };
  64. private void printResult(com.iflytek.cloud.RecognizerResult results) {
  65. // JsonParser是一个工具类
  66. String text = JsonParser.parseIatResult(results.getResultString());
  67. String sn = null;
  68. // 读取json结果中的sn字段
  69. try {
  70. JSONObject resultJson = new JSONObject(results.getResultString());
  71. sn = resultJson.optString("sn");
  72. } catch (JSONException e) {
  73. e.printStackTrace();
  74. }
  75. mIatResults.put(sn, text);
  76. // resultBuffer 为最终返回的结果
  77. StringBuffer resultBuffer = new StringBuffer();
  78. for (String key : mIatResults.keySet()) {
  79. resultBuffer.append(mIatResults.get(key));
  80. }
  81. // 把得到的结果返回给Unity 第一个参数为unity种的游戏物体 第二个参数为 这个游戏物体身上脚本的方法 第三个参数为讯飞返回的最终结果
  82. UnityPlayer.UnitySendMessage("XfManager","OnResult",resultBuffer.toString());
  83. }
  84. public void VoidTest()
  85. {
  86. UnityPlayer.UnitySendMessage("XfManager","FromAndroid","Android:消息发送至Unity");
  87. }
  88. }

Json类(这个是讯飞demo里面的)

  1. package com.example.mylibrary;
  2. import org.json.JSONArray;
  3. import org.json.JSONObject;
  4. import org.json.JSONTokener;
  5. /**
  6. * Json结果解析类
  7. */
  8. public class JsonParser {
  9. public static String parseIatResult(String json) {
  10. StringBuffer ret = new StringBuffer();
  11. try {
  12. JSONTokener tokener = new JSONTokener(json);
  13. JSONObject joResult = new JSONObject(tokener);
  14. JSONArray words = joResult.getJSONArray("ws");
  15. for (int i = 0; i < words.length(); i++) {
  16. // 转写结果词,默认使用第一个结果
  17. JSONArray items = words.getJSONObject(i).getJSONArray("cw");
  18. JSONObject obj = items.getJSONObject(0);
  19. ret.append(obj.getString("w"));
  20. // 如果需要多候选结果,解析数组其他字段
  21. // for(int j = 0; j < items.length(); j++)
  22. // {
  23. // JSONObject obj = items.getJSONObject(j);
  24. // ret.append(obj.getString("w"));
  25. // }
  26. }
  27. } catch (Exception e) {
  28. e.printStackTrace();
  29. }
  30. return ret.toString();
  31. }
  32. public static String parseGrammarResult(String json, String engType) {
  33. StringBuffer ret = new StringBuffer();
  34. try {
  35. JSONTokener tokener = new JSONTokener(json);
  36. JSONObject joResult = new JSONObject(tokener);
  37. JSONArray words = joResult.getJSONArray("ws");
  38. // 云端和本地结果分情况解析
  39. if ("cloud".equals(engType)) {
  40. for (int i = 0; i < words.length(); i++) {
  41. JSONArray items = words.getJSONObject(i).getJSONArray("cw");
  42. for (int j = 0; j < items.length(); j++) {
  43. JSONObject obj = items.getJSONObject(j);
  44. if (obj.getString("w").contains("nomatch")) {
  45. ret.append("没有匹配结果.");
  46. return ret.toString();
  47. }
  48. ret.append("【结果】" + obj.getString("w"));
  49. ret.append("【置信度】" + obj.getInt("sc"));
  50. ret.append("\n");
  51. }
  52. }
  53. } else if ("local".equals(engType)) {
  54. ret.append("【结果】");
  55. for (int i = 0; i < words.length(); i++) {
  56. JSONObject wsItem = words.getJSONObject(i);
  57. JSONArray items = wsItem.getJSONArray("cw");
  58. if ("<contact>".equals(wsItem.getString("slot"))) {
  59. // 可能会有多个联系人供选择,用中括号括起来,这些候选项具有相同的置信度
  60. ret.append("【");
  61. for (int j = 0; j < items.length(); j++) {
  62. JSONObject obj = items.getJSONObject(j);
  63. if (obj.getString("w").contains("nomatch")) {
  64. ret.append("没有匹配结果.");
  65. return ret.toString();
  66. }
  67. ret.append(obj.getString("w")).append("|");
  68. }
  69. ret.setCharAt(ret.length() - 1, '】');
  70. } else {
  71. //本地多候选按照置信度高低排序,一般选取第一个结果即可
  72. JSONObject obj = items.getJSONObject(0);
  73. if (obj.getString("w").contains("nomatch")) {
  74. ret.append("没有匹配结果.");
  75. return ret.toString();
  76. }
  77. ret.append(obj.getString("w"));
  78. }
  79. }
  80. ret.append("【置信度】" + joResult.getInt("sc"));
  81. ret.append("\n");
  82. }
  83. } catch (Exception e) {
  84. e.printStackTrace();
  85. ret.append("没有匹配结果.");
  86. }
  87. return ret.toString();
  88. }
  89. public static String parseGrammarResult(String json) {
  90. StringBuffer ret = new StringBuffer();
  91. try {
  92. JSONTokener tokener = new JSONTokener(json);
  93. JSONObject joResult = new JSONObject(tokener);
  94. JSONArray words = joResult.getJSONArray("ws");
  95. for (int i = 0; i < words.length(); i++) {
  96. JSONArray items = words.getJSONObject(i).getJSONArray("cw");
  97. for (int j = 0; j < items.length(); j++) {
  98. JSONObject obj = items.getJSONObject(j);
  99. if (obj.getString("w").contains("nomatch")) {
  100. ret.append("没有匹配结果.");
  101. return ret.toString();
  102. }
  103. ret.append("【结果】" + obj.getString("w"));
  104. ret.append("【置信度】" + obj.getInt("sc"));
  105. ret.append("\n");
  106. }
  107. }
  108. } catch (Exception e) {
  109. e.printStackTrace();
  110. ret.append("没有匹配结果.");
  111. }
  112. return ret.toString();
  113. }
  114. public static String parseLocalGrammarResult(String json) {
  115. StringBuffer ret = new StringBuffer();
  116. try {
  117. JSONTokener tokener = new JSONTokener(json);
  118. JSONObject joResult = new JSONObject(tokener);
  119. JSONArray words = joResult.getJSONArray("ws");
  120. for (int i = 0; i < words.length(); i++) {
  121. JSONArray items = words.getJSONObject(i).getJSONArray("cw");
  122. for (int j = 0; j < items.length(); j++) {
  123. JSONObject obj = items.getJSONObject(j);
  124. if (obj.getString("w").contains("nomatch")) {
  125. ret.append("没有匹配结果.");
  126. return ret.toString();
  127. }
  128. ret.append("【结果】" + obj.getString("w"));
  129. ret.append("\n");
  130. }
  131. }
  132. ret.append("【置信度】" + joResult.optInt("sc"));
  133. } catch (Exception e) {
  134. e.printStackTrace();
  135. ret.append("没有匹配结果.");
  136. }
  137. return ret.toString();
  138. }
  139. public static String parseTransResult(String json, String key) {
  140. StringBuffer ret = new StringBuffer();
  141. try {
  142. JSONTokener tokener = new JSONTokener(json);
  143. JSONObject joResult = new JSONObject(tokener);
  144. String errorCode = joResult.optString("ret");
  145. if (!errorCode.equals("0")) {
  146. return joResult.optString("errmsg");
  147. }
  148. JSONObject transResult = joResult.optJSONObject("trans_result");
  149. ret.append(transResult.optString(key));
  150. /*JSONArray words = joResult.getJSONArray("results");
  151. for (int i = 0; i < words.length(); i++) {
  152. JSONObject obj = words.getJSONObject(i);
  153. ret.append(obj.getString(key));
  154. }*/
  155. } catch (Exception e) {
  156. e.printStackTrace();
  157. }
  158. return ret.toString();
  159. }
  160. }

代码就是以上这些了,接下来就是修改AndroidManifest

第五步:

AndroidManifest.xml文件

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <manifest xmlns:tools="http://schemas.android.com/tools"
  3. xmlns:android="http://schemas.android.com/apk/res/android"
  4. package="com.example.mylibrary">
  5. <application
  6. android:allowBackup="true"
  7. android:supportsRtl="true">
  8. <activity android:name=".XunFeiSdk"
  9. android:exported="true">
  10. <intent-filter>
  11. <action android:name="android.intent.action.MAIN" />
  12. <category android:name="android.intent.category.LAUNCHER" />
  13. </intent-filter>
  14. </activity>
  15. <meta-data android:name="unityplayer.UnityActivity" android:value="true"/>
  16. </application>
  17. <uses-permission android:name="android.permission.RECORD_AUDIO" />
  18. <uses-permission android:name="android.permission.INTERNET" />
  19. <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
  20. <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
  21. <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
  22. <uses-permission android:name="android.permission.READ_PHONE_STATE" />
  23. <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
  24. <uses-permission android:name="android.permission.READ_CONTACTS" />
  25. <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
  26. <uses-permission android:name="android.permission.WRITE_SETTINGS"
  27. tools:ignore="ProtectedPermissions" />
  28. <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
  29. <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
  30. <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
  31. </manifest>

第六步:

完成以上这些步骤就可以打包成arr文件了

选中你的库文件然后点击build-Make Module,如图所示

arr生成路径是

结果如下

把mylibrary.arr文件根目录里的classes.jar和AndroidManifest复制出来(拖出来)

下面这个是从arr包里取出来的AndroidManifest文件,把<uses-sdk android:minSdkVersion="26" />删掉

第七步:

下面就是Unity这边了,Unity端比较简单,直接看图吧

这个AndroidManifest文件就是第六步的AndroidManifest文件,

classes.jar文件放在Plugins-Android-bin目录下

libs目录下放的是同第二步一样的3个文件

然后Unity测试界面

  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using TMPro;
  5. using UnityEngine;
  6. using UnityEngine.UI;
  7. public class XfManager : MonoBehaviour
  8. {
  9. private AndroidJavaClass ajc;
  10. private AndroidJavaObject ajo;
  11. //private AndroidJavaObject XunFeiSdk;
  12. public Button StartButton,testBtn;
  13. public TextMeshProUGUI ResultText;
  14. private void Start()
  15. {
  16. ajc = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
  17. ajo = ajc.GetStatic<AndroidJavaObject>("currentActivity");
  18. //XunFeiSdk = new AndroidJavaObject("com.example.mylibrary.XunFeiSdk");
  19. testBtn.onClick.AddListener(TestConnect);
  20. if (StartButton)
  21. {
  22. StartButton.onClick.AddListener(() => { StartListening(); });
  23. }
  24. }
  25. private void TestConnect()
  26. {
  27. ajo.Call("VoidTest");
  28. }
  29. public void FromAndroid(string s)
  30. {
  31. ResultText.text = s;
  32. }
  33. public void StartListening()
  34. {
  35. ajo.Call("StartListening");
  36. }
  37. public void OnStartListening(string ret)
  38. {
  39. int result = int.Parse(ret);
  40. StartButton.interactable = result == 0;
  41. }
  42. public void OnResult(string result)
  43. {
  44. ResultText.text = result;
  45. }
  46. public void OnError(string errorMessage)
  47. {
  48. ResultText.text = errorMessage;
  49. }
  50. public void OnEndOfSpeech()
  51. {
  52. StartButton.GetComponentInChildren<TextMeshProUGUI>().text = "已结束,点击聆听";
  53. StartButton.interactable = true;
  54. }
  55. public void OnBeginOfSpeech()
  56. {
  57. StartButton.GetComponentInChildren<TextMeshProUGUI>().text = "聆听ing";
  58. StartButton.interactable = false;
  59. }
  60. }

最后就是打包了

注:这里的包名必须跟你配置文件里面的一致才行,还有就是再重复一遍,Classes.jar用mono还是IL2CPP得和Unity-PlayerSetting-ScriptBackend一致。

打包成功,测试正常(注意开启权限哦)

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/知新_RL/article/detail/312552
推荐阅读
相关标签
  

闽ICP备14008679号