From 8da8901f4d3018de366679b99d50aa3e9f742504 Mon Sep 17 00:00:00 2001 From: Felipe Keller Braz Date: Thu, 2 Jul 2026 00:38:20 -0300 Subject: [PATCH] fix(audio): correct sample limit tracking and source leaks Fixed a bug in OpenALAudioManager and MiniAudioManager where the engines would continuously allocate new hardware sources without terminating lower priority sounds, eventually exhausting all available physical sources. Also corrected the sample count logic in MiniAudioManager to only evaluate 2D and 3D sample types rather than all playing sounds. --- .../MiniAudioDevice/MiniAudioManager.cpp | 21 +++++++++++++++---- .../OpenALAudioDevice/OpenALAudioManager.cpp | 4 ++-- docs/DEV_BLOG/2026-07-DIARY.md | 10 +++++++++ 3 files changed, 29 insertions(+), 6 deletions(-) create mode 100644 docs/DEV_BLOG/2026-07-DIARY.md diff --git a/Core/GameEngineDevice/Source/MiniAudioDevice/MiniAudioManager.cpp b/Core/GameEngineDevice/Source/MiniAudioDevice/MiniAudioManager.cpp index d886ccf56fc..4bbfdc6c91a 100644 --- a/Core/GameEngineDevice/Source/MiniAudioDevice/MiniAudioManager.cpp +++ b/Core/GameEngineDevice/Source/MiniAudioDevice/MiniAudioManager.cpp @@ -1052,7 +1052,10 @@ Bool MiniAudioManager::isPlayingLowerPriority(AudioEventRTS *event) const for (auto it = m_playingSounds.begin(); it != m_playingSounds.end(); ++it) { if (!(*it)->m_audioEventRTS) continue; const AudioEventInfo *info = (*it)->m_audioEventRTS->getAudioEventInfo(); - if (info && info->m_priority < priority) return true; + if (info && info->m_priority < priority) { + event->setHandleToKill((*it)->m_audioEventRTS->getPlayingHandle()); + return true; + } } return false; } @@ -1573,15 +1576,25 @@ UnsignedInt MiniAudioManager::getNumAvailable2DSamples() const { // GeneralsX @bugfix Mr. Meeseeks 27/06/2026 Fix available samples calculation to prevent voicelines culling UnsignedInt max2D = getAudioSettings()->m_sampleCount2D; - UnsignedInt playing = (UnsignedInt)m_playingSounds.size(); + UnsignedInt playing = 0; + for (auto it = m_playingSounds.begin(); it != m_playingSounds.end(); ++it) { + if ((*it) && (*it)->m_type == PAT_Sample) { + playing++; + } + } return (max2D > playing) ? (max2D - playing) : 0; } //------------------------------------------------------------------------------------------------- UnsignedInt MiniAudioManager::getNumAvailable3DSamples() const { - // GeneralsX @bugfix Mr. Meeseeks 27/06/2026 Fix available samples calculation to prevent voicelines culling + // GeneralsX @bugfix Mr. Meeseeks 01/07/2026 Fix available samples calculation to only count 3D samples UnsignedInt max3D = getAudioSettings()->m_sampleCount3D; - UnsignedInt playing = (UnsignedInt)m_playingSounds.size(); + UnsignedInt playing = 0; + for (auto it = m_playingSounds.begin(); it != m_playingSounds.end(); ++it) { + if ((*it) && (*it)->m_type == PAT_3DSample) { + playing++; + } + } return (max3D > playing) ? (max3D - playing) : 0; } diff --git a/Core/GameEngineDevice/Source/OpenALAudioDevice/OpenALAudioManager.cpp b/Core/GameEngineDevice/Source/OpenALAudioDevice/OpenALAudioManager.cpp index aa7f91cc600..ca83ada7c42 100644 --- a/Core/GameEngineDevice/Source/OpenALAudioDevice/OpenALAudioManager.cpp +++ b/Core/GameEngineDevice/Source/OpenALAudioDevice/OpenALAudioManager.cpp @@ -2131,7 +2131,7 @@ Bool OpenALAudioManager::isPlayingLowerPriority(AudioEventRTS* event) const if (!(*it)->m_audioEventRTS) continue; // GeneralsX @bugfix BenderAI 11/03/2026 const AudioEventInfo* info = (*it)->m_audioEventRTS->getAudioEventInfo(); if (info && info->m_priority < priority) { - //event->setHandleToKill((*it)->m_audioEventRTS->getPlayingHandle()); + event->setHandleToKill((*it)->m_audioEventRTS->getPlayingHandle()); return true; } } @@ -2142,7 +2142,7 @@ Bool OpenALAudioManager::isPlayingLowerPriority(AudioEventRTS* event) const if (!(*it)->m_audioEventRTS) continue; // GeneralsX @bugfix BenderAI 11/03/2026 const AudioEventInfo* info = (*it)->m_audioEventRTS->getAudioEventInfo(); if (info && info->m_priority < priority) { - //event->setHandleToKill((*it)->m_audioEventRTS->getPlayingHandle()); + event->setHandleToKill((*it)->m_audioEventRTS->getPlayingHandle()); return true; } } diff --git a/docs/DEV_BLOG/2026-07-DIARY.md b/docs/DEV_BLOG/2026-07-DIARY.md new file mode 100644 index 00000000000..390701c51b2 --- /dev/null +++ b/docs/DEV_BLOG/2026-07-DIARY.md @@ -0,0 +1,10 @@ +# July 2026 + +## 02/07/2026 +### Audio Fix: Missing Voiceovers +Fixed a significant issue where in-game voiceovers (like "You are victorious" or General Challenge taunts) were not playing, especially during late-game or heavy combat scenarios. +The issue stemmed from two places: +1. **OpenAL and MiniAudio priority leaks:** When the maximum sample limits were hit (e.g., 64 2D sounds), the game would correctly attempt to cull lower priority sounds. However, `OpenALAudioManager` and `MiniAudioManager` were missing the logic to set the `handleToKill` inside `isPlayingLowerPriority()`. This resulted in the engines continuously generating new hardware sources without freeing older ones, eventually exhausting all physical sources (usually 256) and silently dropping new sounds. +2. **MiniAudio incorrect limits:** `MiniAudioManager::getNumAvailable2DSamples` was calculating available 2D samples against the size of the *entire* `m_playingSounds` list (which in MiniAudio includes 3D sounds and Streams/Music). This effectively kept the available samples at 0 at all times, making it always fall back to the broken priority handling. + +Both issues have been resolved by adding proper counting filters in MiniAudio and uncommenting `event->setHandleToKill` in both audio managers' priority checks.