fix: fix audio Mixer freeze

This commit is contained in:
2026-05-25 11:35:03 +02:00
parent 96943116f8
commit 29d5daaa62
+31 -2
View File
@@ -383,17 +383,36 @@ namespace Drivers::Audio::Mixer {
g_lock.Acquire(); g_lock.Acquire();
VirtualStream& s = g_streams[handle]; VirtualStream& s = g_streams[handle];
bool changed = false; bool changed = false;
// Pull the ring pointer out of the slot before freeing it. Once
// s.active=false and s.ring=nullptr are visible under the lock no
// other path can reach this pointer, so the actual PFA free can run
// with the lock released — keeping the HDA buffer-complete IRQ from
// spinning on g_lock while ReallocConsecutive walks the free list.
int16_t* ringToFree = nullptr;
bool lastStream = false;
if (s.active) { if (s.active) {
FreeRing(s.ring); ringToFree = s.ring;
s.ring = nullptr; s.ring = nullptr;
s.active = false; s.active = false;
s.ownerPid = 0; s.ownerPid = 0;
s.name[0] = '\0'; s.name[0] = '\0';
if (g_activeCount > 0) g_activeCount--; if (g_activeCount > 0) g_activeCount--;
lastStream = (g_activeCount == 0);
BumpSerialLocked(); BumpSerialLocked();
changed = true; changed = true;
} }
// Quiesce the hardware when the final virtual stream goes away so
// the HDA DMA ring stops looping its last 32 KiB of samples. The
// next Open() reopens the HDA stream via EnsureHdaOpen().
bool closeHda = lastStream && g_hdaOpened;
int hdaHandle = g_hdaHandle;
if (closeHda) {
g_hdaOpened = false;
g_hdaHandle = -1;
}
g_lock.Release(); g_lock.Release();
if (closeHda) IntelHda::Close(hdaHandle);
if (ringToFree) FreeRing(ringToFree);
if (changed) Sched::WakeObjectWaiters((void*)&g_serial); if (changed) Sched::WakeObjectWaiters((void*)&g_serial);
} }
@@ -495,12 +514,14 @@ namespace Drivers::Audio::Mixer {
} }
void CleanupProcess(int pid) { void CleanupProcess(int pid) {
int16_t* ringsToFree[MAX_STREAMS] = {};
int ringCount = 0;
g_lock.Acquire(); g_lock.Acquire();
bool changed = false; bool changed = false;
for (int i = 0; i < MAX_STREAMS; i++) { for (int i = 0; i < MAX_STREAMS; i++) {
VirtualStream& s = g_streams[i]; VirtualStream& s = g_streams[i];
if (s.active && s.ownerPid == pid) { if (s.active && s.ownerPid == pid) {
FreeRing(s.ring); ringsToFree[ringCount++] = s.ring;
s.ring = nullptr; s.ring = nullptr;
s.active = false; s.active = false;
s.ownerPid = 0; s.ownerPid = 0;
@@ -509,8 +530,16 @@ namespace Drivers::Audio::Mixer {
changed = true; changed = true;
} }
} }
bool closeHda = changed && (g_activeCount == 0) && g_hdaOpened;
int hdaHandle = g_hdaHandle;
if (closeHda) {
g_hdaOpened = false;
g_hdaHandle = -1;
}
if (changed) BumpSerialLocked(); if (changed) BumpSerialLocked();
g_lock.Release(); g_lock.Release();
if (closeHda) IntelHda::Close(hdaHandle);
for (int i = 0; i < ringCount; i++) FreeRing(ringsToFree[i]);
if (changed) Sched::WakeObjectWaiters((void*)&g_serial); if (changed) Sched::WakeObjectWaiters((void*)&g_serial);
} }