修复崩溃

This commit is contained in:
林若思 2026-01-24 19:02:43 +08:00
parent cafe464de6
commit 7ca485cafe
4 changed files with 48 additions and 36 deletions

View File

@ -28,7 +28,7 @@ class VadManager(
sileroVadModelConfig = SileroVadModelConfig( sileroVadModelConfig = SileroVadModelConfig(
model = "silero_vad.onnx", model = "silero_vad.onnx",
threshold = 0.5F, threshold = 0.5F,
minSilenceDuration = 0.25F, minSilenceDuration = 0.1F,
minSpeechDuration = 0.25F, minSpeechDuration = 0.25F,
windowSize = 512, windowSize = 512,
), ),

View File

@ -25,12 +25,15 @@ class VoiceController(
companion object { companion object {
// 日志标签 // 日志标签
private const val TAG = "VoiceController" private const val TAG = "VoiceController"
// 采样率 // 采样率
private const val SAMPLE_RATE = 16000 private const val SAMPLE_RATE = 16000
// 预缓存大小2秒 // 预缓存大小2秒
private const val PRE_BUFFER_SIZE = SAMPLE_RATE * 2 private const val PRE_BUFFER_SIZE = SAMPLE_RATE * 2
private const val INVALID_RESET_DEBOUNCE_MS = 1500L private const val INVALID_RESET_DEBOUNCE_MS = 1500L
// 最小语音时长 // 最小语音时长
private const val MIN_SPEECH_MS = 600L private const val MIN_SPEECH_MS = 600L
@ -78,6 +81,7 @@ class VoiceController(
// 声纹验证相关 // 声纹验证相关
private val CURRENT_USER_ID = "current_wakeup_user" private val CURRENT_USER_ID = "current_wakeup_user"
private val ENABLE_STRICT_SPEAKER_VERIFY = true private val ENABLE_STRICT_SPEAKER_VERIFY = true
private val preBufferLock = Any()
init { init {
try { try {
@ -163,7 +167,10 @@ class VoiceController(
} else { } else {
TimeoutType.IDLE_TIMEOUT TimeoutType.IDLE_TIMEOUT
} }
LogUtils.d(TAG, "⏱ WAIT_SPEECH timeout → WAIT_WAKEUP | 超时类型: $currentTimeoutType") LogUtils.d(
TAG,
"⏱ WAIT_SPEECH timeout → WAIT_WAKEUP | 超时类型: $currentTimeoutType"
)
onTimeoutTip?.invoke(currentTimeoutType) onTimeoutTip?.invoke(currentTimeoutType)
resetAll() resetAll()
return return
@ -273,7 +280,9 @@ class VoiceController(
speechEnableAtMs = System.currentTimeMillis() + SPEECH_COOLDOWN_MS speechEnableAtMs = System.currentTimeMillis() + SPEECH_COOLDOWN_MS
LogUtils.d(TAG, "🎵 提示音结束") LogUtils.d(TAG, "🎵 提示音结束")
if (!preBuffer.isEmpty()) { if (!preBuffer.isEmpty()) {
preBuffer.clear() synchronized(preBufferLock){
preBuffer.clear()
}
} }
state = VoiceState.WAIT_SPEECH_COOLDOWN state = VoiceState.WAIT_SPEECH_COOLDOWN
} }
@ -322,7 +331,9 @@ class VoiceController(
LogUtils.d(TAG, "🔄 重置所有状态 | 本次超时类型: $currentTimeoutType") LogUtils.d(TAG, "🔄 重置所有状态 | 本次超时类型: $currentTimeoutType")
audioBuffer.clear() audioBuffer.clear()
if (!preBuffer.isEmpty()) { if (!preBuffer.isEmpty()) {
preBuffer.clear() synchronized(preBufferLock){
preBuffer.clear()
}
} }
vadManager.reset() vadManager.reset()
wakeupManager.reset() wakeupManager.reset()
@ -363,22 +374,20 @@ class VoiceController(
private fun cachePreBuffer(samples: FloatArray) { private fun cachePreBuffer(samples: FloatArray) {
// 空数据快速返回,避免无效循环 // 空数据快速返回,避免无效循环
if (samples.isEmpty()) return if (samples.isEmpty()) return
synchronized(preBufferLock) {
for (s in samples) { for (s in samples) {
preBuffer.addLast(s) preBuffer.addLast(s)
// 关键修复:移除前先检查队列是否非空 if (preBuffer.size > PRE_BUFFER_SIZE) {
// if (preBuffer.size > PRE_BUFFER_SIZE && !preBuffer.isEmpty()) { if (preBuffer.isEmpty()) {
// preBuffer.removeFirst() LogUtils.w(TAG, "❌ preBuffer is empty when trying to remove first element")
// } } else {
if (preBuffer.size > PRE_BUFFER_SIZE) { preBuffer.removeFirst()
if (preBuffer.isEmpty()) { }
LogUtils.w(TAG, "❌ preBuffer is empty when trying to remove first element")
} else {
preBuffer.removeFirst()
} }
}
}
} }
} }
private fun verifySpeaker(audio: FloatArray): Boolean { private fun verifySpeaker(audio: FloatArray): Boolean {
@ -426,7 +435,10 @@ class VoiceController(
// 3. 计算真实处理耗时(结束时间 - 开始时间) // 3. 计算真实处理耗时(结束时间 - 开始时间)
val verifyCostMs = System.currentTimeMillis() - verifyStartMs val verifyCostMs = System.currentTimeMillis() - verifyStartMs
// 日志区分:音频时长 vs 处理耗时 // 日志区分:音频时长 vs 处理耗时
LogUtils.d(TAG, "📊 声纹验证 | 统一阈值: $SPEAKER_THRESHOLD | 通过: $verifyPass | 音频时长: $audioDurationMs ms | 处理耗时: $verifyCostMs ms") LogUtils.d(
TAG,
"📊 声纹验证 | 统一阈值: $SPEAKER_THRESHOLD | 通过: $verifyPass | 音频时长: $audioDurationMs ms | 处理耗时: $verifyCostMs ms"
)
verifyPass verifyPass
} }
}.onFailure { e -> }.onFailure { e ->

View File

@ -504,24 +504,24 @@ class MainActivity : BaseViewModelActivity<ActivityMainBinding, MainViewModel>()
} }
private fun loadLocalJsonAndPlay() { // private fun loadLocalJsonAndPlay() {
lifecycleScope.launch(Dispatchers.IO) { // lifecycleScope.launch(Dispatchers.IO) {
try { // try {
val jsonStr = assets // val jsonStr = assets
.open("readEnd.json") // .open("readEnd.json")
.bufferedReader() // .bufferedReader()
.use { it.readText() } // .use { it.readText() }
//
UnityPlayerHolder // UnityPlayerHolder
.getInstance() // .getInstance()
.startTalking(jsonStr) // .startTalking(jsonStr)
//
} catch (e: Exception) { // } catch (e: Exception) {
e.printStackTrace() // e.printStackTrace()
LogUtils.eTag("lrs", "loadLocalJsonAndPlay error: ${e.message}") // LogUtils.eTag("lrs", "loadLocalJsonAndPlay error: ${e.message}")
} // }
} // }
} // }
/** /**
* 下载并且安装 * 下载并且安装