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

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: Fixing bug which broke the beep mode. 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 nullptr;
71 }
72
73 size_t wav_file_length = wav_file.GetLength();
74
75 char* wav_file_data = new char[wav_file_length];
76 size_t read_bytes = wav_file.Read(0, wav_file_data, wav_file_length);
77 if (read_bytes != wav_file_length) {
78 CHECK(false) << "Failed to read all bytes of " << wav_filename.value();
79 return nullptr;
80 }
81 *file_length = wav_file_length;
82 return scoped_ptr<char[]>(wav_file_data);
83 }
84
85 // Opens |wav_filename|, reads it and loads it as a Wav file. This function will
86 // bluntly trigger CHECKs if the file doesn't have the sampling frequency, bits
87 // per sample or number of channels as specified in |expected_params|. We also
88 // trigger CHECKs if we can't read the file or if it's malformed.
89 scoped_ptr<media::WavAudioHandler> CreateWavAudioHandler(
90 const base::FilePath& wav_filename, const char* wav_file_data,
91 size_t wav_file_length, const AudioParameters& expected_params) {
92 base::StringPiece wav_data(wav_file_data, wav_file_length);
93 scoped_ptr<media::WavAudioHandler> wav_audio_handler(
94 new media::WavAudioHandler(wav_data));
95
96 // Ensure the input file matches what the audio bus wants, otherwise bail out.
97 CHECK_EQ(wav_audio_handler->params().channels(),
98 expected_params.channels())
99 << "Failed to read " << wav_filename.value() << " to fake device.";
100 CHECK_EQ(wav_audio_handler->params().sample_rate(),
101 expected_params.sample_rate())
102 << "Failed to read " << wav_filename.value() << " to fake device.";
103 CHECK_EQ(wav_audio_handler->params().bits_per_sample(),
104 expected_params.bits_per_sample())
105 << "Failed to read " << wav_filename.value() << " to fake device.";
106
107 return wav_audio_handler.Pass();
108 }
109
56 static base::LazyInstance<BeepContext> g_beep_context = 110 static base::LazyInstance<BeepContext> g_beep_context =
57 LAZY_INSTANCE_INITIALIZER; 111 LAZY_INSTANCE_INITIALIZER;
58 112
59 } // namespace 113 } // namespace
60 114
61 AudioInputStream* FakeAudioInputStream::MakeFakeStream( 115 AudioInputStream* FakeAudioInputStream::MakeFakeStream(
62 AudioManagerBase* manager, 116 AudioManagerBase* manager,
63 const AudioParameters& params) { 117 const AudioParameters& params) {
64 return new FakeAudioInputStream(manager, params); 118 return new FakeAudioInputStream(manager, params);
65 } 119 }
66 120
67 FakeAudioInputStream::FakeAudioInputStream(AudioManagerBase* manager, 121 FakeAudioInputStream::FakeAudioInputStream(AudioManagerBase* manager,
68 const AudioParameters& params) 122 const AudioParameters& params)
69 : audio_manager_(manager), 123 : audio_manager_(manager),
70 callback_(NULL), 124 callback_(NULL),
71 buffer_size_((params.channels() * params.bits_per_sample() * 125 buffer_size_((params.channels() * params.bits_per_sample() *
72 params.frames_per_buffer()) / 126 params.frames_per_buffer()) /
73 8), 127 8),
74 params_(params), 128 params_(params),
75 task_runner_(manager->GetTaskRunner()), 129 task_runner_(manager->GetTaskRunner()),
76 callback_interval_(base::TimeDelta::FromMilliseconds( 130 callback_interval_(base::TimeDelta::FromMilliseconds(
77 (params.frames_per_buffer() * 1000) / params.sample_rate())), 131 (params.frames_per_buffer() * 1000) / params.sample_rate())),
78 beep_duration_in_buffers_(kBeepDurationMilliseconds * 132 beep_duration_in_buffers_(kBeepDurationMilliseconds *
79 params.sample_rate() / 133 params.sample_rate() /
80 params.frames_per_buffer() / 134 params.frames_per_buffer() /
81 1000), 135 1000),
82 beep_generated_in_buffers_(0), 136 beep_generated_in_buffers_(0),
83 beep_period_in_frames_(params.sample_rate() / kBeepFrequency), 137 beep_period_in_frames_(params.sample_rate() / kBeepFrequency),
84 frames_elapsed_(0),
85 audio_bus_(AudioBus::Create(params)), 138 audio_bus_(AudioBus::Create(params)),
139 wav_file_read_pos_(0),
86 weak_factory_(this) { 140 weak_factory_(this) {
87 DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread()); 141 DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread());
88 } 142 }
89 143
90 FakeAudioInputStream::~FakeAudioInputStream() {} 144 FakeAudioInputStream::~FakeAudioInputStream() {}
91 145
92 bool FakeAudioInputStream::Open() { 146 bool FakeAudioInputStream::Open() {
93 DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread()); 147 DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread());
94 buffer_.reset(new uint8[buffer_size_]); 148 buffer_.reset(new char[buffer_size_]);
95 memset(buffer_.get(), 0, buffer_size_); 149 memset(buffer_.get(), 0, buffer_size_);
96 audio_bus_->Zero(); 150 audio_bus_->Zero();
151
152 if (CommandLine::ForCurrentProcess()->HasSwitch(
153 switches::kUseFileForFakeAudioCapture)) {
154 OpenInFileMode(CommandLine::ForCurrentProcess()->GetSwitchValuePath(
155 switches::kUseFileForFakeAudioCapture));
156 }
157
97 return true; 158 return true;
98 } 159 }
99 160
100 void FakeAudioInputStream::Start(AudioInputCallback* callback) { 161 void FakeAudioInputStream::Start(AudioInputCallback* callback) {
101 DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread()); 162 DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread());
102 DCHECK(!callback_); 163 DCHECK(!callback_);
103 callback_ = callback; 164 callback_ = callback;
104 last_callback_time_ = TimeTicks::Now(); 165 last_callback_time_ = TimeTicks::Now();
166
105 task_runner_->PostDelayedTask( 167 task_runner_->PostDelayedTask(
106 FROM_HERE, 168 FROM_HERE,
107 base::Bind(&FakeAudioInputStream::DoCallback, weak_factory_.GetWeakPtr()), 169 base::Bind(&FakeAudioInputStream::DoCallback, weak_factory_.GetWeakPtr()),
108 callback_interval_); 170 callback_interval_);
109 } 171 }
110 172
111 void FakeAudioInputStream::DoCallback() { 173 void FakeAudioInputStream::DoCallback() {
112 DCHECK(callback_); 174 DCHECK(callback_);
113 175
114 const TimeTicks now = TimeTicks::Now(); 176 const TimeTicks now = TimeTicks::Now();
115 base::TimeDelta next_callback_time = 177 base::TimeDelta next_callback_time =
116 last_callback_time_ + callback_interval_ * 2 - now; 178 last_callback_time_ + callback_interval_ * 2 - now;
117 179
118 // If we are falling behind, try to catch up as much as we can in the next 180 // If we are falling behind, try to catch up as much as we can in the next
119 // callback. 181 // callback.
120 if (next_callback_time < base::TimeDelta()) 182 if (next_callback_time < base::TimeDelta())
121 next_callback_time = base::TimeDelta(); 183 next_callback_time = base::TimeDelta();
122 184
123 // Accumulate the time from the last beep. 185 if (PlayingFromFile()) {
124 interval_from_last_beep_ += now - last_callback_time_; 186 PlayFileLooping();
187 } else {
188 PlayBeep();
189 }
125 190
126 last_callback_time_ = now; 191 last_callback_time_ = now;
127 192
193 task_runner_->PostDelayedTask(
194 FROM_HERE,
195 base::Bind(&FakeAudioInputStream::DoCallback, weak_factory_.GetWeakPtr()),
196 next_callback_time);
197 }
198
199 void FakeAudioInputStream::OpenInFileMode(const base::FilePath& wav_filename) {
200 CHECK(!wav_filename.empty())
201 << "You must pass the file to use as argument to --"
202 << switches::kUseFileForFakeAudioCapture << ".";
203
204 // Read the file, and put its data in a scoped_ptr so it gets deleted later.
205 size_t file_length = 0;
206 wav_file_data_ = ReadWavFile(wav_filename, &file_length);
207 wav_audio_handler_ = CreateWavAudioHandler(
208 wav_filename, wav_file_data_.get(), file_length, params_);
209 }
210
211 bool FakeAudioInputStream::PlayingFromFile() {
212 return wav_audio_handler_.get() != nullptr;
213 }
214
215 void FakeAudioInputStream::PlayFileLooping() {
216 size_t bytes_written;
217 wav_audio_handler_->CopyTo(audio_bus_.get(), wav_file_read_pos_,
218 &bytes_written);
219 wav_file_read_pos_ += bytes_written;
220 if (wav_audio_handler_->AtEnd(wav_file_read_pos_))
221 wav_file_read_pos_ = 0;
222 callback_->OnData(this, audio_bus_.get(), buffer_size_, 1.0);
223 }
224
225 void FakeAudioInputStream::PlayBeep() {
226 // Accumulate the time from the last beep.
227 interval_from_last_beep_ += TimeTicks::Now() - last_callback_time_;
228
128 memset(buffer_.get(), 0, buffer_size_); 229 memset(buffer_.get(), 0, buffer_size_);
129
130 bool should_beep = false; 230 bool should_beep = false;
131 { 231 {
132 BeepContext* beep_context = g_beep_context.Pointer(); 232 BeepContext* beep_context = g_beep_context.Pointer();
133 if (beep_context->automatic_beep()) { 233 if (beep_context->automatic_beep()) {
134 base::TimeDelta delta = interval_from_last_beep_ - 234 base::TimeDelta delta = interval_from_last_beep_ -
135 TimeDelta::FromMilliseconds(kAutomaticBeepIntervalInMs); 235 TimeDelta::FromMilliseconds(kAutomaticBeepIntervalInMs);
136 if (delta > base::TimeDelta()) { 236 if (delta > base::TimeDelta()) {
137 should_beep = true; 237 should_beep = true;
138 interval_from_last_beep_ = delta; 238 interval_from_last_beep_ = delta;
139 } 239 }
(...skipping 23 matching lines...) Expand all
163 } 263 }
164 264
165 ++beep_generated_in_buffers_; 265 ++beep_generated_in_buffers_;
166 if (beep_generated_in_buffers_ >= beep_duration_in_buffers_) 266 if (beep_generated_in_buffers_ >= beep_duration_in_buffers_)
167 beep_generated_in_buffers_ = 0; 267 beep_generated_in_buffers_ = 0;
168 } 268 }
169 269
170 audio_bus_->FromInterleaved( 270 audio_bus_->FromInterleaved(
171 buffer_.get(), audio_bus_->frames(), params_.bits_per_sample() / 8); 271 buffer_.get(), audio_bus_->frames(), params_.bits_per_sample() / 8);
172 callback_->OnData(this, audio_bus_.get(), buffer_size_, 1.0); 272 callback_->OnData(this, audio_bus_.get(), buffer_size_, 1.0);
173 frames_elapsed_ += params_.frames_per_buffer();
174
175 task_runner_->PostDelayedTask(
176 FROM_HERE,
177 base::Bind(&FakeAudioInputStream::DoCallback, weak_factory_.GetWeakPtr()),
178 next_callback_time);
179 } 273 }
180 274
181 void FakeAudioInputStream::Stop() { 275 void FakeAudioInputStream::Stop() {
182 DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread()); 276 DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread());
183 weak_factory_.InvalidateWeakPtrs(); 277 weak_factory_.InvalidateWeakPtrs();
184 callback_ = NULL; 278 callback_ = NULL;
185 } 279 }
186 280
187 void FakeAudioInputStream::Close() { 281 void FakeAudioInputStream::Close() {
188 DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread()); 282 DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread());
(...skipping 25 matching lines...) Expand all
214 return true; 308 return true;
215 } 309 }
216 310
217 // static 311 // static
218 void FakeAudioInputStream::BeepOnce() { 312 void FakeAudioInputStream::BeepOnce() {
219 BeepContext* beep_context = g_beep_context.Pointer(); 313 BeepContext* beep_context = g_beep_context.Pointer();
220 beep_context->SetBeepOnce(true); 314 beep_context->SetBeepOnce(true);
221 } 315 }
222 316
223 } // namespace media 317 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698