blob: 8b30530ad95456d96e504351aa057810058a0964 [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
Raphael Kubo da Costa7ce30912018-04-16 11:17:10 +020011#include <string.h>
kwiberg@webrtc.org877083c2014-08-20 07:42:46 +000012#include <limits>
13
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020014#include "common_audio/wav_header.h"
15#include "test/gtest.h"
kwiberg@webrtc.org877083c2014-08-20 07:42:46 +000016
andrew@webrtc.org048c5022014-12-16 20:17:21 +000017namespace webrtc {
18
19// Doesn't take ownership of the buffer.
20class ReadableWavBuffer : public ReadableWav {
21 public:
22 ReadableWavBuffer(const uint8_t* buf, size_t size)
23 : buf_(buf),
24 size_(size),
25 pos_(0),
26 buf_exhausted_(false),
27 check_read_size_(true) {}
28 ReadableWavBuffer(const uint8_t* buf, size_t size, bool check_read_size)
29 : buf_(buf),
30 size_(size),
31 pos_(0),
32 buf_exhausted_(false),
33 check_read_size_(check_read_size) {}
34
35 virtual ~ReadableWavBuffer() {
36 // Verify the entire buffer has been read.
37 if (check_read_size_)
38 EXPECT_EQ(size_, pos_);
39 }
40
41 virtual size_t Read(void* buf, size_t num_bytes) {
42 // Verify we don't try to read outside of a properly sized header.
43 if (size_ >= kWavHeaderSize)
44 EXPECT_GE(size_, pos_ + num_bytes);
45 EXPECT_FALSE(buf_exhausted_);
46
47 const size_t bytes_remaining = size_ - pos_;
48 if (num_bytes > bytes_remaining) {
49 // The caller is signalled about an exhausted buffer when we return fewer
50 // bytes than requested. There should not be another read attempt after
51 // this point.
52 buf_exhausted_ = true;
53 num_bytes = bytes_remaining;
54 }
55 memcpy(buf, &buf_[pos_], num_bytes);
56 pos_ += num_bytes;
57 return num_bytes;
58 }
59
60 private:
61 const uint8_t* buf_;
62 const size_t size_;
63 size_t pos_;
64 bool buf_exhausted_;
65 const bool check_read_size_;
66};
67
kwiberg@webrtc.org877083c2014-08-20 07:42:46 +000068// Try various choices of WAV header parameters, and make sure that the good
69// ones are accepted and the bad ones rejected.
70TEST(WavHeaderTest, CheckWavParameters) {
71 // Try some really stupid values for one parameter at a time.
andrew@webrtc.org048c5022014-12-16 20:17:21 +000072 EXPECT_TRUE(CheckWavParameters(1, 8000, kWavFormatPcm, 1, 0));
73 EXPECT_FALSE(CheckWavParameters(0, 8000, kWavFormatPcm, 1, 0));
pkasting25702cb2016-01-08 13:50:27 -080074 EXPECT_FALSE(CheckWavParameters(0x10000, 8000, kWavFormatPcm, 1, 0));
andrew@webrtc.org048c5022014-12-16 20:17:21 +000075 EXPECT_FALSE(CheckWavParameters(1, 0, kWavFormatPcm, 1, 0));
76 EXPECT_FALSE(CheckWavParameters(1, 8000, WavFormat(0), 1, 0));
77 EXPECT_FALSE(CheckWavParameters(1, 8000, kWavFormatPcm, 0, 0));
kwiberg@webrtc.org877083c2014-08-20 07:42:46 +000078
79 // Try invalid format/bytes-per-sample combinations.
andrew@webrtc.org048c5022014-12-16 20:17:21 +000080 EXPECT_TRUE(CheckWavParameters(1, 8000, kWavFormatPcm, 2, 0));
81 EXPECT_FALSE(CheckWavParameters(1, 8000, kWavFormatPcm, 4, 0));
82 EXPECT_FALSE(CheckWavParameters(1, 8000, kWavFormatALaw, 2, 0));
83 EXPECT_FALSE(CheckWavParameters(1, 8000, kWavFormatMuLaw, 2, 0));
kwiberg@webrtc.org877083c2014-08-20 07:42:46 +000084
85 // Too large values.
andrew@webrtc.org048c5022014-12-16 20:17:21 +000086 EXPECT_FALSE(CheckWavParameters(1 << 20, 1 << 20, kWavFormatPcm, 1, 0));
87 EXPECT_FALSE(CheckWavParameters(
88 1, 8000, kWavFormatPcm, 1, std::numeric_limits<uint32_t>::max()));
kwiberg@webrtc.org877083c2014-08-20 07:42:46 +000089
90 // Not the same number of samples for each channel.
andrew@webrtc.org048c5022014-12-16 20:17:21 +000091 EXPECT_FALSE(CheckWavParameters(3, 8000, kWavFormatPcm, 1, 5));
kwiberg@webrtc.org877083c2014-08-20 07:42:46 +000092}
93
andrew@webrtc.orgf866b2d2014-11-03 18:20:06 +000094TEST(WavHeaderTest, ReadWavHeaderWithErrors) {
Peter Kasting69558702016-01-12 16:26:35 -080095 size_t num_channels = 0;
andrew@webrtc.orga3ed7132014-10-31 21:51:03 +000096 int sample_rate = 0;
andrew@webrtc.org048c5022014-12-16 20:17:21 +000097 WavFormat format = kWavFormatPcm;
pkasting25702cb2016-01-08 13:50:27 -080098 size_t bytes_per_sample = 0;
99 size_t num_samples = 0;
andrew@webrtc.orga3ed7132014-10-31 21:51:03 +0000100
101 // Test a few ways the header can be invalid. We start with the valid header
102 // used in WriteAndReadWavHeader, and invalidate one field per test. The
103 // invalid field is indicated in the array name, and in the comments with
104 // *BAD*.
andrew@webrtc.org048c5022014-12-16 20:17:21 +0000105 {
106 static const uint8_t kBadRiffID[] = {
107 'R', 'i', 'f', 'f', // *BAD*
108 0xbd, 0xd0, 0x5b, 0x07, // size of whole file - 8: 123457689 + 44 - 8
109 'W', 'A', 'V', 'E',
110 'f', 'm', 't', ' ',
111 16, 0, 0, 0, // size of fmt block - 8: 24 - 8
112 6, 0, // format: A-law (6)
113 17, 0, // channels: 17
114 0x39, 0x30, 0, 0, // sample rate: 12345
115 0xc9, 0x33, 0x03, 0, // byte rate: 1 * 17 * 12345
116 17, 0, // block align: NumChannels * BytesPerSample
117 8, 0, // bits per sample: 1 * 8
118 'd', 'a', 't', 'a',
119 0x99, 0xd0, 0x5b, 0x07, // size of payload: 123457689
120 };
121 ReadableWavBuffer r(kBadRiffID, sizeof(kBadRiffID));
122 EXPECT_FALSE(
123 ReadWavHeader(&r, &num_channels, &sample_rate, &format,
124 &bytes_per_sample, &num_samples));
125 }
126 {
127 static const uint8_t kBadBitsPerSample[] = {
128 'R', 'I', 'F', 'F',
129 0xbd, 0xd0, 0x5b, 0x07, // size of whole file - 8: 123457689 + 44 - 8
130 'W', 'A', 'V', 'E',
131 'f', 'm', 't', ' ',
132 16, 0, 0, 0, // size of fmt block - 8: 24 - 8
133 6, 0, // format: A-law (6)
134 17, 0, // channels: 17
135 0x39, 0x30, 0, 0, // sample rate: 12345
136 0xc9, 0x33, 0x03, 0, // byte rate: 1 * 17 * 12345
137 17, 0, // block align: NumChannels * BytesPerSample
138 1, 0, // bits per sample: *BAD*
139 'd', 'a', 't', 'a',
140 0x99, 0xd0, 0x5b, 0x07, // size of payload: 123457689
141 };
142 ReadableWavBuffer r(kBadBitsPerSample, sizeof(kBadBitsPerSample));
143 EXPECT_FALSE(
144 ReadWavHeader(&r, &num_channels, &sample_rate, &format,
145 &bytes_per_sample, &num_samples));
146 }
147 {
148 static const uint8_t kBadByteRate[] = {
149 'R', 'I', 'F', 'F',
150 0xbd, 0xd0, 0x5b, 0x07, // size of whole file - 8: 123457689 + 44 - 8
151 'W', 'A', 'V', 'E',
152 'f', 'm', 't', ' ',
153 16, 0, 0, 0, // size of fmt block - 8: 24 - 8
154 6, 0, // format: A-law (6)
155 17, 0, // channels: 17
156 0x39, 0x30, 0, 0, // sample rate: 12345
157 0x00, 0x33, 0x03, 0, // byte rate: *BAD*
158 17, 0, // block align: NumChannels * BytesPerSample
159 8, 0, // bits per sample: 1 * 8
160 'd', 'a', 't', 'a',
161 0x99, 0xd0, 0x5b, 0x07, // size of payload: 123457689
162 };
163 ReadableWavBuffer r(kBadByteRate, sizeof(kBadByteRate));
164 EXPECT_FALSE(
165 ReadWavHeader(&r, &num_channels, &sample_rate, &format,
166 &bytes_per_sample, &num_samples));
167 }
168 {
169 static const uint8_t kBadFmtHeaderSize[] = {
170 'R', 'I', 'F', 'F',
171 0xbd, 0xd0, 0x5b, 0x07, // size of whole file - 8: 123457689 + 44 - 8
172 'W', 'A', 'V', 'E',
173 'f', 'm', 't', ' ',
174 17, 0, 0, 0, // size of fmt block *BAD*. Only 16 and 18 permitted.
175 6, 0, // format: A-law (6)
176 17, 0, // channels: 17
177 0x39, 0x30, 0, 0, // sample rate: 12345
178 0xc9, 0x33, 0x03, 0, // byte rate: 1 * 17 * 12345
179 17, 0, // block align: NumChannels * BytesPerSample
180 8, 0, // bits per sample: 1 * 8
181 0, // extra (though invalid) header byte
182 'd', 'a', 't', 'a',
183 0x99, 0xd0, 0x5b, 0x07, // size of payload: 123457689
184 };
185 ReadableWavBuffer r(kBadFmtHeaderSize, sizeof(kBadFmtHeaderSize), false);
186 EXPECT_FALSE(
187 ReadWavHeader(&r, &num_channels, &sample_rate, &format,
188 &bytes_per_sample, &num_samples));
189 }
190 {
191 static const uint8_t kNonZeroExtensionField[] = {
192 'R', 'I', 'F', 'F',
193 0xbd, 0xd0, 0x5b, 0x07, // size of whole file - 8: 123457689 + 44 - 8
194 'W', 'A', 'V', 'E',
195 'f', 'm', 't', ' ',
196 18, 0, 0, 0, // size of fmt block - 8: 24 - 8
197 6, 0, // format: A-law (6)
198 17, 0, // channels: 17
199 0x39, 0x30, 0, 0, // sample rate: 12345
200 0xc9, 0x33, 0x03, 0, // byte rate: 1 * 17 * 12345
201 17, 0, // block align: NumChannels * BytesPerSample
202 8, 0, // bits per sample: 1 * 8
203 1, 0, // non-zero extension field *BAD*
204 'd', 'a', 't', 'a',
205 0x99, 0xd0, 0x5b, 0x07, // size of payload: 123457689
206 };
207 ReadableWavBuffer r(kNonZeroExtensionField, sizeof(kNonZeroExtensionField),
208 false);
209 EXPECT_FALSE(
210 ReadWavHeader(&r, &num_channels, &sample_rate, &format,
211 &bytes_per_sample, &num_samples));
212 }
213 {
214 static const uint8_t kMissingDataChunk[] = {
215 'R', 'I', 'F', 'F',
216 0xbd, 0xd0, 0x5b, 0x07, // size of whole file - 8: 123457689 + 44 - 8
217 'W', 'A', 'V', 'E',
218 'f', 'm', 't', ' ',
219 16, 0, 0, 0, // size of fmt block - 8: 24 - 8
220 6, 0, // format: A-law (6)
221 17, 0, // channels: 17
222 0x39, 0x30, 0, 0, // sample rate: 12345
223 0xc9, 0x33, 0x03, 0, // byte rate: 1 * 17 * 12345
224 17, 0, // block align: NumChannels * BytesPerSample
225 8, 0, // bits per sample: 1 * 8
226 };
227 ReadableWavBuffer r(kMissingDataChunk, sizeof(kMissingDataChunk));
228 EXPECT_FALSE(
229 ReadWavHeader(&r, &num_channels, &sample_rate, &format,
230 &bytes_per_sample, &num_samples));
231 }
232 {
233 static const uint8_t kMissingFmtAndDataChunks[] = {
234 'R', 'I', 'F', 'F',
235 0xbd, 0xd0, 0x5b, 0x07, // size of whole file - 8: 123457689 + 44 - 8
236 'W', 'A', 'V', 'E',
237 };
238 ReadableWavBuffer r(kMissingFmtAndDataChunks,
239 sizeof(kMissingFmtAndDataChunks));
240 EXPECT_FALSE(
241 ReadWavHeader(&r, &num_channels, &sample_rate, &format,
242 &bytes_per_sample, &num_samples));
243 }
andrew@webrtc.orga3ed7132014-10-31 21:51:03 +0000244}
245
andrew@webrtc.orgf866b2d2014-11-03 18:20:06 +0000246// Try writing and reading a valid WAV header and make sure it looks OK.
andrew@webrtc.orga3ed7132014-10-31 21:51:03 +0000247TEST(WavHeaderTest, WriteAndReadWavHeader) {
andrew@webrtc.org048c5022014-12-16 20:17:21 +0000248 static const int kSize = 4 + kWavHeaderSize + 4;
kwiberg@webrtc.org877083c2014-08-20 07:42:46 +0000249 uint8_t buf[kSize];
250 memset(buf, 0xa4, sizeof(buf));
andrew@webrtc.org048c5022014-12-16 20:17:21 +0000251 WriteWavHeader(buf + 4, 17, 12345, kWavFormatALaw, 1, 123457689);
kwiberg@webrtc.org877083c2014-08-20 07:42:46 +0000252 static const uint8_t kExpectedBuf[] = {
253 0xa4, 0xa4, 0xa4, 0xa4, // untouched bytes before header
254 'R', 'I', 'F', 'F',
255 0xbd, 0xd0, 0x5b, 0x07, // size of whole file - 8: 123457689 + 44 - 8
256 'W', 'A', 'V', 'E',
257 'f', 'm', 't', ' ',
258 16, 0, 0, 0, // size of fmt block - 8: 24 - 8
259 6, 0, // format: A-law (6)
260 17, 0, // channels: 17
261 0x39, 0x30, 0, 0, // sample rate: 12345
262 0xc9, 0x33, 0x03, 0, // byte rate: 1 * 17 * 12345
263 17, 0, // block align: NumChannels * BytesPerSample
264 8, 0, // bits per sample: 1 * 8
265 'd', 'a', 't', 'a',
266 0x99, 0xd0, 0x5b, 0x07, // size of payload: 123457689
267 0xa4, 0xa4, 0xa4, 0xa4, // untouched bytes after header
268 };
kwiberg@webrtc.org2ebfac52015-01-14 10:51:54 +0000269 static_assert(sizeof(kExpectedBuf) == kSize, "buffer size");
kwiberg@webrtc.org877083c2014-08-20 07:42:46 +0000270 EXPECT_EQ(0, memcmp(kExpectedBuf, buf, kSize));
andrew@webrtc.orga3ed7132014-10-31 21:51:03 +0000271
Peter Kasting69558702016-01-12 16:26:35 -0800272 size_t num_channels = 0;
andrew@webrtc.orga3ed7132014-10-31 21:51:03 +0000273 int sample_rate = 0;
andrew@webrtc.org048c5022014-12-16 20:17:21 +0000274 WavFormat format = kWavFormatPcm;
pkasting25702cb2016-01-08 13:50:27 -0800275 size_t bytes_per_sample = 0;
276 size_t num_samples = 0;
andrew@webrtc.org048c5022014-12-16 20:17:21 +0000277 ReadableWavBuffer r(buf + 4, sizeof(buf) - 8);
andrew@webrtc.orga3ed7132014-10-31 21:51:03 +0000278 EXPECT_TRUE(
andrew@webrtc.org048c5022014-12-16 20:17:21 +0000279 ReadWavHeader(&r, &num_channels, &sample_rate, &format,
280 &bytes_per_sample, &num_samples));
Peter Kasting69558702016-01-12 16:26:35 -0800281 EXPECT_EQ(17u, num_channels);
andrew@webrtc.orga3ed7132014-10-31 21:51:03 +0000282 EXPECT_EQ(12345, sample_rate);
andrew@webrtc.org048c5022014-12-16 20:17:21 +0000283 EXPECT_EQ(kWavFormatALaw, format);
pkasting25702cb2016-01-08 13:50:27 -0800284 EXPECT_EQ(1u, bytes_per_sample);
andrew@webrtc.orga3ed7132014-10-31 21:51:03 +0000285 EXPECT_EQ(123457689u, num_samples);
kwiberg@webrtc.org877083c2014-08-20 07:42:46 +0000286}
andrew@webrtc.org048c5022014-12-16 20:17:21 +0000287
288// Try reading an atypical but valid WAV header and make sure it's parsed OK.
289TEST(WavHeaderTest, ReadAtypicalWavHeader) {
290 static const uint8_t kBuf[] = {
291 'R', 'I', 'F', 'F',
292 0x3d, 0xd1, 0x5b, 0x07, // size of whole file - 8 + an extra 128 bytes of
293 // "metadata": 123457689 + 44 - 8 + 128. (atypical)
294 'W', 'A', 'V', 'E',
295 'f', 'm', 't', ' ',
296 18, 0, 0, 0, // size of fmt block (with an atypical extension size field)
297 6, 0, // format: A-law (6)
298 17, 0, // channels: 17
299 0x39, 0x30, 0, 0, // sample rate: 12345
300 0xc9, 0x33, 0x03, 0, // byte rate: 1 * 17 * 12345
301 17, 0, // block align: NumChannels * BytesPerSample
302 8, 0, // bits per sample: 1 * 8
303 0, 0, // zero extension size field (atypical)
304 'd', 'a', 't', 'a',
305 0x99, 0xd0, 0x5b, 0x07, // size of payload: 123457689
306 };
307
Peter Kasting69558702016-01-12 16:26:35 -0800308 size_t num_channels = 0;
andrew@webrtc.org048c5022014-12-16 20:17:21 +0000309 int sample_rate = 0;
310 WavFormat format = kWavFormatPcm;
pkasting25702cb2016-01-08 13:50:27 -0800311 size_t bytes_per_sample = 0;
312 size_t num_samples = 0;
andrew@webrtc.org048c5022014-12-16 20:17:21 +0000313 ReadableWavBuffer r(kBuf, sizeof(kBuf));
314 EXPECT_TRUE(
315 ReadWavHeader(&r, &num_channels, &sample_rate, &format,
316 &bytes_per_sample, &num_samples));
Peter Kasting69558702016-01-12 16:26:35 -0800317 EXPECT_EQ(17u, num_channels);
andrew@webrtc.org048c5022014-12-16 20:17:21 +0000318 EXPECT_EQ(12345, sample_rate);
319 EXPECT_EQ(kWavFormatALaw, format);
pkasting25702cb2016-01-08 13:50:27 -0800320 EXPECT_EQ(1u, bytes_per_sample);
andrew@webrtc.org048c5022014-12-16 20:17:21 +0000321 EXPECT_EQ(123457689u, num_samples);
322}
323
324} // namespace webrtc