Audio-dropout fix: OpenAL source-pool lifecycle (uninit aliasing, atomic-delete leak, stranded partials)

Field report: audio cutting in and out toward the end of the match.
Three structural defects in the port's source-pool lifecycle:

1. SourceSet.sources[] was uninitialized heap garbage until first
   acquisition -- AL names are small ints, so a recycled-heap slot could
   alias a LIVE source owned by another sound; alIsSource() skipped
   generation, two sounds shared one source, and whichever released
   first deleted the other's mid-play.  SourceSet ctor now zero-inits.
2. ReleaseSourceSet's bulk alDeleteSources(count, sources) is ATOMIC on
   invalid names (AL spec) -- one empty/-1 slot and NOTHING deleted;
   after the first pool exhaustion every partial release leaked and the
   pool never recovered.  Now per-slot guarded delete, slots parked at 0.
3. Failed acquisitions stranded partial sets forever (dropped transients
   are never released by anything).  ReleaseChannels() handback at both
   failure sites (StartRequest + dormant-resume) + a dtor backstop.

Verified: 2-node MP smoke (mission + lobby-loop relaunch clean, census
live/acquireFails 0/0) + 100s solo combat smoke (52 audio triggers,
zero AL errors).  Awaiting live playtest confirmation at scale.
KB: context/wintesla-port.md audio-dropout section.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
arcattack
2026-07-23 11:23:07 -05:00
co-authored by Claude Opus 4.8
parent cbebb0f1c1
commit a999e5c49f
4 changed files with 73 additions and 12 deletions
+14
View File
@@ -719,6 +719,20 @@ void
//
L4AudioSource::~L4AudioSource()
{
// Audio-dropout fix: backstop -- if this source dies still holding OpenAL
// sources (the stop/suspend maintenance never ran for it), hand them back
// so entity churn can't drain the pool over a long match.
if (application != NULL && application->GetAudioRenderer() != NULL)
{
for (int i = 0; i < channelSet.count; i++)
{
if (alIsSource(channelSet.sources[i]))
{
application->GetAudioRenderer()->ReleaseSourceSet(channelSet);
break;
}
}
}
}
//