Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 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 | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "media/audio/virtual_audio_input_stream.h" | |
| 6 | |
| 7 #include <algorithm> | |
| 8 | |
| 9 #include "base/bind.h" | |
| 10 #include "base/message_loop.h" | |
| 11 #include "media/audio/virtual_audio_output_stream.h" | |
| 12 | |
| 13 namespace media { | |
| 14 | |
| 15 // AudioConverter that can also be used an as InputCallback. This allows this | |
| 16 // audio conversion from input to output params to be used as an input stream to | |
|
Alpha Left Google
2012/11/28 01:04:47
This sentence is too long and hard to parse, can y
justinlin
2012/11/28 14:30:31
Done.
| |
| 17 // other AudioConverters. | |
| 18 class LoopbackAudioConverter | |
| 19 : public AudioConverter, | |
| 20 public AudioConverter::InputCallback { | |
| 21 public: | |
| 22 LoopbackAudioConverter(const AudioParameters& input_params, | |
| 23 const AudioParameters& output_params); | |
| 24 virtual ~LoopbackAudioConverter() {} | |
| 25 | |
| 26 private: | |
| 27 virtual double ProvideInput( | |
| 28 AudioBus* audio_bus, base::TimeDelta buffer_delay) OVERRIDE; | |
| 29 | |
| 30 DISALLOW_COPY_AND_ASSIGN(LoopbackAudioConverter); | |
| 31 }; | |
| 32 | |
| 33 VirtualAudioInputStream* VirtualAudioInputStream::MakeStream( | |
| 34 AudioManagerBase* manager, const AudioParameters& params) { | |
| 35 return new VirtualAudioInputStream(manager, params); | |
| 36 } | |
| 37 | |
| 38 VirtualAudioInputStream::VirtualAudioInputStream(AudioManagerBase* manager, | |
| 39 const AudioParameters& params) | |
| 40 : audio_manager_(manager), | |
| 41 callback_(NULL), | |
| 42 buffer_duration_ms_(params.frames_per_buffer() | |
| 43 * base::Time::kMillisecondsPerSecond | |
| 44 / params.sample_rate()), | |
| 45 buffer_(new uint8[params.GetBytesPerBuffer()]), | |
| 46 params_(params), | |
| 47 audio_bus_(AudioBus::Create(params_)), | |
| 48 mixer_(params_, params_, false), | |
| 49 num_attached_outputs_streams_(0) { | |
| 50 } | |
| 51 | |
| 52 VirtualAudioInputStream::~VirtualAudioInputStream() { | |
| 53 for (AudioConvertersMap::iterator it = converters_.begin(); | |
| 54 it != converters_.end(); ++it) { | |
| 55 delete it->second; | |
| 56 } | |
| 57 DCHECK_EQ(0, num_attached_outputs_streams_); | |
| 58 } | |
| 59 | |
| 60 bool VirtualAudioInputStream::Open() { | |
| 61 memset(buffer_.get(), 0, params_.GetBytesPerBuffer()); | |
| 62 return true; | |
| 63 } | |
| 64 | |
| 65 void VirtualAudioInputStream::Start(AudioInputCallback* callback) { | |
| 66 DCHECK(audio_manager_->GetMessageLoop()->BelongsToCurrentThread()); | |
| 67 callback_ = callback; | |
| 68 on_more_data_cb_.Reset(base::Bind( | |
| 69 &VirtualAudioInputStream::DoCallback, base::Unretained(this))); | |
| 70 next_read_time_ = base::Time::Now(); | |
| 71 audio_manager_->GetMessageLoop()->PostTask( | |
| 72 FROM_HERE, on_more_data_cb_.callback()); | |
| 73 } | |
| 74 | |
| 75 void VirtualAudioInputStream::Stop() { | |
| 76 on_more_data_cb_.Cancel(); | |
| 77 } | |
| 78 | |
| 79 void VirtualAudioInputStream::AddOutputStream( | |
| 80 VirtualAudioOutputStream* stream, const AudioParameters& params) { | |
| 81 DCHECK(audio_manager_->GetMessageLoop()->BelongsToCurrentThread()); | |
| 82 output_params_.insert(std::make_pair(stream, params)); | |
| 83 | |
| 84 LoopbackAudioConverter*& converter = converters_[params]; | |
|
Alpha Left Google
2012/11/28 01:04:47
*& is strange, can you do converters_.find() inste
justinlin
2012/11/28 14:30:31
Done.
| |
| 85 if (!converter) { | |
| 86 converter = new LoopbackAudioConverter(params, params_); | |
| 87 // Add to main mixer if we just added a new AudioTransform. | |
| 88 mixer_.AddInput(converter); | |
| 89 } | |
| 90 converter->AddInput(stream); | |
| 91 ++num_attached_outputs_streams_; | |
| 92 } | |
| 93 | |
| 94 void VirtualAudioInputStream::RemoveOutputStream( | |
| 95 VirtualAudioOutputStream* stream) { | |
| 96 DCHECK(audio_manager_->GetMessageLoop()->BelongsToCurrentThread()); | |
| 97 DCHECK(output_params_.find(stream) != output_params_.end()); | |
| 98 const AudioParameters& params = output_params_[stream]; | |
| 99 | |
| 100 DCHECK(converters_.find(params) != converters_.end()); | |
| 101 converters_[params]->RemoveInput(stream); | |
| 102 // TODO(justinlin): Do we need to delete the AudioConverter and remove it from | |
| 103 // the mixer when there's no more input streams? | |
| 104 | |
| 105 output_params_.erase(stream); | |
| 106 --num_attached_outputs_streams_; | |
| 107 } | |
| 108 | |
| 109 void VirtualAudioInputStream::DoCallback() { | |
| 110 DCHECK(audio_manager_->GetMessageLoop()->BelongsToCurrentThread()); | |
| 111 DCHECK(callback_); | |
| 112 | |
| 113 mixer_.Convert(audio_bus_.get()); | |
| 114 audio_bus_->ToInterleaved(params_.frames_per_buffer(), | |
| 115 params_.bits_per_sample() / 8, | |
| 116 buffer_.get()); | |
| 117 | |
| 118 callback_->OnData(this, buffer_.get(), params_.GetBytesPerBuffer(), | |
| 119 params_.GetBytesPerBuffer(), 1.0); | |
| 120 | |
| 121 next_read_time_ += base::TimeDelta::FromMilliseconds(buffer_duration_ms_); | |
| 122 base::TimeDelta delay = next_read_time_ - base::Time::Now(); | |
| 123 // Try to catchup if we fall behind. | |
| 124 if (delay < base::TimeDelta()) | |
| 125 delay = base::TimeDelta(); | |
| 126 | |
| 127 MessageLoop* message_loop = MessageLoop::current(); | |
| 128 if (message_loop) | |
|
Alpha Left Google
2012/11/28 01:04:47
{} since the statement below has 2 lines.
justinlin
2012/11/28 14:30:31
Done.
| |
| 129 message_loop->PostDelayedTask( | |
| 130 FROM_HERE, on_more_data_cb_.callback(), delay); | |
| 131 } | |
| 132 | |
| 133 void VirtualAudioInputStream::Close() { | |
| 134 DCHECK(audio_manager_->GetMessageLoop()->BelongsToCurrentThread()); | |
| 135 if (callback_) { | |
| 136 DCHECK(on_more_data_cb_.IsCancelled()); | |
| 137 callback_->OnClose(this); | |
| 138 callback_ = NULL; | |
| 139 } | |
| 140 audio_manager_->ReleaseInputStream(this); | |
| 141 } | |
| 142 | |
| 143 double VirtualAudioInputStream::GetMaxVolume() { | |
| 144 return 1.0; | |
| 145 } | |
| 146 | |
| 147 void VirtualAudioInputStream::SetVolume(double volume) {} | |
| 148 | |
| 149 double VirtualAudioInputStream::GetVolume() { | |
| 150 return 1.0; | |
| 151 } | |
| 152 | |
| 153 void VirtualAudioInputStream::SetAutomaticGainControl(bool enabled) {} | |
| 154 | |
| 155 bool VirtualAudioInputStream::GetAutomaticGainControl() { | |
| 156 return false; | |
| 157 } | |
| 158 | |
| 159 LoopbackAudioConverter::LoopbackAudioConverter( | |
|
Alpha Left Google
2012/11/28 01:04:47
Implement these methods inline in the definition o
justinlin
2012/11/28 14:30:31
Done.
| |
| 160 const AudioParameters& input_params, const AudioParameters& output_params) | |
| 161 : AudioConverter(input_params, output_params, false) { | |
| 162 } | |
| 163 | |
| 164 double LoopbackAudioConverter::ProvideInput( | |
| 165 AudioBus* audio_bus, base::TimeDelta buffer_delay) { | |
| 166 Convert(audio_bus); | |
| 167 return 1.0; | |
| 168 } | |
| 169 | |
| 170 } // namespace media | |
| OLD | NEW |