voice reply countdown keeps running through road noise

This commit is contained in:
Seb3thehacker committed 2026-10-05 17:03:43 -07:00
1 parent 1127d4baf7
commit 24d7e4c415
1 file changed
+8 -30
@@ -41,7 +41,7 @@ object VoiceReply {
LISTENING, LISTENING,
/** /**
* Reading the reply back, then counting down to [State.until] while listening for * Reading the reply back, then counting down to [State.until] while listening for
* "cancel" or "change it". [State.until] is 0 while the countdown is held. * "cancel" or "change it". The countdown runs out whatever it hears.
*/ */
CONFIRMING, CONFIRMING,
SENT, SENT,
@@ -193,38 +193,22 @@ object VoiceReply {
} }
} }
/** /** Sends in [ms]. */
* Sends in [ms]. After a hold the bar carries on from where it stopped instead of jumping back
* to full: the span is stretched so the bar still runs out exactly at [ms].
*/
private fun startCountdown(id: Int, ms: Long) { private fun startCountdown(id: Int, ms: Long) {
val sendAt = SystemClock.uptimeMillis() + ms val sendAt = SystemClock.uptimeMillis() + ms
val held = _state.value.held _state.value = _state.value.copy(until = sendAt, span = ms, held = 0f)
val span = if (held > 0f) (ms / held).toLong() else ms
_state.value = _state.value.copy(until = sendAt, span = span, held = 0f)
main.removeCallbacksAndMessages(SEND_TOKEN) main.removeCallbacksAndMessages(SEND_TOKEN)
main.postAtTime({ if (id == run) send() }, SEND_TOKEN, sendAt) main.postAtTime({ if (id == run) send() }, SEND_TOKEN, sendAt)
} }
/** /**
* Listens through the countdown for "cancel", "change it" or "send". The countdown holds from * Listens through the countdown for "cancel", "change it" or "send". The countdown never
* the first word, so a reply can't go out while the driver is still saying "cancel". * pauses: in a noisy car it held for road noise and the radio, and the reply never went.
*/ */
private fun listenForCommand(id: Int) { private fun listenForCommand(id: Int) {
CarAssistant.dictate( CarAssistant.dictate(
onPartial = {}, onPartial = {},
cue = false, cue = false,
onSpeaking = {
if (id != run) return@dictate
main.removeCallbacksAndMessages(SEND_TOKEN)
val s = _state.value
val left = if (s.until > 0L && s.span > 0L) {
((s.until - SystemClock.uptimeMillis()).toFloat() / s.span).coerceIn(0.05f, 1f)
} else {
s.held
}
_state.value = s.copy(until = 0L, span = 0L, held = left)
},
onResult = { text -> onResult = { text ->
if (id != run) return@dictate if (id != run) return@dictate
when (command(text)) { when (command(text)) {
@@ -238,18 +222,14 @@ object VoiceReply {
ask(id) ask(id)
} }
Command.SEND -> send() Command.SEND -> send()
// Talk that wasn't meant for us, a passenger or the radio: carry on counting, // Talk that wasn't meant for us, a passenger or the radio: keep listening, so a
// and keep listening so a "cancel" after it still lands. // "cancel" after it still lands before the countdown runs out.
null -> { null -> listenForCommand(id)
startCountdown(id, RESUME_MS)
listenForCommand(id)
}
} }
}, },
// Silence ends the recognizer before the countdown does: listen again until it sends. // Silence ends the recognizer before the countdown does: listen again until it sends.
onError = { onError = {
if (id != run) return@dictate if (id != run) return@dictate
if (_state.value.until == 0L) startCountdown(id, RESUME_MS)
// A short gap, so a recognizer that fails at once can't spin. // A short gap, so a recognizer that fails at once can't spin.
main.postDelayed({ if (id == run) listenForCommand(id) }, RELISTEN_MS) main.postDelayed({ if (id == run) listenForCommand(id) }, RELISTEN_MS)
}, },
@@ -397,7 +377,5 @@ object VoiceReply {
/** How long "Do you want to reply?" waits for an answer: the start beep, then the engine's silence limit. */ /** How long "Do you want to reply?" waits for an answer: the start beep, then the engine's silence limit. */
private const val OFFER_MS = 6_500L private const val OFFER_MS = 6_500L
private const val OFFER_GRACE_MS = 1_500L private const val OFFER_GRACE_MS = 1_500L
/** After talk that wasn't a command, the reply waits this long again before it goes. */
private const val RESUME_MS = 3_000L
private const val RELISTEN_MS = 400L private const val RELISTEN_MS = 400L
} }