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// Based on the WAV file format documentation at 12// https://ccrma.stanford.edu/courses/422/projects/WaveFormat/ and 13// http://www-mmsp.ece.mcgill.ca/Documents/AudioFormats/WAVE/WAVE.html 14 15#include "webrtc/common_audio/wav_header.h" 16 17#include <algorithm> 18#include <cstring> 19#include <limits> 20#include <string> 21 22#include "webrtc/base/checks.h" 23#include "webrtc/common_audio/include/audio_util.h" 24 25namespace webrtc { 26namespace { 27 28struct ChunkHeader { 29 uint32_t ID; 30 uint32_t Size; 31}; 32static_assert(sizeof(ChunkHeader) == 8, "ChunkHeader size"); 33 34// We can't nest this definition in WavHeader, because VS2013 gives an error 35// on sizeof(WavHeader::fmt): "error C2070: 'unknown': illegal sizeof operand". 36struct FmtSubchunk { 37 ChunkHeader header; 38 uint16_t AudioFormat; 39 uint16_t NumChannels; 40 uint32_t SampleRate; 41 uint32_t ByteRate; 42 uint16_t BlockAlign; 43 uint16_t BitsPerSample; 44}; 45static_assert(sizeof(FmtSubchunk) == 24, "FmtSubchunk size"); 46const uint32_t kFmtSubchunkSize = sizeof(FmtSubchunk) - sizeof(ChunkHeader); 47 48struct WavHeader { 49 struct { 50 ChunkHeader header; 51 uint32_t Format; 52 } riff; 53 FmtSubchunk fmt; 54 struct { 55 ChunkHeader header; 56 } data; 57}; 58static_assert(sizeof(WavHeader) == kWavHeaderSize, "no padding in header"); 59 60} // namespace 61 62bool CheckWavParameters(size_t num_channels, 63 int sample_rate, 64 WavFormat format, 65 size_t bytes_per_sample, 66 size_t num_samples) { 67 // num_channels, sample_rate, and bytes_per_sample must be positive, must fit 68 // in their respective fields, and their product must fit in the 32-bit 69 // ByteRate field. 70 if (num_channels == 0 || sample_rate <= 0 || bytes_per_sample == 0) 71 return false; 72 if (static_cast<uint64_t>(sample_rate) > std::numeric_limits<uint32_t>::max()) 73 return false; 74 if (num_channels > std::numeric_limits<uint16_t>::max()) 75 return false; 76 if (static_cast<uint64_t>(bytes_per_sample) * 8 > 77 std::numeric_limits<uint16_t>::max()) 78 return false; 79 if (static_cast<uint64_t>(sample_rate) * num_channels * bytes_per_sample > 80 std::numeric_limits<uint32_t>::max()) 81 return false; 82 83 // format and bytes_per_sample must agree. 84 switch (format) { 85 case kWavFormatPcm: 86 // Other values may be OK, but for now we're conservative: 87 if (bytes_per_sample != 1 && bytes_per_sample != 2) 88 return false; 89 break; 90 case kWavFormatALaw: 91 case kWavFormatMuLaw: 92 if (bytes_per_sample != 1) 93 return false; 94 break; 95 default: 96 return false; 97 } 98 99 // The number of bytes in the file, not counting the first ChunkHeader, must 100 // be less than 2^32; otherwise, the ChunkSize field overflows. 101 const size_t header_size = kWavHeaderSize - sizeof(ChunkHeader); 102 const size_t max_samples = 103 (std::numeric_limits<uint32_t>::max() - header_size) / bytes_per_sample; 104 if (num_samples > max_samples) 105 return false; 106 107 // Each channel must have the same number of samples. 108 if (num_samples % num_channels != 0) 109 return false; 110 111 return true; 112} 113 114#ifdef WEBRTC_ARCH_LITTLE_ENDIAN 115static inline void WriteLE16(uint16_t* f, uint16_t x) { *f = x; } 116static inline void WriteLE32(uint32_t* f, uint32_t x) { *f = x; } 117static inline void WriteFourCC(uint32_t* f, char a, char b, char c, char d) { 118 *f = static_cast<uint32_t>(a) 119 | static_cast<uint32_t>(b) << 8 120 | static_cast<uint32_t>(c) << 16 121 | static_cast<uint32_t>(d) << 24; 122} 123 124static inline uint16_t ReadLE16(uint16_t x) { return x; } 125static inline uint32_t ReadLE32(uint32_t x) { return x; } 126static inline std::string ReadFourCC(uint32_t x) { 127 return std::string(reinterpret_cast<char*>(&x), 4); 128} 129#else 130#error "Write be-to-le conversion functions" 131#endif 132 133static inline uint32_t RiffChunkSize(size_t bytes_in_payload) { 134 return static_cast<uint32_t>( 135 bytes_in_payload + kWavHeaderSize - sizeof(ChunkHeader)); 136} 137 138static inline uint32_t ByteRate(size_t num_channels, int sample_rate, 139 size_t bytes_per_sample) { 140 return static_cast<uint32_t>(num_channels * sample_rate * bytes_per_sample); 141} 142 143static inline uint16_t BlockAlign(size_t num_channels, 144 size_t bytes_per_sample) { 145 return static_cast<uint16_t>(num_channels * bytes_per_sample); 146} 147 148void WriteWavHeader(uint8_t* buf, 149 size_t num_channels, 150 int sample_rate, 151 WavFormat format, 152 size_t bytes_per_sample, 153 size_t num_samples) { 154 RTC_CHECK(CheckWavParameters(num_channels, sample_rate, format, 155 bytes_per_sample, num_samples)); 156 157 WavHeader header; 158 const size_t bytes_in_payload = bytes_per_sample * num_samples; 159 160 WriteFourCC(&header.riff.header.ID, 'R', 'I', 'F', 'F'); 161 WriteLE32(&header.riff.header.Size, RiffChunkSize(bytes_in_payload)); 162 WriteFourCC(&header.riff.Format, 'W', 'A', 'V', 'E'); 163 164 WriteFourCC(&header.fmt.header.ID, 'f', 'm', 't', ' '); 165 WriteLE32(&header.fmt.header.Size, kFmtSubchunkSize); 166 WriteLE16(&header.fmt.AudioFormat, format); 167 WriteLE16(&header.fmt.NumChannels, static_cast<uint16_t>(num_channels)); 168 WriteLE32(&header.fmt.SampleRate, sample_rate); 169 WriteLE32(&header.fmt.ByteRate, ByteRate(num_channels, sample_rate, 170 bytes_per_sample)); 171 WriteLE16(&header.fmt.BlockAlign, BlockAlign(num_channels, bytes_per_sample)); 172 WriteLE16(&header.fmt.BitsPerSample, 173 static_cast<uint16_t>(8 * bytes_per_sample)); 174 175 WriteFourCC(&header.data.header.ID, 'd', 'a', 't', 'a'); 176 WriteLE32(&header.data.header.Size, static_cast<uint32_t>(bytes_in_payload)); 177 178 // Do an extra copy rather than writing everything to buf directly, since buf 179 // might not be correctly aligned. 180 memcpy(buf, &header, kWavHeaderSize); 181} 182 183bool ReadWavHeader(ReadableWav* readable, 184 size_t* num_channels, 185 int* sample_rate, 186 WavFormat* format, 187 size_t* bytes_per_sample, 188 size_t* num_samples) { 189 WavHeader header; 190 if (readable->Read(&header, kWavHeaderSize - sizeof(header.data)) != 191 kWavHeaderSize - sizeof(header.data)) 192 return false; 193 194 const uint32_t fmt_size = ReadLE32(header.fmt.header.Size); 195 if (fmt_size != kFmtSubchunkSize) { 196 // There is an optional two-byte extension field permitted to be present 197 // with PCM, but which must be zero. 198 int16_t ext_size; 199 if (kFmtSubchunkSize + sizeof(ext_size) != fmt_size) 200 return false; 201 if (readable->Read(&ext_size, sizeof(ext_size)) != sizeof(ext_size)) 202 return false; 203 if (ext_size != 0) 204 return false; 205 } 206 if (readable->Read(&header.data, sizeof(header.data)) != sizeof(header.data)) 207 return false; 208 209 // Parse needed fields. 210 *format = static_cast<WavFormat>(ReadLE16(header.fmt.AudioFormat)); 211 *num_channels = ReadLE16(header.fmt.NumChannels); 212 *sample_rate = ReadLE32(header.fmt.SampleRate); 213 *bytes_per_sample = ReadLE16(header.fmt.BitsPerSample) / 8; 214 const size_t bytes_in_payload = ReadLE32(header.data.header.Size); 215 if (*bytes_per_sample == 0) 216 return false; 217 *num_samples = bytes_in_payload / *bytes_per_sample; 218 219 // Sanity check remaining fields. 220 if (ReadFourCC(header.riff.header.ID) != "RIFF") 221 return false; 222 if (ReadFourCC(header.riff.Format) != "WAVE") 223 return false; 224 if (ReadFourCC(header.fmt.header.ID) != "fmt ") 225 return false; 226 if (ReadFourCC(header.data.header.ID) != "data") 227 return false; 228 229 if (ReadLE32(header.riff.header.Size) < RiffChunkSize(bytes_in_payload)) 230 return false; 231 if (ReadLE32(header.fmt.ByteRate) != 232 ByteRate(*num_channels, *sample_rate, *bytes_per_sample)) 233 return false; 234 if (ReadLE16(header.fmt.BlockAlign) != 235 BlockAlign(*num_channels, *bytes_per_sample)) 236 return false; 237 238 return CheckWavParameters(*num_channels, *sample_rate, *format, 239 *bytes_per_sample, *num_samples); 240} 241 242 243} // namespace webrtc 244