car mic: open a voice session and name the codec before asking for the car's microphone

This commit is contained in:
Seb3thehacker committed 2026-10-13 00:37:49 -07:00
1 parent 8912e88406
commit 1cd3d6f856
2 files changed
+19 -4

No files matched your search

@@ -513,7 +513,14 @@ class GearslipRunner(
} }
val config = mic.configs.first() val config = mic.configs.first()
log.i("car microphone: channel=${mic.serviceId} ${mic.codecName} ${config.sampleRate}Hz/${config.bits}bit/x${config.channels}") log.i("car microphone: channel=${mic.serviceId} ${mic.codecName} ${config.sampleRate}Hz/${config.bits}bit/x${config.channels}")
CarMic.current = CarMic(mic) { id, body -> send(id, body, encrypted = true, channel = mic.serviceId) } CarMic.current = CarMic(
mic,
sendOnChannel = { id, body -> send(id, body, encrypted = true, channel = mic.serviceId) },
// VoiceSessionNotification { status = 1 START, 2 END }, on the control channel.
voiceSession = { start ->
send(MSG_VOICE_SESSION_NOTIFICATION, Protobuf.varintField(1, if (start) 1L else 2L), encrypted = true)
},
)
openChannel(mic.serviceId) openChannel(mic.serviceId)
} }
@@ -1244,6 +1251,7 @@ class GearslipRunner(
const val MSG_PING_RESPONSE = 12 const val MSG_PING_RESPONSE = 12
const val MSG_BYEBYE_REQUEST = 15 const val MSG_BYEBYE_REQUEST = 15
const val MSG_BYEBYE_RESPONSE = 16 const val MSG_BYEBYE_RESPONSE = 16
const val MSG_VOICE_SESSION_NOTIFICATION = 17
const val MSG_CHANNEL_OPEN_REQUEST = 7 const val MSG_CHANNEL_OPEN_REQUEST = 7
const val MSG_CHANNEL_OPEN_RESPONSE = 8 const val MSG_CHANNEL_OPEN_RESPONSE = 8
@@ -12,17 +12,21 @@ import java.util.concurrent.TimeUnit
* *
* -> CHANNEL_OPEN_REQUEST <- CHANNEL_OPEN_RESPONSE * -> CHANNEL_OPEN_REQUEST <- CHANNEL_OPEN_RESPONSE
* -> Setup { config_index } <- Config * -> Setup { config_index } <- Config
* -> VoiceSessionNotification { START } (control channel)
* -> MicrophoneRequest { open } <- MicrophoneResponse { status, session_id } * -> MicrophoneRequest { open } <- MicrophoneResponse { status, session_id }
* <- Data { 8-byte timestamp, PCM }... -> Ack { session_id, ack } * <- Data { 8-byte timestamp, PCM }... -> Ack { session_id, ack }
* -> MicrophoneRequest { open = false } * -> MicrophoneRequest { open = false }
* -> VoiceSessionNotification { END }
* *
* The channel opens with the session, but the car only records between [start] and [stop]. * The channel opens with the session, but the car only records between [start] and [stop], and
* only inside a voice session: the 2024 VW answered a bare MicrophoneRequest with status -7.
* Speech wants 16 kHz mono; a car that records at a multiple of that is averaged down to it, and * Speech wants 16 kHz mono; a car that records at a multiple of that is averaged down to it, and
* one that doesn't isn't used, so voice falls back to the phone's microphone. * one that doesn't isn't used, so voice falls back to the phone's microphone.
*/ */
class CarMic( class CarMic(
private val service: ServiceDiscovery.AudioService, private val service: ServiceDiscovery.AudioService,
private val sendOnChannel: (messageId: Int, body: ByteArray) -> Unit, private val sendOnChannel: (messageId: Int, body: ByteArray) -> Unit,
private val voiceSession: (start: Boolean) -> Unit,
) { ) {
val channelId get() = service.serviceId val channelId get() = service.serviceId
@@ -43,7 +47,8 @@ class CarMic(
val status = Protobuf.readInt32Field(body, 1) ?: 0 val status = Protobuf.readInt32Field(body, 1) ?: 0
GearslipLog.i("mic: <- ChannelOpenResponse: status=$status") GearslipLog.i("mic: <- ChannelOpenResponse: status=$status")
if (status != 0) return if (status != 0) return
sendOnChannel(MSG_SETUP, Protobuf.varintField(1, 0L)) // Setup { type = the codec }, as for audio: 0 got UNEXPECTED_MESSAGE from the VW.
sendOnChannel(MSG_SETUP, Protobuf.varintField(1, service.codecType.toLong()))
ready = usable ready = usable
if (!usable) { if (!usable) {
GearslipLog.w( GearslipLog.w(
@@ -97,6 +102,7 @@ class CarMic(
chunks.clear() chunks.clear()
packets = 0 packets = 0
listening = true listening = true
voiceSession(true)
sendOnChannel(MSG_MIC_REQUEST, Protobuf.varintField(1, 1L) + Protobuf.varintField(4, 1L)) sendOnChannel(MSG_MIC_REQUEST, Protobuf.varintField(1, 1L) + Protobuf.varintField(4, 1L))
GearslipLog.i("mic: -> MicrophoneRequest(open)") GearslipLog.i("mic: -> MicrophoneRequest(open)")
return true return true
@@ -109,7 +115,8 @@ class CarMic(
if (!listening) return if (!listening) return
listening = false listening = false
sendOnChannel(MSG_MIC_REQUEST, Protobuf.varintField(1, 0L)) sendOnChannel(MSG_MIC_REQUEST, Protobuf.varintField(1, 0L))
GearslipLog.i("mic: -> MicrophoneRequest(close) after $packets packets") voiceSession(false)
GearslipLog.i("mic: -> MicrophoneRequest(close) after $packets packets, voice session ended")
} }
companion object { companion object {