fix: make BT A2DP output exclusive to one process

The A2DP output is a single unmixed PCM stream. A second process
opening audio while a stream was active would reconfigure the SBC
encoder and media clock under the owner and interleave both apps' PCM
into one ring, garbling playback (e.g. launching DOOM destabilized
Music). Add ClaimOutput/ReleaseOutput pid ownership: the first opener
gets the BT sink, later openers fall back to the HDA mixer, and only
the owner can tear the stream down. The scheduler releases ownership
on process exit so a killed app cannot leak the claim.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-10 12:41:17 +02:00
co-authored by Claude Fable 5
parent 9519e174c0
commit 928fe0bbed
5 changed files with 75 additions and 14 deletions
+26
View File
@@ -134,6 +134,11 @@ namespace Drivers::USB::Bluetooth::A2dp {
// Volume
static int g_volume = 80;
// Exclusive owner (pid) of the A2DP audio output, -1 = free. See
// ClaimOutput/ReleaseOutput in the header: the output is one unmixed
// stream, so a second process sharing the handle would corrupt it.
static std::atomic<int> g_outputOwnerPid{-1};
// AVDTP response tracking
static volatile bool g_avdtpResponseReady = false;
static uint8_t g_avdtpResponseBuf[128] = {};
@@ -1606,4 +1611,25 @@ namespace Drivers::USB::Bluetooth::A2dp {
g_volume = percent;
}
// =========================================================================
// Output ownership (one process at a time; see header)
// =========================================================================
bool ClaimOutput(int pid) {
if (pid < 0) return false;
int expected = -1;
return g_outputOwnerPid.compare_exchange_strong(expected, pid,
std::memory_order_acq_rel);
}
void ReleaseOutput(int pid) {
if (pid < 0) return;
if (g_outputOwnerPid.load(std::memory_order_acquire) != pid) return;
// Stop (suspend + flush queued PCM) BEFORE freeing ownership, so a
// concurrent Open cannot configure the stream while it is being
// torn down.
StopStream(true);
g_outputOwnerPid.store(-1, std::memory_order_release);
}
}