xref: /aosp_15_r20/external/webrtc/common_audio/wav_file.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
1*d9f75844SAndroid Build Coastguard Worker /*
2*d9f75844SAndroid Build Coastguard Worker  *  Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
3*d9f75844SAndroid Build Coastguard Worker  *
4*d9f75844SAndroid Build Coastguard Worker  *  Use of this source code is governed by a BSD-style license
5*d9f75844SAndroid Build Coastguard Worker  *  that can be found in the LICENSE file in the root of the source
6*d9f75844SAndroid Build Coastguard Worker  *  tree. An additional intellectual property rights grant can be found
7*d9f75844SAndroid Build Coastguard Worker  *  in the file PATENTS.  All contributing project authors may
8*d9f75844SAndroid Build Coastguard Worker  *  be found in the AUTHORS file in the root of the source tree.
9*d9f75844SAndroid Build Coastguard Worker  */
10*d9f75844SAndroid Build Coastguard Worker 
11*d9f75844SAndroid Build Coastguard Worker #include "common_audio/wav_file.h"
12*d9f75844SAndroid Build Coastguard Worker 
13*d9f75844SAndroid Build Coastguard Worker #include <errno.h>
14*d9f75844SAndroid Build Coastguard Worker 
15*d9f75844SAndroid Build Coastguard Worker #include <algorithm>
16*d9f75844SAndroid Build Coastguard Worker #include <array>
17*d9f75844SAndroid Build Coastguard Worker #include <cstdio>
18*d9f75844SAndroid Build Coastguard Worker #include <type_traits>
19*d9f75844SAndroid Build Coastguard Worker #include <utility>
20*d9f75844SAndroid Build Coastguard Worker 
21*d9f75844SAndroid Build Coastguard Worker #include "common_audio/include/audio_util.h"
22*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/checks.h"
23*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/system/arch.h"
24*d9f75844SAndroid Build Coastguard Worker 
25*d9f75844SAndroid Build Coastguard Worker namespace webrtc {
26*d9f75844SAndroid Build Coastguard Worker namespace {
27*d9f75844SAndroid Build Coastguard Worker 
28*d9f75844SAndroid Build Coastguard Worker static_assert(std::is_trivially_destructible<WavFormat>::value, "");
29*d9f75844SAndroid Build Coastguard Worker 
30*d9f75844SAndroid Build Coastguard Worker // Checks whether the format is supported or not.
FormatSupported(WavFormat format)31*d9f75844SAndroid Build Coastguard Worker bool FormatSupported(WavFormat format) {
32*d9f75844SAndroid Build Coastguard Worker   // Only PCM and IEEE Float formats are supported.
33*d9f75844SAndroid Build Coastguard Worker   return format == WavFormat::kWavFormatPcm ||
34*d9f75844SAndroid Build Coastguard Worker          format == WavFormat::kWavFormatIeeeFloat;
35*d9f75844SAndroid Build Coastguard Worker }
36*d9f75844SAndroid Build Coastguard Worker 
37*d9f75844SAndroid Build Coastguard Worker // Doesn't take ownership of the file handle and won't close it.
38*d9f75844SAndroid Build Coastguard Worker class WavHeaderFileReader : public WavHeaderReader {
39*d9f75844SAndroid Build Coastguard Worker  public:
WavHeaderFileReader(FileWrapper * file)40*d9f75844SAndroid Build Coastguard Worker   explicit WavHeaderFileReader(FileWrapper* file) : file_(file) {}
41*d9f75844SAndroid Build Coastguard Worker 
42*d9f75844SAndroid Build Coastguard Worker   WavHeaderFileReader(const WavHeaderFileReader&) = delete;
43*d9f75844SAndroid Build Coastguard Worker   WavHeaderFileReader& operator=(const WavHeaderFileReader&) = delete;
44*d9f75844SAndroid Build Coastguard Worker 
Read(void * buf,size_t num_bytes)45*d9f75844SAndroid Build Coastguard Worker   size_t Read(void* buf, size_t num_bytes) override {
46*d9f75844SAndroid Build Coastguard Worker     size_t count = file_->Read(buf, num_bytes);
47*d9f75844SAndroid Build Coastguard Worker     pos_ += count;
48*d9f75844SAndroid Build Coastguard Worker     return count;
49*d9f75844SAndroid Build Coastguard Worker   }
SeekForward(uint32_t num_bytes)50*d9f75844SAndroid Build Coastguard Worker   bool SeekForward(uint32_t num_bytes) override {
51*d9f75844SAndroid Build Coastguard Worker     bool success = file_->SeekRelative(num_bytes);
52*d9f75844SAndroid Build Coastguard Worker     if (success) {
53*d9f75844SAndroid Build Coastguard Worker       pos_ += num_bytes;
54*d9f75844SAndroid Build Coastguard Worker     }
55*d9f75844SAndroid Build Coastguard Worker     return success;
56*d9f75844SAndroid Build Coastguard Worker   }
GetPosition()57*d9f75844SAndroid Build Coastguard Worker   int64_t GetPosition() override { return pos_; }
58*d9f75844SAndroid Build Coastguard Worker 
59*d9f75844SAndroid Build Coastguard Worker  private:
60*d9f75844SAndroid Build Coastguard Worker   FileWrapper* file_;
61*d9f75844SAndroid Build Coastguard Worker   int64_t pos_ = 0;
62*d9f75844SAndroid Build Coastguard Worker };
63*d9f75844SAndroid Build Coastguard Worker 
64*d9f75844SAndroid Build Coastguard Worker constexpr size_t kMaxChunksize = 4096;
65*d9f75844SAndroid Build Coastguard Worker 
66*d9f75844SAndroid Build Coastguard Worker }  // namespace
67*d9f75844SAndroid Build Coastguard Worker 
WavReader(absl::string_view filename)68*d9f75844SAndroid Build Coastguard Worker WavReader::WavReader(absl::string_view filename)
69*d9f75844SAndroid Build Coastguard Worker     : WavReader(FileWrapper::OpenReadOnly(filename)) {}
70*d9f75844SAndroid Build Coastguard Worker 
WavReader(FileWrapper file)71*d9f75844SAndroid Build Coastguard Worker WavReader::WavReader(FileWrapper file) : file_(std::move(file)) {
72*d9f75844SAndroid Build Coastguard Worker   RTC_CHECK(file_.is_open())
73*d9f75844SAndroid Build Coastguard Worker       << "Invalid file. Could not create file handle for wav file.";
74*d9f75844SAndroid Build Coastguard Worker 
75*d9f75844SAndroid Build Coastguard Worker   WavHeaderFileReader readable(&file_);
76*d9f75844SAndroid Build Coastguard Worker   size_t bytes_per_sample;
77*d9f75844SAndroid Build Coastguard Worker   RTC_CHECK(ReadWavHeader(&readable, &num_channels_, &sample_rate_, &format_,
78*d9f75844SAndroid Build Coastguard Worker                           &bytes_per_sample, &num_samples_in_file_,
79*d9f75844SAndroid Build Coastguard Worker                           &data_start_pos_));
80*d9f75844SAndroid Build Coastguard Worker   num_unread_samples_ = num_samples_in_file_;
81*d9f75844SAndroid Build Coastguard Worker   RTC_CHECK(FormatSupported(format_)) << "Non-implemented wav-format";
82*d9f75844SAndroid Build Coastguard Worker }
83*d9f75844SAndroid Build Coastguard Worker 
Reset()84*d9f75844SAndroid Build Coastguard Worker void WavReader::Reset() {
85*d9f75844SAndroid Build Coastguard Worker   RTC_CHECK(file_.SeekTo(data_start_pos_))
86*d9f75844SAndroid Build Coastguard Worker       << "Failed to set position in the file to WAV data start position";
87*d9f75844SAndroid Build Coastguard Worker   num_unread_samples_ = num_samples_in_file_;
88*d9f75844SAndroid Build Coastguard Worker }
89*d9f75844SAndroid Build Coastguard Worker 
ReadSamples(const size_t num_samples,int16_t * const samples)90*d9f75844SAndroid Build Coastguard Worker size_t WavReader::ReadSamples(const size_t num_samples,
91*d9f75844SAndroid Build Coastguard Worker                               int16_t* const samples) {
92*d9f75844SAndroid Build Coastguard Worker #ifndef WEBRTC_ARCH_LITTLE_ENDIAN
93*d9f75844SAndroid Build Coastguard Worker #error "Need to convert samples to big-endian when reading from WAV file"
94*d9f75844SAndroid Build Coastguard Worker #endif
95*d9f75844SAndroid Build Coastguard Worker 
96*d9f75844SAndroid Build Coastguard Worker   size_t num_samples_left_to_read = num_samples;
97*d9f75844SAndroid Build Coastguard Worker   size_t next_chunk_start = 0;
98*d9f75844SAndroid Build Coastguard Worker   while (num_samples_left_to_read > 0 && num_unread_samples_ > 0) {
99*d9f75844SAndroid Build Coastguard Worker     const size_t chunk_size = std::min(
100*d9f75844SAndroid Build Coastguard Worker         std::min(kMaxChunksize, num_samples_left_to_read), num_unread_samples_);
101*d9f75844SAndroid Build Coastguard Worker     size_t num_bytes_read;
102*d9f75844SAndroid Build Coastguard Worker     size_t num_samples_read;
103*d9f75844SAndroid Build Coastguard Worker     if (format_ == WavFormat::kWavFormatIeeeFloat) {
104*d9f75844SAndroid Build Coastguard Worker       std::array<float, kMaxChunksize> samples_to_convert;
105*d9f75844SAndroid Build Coastguard Worker       num_bytes_read = file_.Read(samples_to_convert.data(),
106*d9f75844SAndroid Build Coastguard Worker                                   chunk_size * sizeof(samples_to_convert[0]));
107*d9f75844SAndroid Build Coastguard Worker       num_samples_read = num_bytes_read / sizeof(samples_to_convert[0]);
108*d9f75844SAndroid Build Coastguard Worker 
109*d9f75844SAndroid Build Coastguard Worker       for (size_t j = 0; j < num_samples_read; ++j) {
110*d9f75844SAndroid Build Coastguard Worker         samples[next_chunk_start + j] = FloatToS16(samples_to_convert[j]);
111*d9f75844SAndroid Build Coastguard Worker       }
112*d9f75844SAndroid Build Coastguard Worker     } else {
113*d9f75844SAndroid Build Coastguard Worker       RTC_CHECK_EQ(format_, WavFormat::kWavFormatPcm);
114*d9f75844SAndroid Build Coastguard Worker       num_bytes_read = file_.Read(&samples[next_chunk_start],
115*d9f75844SAndroid Build Coastguard Worker                                   chunk_size * sizeof(samples[0]));
116*d9f75844SAndroid Build Coastguard Worker       num_samples_read = num_bytes_read / sizeof(samples[0]);
117*d9f75844SAndroid Build Coastguard Worker     }
118*d9f75844SAndroid Build Coastguard Worker     RTC_CHECK(num_samples_read == 0 || (num_bytes_read % num_samples_read) == 0)
119*d9f75844SAndroid Build Coastguard Worker         << "Corrupt file: file ended in the middle of a sample.";
120*d9f75844SAndroid Build Coastguard Worker     RTC_CHECK(num_samples_read == chunk_size || file_.ReadEof())
121*d9f75844SAndroid Build Coastguard Worker         << "Corrupt file: payload size does not match header.";
122*d9f75844SAndroid Build Coastguard Worker 
123*d9f75844SAndroid Build Coastguard Worker     next_chunk_start += num_samples_read;
124*d9f75844SAndroid Build Coastguard Worker     num_unread_samples_ -= num_samples_read;
125*d9f75844SAndroid Build Coastguard Worker     num_samples_left_to_read -= num_samples_read;
126*d9f75844SAndroid Build Coastguard Worker   }
127*d9f75844SAndroid Build Coastguard Worker 
128*d9f75844SAndroid Build Coastguard Worker   return num_samples - num_samples_left_to_read;
129*d9f75844SAndroid Build Coastguard Worker }
130*d9f75844SAndroid Build Coastguard Worker 
ReadSamples(const size_t num_samples,float * const samples)131*d9f75844SAndroid Build Coastguard Worker size_t WavReader::ReadSamples(const size_t num_samples, float* const samples) {
132*d9f75844SAndroid Build Coastguard Worker #ifndef WEBRTC_ARCH_LITTLE_ENDIAN
133*d9f75844SAndroid Build Coastguard Worker #error "Need to convert samples to big-endian when reading from WAV file"
134*d9f75844SAndroid Build Coastguard Worker #endif
135*d9f75844SAndroid Build Coastguard Worker 
136*d9f75844SAndroid Build Coastguard Worker   size_t num_samples_left_to_read = num_samples;
137*d9f75844SAndroid Build Coastguard Worker   size_t next_chunk_start = 0;
138*d9f75844SAndroid Build Coastguard Worker   while (num_samples_left_to_read > 0 && num_unread_samples_ > 0) {
139*d9f75844SAndroid Build Coastguard Worker     const size_t chunk_size = std::min(
140*d9f75844SAndroid Build Coastguard Worker         std::min(kMaxChunksize, num_samples_left_to_read), num_unread_samples_);
141*d9f75844SAndroid Build Coastguard Worker     size_t num_bytes_read;
142*d9f75844SAndroid Build Coastguard Worker     size_t num_samples_read;
143*d9f75844SAndroid Build Coastguard Worker     if (format_ == WavFormat::kWavFormatPcm) {
144*d9f75844SAndroid Build Coastguard Worker       std::array<int16_t, kMaxChunksize> samples_to_convert;
145*d9f75844SAndroid Build Coastguard Worker       num_bytes_read = file_.Read(samples_to_convert.data(),
146*d9f75844SAndroid Build Coastguard Worker                                   chunk_size * sizeof(samples_to_convert[0]));
147*d9f75844SAndroid Build Coastguard Worker       num_samples_read = num_bytes_read / sizeof(samples_to_convert[0]);
148*d9f75844SAndroid Build Coastguard Worker 
149*d9f75844SAndroid Build Coastguard Worker       for (size_t j = 0; j < num_samples_read; ++j) {
150*d9f75844SAndroid Build Coastguard Worker         samples[next_chunk_start + j] =
151*d9f75844SAndroid Build Coastguard Worker             static_cast<float>(samples_to_convert[j]);
152*d9f75844SAndroid Build Coastguard Worker       }
153*d9f75844SAndroid Build Coastguard Worker     } else {
154*d9f75844SAndroid Build Coastguard Worker       RTC_CHECK_EQ(format_, WavFormat::kWavFormatIeeeFloat);
155*d9f75844SAndroid Build Coastguard Worker       num_bytes_read = file_.Read(&samples[next_chunk_start],
156*d9f75844SAndroid Build Coastguard Worker                                   chunk_size * sizeof(samples[0]));
157*d9f75844SAndroid Build Coastguard Worker       num_samples_read = num_bytes_read / sizeof(samples[0]);
158*d9f75844SAndroid Build Coastguard Worker 
159*d9f75844SAndroid Build Coastguard Worker       for (size_t j = 0; j < num_samples_read; ++j) {
160*d9f75844SAndroid Build Coastguard Worker         samples[next_chunk_start + j] =
161*d9f75844SAndroid Build Coastguard Worker             FloatToFloatS16(samples[next_chunk_start + j]);
162*d9f75844SAndroid Build Coastguard Worker       }
163*d9f75844SAndroid Build Coastguard Worker     }
164*d9f75844SAndroid Build Coastguard Worker     RTC_CHECK(num_samples_read == 0 || (num_bytes_read % num_samples_read) == 0)
165*d9f75844SAndroid Build Coastguard Worker         << "Corrupt file: file ended in the middle of a sample.";
166*d9f75844SAndroid Build Coastguard Worker     RTC_CHECK(num_samples_read == chunk_size || file_.ReadEof())
167*d9f75844SAndroid Build Coastguard Worker         << "Corrupt file: payload size does not match header.";
168*d9f75844SAndroid Build Coastguard Worker 
169*d9f75844SAndroid Build Coastguard Worker     next_chunk_start += num_samples_read;
170*d9f75844SAndroid Build Coastguard Worker     num_unread_samples_ -= num_samples_read;
171*d9f75844SAndroid Build Coastguard Worker     num_samples_left_to_read -= num_samples_read;
172*d9f75844SAndroid Build Coastguard Worker   }
173*d9f75844SAndroid Build Coastguard Worker 
174*d9f75844SAndroid Build Coastguard Worker   return num_samples - num_samples_left_to_read;
175*d9f75844SAndroid Build Coastguard Worker }
176*d9f75844SAndroid Build Coastguard Worker 
Close()177*d9f75844SAndroid Build Coastguard Worker void WavReader::Close() {
178*d9f75844SAndroid Build Coastguard Worker   file_.Close();
179*d9f75844SAndroid Build Coastguard Worker }
180*d9f75844SAndroid Build Coastguard Worker 
WavWriter(absl::string_view filename,int sample_rate,size_t num_channels,SampleFormat sample_format)181*d9f75844SAndroid Build Coastguard Worker WavWriter::WavWriter(absl::string_view filename,
182*d9f75844SAndroid Build Coastguard Worker                      int sample_rate,
183*d9f75844SAndroid Build Coastguard Worker                      size_t num_channels,
184*d9f75844SAndroid Build Coastguard Worker                      SampleFormat sample_format)
185*d9f75844SAndroid Build Coastguard Worker     // Unlike plain fopen, OpenWriteOnly takes care of filename utf8 ->
186*d9f75844SAndroid Build Coastguard Worker     // wchar conversion on windows.
187*d9f75844SAndroid Build Coastguard Worker     : WavWriter(FileWrapper::OpenWriteOnly(filename),
188*d9f75844SAndroid Build Coastguard Worker                 sample_rate,
189*d9f75844SAndroid Build Coastguard Worker                 num_channels,
190*d9f75844SAndroid Build Coastguard Worker                 sample_format) {}
191*d9f75844SAndroid Build Coastguard Worker 
WavWriter(FileWrapper file,int sample_rate,size_t num_channels,SampleFormat sample_format)192*d9f75844SAndroid Build Coastguard Worker WavWriter::WavWriter(FileWrapper file,
193*d9f75844SAndroid Build Coastguard Worker                      int sample_rate,
194*d9f75844SAndroid Build Coastguard Worker                      size_t num_channels,
195*d9f75844SAndroid Build Coastguard Worker                      SampleFormat sample_format)
196*d9f75844SAndroid Build Coastguard Worker     : sample_rate_(sample_rate),
197*d9f75844SAndroid Build Coastguard Worker       num_channels_(num_channels),
198*d9f75844SAndroid Build Coastguard Worker       num_samples_written_(0),
199*d9f75844SAndroid Build Coastguard Worker       format_(sample_format == SampleFormat::kInt16
200*d9f75844SAndroid Build Coastguard Worker                   ? WavFormat::kWavFormatPcm
201*d9f75844SAndroid Build Coastguard Worker                   : WavFormat::kWavFormatIeeeFloat),
202*d9f75844SAndroid Build Coastguard Worker       file_(std::move(file)) {
203*d9f75844SAndroid Build Coastguard Worker   // Handle errors from the OpenWriteOnly call in above constructor.
204*d9f75844SAndroid Build Coastguard Worker   RTC_CHECK(file_.is_open()) << "Invalid file. Could not create wav file.";
205*d9f75844SAndroid Build Coastguard Worker 
206*d9f75844SAndroid Build Coastguard Worker   RTC_CHECK(CheckWavParameters(num_channels_, sample_rate_, format_,
207*d9f75844SAndroid Build Coastguard Worker                                num_samples_written_));
208*d9f75844SAndroid Build Coastguard Worker 
209*d9f75844SAndroid Build Coastguard Worker   // Write a blank placeholder header, since we need to know the total number
210*d9f75844SAndroid Build Coastguard Worker   // of samples before we can fill in the real data.
211*d9f75844SAndroid Build Coastguard Worker   static const uint8_t blank_header[MaxWavHeaderSize()] = {0};
212*d9f75844SAndroid Build Coastguard Worker   RTC_CHECK(file_.Write(blank_header, WavHeaderSize(format_)));
213*d9f75844SAndroid Build Coastguard Worker }
214*d9f75844SAndroid Build Coastguard Worker 
WriteSamples(const int16_t * samples,size_t num_samples)215*d9f75844SAndroid Build Coastguard Worker void WavWriter::WriteSamples(const int16_t* samples, size_t num_samples) {
216*d9f75844SAndroid Build Coastguard Worker #ifndef WEBRTC_ARCH_LITTLE_ENDIAN
217*d9f75844SAndroid Build Coastguard Worker #error "Need to convert samples to little-endian when writing to WAV file"
218*d9f75844SAndroid Build Coastguard Worker #endif
219*d9f75844SAndroid Build Coastguard Worker 
220*d9f75844SAndroid Build Coastguard Worker   for (size_t i = 0; i < num_samples; i += kMaxChunksize) {
221*d9f75844SAndroid Build Coastguard Worker     const size_t num_remaining_samples = num_samples - i;
222*d9f75844SAndroid Build Coastguard Worker     const size_t num_samples_to_write =
223*d9f75844SAndroid Build Coastguard Worker         std::min(kMaxChunksize, num_remaining_samples);
224*d9f75844SAndroid Build Coastguard Worker 
225*d9f75844SAndroid Build Coastguard Worker     if (format_ == WavFormat::kWavFormatPcm) {
226*d9f75844SAndroid Build Coastguard Worker       RTC_CHECK(
227*d9f75844SAndroid Build Coastguard Worker           file_.Write(&samples[i], num_samples_to_write * sizeof(samples[0])));
228*d9f75844SAndroid Build Coastguard Worker     } else {
229*d9f75844SAndroid Build Coastguard Worker       RTC_CHECK_EQ(format_, WavFormat::kWavFormatIeeeFloat);
230*d9f75844SAndroid Build Coastguard Worker       std::array<float, kMaxChunksize> converted_samples;
231*d9f75844SAndroid Build Coastguard Worker       for (size_t j = 0; j < num_samples_to_write; ++j) {
232*d9f75844SAndroid Build Coastguard Worker         converted_samples[j] = S16ToFloat(samples[i + j]);
233*d9f75844SAndroid Build Coastguard Worker       }
234*d9f75844SAndroid Build Coastguard Worker       RTC_CHECK(
235*d9f75844SAndroid Build Coastguard Worker           file_.Write(converted_samples.data(),
236*d9f75844SAndroid Build Coastguard Worker                       num_samples_to_write * sizeof(converted_samples[0])));
237*d9f75844SAndroid Build Coastguard Worker     }
238*d9f75844SAndroid Build Coastguard Worker 
239*d9f75844SAndroid Build Coastguard Worker     num_samples_written_ += num_samples_to_write;
240*d9f75844SAndroid Build Coastguard Worker     RTC_CHECK_GE(num_samples_written_,
241*d9f75844SAndroid Build Coastguard Worker                  num_samples_to_write);  // detect size_t overflow
242*d9f75844SAndroid Build Coastguard Worker   }
243*d9f75844SAndroid Build Coastguard Worker }
244*d9f75844SAndroid Build Coastguard Worker 
WriteSamples(const float * samples,size_t num_samples)245*d9f75844SAndroid Build Coastguard Worker void WavWriter::WriteSamples(const float* samples, size_t num_samples) {
246*d9f75844SAndroid Build Coastguard Worker #ifndef WEBRTC_ARCH_LITTLE_ENDIAN
247*d9f75844SAndroid Build Coastguard Worker #error "Need to convert samples to little-endian when writing to WAV file"
248*d9f75844SAndroid Build Coastguard Worker #endif
249*d9f75844SAndroid Build Coastguard Worker 
250*d9f75844SAndroid Build Coastguard Worker   for (size_t i = 0; i < num_samples; i += kMaxChunksize) {
251*d9f75844SAndroid Build Coastguard Worker     const size_t num_remaining_samples = num_samples - i;
252*d9f75844SAndroid Build Coastguard Worker     const size_t num_samples_to_write =
253*d9f75844SAndroid Build Coastguard Worker         std::min(kMaxChunksize, num_remaining_samples);
254*d9f75844SAndroid Build Coastguard Worker 
255*d9f75844SAndroid Build Coastguard Worker     if (format_ == WavFormat::kWavFormatPcm) {
256*d9f75844SAndroid Build Coastguard Worker       std::array<int16_t, kMaxChunksize> converted_samples;
257*d9f75844SAndroid Build Coastguard Worker       for (size_t j = 0; j < num_samples_to_write; ++j) {
258*d9f75844SAndroid Build Coastguard Worker         converted_samples[j] = FloatS16ToS16(samples[i + j]);
259*d9f75844SAndroid Build Coastguard Worker       }
260*d9f75844SAndroid Build Coastguard Worker       RTC_CHECK(
261*d9f75844SAndroid Build Coastguard Worker           file_.Write(converted_samples.data(),
262*d9f75844SAndroid Build Coastguard Worker                       num_samples_to_write * sizeof(converted_samples[0])));
263*d9f75844SAndroid Build Coastguard Worker     } else {
264*d9f75844SAndroid Build Coastguard Worker       RTC_CHECK_EQ(format_, WavFormat::kWavFormatIeeeFloat);
265*d9f75844SAndroid Build Coastguard Worker       std::array<float, kMaxChunksize> converted_samples;
266*d9f75844SAndroid Build Coastguard Worker       for (size_t j = 0; j < num_samples_to_write; ++j) {
267*d9f75844SAndroid Build Coastguard Worker         converted_samples[j] = FloatS16ToFloat(samples[i + j]);
268*d9f75844SAndroid Build Coastguard Worker       }
269*d9f75844SAndroid Build Coastguard Worker       RTC_CHECK(
270*d9f75844SAndroid Build Coastguard Worker           file_.Write(converted_samples.data(),
271*d9f75844SAndroid Build Coastguard Worker                       num_samples_to_write * sizeof(converted_samples[0])));
272*d9f75844SAndroid Build Coastguard Worker     }
273*d9f75844SAndroid Build Coastguard Worker 
274*d9f75844SAndroid Build Coastguard Worker     num_samples_written_ += num_samples_to_write;
275*d9f75844SAndroid Build Coastguard Worker     RTC_CHECK(num_samples_written_ >=
276*d9f75844SAndroid Build Coastguard Worker               num_samples_to_write);  // detect size_t overflow
277*d9f75844SAndroid Build Coastguard Worker   }
278*d9f75844SAndroid Build Coastguard Worker }
279*d9f75844SAndroid Build Coastguard Worker 
Close()280*d9f75844SAndroid Build Coastguard Worker void WavWriter::Close() {
281*d9f75844SAndroid Build Coastguard Worker   RTC_CHECK(file_.Rewind());
282*d9f75844SAndroid Build Coastguard Worker   std::array<uint8_t, MaxWavHeaderSize()> header;
283*d9f75844SAndroid Build Coastguard Worker   size_t header_size;
284*d9f75844SAndroid Build Coastguard Worker   WriteWavHeader(num_channels_, sample_rate_, format_, num_samples_written_,
285*d9f75844SAndroid Build Coastguard Worker                  header.data(), &header_size);
286*d9f75844SAndroid Build Coastguard Worker   RTC_CHECK(file_.Write(header.data(), header_size));
287*d9f75844SAndroid Build Coastguard Worker   RTC_CHECK(file_.Close());
288*d9f75844SAndroid Build Coastguard Worker }
289*d9f75844SAndroid Build Coastguard Worker 
290*d9f75844SAndroid Build Coastguard Worker }  // namespace webrtc
291