CNA-BUG-147: SoundBank::PlayCue destroys a fire-and-forget cue that is still playing five minutes after it started
Evidence basis: source-verified at the pinned commit; tests exist (not executed for this page). Claims on this page were checked by reading the CNA source at commit 009d40f5; unless a sentence says otherwise, nothing here was built or executed. Nothing on this page was executed unless the Evidence section says so.
SweepFireAndForget, run by every AudioEngine::Update and every PlayCue, removes still-playing or paused fire-and-forget cues older than kFireAndForgetSafetyNet (5 minutes), which stops long or looping cues such as music started with PlayCue.
- Identifier
CNA-BUG-147- Category
- Bug
- Subsystem
- Audio & media
- Status
- Open
- Verified against
- CNA
009d40f5(009d40f5dd085c4e674d3479675fac84b12b3e0a) - Severity
- Medium (a triage suggestion, not a project priority)
- Evidence basis
- Source-verified: read at TARGET, not executed
- Tests touching this area
- Yes: see Current tests
- Affected contract
- SoundBank::PlayCue(const std::string&) and PlayCue(name, listener, emitter)
Expected behaviour
In XNA, a cue started with SoundBank.PlayCue plays until it ends or its category is stopped; there is no age limit, and looping music or ambience is commonly started this way.
Actual behaviour at TARGET
AudioEngine::Update in AudioEngine.cpp sweeps every registered bank, and SoundBank::PlayCueInternal in SoundBank.cpp calls SweepFireAndForget first. The sweep keeps a playing or paused cue only while now - faf.created < kFireAndForgetSafetyNet (5 minutes); older entries are erased, destroying the Cue and its instances. Any AudioEngine::Update (which XNA games call every frame) or PlayCue more than five minutes after a looping cue started therefore cuts that cue off. The comment calls the constant a safety net against unbounded growth that “never affects ordinary playback”; the test comment explains that a looping cue never reports itself finished (plan_audio.md Fáze 7 D6).
Source locations
modules/audio/src/Xna/SoundBank.cpp— kFireAndForgetSafetyNet, SoundBank::SweepFireAndForget, SoundBank::PlayCueInternalmodules/audio/src/Xna/AudioEngine.cpp— AudioEngine::Update sweeps every registered bankmodules/audio/tests/Microsoft/Xna/Framework/Audio/SoundBankTests.cpp— FireAndForgetCueIsForceSweptPastSafetyNetEvenIfStillPlaying pins the cut
Evidence
Checked by reading at 009d40f5; not executed.
Focused reproduction
// Illustrative; not compiled or run.
soundBank.PlayCue("MusicLoop"); // a looping cue
// ... more than five minutes later, the next per-frame call:
audioEngine.Update(); // the sweep destroys MusicLoop
Current tests
SoundBankTests.cpp keeps long-playing and paused cues across sweeps and pins the cut itself: FireAndForgetCueIsForceSweptPastSafetyNetEvenIfStillPlaying backdates a playing cue by ten minutes and expects it swept. A fix must change that test.
Regression test
A test with an injectable clock (or a shortened safety net) asserting a looping fire-and-forget cue survives later PlayCue calls; bound growth by sweeping stopped cues only, or by a count limit that does not stop audible cues.
Blast radius
Games that start music or ambience with PlayCue and keep playing cues from the same bank; the long cue stops abruptly after five minutes.
Workaround
Start long or looping cues with GetCue + Play and keep the Cue.
Related pages
The same subject is explained at several altitudes. These are the neighbouring pages at each one.
- User guide
- Audio: XACT
- Deep dives
- XACT runtime: categories and limits
- Known issues
- Bug index