1/* 2 * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11#include <limits> 12 13#include "testing/gtest/include/gtest/gtest.h" 14#include "webrtc/common_audio/wav_header.h" 15 16namespace webrtc { 17 18// Doesn't take ownership of the buffer. 19class ReadableWavBuffer : public ReadableWav { 20 public: 21 ReadableWavBuffer(const uint8_t* buf, size_t size) 22 : buf_(buf), 23 size_(size), 24 pos_(0), 25 buf_exhausted_(false), 26 check_read_size_(true) {} 27 ReadableWavBuffer(const uint8_t* buf, size_t size, bool check_read_size) 28 : buf_(buf), 29 size_(size), 30 pos_(0), 31 buf_exhausted_(false), 32 check_read_size_(check_read_size) {} 33 34 virtual ~ReadableWavBuffer() { 35 // Verify the entire buffer has been read. 36 if (check_read_size_) 37 EXPECT_EQ(size_, pos_); 38 } 39 40 virtual size_t Read(void* buf, size_t num_bytes) { 41 // Verify we don't try to read outside of a properly sized header. 42 if (size_ >= kWavHeaderSize) 43 EXPECT_GE(size_, pos_ + num_bytes); 44 EXPECT_FALSE(buf_exhausted_); 45 46 const size_t bytes_remaining = size_ - pos_; 47 if (num_bytes > bytes_remaining) { 48 // The caller is signalled about an exhausted buffer when we return fewer 49 // bytes than requested. There should not be another read attempt after 50 // this point. 51 buf_exhausted_ = true; 52 num_bytes = bytes_remaining; 53 } 54 memcpy(buf, &buf_[pos_], num_bytes); 55 pos_ += num_bytes; 56 return num_bytes; 57 } 58 59 private: 60 const uint8_t* buf_; 61 const size_t size_; 62 size_t pos_; 63 bool buf_exhausted_; 64 const bool check_read_size_; 65}; 66 67// Try various choices of WAV header parameters, and make sure that the good 68// ones are accepted and the bad ones rejected. 69TEST(WavHeaderTest, CheckWavParameters) { 70 // Try some really stupid values for one parameter at a time. 71 EXPECT_TRUE(CheckWavParameters(1, 8000, kWavFormatPcm, 1, 0)); 72 EXPECT_FALSE(CheckWavParameters(0, 8000, kWavFormatPcm, 1, 0)); 73 EXPECT_FALSE(CheckWavParameters(0x10000, 8000, kWavFormatPcm, 1, 0)); 74 EXPECT_FALSE(CheckWavParameters(1, 0, kWavFormatPcm, 1, 0)); 75 EXPECT_FALSE(CheckWavParameters(1, 8000, WavFormat(0), 1, 0)); 76 EXPECT_FALSE(CheckWavParameters(1, 8000, kWavFormatPcm, 0, 0)); 77 78 // Try invalid format/bytes-per-sample combinations. 79 EXPECT_TRUE(CheckWavParameters(1, 8000, kWavFormatPcm, 2, 0)); 80 EXPECT_FALSE(CheckWavParameters(1, 8000, kWavFormatPcm, 4, 0)); 81 EXPECT_FALSE(CheckWavParameters(1, 8000, kWavFormatALaw, 2, 0)); 82 EXPECT_FALSE(CheckWavParameters(1, 8000, kWavFormatMuLaw, 2, 0)); 83 84 // Too large values. 85 EXPECT_FALSE(CheckWavParameters(1 << 20, 1 << 20, kWavFormatPcm, 1, 0)); 86 EXPECT_FALSE(CheckWavParameters( 87 1, 8000, kWavFormatPcm, 1, std::numeric_limits<uint32_t>::max())); 88 89 // Not the same number of samples for each channel. 90 EXPECT_FALSE(CheckWavParameters(3, 8000, kWavFormatPcm, 1, 5)); 91} 92 93TEST(WavHeaderTest, ReadWavHeaderWithErrors) { 94 size_t num_channels = 0; 95 int sample_rate = 0; 96 WavFormat format = kWavFormatPcm; 97 size_t bytes_per_sample = 0; 98 size_t num_samples = 0; 99 100 // Test a few ways the header can be invalid. We start with the valid header 101 // used in WriteAndReadWavHeader, and invalidate one field per test. The 102 // invalid field is indicated in the array name, and in the comments with 103 // *BAD*. 104 { 105 static const uint8_t kBadRiffID[] = { 106 'R', 'i', 'f', 'f', // *BAD* 107 0xbd, 0xd0, 0x5b, 0x07, // size of whole file - 8: 123457689 + 44 - 8 108 'W', 'A', 'V', 'E', 109 'f', 'm', 't', ' ', 110 16, 0, 0, 0, // size of fmt block - 8: 24 - 8 111 6, 0, // format: A-law (6) 112 17, 0, // channels: 17 113 0x39, 0x30, 0, 0, // sample rate: 12345 114 0xc9, 0x33, 0x03, 0, // byte rate: 1 * 17 * 12345 115 17, 0, // block align: NumChannels * BytesPerSample 116 8, 0, // bits per sample: 1 * 8 117 'd', 'a', 't', 'a', 118 0x99, 0xd0, 0x5b, 0x07, // size of payload: 123457689 119 }; 120 ReadableWavBuffer r(kBadRiffID, sizeof(kBadRiffID)); 121 EXPECT_FALSE( 122 ReadWavHeader(&r, &num_channels, &sample_rate, &format, 123 &bytes_per_sample, &num_samples)); 124 } 125 { 126 static const uint8_t kBadBitsPerSample[] = { 127 'R', 'I', 'F', 'F', 128 0xbd, 0xd0, 0x5b, 0x07, // size of whole file - 8: 123457689 + 44 - 8 129 'W', 'A', 'V', 'E', 130 'f', 'm', 't', ' ', 131 16, 0, 0, 0, // size of fmt block - 8: 24 - 8 132 6, 0, // format: A-law (6) 133 17, 0, // channels: 17 134 0x39, 0x30, 0, 0, // sample rate: 12345 135 0xc9, 0x33, 0x03, 0, // byte rate: 1 * 17 * 12345 136 17, 0, // block align: NumChannels * BytesPerSample 137 1, 0, // bits per sample: *BAD* 138 'd', 'a', 't', 'a', 139 0x99, 0xd0, 0x5b, 0x07, // size of payload: 123457689 140 }; 141 ReadableWavBuffer r(kBadBitsPerSample, sizeof(kBadBitsPerSample)); 142 EXPECT_FALSE( 143 ReadWavHeader(&r, &num_channels, &sample_rate, &format, 144 &bytes_per_sample, &num_samples)); 145 } 146 { 147 static const uint8_t kBadByteRate[] = { 148 'R', 'I', 'F', 'F', 149 0xbd, 0xd0, 0x5b, 0x07, // size of whole file - 8: 123457689 + 44 - 8 150 'W', 'A', 'V', 'E', 151 'f', 'm', 't', ' ', 152 16, 0, 0, 0, // size of fmt block - 8: 24 - 8 153 6, 0, // format: A-law (6) 154 17, 0, // channels: 17 155 0x39, 0x30, 0, 0, // sample rate: 12345 156 0x00, 0x33, 0x03, 0, // byte rate: *BAD* 157 17, 0, // block align: NumChannels * BytesPerSample 158 8, 0, // bits per sample: 1 * 8 159 'd', 'a', 't', 'a', 160 0x99, 0xd0, 0x5b, 0x07, // size of payload: 123457689 161 }; 162 ReadableWavBuffer r(kBadByteRate, sizeof(kBadByteRate)); 163 EXPECT_FALSE( 164 ReadWavHeader(&r, &num_channels, &sample_rate, &format, 165 &bytes_per_sample, &num_samples)); 166 } 167 { 168 static const uint8_t kBadFmtHeaderSize[] = { 169 'R', 'I', 'F', 'F', 170 0xbd, 0xd0, 0x5b, 0x07, // size of whole file - 8: 123457689 + 44 - 8 171 'W', 'A', 'V', 'E', 172 'f', 'm', 't', ' ', 173 17, 0, 0, 0, // size of fmt block *BAD*. Only 16 and 18 permitted. 174 6, 0, // format: A-law (6) 175 17, 0, // channels: 17 176 0x39, 0x30, 0, 0, // sample rate: 12345 177 0xc9, 0x33, 0x03, 0, // byte rate: 1 * 17 * 12345 178 17, 0, // block align: NumChannels * BytesPerSample 179 8, 0, // bits per sample: 1 * 8 180 0, // extra (though invalid) header byte 181 'd', 'a', 't', 'a', 182 0x99, 0xd0, 0x5b, 0x07, // size of payload: 123457689 183 }; 184 ReadableWavBuffer r(kBadFmtHeaderSize, sizeof(kBadFmtHeaderSize), false); 185 EXPECT_FALSE( 186 ReadWavHeader(&r, &num_channels, &sample_rate, &format, 187 &bytes_per_sample, &num_samples)); 188 } 189 { 190 static const uint8_t kNonZeroExtensionField[] = { 191 'R', 'I', 'F', 'F', 192 0xbd, 0xd0, 0x5b, 0x07, // size of whole file - 8: 123457689 + 44 - 8 193 'W', 'A', 'V', 'E', 194 'f', 'm', 't', ' ', 195 18, 0, 0, 0, // size of fmt block - 8: 24 - 8 196 6, 0, // format: A-law (6) 197 17, 0, // channels: 17 198 0x39, 0x30, 0, 0, // sample rate: 12345 199 0xc9, 0x33, 0x03, 0, // byte rate: 1 * 17 * 12345 200 17, 0, // block align: NumChannels * BytesPerSample 201 8, 0, // bits per sample: 1 * 8 202 1, 0, // non-zero extension field *BAD* 203 'd', 'a', 't', 'a', 204 0x99, 0xd0, 0x5b, 0x07, // size of payload: 123457689 205 }; 206 ReadableWavBuffer r(kNonZeroExtensionField, sizeof(kNonZeroExtensionField), 207 false); 208 EXPECT_FALSE( 209 ReadWavHeader(&r, &num_channels, &sample_rate, &format, 210 &bytes_per_sample, &num_samples)); 211 } 212 { 213 static const uint8_t kMissingDataChunk[] = { 214 'R', 'I', 'F', 'F', 215 0xbd, 0xd0, 0x5b, 0x07, // size of whole file - 8: 123457689 + 44 - 8 216 'W', 'A', 'V', 'E', 217 'f', 'm', 't', ' ', 218 16, 0, 0, 0, // size of fmt block - 8: 24 - 8 219 6, 0, // format: A-law (6) 220 17, 0, // channels: 17 221 0x39, 0x30, 0, 0, // sample rate: 12345 222 0xc9, 0x33, 0x03, 0, // byte rate: 1 * 17 * 12345 223 17, 0, // block align: NumChannels * BytesPerSample 224 8, 0, // bits per sample: 1 * 8 225 }; 226 ReadableWavBuffer r(kMissingDataChunk, sizeof(kMissingDataChunk)); 227 EXPECT_FALSE( 228 ReadWavHeader(&r, &num_channels, &sample_rate, &format, 229 &bytes_per_sample, &num_samples)); 230 } 231 { 232 static const uint8_t kMissingFmtAndDataChunks[] = { 233 'R', 'I', 'F', 'F', 234 0xbd, 0xd0, 0x5b, 0x07, // size of whole file - 8: 123457689 + 44 - 8 235 'W', 'A', 'V', 'E', 236 }; 237 ReadableWavBuffer r(kMissingFmtAndDataChunks, 238 sizeof(kMissingFmtAndDataChunks)); 239 EXPECT_FALSE( 240 ReadWavHeader(&r, &num_channels, &sample_rate, &format, 241 &bytes_per_sample, &num_samples)); 242 } 243} 244 245// Try writing and reading a valid WAV header and make sure it looks OK. 246TEST(WavHeaderTest, WriteAndReadWavHeader) { 247 static const int kSize = 4 + kWavHeaderSize + 4; 248 uint8_t buf[kSize]; 249 memset(buf, 0xa4, sizeof(buf)); 250 WriteWavHeader(buf + 4, 17, 12345, kWavFormatALaw, 1, 123457689); 251 static const uint8_t kExpectedBuf[] = { 252 0xa4, 0xa4, 0xa4, 0xa4, // untouched bytes before header 253 'R', 'I', 'F', 'F', 254 0xbd, 0xd0, 0x5b, 0x07, // size of whole file - 8: 123457689 + 44 - 8 255 'W', 'A', 'V', 'E', 256 'f', 'm', 't', ' ', 257 16, 0, 0, 0, // size of fmt block - 8: 24 - 8 258 6, 0, // format: A-law (6) 259 17, 0, // channels: 17 260 0x39, 0x30, 0, 0, // sample rate: 12345 261 0xc9, 0x33, 0x03, 0, // byte rate: 1 * 17 * 12345 262 17, 0, // block align: NumChannels * BytesPerSample 263 8, 0, // bits per sample: 1 * 8 264 'd', 'a', 't', 'a', 265 0x99, 0xd0, 0x5b, 0x07, // size of payload: 123457689 266 0xa4, 0xa4, 0xa4, 0xa4, // untouched bytes after header 267 }; 268 static_assert(sizeof(kExpectedBuf) == kSize, "buffer size"); 269 EXPECT_EQ(0, memcmp(kExpectedBuf, buf, kSize)); 270 271 size_t num_channels = 0; 272 int sample_rate = 0; 273 WavFormat format = kWavFormatPcm; 274 size_t bytes_per_sample = 0; 275 size_t num_samples = 0; 276 ReadableWavBuffer r(buf + 4, sizeof(buf) - 8); 277 EXPECT_TRUE( 278 ReadWavHeader(&r, &num_channels, &sample_rate, &format, 279 &bytes_per_sample, &num_samples)); 280 EXPECT_EQ(17u, num_channels); 281 EXPECT_EQ(12345, sample_rate); 282 EXPECT_EQ(kWavFormatALaw, format); 283 EXPECT_EQ(1u, bytes_per_sample); 284 EXPECT_EQ(123457689u, num_samples); 285} 286 287// Try reading an atypical but valid WAV header and make sure it's parsed OK. 288TEST(WavHeaderTest, ReadAtypicalWavHeader) { 289 static const uint8_t kBuf[] = { 290 'R', 'I', 'F', 'F', 291 0x3d, 0xd1, 0x5b, 0x07, // size of whole file - 8 + an extra 128 bytes of 292 // "metadata": 123457689 + 44 - 8 + 128. (atypical) 293 'W', 'A', 'V', 'E', 294 'f', 'm', 't', ' ', 295 18, 0, 0, 0, // size of fmt block (with an atypical extension size field) 296 6, 0, // format: A-law (6) 297 17, 0, // channels: 17 298 0x39, 0x30, 0, 0, // sample rate: 12345 299 0xc9, 0x33, 0x03, 0, // byte rate: 1 * 17 * 12345 300 17, 0, // block align: NumChannels * BytesPerSample 301 8, 0, // bits per sample: 1 * 8 302 0, 0, // zero extension size field (atypical) 303 'd', 'a', 't', 'a', 304 0x99, 0xd0, 0x5b, 0x07, // size of payload: 123457689 305 }; 306 307 size_t num_channels = 0; 308 int sample_rate = 0; 309 WavFormat format = kWavFormatPcm; 310 size_t bytes_per_sample = 0; 311 size_t num_samples = 0; 312 ReadableWavBuffer r(kBuf, sizeof(kBuf)); 313 EXPECT_TRUE( 314 ReadWavHeader(&r, &num_channels, &sample_rate, &format, 315 &bytes_per_sample, &num_samples)); 316 EXPECT_EQ(17u, num_channels); 317 EXPECT_EQ(12345, sample_rate); 318 EXPECT_EQ(kWavFormatALaw, format); 319 EXPECT_EQ(1u, bytes_per_sample); 320 EXPECT_EQ(123457689u, num_samples); 321} 322 323} // namespace webrtc 324