From 7d6b9cf5783811ad262456dbc3c6cc299e4dddbc Mon Sep 17 00:00:00 2001 From: Seb3thehacker Date: Mon, 12 Oct 2026 01:31:24 -0700 Subject: [PATCH] car audio: run the audio threads at audio priority so a busy phone doesn't make it skip --- .../main/java/app/seb3thehacker/gearslip/GearslipRunner.kt | 7 ++++++- .../seb3thehacker/gearslip/audio/AudioCaptureService.kt | 4 ++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/gearslip/src/main/java/app/seb3thehacker/gearslip/GearslipRunner.kt b/gearslip/src/main/java/app/seb3thehacker/gearslip/GearslipRunner.kt index f80a860..9f15b3a 100644 --- a/gearslip/src/main/java/app/seb3thehacker/gearslip/GearslipRunner.kt +++ b/gearslip/src/main/java/app/seb3thehacker/gearslip/GearslipRunner.kt @@ -45,7 +45,10 @@ class GearslipRunner( private lateinit var identityTask: FutureTask /** Sends every message, in order, so no other thread ever blocks on the USB link. See [send]. */ - private val writer = java.util.concurrent.Executors.newSingleThreadExecutor { Thread(it, "gearslip-writer") } + private val writer = java.util.concurrent.Executors.newSingleThreadExecutor { + // Sound goes out through here too, so it gets audio's priority: late writes are skips. + Thread({ android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_AUDIO); it.run() }, "gearslip-writer") + } /** Waits for the certificate only when TLS is first needed; see [run]. */ private val tls: PhoneTls by lazy { identityTask.get() } @@ -88,6 +91,8 @@ class GearslipRunner( @Volatile private var lastKeyframeSentAt = 0L fun run() { + // This thread reads the car's acks; audio waits on them, so it can't be left at the back. + android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_AUDIO) SessionReport.begin() log.i("--- session starting ---") SessionStatus.connecting("Connected to the head unit") diff --git a/gearslip/src/main/java/app/seb3thehacker/gearslip/audio/AudioCaptureService.kt b/gearslip/src/main/java/app/seb3thehacker/gearslip/audio/AudioCaptureService.kt index cbdb536..6948015 100644 --- a/gearslip/src/main/java/app/seb3thehacker/gearslip/audio/AudioCaptureService.kt +++ b/gearslip/src/main/java/app/seb3thehacker/gearslip/audio/AudioCaptureService.kt @@ -16,6 +16,7 @@ import android.media.AudioRecord import android.media.projection.MediaProjection import android.media.projection.MediaProjectionManager import android.os.IBinder +import android.os.Process import app.seb3thehacker.gearslip.GearslipLog import kotlin.math.abs @@ -147,6 +148,9 @@ class AudioCaptureService : Service() { reading = true thread = Thread({ + // A busy phone (a map app drawing, the video encoder) would otherwise starve this + // loop, and the car hears every late read as a skip. + Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_AUDIO) val buffer = ByteArray(CHUNK_BYTES) var peak = 0 var heardAt = System.currentTimeMillis()