Browse Source

上传闪退修复

weicu
liwei1dao 7 months ago
parent
commit
b188bd319f
  1. 35
      local_plugins/agent_service/android/src/main/kotlin/com/yunqiinnovation/agent_service/StsAgent.kt

35
local_plugins/agent_service/android/src/main/kotlin/com/yunqiinnovation/agent_service/StsAgent.kt

@ -2,9 +2,11 @@ package com.yunqiinnovation.agent_service
import android.content.Context
import android.media.AudioFormat
import android.media.AudioManager
import android.media.AudioRecord
import android.media.MediaPlayer
import android.media.MediaRecorder
import android.media.ToneGenerator
import android.os.Handler
import android.os.Looper
import android.util.Log
@ -91,6 +93,9 @@ class StsAgent(
// ── 预缓冲(VAD 触发前 ~1.5s)────────────────────────────────────────────
private val preBuffer = ArrayDeque<ByteArray>()
private val preBufferLock = Any()
// ── 麦克风读写锁(防止 read() 与 stop()/release() 并发导致 native SIGABRT)──
private val micLock = Any()
private val PRE_BUFFER_MAX_CHUNKS = 75
// ── 本地 VAD ──────────────────────────────────────────────────────────────
@ -406,8 +411,15 @@ class StsAgent(
recordingJob = launch {
val buf = ByteArray(RECORD_CHUNK)
while (isActive && (inCall || pttRecording)) {
val read = audioRecord?.read(buf, 0, buf.size) ?: break
// 使用非阻塞读 + micLock,确保与 stopMicHard() 中的 stop()/release() 互斥。
// READ_NON_BLOCKING 让 read() 立即返回(微秒级),锁持有时间极短,
// 彻底消除 releaseBuffer 并发导致的 native SIGABRT。
val read = synchronized(micLock) {
audioRecord?.read(buf, 0, buf.size, AudioRecord.READ_NON_BLOCKING) ?: -1
}
if (read < 0) break
if (read > 0) { micChunkCount++; onMicAudio(buf.copyOf(read)) }
else delay(5) // 无数据时释放协程让出线程,避免忙等
}
}
} catch (e: Exception) {
@ -417,8 +429,13 @@ class StsAgent(
private fun stopMicHard() {
recordingJob?.cancel(); recordingJob = null
try { audioRecord?.stop(); audioRecord?.release() } catch (_: Exception) {}
audioRecord = null
// 拿 micLock 后再 stop()/release(),与录音循环的 read() 互斥,
// 保证 stop() 永远不会在 read() 内部 releaseBuffer 期间被调用。
synchronized(micLock) {
val ar = audioRecord
audioRecord = null
try { ar?.stop(); ar?.release() } catch (_: Exception) {}
}
}
private fun startMicWatchdog() {
@ -504,12 +521,24 @@ class StsAgent(
}
forwardingAudio = true; wsConnecting = false
playReadyBeep()
emit("recognition_started", emptyMap())
val cached = synchronized(preBufferLock) { preBuffer.toList().also { preBuffer.clear() } }
for (c in cached) feedSendBuffer(c)
}
/** 唤醒成功提示音:通知用户可以说话了 */
private fun playReadyBeep() {
try {
val toneGen = ToneGenerator(AudioManager.STREAM_MUSIC, 60)
toneGen.startTone(ToneGenerator.TONE_PROP_BEEP, 180)
mainHandler.postDelayed({ toneGen.release() }, 300)
} catch (e: Exception) {
Log.w(TAG, "playReadyBeep failed: ${e.message}")
}
}
// ═════════════════════════════════════════════════════════════════════════
// WebSocket
// ═════════════════════════════════════════════════════════════════════════

Loading…
Cancel
Save