下沉 tts 功能,分别实现"小智语音"和"小迪语音"

This commit is contained in:
wangcongtao
2020-10-12 20:21:15 +08:00
parent f628198de9
commit 0b7468a8a8
42 changed files with 1363 additions and 572 deletions

4
.idea/gradle.xml generated
View File

@@ -71,6 +71,10 @@
<option value="$PROJECT_DIR$/test/crashreport" />
<option value="$PROJECT_DIR$/test/crashreport-bugly" />
<option value="$PROJECT_DIR$/test/crashreport-noop" />
<option value="$PROJECT_DIR$/tts" />
<option value="$PROJECT_DIR$/tts/tts-base" />
<option value="$PROJECT_DIR$/tts/tts-di" />
<option value="$PROJECT_DIR$/tts/tts-zhi" />
</set>
</option>
<option name="resolveModulePerSourceSet" value="false" />

View File

@@ -393,6 +393,7 @@ dependencies {
apply from: "./functions/skin.gradle"
apply from: "./functions/crashreport.gradle"
apply from: "./functions/widgets.gradle"
apply from: "./functions/tts.gradle"
}
android.applicationVariants.all { variant ->

25
app/functions/tts.gradle Normal file
View File

@@ -0,0 +1,25 @@
project.dependencies {
if (Boolean.valueOf(RELEASE)) {
bydautoImplementation rootProject.ext.dependencies.ttszhi
d82xImplementation rootProject.ext.dependencies.ttszhi
em1Implementation rootProject.ext.dependencies.ttszhi
em3Implementation rootProject.ext.dependencies.ttszhi
d8xxImplementation rootProject.ext.dependencies.ttszhi
d80xImplementation rootProject.ext.dependencies.ttszhi
f8xxImplementation rootProject.ext.dependencies.ttszhi
f80xImplementation rootProject.ext.dependencies.ttszhi
em4Implementation rootProject.ext.dependencies.ttszhi
e8xxImplementation rootProject.ext.dependencies.ttszhi
} else {
bydautoImplementation project(':tts:tts-zhi')
d82xImplementation project(':tts:tts-zhi')
em1Implementation project(':tts:tts-zhi')
em3Implementation project(':tts:tts-zhi')
d8xxImplementation project(':tts:tts-zhi')
d80xImplementation project(':tts:tts-zhi')
f8xxImplementation project(':tts:tts-zhi')
f80xImplementation project(':tts:tts-zhi')
em4Implementation project(':tts:tts-zhi')
e8xxImplementation project(':tts:tts-zhi')
}
}

View File

@@ -207,6 +207,10 @@ targetSdkVersion : 22,
skinsupportcardview : "com.mogo.skin:skin-support-cardview:${SKIN_SUPPORT_CARDVIEW_VERSION}",
skinsupportconstraintlayout: "com.mogo.skin:skin-support-constraint-layout:${SKIN_SUPPORT_CONSTRAINT_LAYOUT_VERSION}",
skinsupportdesign : "com.mogo.skin:skin-support-design:${SKIN_SUPPORT_DESIGN_VERSION}",
ttsbase : "com.mogo.tts:tts-base:${TTS_BASE_VERSION}",
ttsdi : "com.mogo.tts:tts-di:${TTS_DI_VERSION}",
ttszhi : "com.mogo.tts:tts-zhi:${TTS_ZHI_VERSION}",
]
}

View File

@@ -36,8 +36,6 @@ android {
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
api rootProject.ext.dependencies.aiassist
api rootProject.ext.dependencies.aiassistReplace
api rootProject.ext.dependencies.androidxappcompat
api rootProject.ext.dependencies.analytics
implementation rootProject.ext.dependencies.arouter
@@ -46,9 +44,11 @@ dependencies {
implementation rootProject.ext.dependencies.accountsdk
if (Boolean.valueOf(RELEASE)) {
implementation rootProject.ext.dependencies.mogoutils
api rootProject.ext.dependencies.ttsbase
implementation rootProject.ext.dependencies.skinsupport
} else {
implementation project(":foudations:mogo-utils")
api project(":tts:tts-base")
implementation project(":skin:mogo-skin-support")
}
api 'org.greenrobot:eventbus:3.1.1'

View File

@@ -14,7 +14,6 @@ import com.mogo.utils.DeviceIdUtils;
import com.mogo.utils.WindowUtils;
import com.mogo.utils.logger.Logger;
import com.mogo.utils.network.utils.GsonUtil;
import com.zhidao.auto.platform.util.DeviceUtil;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
@@ -37,7 +36,7 @@ public class ParamsUtil {
params.put( ServerParam.NET_TYPE, CommonUtils.getNetworkType( AbsMogoApplication.getApp() ) );
params.put( ServerParam.CELL_ID, Utils.getCellId( AbsMogoApplication.getApp() ) );
params.put( ServerParam.DISPLAY_ID, DeviceUtil.getSystemVersion() );
// params.put( ServerParam.DISPLAY_ID, DeviceUtil.getSystemVersion() );
params.put( ServerParam.SN, Utils.getSn() );
params.put( ServerParam.TICKET, SpStorage.getTicket() );

View File

@@ -1,25 +1,11 @@
package com.mogo.commons.voice;
import android.app.ActivityManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.text.TextUtils;
import com.mogo.commons.AbsMogoApplication;
import com.mogo.utils.logger.Logger;
import com.zhidao.auto.platform.voice.VoiceClient;
import com.zhidao.voicesdk.MogoVoiceManager;
import com.zhidao.voicesdk.MogoVoiceManagerImpl;
import com.zhidao.voicesdk.callback.OnConnStatusListener;
import com.zhidao.voicesdk.callback.OnTtsListener;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import com.alibaba.android.arouter.launcher.ARouter;
import com.mogo.tts.base.IMogoTTS;
import com.mogo.tts.base.MogoTTSConstants;
import com.mogo.tts.base.PreemptType;
/**
* @author congtaowang
@@ -27,14 +13,11 @@ import java.util.concurrent.ConcurrentHashMap;
* <p>
* 语音助手通信助手
*/
public class AIAssist implements VoiceClient.VoiceCmdCallBack, OnTtsListener {
public class AIAssist {
private static final String TAG = "AIAssist";
private static volatile AIAssist sInstance;
private String mLastQAndASpeakText;
private boolean mHasFlush = false;
private boolean mInitReady = false;
private IMogoTTS mTTS;
public static AIAssist getInstance( Context context ) {
if ( sInstance == null ) {
@@ -48,61 +31,15 @@ public class AIAssist implements VoiceClient.VoiceCmdCallBack, OnTtsListener {
}
public synchronized void release() {
Logger.d( TAG, "release" );
if ( mCmdMap != null && !mCmdMap.isEmpty() && mVoiceClient != null ) {
for ( String cmd : mCmdMap.keySet() ) {
mVoiceClient.unRegisterCustomWakeupCmd( cmd );
}
if ( mTTS != null ) {
mTTS.release();
}
mQAndAMap.clear();
mVoiceClient.release();
mSpeakVoiceMap.clear();
mCacheUnWakeupCommands.clear();
sInstance = null;
}
private final VoiceClient mVoiceClient;
private MogoVoiceManager mogoVoiceManager;
// 免唤醒指令
private Map< String, List< IMogoVoiceCmdCallBack > > mCmdMap = new HashMap<>();
// 问答指令
private Map< String, IMogoVoiceCmdCallBack > mQAndAMap = new HashMap<>();
// 单独的语音播放
private Map< String, IMogoVoiceCmdCallBack > mSpeakVoiceMap = new HashMap<>();
private Map< String, String[] > mCacheUnWakeupCommands = new ConcurrentHashMap<>();
private AIAssist( Context context ) {
// private constructor
mVoiceClient = new VoiceClient( context.getApplicationContext() );
mVoiceClient.setCallBack( this );
initFlushStatus( context );
initSpeech( context );
Logger.w( TAG, "voice is ready = %s", mHasFlush );
}
private void initFlushStatus( Context context ) {
if ( !mHasFlush ) {
mHasFlush = isVoiceServiceReady( context );
}
}
/**
* 初始化
*/
private void initSpeech( Context context ) {
mogoVoiceManager = MogoVoiceManagerImpl.getInstance();
mogoVoiceManager.init( context, new OnConnStatusListener() {
@Override
public void onSuccess() {
mInitReady = true;
}
@Override
public void onFailed() {
}
} );
mTTS = ( IMogoTTS ) ARouter.getInstance().build( MogoTTSConstants.API_PATH ).navigation( context.getApplicationContext() );
}
/**
@@ -111,83 +48,10 @@ public class AIAssist implements VoiceClient.VoiceCmdCallBack, OnTtsListener {
* @return
*/
public boolean hasFlush() {
return mHasFlush;
}
@Override
public void onCmdSelected( String cmd ) {
if ( !mCmdMap.containsKey( cmd ) ) {
return;
}
Logger.d( TAG, "received command: %s", cmd );
Iterator< IMogoVoiceCmdCallBack > iterator = null;
try {
List< IMogoVoiceCmdCallBack > cmdCallBacks = mCmdMap.get( cmd );
iterator = new ArrayList<>( cmdCallBacks ).iterator();
} catch ( Exception e ) {
}
while ( iterator != null && iterator.hasNext() ) {
IMogoVoiceCmdCallBack callBack = iterator.next();
if ( callBack != null ) {
callBack.onCmdSelected( cmd );
}
}
}
@Override
public void onCmdAction( String speakText ) {
if ( !TextUtils.isEmpty( mLastQAndASpeakText ) ) {
IMogoVoiceCmdCallBack cmdCallBack = mQAndAMap.remove( mLastQAndASpeakText );
if ( cmdCallBack != null ) {
cmdCallBack.onCmdAction( speakText );
}
}
}
@Override
public void onCmdCancel( String speakText ) {
if ( !TextUtils.isEmpty( mLastQAndASpeakText ) ) {
IMogoVoiceCmdCallBack cmdCallBack = mQAndAMap.remove( mLastQAndASpeakText );
if ( cmdCallBack != null ) {
cmdCallBack.onCmdCancel( speakText );
}
}
}
@Override
public void onSpeakEnd( String speakText ) {
if ( mQAndAMap.containsKey( speakText ) ) {
mLastQAndASpeakText = speakText;
IMogoVoiceCmdCallBack cmdCallBack = mQAndAMap.get( speakText );
if ( cmdCallBack != null ) {
cmdCallBack.onSpeakEnd( speakText );
return;
}
}
IMogoVoiceCmdCallBack callBack = mSpeakVoiceMap.remove( speakText );
if ( callBack != null ) {
callBack.onSpeakEnd( speakText );
}
}
@Override
public void onSpeakSelectTimeOut( String speakText ) {
if ( mQAndAMap.containsKey( speakText ) ) {
if ( TextUtils.equals( speakText, mLastQAndASpeakText ) ) {
mLastQAndASpeakText = null;
}
IMogoVoiceCmdCallBack cmdCallBack = mQAndAMap.remove( speakText );
if ( cmdCallBack != null ) {
cmdCallBack.onSpeakSelectTimeOut( speakText );
return;
}
}
IMogoVoiceCmdCallBack callBack = mSpeakVoiceMap.remove( speakText );
if ( callBack != null ) {
callBack.onSpeakSelectTimeOut( speakText );
if ( mTTS != null ) {
return mTTS.hasFlush();
}
return false;
}
/**
@@ -196,13 +60,8 @@ public class AIAssist implements VoiceClient.VoiceCmdCallBack, OnTtsListener {
* @param text
*/
public void speakTTSVoice( String text, IMogoVoiceCmdCallBack callBack ) {
try {
initFlushStatus( AbsMogoApplication.getApp() );
if ( mHasFlush ) {
mSpeakVoiceMap.put( text, callBack );
mVoiceClient.speakDefault( text );
}
} catch ( Exception e ) {
if ( mTTS != null ) {
mTTS.speakTTSVoice( text, callBack );
}
}
@@ -212,12 +71,8 @@ public class AIAssist implements VoiceClient.VoiceCmdCallBack, OnTtsListener {
* @param text
*/
public void speakTTSVoice( String text ) {
try {
initFlushStatus( AbsMogoApplication.getApp() );
if ( mHasFlush ) {
mVoiceClient.speakDefault( text );
}
} catch ( Exception e ) {
if ( mTTS != null ) {
mTTS.speakTTSVoice( text );
}
}
@@ -228,13 +83,25 @@ public class AIAssist implements VoiceClient.VoiceCmdCallBack, OnTtsListener {
* @param type 播报策略
*/
public void speakTTSVoice( String text, VoicePreemptType type, IMogoVoiceCmdCallBack callBack ) {
try {
initFlushStatus( AbsMogoApplication.getApp() );
if ( mHasFlush ) {
mSpeakVoiceMap.put( text, callBack );
mVoiceClient.speakTypeText( text, type.getPreemptType() );
if ( mTTS != null ) {
PreemptType preemptType = PreemptType.PREEMPT_TYPE_NONE;
if ( type != null ) {
switch ( type ) {
case PREEMPT_TYPE_FLUSH:
preemptType = PreemptType.PREEMPT_TYPE_FLUSH;
break;
case PREEMPT_TYPE_NEXT:
preemptType = PreemptType.PREEMPT_TYPE_NEXT;
break;
case PREEMPT_TYPE_IMMEADIATELY:
preemptType = PreemptType.PREEMPT_TYPE_IMMEDIATELY;
break;
case PREEMPT_TYPE_IMMEADIATELY_WITHOUT_CANCLE:
preemptType = PreemptType.PREEMPT_TYPE_IMMEDIATELY_WITHOUT_CANCEL;
break;
}
}
} catch ( Exception e ) {
mTTS.speakTTSVoice( text, preemptType, callBack );
}
}
@@ -244,10 +111,8 @@ public class AIAssist implements VoiceClient.VoiceCmdCallBack, OnTtsListener {
* @param tts 播报内容
*/
public void speakQAndACmd( String tts, IMogoVoiceCmdCallBack callBack ) {
initFlushStatus( AbsMogoApplication.getApp() );
if ( mHasFlush ) {
mQAndAMap.put( tts, callBack );
mVoiceClient.speakTtsAndRegistCmd( tts );
if ( mTTS != null ) {
mTTS.speakQAndACmd( tts, callBack );
}
}
@@ -259,10 +124,8 @@ public class AIAssist implements VoiceClient.VoiceCmdCallBack, OnTtsListener {
* @param cancelCmds 取消命令唤醒词
*/
public void speakQAndACmd( String tts, String[] okCmds, String[] cancelCmds, IMogoVoiceCmdCallBack callBack ) {
initFlushStatus( AbsMogoApplication.getApp() );
if ( mHasFlush ) {
mQAndAMap.put( tts, callBack );
mVoiceClient.speakTtsAndRegistCmd( tts, okCmds, cancelCmds );
if ( mTTS != null ) {
mTTS.speakQAndACmd( tts, okCmds, cancelCmds, callBack );
}
}
@@ -274,47 +137,9 @@ public class AIAssist implements VoiceClient.VoiceCmdCallBack, OnTtsListener {
* @param callBack
*/
public void registerUnWakeupCommand( String cmd, String[] cmdWords, IMogoVoiceCmdCallBack callBack ) {
if ( !mCmdMap.containsKey( cmd ) ) {
mCmdMap.put( cmd, new ArrayList<>() );
if ( mTTS != null ) {
mTTS.registerUnWakeupCommand( cmd, cmdWords, callBack );
}
mCmdMap.get( cmd ).add( callBack );
initFlushStatus( AbsMogoApplication.getApp() );
if ( mHasFlush ) {
mVoiceClient.registerCustomWakeupCmd( cmd, cmdWords );
mCacheUnWakeupCommands.remove( cmd );
}
Logger.i( TAG, "cache un wakeup command2. %s", cmd );
mCacheUnWakeupCommands.put( cmd, cmdWords );
}
/**
* 注册免唤醒命令
*
* @param cmd
* @param cmdWords
*/
public void registerUnWakeupCommand( String cmd, String[] cmdWords ) {
initFlushStatus( AbsMogoApplication.getApp() );
if ( mHasFlush ) {
mVoiceClient.registerCustomWakeupCmd( cmd, cmdWords );
mCacheUnWakeupCommands.remove( cmd );
}
Logger.i( TAG, "cache un wakeup command. %s", cmd );
mCacheUnWakeupCommands.put( cmd, cmdWords );
}
/**
* 注册免唤醒命令回调
*
* @param cmd
* @param callBack
*/
public synchronized void registerUnWakeupCommandCallback( String cmd, IMogoVoiceCmdCallBack callBack ) {
if ( !mCmdMap.containsKey( cmd ) ) {
mCmdMap.put( cmd, new ArrayList<>() );
}
mCmdMap.get( cmd ).add( callBack );
}
/**
@@ -323,9 +148,9 @@ public class AIAssist implements VoiceClient.VoiceCmdCallBack, OnTtsListener {
* @param cmd
*/
public synchronized void unregisterUnWakeupCommand( String cmd ) {
mCmdMap.remove( cmd );
mVoiceClient.unRegisterCustomWakeupCmd( cmd );
mCacheUnWakeupCommands.remove( cmd );
if ( mTTS != null ) {
mTTS.unregisterUnWakeupCommand( cmd );
}
}
/**
@@ -334,20 +159,12 @@ public class AIAssist implements VoiceClient.VoiceCmdCallBack, OnTtsListener {
* @param cmd
*/
public synchronized void unregisterUnWakeupCommand( String cmd, IMogoVoiceCmdCallBack callBack ) {
if ( mCmdMap.containsKey( cmd ) ) {
List< IMogoVoiceCmdCallBack > callBacks = mCmdMap.get( cmd );
if ( callBacks != null ) {
callBacks.remove( callBack );
}
if ( callBacks.isEmpty() ) {
mCmdMap.remove( cmd );
mVoiceClient.unRegisterCustomWakeupCmd( cmd );
mCacheUnWakeupCommands.remove( cmd );
}
if ( mTTS != null ) {
mTTS.unregisterUnWakeupCommand( cmd, callBack );
}
}
public static void startAssistant( Context context ) {
public void startAssistant( Context context ) {
startAssistant( context, 1 );
}
@@ -355,127 +172,33 @@ public class AIAssist implements VoiceClient.VoiceCmdCallBack, OnTtsListener {
* @param context
* @param status window_start_cancel 0 - 结束, 1 - 显示, 2 - 未激活调试进入
*/
public static void startAssistant( Context context, int status ) {
final Intent intent = new Intent();
intent.setFlags( Intent.FLAG_INCLUDE_STOPPED_PACKAGES );
intent.setAction( "pvetec.intent.action.txz.switch" );
intent.putExtra( "window_start_cancel", status );
intent.putExtra( "extra_switch_type", "window_start_cancel" );
Logger.d( TAG, "status = %d", status );
context.sendBroadcast( intent );
public void startAssistant( Context context, int status ) {
if ( mTTS != null ) {
mTTS.startAIAssist( context, status );
}
}
public synchronized void flush() {
if ( mCacheUnWakeupCommands.isEmpty() ) {
return;
if ( mTTS != null ) {
mTTS.flush();
}
mHasFlush = true;
Logger.d( TAG, "flush cache voice command when voice service ready." );
final Map< String, String[] > tmp = new HashMap<>( mCacheUnWakeupCommands );
for ( String cmd : tmp.keySet() ) {
registerUnWakeupCommand( cmd, tmp.get( cmd ) );
}
}
private boolean isVoiceServiceReady( Context context ) {
if ( isProcessRunning( context, getPackageUid( context, "com.zhidao.speech" ) )
&& isProcessRunning( context, getPackageUid( context, "com.zhidao.speech.adapter" ) ) ) {
return true;
} else if (isProcessRunning(context, getPackageUid(context, "com.txznet.txz")) && isProcessRunning(context, getPackageUid(context, "com.txznet.adapter"))) {
Logger.d(TAG, "txz is voiceServiceReady");
return true;
}
return false;
}
// private boolean isRunningTaskExist( Context context, String processName ) {
//// ActivityManager am = ( ActivityManager ) context.getSystemService( Context.ACTIVITY_SERVICE );
//// List< ActivityManager.RunningAppProcessInfo > processList = am.getRunningAppProcesses();
//// for ( ActivityManager.RunningAppProcessInfo info : processList ) {
//// if ( info.processName.equals( processName ) ) {
//// return true;
//// }
//// }
//// return false;
//// }
/**
* 方法描述:判断某一应用是否正在运行
* Created by cafeting on 2017/2/4.
*
* @param context 上下文
* @param packageName 应用的包名
* @return true 表示正在运行false 表示没有运行
*/
public static boolean isAppRunning( Context context, String packageName ) {
ActivityManager am = ( ActivityManager ) context.getSystemService( Context.ACTIVITY_SERVICE );
List< ActivityManager.RunningTaskInfo > list = am.getRunningTasks( 100 );
if ( list.size() <= 0 ) {
return false;
}
for ( ActivityManager.RunningTaskInfo info : list ) {
if ( info.baseActivity.getPackageName().equals( packageName ) ) {
return true;
}
}
return false;
}
//获取已安装应用的 uid-1 表示未安装此应用或程序异常
public static int getPackageUid( Context context, String packageName ) {
try {
ApplicationInfo applicationInfo = context.getPackageManager().getApplicationInfo( packageName, 0 );
if ( applicationInfo != null ) {
return applicationInfo.uid;
}
} catch ( Exception e ) {
return -1;
}
return -1;
}
/**
* 判断某一 uid 的程序是否有正在运行的进程,即是否存活
* Created by cafeting on 2017/2/4.
*
* @param context 上下文
* @param uid 已安装应用的 uid
* @return true 表示正在运行false 表示没有运行
*/
public static boolean isProcessRunning( Context context, int uid ) {
ActivityManager am = ( ActivityManager ) context.getSystemService( Context.ACTIVITY_SERVICE );
List< ActivityManager.RunningServiceInfo > runningServiceInfos = am.getRunningServices( 200 );
if ( runningServiceInfos.size() > 0 ) {
for ( ActivityManager.RunningServiceInfo appProcess : runningServiceInfos ) {
if ( uid == appProcess.uid ) {
return true;
}
}
}
return false;
}
public void speakTTSAndDuck( String text ) {
speakTTSAndDuck( text, null );
if ( mTTS != null ) {
mTTS.speakTTSAndDuck( text );
}
}
public void speakTTSAndDuck( String text, IMogoVoiceCmdCallBack callBack ) {
try {
if ( mInitReady ) {
mSpeakVoiceMap.put( text, callBack );
mogoVoiceManager.toSpeak( text, -3, this );
}
} catch ( Exception e ) {
if ( mTTS != null ) {
mTTS.speakTTSAndDuck( text, callBack );
}
}
public void shutUp( String ttsId, String text ) {
try {
mSpeakVoiceMap.remove( text );
mogoVoiceManager.shutUp( ttsId );
} catch ( Exception e ) {
if ( mTTS != null ) {
mTTS.shutUp( ttsId, text );
}
}
@@ -483,40 +206,15 @@ public class AIAssist implements VoiceClient.VoiceCmdCallBack, OnTtsListener {
* 打断上一条正在播报的语音内容仅在Speech上生效TXZ为空实现
* 语音SDK生效版本从1.0.8.4版本起
*/
public void breakOffSpeak(){
mVoiceClient.breakOffSpeak();
public void breakOffSpeak() {
if ( mTTS != null ) {
mTTS.breakOffSpeak();
}
}
public void clearTTSCallback( String text ) {
try {
mSpeakVoiceMap.remove( text );
} catch ( Exception e ) {
e.printStackTrace();
if ( mTTS != null ) {
mTTS.clearTTSCallback( text );
}
}
@Override
public void onTtsStart( String ttsId, String text ) {
IMogoVoiceCmdCallBack callBack = mSpeakVoiceMap.get( text );
if ( callBack != null ) {
callBack.onTTSStart( ttsId, text );
}
}
@Override
public void onTtsFinish( String ttsId, String text ) {
IMogoVoiceCmdCallBack callBack = mSpeakVoiceMap.remove( text );
if ( callBack != null ) {
callBack.onTTSEnd( ttsId, text );
}
}
@Override
public void onTtsError( String ttsId, String text ) {
IMogoVoiceCmdCallBack callBack = mSpeakVoiceMap.remove( text );
if ( callBack != null ) {
callBack.onTTSError( ttsId, text );
}
}
}

View File

@@ -1,66 +1,7 @@
package com.mogo.commons.voice;
public interface IMogoVoiceCmdCallBack {
import com.mogo.tts.base.IMogoTTSCallback;
/**
* 新SDK接口
*
* @param ttsId
* @param tts
*/
default void onTTSStart( String ttsId, String tts ) {
}
public interface IMogoVoiceCmdCallBack extends IMogoTTSCallback {
/**
* 新SDK接口
*
* @param ttsId
* @param tts
*/
default void onTTSEnd( String ttsId, String tts ) {
}
/**
* 新SDK接口
*
* @param ttsId
* @param tts
*/
default void onTTSError( String ttsId, String tts ) {
}
/**
* 免唤醒命令响应回调
*
* @param cmd
*/
default void onCmdSelected( String cmd ){}
/**
* 语音播报临时免唤醒“确定”命令
*
* @param speakText 播报内容
*/
default void onCmdAction( String speakText ){}
/**
* 语音播报临时免唤醒“取消”命令
*
* @param speakText 播报内容
*/
default void onCmdCancel( String speakText ){}
/**
* 语音播报完毕
*
* @param speakText 播报内容
*/
default void onSpeakEnd( String speakText ){}
/**
* 语音播报完临时命令选择超时
*
* @param speakText 播报内容
*/
default void onSpeakSelectTimeOut( String speakText ){}
}

View File

@@ -1,23 +1,9 @@
package com.mogo.commons.voice;
import com.zhidao.auto.platform.voice.VoiceClient;
public enum VoicePreemptType {
PREEMPT_TYPE_NONE( VoiceClient.PreemptType.PREEMPT_TYPE_NONE ), //不打断
PREEMPT_TYPE_IMMEADIATELY( VoiceClient.PreemptType.PREEMPT_TYPE_IMMEADIATELY ), //立即打断取消当前的tts插队播放
PREEMPT_TYPE_NEXT( VoiceClient.PreemptType.PREEMPT_TYPE_NEXT ), //下一个插入,不取消当前tts,插队下一个播放
PREEMPT_TYPE_FLUSH( VoiceClient.PreemptType.PREEMPT_TYPE_FLUSH ), //清空队列
PREEMPT_TYPE_IMMEADIATELY_WITHOUT_CANCLE( VoiceClient.PreemptType.PREEMPT_TYPE_IMMEADIATELY_WITHOUT_CANCLE ); //立即打断不取消当前tts
public VoiceClient.PreemptType preemptType;
VoicePreemptType( VoiceClient.PreemptType preemptType ) {
this.preemptType = preemptType;
}
public VoiceClient.PreemptType getPreemptType() {
return preemptType;
}
PREEMPT_TYPE_NONE, //不打断
PREEMPT_TYPE_IMMEADIATELY, //立即打断取消当前的tts插队播放
PREEMPT_TYPE_NEXT, //下一个插入不取消当前的tts插队下一个播放
PREEMPT_TYPE_FLUSH, //清空队列
PREEMPT_TYPE_IMMEADIATELY_WITHOUT_CANCLE; //立即打断不取消当前tts
}

View File

@@ -87,4 +87,38 @@ public class AppUtils {
}
return false;
}
//获取已安装应用的 uid-1 表示未安装此应用或程序异常
public static int getPackageUid( Context context, String packageName ) {
try {
ApplicationInfo applicationInfo = context.getPackageManager().getApplicationInfo( packageName, 0 );
if ( applicationInfo != null ) {
return applicationInfo.uid;
}
} catch ( Exception e ) {
return -1;
}
return -1;
}
/**
* 判断某一 uid 的程序是否有正在运行的进程,即是否存活
* Created by cafeting on 2017/2/4.
*
* @param context 上下文
* @param uid 已安装应用的 uid
* @return true 表示正在运行false 表示没有运行
*/
public static boolean isProcessRunning( Context context, int uid ) {
ActivityManager am = ( ActivityManager ) context.getSystemService( Context.ACTIVITY_SERVICE );
List< ActivityManager.RunningServiceInfo > runningServiceInfos = am.getRunningServices( 200 );
if ( runningServiceInfos.size() > 0 ) {
for ( ActivityManager.RunningServiceInfo appProcess : runningServiceInfos ) {
if ( uid == appProcess.uid ) {
return true;
}
}
}
return false;
}
}

View File

@@ -98,6 +98,10 @@ MOGO_MODULE_MONITOR_VERSION=2.0.0
CRASHREPORT_VERSION=2.0.0
CRASHREPORT_BUGLY_VERSION=2.0.0
CRASHREPORT_NOOP_VERSION=2.0.0
## tts
TTS_BASE_VERSION=1.0.0
TTS_DI_VERSION=1.0.0
TTS_ZHI_VERSION=1.0.0
######## 外部依赖引用
# 车聊聊

View File

@@ -4,7 +4,6 @@ import android.text.TextUtils;
import com.mogo.commons.AbsMogoApplication;
import com.mogo.commons.voice.AIAssist;
import com.mogo.commons.voice.IMogoVoiceCmdCallBack;
import java.util.LinkedList;
@@ -16,7 +15,7 @@ import java.util.LinkedList;
* <p>
* 策略:队列缓存预播报的 tts然后上一句播完后
*/
public class TTSSpeaker implements IMogoVoiceCmdCallBack {
public class TTSSpeaker {
private static volatile TTSSpeaker sInstance;
@@ -48,7 +47,6 @@ public class TTSSpeaker implements IMogoVoiceCmdCallBack {
return;
}
mWaiting.add( tts );
peekAndSpeak();
}
public synchronized void shutUp() {
@@ -60,61 +58,5 @@ public class TTSSpeaker implements IMogoVoiceCmdCallBack {
}
}
@Override
public void onCmdSelected( String cmd ) {
}
@Override
public void onCmdAction( String speakText ) {
}
@Override
public void onCmdCancel( String speakText ) {
}
@Override
public void onSpeakEnd( String speakText ) {
}
@Override
public void onSpeakSelectTimeOut( String speakText ) {
}
@Override
public void onTTSStart( String ttsId, String tts ) {
if ( TextUtils.equals( mLastTts, tts ) ) {
mLastTtsId = ttsId;
}
}
@Override
public void onTTSEnd( String ttsId, String tts ) {
mLastTtsId = null;
peekAndSpeak();
}
@Override
public void onTTSError( String ttsId, String tts ) {
mLastTtsId = null;
peekAndSpeak();
}
private synchronized void peekAndSpeak() {
if ( mWaiting.isEmpty() ) {
mLastTts = null;
mLastTtsId = null;
return;
}
if ( mLastTtsId != null ) {
// 上一句还没有播完
return;
}
mLastTts = mWaiting.pop();
AIAssist.getInstance( AbsMogoApplication.getApp() ).speakTTSAndDuck( mLastTts, this );
}
}

View File

@@ -27,10 +27,10 @@ class OnAiAssistClickListener implements View.OnClickListener {
@Override
public void onClick( View v ) {
if ( Devices.isBind() || !DebugConfig.isActiveAIAssistFlag() ) {
AIAssist.startAssistant( v.getContext() );
AIAssist.getInstance( v.getContext() ).startAssistant( v.getContext() );
} else {
if ( mDebugModeOpen ) {
AIAssist.startAssistant( v.getContext(), 1 );
AIAssist.getInstance( v.getContext() ).startAssistant( v.getContext(), 1 );
return;
}
if ( mClickCounter == 0 ) {
@@ -38,7 +38,7 @@ class OnAiAssistClickListener implements View.OnClickListener {
mClickCounter++;
} else {
if ( mClickCounter == TOTAL_CLICK_AMOUNT ) {
AIAssist.startAssistant( v.getContext(), 2 );
AIAssist.getInstance( v.getContext() ).startAssistant( v.getContext(), 2 );
TipToast.shortTip( "开启语音调试" );
mClickCounter = 0;
mLastClickTime = 0L;

View File

@@ -8,6 +8,7 @@ import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import com.alibaba.android.arouter.facade.annotation.Route;
import com.mogo.commons.debug.DebugConfig;
import com.mogo.module.common.MogoApisHandler;
import com.mogo.module.common.utils.CarSeries;
import com.mogo.service.IMogoServiceApis;
@@ -50,8 +51,19 @@ public class BackToLauncherModuleProvider implements IMogoModuleProvider {
@Override
public void init( Context context ) {
if ( CarSeries.getSeries() == CarSeries.CAR_SERIES_F80X ) {
BackToMainHomeManager.addMainHomeView();
final String product = DebugConfig.getProductFlavor();
if ( product != null ) {
switch ( product ) {
case "f80x":
case "f8xx":
BackToMainHomeManager.addMainHomeView();
break;
case "changanauto":
if ( DebugConfig.isDebug() ) {
BackToMainHomeManager.addMainHomeView();
}
break;
}
}
mServiceApis = MogoApisHandler.getInstance().getApis();
BackToMainHomeManager.init( mServiceApis );

View File

@@ -1,57 +0,0 @@
package com.mogo.module.tanlu.voice
import com.zhidao.auto.platform.voice.VoiceClient
/**
* @description 声音控制类
*
* @author lixiaopeng
* @since 2019-11-01
*/
object VoiceController {
private lateinit var voiceClient: VoiceClient
// fun initVoice() {
// voiceClient = VoiceClient.getInstance(BaseApplication.getAppContext())
// }
/**
* 设置语音命令回调接口
* @param callBack
*/
fun setCallBack(callBack: VoiceClient.VoiceCmdCallBack) {
voiceClient.setCallBack(callBack)
}
/**
* @param speakText 语音播报内容
*/
fun speakVoice(speakText: String) {
voiceClient.speakDefault(speakText)
}
/**
* 注册免唤醒命令
* @param customType 命令
* @param customWakeupCmd 命令对应的唤醒词集合
*/
fun registerCustomWakeupCmd(customType: String, customWakeupCmd: Array<String>) {
voiceClient.registerCustomWakeupCmd(customType, customWakeupCmd)
}
/**
* 取消免唤醒命令
* @param customType 命令
*/
fun unRegisterCustomWakeupCmd(customType: String) {
voiceClient.unRegisterCustomWakeupCmd(customType)
}
/**
* 释放资源(界面销毁的时候调用)
*/
fun release() {
voiceClient.release()
}
}

View File

@@ -1,3 +1,6 @@
include ':tts:tts-base'
include ':tts:tts-di'
include ':tts:tts-zhi'
include ':test:crashreport'
include ':test:crashreport-bugly'
include ':test:crashreport-noop'
@@ -58,3 +61,4 @@ include ':modules:mogo-module-tanlu'
include ':libraries:tanlulib'
include ':skin'
include ':test'
include ':tts'

1
tts/tts-base/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
/build

44
tts/tts-base/build.gradle Normal file
View File

@@ -0,0 +1,44 @@
apply plugin: 'com.android.library'
apply plugin: 'com.alibaba.arouter'
android {
compileSdkVersion rootProject.ext.android.compileSdkVersion
// buildToolsVersion rootProject.ext.android.buildToolsVersion
defaultConfig {
minSdkVersion rootProject.ext.android.minSdkVersion
targetSdkVersion rootProject.ext.android.targetSdkVersion
versionCode Integer.valueOf(VERSION_CODE)
versionName getValueFromRootProperties("${project.name.replace("-", "_").toUpperCase()}_VERSION")
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles "consumer-rules.pro"
javaCompileOptions {
annotationProcessorOptions {
arguments = [AROUTER_MODULE_NAME: project.getName()]
}
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(dir: "libs", include: ["*.jar"])
implementation rootProject.ext.dependencies.androidxappcompat
implementation rootProject.ext.dependencies.arouter
annotationProcessor rootProject.ext.dependencies.aroutercompiler
}
apply from: new File(rootProject.rootDir, "gradle/upload.gradle").toString()

View File

View File

@@ -0,0 +1,3 @@
GROUP=com.mogo.tts
POM_ARTIFACT_ID=tts-base
VERSION_CODE=1

21
tts/tts-base/proguard-rules.pro vendored Normal file
View File

@@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

View File

@@ -0,0 +1,5 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.mogo.tts.base">
/
</manifest>

View File

@@ -0,0 +1,153 @@
package com.mogo.tts.base;
import android.content.Context;
import com.alibaba.android.arouter.facade.template.IProvider;
public
/**
* @author congtaowang
* @since 2020/10/12
*
* 语音抽象
*/
interface IMogoTTS extends IProvider {
/**
* 释放资源
*/
void release();
/**
* 缓存的语音指令注册状态
*
* @return true - 已注册、false - 未注册
*/
default boolean hasFlush() {
return true;
}
/**
* 将缓存的免唤醒指令全部注册一遍
*/
void flush();
/**
* 播报 tts 语音
*
* @param tts 语音内容
*/
void speakTTSVoice( String tts );
/**
* 播放 tts 语音
*
* @param tts 语音内容
* @param callback 回调
* {@link IMogoTTSCallback#onSpeakEnd(String)}
*/
void speakTTSVoice( String tts, IMogoTTSCallback callback );
/**
* 播放 tts并设置播报类型
*
* @param tts 语音内容
* @param type 播报类型 {@link PreemptType}
* @param callback 回调
* {@link IMogoTTSCallback#onSpeakEnd(String)}
*/
void speakTTSVoice( String tts, PreemptType type, IMogoTTSCallback callback );
/**
* 注册问答指令,默认恢复:确认、取消
*
* @param tts 播报内容
* @param callback 回调
* {@link IMogoTTSCallback#onCmdAction(String)}
* {@link IMogoTTSCallback#onCmdCancel(String)} (String)}
* {@link IMogoTTSCallback#onSpeakSelectTimeOut(String)} (String)}
*/
void speakQAndACmd( String tts, IMogoTTSCallback callback );
/**
* 注册问答指令,默认恢复:确认、取消
*
* @param tts 播报内容
* @param okWords 确认指令唤醒词
* @param cancelWords 取消指令唤醒词
* @param callback 回调
* {@link IMogoTTSCallback#onCmdAction(String)}
* {@link IMogoTTSCallback#onCmdCancel(String)} (String)}
* {@link IMogoTTSCallback#onSpeakSelectTimeOut(String)} (String)}
*/
void speakQAndACmd( String tts, String[] okWords, String[] cancelWords, IMogoTTSCallback callback );
/**
* 注册免唤醒指令
*
* @param cmd 免唤醒指令
* @param cmdWords 免唤醒词组
* @param callback 回调
* {@link IMogoTTSCallback#onCmdSelected(String)}
*/
void registerUnWakeupCommand( String cmd, String[] cmdWords, IMogoTTSCallback callback );
/**
* 注销免唤醒指令
*
* @param cmd 指令
*/
void unregisterUnWakeupCommand( String cmd );
/**
* 注销免唤醒指令
*
* @param cmd 指令
* @param callback 具体注销的回调对象(部分指令复用的情况)
*/
void unregisterUnWakeupCommand( String cmd, IMogoTTSCallback callback );
/**
* 启动语音
*
* @param context
*/
void startAIAssist( Context context );
/**
* 启动语音
*
* @param context
* @param status window_start_cancel
* 0 - 结束
* 1 - 显示
* 2 - 未激活调试进入
*/
void startAIAssist( Context context, int status );
/**
* 中断正在播报的语音内容
*/
void breakOffSpeak();
// Deprecated api, but should keep...
@Deprecated
default void speakTTSAndDuck( String tts ) {
}
@Deprecated
default void speakTTSAndDuck( String tts, IMogoTTSCallback callback ) {
}
@Deprecated
default void shutUp( String ttsId, String text ) {
}
default void clearTTSCallback( String tts ) {
}
}

View File

@@ -0,0 +1,81 @@
package com.mogo.tts.base;
public
/**
* @author congtaowang
* @since 2020/10/12
*
* 描述
*/
interface IMogoTTSCallback {
/**
* 新SDK接口
*
* @param ttsId
* @param tts
*/
@Deprecated
default void onTTSStart( String ttsId, String tts ) {
}
/**
* 新SDK接口
*
* @param ttsId
* @param tts
*/
@Deprecated
default void onTTSEnd( String ttsId, String tts ) {
}
/**
* 新SDK接口
*
* @param ttsId
* @param tts
*/
@Deprecated
default void onTTSError( String ttsId, String tts ) {
}
/**
* 免唤醒命令响应回调
*
* @param cmd
*/
default void onCmdSelected( String cmd ) {
}
/**
* 语音播报临时免唤醒“确定”命令
*
* @param speakText 播报内容
*/
default void onCmdAction( String speakText ) {
}
/**
* 语音播报临时免唤醒“取消”命令
*
* @param speakText 播报内容
*/
default void onCmdCancel( String speakText ) {
}
/**
* 语音播报完毕
*
* @param speakText 播报内容
*/
default void onSpeakEnd( String speakText ) {
}
/**
* 语音播报完临时命令选择超时
*
* @param speakText 播报内容
*/
default void onSpeakSelectTimeOut( String speakText ) {
}
}

View File

@@ -0,0 +1,15 @@
package com.mogo.tts.base;
public
/**
* @author congtaowang
* @since 2020/10/12
* <p>
* 描述
*/
interface MogoTTSConstants {
String API_PATH = "/tts/api";
String API_NAME = "TTS";
}

View File

@@ -0,0 +1,32 @@
package com.mogo.tts.base;
public
/**
* @author congtaowang
* @since 2020/10/12
*
* 语音打算类型
*/
enum PreemptType {
/**
* 不打断
*/
PREEMPT_TYPE_NONE,
/**
* 立即打断取消当前的tts插队播放
*/
PREEMPT_TYPE_IMMEDIATELY,
/**
* 下一个插入不取消当前的tts插队下一个播放
*/
PREEMPT_TYPE_NEXT,
/**
* 清空队列
*/
PREEMPT_TYPE_FLUSH,
/**
* 立即打断不取消当前tts
*/
PREEMPT_TYPE_IMMEDIATELY_WITHOUT_CANCEL
}

1
tts/tts-di/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
/build

50
tts/tts-di/build.gradle Normal file
View File

@@ -0,0 +1,50 @@
apply plugin: 'com.android.library'
apply plugin: 'com.alibaba.arouter'
android {
compileSdkVersion rootProject.ext.android.compileSdkVersion
// buildToolsVersion rootProject.ext.android.buildToolsVersion
defaultConfig {
minSdkVersion rootProject.ext.android.minSdkVersion
targetSdkVersion rootProject.ext.android.targetSdkVersion
versionCode Integer.valueOf(VERSION_CODE)
versionName getValueFromRootProperties("${project.name.replace("-", "_").toUpperCase()}_VERSION")
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles "consumer-rules.pro"
javaCompileOptions {
annotationProcessorOptions {
arguments = [AROUTER_MODULE_NAME: project.getName()]
}
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
dependencies {
implementation fileTree(dir: "libs", include: ["*.jar"])
implementation rootProject.ext.dependencies.androidxappcompat
implementation rootProject.ext.dependencies.arouter
annotationProcessor rootProject.ext.dependencies.aroutercompiler
if (Boolean.valueOf(RELEASE)) {
implementation rootProject.ext.dependencies.ttsbase
} else {
implementation project(":tts:tts-base")
}
}
apply from: new File(rootProject.rootDir, "gradle/upload.gradle").toString()

View File

View File

@@ -0,0 +1,3 @@
GROUP=com.mogo.tts
POM_ARTIFACT_ID=tts-di
VERSION_CODE=1

21
tts/tts-di/proguard-rules.pro vendored Normal file
View File

@@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

View File

@@ -0,0 +1,5 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.mogo.tts.di">
/
</manifest>

View File

@@ -0,0 +1,98 @@
package com.mogo.tts.di;
import android.content.Context;
import android.util.Log;
import com.alibaba.android.arouter.facade.annotation.Route;
import com.mogo.tts.base.IMogoTTS;
import com.mogo.tts.base.IMogoTTSCallback;
import com.mogo.tts.base.MogoTTSConstants;
import com.mogo.tts.base.PreemptType;
public
/**
* @author congtaowang
* @since 2020/10/12
*
* 比亚迪语音播报
*/
@Route( path = MogoTTSConstants.API_PATH )
class DiTTS implements IMogoTTS {
private static final String TAG = "DiTTS";
private Context mContext;
@Override
public void release() {
mContext = null;
}
@Override
public void flush() {
Log.d( TAG, "noop - flush" );
}
@Override
public void speakTTSVoice( String tts ) {
TTSManager.getInstance().speakTTS( mContext, tts );
}
@Override
public void speakTTSVoice( String tts, IMogoTTSCallback callback ) {
speakTTSVoice( tts );
}
@Override
public void speakTTSVoice( String tts, PreemptType type, IMogoTTSCallback callback ) {
speakTTSVoice( tts );
}
@Override
public void speakQAndACmd( String tts, IMogoTTSCallback callback ) {
Log.d( TAG, "noop - speakQAndACmd" );
}
@Override
public void speakQAndACmd( String tts, String[] okWords, String[] cancelWords, IMogoTTSCallback callback ) {
Log.d( TAG, "noop - speakQAndACmd2" );
}
@Override
public void registerUnWakeupCommand( String cmd, String[] cmdWords, IMogoTTSCallback callback ) {
Log.d( TAG, "noop - registerUnWakeupCommand" );
}
@Override
public void unregisterUnWakeupCommand( String cmd ) {
Log.d( TAG, "noop - unregisterUnWakeupCommand" );
}
@Override
public void unregisterUnWakeupCommand( String cmd, IMogoTTSCallback callback ) {
Log.d( TAG, "noop - unregisterUnWakeupCommand2" );
}
@Override
public void startAIAssist( Context context ) {
Log.d( TAG, "noop - startAIAssist" );
}
@Override
public void startAIAssist( Context context, int status ) {
Log.d( TAG, "noop - startAIAssist2" );
}
@Override
public void breakOffSpeak() {
TTSManager.getInstance().breakOffSpeak( mContext );
}
@Override
public void init( Context context ) {
if ( context != null ) {
mContext = context.getApplicationContext();
}
}
}

View File

@@ -0,0 +1,99 @@
package com.mogo.tts.di;
import android.content.Context;
import android.content.Intent;
public
/**
* @author congtaowang
* @since 2020/10/12
*
* 语音播报
*/
class TTSManager {
/**
* 语音播报广播 action
*/
public static final String ACTION_SPEAK_TTS = "com.byd.NotifyService.thirdTts";
/**
* 播报语音内容
*/
public static final String EXTRA_TTS_CONTENT = "thirdVoiceText";
/**
* 发音人“0”表示使用默认发音人或设置为“1”表示吉祥物发音人
*/
public static final String EXTRA_TTS_SPEAKER = "thirdSpeaker";
/**
* 值类型为String型可以设置为“THIRD_PLAY”表示请求播报或设置为“THIRD_STOP”表示终止播报
*/
public static final String EXTRA_TTS_ACTION = "thirdType";
public final String VAL_THIRD_PLAY = "THIRD_PLAY";
public final String VAL_THIRD_STOP = "THIRD_STOP";
/**
* 值类型为Boolean 型,可以设置为 true,表示打开语音界面显示文字,并播报内容,或设置 为 false,表示后台播报内容。
*/
public static final String EXTRA_TTS_SHOW_UI = "booleanShowText";
private static volatile TTSManager sInstance;
private TTSManager() {
}
public static TTSManager getInstance() {
if ( sInstance == null ) {
synchronized ( TTSManager.class ) {
if ( sInstance == null ) {
sInstance = new TTSManager();
}
}
}
return sInstance;
}
public synchronized void release() {
sInstance = null;
}
private Object readResolve() {
// 阻止反序列化,必须实现 Serializable 接口
return sInstance;
}
/**
* 播报 tts
*
* @param context
* @param tts
*/
public void speakTTS( Context context, String tts ) {
if ( context == null ) {
return;
}
Intent intent = new Intent();
intent.setAction( ACTION_SPEAK_TTS );
intent.putExtra( EXTRA_TTS_CONTENT, tts );
intent.putExtra( EXTRA_TTS_SPEAKER, 0 );
intent.putExtra( EXTRA_TTS_ACTION, VAL_THIRD_PLAY );
intent.putExtra( EXTRA_TTS_SHOW_UI, false );
context.sendBroadcast( intent );
}
/**
* 打断播报
*
* @param context
*/
public void breakOffSpeak( Context context ) {
if ( context == null ) {
return;
}
Intent intent = new Intent();
intent.setAction( ACTION_SPEAK_TTS );
intent.putExtra( EXTRA_TTS_ACTION, VAL_THIRD_STOP );
context.sendBroadcast( intent );
}
}

1
tts/tts-zhi/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
/build

54
tts/tts-zhi/build.gradle Normal file
View File

@@ -0,0 +1,54 @@
apply plugin: 'com.android.library'
apply plugin: 'com.alibaba.arouter'
android {
compileSdkVersion rootProject.ext.android.compileSdkVersion
// buildToolsVersion rootProject.ext.android.buildToolsVersion
defaultConfig {
minSdkVersion rootProject.ext.android.minSdkVersion
targetSdkVersion rootProject.ext.android.targetSdkVersion
versionCode Integer.valueOf(VERSION_CODE)
versionName getValueFromRootProperties("${project.name.replace("-", "_").toUpperCase()}_VERSION")
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles "consumer-rules.pro"
javaCompileOptions {
annotationProcessorOptions {
arguments = [AROUTER_MODULE_NAME: project.getName()]
}
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
dependencies {
implementation fileTree(dir: "libs", include: ["*.jar"])
implementation rootProject.ext.dependencies.androidxappcompat
implementation rootProject.ext.dependencies.arouter
annotationProcessor rootProject.ext.dependencies.aroutercompiler
api rootProject.ext.dependencies.aiassist
api rootProject.ext.dependencies.aiassistReplace
if (Boolean.valueOf(RELEASE)) {
implementation rootProject.ext.dependencies.ttsbase
implementation rootProject.ext.dependencies.mogoutils
} else {
implementation project(":tts:tts-base")
implementation project(":foudations:mogo-utils")
}
}
apply from: new File(rootProject.rootDir, "gradle/upload.gradle").toString()

View File

View File

@@ -0,0 +1,3 @@
GROUP=com.mogo.tts
POM_ARTIFACT_ID=tts-zhi
VERSION_CODE=1

21
tts/tts-zhi/proguard-rules.pro vendored Normal file
View File

@@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

View File

@@ -0,0 +1,5 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.mogo.tts.zhi">
/
</manifest>

View File

@@ -0,0 +1,472 @@
package com.mogo.tts.zhi;
import android.content.Context;
import android.content.Intent;
import android.text.TextUtils;
import com.alibaba.android.arouter.facade.annotation.Route;
import com.mogo.tts.base.IMogoTTS;
import com.mogo.tts.base.IMogoTTSCallback;
import com.mogo.tts.base.MogoTTSConstants;
import com.mogo.tts.base.PreemptType;
import com.mogo.utils.AppUtils;
import com.mogo.utils.logger.Logger;
import com.zhidao.auto.platform.voice.VoiceClient;
import com.zhidao.voicesdk.MogoVoiceManager;
import com.zhidao.voicesdk.MogoVoiceManagerImpl;
import com.zhidao.voicesdk.callback.OnConnStatusListener;
import com.zhidao.voicesdk.callback.OnTtsListener;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public
/**
* @author congtaowang
* @since 2020/10/12
* <p>
* 描述
*/
@Route( path = MogoTTSConstants.API_PATH )
class ZhiTTS implements IMogoTTS, VoiceClient.VoiceCmdCallBack, OnTtsListener {
private static final String TAG = "ZhiTTS";
private String mLastQAndASpeakText;
private boolean mHasFlush = false;
private boolean mInitReady = false;
private Context mContext;
public synchronized void release() {
Logger.d( TAG, "release" );
if ( mCmdMap != null && !mCmdMap.isEmpty() && mVoiceClient != null ) {
for ( String cmd : mCmdMap.keySet() ) {
mVoiceClient.unRegisterCustomWakeupCmd( cmd );
}
}
mQAndAMap.clear();
mVoiceClient.release();
mSpeakVoiceMap.clear();
mCacheUnWakeupCommands.clear();
mContext = null;
}
private VoiceClient mVoiceClient;
private MogoVoiceManager mogoVoiceManager;
// 免唤醒指令
private Map< String, List< IMogoTTSCallback > > mCmdMap = new HashMap<>();
// 问答指令
private Map< String, IMogoTTSCallback > mQAndAMap = new HashMap<>();
// 单独的语音播放
private Map< String, IMogoTTSCallback > mSpeakVoiceMap = new HashMap<>();
private Map< String, String[] > mCacheUnWakeupCommands = new ConcurrentHashMap<>();
private void initFlushStatus() {
if ( !mHasFlush ) {
mHasFlush = isVoiceServiceReady( mContext );
}
}
/**
* 初始化
*/
private void initSpeech( Context context ) {
mogoVoiceManager = MogoVoiceManagerImpl.getInstance();
mogoVoiceManager.init( context, new OnConnStatusListener() {
@Override
public void onSuccess() {
mInitReady = true;
}
@Override
public void onFailed() {
}
} );
}
/**
* 是否语音注册成功
*
* @return
*/
@Override
public boolean hasFlush() {
return mHasFlush;
}
@Override
public void onCmdSelected( String cmd ) {
if ( !mCmdMap.containsKey( cmd ) ) {
return;
}
Logger.d( TAG, "received command: %s", cmd );
Iterator< IMogoTTSCallback > iterator = null;
try {
List< IMogoTTSCallback > cmdCallBacks = mCmdMap.get( cmd );
iterator = new ArrayList<>( cmdCallBacks ).iterator();
} catch ( Exception e ) {
}
while ( iterator != null && iterator.hasNext() ) {
IMogoTTSCallback callBack = iterator.next();
if ( callBack != null ) {
callBack.onCmdSelected( cmd );
}
}
}
@Override
public void onCmdAction( String speakText ) {
if ( !TextUtils.isEmpty( mLastQAndASpeakText ) ) {
IMogoTTSCallback cmdCallBack = mQAndAMap.remove( mLastQAndASpeakText );
if ( cmdCallBack != null ) {
cmdCallBack.onCmdAction( speakText );
}
}
}
@Override
public void onCmdCancel( String speakText ) {
if ( !TextUtils.isEmpty( mLastQAndASpeakText ) ) {
IMogoTTSCallback cmdCallBack = mQAndAMap.remove( mLastQAndASpeakText );
if ( cmdCallBack != null ) {
cmdCallBack.onCmdCancel( speakText );
}
}
}
@Override
public void onSpeakEnd( String speakText ) {
if ( mQAndAMap.containsKey( speakText ) ) {
mLastQAndASpeakText = speakText;
IMogoTTSCallback cmdCallBack = mQAndAMap.get( speakText );
if ( cmdCallBack != null ) {
cmdCallBack.onSpeakEnd( speakText );
return;
}
}
IMogoTTSCallback callBack = mSpeakVoiceMap.remove( speakText );
if ( callBack != null ) {
callBack.onSpeakEnd( speakText );
}
}
@Override
public void onSpeakSelectTimeOut( String speakText ) {
if ( mQAndAMap.containsKey( speakText ) ) {
if ( TextUtils.equals( speakText, mLastQAndASpeakText ) ) {
mLastQAndASpeakText = null;
}
IMogoTTSCallback cmdCallBack = mQAndAMap.remove( speakText );
if ( cmdCallBack != null ) {
cmdCallBack.onSpeakSelectTimeOut( speakText );
return;
}
}
IMogoTTSCallback callBack = mSpeakVoiceMap.remove( speakText );
if ( callBack != null ) {
callBack.onSpeakSelectTimeOut( speakText );
}
}
/**
* 语音播报
*
* @param text
*/
public void speakTTSVoice( String text, IMogoTTSCallback callBack ) {
try {
initFlushStatus();
if ( mHasFlush ) {
mSpeakVoiceMap.put( text, callBack );
mVoiceClient.speakDefault( text );
}
} catch ( Exception e ) {
}
}
/**
* 语音播报
*
* @param text
*/
public void speakTTSVoice( String text ) {
try {
initFlushStatus();
if ( mHasFlush ) {
mVoiceClient.speakDefault( text );
}
} catch ( Exception e ) {
}
}
/**
* 语音播报
*
* @param text 播报内容
* @param type 播报策略
*/
public void speakTTSVoice( String text, PreemptType type, IMogoTTSCallback callBack ) {
try {
initFlushStatus();
if ( mHasFlush ) {
mSpeakVoiceMap.put( text, callBack );
VoiceClient.PreemptType preemptType = VoiceClient.PreemptType.PREEMPT_TYPE_NONE;
if ( type != null ) {
switch ( type ) {
case PREEMPT_TYPE_NEXT:
preemptType = VoiceClient.PreemptType.PREEMPT_TYPE_NEXT;
break;
case PREEMPT_TYPE_FLUSH:
preemptType = VoiceClient.PreemptType.PREEMPT_TYPE_FLUSH;
break;
case PREEMPT_TYPE_IMMEDIATELY:
preemptType = VoiceClient.PreemptType.PREEMPT_TYPE_IMMEADIATELY;
break;
case PREEMPT_TYPE_IMMEDIATELY_WITHOUT_CANCEL:
preemptType = VoiceClient.PreemptType.PREEMPT_TYPE_IMMEADIATELY_WITHOUT_CANCLE;
break;
}
}
mVoiceClient.speakTypeText( text, preemptType );
}
} catch ( Exception e ) {
}
}
/**
* 问答类型语音注册:默认确认和取消
*
* @param tts 播报内容
*/
public void speakQAndACmd( String tts, IMogoTTSCallback callBack ) {
initFlushStatus();
if ( mHasFlush ) {
mQAndAMap.put( tts, callBack );
mVoiceClient.speakTtsAndRegistCmd( tts );
}
}
/**
* 问答类型语音注册
*
* @param tts 播报内容
* @param okCmds 确认命令唤醒词
* @param cancelCmds 取消命令唤醒词
*/
public void speakQAndACmd( String tts, String[] okCmds, String[] cancelCmds, IMogoTTSCallback callBack ) {
initFlushStatus();
if ( mHasFlush ) {
mQAndAMap.put( tts, callBack );
mVoiceClient.speakTtsAndRegistCmd( tts, okCmds, cancelCmds );
}
}
/**
* 注册免唤醒命令
*
* @param cmd
* @param cmdWords
* @param callBack
*/
public void registerUnWakeupCommand( String cmd, String[] cmdWords, IMogoTTSCallback callBack ) {
if ( !mCmdMap.containsKey( cmd ) ) {
mCmdMap.put( cmd, new ArrayList<>() );
}
mCmdMap.get( cmd ).add( callBack );
initFlushStatus();
if ( mHasFlush ) {
mVoiceClient.registerCustomWakeupCmd( cmd, cmdWords );
mCacheUnWakeupCommands.remove( cmd );
}
Logger.i( TAG, "cache un wakeup command2. %s", cmd );
mCacheUnWakeupCommands.put( cmd, cmdWords );
}
/**
* 注册免唤醒命令
*
* @param cmd
* @param cmdWords
*/
private void registerUnWakeupCommand( String cmd, String[] cmdWords ) {
initFlushStatus();
if ( mHasFlush ) {
mVoiceClient.registerCustomWakeupCmd( cmd, cmdWords );
mCacheUnWakeupCommands.remove( cmd );
}
Logger.i( TAG, "cache un wakeup command. %s", cmd );
mCacheUnWakeupCommands.put( cmd, cmdWords );
}
/**
* 注销免唤醒命令
*
* @param cmd
*/
public synchronized void unregisterUnWakeupCommand( String cmd ) {
mCmdMap.remove( cmd );
mVoiceClient.unRegisterCustomWakeupCmd( cmd );
mCacheUnWakeupCommands.remove( cmd );
}
/**
* 注销免唤醒命令
*
* @param cmd
*/
public synchronized void unregisterUnWakeupCommand( String cmd, IMogoTTSCallback callBack ) {
if ( mCmdMap.containsKey( cmd ) ) {
List< IMogoTTSCallback > callBacks = mCmdMap.get( cmd );
if ( callBacks != null ) {
callBacks.remove( callBack );
}
if ( callBacks.isEmpty() ) {
mCmdMap.remove( cmd );
mVoiceClient.unRegisterCustomWakeupCmd( cmd );
mCacheUnWakeupCommands.remove( cmd );
}
}
}
public static void startAssistant( Context context ) {
startAssistant( context, 1 );
}
/**
* @param context
* @param status window_start_cancel 0 - 结束, 1 - 显示, 2 - 未激活调试进入
*/
public static void startAssistant( Context context, int status ) {
final Intent intent = new Intent();
intent.setFlags( Intent.FLAG_INCLUDE_STOPPED_PACKAGES );
intent.setAction( "pvetec.intent.action.txz.switch" );
intent.putExtra( "window_start_cancel", status );
intent.putExtra( "extra_switch_type", "window_start_cancel" );
Logger.d( TAG, "status = %d", status );
context.sendBroadcast( intent );
}
public synchronized void flush() {
if ( mCacheUnWakeupCommands.isEmpty() ) {
return;
}
mHasFlush = true;
Logger.d( TAG, "flush cache voice command when voice service ready." );
final Map< String, String[] > tmp = new HashMap<>( mCacheUnWakeupCommands );
for ( String cmd : tmp.keySet() ) {
registerUnWakeupCommand( cmd, tmp.get( cmd ) );
}
}
private boolean isVoiceServiceReady( Context context ) {
if ( AppUtils.isProcessRunning( context, AppUtils.getPackageUid( context, "com.zhidao.speech" ) )
&& AppUtils.isProcessRunning( context, AppUtils.getPackageUid( context, "com.zhidao.speech.adapter" ) ) ) {
return true;
} else if ( AppUtils.isProcessRunning( context, AppUtils.getPackageUid( context, "com.txznet.txz" ) )
&& AppUtils.isProcessRunning( context, AppUtils.getPackageUid( context, "com.txznet.adapter" ) ) ) {
Logger.d( TAG, "txz is voiceServiceReady" );
return true;
}
return false;
}
public void speakTTSAndDuck( String text ) {
speakTTSAndDuck( text, null );
}
public void speakTTSAndDuck( String text, IMogoTTSCallback callBack ) {
try {
if ( mInitReady ) {
mSpeakVoiceMap.put( text, callBack );
mogoVoiceManager.toSpeak( text, -3, this );
}
} catch ( Exception e ) {
}
}
public void shutUp( String ttsId, String text ) {
try {
mSpeakVoiceMap.remove( text );
mogoVoiceManager.shutUp( ttsId );
} catch ( Exception e ) {
}
}
/**
* 打断上一条正在播报的语音内容仅在Speech上生效TXZ为空实现
* 语音SDK生效版本从1.0.8.4版本起
*/
public void breakOffSpeak() {
mVoiceClient.breakOffSpeak();
}
public void clearTTSCallback( String text ) {
try {
mSpeakVoiceMap.remove( text );
} catch ( Exception e ) {
e.printStackTrace();
}
}
@Override
public void onTtsStart( String ttsId, String text ) {
IMogoTTSCallback callBack = mSpeakVoiceMap.get( text );
if ( callBack != null ) {
callBack.onTTSStart( ttsId, text );
}
}
@Override
public void onTtsFinish( String ttsId, String text ) {
IMogoTTSCallback callBack = mSpeakVoiceMap.remove( text );
if ( callBack != null ) {
callBack.onTTSEnd( ttsId, text );
}
}
@Override
public void onTtsError( String ttsId, String text ) {
IMogoTTSCallback callBack = mSpeakVoiceMap.remove( text );
if ( callBack != null ) {
callBack.onTTSError( ttsId, text );
}
}
@Override
public void init( Context context ) {
if ( context != null ) {
mContext = context.getApplicationContext();
mVoiceClient = new VoiceClient( mContext );
mVoiceClient.setCallBack( this );
initFlushStatus();
initSpeech( context );
Logger.w( TAG, "voice is ready = %s", mHasFlush );
}
}
@Override
public void startAIAssist( Context context ) {
startAssistant( context, 1 );
}
@Override
public void startAIAssist( Context context, int status ) {
final Intent intent = new Intent();
intent.setFlags( Intent.FLAG_INCLUDE_STOPPED_PACKAGES );
intent.setAction( "pvetec.intent.action.txz.switch" );
intent.putExtra( "window_start_cancel", status );
intent.putExtra( "extra_switch_type", "window_start_cancel" );
Logger.d( TAG, "status = %d", status );
context.sendBroadcast( intent );
}
}

View File

@@ -4,6 +4,12 @@
if [ $? -ne 0 ];then exit; fi
./gradlew :skin:mogo-skin-support:clean :skin:mogo-skin-support:uploadArchives
if [ $? -ne 0 ]; then exit; fi
./gradlew :tts:tts-base:clean :tts:tts-base:uploadArchives
if [ $? -ne 0 ]; then exit; fi
./gradlew :tts:tts-zhi:clean :tts:tts-zhi:uploadArchives
if [ $? -ne 0 ]; then exit; fi
./gradlew :tts:tts-di:clean :tts:tts-di:uploadArchives
if [ $? -ne 0 ]; then exit; fi
./gradlew :foudations:mogo-commons:clean :foudations:mogo-commons:uploadArchives
if [ $? -ne 0 ]; then exit; fi
./gradlew :libraries:mogo-map-api:clean :libraries:mogo-map-api:uploadArchives