Browse Source

fix: ci

sibichiAi
高志龙 9 months ago
parent
commit
51870a2a7f
  1. 4
      app/build.gradle
  2. BIN
      app/libs/SparkChain.aar
  3. BIN
      app/release/app-release.apk
  4. BIN
      app/release/app_andorid_V2_视美泰iot分屏容器_V2.0.7.31.apk
  5. BIN
      app/release/app_andorid_V2_视美泰iot分屏容器_V2.0.7.32.apk
  6. BIN
      app/release/app_andorid_V2_视美泰设备iot分屏容器_V2.0.7.33.apk
  7. 2
      app/release/output-metadata.json
  8. 6
      app/src/main/AndroidManifest.xml
  9. 20
      app/src/main/java/qianmu/container/activity/H5/UpdateFileActivity.java
  10. 257
      app/src/main/java/qianmu/container/activity/H5/WebViewActivity.java
  11. 2
      app/src/main/java/qianmu/container/app/Constant.java
  12. 86
      app/src/main/java/qianmu/container/util/DeviceUtil.java
  13. 7
      app/src/main/java/qianmu/container/util/SignWayUtil.java
  14. 179
      app/src/main/java/qianmu/container/util/TTSUtil.java
  15. 3
      app/src/main/res/values/strings.xml

4
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')//

BIN
app/libs/SparkChain.aar

Binary file not shown.

BIN
app/release/app-release.apk

Binary file not shown.

BIN
app/release/app_andorid_V2_视美泰iot分屏容器_V2.0.7.31.apk

Binary file not shown.

BIN
app/release/app_andorid_V2_视美泰iot分屏容器_V2.0.7.32.apk

Binary file not shown.

BIN
app/release/app_andorid_V2_视美泰设备iot分屏容器_V2.0.7.33.apk

Binary file not shown.

2
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"
}
]

6
app/src/main/AndroidManifest.xml

@ -21,7 +21,6 @@
<uses-permission android:name="android.permission.BROADCAST_STICKY" /> <!-- 拍照权限 允许访问摄像头进行拍照 -->
<uses-permission android:name="android.permission.CAMERA" /> <!-- 读取电话状态 访问电话状态 -->
<uses-permission android:name="android.permission.READ_PHONE_STATE" /> <!-- 读取外部存储 允许程序读取外部存储,如SD卡上读文件 -->
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" /> <!-- 获取任务信息 允许程序获取当前或最近运行的应用 -->
<uses-permission android:name="android.permission.GET_TASKS" /> <!-- 对话框权限 -->
<uses-permission android:name="android.permission.SYSTEM_OVERLAY_WINDOW" />
<uses-permission
@ -44,11 +43,8 @@
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:usesCleartextTraffic="true"
android:requestLegacyExternalStorage="true"
android:theme="@style/AppTheme">
<!-- 测试页面 -->
<activity android:name=".activity.TestActivity">
</activity>
<provider
android:name="androidx.core.content.FileProvider"

20
app/src/main/java/qianmu/container/activity/H5/UpdateFileActivity.java

@ -16,6 +16,8 @@ import androidx.databinding.DataBindingUtil;
import com.alibaba.android.arouter.facade.annotation.Route;
import com.alibaba.android.arouter.launcher.ARouter;
import com.iflytek.sparkchain.core.SparkChain;
import com.iflytek.sparkchain.core.SparkChainConfig;
import com.sdkapi.api.SdkApi;
import java.io.File;
@ -252,6 +254,24 @@ public class UpdateFileActivity extends BaseActivity {
//新版欣威视通初始化
SdkApi.newInstance(this);
}
if("kdxf".equals(Constant.TTSFac)){
Log.d("MainActivity: ","initKDXFSDK");
// 初始化SDK,Appid等信息在清单中配置
SparkChainConfig sparkChainConfig = SparkChainConfig.builder();
sparkChainConfig.appID(getResources().getString(R.string.appid))
.apiKey(getResources().getString(R.string.apikey))
.apiSecret(getResources().getString(R.string.apiSecret))//应用申请的appid三元组
.logLevel(666);
int ret = SparkChain.getInst().init(getApplicationContext(),sparkChainConfig);
String result;
if(ret == 0){
result = "SDK初始化成功,请选择相应的功能点击体验。";
}else{
result = "SDK初始化失败,错误码:" + ret;
}
Log.e("MainActivity: ",result);
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
if(!Environment.isExternalStorageManager()){
Intent intent = new Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION);

257
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;

2
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(),

86
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<NetworkInterface> 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<NetworkInterface> 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<InetAddress> 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

7
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")){

179
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();
}
});
}

3
app/src/main/res/values/strings.xml

@ -1,4 +1,7 @@
<resources>
<string name="appid">deb3f3ab</string>
<string name="apiSecret">MGRjYzQwZjExMTI4YjA3MzZmZTdjZjVm</string>
<string name="apikey">daf84ac85c24e300a517c7ef96744b25</string>
<string name="app_name">Android容器</string>
<string name="register_state">设备注册状态:</string>
<string name="hint_mall_code">商场编号:</string>

Loading…
Cancel
Save