diff --git a/src/AcDream.App/Audio/OpenAlAudioEngine.cs b/src/AcDream.App/Audio/OpenAlAudioEngine.cs index ba4f249a..959415ea 100644 --- a/src/AcDream.App/Audio/OpenAlAudioEngine.cs +++ b/src/AcDream.App/Audio/OpenAlAudioEngine.cs @@ -82,7 +82,7 @@ public sealed unsafe class OpenAlAudioEngine : IAudioEngine, IWorldAudioQuiescen public bool InUse; public uint PriorityBase; // raw priority from SoundEntry.Priority } - private readonly Slot3D[] _pool3D = new Slot3D[PoolSize3D]; + private readonly Slot3D[] _pool3D = CreateWorldSlots(); private int _pool3DCursor; // round-robin start private bool _worldAudioSuspended; @@ -159,7 +159,7 @@ public sealed unsafe class OpenAlAudioEngine : IAudioEngine, IWorldAudioQuiescen for (int i = 0; i < PoolSize3D; i++) { uint src = _resources.Create3DSource(); - _pool3D[i] = new Slot3D { SourceId = src, InUse = false }; + _pool3D[i].SourceId = src; } // UI sources are source-relative (attached to listener) so they @@ -520,4 +520,12 @@ public sealed unsafe class OpenAlAudioEngine : IAudioEngine, IWorldAudioQuiescen slot.PriorityBase = 0; slot.InUse = false; } + + private static Slot3D[] CreateWorldSlots() + { + var slots = new Slot3D[PoolSize3D]; + for (int i = 0; i < slots.Length; i++) + slots[i] = new Slot3D(); + return slots; + } } diff --git a/tests/AcDream.App.Tests/Audio/OpenAlResourceLifetimeTests.cs b/tests/AcDream.App.Tests/Audio/OpenAlResourceLifetimeTests.cs index f2c4e115..bcf599eb 100644 --- a/tests/AcDream.App.Tests/Audio/OpenAlResourceLifetimeTests.cs +++ b/tests/AcDream.App.Tests/Audio/OpenAlResourceLifetimeTests.cs @@ -89,6 +89,21 @@ public sealed class OpenAlResourceLifetimeTests Assert.Equal(1, api.CloseDeviceCalls); } + [Fact] + public void UnavailableEngineWorldQuiescenceRemainsASafeNoOp() + { + var api = new RecordingApi { ContextResult = 0 }; + var engine = new OpenAlAudioEngine(new Factory(api)); + + engine.SuspendWorldAudio(); + engine.StopAllForOwner(0x50000001u); + engine.ResumeWorldAudio(); + + Assert.False(engine.IsAvailable); + Assert.True(engine.IsDisposalComplete); + Assert.Empty(api.GeneratedSources); + } + private sealed class Factory(IOpenAlResourceApi api) : IOpenAlResourceApiFactory { public IOpenAlResourceApi Create() => api;