car audio: send Start once, even when the car answers the focus request while it's starting

Starting the stream at once and the car's focus answer could both get through, so the car got
Start twice and two AAC encoders ran. A 2014 aftermarket head unit dropped the connection on the
first audio. Directions now also log why a turn went unspoken.
This commit is contained in:
Seb3thehacker committed 2026-10-23 13:21:33 -07:00
1 parent 405cecf2e9
commit 456dda897e
2 files changed
+29 -3

No files matched your search

@@ -233,7 +233,19 @@ class AudioLink(
startStream()
}
/**
* Guards starting and stopping. [start] starts the stream at once for head units that never
* answer the focus request, and the car's answer arrives on another thread and starts it
* too: without this both got through, so the car got Start twice and two AAC encoders, and a
* 2014 head unit dropped the connection on the first audio.
*/
private val startLock = Any()
private fun startStream() {
synchronized(startLock) { startStreamLocked() }
}
private fun startStreamLocked() {
if (!ready || started) return
sendOnChannel(
MSG_START,
@@ -252,6 +264,10 @@ class AudioLink(
}
override fun stop() {
synchronized(startLock) { stopLocked() }
}
private fun stopLocked() {
if (!started) return
started = false
synchronized(ackLock) { ackLock.notifyAll() }
@@ -87,16 +87,26 @@ object DirectionsVoice {
running = false
}
/** Why the last turn wasn't spoken, so the log says it once rather than every tick. */
private var silentBecause: String? = null
private fun quiet(reason: String) {
if (silentBecause == reason) return
silentBecause = reason
GearslipLog.i("guidance: not speaking - $reason")
}
private fun tick() {
if (!CarSettings.speakDirections.value) return
val turn = NavTurn.current()
if (turn == null) {
turnKey = null
return
}
if (turn.rerouting) return
if (!CarSettings.speakDirections.value) return quiet("Spoken directions is off in the car's Settings")
if (turn.rerouting) return quiet("the map app is rerouting")
val step = turn.step
val instruction = instruction(step) ?: return
val instruction = instruction(step) ?: return quiet("the map app gave this turn no words")
silentBecause = null
val meters = turn.distance?.let(NavTurn::toMeters)
val close = (turn.seconds != null && turn.seconds <= NEAR_SECONDS) || (meters != null && meters <= NEAR_METERS)