CNA-BUG-148: DynamicSoundEffectInstance::SubmitBuffer accepts empty and non-frame-aligned buffers that XNA rejects

CNA snapshot 009d40f5  ·  Known Issues › Current bugs  ·  source links pinned to 009d40f5

✓

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.

CNA checks only that offset and count lie inside the buffer; XNA throws ArgumentException for an empty buffer, a length, offset or count that is not block-aligned, or a count of zero. Such submissions are queued without error, then dropped by SDL3 audio or played shifted by CNA's ALSA mixer. SubmitFloatBufferEXT (an FNA extension with no XNA contract) has the same gap for channel frames.

Identifier
CNA-BUG-148
Category
Bug
Subsystem
Audio & media
Status
Open
Verified against
CNA 009d40f5 (009d40f5dd085c4e674d3479675fac84b12b3e0a)
Severity
Low (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
DynamicSoundEffectInstance::SubmitBuffer(const std::vector<bytecs>&[, int offset, int count]) and SubmitFloatBufferEXT

Expected behaviour

XNA 4.0's SubmitBuffer(byte[], int, int) (IL) throws ArgumentException when the buffer is null or empty or its length is not format.IsAligned, when the offset is out of range or unaligned, and when the count is not positive, overruns the buffer or is unaligned. CNA's own plan carries the same requirement as open P0 tasks AUD-07-005 and AUD-07-006 in plan_audio.md.

Actual behaviour at TARGET

SubmitBuffer in DynamicSoundEffectInstance.cpp throws only when the instance is disposed, when offset/count are negative or overrun the buffer, or on the int/float mode guard; an empty buffer, a zero count and a byte count that is not a whole number of frames are queued without an error. What happens next depends on the mixer. With SDL3 audio, SDL_PutAudioStreamData refuses a chunk that is not a whole number of frames ("Can't add partial sample frames"), so SubmitQueuedToStreamLocked writes "stream submit failed (N bytes dropped)" to stderr and the chunk is silently lost. With CNA's own ALSA mixer, PutMixerStreamData appends the bytes unchecked and ReadFrame consumes whole frames, so a partial frame at the end of one chunk joins the start of the next and shifts every later sample (stereo channels swap, 16-bit samples split).

Source locations

Evidence

Checked by reading at 009d40f5 against the XNA 4.0 IL of DynamicSoundEffectInstance.SubmitBuffer; not executed.

Independent re-verification: Checked by reading at 009d40f5 against the XNA 4.0 IL of DynamicSoundEffectInstance.SubmitBuffer; not executed. Three tests pin the current no-throw behaviour on purpose (SubmitBufferWithNonFrameAlignedByteCountDoesNotThrowWhileStopped, SubmitBufferWithNonFrameAlignedByteCountWhilePlayingDoesNotThrow, SubmitFloatBufferWithSampleCountNotDivisibleByChannelCountDoesNotThrow, from plan P9-DYNAMIC-009 which matched FNA), so a fix must change them; plan_audio.md records AUD-07-005/006 as open P0 tasks. CNA's own plan records the SDL3 'Can't add partial sample frames' rejection from a real run.

Focused reproduction

// Illustrative; not compiled or run.
DynamicSoundEffectInstance d(44100, AudioChannels::Stereo);
std::vector<SharpRuntime::bytecs> odd(4097);
d.SubmitBuffer(odd);   // XNA: ArgumentException; CNA: queued

Current tests

DynamicSoundEffectInstanceTests.cpp covers range errors and disposal; no test submits an unaligned or empty buffer.

Regression test

Cases for an empty buffer, an odd byte count on 16-bit audio, an odd float count on stereo and a zero count, each expecting ArgumentException.

Blast radius

Streaming audio code with an arithmetic slip; XNA would have thrown, CNA plays corrupted audio.

Workaround

Submit whole frames only (a multiple of 2 × channels bytes).

The same subject is explained at several altitudes. These are the neighbouring pages at each one.

User guide
Audio: overview
Known issues
Bug index