diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
commit | 36d22d82aa202bb199967e9512281e9a53db42c9 (patch) | |
tree | 105e8c98ddea1c1e4784a60a5a6410fa416be2de /third_party/libwebrtc/common_audio/wav_header_unittest.cc | |
parent | Initial commit. (diff) | |
download | firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip |
Adding upstream version 115.7.0esr.upstream/115.7.0esr
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/libwebrtc/common_audio/wav_header_unittest.cc')
-rw-r--r-- | third_party/libwebrtc/common_audio/wav_header_unittest.cc | 447 |
1 files changed, 447 insertions, 0 deletions
diff --git a/third_party/libwebrtc/common_audio/wav_header_unittest.cc b/third_party/libwebrtc/common_audio/wav_header_unittest.cc new file mode 100644 index 0000000000..95721dac65 --- /dev/null +++ b/third_party/libwebrtc/common_audio/wav_header_unittest.cc @@ -0,0 +1,447 @@ +/* + * Copyright (c) 2014 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 "common_audio/wav_header.h" + +#include <string.h> + +#include <limits> + +#include "test/gtest.h" + +namespace webrtc { + +// Doesn't take ownership of the buffer. +class WavHeaderBufferReader : public WavHeaderReader { + public: + WavHeaderBufferReader(const uint8_t* buf, size_t size, bool check_read_size) + : buf_(buf), + size_(size), + pos_(0), + buf_exhausted_(false), + check_read_size_(check_read_size) {} + + ~WavHeaderBufferReader() override { + // Verify the entire buffer has been read. + if (check_read_size_) + EXPECT_EQ(size_, pos_); + } + + size_t Read(void* buf, size_t num_bytes) override { + EXPECT_FALSE(buf_exhausted_); + + const size_t bytes_remaining = size_ - pos_; + if (num_bytes > bytes_remaining) { + // The caller is signalled about an exhausted buffer when we return fewer + // bytes than requested. There should not be another read attempt after + // this point. + buf_exhausted_ = true; + num_bytes = bytes_remaining; + } + memcpy(buf, &buf_[pos_], num_bytes); + pos_ += num_bytes; + return num_bytes; + } + + bool SeekForward(uint32_t num_bytes) override { + // Verify we don't try to read outside of a properly sized header. + if (size_ >= kPcmWavHeaderSize) + EXPECT_GE(size_, pos_ + num_bytes); + EXPECT_FALSE(buf_exhausted_); + + const size_t bytes_remaining = size_ - pos_; + if (num_bytes > bytes_remaining) { + // Error: cannot seek beyond EOF. + return false; + } + if (num_bytes == bytes_remaining) { + // There should not be another read attempt after this point. + buf_exhausted_ = true; + } + pos_ += num_bytes; + return true; + } + + int64_t GetPosition() override { return pos_; } + + private: + const uint8_t* buf_; + const size_t size_; + size_t pos_; + bool buf_exhausted_; + const bool check_read_size_; +}; + +// Try various choices of WAV header parameters, and make sure that the good +// ones are accepted and the bad ones rejected. +TEST(WavHeaderTest, CheckWavParameters) { + // Try some really stupid values for one parameter at a time. + EXPECT_TRUE(CheckWavParameters(1, 8000, WavFormat::kWavFormatPcm, 0)); + EXPECT_FALSE(CheckWavParameters(0, 8000, WavFormat::kWavFormatPcm, 0)); + EXPECT_FALSE(CheckWavParameters(0x10000, 8000, WavFormat::kWavFormatPcm, 0)); + EXPECT_FALSE(CheckWavParameters(1, 0, WavFormat::kWavFormatPcm, 0)); + + // Too large values. + EXPECT_FALSE( + CheckWavParameters(1 << 20, 1 << 20, WavFormat::kWavFormatPcm, 0)); + EXPECT_FALSE(CheckWavParameters(1, 8000, WavFormat::kWavFormatPcm, + std::numeric_limits<uint32_t>::max())); + + // Not the same number of samples for each channel. + EXPECT_FALSE(CheckWavParameters(3, 8000, WavFormat::kWavFormatPcm, 5)); +} + +TEST(WavHeaderTest, ReadWavHeaderWithErrors) { + size_t num_channels = 0; + int sample_rate = 0; + WavFormat format = WavFormat::kWavFormatPcm; + size_t bytes_per_sample = 0; + size_t num_samples = 0; + int64_t data_start_pos = 0; + + // Test a few ways the header can be invalid. We start with the valid header + // used in WriteAndReadWavHeader, and invalidate one field per test. The + // invalid field is indicated in the array name, and in the comments with + // *BAD*. + { + constexpr uint8_t kBadRiffID[] = { + // clang-format off + // clang formatting doesn't respect inline comments. + 'R', 'i', 'f', 'f', // *BAD* + 0xbd, 0xd0, 0x5b, 0x07, // size of whole file - 8: 123457689 + 44 - 8 + 'W', 'A', 'V', 'E', + 'f', 'm', 't', ' ', + 16, 0, 0, 0, // size of fmt block - 8: 24 - 8 + 1, 0, // format: PCM (1) + 17, 0, // channels: 17 + 0x39, 0x30, 0, 0, // sample rate: 12345 + 0xc9, 0x33, 0x03, 0, // byte rate: 1 * 17 * 12345 + 17, 0, // block align: NumChannels * BytesPerSample + 8, 0, // bits per sample: 1 * 8 + 'd', 'a', 't', 'a', + 0x99, 0xd0, 0x5b, 0x07, // size of payload: 123457689 + // clang-format on + }; + WavHeaderBufferReader r(kBadRiffID, sizeof(kBadRiffID), + /*check_read_size=*/false); + EXPECT_FALSE(ReadWavHeader(&r, &num_channels, &sample_rate, &format, + &bytes_per_sample, &num_samples, + &data_start_pos)); + } + { + constexpr uint8_t kBadBitsPerSample[] = { + // clang-format off + // clang formatting doesn't respect inline comments. + 'R', 'I', 'F', 'F', + 0xbd, 0xd0, 0x5b, 0x07, // size of whole file - 8: 123457689 + 44 - 8 + 'W', 'A', 'V', 'E', + 'f', 'm', 't', ' ', + 16, 0, 0, 0, // size of fmt block - 8: 24 - 8 + 1, 0, // format: PCM (1) + 17, 0, // channels: 17 + 0x39, 0x30, 0, 0, // sample rate: 12345 + 0xc9, 0x33, 0x03, 0, // byte rate: 1 * 17 * 12345 + 17, 0, // block align: NumChannels * BytesPerSample + 1, 0, // bits per sample: *BAD* + 'd', 'a', 't', 'a', + 0x99, 0xd0, 0x5b, 0x07, // size of payload: 123457689 + // clang-format on + }; + WavHeaderBufferReader r(kBadBitsPerSample, sizeof(kBadBitsPerSample), + /*check_read_size=*/true); + EXPECT_FALSE(ReadWavHeader(&r, &num_channels, &sample_rate, &format, + &bytes_per_sample, &num_samples, + &data_start_pos)); + } + { + constexpr uint8_t kBadByteRate[] = { + // clang-format off + // clang formatting doesn't respect inline comments. + 'R', 'I', 'F', 'F', + 0xbd, 0xd0, 0x5b, 0x07, // size of whole file - 8: 123457689 + 44 - 8 + 'W', 'A', 'V', 'E', + 'f', 'm', 't', ' ', + 16, 0, 0, 0, // size of fmt block - 8: 24 - 8 + 1, 0, // format: PCM (1) + 17, 0, // channels: 17 + 0x39, 0x30, 0, 0, // sample rate: 12345 + 0x00, 0x33, 0x03, 0, // byte rate: *BAD* + 17, 0, // block align: NumChannels * BytesPerSample + 8, 0, // bits per sample: 1 * 8 + 'd', 'a', 't', 'a', + 0x99, 0xd0, 0x5b, 0x07, // size of payload: 123457689 + // clang-format on + }; + WavHeaderBufferReader r(kBadByteRate, sizeof(kBadByteRate), + /*check_read_size=*/true); + EXPECT_FALSE(ReadWavHeader(&r, &num_channels, &sample_rate, &format, + &bytes_per_sample, &num_samples, + &data_start_pos)); + } + { + constexpr uint8_t kBadFmtHeaderSize[] = { + // clang-format off + // clang formatting doesn't respect inline comments. + 'R', 'I', 'F', 'F', + 0xbd, 0xd0, 0x5b, 0x07, // size of whole file - 8: 123457689 + 44 - 8 + 'W', 'A', 'V', 'E', + 'f', 'm', 't', ' ', + 17, 0, 0, 0, // size of fmt block *BAD*. Only 16 and 18 permitted. + 1, 0, // format: PCM (1) + 17, 0, // channels: 17 + 0x39, 0x30, 0, 0, // sample rate: 12345 + 0xc9, 0x33, 0x03, 0, // byte rate: 1 * 17 * 12345 + 17, 0, // block align: NumChannels * BytesPerSample + 8, 0, // bits per sample: 1 * 8 + 0, // extra (though invalid) header byte + 'd', 'a', 't', 'a', + 0x99, 0xd0, 0x5b, 0x07, // size of payload: 123457689 + // clang-format on + }; + WavHeaderBufferReader r(kBadFmtHeaderSize, sizeof(kBadFmtHeaderSize), + /*check_read_size=*/false); + EXPECT_FALSE(ReadWavHeader(&r, &num_channels, &sample_rate, &format, + &bytes_per_sample, &num_samples, + &data_start_pos)); + } + { + constexpr uint8_t kNonZeroExtensionField[] = { + // clang-format off + // clang formatting doesn't respect inline comments. + 'R', 'I', 'F', 'F', + 0xbd, 0xd0, 0x5b, 0x07, // size of whole file - 8: 123457689 + 44 - 8 + 'W', 'A', 'V', 'E', + 'f', 'm', 't', ' ', + 18, 0, 0, 0, // size of fmt block - 8: 24 - 8 + 1, 0, // format: PCM (1) + 17, 0, // channels: 17 + 0x39, 0x30, 0, 0, // sample rate: 12345 + 0xc9, 0x33, 0x03, 0, // byte rate: 1 * 17 * 12345 + 17, 0, // block align: NumChannels * BytesPerSample + 8, 0, // bits per sample: 1 * 8 + 1, 0, // non-zero extension field *BAD* + 'd', 'a', 't', 'a', + 0x99, 0xd0, 0x5b, 0x07, // size of payload: 123457689 + // clang-format on + }; + WavHeaderBufferReader r(kNonZeroExtensionField, + sizeof(kNonZeroExtensionField), + /*check_read_size=*/false); + EXPECT_FALSE(ReadWavHeader(&r, &num_channels, &sample_rate, &format, + &bytes_per_sample, &num_samples, + &data_start_pos)); + } + { + constexpr uint8_t kMissingDataChunk[] = { + // clang-format off + // clang formatting doesn't respect inline comments. + 'R', 'I', 'F', 'F', + 0xbd, 0xd0, 0x5b, 0x07, // size of whole file - 8: 123457689 + 44 - 8 + 'W', 'A', 'V', 'E', + 'f', 'm', 't', ' ', + 16, 0, 0, 0, // size of fmt block - 8: 24 - 8 + 1, 0, // format: PCM (1) + 17, 0, // channels: 17 + 0x39, 0x30, 0, 0, // sample rate: 12345 + 0xc9, 0x33, 0x03, 0, // byte rate: 1 * 17 * 12345 + 17, 0, // block align: NumChannels * BytesPerSample + 8, 0, // bits per sample: 1 * 8 + // clang-format on + }; + WavHeaderBufferReader r(kMissingDataChunk, sizeof(kMissingDataChunk), + /*check_read_size=*/true); + EXPECT_FALSE(ReadWavHeader(&r, &num_channels, &sample_rate, &format, + &bytes_per_sample, &num_samples, + &data_start_pos)); + } + { + constexpr uint8_t kMissingFmtAndDataChunks[] = { + // clang-format off + // clang formatting doesn't respect inline comments. + 'R', 'I', 'F', 'F', + 0xbd, 0xd0, 0x5b, 0x07, // size of whole file - 8: 123457689 + 44 - 8 + 'W', 'A', 'V', 'E', + // clang-format on + }; + WavHeaderBufferReader r(kMissingFmtAndDataChunks, + sizeof(kMissingFmtAndDataChunks), + /*check_read_size=*/true); + EXPECT_FALSE(ReadWavHeader(&r, &num_channels, &sample_rate, &format, + &bytes_per_sample, &num_samples, + &data_start_pos)); + } +} + +// Try writing and reading a valid WAV header and make sure it looks OK. +TEST(WavHeaderTest, WriteAndReadWavHeader) { + constexpr int kSize = 4 + kPcmWavHeaderSize + 4; + uint8_t buf[kSize]; + size_t header_size; + memset(buf, 0xa4, sizeof(buf)); + WriteWavHeader(17, 12345, WavFormat::kWavFormatPcm, 123457689, buf + 4, + &header_size); + constexpr uint8_t kExpectedBuf[] = { + // clang-format off + // clang formatting doesn't respect inline comments. + 0xa4, 0xa4, 0xa4, 0xa4, // untouched bytes before header + 'R', 'I', 'F', 'F', + 0x56, 0xa1, 0xb7, 0x0e, // size of whole file - 8: 123457689 + 44 - 8 + 'W', 'A', 'V', 'E', + 'f', 'm', 't', ' ', + 16, 0, 0, 0, // size of fmt block - 8: 24 - 8 + 1, 0, // format: PCM (1) + 17, 0, // channels: 17 + 0x39, 0x30, 0, 0, // sample rate: 12345 + 0x92, 0x67, 0x06, 0, // byte rate: 2 * 17 * 12345 + 34, 0, // block align: NumChannels * BytesPerSample + 16, 0, // bits per sample: 2 * 8 + 'd', 'a', 't', 'a', + 0x32, 0xa1, 0xb7, 0x0e, // size of payload: 2 * 123457689 + 0xa4, 0xa4, 0xa4, 0xa4, // untouched bytes after header + // clang-format on + }; + static_assert(sizeof(kExpectedBuf) == kSize, "buffer size"); + EXPECT_EQ(0, memcmp(kExpectedBuf, buf, kSize)); + + size_t num_channels = 0; + int sample_rate = 0; + WavFormat format = WavFormat::kWavFormatPcm; + size_t bytes_per_sample = 0; + size_t num_samples = 0; + int64_t data_start_pos = 0; + WavHeaderBufferReader r(buf + 4, sizeof(buf) - 8, + /*check_read_size=*/true); + EXPECT_TRUE(ReadWavHeader(&r, &num_channels, &sample_rate, &format, + &bytes_per_sample, &num_samples, &data_start_pos)); + EXPECT_EQ(17u, num_channels); + EXPECT_EQ(12345, sample_rate); + EXPECT_EQ(WavFormat::kWavFormatPcm, format); + EXPECT_EQ(2u, bytes_per_sample); + EXPECT_EQ(123457689u, num_samples); +} + +// Try reading an atypical but valid WAV header and make sure it's parsed OK. +TEST(WavHeaderTest, ReadAtypicalWavHeader) { + constexpr uint8_t kBuf[] = { + // clang-format off + // clang formatting doesn't respect inline comments. + 'R', 'I', 'F', 'F', + 0xbf, 0xd0, 0x5b, 0x07, // Size of whole file - 8 + extra 2 bytes of zero + // extension: 123457689 + 44 - 8 + 2 (atypical). + 'W', 'A', 'V', 'E', + 'f', 'm', 't', ' ', + 18, 0, 0, 0, // Size of fmt block (with an atypical extension + // size field). + 1, 0, // Format: PCM (1). + 17, 0, // Channels: 17. + 0x39, 0x30, 0, 0, // Sample rate: 12345. + 0xc9, 0x33, 0x03, 0, // Byte rate: 1 * 17 * 12345. + 17, 0, // Block align: NumChannels * BytesPerSample. + 8, 0, // Bits per sample: 1 * 8. + 0, 0, // Zero extension size field (atypical). + 'd', 'a', 't', 'a', + 0x99, 0xd0, 0x5b, 0x07, // Size of payload: 123457689. + // clang-format on + }; + + size_t num_channels = 0; + int sample_rate = 0; + WavFormat format = WavFormat::kWavFormatPcm; + size_t bytes_per_sample = 0; + size_t num_samples = 0; + int64_t data_start_pos = 0; + WavHeaderBufferReader r(kBuf, sizeof(kBuf), /*check_read_size=*/true); + EXPECT_TRUE(ReadWavHeader(&r, &num_channels, &sample_rate, &format, + &bytes_per_sample, &num_samples, &data_start_pos)); + EXPECT_EQ(17u, num_channels); + EXPECT_EQ(12345, sample_rate); + EXPECT_EQ(WavFormat::kWavFormatPcm, format); + EXPECT_EQ(1u, bytes_per_sample); + EXPECT_EQ(123457689u, num_samples); +} + +// Try reading a valid WAV header which contains an optional chunk and make sure +// it's parsed OK. +TEST(WavHeaderTest, ReadWavHeaderWithOptionalChunk) { + constexpr uint8_t kBuf[] = { + // clang-format off + // clang formatting doesn't respect inline comments. + 'R', 'I', 'F', 'F', + 0xcd, 0xd0, 0x5b, 0x07, // Size of whole file - 8 + an extra 16 bytes of + // "metadata" (8 bytes header, 16 bytes payload): + // 123457689 + 44 - 8 + 16. + 'W', 'A', 'V', 'E', + 'f', 'm', 't', ' ', + 16, 0, 0, 0, // Size of fmt block. + 1, 0, // Format: PCM (1). + 17, 0, // Channels: 17. + 0x39, 0x30, 0, 0, // Sample rate: 12345. + 0xc9, 0x33, 0x03, 0, // Byte rate: 1 * 17 * 12345. + 17, 0, // Block align: NumChannels * BytesPerSample. + 8, 0, // Bits per sample: 1 * 8. + 'L', 'I', 'S', 'T', // Metadata chunk ID. + 16, 0, 0, 0, // Metadata chunk payload size. + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Metadata (16 bytes). + 'd', 'a', 't', 'a', + 0x99, 0xd0, 0x5b, 0x07, // Size of payload: 123457689. + // clang-format on + }; + + size_t num_channels = 0; + int sample_rate = 0; + WavFormat format = WavFormat::kWavFormatPcm; + size_t bytes_per_sample = 0; + size_t num_samples = 0; + int64_t data_start_pos = 0; + WavHeaderBufferReader r(kBuf, sizeof(kBuf), /*check_read_size=*/true); + EXPECT_TRUE(ReadWavHeader(&r, &num_channels, &sample_rate, &format, + &bytes_per_sample, &num_samples, &data_start_pos)); + EXPECT_EQ(17u, num_channels); + EXPECT_EQ(12345, sample_rate); + EXPECT_EQ(WavFormat::kWavFormatPcm, format); + EXPECT_EQ(1u, bytes_per_sample); + EXPECT_EQ(123457689u, num_samples); +} + +// Try reading an invalid WAV header which has the the data chunk before the +// format one and make sure it's not parsed. +TEST(WavHeaderTest, ReadWavHeaderWithDataBeforeFormat) { + constexpr uint8_t kBuf[] = { + // clang-format off + // clang formatting doesn't respect inline comments. + 'R', 'I', 'F', 'F', + 52, 0, 0, 0, // Size of whole file - 8: 16 + 44 - 8. + 'W', 'A', 'V', 'E', + 'd', 'a', 't', 'a', + 16, 0, 0, 0, // Data chunk payload size. + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Data 16 bytes. + 'f', 'm', 't', ' ', + 16, 0, 0, 0, // Size of fmt block. + 1, 0, // Format: Pcm (1). + 1, 0, // Channels: 1. + 60, 0, 0, 0, // Sample rate: 60. + 60, 0, 0, 0, // Byte rate: 1 * 1 * 60. + 1, 0, // Block align: NumChannels * BytesPerSample. + 8, 0, // Bits per sample: 1 * 8. + // clang-format on + }; + + size_t num_channels = 0; + int sample_rate = 0; + WavFormat format = WavFormat::kWavFormatPcm; + size_t bytes_per_sample = 0; + size_t num_samples = 0; + int64_t data_start_pos = 0; + WavHeaderBufferReader r(kBuf, sizeof(kBuf), /*check_read_size=*/false); + EXPECT_FALSE(ReadWavHeader(&r, &num_channels, &sample_rate, &format, + &bytes_per_sample, &num_samples, &data_start_pos)); +} + +} // namespace webrtc |