blob: 58f888f65b763355c3584b169d76724d97e9ae2d [file]
/*
* Copyright 2024 The WebRTC project authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "modules/rtp_rtcp/source/corruption_detection_extension.h"
#include <cstddef>
#include <cstdint>
#include <optional>
#include "api/transport/rtp/corruption_detection_message.h"
#include "test/gmock.h"
#include "test/gtest.h"
namespace webrtc {
namespace {
using ::testing::DoubleEq;
using ::testing::ElementsAre;
using ::testing::ElementsAreArray;
TEST(CorruptionDetectionExtensionTest, ValueSizeIs1UnlessSamplesAreSpecified) {
const std::optional<CorruptionDetectionMessage> kMessage =
CorruptionDetectionMessage::Builder()
.WithSequenceIndex(0b0110'1111)
.WithInterpretSequenceIndexAsMostSignificantBits(true)
.WithStdDev(8.0)
.WithSampleValues({})
.Build();
ASSERT_NE(kMessage, std::nullopt);
EXPECT_EQ(CorruptionDetectionExtension::ValueSize(*kMessage), size_t{1});
}
TEST(CorruptionDetectionExtensionTest,
GivenSamplesTheValueSizeIsTheSumOfTheNumberOfSamplesPlus3) {
const double kSampleValues[] = {1.0, 2.0, 3.0, 4.0};
const std::optional<CorruptionDetectionMessage> kMessage =
CorruptionDetectionMessage::Builder()
.WithSampleValues(kSampleValues)
.Build();
ASSERT_NE(kMessage, std::nullopt);
EXPECT_EQ(CorruptionDetectionExtension::ValueSize(*kMessage), size_t{7});
}
TEST(CorruptionDetectionExtensionTest,
WritesMandatoryWhenEnoughMemoryIsAllocatedWithoutSamples) {
const std::optional<CorruptionDetectionMessage> kMessage =
CorruptionDetectionMessage::Builder()
.WithSequenceIndex(0b0110'1111)
.WithInterpretSequenceIndexAsMostSignificantBits(true)
.Build();
uint8_t data[] = {0};
ASSERT_NE(kMessage, std::nullopt);
EXPECT_TRUE(CorruptionDetectionExtension::Write(data, *kMessage));
EXPECT_THAT(data, ElementsAre(0b1110'1111));
}
TEST(CorruptionDetectionExtensionTest,
FailsToWriteWhenTooMuchMemoryIsAllocatedWithoutSamples) {
const std::optional<CorruptionDetectionMessage> kMessage =
CorruptionDetectionMessage::Builder()
.WithSequenceIndex(0b0110'1111)
.WithInterpretSequenceIndexAsMostSignificantBits(true)
.Build();
uint8_t data[] = {0, 0, 0};
ASSERT_NE(kMessage, std::nullopt);
EXPECT_FALSE(CorruptionDetectionExtension::Write(data, *kMessage));
}
TEST(CorruptionDetectionExtensionTest,
FailsToWriteWhenTooMuchMemoryIsAllocatedWithSamples) {
const double kSampleValues[] = {1.0};
const std::optional<CorruptionDetectionMessage> kMessage =
CorruptionDetectionMessage::Builder()
.WithSequenceIndex(0b0110'1111)
.WithInterpretSequenceIndexAsMostSignificantBits(true)
.WithStdDev(8.0)
.WithSampleValues(kSampleValues)
.Build();
uint8_t data[] = {0, 0, 0, 0, 0};
ASSERT_NE(kMessage, std::nullopt);
EXPECT_FALSE(CorruptionDetectionExtension::Write(data, *kMessage));
}
TEST(CorruptionDetectionExtensionTest,
WritesEverythingWhenEnoughMemoryIsAllocatedWithSamples) {
const double kSampleValues[] = {1.0};
const std::optional<CorruptionDetectionMessage> kMessage =
CorruptionDetectionMessage::Builder()
.WithSequenceIndex(0b0110'1111)
.WithInterpretSequenceIndexAsMostSignificantBits(true)
.WithStdDev(8.0)
.WithSampleValues(kSampleValues)
.Build();
uint8_t data[] = {0, 0, 0, 0};
ASSERT_NE(kMessage, std::nullopt);
EXPECT_TRUE(CorruptionDetectionExtension::Write(data, *kMessage));
EXPECT_THAT(data, ElementsAre(0b1110'1111, 51, 0, 1));
}
TEST(CorruptionDetectionExtensionTest,
WritesEverythingToExtensionWhenUpperBitsAreUsedForSequenceIndex) {
const double kSampleValues[] = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0,
8.0, 9.0, 10.0, 11.0, 12.0, 13.0};
const std::optional<CorruptionDetectionMessage> kMessage =
CorruptionDetectionMessage::Builder()
.WithSequenceIndex(0b0110'1111)
.WithInterpretSequenceIndexAsMostSignificantBits(true)
.WithStdDev(34.5098) // 220 / 255.0 * 40.0
.WithLumaErrorThreshold(0b1110)
.WithChromaErrorThreshold(0b1111)
.WithSampleValues(kSampleValues)
.Build();
uint8_t data[16];
ASSERT_NE(kMessage, std::nullopt);
EXPECT_TRUE(CorruptionDetectionExtension::Write(data, *kMessage));
EXPECT_THAT(data, ElementsAre(0b1110'1111, 220, 0b1110'1111, 1, 2, 3, 4, 5, 6,
7, 8, 9, 10, 11, 12, 13));
}
TEST(CorruptionDetectionExtensionTest,
WritesEverythingToExtensionWhenLowerBitsAreUsedForSequenceIndex) {
const double kSampleValues[] = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0,
8.0, 9.0, 10.0, 11.0, 12.0, 13.0};
const std::optional<CorruptionDetectionMessage> kMessage =
CorruptionDetectionMessage::Builder()
.WithSequenceIndex(0b0110'1111)
.WithInterpretSequenceIndexAsMostSignificantBits(false)
.WithStdDev(34.5098) // 220 / 255.0 * 40.0
.WithLumaErrorThreshold(0b1110)
.WithChromaErrorThreshold(0b1111)
.WithSampleValues(kSampleValues)
.Build();
uint8_t data[16];
ASSERT_NE(kMessage, std::nullopt);
EXPECT_TRUE(CorruptionDetectionExtension::Write(data, *kMessage));
EXPECT_THAT(data, ElementsAre(0b0110'1111, 220, 0b1110'1111, 1, 2, 3, 4, 5, 6,
7, 8, 9, 10, 11, 12, 13));
}
TEST(CorruptionDetectionExtensionTest, TruncatesSampleValuesWhenWriting) {
const double kSampleValues[] = {1.4, 2.5, 3.6};
const std::optional<CorruptionDetectionMessage> kMessage =
CorruptionDetectionMessage::Builder()
.WithSampleValues(kSampleValues)
.Build();
uint8_t data[6];
ASSERT_NE(kMessage, std::nullopt);
EXPECT_TRUE(CorruptionDetectionExtension::Write(data, *kMessage));
EXPECT_THAT(data, ElementsAre(0, 0, 0, 1, 2, 3));
}
TEST(CorruptionDetectionExtensionTest, ParsesMandatoryFieldsFromExtension) {
CorruptionDetectionMessage message;
const uint8_t kData[] = {0b1110'1111};
EXPECT_TRUE(CorruptionDetectionExtension::Parse(kData, &message));
EXPECT_EQ(message.sequence_index(), 0b0110'1111);
EXPECT_TRUE(message.interpret_sequence_index_as_most_significant_bits());
EXPECT_THAT(message.std_dev(), DoubleEq(0.0));
EXPECT_EQ(message.luma_error_threshold(), 0);
EXPECT_EQ(message.chroma_error_threshold(), 0);
EXPECT_THAT(message.sample_values(), ElementsAre());
}
TEST(CorruptionDetectionExtensionTest, FailsToParseWhenGivenTooFewFields) {
CorruptionDetectionMessage message;
const uint8_t kData[] = {0b1110'1111, 8, 0};
EXPECT_FALSE(CorruptionDetectionExtension::Parse(kData, &message));
}
TEST(CorruptionDetectionExtensionTest,
ParsesEverythingFromExtensionWhenUpperBitsAreUsedForSequenceIndex) {
CorruptionDetectionMessage message;
const uint8_t kSampleValues[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13};
const uint8_t kData[] = {0b1100'0100, 220,
0b1110'1111, kSampleValues[0],
kSampleValues[1], kSampleValues[2],
kSampleValues[3], kSampleValues[4],
kSampleValues[5], kSampleValues[6],
kSampleValues[7], kSampleValues[8],
kSampleValues[9], kSampleValues[10],
kSampleValues[11], kSampleValues[12]};
EXPECT_TRUE(CorruptionDetectionExtension::Parse(kData, &message));
EXPECT_EQ(message.sequence_index(), 0b0100'0100);
EXPECT_TRUE(message.interpret_sequence_index_as_most_significant_bits());
EXPECT_THAT(message.std_dev(),
DoubleEq(34.509803921568626)); // 220 / 255.0 * 40.0
EXPECT_EQ(message.luma_error_threshold(), 0b1110);
EXPECT_EQ(message.chroma_error_threshold(), 0b1111);
EXPECT_THAT(message.sample_values(), ElementsAreArray(kSampleValues));
}
TEST(CorruptionDetectionExtensionTest,
ParsesEverythingFromExtensionWhenLowerBitsAreUsedForSequenceIndex) {
CorruptionDetectionMessage message;
const uint8_t kSampleValues[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13};
const uint8_t kData[] = {0b0100'0100, 220,
0b1110'1111, kSampleValues[0],
kSampleValues[1], kSampleValues[2],
kSampleValues[3], kSampleValues[4],
kSampleValues[5], kSampleValues[6],
kSampleValues[7], kSampleValues[8],
kSampleValues[9], kSampleValues[10],
kSampleValues[11], kSampleValues[12]};
EXPECT_TRUE(CorruptionDetectionExtension::Parse(kData, &message));
EXPECT_EQ(message.sequence_index(), 0b0100'0100);
EXPECT_FALSE(message.interpret_sequence_index_as_most_significant_bits());
EXPECT_THAT(message.std_dev(),
DoubleEq(34.509803921568626)); // 220 / 255.0 * 40.0
EXPECT_EQ(message.luma_error_threshold(), 0b1110);
EXPECT_EQ(message.chroma_error_threshold(), 0b1111);
EXPECT_THAT(message.sample_values(), ElementsAreArray(kSampleValues));
}
TEST(CorruptionDetectionExtensionTest, FailsToParseWhenGivenNullptrAsOutput) {
const uint8_t kData[] = {0, 0, 0};
EXPECT_FALSE(CorruptionDetectionExtension::Parse(kData, nullptr));
}
TEST(CorruptionDetectionExtensionTest,
FailsToParseWhenTooManySamplesAreSpecified) {
CorruptionDetectionMessage message;
uint8_t data[17];
EXPECT_FALSE(CorruptionDetectionExtension::Parse(data, &message));
}
} // namespace
} // namespace webrtc