Browse Source

修复安卓通话翻译频繁切换奔溃问题

weicu
fdp 1 year ago
parent
commit
0a31525e30
  1. 130
      local_plugins/azure_speech/android/src/main/kotlin/com/yunqiinnovation/azure_speech/AzureAsrToAsr.kt

130
local_plugins/azure_speech/android/src/main/kotlin/com/yunqiinnovation/azure_speech/AzureAsrToAsr.kt

@ -475,26 +475,57 @@ class IntegratedSpeechTranslationService(
}
/**
* 停止连续语音翻译
* 停止连续语音翻译(非阻塞)
* 在 IO 线程内顺序停止识别器、录音线程与文件,并对翻译/合成收尾增加统一超时保护,避免阻塞主线程与潜在 ANR。
*/
fun stopContinuousTranslation() {
try {
recognizer?.stopContinuousRecognitionAsync()
audioProcessor?.stopRecording()
recordfile1!!.closeFile(true)
Log.d(TAG, "停止连续语音翻译-开始")
// 先标记识别关闭,避免后续流程继续入队处理
serviceState.isRecognizing.set(false)
// 等待当前处理完成
while (serviceState.isTranslating.get() || serviceState.isSynthesizing.get()) {
Thread.sleep(100)
}
Log.d(TAG, "停止连续语音翻译")
// 在 IO 线程中做真实的停止动作,避免阻塞主线程
launch(Dispatchers.IO) {
// 1) 停止识别器:等待短超时,避免卡住
try {
recognizer?.stopContinuousRecognitionAsync()
?.get(1500, java.util.concurrent.TimeUnit.MILLISECONDS)
} catch (t: Throwable) {
Log.w(TAG, "停止识别器超时或失败", t)
}
// 2) 停止录音线程(打断并短等待退出)
runCatching { audioProcessor?.stopRecording() }
.onFailure { Log.w(TAG, "停止录音失败", it) }
// 3) 关闭录音文件(若开启过录音)
runCatching { recordfile1?.closeFile(true) }
.onFailure { Log.w(TAG, "关闭录音文件失败", it) }
// 4) 等待翻译/合成收尾,整体不超过 2s
val start = System.currentTimeMillis()
while ((serviceState.isTranslating.get() || serviceState.isSynthesizing.get())
&& System.currentTimeMillis() - start < 2000
) {
delay(100)
}
if (serviceState.isTranslating.get() || serviceState.isSynthesizing.get()) {
Log.w(TAG, "等待翻译/合成完成超时,强制标记结束")
}
// 5) 统一落幕:确保状态关闭
serviceState.isTranslating.set(false)
serviceState.isSynthesizing.set(false)
Log.d(TAG, "停止连续语音翻译-完成")
}
} catch (e: Exception) {
Log.e(TAG, "停止翻译失败", e)
eventCallback?.onError("Service", "停止失败: ${e.message}")
}
}
/**
* 处理翻译和合成流程
*/
@ -1184,58 +1215,57 @@ fun getSupportedLanguages(): List<String> {
}
/**
* 改进的资源释放方法
* 安全释放音频处理器资源
* 添加更强的异常处理和超时保护
*/
fun dispose() {
try {
Log.d(TAG, "开始释放音频处理器资源...")
// 1. 停止运行标志
isRunning.set(false)
// 1. 设置停止标志
if (!isRunning.compareAndSet(true, false)) {
Log.d(TAG, "音频处理器已停止,跳过释放")
return
}
// 2. 中断处理线程
processingThread?.let { thread ->
if (thread.isAlive) {
// 1) 安全停止处理线程
processingThread?.let { thread ->
if (thread.isAlive) {
try {
thread.interrupt()
try {
// 等待线程结束,最多等待2秒
thread.join(2000)
if (thread.isAlive) {
Log.w(TAG, "音频处理线程未能正常结束")
} else {
Log.d(TAG, "音频处理线程已结束")
}
} catch (e: InterruptedException) {
Log.w(TAG, "等待音频处理线程结束时被中断")
Thread.currentThread().interrupt()
thread.join(500)
if (thread.isAlive) {
Log.w(TAG, "音频处理线程未在500ms内结束")
// 不强制杀死,交由系统回收,但继续清理资源
} else {
Log.d(TAG, "音频处理线程已正常结束")
}
} catch (e: InterruptedException) {
Log.w(TAG, "等待线程结束时被中断", e)
Thread.currentThread().interrupt()
} catch (e: Exception) {
Log.e(TAG, "停止处理线程时发生异常", e)
}
}
processingThread = null
// 3. 关闭音频流
try {
pushAudioStream?.close()
pushAudioStream = null
Log.d(TAG, "音频流已关闭")
} catch (e: Exception) {
Log.e(TAG, "关闭音频流失败", e)
}
// 4. 清理音频队列
try {
val remainingData = audioQueue.size
audioQueue.clear()
Log.d(TAG, "音频队列已清理,丢弃 $remainingData 个数据包")
} catch (e: Exception) {
Log.e(TAG, "清理音频队列失败", e)
}
Log.d(TAG, "音频处理器资源释放完成")
} catch (e: Exception) {
Log.e(TAG, "释放音频处理器资源时发生异常", e)
}
processingThread = null
// 2) 关闭输入流
try {
pushAudioStream?.close()
} catch (t: Throwable) {
Log.w(TAG, "关闭 PushAudioInputStream 时异常", t)
} finally {
pushAudioStream = null
}
// 3) 清空队列
audioQueue.clear()
Log.d(TAG, "音频处理器资源释放完成")
} catch (e: Exception) {
Log.e(TAG, "释放音频处理器资源失败", e)
}
}
}
}

Loading…
Cancel
Save