Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2)

Side by Side Diff: media/audio/audio_debug_file_writer.cc

Issue 2891983002: Make AudioDebugFileWriter::AudioFileWriter use a SequencedTaskRunner (Closed)
Patch Set: Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "media/audio/audio_debug_file_writer.h" 5 #include "media/audio/audio_debug_file_writer.h"
6 6
7 #include <stdint.h> 7 #include <stdint.h>
8 #include <array> 8 #include <array>
9 #include <utility> 9 #include <utility>
10 10
11 #include "base/bind.h" 11 #include "base/bind.h"
12 #include "base/logging.h" 12 #include "base/logging.h"
13 #include "base/memory/ptr_util.h" 13 #include "base/memory/ptr_util.h"
14 #include "base/sys_byteorder.h" 14 #include "base/sys_byteorder.h"
15 #include "base/threading/thread_restrictions.h"
15 #include "media/base/audio_bus.h" 16 #include "media/base/audio_bus.h"
16 #include "media/base/audio_sample_types.h" 17 #include "media/base/audio_sample_types.h"
17 18
18 namespace media { 19 namespace media {
19 20
20 namespace { 21 namespace {
21 22
22 // Windows WAVE format header 23 // Windows WAVE format header
23 // Byte order: Little-endian 24 // Byte order: Little-endian
24 // Offset Length Content 25 // Offset Length Content
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after
127 writer.WriteLE32(byte_rate); 128 writer.WriteLE32(byte_rate);
128 writer.WriteLE16(block_align); 129 writer.WriteLE16(block_align);
129 writer.WriteLE16(kBytesPerSample * 8); 130 writer.WriteLE16(kBytesPerSample * 8);
130 writer.Write(kData); 131 writer.Write(kData);
131 writer.WriteLE32(bytes_in_payload); 132 writer.WriteLE32(bytes_in_payload);
132 } 133 }
133 134
134 } // namespace 135 } // namespace
135 136
136 // Manages the debug recording file and writes to it. Can be created on any 137 // Manages the debug recording file and writes to it. Can be created on any
137 // thread. All the operations must be executed on |task_runner_|. Must be 138 // thread. All the operations must be executed on a thread that has IO
138 // destroyed on |task_runner_|. 139 // permissions.
139 class AudioDebugFileWriter::AudioFileWriter { 140 class AudioDebugFileWriter::AudioFileWriter {
140 public: 141 public:
141 static AudioFileWriterUniquePtr Create( 142 static AudioFileWriterUniquePtr Create(
142 const base::FilePath& file_name, 143 const base::FilePath& file_name,
143 const AudioParameters& params, 144 const AudioParameters& params,
144 scoped_refptr<base::SingleThreadTaskRunner> task_runner); 145 scoped_refptr<base::SequencedTaskRunner> task_runner);
145 146
146 ~AudioFileWriter(); 147 ~AudioFileWriter();
147 148
148 // Write data from |data| to file. 149 // Write data from |data| to file.
149 void Write(const AudioBus* data); 150 void Write(const AudioBus* data);
150 151
151 scoped_refptr<base::SingleThreadTaskRunner> task_runner() {
152 return task_runner_;
153 }
154
155 private: 152 private:
156 AudioFileWriter(const AudioParameters& params, 153 AudioFileWriter(const AudioParameters& params);
157 scoped_refptr<base::SingleThreadTaskRunner> task_runner);
158 154
159 // Write wave header to file. Called on the |task_runner_| twice: on 155 // Write wave header to file. Called on the |task_runner_| twice: on
160 // construction 156 // construction
161 // of AudioFileWriter size of the wave data is unknown, so the header is 157 // of AudioFileWriter size of the wave data is unknown, so the header is
162 // written with zero sizes; then on destruction it is re-written with the 158 // written with zero sizes; then on destruction it is re-written with the
163 // actual size info accumulated throughout the object lifetime. 159 // actual size info accumulated throughout the object lifetime.
164 void WriteHeader(); 160 void WriteHeader();
165 161
166 void CreateRecordingFile(const base::FilePath& file_name); 162 void CreateRecordingFile(const base::FilePath& file_name);
167 163
168 // The file to write to. 164 // The file to write to.
169 base::File file_; 165 base::File file_;
170 166
171 // Number of written samples. 167 // Number of written samples.
172 uint64_t samples_; 168 uint64_t samples_;
173 169
174 // Audio parameters required to build wave header. Number of channels and 170 // Audio parameters required to build wave header. Number of channels and
175 // sample rate are used. 171 // sample rate are used.
176 const AudioParameters params_; 172 const AudioParameters params_;
177 173
178 // Intermediate buffer to be written to file. Interleaved 16 bit audio data. 174 // Intermediate buffer to be written to file. Interleaved 16 bit audio data.
179 std::unique_ptr<int16_t[]> interleaved_data_; 175 std::unique_ptr<int16_t[]> interleaved_data_;
180 int interleaved_data_size_; 176 int interleaved_data_size_;
181 177
182 // The task runner this class operates on. 178 SEQUENCE_CHECKER(sequence_checker_);
183 scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
184 }; 179 };
185 180
186 AudioDebugFileWriter::OnThreadDeleter::OnThreadDeleter() {} 181 AudioDebugFileWriter::OnSequenceDeleter::OnSequenceDeleter() {}
187 182
188 AudioDebugFileWriter::OnThreadDeleter::OnThreadDeleter( 183 AudioDebugFileWriter::OnSequenceDeleter::OnSequenceDeleter(
189 const OnThreadDeleter& other) 184 const OnSequenceDeleter& other)
190 : task_runner_(other.task_runner_) {} 185 : task_runner_(other.task_runner_) {}
191 186
192 AudioDebugFileWriter::OnThreadDeleter::OnThreadDeleter( 187 AudioDebugFileWriter::OnSequenceDeleter::OnSequenceDeleter(
193 scoped_refptr<base::SingleThreadTaskRunner> task_runner) 188 scoped_refptr<base::SequencedTaskRunner> task_runner)
194 : task_runner_(task_runner) {} 189 : task_runner_(task_runner) {}
gab 2017/05/18 20:38:17 std::move(task_runner)
Sébastien Marchand 2017/05/18 21:24:25 Done.
195 190
196 AudioDebugFileWriter::OnThreadDeleter::~OnThreadDeleter() {} 191 AudioDebugFileWriter::OnSequenceDeleter::~OnSequenceDeleter() {}
197 192
198 // AudioFileWriter deleter. Inspired by 193 // AudioFileWriter deleter.
199 // content::BrowserThread::DeleteOnFileThread. 194 void AudioDebugFileWriter::OnSequenceDeleter::operator()(
200 void AudioDebugFileWriter::OnThreadDeleter::operator()(
201 AudioDebugFileWriter::AudioFileWriter* ptr) const { 195 AudioDebugFileWriter::AudioFileWriter* ptr) const {
202 if (!task_runner_->DeleteSoon(FROM_HERE, ptr)) { 196 if (!task_runner_->DeleteSoon(FROM_HERE, ptr)) {
203 #if defined(UNIT_TEST) 197 #if defined(UNIT_TEST)
204 // Only logged under unit testing because leaks at shutdown 198 // Only logged under unit testing because leaks at shutdown
205 // are acceptable under normal circumstances. 199 // are acceptable under normal circumstances.
206 LOG(ERROR) << "DeleteSoon failed for AudioDebugFileWriter::AudioFileWriter"; 200 LOG(ERROR) << "DeleteSoon failed for AudioDebugFileWriter::AudioFileWriter";
207 #endif 201 #endif
208 } 202 }
209 } 203 }
210 204
211 // static 205 // static
212 AudioDebugFileWriter::AudioFileWriterUniquePtr 206 AudioDebugFileWriter::AudioFileWriterUniquePtr
213 AudioDebugFileWriter::AudioFileWriter::Create( 207 AudioDebugFileWriter::AudioFileWriter::Create(
214 const base::FilePath& file_name, 208 const base::FilePath& file_name,
215 const AudioParameters& params, 209 const AudioParameters& params,
216 scoped_refptr<base::SingleThreadTaskRunner> task_runner) { 210 scoped_refptr<base::SequencedTaskRunner> task_runner) {
217 AudioFileWriterUniquePtr file_writer(new AudioFileWriter(params, task_runner), 211 AudioFileWriterUniquePtr file_writer(new AudioFileWriter(params),
218 OnThreadDeleter(task_runner)); 212 OnSequenceDeleter(task_runner));
219 213
220 // base::Unretained is safe, because destructor is called on 214 // base::Unretained is safe, because destructor is called on
221 // |task_runner|. 215 // |task_runner|.
222 task_runner->PostTask( 216 task_runner->PostTask(
223 FROM_HERE, 217 FROM_HERE,
224 base::Bind(&AudioFileWriter::CreateRecordingFile, 218 base::Bind(&AudioFileWriter::CreateRecordingFile,
225 base::Unretained(file_writer.get()), file_name)); 219 base::Unretained(file_writer.get()), file_name));
226 return file_writer; 220 return file_writer;
227 } 221 }
228 222
229 AudioDebugFileWriter::AudioFileWriter::AudioFileWriter( 223 AudioDebugFileWriter::AudioFileWriter::AudioFileWriter(
230 const AudioParameters& params, 224 const AudioParameters& params)
231 scoped_refptr<base::SingleThreadTaskRunner> task_runner) 225 : samples_(0), params_(params), interleaved_data_size_(0) {
232 : samples_(0), 226 DETACH_FROM_SEQUENCE(sequence_checker_);
233 params_(params), 227 }
234 interleaved_data_size_(0),
235 task_runner_(std::move(task_runner)) {}
236 228
237 AudioDebugFileWriter::AudioFileWriter::~AudioFileWriter() { 229 AudioDebugFileWriter::AudioFileWriter::~AudioFileWriter() {
238 DCHECK(task_runner_->BelongsToCurrentThread()); 230 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
239 if (file_.IsValid()) 231 if (file_.IsValid())
240 WriteHeader(); 232 WriteHeader();
241 } 233 }
242 234
243 void AudioDebugFileWriter::AudioFileWriter::Write(const AudioBus* data) { 235 void AudioDebugFileWriter::AudioFileWriter::Write(const AudioBus* data) {
244 DCHECK(task_runner_->BelongsToCurrentThread()); 236 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
245 DCHECK_EQ(params_.channels(), data->channels()); 237 DCHECK_EQ(params_.channels(), data->channels());
246 if (!file_.IsValid()) 238 if (!file_.IsValid())
247 return; 239 return;
248 240
249 // Convert to 16 bit audio and write to file. 241 // Convert to 16 bit audio and write to file.
250 int data_size = data->frames() * data->channels(); 242 int data_size = data->frames() * data->channels();
251 if (!interleaved_data_ || interleaved_data_size_ < data_size) { 243 if (!interleaved_data_ || interleaved_data_size_ < data_size) {
252 interleaved_data_.reset(new int16_t[data_size]); 244 interleaved_data_.reset(new int16_t[data_size]);
253 interleaved_data_size_ = data_size; 245 interleaved_data_size_ = data_size;
254 } 246 }
255 samples_ += data_size; 247 samples_ += data_size;
256 data->ToInterleaved<media::SignedInt16SampleTypeTraits>( 248 data->ToInterleaved<media::SignedInt16SampleTypeTraits>(
257 data->frames(), interleaved_data_.get()); 249 data->frames(), interleaved_data_.get());
258 250
259 #ifndef ARCH_CPU_LITTLE_ENDIAN 251 #ifndef ARCH_CPU_LITTLE_ENDIAN
260 static_assert(sizeof(interleaved_data_[0]) == sizeof(uint16_t), 252 static_assert(sizeof(interleaved_data_[0]) == sizeof(uint16_t),
261 "Only 2 bytes per channel is supported."); 253 "Only 2 bytes per channel is supported.");
262 for (int i = 0; i < data_size; ++i) 254 for (int i = 0; i < data_size; ++i)
263 interleaved_data_[i] = base::ByteSwapToLE16(interleaved_data_[i]); 255 interleaved_data_[i] = base::ByteSwapToLE16(interleaved_data_[i]);
264 #endif 256 #endif
265 257
266 file_.WriteAtCurrentPos(reinterpret_cast<char*>(interleaved_data_.get()), 258 file_.WriteAtCurrentPos(reinterpret_cast<char*>(interleaved_data_.get()),
267 data_size * sizeof(interleaved_data_[0])); 259 data_size * sizeof(interleaved_data_[0]));
268 } 260 }
269 261
270 void AudioDebugFileWriter::AudioFileWriter::WriteHeader() { 262 void AudioDebugFileWriter::AudioFileWriter::WriteHeader() {
271 DCHECK(task_runner_->BelongsToCurrentThread()); 263 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
272 if (!file_.IsValid()) 264 if (!file_.IsValid())
273 return; 265 return;
274 WavHeaderBuffer buf; 266 WavHeaderBuffer buf;
275 WriteWavHeader(&buf, params_.channels(), params_.sample_rate(), samples_); 267 WriteWavHeader(&buf, params_.channels(), params_.sample_rate(), samples_);
276 file_.Write(0, &buf[0], kWavHeaderSize); 268 file_.Write(0, &buf[0], kWavHeaderSize);
277 269
278 // Write() does not move the cursor if file is not in APPEND mode; Seek() so 270 // Write() does not move the cursor if file is not in APPEND mode; Seek() so
279 // that the header is not overwritten by the following writes. 271 // that the header is not overwritten by the following writes.
280 file_.Seek(base::File::FROM_BEGIN, kWavHeaderSize); 272 file_.Seek(base::File::FROM_BEGIN, kWavHeaderSize);
281 } 273 }
282 274
283 void AudioDebugFileWriter::AudioFileWriter::CreateRecordingFile( 275 void AudioDebugFileWriter::AudioFileWriter::CreateRecordingFile(
284 const base::FilePath& file_name) { 276 const base::FilePath& file_name) {
285 DCHECK(task_runner_->BelongsToCurrentThread()); 277 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
278 base::ThreadRestrictions::AssertIOAllowed();
286 DCHECK(!file_.IsValid()); 279 DCHECK(!file_.IsValid());
287 280
288 file_ = base::File(file_name, 281 file_ = base::File(file_name,
289 base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE); 282 base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
290 283
291 if (file_.IsValid()) { 284 if (file_.IsValid()) {
292 WriteHeader(); 285 WriteHeader();
293 return; 286 return;
294 } 287 }
295 288
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
348 // here, but it's fine: we can afford missing some data or scheduling some 341 // here, but it's fine: we can afford missing some data or scheduling some
349 // no-op writes. 342 // no-op writes.
350 return !!file_writer_; 343 return !!file_writer_;
351 } 344 }
352 345
353 const base::FilePath::CharType* AudioDebugFileWriter::GetFileNameExtension() { 346 const base::FilePath::CharType* AudioDebugFileWriter::GetFileNameExtension() {
354 return FILE_PATH_LITERAL("wav"); 347 return FILE_PATH_LITERAL("wav");
355 } 348 }
356 349
357 } // namspace media 350 } // namspace media
OLDNEW
« media/audio/audio_debug_file_writer.h ('K') | « media/audio/audio_debug_file_writer.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698