diff --git a/src/tests/Dragon-ISO.Engine.Tests/Pipeline/AudioPeakComputerTests.cs b/src/tests/Dragon-ISO.Engine.Tests/Pipeline/AudioPeakComputerTests.cs
index 382af71..52a43f0 100644
--- a/src/tests/Dragon-ISO.Engine.Tests/Pipeline/AudioPeakComputerTests.cs
+++ b/src/tests/Dragon-ISO.Engine.Tests/Pipeline/AudioPeakComputerTests.cs
@@ -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);
+ }
+
+ /// Little-endian ASCII FourCC packing: first char in the low byte.
+ 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[] arr) where T : struct
{
var span = MemoryMarshal.Cast(arr.AsSpan());