diff --git a/app/build.gradle b/app/build.gradle index 90ff28c..208bfab 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -10,7 +10,7 @@ android { minSdkVersion 22 targetSdkVersion 30 versionCode 6 - versionName "V2.0.7.30" + versionName "V2.0.7.33" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" consumerProguardFiles 'consumer-rules.pro' @@ -90,7 +90,7 @@ dependencies { implementation 'androidx.constraintlayout:constraintlayout:1.1.3' implementation files('libs\\ymeeting.jar')//亿晟 implementation project(path: ':playerview') - implementation files('libs\\Msc.jar') + implementation files('libs/SparkChain.aar') implementation files('libs\\zckjAPI-2.2.jar')//卓策 implementation files('libs\\jna-min.jar') implementation files('libs\\toolbox_kit.jar')//灰度主板 罗湖寻车机 diff --git a/app/libs/SparkChain.aar b/app/libs/SparkChain.aar new file mode 100644 index 0000000..51937e1 Binary files /dev/null and b/app/libs/SparkChain.aar differ diff --git a/app/release/app-release.apk b/app/release/app-release.apk deleted file mode 100644 index 9560089..0000000 Binary files a/app/release/app-release.apk and /dev/null differ diff --git a/app/release/app_andorid_V2_视美泰iot分屏容器_V2.0.7.31.apk b/app/release/app_andorid_V2_视美泰iot分屏容器_V2.0.7.31.apk new file mode 100644 index 0000000..209b863 Binary files /dev/null and b/app/release/app_andorid_V2_视美泰iot分屏容器_V2.0.7.31.apk differ diff --git a/app/release/app_andorid_V2_视美泰iot分屏容器_V2.0.7.32.apk b/app/release/app_andorid_V2_视美泰iot分屏容器_V2.0.7.32.apk new file mode 100644 index 0000000..0a9c1e7 Binary files /dev/null and b/app/release/app_andorid_V2_视美泰iot分屏容器_V2.0.7.32.apk differ diff --git a/app/release/app_andorid_V2_视美泰设备iot分屏容器_V2.0.7.33.apk b/app/release/app_andorid_V2_视美泰设备iot分屏容器_V2.0.7.33.apk new file mode 100644 index 0000000..2203880 Binary files /dev/null and b/app/release/app_andorid_V2_视美泰设备iot分屏容器_V2.0.7.33.apk differ diff --git a/app/release/output-metadata.json b/app/release/output-metadata.json index 81d7a5a..8ecfeb8 100644 --- a/app/release/output-metadata.json +++ b/app/release/output-metadata.json @@ -11,7 +11,7 @@ "type": "SINGLE", "filters": [], "versionCode": 6, - "versionName": "V2.0.8.0", + "versionName": "V2.0.7.33", "outputFile": "app-release.apk" } ] diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index e42c0ae..00f1873 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -21,7 +21,6 @@ - - - - - = Build.VERSION_CODES.R) { if(!Environment.isExternalStorageManager()){ Intent intent = new Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION); diff --git a/app/src/main/java/qianmu/container/activity/H5/WebViewActivity.java b/app/src/main/java/qianmu/container/activity/H5/WebViewActivity.java index ac6bc8c..20bb31e 100644 --- a/app/src/main/java/qianmu/container/activity/H5/WebViewActivity.java +++ b/app/src/main/java/qianmu/container/activity/H5/WebViewActivity.java @@ -40,6 +40,8 @@ import com.iflytek.cloud.SpeechConstant; import com.iflytek.cloud.SpeechError; import com.iflytek.cloud.SpeechRecognizer; import com.iflytek.cloud.SpeechUtility; +import com.iflytek.sparkchain.core.asr.ASR; +import com.iflytek.sparkchain.core.asr.AsrCallbacks; import com.shockman.sm.vendor.IHttp; import com.shockman.sm.vendor.SmUtils; import com.shockman.sm.vendor.TargetVo; @@ -84,6 +86,7 @@ import qianmu.container.util.GsonUtil; import qianmu.container.util.KeyboardUtil; import qianmu.container.util.LoggerUtil; import qianmu.container.util.StringUtil; +import qianmu.container.util.TTSUtil; import qianmu.container.util.ToastUtils; import static qianmu.container.service.ContainerService.initFirstTime; @@ -97,11 +100,19 @@ public class WebViewActivity extends BaseActivity { static final int TYPE_GO_SAVESCREEN = 300;//导视通知跳转屏保 static final int TYPE_HINT_PASSWORD = 3;//隐藏密码输入框 static final int TYPE_START_SERVER = 4;//重新启动web服务 - static String HtmlUrl = "http://127.0.0.1:8080/index.html";//webServer服务地址 + static String HtmlUrl = "http://127.0.0.1:8080/index.html";//webServer服务地址 http://192.168.1.218:5173/ + //static String HtmlUrl = "http://192.168.1.218:5173/"; int time = 0; private VideoView currentVideo; SocketClient localSocketClient; + // 语音听写对象 + private ASR mAsr; + private boolean isrun = false; // 是否正在听写 + private boolean isdws = false; // 是否可以修正 + private String language = "zh_cn"; + private TTSUtil ttsUtil; + Handler handler = new Handler() { @SuppressLint("HandlerLeak") @Override @@ -165,7 +176,13 @@ public class WebViewActivity extends BaseActivity { loadingSpeekVideo(); //设置密码 initPass(); - connectLocalSocket(); + if("sbc".equals(Constant.TTSFac)){ // 思必驰 + connectLocalSocket(); + }else{ //kdxf + initASR(); + ttsUtil = new TTSUtil(); + ttsUtil.initTts(); + } } private void loadingbgVideo(Boolean isplay){ Uri videoUri = Uri.parse("android.resource://" + getPackageName() + "/" + R.raw.bg); @@ -401,6 +418,7 @@ public class WebViewActivity extends BaseActivity { }); binding.web.addJavascriptInterface(new AndroidtoJs(), "android"); } + int count = 0; // JS 调用 android public class AndroidtoJs extends Object { // 回到屏保页面 @@ -436,25 +454,54 @@ public class WebViewActivity extends BaseActivity { @JavascriptInterface public void startRecord() { LoggerUtil.e(TAG,"JS调用了Android的方法:startRecord()"); - localSocketClient.send(StringUtil.strSplice("{\"method\":\"/asr/start\"}")); + if("sbc".equals(Constant.TTSFac)) { + localSocketClient.send(StringUtil.strSplice("{\"method\":\"/asr/start\"}")); + }else{ + if(isrun){ + return; + } + if(mAsr == null){ + LoggerUtil.d(TAG, "未初始化"); + initASR(); + } + count++; + int ret = mAsr.startListener(count+""); + if(ret != 0){ + LoggerUtil.d(TAG,"识别开启失败,错误码:"+ret+"\n"); + }else{ + isrun = true; + } + } } // h5调用android:停止识别语音 @JavascriptInterface public void stopRecord() { LoggerUtil.e(TAG,"JS调用了Android的方法:stopRecord()"); - localSocketClient.send(StringUtil.strSplice("{\"method\":\"/asr/stop\"}")); + if("sbc".equals(Constant.TTSFac)) { + localSocketClient.send(StringUtil.strSplice("{\"method\":\"/asr/stop\"}")); + }else{ + stopAsr(); + } } // h5调用android:开始合成语音 @JavascriptInterface public void startTTS(String txt) { LoggerUtil.e(TAG,"JS调用了Android的方法:startTTS()"); - localSocketClient.send(StringUtil.strSplice("{\"method\": \"/tts/start\",\"params\": {\"text\":\"", txt, "\", \"mode\":\"autoPlay\"}}")); + if("sbc".equals(Constant.TTSFac)) { + localSocketClient.send(StringUtil.strSplice("{\"method\": \"/tts/start\",\"params\": {\"text\":\"", txt, "\", \"mode\":\"autoPlay\"}}")); + }else{ + ttsUtil.startTTs(txt); + } } // h5调用android:停止合成语音 @JavascriptInterface public void stopTTS() { LoggerUtil.e(TAG,"JS调用了Android的方法:stopTTS()"); - localSocketClient.send(StringUtil.strSplice("{\"method\":\"/tts/stop\"}")); + if("sbc".equals(Constant.TTSFac)){ + localSocketClient.send(StringUtil.strSplice("{\"method\":\"/tts/stop\"}")); + }else{ + ttsUtil.stopTTs(); + } runOnUiThread(new Runnable() { @Override public void run() { @@ -474,62 +521,7 @@ public class WebViewActivity extends BaseActivity { }); } } - //语音交互 - private void setLocalSocketListener() { - localSocketClient.setOnOpenListener((handshakeData) -> { - LoggerUtil.e("connectLocalSocket", "TTS客户端连接成功"); - localSocketClient.send(StringUtil.strSplice("{\"method\":\"/asr/stop\"}")); - }); - localSocketClient.setOnMessageListener((conn, message) -> { - try { - TTSMessage messageBean = new Gson().fromJson(message, TTSMessage.class); - TTSMessage.Params content = messageBean.getParams(); - if (content == null) return; - String method = messageBean.getMethod(); - if("asr.text".equals(method)){ - LoggerUtil.e("ttsSocket:",content.getText()); - runOnUiThread(new Runnable() { - @Override - public void run() { - binding.web.loadUrl(StringUtil.strSplice("javascript:window.giveAskText('", content.getText(), "');")); - } - }); - }else if("asr.result".equals(method)){ - LoggerUtil.e("ttsSocket:",content.getText()); - runOnUiThread(new Runnable() { - @Override - public void run() { - localSocketClient.send(StringUtil.strSplice("{\"method\":\"/asr/stop\"}")); - binding.web.loadUrl(StringUtil.strSplice("javascript:window.youAskOver('", content.getText(), "');")); - } - }); - }else if("tts.result".equals(method)){ - LoggerUtil.e("ttsSocket:", messageBean.getParams().getStatus().trim()); - if("end".equals(messageBean.getParams().getStatus().trim())) { - runOnUiThread(new Runnable() { - @Override - public void run() { - changeVideo("bg"); - } - }); - } - } - } catch (Throwable t) { - LoggerUtil.e("setOnMessageListener", StringUtil.getThrowableStr(t)); - } - }); - - localSocketClient.setOnCloseListener((code, reason, remote) -> { - LoggerUtil.e("LocSocCliManager", "onClose:code="+code); - if (localSocketClient == null){ - initLocalSocketClient(); - }else { - localSocketClient.reconnect(); - } - }); - localSocketClient.setOnErrorListener((ex) -> LoggerUtil.e("LocSocCliManager", "onError")); - } /** * 安卓调用h5方法通知进入导视 @@ -566,7 +558,9 @@ public class WebViewActivity extends BaseActivity { } break; - + case Constant.VOID_STOP: + changeVideo("bg"); + break; case Constant.ACTION_UPDATE_PROG2://后台下发节目通知,重置导视倒计时。 LoggerUtil.e(TAG,"重启导视倒计时"); leaveScreenSave(); @@ -574,6 +568,89 @@ public class WebViewActivity extends BaseActivity { } } + //-------- 科大讯飞 + private void initASR(){ + if(mAsr == null){ + mAsr = new ASR(); + mAsr.registerCallbacks(mAsrCallbacks); + mAsr.language(language);//语种,zh_cn:中文,en_us:英文。其他语种参见集成文档 + mAsr.domain("iat");//应用领域,iat:日常用语。其他领域参见集成文档 + mAsr.accent("mandarin");//方言,mandarin:普通话。方言仅当language为中文时才会生效。其他方言参见集成文档。 + mAsr.vinfo(true);//返回子句结果对应的起始和结束的端点帧偏移值。 + if("zh_cn".equals(language)){ + mAsr.dwa("wpgs");//动态修正 + } + } + } + + AsrCallbacks mAsrCallbacks = new AsrCallbacks() { + @Override + public void onResult(ASR.ASRResult asrResult, Object o) { + //以下信息需要开发者根据自身需求,如无必要,可不需要解析执行。 + int status = asrResult.getStatus(); //结果数据状态,0:识别的第一块结果,1:识别中间结果,2:识别最后一块结果 + String result = asrResult.getBestMatchText(); //识别结果 + if(status == 0){ + voiceContent(result); + }else if(status == 2){ + voiceContent(result); + stopAsr(); + }else{ + voiceContent(result); + } + } + + @Override + public void onError(ASR.ASRError asrError, Object o) { + // 在非主线程中需要调用 WebView 方法时 + runOnUiThread(new Runnable() { + @Override + public void run() { + binding.web.loadUrl(StringUtil.strSplice("javascript:window.youAskOver('"+"');")); + } + }); + stopAsr(); + } + + @Override + public void onBeginOfSpeech() { + + } + + @Override + public void onEndOfSpeech() { + Log.d(TAG, "结束说话"); + runOnUiThread(new Runnable() { + @Override + public void run() { + binding.web.loadUrl(StringUtil.strSplice("javascript:window.youAskOver('"+"');")); + } + }); + } + }; + /** + * android调用js:传送识别语音内容 + */ + public void voiceContent(String msg) { + if (binding.web != null) { + LoggerUtil.e(TAG, "android调用js方法:voiceContent(),语音内容:" + msg); + runOnUiThread(new Runnable() { + @Override + public void run() { + binding.web.loadUrl(StringUtil.strSplice("javascript:window.giveAskText('" + msg + "');")); + } + }); + } + } + private void stopAsr(){ + if(isrun){ + if(mAsr!=null){ + mAsr.stopListener(false); + } + isrun = false; + } + } + + // 思必驰---------------- private void initLocalSocketClient() { try { URI localUri = new URI("ws://127.0.0.1:50002"); @@ -608,6 +685,62 @@ public class WebViewActivity extends BaseActivity { } } + //语音交互 + private void setLocalSocketListener() { + localSocketClient.setOnOpenListener((handshakeData) -> { + LoggerUtil.e("connectLocalSocket", "TTS客户端连接成功"); + localSocketClient.send(StringUtil.strSplice("{\"method\":\"/asr/stop\"}")); + }); + + localSocketClient.setOnMessageListener((conn, message) -> { + try { + TTSMessage messageBean = new Gson().fromJson(message, TTSMessage.class); + TTSMessage.Params content = messageBean.getParams(); + if (content == null) return; + String method = messageBean.getMethod(); + if("asr.text".equals(method)){ + LoggerUtil.e("ttsSocket:",content.getText()); + runOnUiThread(new Runnable() { + @Override + public void run() { + binding.web.loadUrl(StringUtil.strSplice("javascript:window.giveAskText('", content.getText(), "');")); + } + }); + }else if("asr.result".equals(method)){ + LoggerUtil.e("ttsSocket:",content.getText()); + runOnUiThread(new Runnable() { + @Override + public void run() { + localSocketClient.send(StringUtil.strSplice("{\"method\":\"/asr/stop\"}")); + binding.web.loadUrl(StringUtil.strSplice("javascript:window.youAskOver('", content.getText(), "');")); + } + }); + }else if("tts.result".equals(method)){ + LoggerUtil.e("ttsSocket:", messageBean.getParams().getStatus().trim()); + if("end".equals(messageBean.getParams().getStatus().trim())) { + runOnUiThread(new Runnable() { + @Override + public void run() { + changeVideo("bg"); + } + }); + } + } + } catch (Throwable t) { + LoggerUtil.e("setOnMessageListener", StringUtil.getThrowableStr(t)); + } + }); + + localSocketClient.setOnCloseListener((code, reason, remote) -> { + LoggerUtil.e("LocSocCliManager", "onClose:code="+code); + if (localSocketClient == null){ + initLocalSocketClient(); + }else { + localSocketClient.reconnect(); + } + }); + localSocketClient.setOnErrorListener((ex) -> LoggerUtil.e("LocSocCliManager", "onError")); + } //销毁当前的客户端 public void destroyLocalSocketClient() { if (localSocketClient == null) return; diff --git a/app/src/main/java/qianmu/container/app/Constant.java b/app/src/main/java/qianmu/container/app/Constant.java index 8edc68e..0186258 100644 --- a/app/src/main/java/qianmu/container/app/Constant.java +++ b/app/src/main/java/qianmu/container/app/Constant.java @@ -33,6 +33,8 @@ public class Constant { // public static String androidBoardType = "bv"; //设备板子型号 Bv-3588M public static String androidBoardType = "smt"; //设备板子型号 视美泰 + public static String TTSFac = "sbc"; // 语音识别厂家 ksxf--科大讯飞 sbc-思必驰 + public static final String VOID_STOP = "void_stop";// public static String whoActivity = ""; // 哪个activity页面 // 本地缓存地址 public static final String CACHE_PATH = StringUtil.strSplice(Environment.getExternalStorageDirectory().getPath(), diff --git a/app/src/main/java/qianmu/container/util/DeviceUtil.java b/app/src/main/java/qianmu/container/util/DeviceUtil.java index cd173a0..d610ff6 100644 --- a/app/src/main/java/qianmu/container/util/DeviceUtil.java +++ b/app/src/main/java/qianmu/container/util/DeviceUtil.java @@ -19,6 +19,7 @@ import java.io.File; import java.net.Inet4Address; import java.net.InetAddress; import java.net.NetworkInterface; +import java.net.Socket; import java.net.SocketException; import java.util.Enumeration; import java.util.List; @@ -45,7 +46,11 @@ public class DeviceUtil { try { if(Constant.androidBoardType.equals("nova")){ //诺瓦 - return getEthIpAddress(); + String ip = getEthIpAddress(); + if(StringUtil.isEmpty(ip)){ + ip = getLocalIPByWIFI(); + } + return ip; }else { String allIP = ""; for (Enumeration en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements(); ) { @@ -92,7 +97,7 @@ public class DeviceUtil { //获取有线网络ip public static String getEthIpAddress() { String infaceName = "eth0"; - String ip = "0.0.0.0"; + String ip = ""; try { Enumeration netInterface = NetworkInterface.getNetworkInterfaces(); while (netInterface.hasMoreElements()) { @@ -100,12 +105,10 @@ public class DeviceUtil { if (!inface.isUp()) { continue; } - // eth0 有线网络判断 if (!infaceName.equals(inface.getDisplayName())) { continue; } - Enumeration netAddressList = inface.getInetAddresses(); while (netAddressList.hasMoreElements()) { InetAddress inetAddress = netAddressList.nextElement(); @@ -123,7 +126,6 @@ public class DeviceUtil { //获取有线网络mac public static String getLanMac(){ - ConnectivityManager cm = (ConnectivityManager) MyApplication.getInstance().getApplicationContext().getSystemService(Service.CONNECTIVITY_SERVICE); NetworkInfo activeNetworkInfo = cm.getActiveNetworkInfo(); String extraInfo = activeNetworkInfo.getExtraInfo(); @@ -136,27 +138,36 @@ public class DeviceUtil { * @return */ public static String getLocalIPByWIFI() { + String ip=""; try { - //获取wifi服务 - WifiManager wifiManager = (WifiManager) MyApplication.getInstance().getApplicationContext().getSystemService(Context.WIFI_SERVICE); - //判断wifi是否开启 - if (!wifiManager.isWifiEnabled()) wifiManager.setWifiEnabled(true); - WifiInfo wifiInfo = wifiManager.getConnectionInfo(); - int ipAddress = wifiInfo.getIpAddress(); - return intToIp(ipAddress); - } catch (Throwable t) { - LoggerUtil.e("getLocalIPByWIFI", StringUtil.getThrowableStr(t)); - return ""; + Socket socket = new Socket("www.baidu.com",80); + ip = socket.getLocalAddress().toString(); + LoggerUtil.e("GETIP: ", ip); + } catch (Exception e) { + Log.e(TAG, "网络接口遍历获取IP失败", e); + } + if("".equals(ip)){ + try { + //获取wifi服务 + WifiManager wifiManager = (WifiManager) MyApplication.getInstance().getApplicationContext().getSystemService(Context.WIFI_SERVICE); + //判断wifi是否开启 + if (!wifiManager.isWifiEnabled()) wifiManager.setWifiEnabled(true); + WifiInfo wifiInfo = wifiManager.getConnectionInfo(); + int ipAddress = wifiInfo.getIpAddress(); + ip = intToIp(ipAddress); + } catch (Throwable t) { + LoggerUtil.e("getLocalIPByWIFI", StringUtil.getThrowableStr(t)); + return ""; + } } + return ip; } private static String intToIp(int i) { - String first = String.valueOf((i & 0xFF)); String second = String.valueOf(((i >> 8) & 0xFF)); String third = String.valueOf(((i >> 16) & 0xFF)); String fourth = String.valueOf((i >> 24 & 0xFF)); - return StringUtil.strSplice(first, ".", second, ".", third, ".", fourth); } @@ -195,23 +206,38 @@ public class DeviceUtil { * @return */ public static String getLocalMacAddressFromIp() { - String strMacAddr = null; + String macAddress=""; + WifiManager wifiManager = (WifiManager) MyApplication.getInstance().getApplicationContext().getSystemService(Context.WIFI_SERVICE); + WifiInfo wifiInfo = wifiManager.getConnectionInfo(); + macAddress = wifiInfo.getBSSID(); + if(StringUtil.isEmpty(macAddress)){ + macAddress = getMacFromNetworkInterface(); + } + return macAddress; + } + /** + * 通过网络接口获取MAC地址(备选方案) + */ + private static String getMacFromNetworkInterface() { try { - //获得IpD地址 - InetAddress ip = getLocalInetAddress(); - byte[] b = NetworkInterface.getByInetAddress(ip).getHardwareAddress(); - StringBuffer buffer = new StringBuffer(); - for (int i = 0; i < b.length; i++) { - if (i != 0) { - buffer.append(':'); - } - String str = Integer.toHexString(b[i] & 0xFF); - buffer.append(str.length() == 1 ? 0 + str : str); + java.net.NetworkInterface networkInterface = java.net.NetworkInterface.getByName("wlan0"); + if (networkInterface == null) return ""; + + byte[] macBytes = networkInterface.getHardwareAddress(); + if (macBytes == null) return ""; + + StringBuilder mac = new StringBuilder(); + for (byte b : macBytes) { + mac.append(String.format("%02X:", b)); } - strMacAddr = buffer.toString().toUpperCase(); + if (mac.length() > 0) { + mac.deleteCharAt(mac.length() - 1); + } + return mac.toString(); } catch (Exception e) { + Log.e(TAG, "通过网络接口获取MAC失败", e); + return ""; } - return strMacAddr; } /** * 获取移动设备本地IP diff --git a/app/src/main/java/qianmu/container/util/SignWayUtil.java b/app/src/main/java/qianmu/container/util/SignWayUtil.java index 36bbd3f..262ff79 100644 --- a/app/src/main/java/qianmu/container/util/SignWayUtil.java +++ b/app/src/main/java/qianmu/container/util/SignWayUtil.java @@ -430,8 +430,11 @@ public class SignWayUtil { zcApi.getContext(MyApplication.getInstance()); return zcApi.getEthMacAddress("eth0"); }if(Constant.androidBoardType.equals("nova")){ - return DeviceUtil.getLanMac(); -// return DeviceUtil.getMacFromHardware(); + String mac = DeviceUtil.getLanMac(); + if(StringUtil.isEmpty(mac)){ + mac = DeviceUtil.getMacFromHardware(); + } + return mac; } else if(Constant.androidBoardType.equals("huidu")){ diff --git a/app/src/main/java/qianmu/container/util/TTSUtil.java b/app/src/main/java/qianmu/container/util/TTSUtil.java new file mode 100644 index 0000000..55f9f3e --- /dev/null +++ b/app/src/main/java/qianmu/container/util/TTSUtil.java @@ -0,0 +1,179 @@ +package qianmu.container.util; + + +import android.media.AudioFormat; +import android.media.AudioManager; +import android.media.AudioTrack; +import android.os.Bundle; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.util.Log; +import androidx.annotation.NonNull; +import com.iflytek.sparkchain.core.tts.OnlineTTS; +import com.iflytek.sparkchain.core.tts.TTS; +import com.iflytek.sparkchain.core.tts.TTSCallbacks; + +import org.greenrobot.eventbus.EventBus; + +import qianmu.container.app.Constant; +import qianmu.container.entity.MessageEvent; + +public class TTSUtil { + private static String TAG = "TTS: "; + // 语音合成对象 + private OnlineTTS mOnlineTTS; + private int sampleRate = 16000; + + TTSCallbacks mTTSCallback = new TTSCallbacks() { + + @Override + public void onResult(TTS.TTSResult result, Object o) { + //解析获取的交互结果,示例展示所有结果获取,开发者可根据自身需要,选择获取。 + byte[] audio = result.getData();//音频数据 + int status = result.getStatus();//数据状态 + + Bundle bundle = new Bundle(); + bundle.putByteArray("audio", audio); + Message msg = mAudioPlayHandler.obtainMessage(); + msg.what = AUDIOPLAYER_WRITE; + msg.obj = bundle; + mAudioPlayHandler.sendMessage(msg); + if(status == 2){ + //音频合成回调结束状态,注意,此状态不是播报完成状态 + mAudioPlayHandler.sendEmptyMessage(AUDIOPLAYER_END); + } + } + + @Override + public void onError(TTS.TTSError ttsError, Object o) { + int errCode = ttsError.getCode();//错误码 + String errMsg = ttsError.getErrMsg();//错误信息 + LoggerUtil.d(TAG, "onError:errCode:" + errCode+ ",errMsg:" + errMsg); + //如果此时已经播报,则停止播报 + EventBus.getDefault().post(new MessageEvent(Constant.VOID_STOP)); + stopTTs(); + } + }; + + public void initTts(){ + mAudioPlayThread.start(); + // 初始化合成对象 发音人 + mOnlineTTS = new OnlineTTS("xiaoyan"); //xiaoyan + } + + //开始听写 + public void startTTs(String texts){ + if (null == mOnlineTTS) { + LoggerUtil.d(TAG, "未初始化"); + initTts(); + } + if(audioTrack == null){ + mAudioPlayHandler.sendEmptyMessage(AUDIOPLAYER_INIT); + }else{ + mAudioPlayHandler.sendEmptyMessage(AUDIOPLAYER_START); + } + setParam(); + // 合成并播放 + int ret = mOnlineTTS.aRun(texts); + if(ret!=0){ + LoggerUtil.d(TAG, "语音合成失败" ); + } + } + + //停止听写 + public void stopTTs(){ + LoggerUtil.d(TAG, "手动暂停播放"); + if (null == mOnlineTTS) { + LoggerUtil.d(TAG, "未初始化"); + return; + } + mAudioPlayHandler.removeCallbacksAndMessages(null); + mAudioPlayHandler.sendEmptyMessage(AUDIOPLAYER_END); + mOnlineTTS.stop(); + } + + /** + * 参数设置 + * + * @return + */ + private void setParam() { + mOnlineTTS.aue("raw"); + mOnlineTTS.auf("audio/L16;rate="+sampleRate); // 8K 或 16K + mOnlineTTS.speed(60);//语速:0对应默认语速的1/2,100对应默认语速的2倍。最⼩值:0, 最⼤值:100 + mOnlineTTS.pitch(50);//语调:0对应默认语速的1/2,100对应默认语速的2倍。最⼩值:0, 最⼤值:100 + mOnlineTTS.volume(80);//音量:0是静音,1对应默认音量1/2,100对应默认音量的2倍。最⼩值:0, 最⼤值:100 + mOnlineTTS.bgs(0); //合成音频的背景音 0:无背景音(默认值) 1:有背景音 + mOnlineTTS.tte("UTF8"); + mOnlineTTS.registerCallbacks(mTTSCallback); + } + + /** + * 播放器,用于播报合成的音频。 + * 注意:当前Demo中的播放器仅实现了播放PCM格式的音频,如果客户合成的是其他格式的音频,需自行实现播放功能。 + */ + private static final int AUDIOPLAYER_INIT = 0x0000; + private static final int AUDIOPLAYER_START = 0x0001; + private static final int AUDIOPLAYER_WRITE = 0x0002; + private static final int AUDIOPLAYER_END = 0x0003; + private static final int CHANNEL_CONFIG = AudioFormat.CHANNEL_OUT_MONO; // 单声道输出 + private static final int AUDIO_FORMAT = AudioFormat.ENCODING_PCM_16BIT; // PCM 16位编码 + private AudioTrack audioTrack; + private Handler mAudioPlayHandler; + private boolean isPlaying = false; + int count = 0; + private Thread mAudioPlayThread = new Thread(new Runnable() { + @Override + public void run() { + Looper.prepare(); + mAudioPlayHandler = new Handler(Looper.myLooper()){ + @Override + public void handleMessage(@NonNull Message msg) { + super.handleMessage(msg); + switch(msg.what){ + case AUDIOPLAYER_INIT: + Log.d(TAG,"audioInit"); + int minBufferSize = AudioTrack.getMinBufferSize(sampleRate, CHANNEL_CONFIG, AUDIO_FORMAT); + audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRate, CHANNEL_CONFIG, AUDIO_FORMAT, minBufferSize, AudioTrack.MODE_STREAM); + mAudioPlayHandler.sendEmptyMessage(AUDIOPLAYER_START); + break; + case AUDIOPLAYER_START: + Log.d(TAG,"audioStart"); + if(audioTrack!=null) { + isPlaying = true; + audioTrack.play(); + } + break; + case AUDIOPLAYER_WRITE: + count ++; + if(count%5 == 0){ + Log.d(TAG,"audioWrite"); + count = 0; + } + Bundle bundle = (Bundle) msg.obj; + byte[] audioData = bundle.getByteArray("audio"); + if(audioTrack!=null&&audioData.length>0){ + audioTrack.write(audioData,0,audioData.length); + } + break; + case AUDIOPLAYER_END: + Log.d(TAG,"audioEnd"); + EventBus.getDefault().post(new MessageEvent(Constant.VOID_STOP)); + if(audioTrack!=null) { + audioTrack.stop(); + audioTrack.release(); + audioTrack = null; + isPlaying = false; + } + break; + + } + } + }; + Looper.loop(); + } + }); + + +} diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 2aba994..6b3d702 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,4 +1,7 @@ + deb3f3ab + MGRjYzQwZjExMTI4YjA3MzZmZTdjZjVm + daf84ac85c24e300a517c7ef96744b25 Android容器 设备注册状态: 商场编号: