blob: c6f605f7298b0350fcf1c788450ec609dc07c7d4 [file] [log] [blame]
kwiberg@webrtc.org877083c2014-08-20 07:42:46 +00001/*
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
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020013#include "common_audio/wav_header.h"
14#include "test/gtest.h"
kwiberg@webrtc.org877083c2014-08-20 07:42:46 +000015
andrew@webrtc.org048c5022014-12-16 20:17:21 +000016namespace 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
kwiberg@webrtc.org877083c2014-08-20 07:42:46 +000067// 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.
andrew@webrtc.org048c5022014-12-16 20:17:21 +000071 EXPECT_TRUE(CheckWavParameters(1, 8000, kWavFormatPcm, 1, 0));
72 EXPECT_FALSE(CheckWavParameters(0, 8000, kWavFormatPcm, 1, 0));
pkasting25702cb2016-01-08 13:50:27 -080073 EXPECT_FALSE(CheckWavParameters(0x10000, 8000, kWavFormatPcm, 1, 0));
andrew@webrtc.org048c5022014-12-16 20:17:21 +000074 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));
kwiberg@webrtc.org877083c2014-08-20 07:42:46 +000077
78 // Try invalid format/bytes-per-sample combinations.
andrew@webrtc.org048c5022014-12-16 20:17:21 +000079 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));
kwiberg@webrtc.org877083c2014-08-20 07:42:46 +000083
84 // Too large values.
andrew@webrtc.org048c5022014-12-16 20:17:21 +000085 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()));
kwiberg@webrtc.org877083c2014-08-20 07:42:46 +000088
89 // Not the same number of samples for each channel.
andrew@webrtc.org048c5022014-12-16 20:17:21 +000090 EXPECT_FALSE(CheckWavParameters(3, 8000, kWavFormatPcm, 1, 5));
kwiberg@webrtc.org877083c2014-08-20 07:42:46 +000091}
92
andrew@webrtc.orgf866b2d2014-11-03 18:20:06 +000093TEST(WavHeaderTest, ReadWavHeaderWithErrors) {
Peter Kasting69558702016-01-12 16:26:35 -080094 size_t num_channels = 0;
andrew@webrtc.orga3ed7132014-10-31 21:51:03 +000095 int sample_rate = 0;
andrew@webrtc.org048c5022014-12-16 20:17:21 +000096 WavFormat format = kWavFormatPcm;
pkasting25702cb2016-01-08 13:50:27 -080097 size_t bytes_per_sample = 0;
98 size_t num_samples = 0;
andrew@webrtc.orga3ed7132014-10-31 21:51:03 +000099
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*.
andrew@webrtc.org048c5022014-12-16 20:17:21 +0000104 {
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 }
andrew@webrtc.orga3ed7132014-10-31 21:51:03 +0000243}
244
andrew@webrtc.orgf866b2d2014-11-03 18:20:06 +0000245// Try writing and reading a valid WAV header and make sure it looks OK.
andrew@webrtc.orga3ed7132014-10-31 21:51:03 +0000246TEST(WavHeaderTest, WriteAndReadWavHeader) {
andrew@webrtc.org048c5022014-12-16 20:17:21 +0000247 static const int kSize = 4 + kWavHeaderSize + 4;
kwiberg@webrtc.org877083c2014-08-20 07:42:46 +0000248 uint8_t buf[kSize];
249 memset(buf, 0xa4, sizeof(buf));
andrew@webrtc.org048c5022014-12-16 20:17:21 +0000250 WriteWavHeader(buf + 4, 17, 12345, kWavFormatALaw, 1, 123457689);
kwiberg@webrtc.org877083c2014-08-20 07:42:46 +0000251 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 };
kwiberg@webrtc.org2ebfac52015-01-14 10:51:54 +0000268 static_assert(sizeof(kExpectedBuf) == kSize, "buffer size");
kwiberg@webrtc.org877083c2014-08-20 07:42:46 +0000269 EXPECT_EQ(0, memcmp(kExpectedBuf, buf, kSize));
andrew@webrtc.orga3ed7132014-10-31 21:51:03 +0000270
Peter Kasting69558702016-01-12 16:26:35 -0800271 size_t num_channels = 0;
andrew@webrtc.orga3ed7132014-10-31 21:51:03 +0000272 int sample_rate = 0;
andrew@webrtc.org048c5022014-12-16 20:17:21 +0000273 WavFormat format = kWavFormatPcm;
pkasting25702cb2016-01-08 13:50:27 -0800274 size_t bytes_per_sample = 0;
275 size_t num_samples = 0;
andrew@webrtc.org048c5022014-12-16 20:17:21 +0000276 ReadableWavBuffer r(buf + 4, sizeof(buf) - 8);
andrew@webrtc.orga3ed7132014-10-31 21:51:03 +0000277 EXPECT_TRUE(
andrew@webrtc.org048c5022014-12-16 20:17:21 +0000278 ReadWavHeader(&r, &num_channels, &sample_rate, &format,
279 &bytes_per_sample, &num_samples));
Peter Kasting69558702016-01-12 16:26:35 -0800280 EXPECT_EQ(17u, num_channels);
andrew@webrtc.orga3ed7132014-10-31 21:51:03 +0000281 EXPECT_EQ(12345, sample_rate);
andrew@webrtc.org048c5022014-12-16 20:17:21 +0000282 EXPECT_EQ(kWavFormatALaw, format);
pkasting25702cb2016-01-08 13:50:27 -0800283 EXPECT_EQ(1u, bytes_per_sample);
andrew@webrtc.orga3ed7132014-10-31 21:51:03 +0000284 EXPECT_EQ(123457689u, num_samples);
kwiberg@webrtc.org877083c2014-08-20 07:42:46 +0000285}
andrew@webrtc.org048c5022014-12-16 20:17:21 +0000286
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
Peter Kasting69558702016-01-12 16:26:35 -0800307 size_t num_channels = 0;
andrew@webrtc.org048c5022014-12-16 20:17:21 +0000308 int sample_rate = 0;
309 WavFormat format = kWavFormatPcm;
pkasting25702cb2016-01-08 13:50:27 -0800310 size_t bytes_per_sample = 0;
311 size_t num_samples = 0;
andrew@webrtc.org048c5022014-12-16 20:17:21 +0000312 ReadableWavBuffer r(kBuf, sizeof(kBuf));
313 EXPECT_TRUE(
314 ReadWavHeader(&r, &num_channels, &sample_rate, &format,
315 &bytes_per_sample, &num_samples));
Peter Kasting69558702016-01-12 16:26:35 -0800316 EXPECT_EQ(17u, num_channels);
andrew@webrtc.org048c5022014-12-16 20:17:21 +0000317 EXPECT_EQ(12345, sample_rate);
318 EXPECT_EQ(kWavFormatALaw, format);
pkasting25702cb2016-01-08 13:50:27 -0800319 EXPECT_EQ(1u, bytes_per_sample);
andrew@webrtc.org048c5022014-12-16 20:17:21 +0000320 EXPECT_EQ(123457689u, num_samples);
321}
322
323} // namespace webrtc