test(engine): pin audio FourCC constants to ASCII packing
All checks were successful
CI / build-and-test (push) Successful in 28s
All checks were successful
CI / build-and-test (push) Successful in 28s
Adds regression tests that would have caught the PCMs16 FourCC typo
(0x73334d50 'PM3s' vs correct 0x734D4350 'PCMs'). The prior tests
referenced the symbol on both sides of the assertion, so a wrong literal
stayed self-consistent and green. These new tests:
1. Assert each public FourCC constant equals the little-endian ASCII
packing of its documented characters (the same convention the NDI
SDK and the video FourCCs use).
2. Feed a raw PCM16 buffer tagged with the *literal* 0x734D4350 and
assert the peak is decoded — proving a real Teams legacy sender's
FourCC routes to the int16 decoder rather than the unknown branch.
This commit is contained in:
parent
915510c938
commit
e5f10f2667
1 changed files with 52 additions and 3 deletions
|
|
@ -22,7 +22,7 @@ public class AudioPeakComputerTests
|
|||
[Fact]
|
||||
public void UnknownFourCC_ReturnsZero_RatherThanThrow()
|
||||
{
|
||||
// Receiver loop must never crash on an unrecognized format — better to
|
||||
// Receiver loop must never crash on an unrecognized format — better to
|
||||
// show silence on the meter than to take down the pipeline.
|
||||
var floats = new[] { 0.5f, -0.5f };
|
||||
var bytes = AsBytes(floats);
|
||||
|
|
@ -77,7 +77,7 @@ public class AudioPeakComputerTests
|
|||
public void Fltp_TotalSamplesSmallerThanBuffer_OnlyConsumesReportedRange()
|
||||
{
|
||||
// The reported range covers only the first 3 floats. The 4th
|
||||
// (largest) is past `totalSamples` and must be ignored — otherwise we'd
|
||||
// (largest) is past `totalSamples` and must be ignored — otherwise we'd
|
||||
// be reading beyond what the source said it wrote.
|
||||
var floats = new[] { 0.1f, -0.2f, 0.3f, 0.99f };
|
||||
var bytes = AsBytes(floats);
|
||||
|
|
@ -128,10 +128,59 @@ public class AudioPeakComputerTests
|
|||
var samples = new[] { (short)0, (short)16384, (short)-16383 };
|
||||
var bytes = AsBytes(samples);
|
||||
var peak = AudioPeakComputer.ComputePeak(bytes, AudioPeakComputer.FourCC_PCMs16, samples.Length);
|
||||
// 16384 / 32767 ≈ 0.500015; tolerate small precision drift.
|
||||
// 16384 / 32767 ≈ 0.500015; tolerate small precision drift.
|
||||
Assert.InRange(peak, 0.49, 0.51);
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// FourCC constant integrity — regression guard
|
||||
// ============================================================
|
||||
//
|
||||
// The NDI SDK packs FourCCs little-endian: the first ASCII character
|
||||
// lands in the least-significant byte. These tests pin each public
|
||||
// constant to the little-endian packing of its documented characters,
|
||||
// so a transposed/typo'd literal (the PCMs16 0x73334d50 → 0x734D4350
|
||||
// fix) fails loudly instead of silently routing real audio to the
|
||||
// "unknown format → 0.0" branch.
|
||||
|
||||
[Fact]
|
||||
public void FourCC_FLTP_MatchesAsciiPacking()
|
||||
{
|
||||
AudioPeakComputer.FourCC_FLTP.Should().Be(Pack('F', 'L', 'T', 'p'));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FourCC_FLT_MatchesAsciiPacking()
|
||||
{
|
||||
AudioPeakComputer.FourCC_FLT.Should().Be(Pack('F', 'L', 'T', ' '));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FourCC_PCMs16_MatchesAsciiPacking()
|
||||
{
|
||||
// Regression: was 0x73334d50 ('P','M','3','s'), should be 'P','C','M','s'.
|
||||
AudioPeakComputer.FourCC_PCMs16.Should().Be(Pack('P', 'C', 'M', 's'));
|
||||
AudioPeakComputer.FourCC_PCMs16.Should().Be(0x734D4350u);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Pcms16_DecodedViaLiteralFourCC_NotJustSymbol()
|
||||
{
|
||||
// Belt-and-braces: feed a PCM16 buffer tagged with the *literal* FourCC
|
||||
// a real legacy Teams/NDI sender emits, not the symbol. If the constant
|
||||
// ever drifts from the wire value again, this peak collapses to 0.0
|
||||
// because ComputePeak falls through to the unknown branch.
|
||||
const uint wirePcms16 = 0x734D4350; // little-endian 'P','C','M','s'
|
||||
var samples = new[] { (short)0, (short)16384, (short)-200 };
|
||||
var bytes = AsBytes(samples);
|
||||
var peak = AudioPeakComputer.ComputePeak(bytes, wirePcms16, samples.Length);
|
||||
peak.Should().BeInRange(0.49, 0.51);
|
||||
}
|
||||
|
||||
/// <summary>Little-endian ASCII FourCC packing: first char in the low byte.</summary>
|
||||
private static uint Pack(char a, char b, char c, char d) =>
|
||||
(uint)a | ((uint)b << 8) | ((uint)c << 16) | ((uint)d << 24);
|
||||
|
||||
private static byte[] AsBytes<T>(T[] arr) where T : struct
|
||||
{
|
||||
var span = MemoryMarshal.Cast<T, byte>(arr.AsSpan());
|
||||
|
|
|
|||
Loading…
Reference in a new issue