Chromium Code Reviews| Index: media/audio/fake_audio_input_stream.cc |
| diff --git a/media/audio/fake_audio_input_stream.cc b/media/audio/fake_audio_input_stream.cc |
| index 157d3978c7613d7f62d39c64e2b8cb656ecd8aa2..e13afce6d53ab9dfeec1d93ec0c9dd84ea8ad590 100644 |
| --- a/media/audio/fake_audio_input_stream.cc |
| +++ b/media/audio/fake_audio_input_stream.cc |
| @@ -5,9 +5,12 @@ |
| #include "media/audio/fake_audio_input_stream.h" |
| #include "base/bind.h" |
| +#include "base/command_line.h" |
| +#include "base/files/file.h" |
| #include "base/lazy_instance.h" |
| #include "media/audio/audio_manager_base.h" |
| #include "media/base/audio_bus.h" |
| +#include "media/base/media_switches.h" |
| using base::TimeTicks; |
| using base::TimeDelta; |
| @@ -53,6 +56,60 @@ class BeepContext { |
| bool automatic_beep_; |
| }; |
| +// Opens |wav_filename|, reads it and loads it as a wav file. This function will |
| +// bluntly trigger CHECKs if we can't read the file or if it's malformed. The |
| +// caller takes ownership of the returned data. The size of the data is stored |
| +// in |read_length|. |
| +scoped_ptr<char[]> ReadWavFile(const base::FilePath& wav_filename, |
| + size_t* file_length) { |
| + base::File wav_file( |
| + wav_filename, base::File::FLAG_OPEN | base::File::FLAG_READ); |
| + if (!wav_file.IsValid()) { |
| + CHECK(false) << "Failed to read " << wav_filename.value() << " as input to " |
| + << "the fake device."; |
| + return scoped_ptr<char[]>(); |
|
DaleCurtis
2014/11/18 21:59:17
Does nullptr work?
phoglund_chromium
2014/11/19 09:56:09
Done.
|
| + } |
| + |
| + size_t wav_file_length = wav_file.GetLength(); |
| + |
| + CHECK(wav_file_length < 16 * 1024 * 1024) << "Can't use fake file input " |
|
DaleCurtis
2014/11/18 21:59:17
Why?
phoglund_chromium
2014/11/19 09:56:09
I reckoned I should put some reasonable limit here
|
| + << "stream with wav files > 16 MiB."; |
| + |
| + char* wav_file_data = new char[wav_file_length]; |
| + size_t read_bytes = wav_file.Read(0, wav_file_data, wav_file_length); |
| + if (read_bytes != wav_file_length) { |
| + CHECK(false) << "Failed to read all bytes of " << wav_filename.value(); |
| + return scoped_ptr<char[]>(); |
|
DaleCurtis
2014/11/18 21:59:17
Ditto?
phoglund_chromium
2014/11/19 09:56:09
Done.
|
| + } |
| + *file_length = wav_file_length; |
| + return scoped_ptr<char[]>(wav_file_data); |
| +} |
| + |
| +// Opens |wav_filename|, reads it and loads it as a Wav file. This function will |
| +// bluntly trigger CHECKs if the file doesn't have the sampling frequency, bits |
| +// per sample or number of channels as specified in |expected_params|. We also |
| +// trigger CHECKs if we can't read the file or if it's malformed. |
| +scoped_ptr<media::WavAudioHandler> CreateWavAudioHandler( |
| + const base::FilePath& wav_filename, const char* wav_file_data, |
| + size_t wav_file_length, const AudioParameters& expected_params) { |
| + base::StringPiece wav_data(wav_file_data, wav_file_length); |
| + scoped_ptr<media::WavAudioHandler> wav_audio_handler( |
| + new media::WavAudioHandler(wav_data)); |
| + |
| + // Ensure the input file matches what the audio bus wants, otherwise bail out. |
| + CHECK_EQ(wav_audio_handler->params().channels(), |
| + expected_params.channels()) |
| + << "Failed to read " << wav_filename.value() << " to fake device."; |
| + CHECK_EQ(wav_audio_handler->params().sample_rate(), |
| + expected_params.sample_rate()) |
| + << "Failed to read " << wav_filename.value() << " to fake device."; |
| + CHECK_EQ(wav_audio_handler->params().bits_per_sample(), |
| + expected_params.bits_per_sample()) |
| + << "Failed to read " << wav_filename.value() << " to fake device."; |
| + |
| + return wav_audio_handler.Pass(); |
| +} |
| + |
| static base::LazyInstance<BeepContext> g_beep_context = |
| LAZY_INSTANCE_INITIALIZER; |
| @@ -81,8 +138,8 @@ FakeAudioInputStream::FakeAudioInputStream(AudioManagerBase* manager, |
| 1000), |
| beep_generated_in_buffers_(0), |
| beep_period_in_frames_(params.sample_rate() / kBeepFrequency), |
| - frames_elapsed_(0), |
| audio_bus_(AudioBus::Create(params)), |
| + wav_file_read_pos_(0), |
| weak_factory_(this) { |
| DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread()); |
| } |
| @@ -91,9 +148,16 @@ FakeAudioInputStream::~FakeAudioInputStream() {} |
| bool FakeAudioInputStream::Open() { |
| DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread()); |
| - buffer_.reset(new uint8[buffer_size_]); |
| + buffer_.reset(new char[buffer_size_]); |
| memset(buffer_.get(), 0, buffer_size_); |
| audio_bus_->Zero(); |
| + |
| + if (CommandLine::ForCurrentProcess()->HasSwitch( |
| + switches::kUseFileForFakeAudioCapture)) { |
| + OpenInFileMode(CommandLine::ForCurrentProcess()->GetSwitchValuePath( |
| + switches::kUseFileForFakeAudioCapture)); |
| + } |
| + |
| return true; |
| } |
| @@ -102,6 +166,7 @@ void FakeAudioInputStream::Start(AudioInputCallback* callback) { |
| DCHECK(!callback_); |
| callback_ = callback; |
| last_callback_time_ = TimeTicks::Now(); |
| + |
| task_runner_->PostDelayedTask( |
| FROM_HERE, |
| base::Bind(&FakeAudioInputStream::DoCallback, weak_factory_.GetWeakPtr()), |
| @@ -110,6 +175,7 @@ void FakeAudioInputStream::Start(AudioInputCallback* callback) { |
| void FakeAudioInputStream::DoCallback() { |
| DCHECK(callback_); |
| + DCHECK(kAutomaticBeepIntervalInMs); // TODO(phoglund); |
|
DaleCurtis
2014/11/18 21:59:17
Doesn't seem useful?
phoglund_chromium
2014/11/19 09:56:09
Oops, nope that should go away.
|
| const TimeTicks now = TimeTicks::Now(); |
| base::TimeDelta next_callback_time = |
| @@ -120,13 +186,54 @@ void FakeAudioInputStream::DoCallback() { |
| if (next_callback_time < base::TimeDelta()) |
| next_callback_time = base::TimeDelta(); |
| - // Accumulate the time from the last beep. |
| - interval_from_last_beep_ += now - last_callback_time_; |
| - |
| last_callback_time_ = now; |
| - memset(buffer_.get(), 0, buffer_size_); |
| + if (PlayingFromFile()) { |
| + PlayFileLooping(); |
| + } else { |
| + PlayBeep(); |
| + } |
| + |
| + task_runner_->PostDelayedTask( |
| + FROM_HERE, |
| + base::Bind(&FakeAudioInputStream::DoCallback, weak_factory_.GetWeakPtr()), |
| + next_callback_time); |
| +} |
| + |
| +void FakeAudioInputStream::OpenInFileMode(const base::FilePath& wav_filename) { |
| + CHECK(!wav_filename.empty()) |
| + << "You must pass the file to use as argument to --" |
| + << switches::kUseFileForFakeAudioCapture << "."; |
| + // Read the file, and put its data in a scoped_ptr so it gets deleted later. |
| + size_t file_length = 0; |
| + wav_file_data_ = ReadWavFile(wav_filename, &file_length); |
| + wav_audio_handler_ = CreateWavAudioHandler( |
| + wav_filename, wav_file_data_.get(), file_length, params_); |
| +} |
| + |
| +bool FakeAudioInputStream::PlayingFromFile() { |
| + return wav_audio_handler_.get() != nullptr; |
| +} |
| + |
| +void FakeAudioInputStream::PlayFileLooping() { |
| + audio_bus_->FromInterleaved( |
|
DaleCurtis
2014/11/18 21:59:17
Why? You're just overwriting this below.
phoglund_chromium
2014/11/19 09:56:09
Good catch, that shouldn't be there either.
|
| + buffer_.get(), audio_bus_->frames(), params_.bits_per_sample() / 8); |
| + |
| + size_t bytes_written; |
| + wav_audio_handler_->CopyTo(audio_bus_.get(), wav_file_read_pos_, |
| + &bytes_written); |
| + wav_file_read_pos_ += bytes_written; |
|
DaleCurtis
2014/11/18 21:59:17
If bytes_written doesn't completely fill the Audio
phoglund_chromium
2014/11/19 09:56:09
Right; I think the wav_audio_handler deals with th
DaleCurtis
2014/11/20 19:13:47
Add a comment here that unfilled frames are zeroed
phoglund_chromium
2014/11/20 19:48:31
Done.
|
| + if (wav_audio_handler_->AtEnd(wav_file_read_pos_)) |
| + wav_file_read_pos_ = 0; |
| + callback_->OnData(this, audio_bus_.get(), buffer_size_, 1.0); |
| +} |
| + |
| +void FakeAudioInputStream::PlayBeep() { |
| + // Accumulate the time from the last beep. |
| + interval_from_last_beep_ += TimeTicks::Now() - last_callback_time_; |
| + |
| + memset(buffer_.get(), 0, buffer_size_); |
| bool should_beep = false; |
| { |
| BeepContext* beep_context = g_beep_context.Pointer(); |
| @@ -170,12 +277,6 @@ void FakeAudioInputStream::DoCallback() { |
| audio_bus_->FromInterleaved( |
| buffer_.get(), audio_bus_->frames(), params_.bits_per_sample() / 8); |
| callback_->OnData(this, audio_bus_.get(), buffer_size_, 1.0); |
| - frames_elapsed_ += params_.frames_per_buffer(); |
| - |
| - task_runner_->PostDelayedTask( |
| - FROM_HERE, |
| - base::Bind(&FakeAudioInputStream::DoCallback, weak_factory_.GetWeakPtr()), |
| - next_callback_time); |
| } |
| void FakeAudioInputStream::Stop() { |