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
16 namespace webrtc {
17
18 // Doesn't take ownership of the buffer.
19 class ReadableWavBuffer : public ReadableWav {
20 public:
ReadableWavBuffer(const uint8_t * buf,size_t size)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) {}
ReadableWavBuffer(const uint8_t * buf,size_t size,bool check_read_size)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
~ReadableWavBuffer()34 virtual ~ReadableWavBuffer() {
35 // Verify the entire buffer has been read.
36 if (check_read_size_)
37 EXPECT_EQ(size_, pos_);
38 }
39
Read(void * buf,size_t num_bytes)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.
TEST(WavHeaderTest,CheckWavParameters)69 TEST(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
TEST(WavHeaderTest,ReadWavHeaderWithErrors)93 TEST(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.
TEST(WavHeaderTest,WriteAndReadWavHeader)246 TEST(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.
TEST(WavHeaderTest,ReadAtypicalWavHeader)288 TEST(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