|  | /* | 
|  | *  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 |