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

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

Issue 734993002: Makes the WebRTC fake device capable of playing audio from a file. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 6 years, 1 month 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/command_line.h"
9 #include "base/files/file.h"
8 #include "base/lazy_instance.h" 10 #include "base/lazy_instance.h"
9 #include "media/audio/audio_manager_base.h" 11 #include "media/audio/audio_manager_base.h"
10 #include "media/base/audio_bus.h" 12 #include "media/base/audio_bus.h"
13 #include "media/base/media_switches.h"
11 14
12 using base::TimeTicks; 15 using base::TimeTicks;
13 using base::TimeDelta; 16 using base::TimeDelta;
14 17
15 namespace media { 18 namespace media {
16 19
17 namespace { 20 namespace {
18 21
19 // These values are based on experiments for local-to-local 22 // These values are based on experiments for local-to-local
20 // PeerConnection to demonstrate audio/video synchronization. 23 // PeerConnection to demonstrate audio/video synchronization.
(...skipping 25 matching lines...) Expand all
46 base::AutoLock auto_lock(lock_); 49 base::AutoLock auto_lock(lock_);
47 return automatic_beep_; 50 return automatic_beep_;
48 } 51 }
49 52
50 private: 53 private:
51 mutable base::Lock lock_; 54 mutable base::Lock lock_;
52 bool beep_once_; 55 bool beep_once_;
53 bool automatic_beep_; 56 bool automatic_beep_;
54 }; 57 };
55 58
59 // Opens |wav_filename|, reads it and loads it as a wav file. This function will
60 // bluntly trigger CHECKs if we can't read the file or if it's malformed. The
61 // caller takes ownership of the returned data. The size of the data is stored
62 // in |read_length|.
63 scoped_ptr<char[]> ReadWavFile(const base::FilePath& wav_filename,
64 size_t* file_length) {
65 base::File wav_file(
66 wav_filename, base::File::FLAG_OPEN | base::File::FLAG_READ);
67 if (!wav_file.IsValid()) {
68 CHECK(false) << "Failed to read " << wav_filename.value() << " as input to "
69 << "the fake device.";
70 return scoped_ptr<char[]>();
71 }
72
73 size_t wav_file_length = wav_file.GetLength();
74
75 CHECK(wav_file_length < 16 * 1024 * 1024) << "Can't use fake file input "
76 << "stream with wav files > 16 MiB.";
77
78 char* wav_file_data = new char[wav_file_length];
79 size_t read_bytes = wav_file.Read(0, wav_file_data, wav_file_length);
80 if (read_bytes != wav_file_length) {
81 CHECK(false) << "Failed to read all bytes of " << wav_filename.value();
82 return scoped_ptr<char[]>();
83 }
84 *file_length = wav_file_length;
85 return scoped_ptr<char[]>(wav_file_data);
86 }
87
88 // Opens |wav_filename|, reads it and loads it as a Wav file. This function will
89 // bluntly trigger CHECKs if the file doesn't have the sampling frequency, bits
90 // per sample or number of channels as specified in |expected_params|. We also
91 // trigger CHECKs if we can't read the file or if it's malformed.
92 scoped_ptr<media::WavAudioHandler> CreateWavAudioHandler(
93 const base::FilePath& wav_filename, const char* wav_file_data,
94 size_t wav_file_length, const AudioParameters& expected_params) {
95 base::StringPiece wav_data(wav_file_data, wav_file_length);
96 scoped_ptr<media::WavAudioHandler> wav_audio_handler(
97 new media::WavAudioHandler(wav_data));
98
99 // Ensure the input file matches what the audio bus wants, otherwise bail out.
100 CHECK_EQ(wav_audio_handler->params().channels(),
101 expected_params.channels())
102 << "Failed to read " << wav_filename.value() << " to fake device.";
103 CHECK_EQ(wav_audio_handler->params().sample_rate(),
104 expected_params.sample_rate())
105 << "Failed to read " << wav_filename.value() << " to fake device.";
106 CHECK_EQ(wav_audio_handler->params().bits_per_sample(),
107 expected_params.bits_per_sample())
108 << "Failed to read " << wav_filename.value() << " to fake device.";
109
110 return wav_audio_handler.Pass();
111 }
112
56 static base::LazyInstance<BeepContext> g_beep_context = 113 static base::LazyInstance<BeepContext> g_beep_context =
57 LAZY_INSTANCE_INITIALIZER; 114 LAZY_INSTANCE_INITIALIZER;
58 115
59 } // namespace 116 } // namespace
60 117
61 AudioInputStream* FakeAudioInputStream::MakeFakeStream( 118 AudioInputStream* FakeAudioInputStream::MakeFakeStream(
62 AudioManagerBase* manager, 119 AudioManagerBase* manager,
63 const AudioParameters& params) { 120 const AudioParameters& params) {
64 return new FakeAudioInputStream(manager, params); 121 return new FakeAudioInputStream(manager, params);
65 } 122 }
(...skipping 10 matching lines...) Expand all
76 callback_interval_(base::TimeDelta::FromMilliseconds( 133 callback_interval_(base::TimeDelta::FromMilliseconds(
77 (params.frames_per_buffer() * 1000) / params.sample_rate())), 134 (params.frames_per_buffer() * 1000) / params.sample_rate())),
78 beep_duration_in_buffers_(kBeepDurationMilliseconds * 135 beep_duration_in_buffers_(kBeepDurationMilliseconds *
79 params.sample_rate() / 136 params.sample_rate() /
80 params.frames_per_buffer() / 137 params.frames_per_buffer() /
81 1000), 138 1000),
82 beep_generated_in_buffers_(0), 139 beep_generated_in_buffers_(0),
83 beep_period_in_frames_(params.sample_rate() / kBeepFrequency), 140 beep_period_in_frames_(params.sample_rate() / kBeepFrequency),
84 frames_elapsed_(0), 141 frames_elapsed_(0),
85 audio_bus_(AudioBus::Create(params)), 142 audio_bus_(AudioBus::Create(params)),
143 wav_file_read_pos_(0),
86 weak_factory_(this) { 144 weak_factory_(this) {
87 DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread()); 145 DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread());
88 } 146 }
89 147
90 FakeAudioInputStream::~FakeAudioInputStream() {} 148 FakeAudioInputStream::~FakeAudioInputStream() {}
91 149
92 bool FakeAudioInputStream::Open() { 150 bool FakeAudioInputStream::Open() {
93 DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread()); 151 DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread());
94 buffer_.reset(new uint8[buffer_size_]); 152 buffer_.reset(new char[buffer_size_]);
95 memset(buffer_.get(), 0, buffer_size_); 153 memset(buffer_.get(), 0, buffer_size_);
96 audio_bus_->Zero(); 154 audio_bus_->Zero();
155
156 if (CommandLine::ForCurrentProcess()->HasSwitch(
157 switches::kUseFileForFakeAudioCapture)) {
158 OpenInFileMode(CommandLine::ForCurrentProcess()->GetSwitchValuePath(
159 switches::kUseFileForFakeAudioCapture));
160 }
161
97 return true; 162 return true;
98 } 163 }
99 164
100 void FakeAudioInputStream::Start(AudioInputCallback* callback) { 165 void FakeAudioInputStream::Start(AudioInputCallback* callback) {
101 DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread()); 166 DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread());
102 DCHECK(!callback_); 167 DCHECK(!callback_);
103 callback_ = callback; 168 callback_ = callback;
104 last_callback_time_ = TimeTicks::Now(); 169 last_callback_time_ = TimeTicks::Now();
170
105 task_runner_->PostDelayedTask( 171 task_runner_->PostDelayedTask(
106 FROM_HERE, 172 FROM_HERE,
107 base::Bind(&FakeAudioInputStream::DoCallback, weak_factory_.GetWeakPtr()), 173 base::Bind(&FakeAudioInputStream::DoCallback, weak_factory_.GetWeakPtr()),
108 callback_interval_); 174 callback_interval_);
109 } 175 }
110 176
111 void FakeAudioInputStream::DoCallback() { 177 void FakeAudioInputStream::DoCallback() {
112 DCHECK(callback_); 178 DCHECK(callback_);
179 DCHECK(kAutomaticBeepIntervalInMs); // TODO(phoglund);
113 180
114 const TimeTicks now = TimeTicks::Now(); 181 const TimeTicks now = TimeTicks::Now();
115 base::TimeDelta next_callback_time = 182 base::TimeDelta next_callback_time =
116 last_callback_time_ + callback_interval_ * 2 - now; 183 last_callback_time_ + callback_interval_ * 2 - now;
117 184
118 // If we are falling behind, try to catch up as much as we can in the next 185 // If we are falling behind, try to catch up as much as we can in the next
119 // callback. 186 // callback.
120 if (next_callback_time < base::TimeDelta()) 187 if (next_callback_time < base::TimeDelta())
121 next_callback_time = base::TimeDelta(); 188 next_callback_time = base::TimeDelta();
122 189
123 // Accumulate the time from the last beep.
124 interval_from_last_beep_ += now - last_callback_time_;
125
126 last_callback_time_ = now; 190 last_callback_time_ = now;
127 191
192 if (PlayingFromFile()) {
193 PlayFileLooping();
194 } else {
195 PlayBeep();
196 }
197
198 task_runner_->PostDelayedTask(
199 FROM_HERE,
200 base::Bind(&FakeAudioInputStream::DoCallback, weak_factory_.GetWeakPtr()),
201 next_callback_time);
202 }
203
204 void FakeAudioInputStream::OpenInFileMode(const base::FilePath& wav_filename) {
205 CHECK(!wav_filename.empty())
206 << "You must pass the file to use as argument to --"
207 << switches::kUseFileForFakeAudioCapture << ".";
208
209 // Read the file, and put its data in a scoped_ptr so it gets deleted later.
210 size_t file_length = 0;
211 wav_file_data_ = ReadWavFile(wav_filename, &file_length);
212 wav_audio_handler_ = CreateWavAudioHandler(
213 wav_filename, wav_file_data_.get(), file_length, params_);
214 }
215
216 bool FakeAudioInputStream::PlayingFromFile() {
217 return wav_audio_handler_.get() != nullptr;
218 }
219
220 void FakeAudioInputStream::PlayFileLooping() {
221 audio_bus_->FromInterleaved(
222 buffer_.get(), audio_bus_->frames(), params_.bits_per_sample() / 8);
223
224 size_t bytes_written;
225 wav_audio_handler_->CopyTo(audio_bus_.get(), wav_file_read_pos_,
226 &bytes_written);
227 wav_file_read_pos_ += bytes_written;
228 if (wav_audio_handler_->AtEnd(wav_file_read_pos_))
229 wav_file_read_pos_ = 0;
230 callback_->OnData(this, audio_bus_.get(), buffer_size_, 1.0);
231 frames_elapsed_ += params_.frames_per_buffer();
232 }
233
234 void FakeAudioInputStream::PlayBeep() {
235 // Accumulate the time from the last beep.
236 interval_from_last_beep_ += TimeTicks::Now() - last_callback_time_;
237
128 memset(buffer_.get(), 0, buffer_size_); 238 memset(buffer_.get(), 0, buffer_size_);
129
130 bool should_beep = false; 239 bool should_beep = false;
131 { 240 {
132 BeepContext* beep_context = g_beep_context.Pointer(); 241 BeepContext* beep_context = g_beep_context.Pointer();
133 if (beep_context->automatic_beep()) { 242 if (beep_context->automatic_beep()) {
134 base::TimeDelta delta = interval_from_last_beep_ - 243 base::TimeDelta delta = interval_from_last_beep_ -
135 TimeDelta::FromMilliseconds(kAutomaticBeepIntervalInMs); 244 TimeDelta::FromMilliseconds(kAutomaticBeepIntervalInMs);
136 if (delta > base::TimeDelta()) { 245 if (delta > base::TimeDelta()) {
137 should_beep = true; 246 should_beep = true;
138 interval_from_last_beep_ = delta; 247 interval_from_last_beep_ = delta;
139 } 248 }
(...skipping 23 matching lines...) Expand all
163 } 272 }
164 273
165 ++beep_generated_in_buffers_; 274 ++beep_generated_in_buffers_;
166 if (beep_generated_in_buffers_ >= beep_duration_in_buffers_) 275 if (beep_generated_in_buffers_ >= beep_duration_in_buffers_)
167 beep_generated_in_buffers_ = 0; 276 beep_generated_in_buffers_ = 0;
168 } 277 }
169 278
170 audio_bus_->FromInterleaved( 279 audio_bus_->FromInterleaved(
171 buffer_.get(), audio_bus_->frames(), params_.bits_per_sample() / 8); 280 buffer_.get(), audio_bus_->frames(), params_.bits_per_sample() / 8);
172 callback_->OnData(this, audio_bus_.get(), buffer_size_, 1.0); 281 callback_->OnData(this, audio_bus_.get(), buffer_size_, 1.0);
173 frames_elapsed_ += params_.frames_per_buffer();
phoglund_chromium 2014/11/18 12:30:41 Turned out to not be used.
174
175 task_runner_->PostDelayedTask(
176 FROM_HERE,
177 base::Bind(&FakeAudioInputStream::DoCallback, weak_factory_.GetWeakPtr()),
178 next_callback_time);
179 } 282 }
180 283
181 void FakeAudioInputStream::Stop() { 284 void FakeAudioInputStream::Stop() {
182 DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread()); 285 DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread());
183 weak_factory_.InvalidateWeakPtrs(); 286 weak_factory_.InvalidateWeakPtrs();
184 callback_ = NULL; 287 callback_ = NULL;
185 } 288 }
186 289
187 void FakeAudioInputStream::Close() { 290 void FakeAudioInputStream::Close() {
188 DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread()); 291 DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread());
(...skipping 25 matching lines...) Expand all
214 return true; 317 return true;
215 } 318 }
216 319
217 // static 320 // static
218 void FakeAudioInputStream::BeepOnce() { 321 void FakeAudioInputStream::BeepOnce() {
219 BeepContext* beep_context = g_beep_context.Pointer(); 322 BeepContext* beep_context = g_beep_context.Pointer();
220 beep_context->SetBeepOnce(true); 323 beep_context->SetBeepOnce(true);
221 } 324 }
222 325
223 } // namespace media 326 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698