blob: 101f3ff389ee2b1aea1b22ea911cab9b9b380526 [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));
Yves Gerey665174f2018-06-19 15:03:05 +020087 EXPECT_FALSE(CheckWavParameters(1, 8000, kWavFormatPcm, 1,
88 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[] = {
Yves Gerey665174f2018-06-19 15:03:05 +0200107 // clang-format off
108 // clang formatting doesn't respect inline comments.
andrew@webrtc.org048c5022014-12-16 20:17:21 +0000109 'R', 'i', 'f', 'f', // *BAD*
110 0xbd, 0xd0, 0x5b, 0x07, // size of whole file - 8: 123457689 + 44 - 8
111 'W', 'A', 'V', 'E',
112 'f', 'm', 't', ' ',
113 16, 0, 0, 0, // size of fmt block - 8: 24 - 8
114 6, 0, // format: A-law (6)
115 17, 0, // channels: 17
116 0x39, 0x30, 0, 0, // sample rate: 12345
117 0xc9, 0x33, 0x03, 0, // byte rate: 1 * 17 * 12345
118 17, 0, // block align: NumChannels * BytesPerSample
119 8, 0, // bits per sample: 1 * 8
120 'd', 'a', 't', 'a',
121 0x99, 0xd0, 0x5b, 0x07, // size of payload: 123457689
Yves Gerey665174f2018-06-19 15:03:05 +0200122 // clang-format on
andrew@webrtc.org048c5022014-12-16 20:17:21 +0000123 };
124 ReadableWavBuffer r(kBadRiffID, sizeof(kBadRiffID));
Yves Gerey665174f2018-06-19 15:03:05 +0200125 EXPECT_FALSE(ReadWavHeader(&r, &num_channels, &sample_rate, &format,
126 &bytes_per_sample, &num_samples));
andrew@webrtc.org048c5022014-12-16 20:17:21 +0000127 }
128 {
129 static const uint8_t kBadBitsPerSample[] = {
Yves Gerey665174f2018-06-19 15:03:05 +0200130 // clang-format off
131 // clang formatting doesn't respect inline comments.
andrew@webrtc.org048c5022014-12-16 20:17:21 +0000132 'R', 'I', 'F', 'F',
133 0xbd, 0xd0, 0x5b, 0x07, // size of whole file - 8: 123457689 + 44 - 8
134 'W', 'A', 'V', 'E',
135 'f', 'm', 't', ' ',
136 16, 0, 0, 0, // size of fmt block - 8: 24 - 8
137 6, 0, // format: A-law (6)
138 17, 0, // channels: 17
139 0x39, 0x30, 0, 0, // sample rate: 12345
140 0xc9, 0x33, 0x03, 0, // byte rate: 1 * 17 * 12345
141 17, 0, // block align: NumChannels * BytesPerSample
142 1, 0, // bits per sample: *BAD*
143 'd', 'a', 't', 'a',
144 0x99, 0xd0, 0x5b, 0x07, // size of payload: 123457689
Yves Gerey665174f2018-06-19 15:03:05 +0200145 // clang-format on
andrew@webrtc.org048c5022014-12-16 20:17:21 +0000146 };
147 ReadableWavBuffer r(kBadBitsPerSample, sizeof(kBadBitsPerSample));
Yves Gerey665174f2018-06-19 15:03:05 +0200148 EXPECT_FALSE(ReadWavHeader(&r, &num_channels, &sample_rate, &format,
149 &bytes_per_sample, &num_samples));
andrew@webrtc.org048c5022014-12-16 20:17:21 +0000150 }
151 {
152 static const uint8_t kBadByteRate[] = {
Yves Gerey665174f2018-06-19 15:03:05 +0200153 // clang-format off
154 // clang formatting doesn't respect inline comments.
andrew@webrtc.org048c5022014-12-16 20:17:21 +0000155 'R', 'I', 'F', 'F',
156 0xbd, 0xd0, 0x5b, 0x07, // size of whole file - 8: 123457689 + 44 - 8
157 'W', 'A', 'V', 'E',
158 'f', 'm', 't', ' ',
159 16, 0, 0, 0, // size of fmt block - 8: 24 - 8
160 6, 0, // format: A-law (6)
161 17, 0, // channels: 17
162 0x39, 0x30, 0, 0, // sample rate: 12345
163 0x00, 0x33, 0x03, 0, // byte rate: *BAD*
164 17, 0, // block align: NumChannels * BytesPerSample
165 8, 0, // bits per sample: 1 * 8
166 'd', 'a', 't', 'a',
167 0x99, 0xd0, 0x5b, 0x07, // size of payload: 123457689
Yves Gerey665174f2018-06-19 15:03:05 +0200168 // clang-format on
andrew@webrtc.org048c5022014-12-16 20:17:21 +0000169 };
170 ReadableWavBuffer r(kBadByteRate, sizeof(kBadByteRate));
Yves Gerey665174f2018-06-19 15:03:05 +0200171 EXPECT_FALSE(ReadWavHeader(&r, &num_channels, &sample_rate, &format,
172 &bytes_per_sample, &num_samples));
andrew@webrtc.org048c5022014-12-16 20:17:21 +0000173 }
174 {
175 static const uint8_t kBadFmtHeaderSize[] = {
Yves Gerey665174f2018-06-19 15:03:05 +0200176 // clang-format off
177 // clang formatting doesn't respect inline comments.
andrew@webrtc.org048c5022014-12-16 20:17:21 +0000178 'R', 'I', 'F', 'F',
179 0xbd, 0xd0, 0x5b, 0x07, // size of whole file - 8: 123457689 + 44 - 8
180 'W', 'A', 'V', 'E',
181 'f', 'm', 't', ' ',
182 17, 0, 0, 0, // size of fmt block *BAD*. Only 16 and 18 permitted.
183 6, 0, // format: A-law (6)
184 17, 0, // channels: 17
185 0x39, 0x30, 0, 0, // sample rate: 12345
186 0xc9, 0x33, 0x03, 0, // byte rate: 1 * 17 * 12345
187 17, 0, // block align: NumChannels * BytesPerSample
188 8, 0, // bits per sample: 1 * 8
189 0, // extra (though invalid) header byte
190 'd', 'a', 't', 'a',
191 0x99, 0xd0, 0x5b, 0x07, // size of payload: 123457689
Yves Gerey665174f2018-06-19 15:03:05 +0200192 // clang-format on
andrew@webrtc.org048c5022014-12-16 20:17:21 +0000193 };
194 ReadableWavBuffer r(kBadFmtHeaderSize, sizeof(kBadFmtHeaderSize), false);
Yves Gerey665174f2018-06-19 15:03:05 +0200195 EXPECT_FALSE(ReadWavHeader(&r, &num_channels, &sample_rate, &format,
196 &bytes_per_sample, &num_samples));
andrew@webrtc.org048c5022014-12-16 20:17:21 +0000197 }
198 {
199 static const uint8_t kNonZeroExtensionField[] = {
Yves Gerey665174f2018-06-19 15:03:05 +0200200 // clang-format off
201 // clang formatting doesn't respect inline comments.
andrew@webrtc.org048c5022014-12-16 20:17:21 +0000202 'R', 'I', 'F', 'F',
203 0xbd, 0xd0, 0x5b, 0x07, // size of whole file - 8: 123457689 + 44 - 8
204 'W', 'A', 'V', 'E',
205 'f', 'm', 't', ' ',
206 18, 0, 0, 0, // size of fmt block - 8: 24 - 8
207 6, 0, // format: A-law (6)
208 17, 0, // channels: 17
209 0x39, 0x30, 0, 0, // sample rate: 12345
210 0xc9, 0x33, 0x03, 0, // byte rate: 1 * 17 * 12345
211 17, 0, // block align: NumChannels * BytesPerSample
212 8, 0, // bits per sample: 1 * 8
213 1, 0, // non-zero extension field *BAD*
214 'd', 'a', 't', 'a',
215 0x99, 0xd0, 0x5b, 0x07, // size of payload: 123457689
Yves Gerey665174f2018-06-19 15:03:05 +0200216 // clang-format on
andrew@webrtc.org048c5022014-12-16 20:17:21 +0000217 };
218 ReadableWavBuffer r(kNonZeroExtensionField, sizeof(kNonZeroExtensionField),
219 false);
Yves Gerey665174f2018-06-19 15:03:05 +0200220 EXPECT_FALSE(ReadWavHeader(&r, &num_channels, &sample_rate, &format,
221 &bytes_per_sample, &num_samples));
andrew@webrtc.org048c5022014-12-16 20:17:21 +0000222 }
223 {
224 static const uint8_t kMissingDataChunk[] = {
Yves Gerey665174f2018-06-19 15:03:05 +0200225 // clang-format off
226 // clang formatting doesn't respect inline comments.
andrew@webrtc.org048c5022014-12-16 20:17:21 +0000227 'R', 'I', 'F', 'F',
228 0xbd, 0xd0, 0x5b, 0x07, // size of whole file - 8: 123457689 + 44 - 8
229 'W', 'A', 'V', 'E',
230 'f', 'm', 't', ' ',
231 16, 0, 0, 0, // size of fmt block - 8: 24 - 8
232 6, 0, // format: A-law (6)
233 17, 0, // channels: 17
234 0x39, 0x30, 0, 0, // sample rate: 12345
235 0xc9, 0x33, 0x03, 0, // byte rate: 1 * 17 * 12345
236 17, 0, // block align: NumChannels * BytesPerSample
237 8, 0, // bits per sample: 1 * 8
Yves Gerey665174f2018-06-19 15:03:05 +0200238 // clang-format on
andrew@webrtc.org048c5022014-12-16 20:17:21 +0000239 };
240 ReadableWavBuffer r(kMissingDataChunk, sizeof(kMissingDataChunk));
Yves Gerey665174f2018-06-19 15:03:05 +0200241 EXPECT_FALSE(ReadWavHeader(&r, &num_channels, &sample_rate, &format,
242 &bytes_per_sample, &num_samples));
andrew@webrtc.org048c5022014-12-16 20:17:21 +0000243 }
244 {
245 static const uint8_t kMissingFmtAndDataChunks[] = {
Yves Gerey665174f2018-06-19 15:03:05 +0200246 // clang-format off
247 // clang formatting doesn't respect inline comments.
andrew@webrtc.org048c5022014-12-16 20:17:21 +0000248 'R', 'I', 'F', 'F',
249 0xbd, 0xd0, 0x5b, 0x07, // size of whole file - 8: 123457689 + 44 - 8
250 'W', 'A', 'V', 'E',
Yves Gerey665174f2018-06-19 15:03:05 +0200251 // clang-format on
andrew@webrtc.org048c5022014-12-16 20:17:21 +0000252 };
253 ReadableWavBuffer r(kMissingFmtAndDataChunks,
254 sizeof(kMissingFmtAndDataChunks));
Yves Gerey665174f2018-06-19 15:03:05 +0200255 EXPECT_FALSE(ReadWavHeader(&r, &num_channels, &sample_rate, &format,
256 &bytes_per_sample, &num_samples));
andrew@webrtc.org048c5022014-12-16 20:17:21 +0000257 }
andrew@webrtc.orga3ed7132014-10-31 21:51:03 +0000258}
259
andrew@webrtc.orgf866b2d2014-11-03 18:20:06 +0000260// Try writing and reading a valid WAV header and make sure it looks OK.
andrew@webrtc.orga3ed7132014-10-31 21:51:03 +0000261TEST(WavHeaderTest, WriteAndReadWavHeader) {
andrew@webrtc.org048c5022014-12-16 20:17:21 +0000262 static const int kSize = 4 + kWavHeaderSize + 4;
kwiberg@webrtc.org877083c2014-08-20 07:42:46 +0000263 uint8_t buf[kSize];
264 memset(buf, 0xa4, sizeof(buf));
andrew@webrtc.org048c5022014-12-16 20:17:21 +0000265 WriteWavHeader(buf + 4, 17, 12345, kWavFormatALaw, 1, 123457689);
kwiberg@webrtc.org877083c2014-08-20 07:42:46 +0000266 static const uint8_t kExpectedBuf[] = {
Yves Gerey665174f2018-06-19 15:03:05 +0200267 // clang-format off
268 // clang formatting doesn't respect inline comments.
kwiberg@webrtc.org877083c2014-08-20 07:42:46 +0000269 0xa4, 0xa4, 0xa4, 0xa4, // untouched bytes before header
270 'R', 'I', 'F', 'F',
271 0xbd, 0xd0, 0x5b, 0x07, // size of whole file - 8: 123457689 + 44 - 8
272 'W', 'A', 'V', 'E',
273 'f', 'm', 't', ' ',
274 16, 0, 0, 0, // size of fmt block - 8: 24 - 8
275 6, 0, // format: A-law (6)
276 17, 0, // channels: 17
277 0x39, 0x30, 0, 0, // sample rate: 12345
278 0xc9, 0x33, 0x03, 0, // byte rate: 1 * 17 * 12345
279 17, 0, // block align: NumChannels * BytesPerSample
280 8, 0, // bits per sample: 1 * 8
281 'd', 'a', 't', 'a',
282 0x99, 0xd0, 0x5b, 0x07, // size of payload: 123457689
283 0xa4, 0xa4, 0xa4, 0xa4, // untouched bytes after header
Yves Gerey665174f2018-06-19 15:03:05 +0200284 // clang-format on
kwiberg@webrtc.org877083c2014-08-20 07:42:46 +0000285 };
kwiberg@webrtc.org2ebfac52015-01-14 10:51:54 +0000286 static_assert(sizeof(kExpectedBuf) == kSize, "buffer size");
kwiberg@webrtc.org877083c2014-08-20 07:42:46 +0000287 EXPECT_EQ(0, memcmp(kExpectedBuf, buf, kSize));
andrew@webrtc.orga3ed7132014-10-31 21:51:03 +0000288
Peter Kasting69558702016-01-12 16:26:35 -0800289 size_t num_channels = 0;
andrew@webrtc.orga3ed7132014-10-31 21:51:03 +0000290 int sample_rate = 0;
andrew@webrtc.org048c5022014-12-16 20:17:21 +0000291 WavFormat format = kWavFormatPcm;
pkasting25702cb2016-01-08 13:50:27 -0800292 size_t bytes_per_sample = 0;
293 size_t num_samples = 0;
andrew@webrtc.org048c5022014-12-16 20:17:21 +0000294 ReadableWavBuffer r(buf + 4, sizeof(buf) - 8);
Yves Gerey665174f2018-06-19 15:03:05 +0200295 EXPECT_TRUE(ReadWavHeader(&r, &num_channels, &sample_rate, &format,
296 &bytes_per_sample, &num_samples));
Peter Kasting69558702016-01-12 16:26:35 -0800297 EXPECT_EQ(17u, num_channels);
andrew@webrtc.orga3ed7132014-10-31 21:51:03 +0000298 EXPECT_EQ(12345, sample_rate);
andrew@webrtc.org048c5022014-12-16 20:17:21 +0000299 EXPECT_EQ(kWavFormatALaw, format);
pkasting25702cb2016-01-08 13:50:27 -0800300 EXPECT_EQ(1u, bytes_per_sample);
andrew@webrtc.orga3ed7132014-10-31 21:51:03 +0000301 EXPECT_EQ(123457689u, num_samples);
kwiberg@webrtc.org877083c2014-08-20 07:42:46 +0000302}
andrew@webrtc.org048c5022014-12-16 20:17:21 +0000303
304// Try reading an atypical but valid WAV header and make sure it's parsed OK.
305TEST(WavHeaderTest, ReadAtypicalWavHeader) {
306 static const uint8_t kBuf[] = {
Yves Gerey665174f2018-06-19 15:03:05 +0200307 // clang-format off
308 // clang formatting doesn't respect inline comments.
andrew@webrtc.org048c5022014-12-16 20:17:21 +0000309 'R', 'I', 'F', 'F',
310 0x3d, 0xd1, 0x5b, 0x07, // size of whole file - 8 + an extra 128 bytes of
311 // "metadata": 123457689 + 44 - 8 + 128. (atypical)
312 'W', 'A', 'V', 'E',
313 'f', 'm', 't', ' ',
314 18, 0, 0, 0, // size of fmt block (with an atypical extension size field)
315 6, 0, // format: A-law (6)
316 17, 0, // channels: 17
317 0x39, 0x30, 0, 0, // sample rate: 12345
318 0xc9, 0x33, 0x03, 0, // byte rate: 1 * 17 * 12345
319 17, 0, // block align: NumChannels * BytesPerSample
320 8, 0, // bits per sample: 1 * 8
321 0, 0, // zero extension size field (atypical)
322 'd', 'a', 't', 'a',
323 0x99, 0xd0, 0x5b, 0x07, // size of payload: 123457689
Yves Gerey665174f2018-06-19 15:03:05 +0200324 // clang-format on
andrew@webrtc.org048c5022014-12-16 20:17:21 +0000325 };
326
Peter Kasting69558702016-01-12 16:26:35 -0800327 size_t num_channels = 0;
andrew@webrtc.org048c5022014-12-16 20:17:21 +0000328 int sample_rate = 0;
329 WavFormat format = kWavFormatPcm;
pkasting25702cb2016-01-08 13:50:27 -0800330 size_t bytes_per_sample = 0;
331 size_t num_samples = 0;
andrew@webrtc.org048c5022014-12-16 20:17:21 +0000332 ReadableWavBuffer r(kBuf, sizeof(kBuf));
Yves Gerey665174f2018-06-19 15:03:05 +0200333 EXPECT_TRUE(ReadWavHeader(&r, &num_channels, &sample_rate, &format,
334 &bytes_per_sample, &num_samples));
Peter Kasting69558702016-01-12 16:26:35 -0800335 EXPECT_EQ(17u, num_channels);
andrew@webrtc.org048c5022014-12-16 20:17:21 +0000336 EXPECT_EQ(12345, sample_rate);
337 EXPECT_EQ(kWavFormatALaw, format);
pkasting25702cb2016-01-08 13:50:27 -0800338 EXPECT_EQ(1u, bytes_per_sample);
andrew@webrtc.org048c5022014-12-16 20:17:21 +0000339 EXPECT_EQ(123457689u, num_samples);
340}
341
342} // namespace webrtc