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:
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user