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

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

Issue 922663002: Moved the fake input stream's processing onto the audio worker thread. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 10 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 (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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/fake_audio_input_stream.h" 5 #include "media/audio/fake_audio_input_stream.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/bind_helpers.h"
8 #include "base/command_line.h" 9 #include "base/command_line.h"
9 #include "base/files/file.h" 10 #include "base/files/file.h"
11 #include "base/files/file_path.h"
10 #include "base/lazy_instance.h" 12 #include "base/lazy_instance.h"
13 #include "base/location.h"
14 #include "base/single_thread_task_runner.h"
15 #include "base/time/time.h"
11 #include "media/audio/audio_manager_base.h" 16 #include "media/audio/audio_manager_base.h"
17 #include "media/audio/sounds/wav_audio_handler.h"
12 #include "media/base/audio_bus.h" 18 #include "media/base/audio_bus.h"
19 #include "media/base/audio_converter.h"
13 #include "media/base/media_switches.h" 20 #include "media/base/media_switches.h"
14 21
15 using base::TimeTicks;
16 using base::TimeDelta;
17
18 namespace media { 22 namespace media {
19 23
20 namespace { 24 namespace {
21 25
22 // These values are based on experiments for local-to-local 26 // These values are based on experiments for local-to-local
23 // PeerConnection to demonstrate audio/video synchronization. 27 // PeerConnection to demonstrate audio/video synchronization.
24 const int kBeepDurationMilliseconds = 20; 28 const int kBeepDurationMilliseconds = 20;
25 const int kBeepFrequency = 400; 29 const int kBeepFrequency = 400;
26 30
27 // Intervals between two automatic beeps. 31 // Intervals between two automatic beeps.
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
95 scoped_ptr<media::WavAudioHandler> wav_audio_handler( 99 scoped_ptr<media::WavAudioHandler> wav_audio_handler(
96 new media::WavAudioHandler(wav_data)); 100 new media::WavAudioHandler(wav_data));
97 return wav_audio_handler.Pass(); 101 return wav_audio_handler.Pass();
98 } 102 }
99 103
100 static base::LazyInstance<BeepContext> g_beep_context = 104 static base::LazyInstance<BeepContext> g_beep_context =
101 LAZY_INSTANCE_INITIALIZER; 105 LAZY_INSTANCE_INITIALIZER;
102 106
103 } // namespace 107 } // namespace
104 108
105 AudioInputStream* FakeAudioInputStream::MakeFakeStream( 109 class FakeAudioInputStream::FileSource : public AudioConverter::InputCallback,
phoglund_chromium 2015/02/18 16:38:15 It felt wrong to toss back all the state into the
DaleCurtis 2015/02/18 19:04:49 Good idea. Take a look at media/audio/simple_sourc
phoglund_chromium 2015/02/19 15:44:10 Sure, done.
106 AudioManagerBase* manager, 110 public FakeAudioInputStream::Source {
107 const AudioParameters& params) { 111 public:
108 return new FakeAudioInputStream(manager, params); 112 FileSource(const AudioParameters& params);
113 ~FileSource() override {}
114
115 void Open(const base::FilePath& path_to_wav_file);
116 void PlayInto(AudioBus* audio_bus, int* buffer_size) override;
117
118 private:
119 AudioParameters params_;
120 scoped_ptr<uint8[]> wav_file_data_;
121 scoped_ptr<media::WavAudioHandler> wav_audio_handler_;
122 scoped_ptr<media::AudioConverter> file_audio_converter_;
123 int wav_file_read_pos_;
124 int buffer_size_;
125
126 // Provides audio data from wav_audio_handler_ into the file audio converter.
127 double ProvideInput(AudioBus* audio_bus,
128 base::TimeDelta buffer_delay) override;
129 };
130
131 FakeAudioInputStream::FileSource::FileSource(const AudioParameters& params)
132 : params_(params),
133 wav_file_read_pos_(0),
134 buffer_size_(params.channels() * params.bits_per_sample() *
135 params.frames_per_buffer() / 8) {
109 } 136 }
110 137
111 FakeAudioInputStream::FakeAudioInputStream(AudioManagerBase* manager, 138 void FakeAudioInputStream::FileSource::Open(
112 const AudioParameters& params) 139 const base::FilePath& wav_filename) {
113 : audio_manager_(manager),
114 callback_(NULL),
115 buffer_size_((params.channels() * params.bits_per_sample() *
116 params.frames_per_buffer()) /
117 8),
118 params_(params),
119 task_runner_(manager->GetTaskRunner()),
120 callback_interval_(base::TimeDelta::FromMilliseconds(
121 (params.frames_per_buffer() * 1000) / params.sample_rate())),
122 beep_duration_in_buffers_(kBeepDurationMilliseconds *
123 params.sample_rate() /
124 params.frames_per_buffer() /
125 1000),
126 beep_generated_in_buffers_(0),
127 beep_period_in_frames_(params.sample_rate() / kBeepFrequency),
128 audio_bus_(AudioBus::Create(params)),
129 wav_file_read_pos_(0),
130 weak_factory_(this) {
131 DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread());
132 }
133
134 FakeAudioInputStream::~FakeAudioInputStream() {}
135
136 bool FakeAudioInputStream::Open() {
137 DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread());
138 buffer_.reset(new uint8[buffer_size_]);
139 memset(buffer_.get(), 0, buffer_size_);
140 audio_bus_->Zero();
141
142 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
143 switches::kUseFileForFakeAudioCapture)) {
144 OpenInFileMode(base::CommandLine::ForCurrentProcess()->GetSwitchValuePath(
145 switches::kUseFileForFakeAudioCapture));
146 }
147
148 return true;
149 }
150
151 void FakeAudioInputStream::Start(AudioInputCallback* callback) {
152 DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread());
153 DCHECK(!callback_);
154 callback_ = callback;
155 last_callback_time_ = TimeTicks::Now();
156
157 task_runner_->PostDelayedTask(
158 FROM_HERE,
159 base::Bind(&FakeAudioInputStream::DoCallback, weak_factory_.GetWeakPtr()),
160 callback_interval_);
161 }
162
163 void FakeAudioInputStream::DoCallback() {
164 DCHECK(callback_);
165
166 const TimeTicks now = TimeTicks::Now();
167 base::TimeDelta next_callback_time =
168 last_callback_time_ + callback_interval_ * 2 - now;
169
170 // If we are falling behind, try to catch up as much as we can in the next
171 // callback.
172 if (next_callback_time < base::TimeDelta())
173 next_callback_time = base::TimeDelta();
174
175 if (PlayingFromFile()) {
176 PlayFile();
177 } else {
178 PlayBeep();
179 }
180
181 last_callback_time_ = now;
182
183 task_runner_->PostDelayedTask(
184 FROM_HERE,
185 base::Bind(&FakeAudioInputStream::DoCallback, weak_factory_.GetWeakPtr()),
186 next_callback_time);
187 }
188
189 void FakeAudioInputStream::OpenInFileMode(const base::FilePath& wav_filename) {
190 CHECK(!wav_filename.empty())
191 << "You must pass the file to use as argument to --"
192 << switches::kUseFileForFakeAudioCapture << ".";
193
194 // Read the file, and put its data in a scoped_ptr so it gets deleted later. 140 // Read the file, and put its data in a scoped_ptr so it gets deleted later.
195 size_t file_length = 0; 141 size_t file_length = 0;
196 wav_file_data_ = ReadWavFile(wav_filename, &file_length); 142 wav_file_data_ = ReadWavFile(wav_filename, &file_length);
197 wav_audio_handler_ = CreateWavAudioHandler( 143 wav_audio_handler_ = CreateWavAudioHandler(
198 wav_filename, wav_file_data_.get(), file_length, params_); 144 wav_filename, wav_file_data_.get(), file_length, params_);
199 145
200 // Hook us up so we pull in data from the file into the converter. We need to 146 // Hook us up so we pull in data from the file into the converter. We need to
201 // modify the wav file's audio parameters since we'll be reading small slices 147 // modify the wav file's audio parameters since we'll be reading small slices
202 // of it at a time and not the whole thing (like 10 ms at a time). 148 // of it at a time and not the whole thing (like 10 ms at a time).
203 AudioParameters file_audio_slice( 149 AudioParameters file_audio_slice(
204 wav_audio_handler_->params().format(), 150 wav_audio_handler_->params().format(),
205 wav_audio_handler_->params().channel_layout(), 151 wav_audio_handler_->params().channel_layout(),
206 wav_audio_handler_->params().sample_rate(), 152 wav_audio_handler_->params().sample_rate(),
207 wav_audio_handler_->params().bits_per_sample(), 153 wav_audio_handler_->params().bits_per_sample(),
208 params_.frames_per_buffer()); 154 params_.frames_per_buffer());
209 155
210 file_audio_converter_.reset( 156 file_audio_converter_.reset(
211 new AudioConverter(file_audio_slice, params_, false)); 157 new AudioConverter(file_audio_slice, params_, false));
212 file_audio_converter_->AddInput(this); 158 file_audio_converter_->AddInput(this);
213 } 159 }
214 160
215 bool FakeAudioInputStream::PlayingFromFile() { 161 void FakeAudioInputStream::FileSource::PlayInto(AudioBus* audio_bus,
216 return wav_audio_handler_.get() != nullptr; 162 int* buffer_size) {
217 } 163 DCHECK(wav_audio_handler_.get() != nullptr);
218 164
219 void FakeAudioInputStream::PlayFile() {
220 // Stop playing if we've played out the whole file. 165 // Stop playing if we've played out the whole file.
221 if (wav_audio_handler_->AtEnd(wav_file_read_pos_)) 166 if (wav_audio_handler_->AtEnd(wav_file_read_pos_))
222 return; 167 return;
223 168
224 file_audio_converter_->Convert(audio_bus_.get()); 169 // This pulls data from ProvideInput.
225 callback_->OnData(this, audio_bus_.get(), buffer_size_, 1.0); 170 file_audio_converter_->Convert(audio_bus);
171 *buffer_size = buffer_size_;
226 } 172 }
227 173
228 void FakeAudioInputStream::PlayBeep() { 174 double FakeAudioInputStream::FileSource::ProvideInput(
175 AudioBus* audio_bus_into_converter,
176 base::TimeDelta buffer_delay) {
177 // Unfilled frames will be zeroed by CopyTo.
178 size_t bytes_written;
179 wav_audio_handler_->CopyTo(audio_bus_into_converter, wav_file_read_pos_,
180 &bytes_written);
181 wav_file_read_pos_ += bytes_written;
182 return 1.0;
183 };
184
185 class FakeAudioInputStream::BeepingSource
186 : public FakeAudioInputStream::Source {
187 public:
188 BeepingSource(const AudioParameters& params);
189 ~BeepingSource() override {}
190
191 void PlayInto(AudioBus* audio_bus, int* buffer_size) override;
192 private:
193 scoped_ptr<uint8[]> buffer_;
194 int buffer_size_;
195 AudioParameters params_;
196 base::TimeTicks last_callback_time_;
197 base::TimeDelta interval_from_last_beep_;
198 int beep_duration_in_buffers_;
199 int beep_generated_in_buffers_;
200 int beep_period_in_frames_;
201 };
202
203 FakeAudioInputStream::BeepingSource::BeepingSource(
204 const AudioParameters& params)
205 : buffer_size_(params.channels() * params.bits_per_sample() *
206 params.frames_per_buffer() / 8),
207 params_(params),
208 beep_duration_in_buffers_(kBeepDurationMilliseconds *
209 params.sample_rate() /
210 params.frames_per_buffer() /
211 1000),
212 beep_generated_in_buffers_(0),
213 beep_period_in_frames_(params.sample_rate() / kBeepFrequency) {
214 buffer_.reset(new uint8[buffer_size_]);
215 memset(buffer_.get(), 0, buffer_size_);
216 }
217
218 void FakeAudioInputStream::BeepingSource::PlayInto(AudioBus* audio_bus,
219 int* buffer_size) {
229 // Accumulate the time from the last beep. 220 // Accumulate the time from the last beep.
230 interval_from_last_beep_ += TimeTicks::Now() - last_callback_time_; 221 interval_from_last_beep_ += base::TimeTicks::Now() - last_callback_time_;
222 last_callback_time_ = base::TimeTicks::Now();
231 223
232 memset(buffer_.get(), 0, buffer_size_); 224 memset(buffer_.get(), 0, buffer_size_);
233 bool should_beep = false; 225 bool should_beep = false;
234 { 226 {
235 BeepContext* beep_context = g_beep_context.Pointer(); 227 BeepContext* beep_context = g_beep_context.Pointer();
236 if (beep_context->automatic_beep()) { 228 if (beep_context->automatic_beep()) {
237 base::TimeDelta delta = interval_from_last_beep_ - 229 base::TimeDelta delta = interval_from_last_beep_ -
238 TimeDelta::FromMilliseconds(kAutomaticBeepIntervalInMs); 230 base::TimeDelta::FromMilliseconds(kAutomaticBeepIntervalInMs);
239 if (delta > base::TimeDelta()) { 231 if (delta > base::TimeDelta()) {
240 should_beep = true; 232 should_beep = true;
241 interval_from_last_beep_ = delta; 233 interval_from_last_beep_ = delta;
242 } 234 }
243 } else { 235 } else {
244 should_beep = beep_context->beep_once(); 236 should_beep = beep_context->beep_once();
245 beep_context->SetBeepOnce(false); 237 beep_context->SetBeepOnce(false);
246 } 238 }
247 } 239 }
248 240
(...skipping 14 matching lines...) Expand all
263 memset(buffer_.get() + position, 128, high_bytes); 255 memset(buffer_.get() + position, 128, high_bytes);
264 // Then leave low values in the buffer with |high_bytes|. 256 // Then leave low values in the buffer with |high_bytes|.
265 position += high_bytes * 2; 257 position += high_bytes * 2;
266 } 258 }
267 259
268 ++beep_generated_in_buffers_; 260 ++beep_generated_in_buffers_;
269 if (beep_generated_in_buffers_ >= beep_duration_in_buffers_) 261 if (beep_generated_in_buffers_ >= beep_duration_in_buffers_)
270 beep_generated_in_buffers_ = 0; 262 beep_generated_in_buffers_ = 0;
271 } 263 }
272 264
273 audio_bus_->FromInterleaved( 265 *buffer_size = buffer_size_;
phoglund_chromium 2015/02/18 16:38:15 Not sure about this: I do feel the sources know be
DaleCurtis 2015/02/18 19:04:49 I don't think you need this, it seems like an inco
phoglund_chromium 2015/02/19 15:44:11 Just passing 0 seems to work so I'll go with that.
274 buffer_.get(), audio_bus_->frames(), params_.bits_per_sample() / 8); 266 audio_bus->FromInterleaved(
275 callback_->OnData(this, audio_bus_.get(), buffer_size_, 1.0); 267 buffer_.get(), audio_bus->frames(), params_.bits_per_sample() / 8);
268 }
269
270 AudioInputStream* FakeAudioInputStream::MakeFakeStream(
271 AudioManagerBase* manager,
272 const AudioParameters& params) {
273 return new FakeAudioInputStream(manager, params);
274 }
275
276 FakeAudioInputStream::FakeAudioInputStream(AudioManagerBase* manager,
277 const AudioParameters& params)
278 : audio_manager_(manager),
279 callback_(NULL),
280 fake_audio_worker_(manager->GetWorkerTaskRunner(), params),
281 params_(params),
282 audio_bus_(AudioBus::Create(params)) {
283 DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread());
284 }
285
286 FakeAudioInputStream::~FakeAudioInputStream() {
287 DCHECK(!callback_);
288 }
289
290 bool FakeAudioInputStream::Open() {
291 DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread());
292 audio_bus_->Zero();
293
294 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
295 switches::kUseFileForFakeAudioCapture)) {
296 base::FilePath path_to_wav_file =
297 base::CommandLine::ForCurrentProcess()->GetSwitchValuePath(
298 switches::kUseFileForFakeAudioCapture);
299 CHECK(!path_to_wav_file.empty())
300 << "You must pass the file to use as argument to --"
301 << switches::kUseFileForFakeAudioCapture << ".";
302
303 FileSource* file_source = new FileSource(params_);
304 audio_source_.reset(file_source);
305 audio_manager_->GetWorkerTaskRunner()->PostTask(
phoglund_chromium 2015/02/18 16:38:15 This is the file loading I talked about earlier. A
DaleCurtis 2015/02/18 19:04:49 I think loading the file source on the first callb
phoglund_chromium 2015/02/19 15:44:11 Done.
306 FROM_HERE,
307 base::Bind(&FileSource::Open,
308 base::Unretained(file_source),
309 path_to_wav_file));
310 } else {
311 audio_source_.reset(new BeepingSource(params_));
312 }
313 return true;
314 }
315
316 void FakeAudioInputStream::Start(AudioInputCallback* callback) {
317 DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread());
318 callback_ = callback;
319 fake_audio_worker_.Start(base::Bind(
320 &FakeAudioInputStream::ReadAudioFromSource, base::Unretained(this)));
276 } 321 }
277 322
278 void FakeAudioInputStream::Stop() { 323 void FakeAudioInputStream::Stop() {
279 DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread()); 324 DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread());
280 weak_factory_.InvalidateWeakPtrs(); 325 fake_audio_worker_.Stop();
281 callback_ = NULL; 326 callback_ = NULL;
282 } 327 }
283 328
284 void FakeAudioInputStream::Close() { 329 void FakeAudioInputStream::Close() {
285 DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread()); 330 DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread());
331 DCHECK(!callback_);
286 audio_manager_->ReleaseInputStream(this); 332 audio_manager_->ReleaseInputStream(this);
287 } 333 }
288 334
289 double FakeAudioInputStream::GetMaxVolume() { 335 double FakeAudioInputStream::GetMaxVolume() {
290 DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread()); 336 DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread());
291 return 1.0; 337 return 1.0;
292 } 338 }
293 339
294 void FakeAudioInputStream::SetVolume(double volume) { 340 void FakeAudioInputStream::SetVolume(double volume) {
295 DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread()); 341 DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread());
(...skipping 10 matching lines...) Expand all
306 } 352 }
307 353
308 bool FakeAudioInputStream::SetAutomaticGainControl(bool enabled) { 354 bool FakeAudioInputStream::SetAutomaticGainControl(bool enabled) {
309 return false; 355 return false;
310 } 356 }
311 357
312 bool FakeAudioInputStream::GetAutomaticGainControl() { 358 bool FakeAudioInputStream::GetAutomaticGainControl() {
313 return false; 359 return false;
314 } 360 }
315 361
316 // static 362 void FakeAudioInputStream::ReadAudioFromSource() {
363 DCHECK(audio_manager_->GetWorkerTaskRunner()->BelongsToCurrentThread());
364 DCHECK(callback_);
365 int buffer_size;
366 audio_source_->PlayInto(audio_bus_.get(), &buffer_size);
367 callback_->OnData(this, audio_bus_.get(), buffer_size, 1.0);
DaleCurtis 2015/02/18 19:04:49 Why are you returning the buffer_size like this? I
phoglund_chromium 2015/02/19 15:44:11 Done.
368 }
369
317 void FakeAudioInputStream::BeepOnce() { 370 void FakeAudioInputStream::BeepOnce() {
318 BeepContext* beep_context = g_beep_context.Pointer(); 371 BeepContext* beep_context = g_beep_context.Pointer();
319 beep_context->SetBeepOnce(true); 372 beep_context->SetBeepOnce(true);
320 } 373 }
321 374
322 double FakeAudioInputStream::ProvideInput(AudioBus* audio_bus_into_converter,
323 base::TimeDelta buffer_delay) {
324 // Unfilled frames will be zeroed by CopyTo.
325 size_t bytes_written;
326 wav_audio_handler_->CopyTo(audio_bus_into_converter, wav_file_read_pos_,
327 &bytes_written);
328 wav_file_read_pos_ += bytes_written;
329 return 1.0;
330 };
331
332 } // namespace media 375 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698