跨进程通讯
This commit is contained in:
@@ -31,6 +31,15 @@
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<service
|
||||
android:name=".TTSService"
|
||||
android:exported="true"
|
||||
android:process=":ttsP"
|
||||
>
|
||||
<intent-filter>
|
||||
<action android:name="com.mogo.tts.ttsservice" />
|
||||
</intent-filter>
|
||||
</service>
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
@@ -5,8 +5,18 @@ import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.appcompat.widget.AppCompatButton
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
import com.mogo.tts.common.IMogoTTSCallback
|
||||
import com.mogo.tts.common.log.TtsLogManager
|
||||
import kotlin.random.Random
|
||||
|
||||
class MainActivity : AppCompatActivity() {
|
||||
|
||||
private val ttsManager = TtsManager()
|
||||
|
||||
private val TAG = "MainActivity"
|
||||
|
||||
private val ranx = Random(10)
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_main)
|
||||
@@ -17,10 +27,31 @@ class MainActivity : AppCompatActivity() {
|
||||
}
|
||||
|
||||
findViewById<AppCompatButton>(R.id.actv_test_tts1).setOnClickListener {
|
||||
TtsManager.speakTTSVoice("此时每个单兵要负责自己的一个视线防区")
|
||||
//TtsInnerManager.speakTTSVoice("此时每个单兵要负责自己的一个视线防区")
|
||||
val info = "此时每个单兵要负责自己的一个视线防区${ranx.nextInt()}"
|
||||
TtsLogManager.d(TAG,"要播放的语音:${info}")
|
||||
ttsManager.speakTTSVoice(info,object :IMogoTTSCallback{
|
||||
override fun onSpeakStart(speakText: String?) {
|
||||
TtsLogManager.d(TAG,"onSpeakStart:${speakText}")
|
||||
}
|
||||
|
||||
override fun onSpeakComple(speakText: String?) {
|
||||
TtsLogManager.d(TAG,"onSpeakComple:${speakText}")
|
||||
}
|
||||
|
||||
override fun onStopTts(speakText: String?) {
|
||||
TtsLogManager.d(TAG,"onStopTts:${speakText}")
|
||||
}
|
||||
|
||||
override fun onSpeakError(speakText: String?, errorMsg: String?) {
|
||||
TtsLogManager.d(TAG,"onSpeakError:${speakText}")
|
||||
}
|
||||
})
|
||||
}
|
||||
findViewById<AppCompatButton>(R.id.actv_test_tts2).setOnClickListener {
|
||||
TtsManager.stopTTS()
|
||||
ttsManager.stopTTS()
|
||||
}
|
||||
|
||||
ttsManager.bindService(this)
|
||||
}
|
||||
}
|
||||
@@ -30,7 +30,7 @@ class MoGoApplication : Application() {
|
||||
}
|
||||
|
||||
private fun initTts() {
|
||||
TtsManager.init(this)
|
||||
TTSService.start(this)
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -8,6 +8,6 @@ import android.os.Build
|
||||
object PhoneUtilsExtend {
|
||||
|
||||
fun getDevicesSn(): String {
|
||||
return Build.getSerial()
|
||||
return "name"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.mogo.tts;
|
||||
|
||||
import com.mogo.tts.ITTSCallbackBinder;
|
||||
|
||||
interface ICoreBinder {
|
||||
|
||||
void speakTTSVoice1(String tts);
|
||||
|
||||
void speakTTSVoice2(String tts,in ITTSCallbackBinder callback);
|
||||
|
||||
void speakTTSVoic3(String tts, int languageType,in ITTSCallbackBinder callback);
|
||||
|
||||
void registerTtsListener(String tag,in ITTSCallbackBinder callback);
|
||||
|
||||
void unRegisterTtsListener(String tag);
|
||||
|
||||
void clearTtsListener();
|
||||
|
||||
void stopTts();
|
||||
|
||||
void stopTtsByText(String tts);
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.mogo.tts;
|
||||
|
||||
|
||||
oneway interface ITTSCallbackBinder {
|
||||
void onSpeakStart(String speakText);
|
||||
void onSpeakComple(String speakText);
|
||||
void onStopTts(String speakText);
|
||||
void onSpeakError(String speakText,String errorMsg);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,254 @@
|
||||
package com.mogo.tts
|
||||
|
||||
import android.app.Notification
|
||||
import android.app.NotificationChannel
|
||||
import android.app.NotificationManager
|
||||
import android.app.Service
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
import android.os.IBinder
|
||||
import androidx.core.app.NotificationCompat
|
||||
import com.mogo.tts.common.IMogoTTSCallback
|
||||
import com.mogo.tts.common.LangTtsEntity
|
||||
import com.mogo.tts.common.R
|
||||
import com.mogo.tts.common.log.TtsLogManager
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
|
||||
class TTSService : Service() {
|
||||
|
||||
private val TAG = "TTSService"
|
||||
|
||||
private val globalStart = "global_"
|
||||
|
||||
// 🔥 最佳方案:ConcurrentHashMap 管理回调(key = tag,value = 回调)
|
||||
private val callbackMap = ConcurrentHashMap<String, ITTSCallbackBinder>()
|
||||
|
||||
|
||||
private val iCorebinder = object : ICoreBinder.Stub() {
|
||||
override fun speakTTSVoice1(tts: String?) {
|
||||
// 防御空字符串
|
||||
val text = tts?.takeIf { it.isNotEmpty() } ?: return
|
||||
TtsInnerManager.speakTTSVoice(tts)
|
||||
}
|
||||
|
||||
override fun speakTTSVoice2(tts: String?, callback: ITTSCallbackBinder?) {
|
||||
// 防御空字符串
|
||||
val text = tts?.takeIf { it.isNotEmpty() } ?: return
|
||||
if(callback==null){
|
||||
TtsInnerManager.speakTTSVoice(tts)
|
||||
return
|
||||
}
|
||||
// 先缓存 callback
|
||||
callbackMap[text] = callback
|
||||
|
||||
TtsInnerManager.speakTTSVoice(tts,object :IMogoTTSCallback{
|
||||
override fun onSpeakStart(speakText: String?) {
|
||||
val cb = callbackMap[speakText] ?: return
|
||||
safeCallback {
|
||||
cb.onSpeakStart(speakText)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onSpeakComple(speakText: String?){
|
||||
val cb = callbackMap[speakText] ?: return
|
||||
safeCallback {
|
||||
cb.onSpeakComple(speakText)
|
||||
}
|
||||
// ✅ 执行完自动销毁 callback
|
||||
callbackMap.remove(speakText)
|
||||
}
|
||||
|
||||
override fun onStopTts(speakText: String?) {
|
||||
val cb = callbackMap[speakText] ?: return
|
||||
safeCallback {
|
||||
cb.onStopTts(speakText)
|
||||
}
|
||||
// ✅ 执行完自动销毁 callback
|
||||
callbackMap.remove(speakText)
|
||||
}
|
||||
|
||||
override fun onSpeakError(speakText: String?, errorMsg: String?) {
|
||||
val cb = callbackMap[speakText] ?: return
|
||||
safeCallback {
|
||||
cb.onSpeakError(speakText,errorMsg)
|
||||
}
|
||||
// ✅ 执行完自动销毁 callback
|
||||
callbackMap.remove(speakText)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
override fun speakTTSVoic3(tts: String?, languageType: Int, callback: ITTSCallbackBinder?) {
|
||||
// 防御空字符串
|
||||
val text = tts?.takeIf { it.isNotEmpty() } ?: return
|
||||
if(callback==null){
|
||||
TtsInnerManager.speakTTSVoice(tts)
|
||||
return
|
||||
}
|
||||
// 先缓存 callback
|
||||
callbackMap[text] = callback
|
||||
|
||||
val langTtsEntity = LangTtsEntity.getLangTtsEntity(tts, languageType)
|
||||
|
||||
TtsInnerManager.speakTTSVoice(langTtsEntity,object :IMogoTTSCallback{
|
||||
override fun onSpeakStart(speakText: String?) {
|
||||
val cb = callbackMap[speakText] ?: return
|
||||
safeCallback {
|
||||
cb.onSpeakStart(speakText)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onSpeakComple(speakText: String?) {
|
||||
val cb = callbackMap[speakText] ?: return
|
||||
safeCallback {
|
||||
cb.onSpeakComple(speakText)
|
||||
}
|
||||
// ✅ 执行完自动销毁 callback
|
||||
callbackMap.remove(speakText)
|
||||
}
|
||||
|
||||
override fun onStopTts(speakText: String?) {
|
||||
val cb = callbackMap[speakText] ?: return
|
||||
safeCallback {
|
||||
cb.onStopTts(speakText)
|
||||
}
|
||||
// ✅ 执行完自动销毁 callback
|
||||
callbackMap.remove(speakText)
|
||||
}
|
||||
|
||||
override fun onSpeakError(speakText: String?, errorMsg: String?) {
|
||||
val cb = callbackMap[speakText] ?: return
|
||||
safeCallback {
|
||||
cb.onSpeakError(speakText,errorMsg)
|
||||
}
|
||||
// ✅ 执行完自动销毁 callback
|
||||
callbackMap.remove(speakText)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
override fun registerTtsListener(tag: String?, callback: ITTSCallbackBinder?) {
|
||||
if(tag.isNullOrEmpty()){
|
||||
return
|
||||
}
|
||||
if(callback==null){
|
||||
return
|
||||
}
|
||||
val key = "${globalStart}${tag}"
|
||||
callbackMap[key] = callback
|
||||
}
|
||||
|
||||
override fun unRegisterTtsListener(tag: String?) {
|
||||
if(tag.isNullOrEmpty()){
|
||||
return
|
||||
}
|
||||
val key = "${globalStart}${tag}"
|
||||
callbackMap.remove(key)
|
||||
}
|
||||
|
||||
override fun clearTtsListener() {
|
||||
callbackMap.clear()
|
||||
}
|
||||
|
||||
override fun stopTts() {
|
||||
TtsInnerManager.stopTTS()
|
||||
}
|
||||
|
||||
override fun stopTtsByText(tts: String?) {
|
||||
// TODO: 如果正在播放直接停止、如果在排队播放从队伍中移除
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
companion object{
|
||||
fun start(context: Context) {
|
||||
val serviceIntent = Intent(context, TTSService::class.java)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
context.startForegroundService(serviceIntent)
|
||||
} else {
|
||||
context.startService(serviceIntent)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
TtsLogManager.d(TAG,"onCreate")
|
||||
TtsInnerManager.init(applicationContext)
|
||||
TtsInnerManager.registerTtsListener(object :IMogoTTSCallback{
|
||||
override fun onSpeakStart(speakText: String?) {
|
||||
callbackMap.forEach {
|
||||
if (it.key.startsWith(globalStart)) {
|
||||
safeCallback {
|
||||
it.value.onSpeakStart(speakText)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override fun onSpeakComple(speakText: String?) {
|
||||
callbackMap.forEach {
|
||||
if (it.key.startsWith(globalStart)) {
|
||||
safeCallback {
|
||||
it.value.onSpeakComple(speakText)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onSpeakError(speakText: String?, errorMsg: String) {
|
||||
callbackMap.forEach {
|
||||
if (it.key.startsWith(globalStart)) {
|
||||
safeCallback {
|
||||
it.value.onSpeakError(speakText,errorMsg)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
override fun onBind(intent: Intent?): IBinder? {
|
||||
TtsLogManager.d(TAG,"onBind")
|
||||
return iCorebinder
|
||||
}
|
||||
|
||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||
TtsLogManager.d(TAG,"onStartCommand")
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
val manager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
|
||||
if (manager != null) {
|
||||
val nc = NotificationChannel("Voice", "语音服务", NotificationManager.IMPORTANCE_HIGH)
|
||||
manager.createNotificationChannel(nc)
|
||||
}
|
||||
}
|
||||
val notification: Notification = NotificationCompat.Builder(applicationContext, "Voice")
|
||||
.setContentTitle("语音服务运行中")
|
||||
.setSmallIcon(R.drawable.voice_manager_icon)
|
||||
.build()
|
||||
|
||||
startForeground(1, notification)
|
||||
return START_STICKY
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
TtsLogManager.d(TAG,"onDestroy")
|
||||
super.onDestroy()
|
||||
TtsInnerManager.unRegisterTtsListener()
|
||||
TtsInnerManager.release()
|
||||
}
|
||||
|
||||
|
||||
// 跨进程回调安全工具方法
|
||||
private inline fun safeCallback(call: () -> Unit) {
|
||||
try {
|
||||
call()
|
||||
} catch (e: Exception) {
|
||||
TtsLogManager.e(TAG,e.toString(),e)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
package com.mogo.tts
|
||||
|
||||
import android.content.Context
|
||||
import com.mogo.tts.common.IMogoTTS
|
||||
import com.mogo.tts.common.IMogoTTSCallback
|
||||
import com.mogo.tts.common.LangTtsEntity
|
||||
import com.mogo.tts.common.LanguageType
|
||||
import com.mogo.tts.common.log.TtsLogManager
|
||||
|
||||
object TtsInnerManager {
|
||||
|
||||
private const val TAG = "TtsManager"
|
||||
|
||||
private var mTTS: IMogoTTS? = null
|
||||
|
||||
fun init(context: Context) {
|
||||
try {
|
||||
// 暂时换成反射,解决死锁问题
|
||||
var clazz1: Class<*>? = null
|
||||
try {
|
||||
// clazz1 = Class.forName("com.mogo.tts.iflytek.offline.IFlyTekOfflineTts")
|
||||
clazz1 = Class.forName("com.k2fsa.sherpa.onnx.MogoOfflineTTS")
|
||||
} catch (ignored: Exception) {
|
||||
}
|
||||
|
||||
if (clazz1 != null) {
|
||||
mTTS = clazz1.getConstructor().newInstance() as IMogoTTS
|
||||
}
|
||||
mTTS?.initTts(context)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
TtsLogManager.d(TAG, "TTS 模块初始化异常")
|
||||
}
|
||||
}
|
||||
|
||||
fun speakTTSVoice(tts: String?) {
|
||||
if(tts.isNullOrEmpty()) return
|
||||
speakTTSVoice(tts,null)
|
||||
}
|
||||
|
||||
|
||||
fun speakTTSVoice(tts: String?, callBack: IMogoTTSCallback?) {
|
||||
if(tts.isNullOrEmpty()) return
|
||||
speakTTSVoice(LangTtsEntity(tts, LanguageType.CHINESE), callBack);
|
||||
}
|
||||
|
||||
fun speakTTSVoice(ttsEntity: LangTtsEntity, callBack: IMogoTTSCallback?) {
|
||||
if(ttsEntity.ttsContent.isEmpty()){
|
||||
return
|
||||
}
|
||||
mTTS?.speakTTSVoice(ttsEntity, callBack)
|
||||
}
|
||||
|
||||
fun registerTtsListener(callback: IMogoTTSCallback) {
|
||||
mTTS?.registerTtsListener(callback)
|
||||
}
|
||||
|
||||
fun unRegisterTtsListener() {
|
||||
mTTS?.unRegisterTtsListener()
|
||||
}
|
||||
|
||||
fun stopTTS() {
|
||||
mTTS?.stopTts()
|
||||
}
|
||||
|
||||
fun release() {
|
||||
mTTS?.release()
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,42 +1,33 @@
|
||||
package com.mogo.tts
|
||||
|
||||
import android.content.ComponentName
|
||||
import android.content.Context
|
||||
import com.mogo.tts.common.IGlobalTtsCallback
|
||||
import com.mogo.tts.common.IMogoTTS
|
||||
import android.content.Intent
|
||||
import android.content.ServiceConnection
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.Build
|
||||
import android.os.IBinder
|
||||
import android.os.RemoteException
|
||||
import com.elegant.utils.UiThreadHandler
|
||||
import com.mogo.tts.common.IMogoTTSCallback
|
||||
import com.mogo.tts.common.LangTtsEntity
|
||||
import com.mogo.tts.common.LanguageType
|
||||
import com.mogo.tts.common.log.TtsLogManager
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
|
||||
object TtsManager {
|
||||
|
||||
private const val TAG = "TtsManager"
|
||||
|
||||
private var mTTS: IMogoTTS? = null
|
||||
|
||||
fun init(context: Context) {
|
||||
try {
|
||||
// 暂时换成反射,解决死锁问题
|
||||
var clazz1: Class<*>? = null
|
||||
try {
|
||||
//clazz1 = Class.forName("com.mogo.tts.iflytek.offline.IFlyTekOfflineTts")
|
||||
clazz1 = Class.forName("com.k2fsa.sherpa.onnx.MogoOfflineTTS")
|
||||
} catch (ignored: Exception) {
|
||||
}
|
||||
|
||||
if (clazz1 != null) {
|
||||
mTTS = clazz1.getConstructor().newInstance() as IMogoTTS
|
||||
}
|
||||
mTTS?.initTts(context)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
TtsLogManager.d(TAG, "TTS 模块初始化异常")
|
||||
}
|
||||
class TtsManager {
|
||||
companion object {
|
||||
private const val SERVER_PACKAGE: String = "com.mogo.tts"
|
||||
}
|
||||
|
||||
private val isBind = AtomicBoolean(false)
|
||||
private val isServiceException = AtomicBoolean(false) //服务绑定成功后出现异常
|
||||
protected var binder: ICoreBinder? = null
|
||||
|
||||
private var context: Context? = null
|
||||
|
||||
fun speakTTSVoice(tts: String?) {
|
||||
if(tts.isNullOrEmpty()) return
|
||||
speakTTSVoice(tts,null)
|
||||
speakTTSVoice(LangTtsEntity(tts, LanguageType.CHINESE), null);
|
||||
}
|
||||
|
||||
|
||||
@@ -49,24 +40,172 @@ object TtsManager {
|
||||
if(ttsEntity.ttsContent.isEmpty()){
|
||||
return
|
||||
}
|
||||
mTTS?.speakTTSVoice(ttsEntity, callBack)
|
||||
if(binder!=null){
|
||||
try {
|
||||
binder?.speakTTSVoic3(ttsEntity.ttsContent,ttsEntity.getLanguageDef(),object :
|
||||
ITTSCallbackBinder.Stub() {
|
||||
override fun onSpeakStart(speakText: String?) {
|
||||
callBack?.onSpeakStart(speakText)
|
||||
}
|
||||
|
||||
override fun onSpeakComple(speakText: String?) {
|
||||
callBack?.onSpeakComple(speakText)
|
||||
}
|
||||
|
||||
override fun onStopTts(speakText: String?) {
|
||||
callBack?.onStopTts(speakText)
|
||||
}
|
||||
|
||||
override fun onSpeakError(speakText: String?, errorMsg: String?) {
|
||||
callBack?.onSpeakError(speakText,errorMsg)
|
||||
}
|
||||
})
|
||||
} catch (e: RemoteException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun registerTtsListener(key: String, callback: IGlobalTtsCallback) {
|
||||
mTTS?.registerTtsListener(key, callback)
|
||||
fun registerTtsListener(tag:String,callback: IMogoTTSCallback) {
|
||||
if(binder!=null){
|
||||
try {
|
||||
binder?.registerTtsListener(tag,object :ITTSCallbackBinder.Stub(){
|
||||
override fun onSpeakStart(speakText: String?) {
|
||||
callback.onSpeakStart(speakText)
|
||||
}
|
||||
|
||||
override fun onSpeakComple(speakText: String?) {
|
||||
callback.onSpeakComple(speakText)
|
||||
}
|
||||
|
||||
override fun onStopTts(speakText: String?) {
|
||||
callback.onStopTts(speakText)
|
||||
}
|
||||
|
||||
override fun onSpeakError(speakText: String?, errorMsg: String?) {
|
||||
callback.onSpeakError(speakText,errorMsg)
|
||||
}
|
||||
})
|
||||
} catch (e: RemoteException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun unRegisterTtsListener(key: String) {
|
||||
mTTS?.unRegisterTtsListener(key)
|
||||
fun unRegisterTtsListener(tag: String) {
|
||||
if(binder!=null){
|
||||
try {
|
||||
binder?.unRegisterTtsListener(tag)
|
||||
} catch (e: RemoteException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun stopTTS() {
|
||||
mTTS?.stopTts()
|
||||
if(binder!=null){
|
||||
try {
|
||||
binder?.stopTts()
|
||||
} catch (e: RemoteException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun release() {
|
||||
mTTS?.release()
|
||||
fun stopTTS(tts:String) {
|
||||
if(binder!=null){
|
||||
try {
|
||||
binder?.stopTtsByText(tts)
|
||||
} catch (e: RemoteException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val connection = object : ServiceConnection {
|
||||
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
|
||||
binder = ICoreBinder.Stub.asInterface(service);
|
||||
}
|
||||
|
||||
override fun onServiceDisconnected(name: ComponentName?) {
|
||||
isServiceException.set(true);
|
||||
unbind()
|
||||
delayBind()
|
||||
}
|
||||
}
|
||||
|
||||
fun bindService(
|
||||
context: Context,
|
||||
) {
|
||||
this.context = context
|
||||
bindService()
|
||||
}
|
||||
|
||||
private fun bindService() {
|
||||
context?.let {
|
||||
if (!isBind.get()) {
|
||||
if (isServerInstalled()) {
|
||||
isBind.set(true)
|
||||
val intent = Intent("com.mogo.tts.ttsservice")
|
||||
intent.setPackage(SERVER_PACKAGE)
|
||||
val isSuccess: Boolean =
|
||||
it.bindService(intent, connection, Context.BIND_AUTO_CREATE)
|
||||
if (!isSuccess) {
|
||||
unbind()
|
||||
}
|
||||
} else {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun unbind() {
|
||||
if (binder != null) {
|
||||
try {
|
||||
binder?.clearTtsListener()
|
||||
} catch (e: RemoteException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
binder = null
|
||||
}
|
||||
context?.let {
|
||||
if (isBind.get()) {
|
||||
isBind.set(false)
|
||||
try {
|
||||
it.unbindService(connection)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun delayBind() {
|
||||
if (isServiceException.get()) {
|
||||
isServiceException.set(false)
|
||||
UiThreadHandler.postDelayed({
|
||||
bindService()
|
||||
}, 4000L)
|
||||
}
|
||||
}
|
||||
|
||||
private fun isServerInstalled(): Boolean {
|
||||
context?.let {
|
||||
val pm: PackageManager = it.getPackageManager()
|
||||
return try {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
pm.getApplicationInfo(
|
||||
SERVER_PACKAGE,
|
||||
PackageManager.ApplicationInfoFlags.of(0)
|
||||
).enabled
|
||||
} else {
|
||||
pm.getApplicationInfo(SERVER_PACKAGE, 0).enabled
|
||||
}
|
||||
} catch (e: PackageManager.NameNotFoundException) {
|
||||
false
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,11 @@
|
||||
package com.mogo.tts.common
|
||||
|
||||
interface IGlobalTtsCallback {
|
||||
fun onTtsSpeakStart()
|
||||
fun onTtsSpeakStart(speakText: String?)
|
||||
|
||||
fun onTtsSpeakEnd()
|
||||
fun onTtsSpeakEnd(speakText: String?)
|
||||
|
||||
fun onTtsSpeakComple(speakText: String?)
|
||||
|
||||
fun onTtsSpeakError(speakText: String?, errorMsg: String)
|
||||
}
|
||||
@@ -18,9 +18,9 @@ interface IMogoTTS {
|
||||
*/
|
||||
void release();
|
||||
|
||||
void registerTtsListener(String key, IGlobalTtsCallback callback);
|
||||
void registerTtsListener(IMogoTTSCallback callback);
|
||||
|
||||
void unRegisterTtsListener(String key);
|
||||
void unRegisterTtsListener();
|
||||
|
||||
void speakTTSVoice(LangTtsEntity ttsEntity, IMogoTTSCallback callBack);
|
||||
|
||||
|
||||
@@ -9,46 +9,10 @@ public
|
||||
*/
|
||||
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 ) {
|
||||
}
|
||||
|
||||
|
||||
default void onSpeakStart( String speakText ) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 语音播报完毕
|
||||
*
|
||||
* @param speakText 播报内容
|
||||
*/
|
||||
default void onSpeakEnd( String speakText ) {
|
||||
default void onSpeakComple( String speakText ) {
|
||||
}
|
||||
|
||||
default void onStopTts( String speakText ) {
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.mogo.tts.common
|
||||
|
||||
data class LangTtsEntity(
|
||||
var ttsContent: String,
|
||||
var language: LanguageType
|
||||
) {
|
||||
override fun toString(): String {
|
||||
return "ttsContent is:$ttsContent,language is:${language.langName}"
|
||||
}
|
||||
|
||||
fun getLanguageDef(): Int {
|
||||
return when (language) {
|
||||
LanguageType.CHINESE -> LanguageTypeDef.MODE_CHINESE
|
||||
LanguageType.ENGLISH -> LanguageTypeDef.MODE_ENGLISH
|
||||
LanguageType.KOREAN -> LanguageTypeDef.MODE_KOREAN
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
companion object {
|
||||
fun getLangTtsEntity(tts: String, languageType: Int): LangTtsEntity {
|
||||
val languageType = when (languageType) {
|
||||
LanguageTypeDef.MODE_ENGLISH -> {
|
||||
LanguageType.ENGLISH
|
||||
}
|
||||
|
||||
LanguageTypeDef.MODE_KOREAN -> {
|
||||
LanguageType.KOREAN
|
||||
}
|
||||
|
||||
else -> {
|
||||
LanguageType.CHINESE
|
||||
}
|
||||
}
|
||||
return LangTtsEntity(tts, languageType)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.mogo.tts.common;
|
||||
|
||||
import androidx.annotation.IntDef;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface LanguageTypeDef{
|
||||
public static final int MODE_CHINESE = 0;
|
||||
public static final int MODE_ENGLISH = 1;
|
||||
public static final int MODE_KOREAN = 2;
|
||||
}
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
package com.mogo.tts.common
|
||||
|
||||
data class MultiLangTtsEntity(
|
||||
private var ttsList: List<LangTtsEntity>
|
||||
) {
|
||||
companion object {
|
||||
private const val TIMEOUT_MILLIS = 60000
|
||||
}
|
||||
|
||||
private val stringBuffer by lazy {
|
||||
StringBuffer()
|
||||
}
|
||||
|
||||
private var ttsIndex = 0
|
||||
private var timeStamp: Long = 0
|
||||
|
||||
fun ttsNext(): LangTtsEntity? {
|
||||
return if (ttsIndex in ttsList.indices) {
|
||||
ttsList[ttsIndex++]
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
fun markTime() {
|
||||
timeStamp = System.currentTimeMillis()
|
||||
}
|
||||
|
||||
fun isTimeout():Boolean {
|
||||
return timeStamp > 0 && System.currentTimeMillis() - timeStamp >= TIMEOUT_MILLIS
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return stringBuffer.let {
|
||||
it.setLength(0)
|
||||
ttsList.forEachIndexed { index, langTtsEntity ->
|
||||
if (index != ttsList.size - 1) {
|
||||
it.append("${langTtsEntity};")
|
||||
} else {
|
||||
it.append(langTtsEntity)
|
||||
}
|
||||
}
|
||||
it.toString()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data class LangTtsEntity(
|
||||
var ttsContent: String,
|
||||
var language: LanguageType
|
||||
) {
|
||||
override fun toString(): String {
|
||||
return "ttsContent is:$ttsContent,language is:${language.langName}"
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,6 @@ import android.content.Context;
|
||||
import android.os.Looper;
|
||||
|
||||
import com.elegant.utils.UiThreadHandler;
|
||||
import com.mogo.tts.common.IGlobalTtsCallback;
|
||||
import com.mogo.tts.common.IMogoTTS;
|
||||
import com.mogo.tts.common.IMogoTTSCallback;
|
||||
import com.mogo.tts.common.LangTtsEntity;
|
||||
@@ -20,7 +19,7 @@ public abstract class BaseMogoTTS implements IMogoTTS {
|
||||
protected volatile LangTtsEntity curTtsEntity = null;
|
||||
|
||||
protected HashMap<String, IMogoTTSCallback> speakVoiceMap = new HashMap<>();
|
||||
protected HashMap<String, IGlobalTtsCallback> mGlobalTtsCallback = new HashMap<>();
|
||||
protected IMogoTTSCallback mGlobalTtsCallback = null;
|
||||
|
||||
protected String getTAG() {
|
||||
return "BaseMogoTTS";
|
||||
@@ -31,14 +30,12 @@ public abstract class BaseMogoTTS implements IMogoTTS {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
public void registerTtsListener(String key,IGlobalTtsCallback callback) {
|
||||
if (!mGlobalTtsCallback.containsKey(key)) {
|
||||
this.mGlobalTtsCallback.put(key,callback);
|
||||
}
|
||||
public void registerTtsListener(IMogoTTSCallback callback) {
|
||||
this.mGlobalTtsCallback = callback;
|
||||
}
|
||||
|
||||
public void unRegisterTtsListener(String key){
|
||||
this.mGlobalTtsCallback.remove(key);
|
||||
public void unRegisterTtsListener(){
|
||||
this.mGlobalTtsCallback = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -59,7 +56,6 @@ public abstract class BaseMogoTTS implements IMogoTTS {
|
||||
}
|
||||
|
||||
protected void speakMultiLangTTS(LangTtsEntity ttsEntity){
|
||||
this.curTtsEntity = ttsEntity;
|
||||
// 合成并播放
|
||||
TtsLogManager.d(getTAG(), "tts准备合成:"+ttsEntity);
|
||||
}
|
||||
@@ -80,7 +76,7 @@ public abstract class BaseMogoTTS implements IMogoTTS {
|
||||
if (speakVoiceMap.containsKey(key)) {
|
||||
IMogoTTSCallback remove = speakVoiceMap.remove(key);
|
||||
if(remove!=null) {
|
||||
remove.onStopTts(key);
|
||||
remove.onStopTts(curTtsEntity.getTtsContent());
|
||||
}
|
||||
}
|
||||
curTtsEntity = null;
|
||||
@@ -89,31 +85,27 @@ public abstract class BaseMogoTTS implements IMogoTTS {
|
||||
}
|
||||
|
||||
public void onSpeakBegin() {
|
||||
if(!mGlobalTtsCallback.isEmpty()) {
|
||||
for (IGlobalTtsCallback callback : mGlobalTtsCallback.values()) {
|
||||
callback.onTtsSpeakStart();
|
||||
}
|
||||
if(mGlobalTtsCallback != null) {
|
||||
mGlobalTtsCallback.onSpeakStart(curTtsContent);
|
||||
}
|
||||
if (curTtsEntity!=null) {
|
||||
String key = curTtsEntity.toString();
|
||||
IMogoTTSCallback iMogoTTSCallback = speakVoiceMap.get(key);
|
||||
if(iMogoTTSCallback!=null){
|
||||
iMogoTTSCallback.onSpeakStart(key);
|
||||
iMogoTTSCallback.onSpeakStart(curTtsEntity.getTtsContent());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void handleCompleteEvent() {
|
||||
if(!mGlobalTtsCallback.isEmpty()) {
|
||||
for (IGlobalTtsCallback callback : mGlobalTtsCallback.values()) {
|
||||
callback.onTtsSpeakEnd();
|
||||
}
|
||||
if(mGlobalTtsCallback!=null) {
|
||||
mGlobalTtsCallback.onSpeakComple(curTtsContent);
|
||||
}
|
||||
if (curTtsEntity!=null) {
|
||||
String key = curTtsEntity.toString();
|
||||
IMogoTTSCallback iMogoTTSCallback = speakVoiceMap.get(key);
|
||||
if(iMogoTTSCallback!=null){
|
||||
iMogoTTSCallback.onSpeakEnd(key);
|
||||
iMogoTTSCallback.onSpeakComple(curTtsEntity.getTtsContent());
|
||||
}
|
||||
}
|
||||
curTtsEntity = null;
|
||||
@@ -121,18 +113,19 @@ public abstract class BaseMogoTTS implements IMogoTTS {
|
||||
}
|
||||
|
||||
public void handleErrorEvent(String error) {
|
||||
if(mGlobalTtsCallback!=null) {
|
||||
mGlobalTtsCallback.onSpeakError(curTtsContent,error);
|
||||
}
|
||||
if (curTtsEntity != null) {
|
||||
String key = curTtsEntity.toString();
|
||||
IMogoTTSCallback iMogoTTSCallback = speakVoiceMap.get(key);
|
||||
if(iMogoTTSCallback!=null){
|
||||
iMogoTTSCallback.onSpeakError(key,
|
||||
error);
|
||||
iMogoTTSCallback.onSpeakError(curTtsEntity.getTtsContent(), error);
|
||||
}
|
||||
} else {
|
||||
IMogoTTSCallback iMogoTTSCallback = speakVoiceMap.get(curTtsContent);
|
||||
if(iMogoTTSCallback!=null){
|
||||
iMogoTTSCallback.onSpeakError(curTtsContent,
|
||||
error);
|
||||
iMogoTTSCallback.onSpeakError(curTtsContent, error);
|
||||
}
|
||||
}
|
||||
curTtsEntity = null;
|
||||
|
||||
@@ -48,4 +48,12 @@ object TtsLogManager {
|
||||
}
|
||||
logListener?.writeLog(LogLevel.error,tag,message)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun e(tag: String, message: String,tr:Throwable?) {
|
||||
if(isDebug) {
|
||||
Log.e(tag, message,tr)
|
||||
}
|
||||
logListener?.writeLog(LogLevel.error,tag,message)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#000000" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
|
||||
|
||||
<path android:fillColor="@android:color/white" android:pathData="M12,15c1.66,0 2.99,-1.34 2.99,-3L15,6c0,-1.66 -1.34,-3 -3,-3S9,4.34 9,6v6c0,1.66 1.34,3 3,3zM17.3,12c0,3 -2.54,5.1 -5.3,5.1S6.7,15 6.7,12L5,12c0,3.42 2.72,6.23 6,6.72L11,22h2v-3.28c3.28,-0.48 6,-3.3 6,-6.72h-1.7z"/>
|
||||
|
||||
</vector>
|
||||
@@ -129,6 +129,7 @@ class IFlyTekOfflineTts : BaseMogoTTS() {
|
||||
|
||||
private fun startSpeak(langTtsEntity: LangTtsEntity?) {
|
||||
langTtsEntity?.let {
|
||||
curTtsEntity = it
|
||||
curTtsContent = it.ttsContent
|
||||
realSpeak(it.ttsContent)
|
||||
}
|
||||
|
||||
@@ -150,6 +150,7 @@ class MogoOfflineTTS : BaseMogoTTS() {
|
||||
private fun startSpeak(langTtsEntity: LangTtsEntity?) {
|
||||
stopTts()
|
||||
langTtsEntity?.let {
|
||||
this.curTtsEntity = langTtsEntity;
|
||||
curTtsContent = it.ttsContent
|
||||
realSpeak(it.ttsContent)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user