Skip to content

fix(gameaudio): Remove the has3DSensitiveStreamsPlaying volume hack - #3252

Open
xezon wants to merge 2 commits into
TheSuperHackers:mainfrom
xezon:xezon/remove-3d-streams-hack
Open

fix(gameaudio): Remove the has3DSensitiveStreamsPlaying volume hack#3252
xezon wants to merge 2 commits into
TheSuperHackers:mainfrom
xezon:xezon/remove-3d-streams-hack

Conversation

@xezon

@xezon xezon commented Sep 3, 2026

Copy link
Copy Markdown

Merge with Rebase

This change has 2 commits.

The first is removing the has3DSensitiveStreamsPlaying hack. It existed to workaround a hang on volume change. We aim to fix application hanging and not rely on the hack from here on.

The second is committing to sound volume change only if the volume has really changed, not merely calling the volume change function. This may or may not avoid unnecessary sound volume updates.

TODO

  • Add pull ids to commits

@xezon xezon added Minor Severity: Minor < Major < Critical < Blocker Gen Relates to Generals ZH Relates to Zero Hour Fix Is fixing something, but is not user facing labels Sep 3, 2026
@xezon xezon changed the title fix(audio): Remove the has3DSensitiveStreamsPlaying volume hack fix(gameaudio): Remove the has3DSensitiveStreamsPlaying volume hack Sep 3, 2026
@qodo-free-for-open-source-projects

Copy link
Copy Markdown

PR Summary by Qodo

Remove 3D stream volume workaround and avoid redundant updates

🐞 Bug fix ✨ Enhancement 🕐 20-40 Minutes

Grey Divider

AI Description

• Removes stream-sensitive suppression so 3D volume adjustments always propagate.
• Marks audio volume dirty only when the effective value changes.
• Deletes the obsolete device API and Miles stream-scanning implementation.
Diagram

graph TD
  A["Volume request"] --> B["Compute volume"] --> C{"Value changed?"}
  C -- "Yes" --> D["Store volume"] --> E["Mark dirty"] --> F["Miles update loop"]
  C -- "No" --> G["Skip update"]
Loading
High-Level Assessment

The direct removal of the obsolete stream-sensitive workaround, combined with effective-value change detection, is proportionate to the goal. Retaining the workaround would continue suppressing legitimate 3D updates, while introducing per-channel dirty flags would broaden the change without being necessary here. Targeted runtime validation around ending cinematic streams remains important because the removed code guarded a historical platform-specific hang.

Files changed (4) +32 / -58

Bug fix (2) +32 / -51
GameAudio.cppCommit and propagate only effective volume changes +32/-16

Commit and propagate only effective volume changes

• Compares calculated music, sound, 3D sound, and speech volumes before storing them and setting the global dirty flag. The 3D adjustment path now uses 'clamp' and always propagates real changes without checking stream sensitivity.

Core/GameEngine/Source/Common/Audio/GameAudio.cpp

MilesAudioManager.cppDelete legacy stream-scanning volume workaround +0/-35

Delete legacy stream-scanning volume workaround

• Removes the Miles-specific scan that classified non-music and non-game streams as unsafe for 3D volume updates. Volume propagation is no longer suppressed based on the contents of the playing-stream list.

Core/GameEngineDevice/Source/MilesAudioDevice/MilesAudioManager.cpp

Refactor (2) +0 / -7
GameAudio.hRemove stream-sensitivity query from the audio interface +0/-2

Remove stream-sensitivity query from the audio interface

• Removes the pure virtual 'has3DSensitiveStreamsPlaying' contract because 3D volume updates no longer depend on active stream classification.

Core/GameEngine/Include/Common/GameAudio.h

MilesAudioManager.hRemove obsolete Miles stream-sensitivity overrides +0/-5

Remove obsolete Miles stream-sensitivity overrides

• Deletes the stream-sensitivity declarations from both the real Miles manager and its dummy implementation after removal from the base interface.

Core/GameEngineDevice/Include/MilesAudioDevice/MilesAudioManager.h

@qodo-free-for-open-source-projects

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (2) 📘 Rule violations (0) 📜 Skill insights (0)

Grey Divider


Action required

1. Alt-tab recovery no longer works 🐞 Bug ☼ Reliability
Description
Removing the unconditional dirty flag makes the explicit equal-volume call in the Win32 alt-tab
recovery path a no-op. Miles consequently skips reapplying volumes to active audio, so the existing
recovery for an audio device that fails to regain focus no longer works.
Code

Core/GameEngine/Source/Common/Audio/GameAudio.cpp[742]

-	m_volumeHasChanged = true;
+		const Real newVolume = m_scriptSpeechVolume * m_systemSpeechVolume;
+		if (m_speechVolume != newVolume)
+		{
+			m_speechVolume = newVolume;
+			m_volumeHasChanged = true;
+		}
+	}
Evidence
The Win32 message loop explicitly documents and performs an equal-volume call to wake Miles after
alt-tab. Because AudioAffect_SystemSetting has no audio-category bit, the updated setVolume
enters none of its branches, while Miles only reapplies active volumes when m_volumeHasChanged is
set and then clears that flag after processing.

Core/GameEngineDevice/Source/Win32Device/Common/Win32GameEngine.cpp[116-120]
Core/GameEngine/Include/Common/AudioAffect.h[35-43]
Core/GameEngine/Source/Common/Audio/GameAudio.cpp[702-763]
Core/GameEngineDevice/Source/MilesAudioDevice/MilesAudioManager.cpp[2187-2209]
Core/GameEngineDevice/Source/MilesAudioDevice/MilesAudioManager.cpp[2244-2260]
Core/GameEngineDevice/Source/MilesAudioDevice/MilesAudioManager.cpp[2292-2294]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Equal-volume calls no longer mark audio volume state dirty, but the Win32 alt-tab path intentionally uses such a call to wake Miles after it fails to regain focus.

## Issue Context
The recovery call passes only `AudioAffect_SystemSetting`, so none of the category-specific equality checks execute. Previously, the unconditional assignment to `m_volumeHasChanged` still forced Miles to reapply all playing volumes.

## Fix Focus Areas
- Core/GameEngine/Source/Common/Audio/GameAudio.cpp[702-763]
- Core/GameEngineDevice/Source/Win32Device/Common/Win32GameEngine.cpp[116-120]
- Core/GameEngineDevice/Source/MilesAudioDevice/MilesAudioManager.cpp[2187-2260]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Stream-ending hang guard removed 🐞 Bug ☼ Reliability
Description
Deleting the sensitive-stream guard allows camera-driven 3D volume changes to invoke Miles volume
operations while a non-music stream is ending, restoring the low-level tight-loop hang documented at
the removed implementation. The current stream-completion and volume-update paths contain no
replacement synchronization or guard.
Code

Core/GameEngine/Source/Common/Audio/GameAudio.cpp[L772-773]

-  if ( ! has3DSensitiveStreamsPlaying() )
-  	m_volumeHasChanged = TRUE;
+	if (m_sound3DVolume != newVolume)
+	{
+		m_sound3DVolume = newVolume;
+		m_volumeHasChanged = true;
+	}
Evidence
Listener updates still call set3DVolumeAdjustment, which now marks volume dirty without checking
sensitive streams. Miles then applies that dirty state to active 3D sounds and streams, while
completion callbacks independently transition ending streams to PS_Stopping; ordinary stereo
streams remain permitted because stereo is rejected only for positional audio.

Core/GameEngine/Source/Common/Audio/GameAudio.cpp[331-364]
Core/GameEngine/Source/Common/Audio/GameAudio.cpp[781-789]
Core/GameEngineDevice/Source/MilesAudioDevice/MilesAudioManager.cpp[1227-1245]
Core/GameEngineDevice/Source/MilesAudioDevice/MilesAudioManager.cpp[2193-2260]
Core/GameEngineDevice/Source/MilesAudioDevice/MilesAudioManager.cpp[1453-1512]
Core/GameEngineDevice/Source/MilesAudioDevice/MilesAudioManager.cpp[1542-1561]
Core/GameEngineDevice/Source/MilesAudioDevice/MilesAudioManager.cpp[3012-3018]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The PR removes the only guard preventing Miles volume updates while sensitive streams are ending, without adding a replacement for the documented low-level hang.

## Issue Context
Listener updates continue changing the 3D volume, `processPlayingList` applies dirty volume state to active samples and streams, and stream completion asynchronously moves streams toward stopping. Keep the suppression behavior or introduce a proven synchronized replacement before removing it.

## Fix Focus Areas
- Core/GameEngine/Source/Common/Audio/GameAudio.cpp[781-789]
- Core/GameEngineDevice/Include/MilesAudioDevice/MilesAudioManager.h[229-234]
- Core/GameEngineDevice/Source/MilesAudioDevice/MilesAudioManager.cpp[2193-2260]
- Core/GameEngineDevice/Source/MilesAudioDevice/MilesAudioManager.cpp[1453-1512]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Tip of the day
💡 Did you know, you can add REVIEW.md to your repo root and Qodo follows it on every PR

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment thread Core/GameEngine/Source/Common/Audio/GameAudio.cpp
Comment thread Core/GameEngine/Source/Common/Audio/GameAudio.cpp
@greptile-apps

greptile-apps Bot commented Sep 3, 2026

Copy link
Copy Markdown

Greptile Summary

This PR removes the stream-sensitive suppression of 3D volume updates and avoids marking audio volume state dirty when the effective value is unchanged.

  • Removes has3DSensitiveStreamsPlaying from the shared audio contract, Miles implementation, and dummy manager.
  • Updates category and zoom-adjusted 3D volumes only when their computed values differ.
  • Marks m_volumeHasChanged only for effective volume changes.

Confidence Score: 5/5

The PR appears safe to merge within its explicitly stated scope, with no unacknowledged actionable defects identified.

The effective-volume comparisons consistently preserve updates when values change, and the known risk associated with removing the legacy stream guard is explicitly acknowledged as intentional in the PR description.

Important Files Changed

Filename Overview
Core/GameEngine/Include/Common/GameAudio.h Removes the stream-sensitivity query from the device-independent audio interface.
Core/GameEngine/Source/Common/Audio/GameAudio.cpp Recomputes category and 3D-adjusted volumes and marks them dirty only when the effective value changes.
Core/GameEngineDevice/Include/MilesAudioDevice/MilesAudioManager.h Removes the obsolete stream-sensitivity overrides from the Miles and dummy managers.
Core/GameEngineDevice/Source/MilesAudioDevice/MilesAudioManager.cpp Deletes the Miles-specific sensitive-stream detection workaround.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart LR
    Camera[Camera or microphone movement] --> Zoom[Compute zoom volume]
    Zoom --> Adjust[set3DVolumeAdjustment]
    Adjust --> Changed{Effective volume changed?}
    Changed -- No --> Skip[Keep dirty flag unchanged]
    Changed -- Yes --> Dirty[Set m_volumeHasChanged]
    Dirty --> Process[processPlayingList]
    Process --> Apply[Apply volume to active samples and streams]
Loading

Reviews (1): Last reviewed commit: "tweak(gameaudio): Only update sound volu..." | Re-trigger Greptile

@Mauller Mauller left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks reasonable

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Fix Is fixing something, but is not user facing Gen Relates to Generals Minor Severity: Minor < Major < Critical < Blocker ZH Relates to Zero Hour

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants