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