























@@ -98,10 +98,6 @@ class TalkModeManager internal constructor(
9898private const val tag = "TalkMode"
9999private const val realtimeSampleRateHz = 24_000
100100private const val realtimeAudioFrameMs = 100
101-private const val realtimeSpeechStartAverageAmplitude = 800
102-private const val realtimeSpeechContinueAverageAmplitude = 800
103-private const val realtimeSpeechStartFrameCount = 3
104-private const val realtimeSpeechHangoverMs = 700L
105101private const val listenWatchdogMs = 12_000L
106102private const val chatFinalWaitWithSubscribeMs = 45_000L
107103private const val chatFinalWaitWithoutSubscribeMs = 6_000L
@@ -166,8 +162,6 @@ class TalkModeManager internal constructor(
166162private var realtimeAudioTrack: AudioTrack? = null
167163private var realtimePlaybackIdleJob: Job? = null
168164 @Volatile private var realtimePlaybackEndsAtMs = 0L
169- @Volatile private var realtimeSpeechActiveUntilMs = 0L
170-private var realtimeSpeechCandidateFrames = 0
171165172166 @Volatile private var realtimeOutputSuppressed = false
173167@@ -641,7 +635,6 @@ class TalkModeManager internal constructor(
641635642636 realtimeSessionId = sessionId
643637 realtimeOutputSuppressed = false
644- resetRealtimeSpeechGate()
645638_isListening.value = true
646639_statusText.value = "Listening"
647640 startRealtimeCapture(sessionId)
@@ -734,7 +727,7 @@ class TalkModeManager internal constructor(
734727while (coroutineContext.isActive && _isEnabled.value && realtimeSessionId == sessionId) {
735728val read = audioRecord.read(buffer, 0, buffer.size)
736729if (read <= 0) continue
737-if (!shouldAppendRealtimeCapturedFrame(buffer, read)) continue
730+if (!shouldAppendRealtimeCapturedFrame(read)) continue
738731 audioFrames.trySend(buffer.copyOf(read))
739732 }
740733 } catch (err: Throwable) {
@@ -754,62 +747,12 @@ class TalkModeManager internal constructor(
754747 }
755748 }
756749757-private fun shouldAppendRealtimeCapturedFrame(
758-frame: ByteArray,
759-length: Int = frame.size,
760- ): Boolean {
761-if (isRealtimePlaybackActive()) {
762- resetRealtimeSpeechGate()
763-return false
764- }
765-val now = SystemClock.elapsedRealtime()
766-val average = pcm16AverageAmplitude(frame, length)
767-if (now < realtimeSpeechActiveUntilMs) {
768-if (average >= realtimeSpeechContinueAverageAmplitude) {
769- realtimeSpeechActiveUntilMs = now + realtimeSpeechHangoverMs
770- }
771-return true
772- }
773-if (average >= realtimeSpeechStartAverageAmplitude) {
774- realtimeSpeechCandidateFrames += 1
775-if (realtimeSpeechCandidateFrames >= realtimeSpeechStartFrameCount) {
776- realtimeSpeechActiveUntilMs = now + realtimeSpeechHangoverMs
777-return true
778- }
779-return false
780- }
781- realtimeSpeechCandidateFrames = 0
782-return false
783- }
750+private fun shouldAppendRealtimeCapturedFrame(length: Int): Boolean =
751+!isRealtimePlaybackActive() && length > 0
784752785753private fun isRealtimePlaybackActive(): Boolean =
786754_isSpeaking.value || SystemClock.elapsedRealtime() < realtimePlaybackEndsAtMs
787755788-private fun resetRealtimeSpeechGate() {
789- realtimeSpeechActiveUntilMs = 0L
790- realtimeSpeechCandidateFrames = 0
791- }
792-793-private fun pcm16AverageAmplitude(
794-frame: ByteArray,
795-length: Int,
796- ): Int {
797-var total = 0L
798-var count = 0
799-var index = 0
800-val limit = length - (length % 2)
801-while (index < limit) {
802-val sample =
803- (frame[index].toInt() and 0xff) or
804- (frame[index + 1].toInt() shl 8)
805-val amplitude = kotlin.math.abs(sample.toShort().toInt())
806- total += amplitude
807- count += 1
808- index += 2
809- }
810-return if (count == 0) 0 else (total / count).toInt()
811- }
812-813756private fun handleRealtimeTalkEvent(payloadJson: String?) {
814757if (payloadJson.isNullOrBlank()) return
815758val obj =
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。