Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 "content/renderer/media/webrtc_audio_capturer.h" | 5 #include "content/renderer/media/webrtc_audio_capturer.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/logging.h" | 8 #include "base/logging.h" |
| 9 #include "base/metrics/histogram.h" | 9 #include "base/metrics/histogram.h" |
| 10 #include "base/string_util.h" | 10 #include "base/string_util.h" |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 37 int buffer_size = 0; | 37 int buffer_size = 0; |
| 38 #if defined(OS_WIN) || defined(OS_MACOSX) | 38 #if defined(OS_WIN) || defined(OS_MACOSX) |
| 39 // Use different buffer sizes depending on the current hardware sample rate. | 39 // Use different buffer sizes depending on the current hardware sample rate. |
| 40 if (sample_rate == 44100) { | 40 if (sample_rate == 44100) { |
| 41 // We do run at 44.1kHz at the actual audio layer, but ask for frames | 41 // We do run at 44.1kHz at the actual audio layer, but ask for frames |
| 42 // at 44.0kHz to ensure that we can feed them to the webrtc::VoiceEngine. | 42 // at 44.0kHz to ensure that we can feed them to the webrtc::VoiceEngine. |
| 43 buffer_size = 440; | 43 buffer_size = 440; |
| 44 } else { | 44 } else { |
| 45 buffer_size = (sample_rate / 100); | 45 buffer_size = (sample_rate / 100); |
| 46 DCHECK_EQ(buffer_size * 100, sample_rate) << | 46 DCHECK_EQ(buffer_size * 100, sample_rate) << |
| 47 "Sample rate not supported. Should have been caught in Init()."; | 47 "Sample rate not supported"; |
| 48 } | 48 } |
| 49 #elif defined(OS_LINUX) || defined(OS_OPENBSD) | 49 #elif defined(OS_LINUX) || defined(OS_OPENBSD) |
| 50 // Based on tests using the current ALSA implementation in Chrome, we have | 50 // Based on tests using the current ALSA implementation in Chrome, we have |
| 51 // found that the best combination is 20ms on the input side and 10ms on the | 51 // found that the best combination is 20ms on the input side and 10ms on the |
| 52 // output side. | 52 // output side. |
| 53 // TODO(henrika): It might be possible to reduce the input buffer | 53 // TODO(henrika): It might be possible to reduce the input buffer |
| 54 // size and reduce the delay even more. | 54 // size and reduce the delay even more. |
| 55 buffer_size = 2 * sample_rate / 100; | 55 buffer_size = 2 * sample_rate / 100; |
| 56 #endif | 56 #endif |
| 57 | 57 |
| 58 return buffer_size; | 58 return buffer_size; |
| 59 } | 59 } |
| 60 | 60 |
| 61 // static | 61 // static |
| 62 scoped_refptr<WebRtcAudioCapturer> WebRtcAudioCapturer::CreateCapturer() { | 62 scoped_refptr<WebRtcAudioCapturer> WebRtcAudioCapturer::CreateCapturer() { |
| 63 scoped_refptr<WebRtcAudioCapturer> capturer = new WebRtcAudioCapturer(); | 63 scoped_refptr<WebRtcAudioCapturer> capturer = new WebRtcAudioCapturer(); |
| 64 if (capturer->Initialize()) | 64 return capturer; |
| 65 return capturer; | 65 } |
| 66 | 66 |
| 67 return NULL; | 67 bool WebRtcAudioCapturer::Initialize(media::ChannelLayout channel_layout, |
| 68 int sample_rate) { | |
| 69 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 70 DCHECK(!sinks_.empty()); | |
| 71 DVLOG(1) << "WebRtcAudioCapturer::Initialize()"; | |
| 72 | |
| 73 media::AudioParameters::Format format = | |
| 74 media::AudioParameters::AUDIO_PCM_LOW_LATENCY; | |
| 75 | |
| 76 DVLOG(1) << "Audio input hardware channel layout: " << channel_layout; | |
| 77 UMA_HISTOGRAM_ENUMERATION("WebRTC.AudioInputChannelLayout", | |
| 78 channel_layout, media::CHANNEL_LAYOUT_MAX); | |
| 79 | |
| 80 DVLOG(1) << "Audio input hardware sample rate: " << sample_rate; | |
| 81 UMA_HISTOGRAM_ENUMERATION("WebRTC.AudioInputSampleRate", | |
| 82 sample_rate, media::kUnexpectedAudioSampleRate); | |
| 83 | |
| 84 // Verify that the reported input hardware sample rate is supported | |
| 85 // on the current platform. | |
| 86 if (std::find(&kValidInputRates[0], | |
| 87 &kValidInputRates[0] + arraysize(kValidInputRates), | |
| 88 sample_rate) == | |
| 89 &kValidInputRates[arraysize(kValidInputRates)]) { | |
| 90 DLOG(ERROR) << sample_rate << " is not a supported input rate."; | |
| 91 return false; | |
|
Chris Evans
2013/01/23 09:39:04
I see that sample_rate is carefully validated in t
henrika (OOO until Aug 14)
2013/01/23 10:25:40
Good point. Will improve before committing. Thanks
| |
| 92 } | |
| 93 | |
| 94 int buffer_size = GetBufferSizeForSampleRate(sample_rate); | |
| 95 | |
| 96 // Configure audio parameters for the default source. | |
| 97 params_.Reset(format, channel_layout, sample_rate, 16, buffer_size); | |
| 98 | |
| 99 // Tell all sinks which format we use. | |
| 100 for (SinkList::const_iterator it = sinks_.begin(); | |
| 101 it != sinks_.end(); ++it) { | |
| 102 (*it)->SetCaptureFormat(params_); | |
| 103 } | |
| 104 | |
| 105 buffer_.reset(new int16[params_.frames_per_buffer() * params_.channels()]); | |
| 106 | |
| 107 // Create and configure the default audio capturing source. The |source_| | |
| 108 // will be overwritten if an external client later calls SetCapturerSource() | |
| 109 // providing an alternaive media::AudioCapturerSource. | |
| 110 SetCapturerSource(AudioDeviceFactory::NewInputDevice(), | |
| 111 channel_layout, | |
| 112 static_cast<float>(sample_rate)); | |
| 113 | |
| 114 return true; | |
| 68 } | 115 } |
| 69 | 116 |
| 70 WebRtcAudioCapturer::WebRtcAudioCapturer() | 117 WebRtcAudioCapturer::WebRtcAudioCapturer() |
| 71 : source_(NULL), | 118 : source_(NULL), |
| 72 running_(false), | 119 running_(false), |
| 73 buffering_(false) { | 120 buffering_(false) { |
| 121 DVLOG(1) << "WebRtcAudioCapturer::WebRtcAudioCapturer()"; | |
| 74 } | 122 } |
| 75 | 123 |
| 76 WebRtcAudioCapturer::~WebRtcAudioCapturer() { | 124 WebRtcAudioCapturer::~WebRtcAudioCapturer() { |
| 125 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 77 DCHECK(sinks_.empty()); | 126 DCHECK(sinks_.empty()); |
| 78 DCHECK(!loopback_fifo_); | 127 DCHECK(!loopback_fifo_); |
| 128 DVLOG(1) << "WebRtcAudioCapturer::~WebRtcAudioCapturer()"; | |
| 79 } | 129 } |
| 80 | 130 |
| 81 void WebRtcAudioCapturer::AddCapturerSink(WebRtcAudioCapturerSink* sink) { | 131 void WebRtcAudioCapturer::AddCapturerSink(WebRtcAudioCapturerSink* sink) { |
| 82 { | 132 DCHECK(thread_checker_.CalledOnValidThread()); |
| 83 base::AutoLock auto_lock(lock_); | 133 DVLOG(1) << "WebRtcAudioCapturer::AddCapturerSink()"; |
| 84 DCHECK(std::find(sinks_.begin(), sinks_.end(), sink) == sinks_.end()); | 134 base::AutoLock auto_lock(lock_); |
| 85 sinks_.push_back(sink); | 135 DCHECK(std::find(sinks_.begin(), sinks_.end(), sink) == sinks_.end()); |
| 86 } | 136 sinks_.push_back(sink); |
| 87 | |
| 88 // Tell the |sink| which format we use. | |
| 89 sink->SetCaptureFormat(params_); | |
| 90 } | 137 } |
| 91 | 138 |
| 92 void WebRtcAudioCapturer::RemoveCapturerSink(WebRtcAudioCapturerSink* sink) { | 139 void WebRtcAudioCapturer::RemoveCapturerSink(WebRtcAudioCapturerSink* sink) { |
| 140 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 141 DVLOG(1) << "WebRtcAudioCapturer::RemoveCapturerSink()"; | |
| 93 base::AutoLock auto_lock(lock_); | 142 base::AutoLock auto_lock(lock_); |
| 94 for (SinkList::iterator it = sinks_.begin(); it != sinks_.end(); ++it) { | 143 for (SinkList::iterator it = sinks_.begin(); it != sinks_.end(); ++it) { |
| 95 if (sink == *it) { | 144 if (sink == *it) { |
| 96 sinks_.erase(it); | 145 sinks_.erase(it); |
| 97 break; | 146 break; |
| 98 } | 147 } |
| 99 } | 148 } |
| 100 } | 149 } |
| 101 | 150 |
| 102 void WebRtcAudioCapturer::SetCapturerSource( | 151 void WebRtcAudioCapturer::SetCapturerSource( |
| 103 const scoped_refptr<media::AudioCapturerSource>& source, | 152 const scoped_refptr<media::AudioCapturerSource>& source, |
| 104 media::ChannelLayout channel_layout, | 153 media::ChannelLayout channel_layout, |
| 105 float sample_rate) { | 154 float sample_rate) { |
| 106 DVLOG(1) << "SetCapturerSource()"; | 155 DVLOG(1) << "SetCapturerSource(channel_layout=" << channel_layout << "," |
| 156 << "sample_rate=" << sample_rate << ")"; | |
| 107 scoped_refptr<media::AudioCapturerSource> old_source; | 157 scoped_refptr<media::AudioCapturerSource> old_source; |
| 108 { | 158 { |
| 109 base::AutoLock auto_lock(lock_); | 159 base::AutoLock auto_lock(lock_); |
| 110 if (source_ == source) | 160 if (source_ == source) |
| 111 return; | 161 return; |
| 112 | 162 |
| 113 source_.swap(old_source); | 163 source_.swap(old_source); |
| 114 source_ = source; | 164 source_ = source; |
| 115 } | 165 } |
| 116 | 166 |
| 117 // Detach the old source from normal recording. | 167 const bool no_default_audio_source_exists = !buffer_.get(); |
| 118 if (old_source) { | 168 |
| 119 old_source->Stop(); | 169 // Detach the old source from normal recording or perform first-time |
| 170 // initialization if Initialize() has never been called. For the second | |
| 171 // case, the caller is not "taking over an ongoing session" but instead | |
| 172 // "taking control over a new session". | |
| 173 if (old_source || no_default_audio_source_exists) { | |
| 174 DVLOG(1) << "New capture source will now be utilized."; | |
| 175 if (old_source) | |
| 176 old_source->Stop(); | |
| 120 | 177 |
| 121 // Dispatch the new parameters both to the sink(s) and to the new source. | 178 // Dispatch the new parameters both to the sink(s) and to the new source. |
| 122 // The idea is to get rid of any dependency of the microphone parameters | 179 // The idea is to get rid of any dependency of the microphone parameters |
| 123 // which would normally be used by default. | 180 // which would normally be used by default. |
| 124 | 181 |
| 125 int buffer_size = GetBufferSizeForSampleRate(sample_rate); | 182 int buffer_size = GetBufferSizeForSampleRate(sample_rate); |
| 126 if (!buffer_size) { | 183 if (!buffer_size) { |
| 127 DLOG(ERROR) << "Unsupported sample-rate: " << sample_rate; | 184 DLOG(ERROR) << "Unsupported sample-rate: " << sample_rate; |
| 128 return; | 185 return; |
| 129 } | 186 } |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 141 (*it)->SetCaptureFormat(params_); | 198 (*it)->SetCaptureFormat(params_); |
| 142 } | 199 } |
| 143 } | 200 } |
| 144 | 201 |
| 145 if (source) | 202 if (source) |
| 146 source->Initialize(params_, this, this); | 203 source->Initialize(params_, this, this); |
| 147 } | 204 } |
| 148 | 205 |
| 149 void WebRtcAudioCapturer::SetStopCallback( | 206 void WebRtcAudioCapturer::SetStopCallback( |
| 150 const base::Closure& on_device_stopped_cb) { | 207 const base::Closure& on_device_stopped_cb) { |
| 208 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 151 DVLOG(1) << "WebRtcAudioCapturer::SetStopCallback()"; | 209 DVLOG(1) << "WebRtcAudioCapturer::SetStopCallback()"; |
| 152 base::AutoLock auto_lock(lock_); | 210 base::AutoLock auto_lock(lock_); |
| 153 on_device_stopped_cb_ = on_device_stopped_cb; | 211 on_device_stopped_cb_ = on_device_stopped_cb; |
| 154 } | 212 } |
| 155 | 213 |
| 156 void WebRtcAudioCapturer::PrepareLoopback() { | 214 void WebRtcAudioCapturer::PrepareLoopback() { |
| 215 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 157 DVLOG(1) << "WebRtcAudioCapturer::PrepareLoopback()"; | 216 DVLOG(1) << "WebRtcAudioCapturer::PrepareLoopback()"; |
| 158 base::AutoLock auto_lock(lock_); | 217 base::AutoLock auto_lock(lock_); |
| 159 DCHECK(!loopback_fifo_); | 218 DCHECK(!loopback_fifo_); |
| 160 | 219 |
| 161 // TODO(henrika): we could add a more dynamic solution here but I prefer | 220 // TODO(henrika): we could add a more dynamic solution here but I prefer |
| 162 // a fixed size combined with bad audio at overflow. The alternative is | 221 // a fixed size combined with bad audio at overflow. The alternative is |
| 163 // that we start to build up latency and that can be more difficult to | 222 // that we start to build up latency and that can be more difficult to |
| 164 // detect. Tests have shown that the FIFO never contains more than 2 or 3 | 223 // detect. Tests have shown that the FIFO never contains more than 2 or 3 |
| 165 // audio frames but I have selected a max size of ten buffers just | 224 // audio frames but I have selected a max size of ten buffers just |
| 166 // in case since these tests were performed on a 16 core, 64GB Win 7 | 225 // in case since these tests were performed on a 16 core, 64GB Win 7 |
| 167 // machine. We could also add some sort of error notifier in this area if | 226 // machine. We could also add some sort of error notifier in this area if |
| 168 // the FIFO overflows. | 227 // the FIFO overflows. |
| 169 loopback_fifo_.reset(new media::AudioFifo(params_.channels(), | 228 loopback_fifo_.reset(new media::AudioFifo(params_.channels(), |
| 170 10 * params_.frames_per_buffer())); | 229 10 * params_.frames_per_buffer())); |
| 171 buffering_ = true; | 230 buffering_ = true; |
| 172 } | 231 } |
| 173 | 232 |
| 174 void WebRtcAudioCapturer::CancelLoopback() { | 233 void WebRtcAudioCapturer::CancelLoopback() { |
| 234 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 175 DVLOG(1) << "WebRtcAudioCapturer::CancelLoopback()"; | 235 DVLOG(1) << "WebRtcAudioCapturer::CancelLoopback()"; |
| 176 base::AutoLock auto_lock(lock_); | 236 base::AutoLock auto_lock(lock_); |
| 177 buffering_ = false; | 237 buffering_ = false; |
| 178 if (loopback_fifo_.get() != NULL) { | 238 if (loopback_fifo_.get() != NULL) { |
| 179 loopback_fifo_->Clear(); | 239 loopback_fifo_->Clear(); |
| 180 loopback_fifo_.reset(); | 240 loopback_fifo_.reset(); |
| 181 } | 241 } |
| 182 } | 242 } |
| 183 | 243 |
| 184 void WebRtcAudioCapturer::PauseBuffering() { | 244 void WebRtcAudioCapturer::PauseBuffering() { |
| 245 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 185 DVLOG(1) << "WebRtcAudioCapturer::PauseBuffering()"; | 246 DVLOG(1) << "WebRtcAudioCapturer::PauseBuffering()"; |
| 186 base::AutoLock auto_lock(lock_); | 247 base::AutoLock auto_lock(lock_); |
| 187 buffering_ = false; | 248 buffering_ = false; |
| 188 } | 249 } |
| 189 | 250 |
| 190 void WebRtcAudioCapturer::ResumeBuffering() { | 251 void WebRtcAudioCapturer::ResumeBuffering() { |
| 252 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 191 DVLOG(1) << "WebRtcAudioCapturer::ResumeBuffering()"; | 253 DVLOG(1) << "WebRtcAudioCapturer::ResumeBuffering()"; |
| 192 base::AutoLock auto_lock(lock_); | 254 base::AutoLock auto_lock(lock_); |
| 193 if (buffering_) | 255 if (buffering_) |
| 194 return; | 256 return; |
| 195 if (loopback_fifo_.get() != NULL) | 257 if (loopback_fifo_.get() != NULL) |
| 196 loopback_fifo_->Clear(); | 258 loopback_fifo_->Clear(); |
| 197 buffering_ = true; | 259 buffering_ = true; |
| 198 } | 260 } |
| 199 | 261 |
| 200 bool WebRtcAudioCapturer::Initialize() { | |
| 201 DVLOG(1) << "WebRtcAudioCapturer::Initialize()"; | |
| 202 // Ask the browser for the default audio input hardware sample-rate. | |
| 203 // This request is based on a synchronous IPC message. | |
| 204 // TODO(xians): we should ask for the native sample rate of a specific device. | |
| 205 int sample_rate = GetAudioInputSampleRate(); | |
| 206 DVLOG(1) << "Audio input hardware sample rate: " << sample_rate; | |
| 207 UMA_HISTOGRAM_ENUMERATION("WebRTC.AudioInputSampleRate", | |
| 208 sample_rate, media::kUnexpectedAudioSampleRate); | |
| 209 | |
| 210 // Verify that the reported input hardware sample rate is supported | |
| 211 // on the current platform. | |
| 212 if (std::find(&kValidInputRates[0], | |
| 213 &kValidInputRates[0] + arraysize(kValidInputRates), | |
| 214 sample_rate) == | |
| 215 &kValidInputRates[arraysize(kValidInputRates)]) { | |
| 216 DLOG(ERROR) << sample_rate << " is not a supported input rate."; | |
| 217 return false; | |
| 218 } | |
| 219 | |
| 220 // Ask the browser for the default number of audio input channels. | |
| 221 // This request is based on a synchronous IPC message. | |
| 222 // TODO(xians): we should ask for the layout of a specific device. | |
| 223 media::ChannelLayout channel_layout = GetAudioInputChannelLayout(); | |
| 224 DVLOG(1) << "Audio input hardware channels: " << channel_layout; | |
| 225 | |
| 226 media::AudioParameters::Format format = | |
| 227 media::AudioParameters::AUDIO_PCM_LOW_LATENCY; | |
| 228 int buffer_size = GetBufferSizeForSampleRate(sample_rate); | |
| 229 if (!buffer_size) { | |
| 230 DLOG(ERROR) << "Unsupported platform"; | |
| 231 return false; | |
| 232 } | |
| 233 | |
| 234 params_.Reset(format, channel_layout, sample_rate, 16, buffer_size); | |
| 235 | |
| 236 buffer_.reset(new int16[params_.frames_per_buffer() * params_.channels()]); | |
| 237 | |
| 238 // Create and configure the default audio capturing source. The |source_| | |
| 239 // will be overwritten if the client call the source calls | |
| 240 // SetCapturerSource(). | |
| 241 SetCapturerSource( | |
| 242 AudioDeviceFactory::NewInputDevice(), channel_layout, sample_rate); | |
| 243 | |
| 244 UMA_HISTOGRAM_ENUMERATION("WebRTC.AudioInputChannelLayout", | |
| 245 channel_layout, media::CHANNEL_LAYOUT_MAX); | |
| 246 | |
| 247 return true; | |
| 248 } | |
| 249 | |
| 250 void WebRtcAudioCapturer::ProvideInput(media::AudioBus* dest) { | 262 void WebRtcAudioCapturer::ProvideInput(media::AudioBus* dest) { |
| 251 base::AutoLock auto_lock(lock_); | 263 base::AutoLock auto_lock(lock_); |
| 252 DCHECK(loopback_fifo_.get() != NULL); | 264 DCHECK(loopback_fifo_.get() != NULL); |
| 253 | 265 |
| 254 if (!running_) { | 266 if (!running_) { |
| 255 dest->Zero(); | 267 dest->Zero(); |
| 256 return; | 268 return; |
| 257 } | 269 } |
| 258 | 270 |
| 259 // Provide data by reading from the FIFO if the FIFO contains enough | 271 // Provide data by reading from the FIFO if the FIFO contains enough |
| 260 // to fulfill the request. | 272 // to fulfill the request. |
| 261 if (loopback_fifo_->frames() >= dest->frames()) { | 273 if (loopback_fifo_->frames() >= dest->frames()) { |
| 262 loopback_fifo_->Consume(dest, 0, dest->frames()); | 274 loopback_fifo_->Consume(dest, 0, dest->frames()); |
| 263 } else { | 275 } else { |
| 264 dest->Zero(); | 276 dest->Zero(); |
| 265 // This warning is perfectly safe if it happens for the first audio | 277 // This warning is perfectly safe if it happens for the first audio |
| 266 // frames. It should not happen in a steady-state mode. | 278 // frames. It should not happen in a steady-state mode. |
| 267 DLOG(WARNING) << "WARNING: loopback FIFO is empty."; | 279 DVLOG(2) << "WARNING: loopback FIFO is empty."; |
| 268 } | 280 } |
| 269 } | 281 } |
| 270 | 282 |
| 271 void WebRtcAudioCapturer::Start() { | 283 void WebRtcAudioCapturer::Start() { |
| 272 DVLOG(1) << "WebRtcAudioCapturer::Start()"; | 284 DVLOG(1) << "WebRtcAudioCapturer::Start()"; |
| 273 base::AutoLock auto_lock(lock_); | 285 base::AutoLock auto_lock(lock_); |
| 274 if (running_) | 286 if (running_) |
| 275 return; | 287 return; |
| 276 | 288 |
| 277 // What Start() does is supposed to be very light, for example, posting a | 289 // What Start() does is supposed to be very light, for example, posting a |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 301 running_ = false; | 313 running_ = false; |
| 302 } | 314 } |
| 303 | 315 |
| 304 if (source) | 316 if (source) |
| 305 source->Stop(); | 317 source->Stop(); |
| 306 } | 318 } |
| 307 | 319 |
| 308 void WebRtcAudioCapturer::SetVolume(double volume) { | 320 void WebRtcAudioCapturer::SetVolume(double volume) { |
| 309 DVLOG(1) << "WebRtcAudioCapturer::SetVolume()"; | 321 DVLOG(1) << "WebRtcAudioCapturer::SetVolume()"; |
| 310 base::AutoLock auto_lock(lock_); | 322 base::AutoLock auto_lock(lock_); |
| 311 | |
| 312 if (source_) | 323 if (source_) |
| 313 source_->SetVolume(volume); | 324 source_->SetVolume(volume); |
| 314 } | 325 } |
| 315 | 326 |
| 316 void WebRtcAudioCapturer::SetDevice(int session_id) { | 327 void WebRtcAudioCapturer::SetDevice(int session_id) { |
| 328 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 317 DVLOG(1) << "WebRtcAudioCapturer::SetDevice(" << session_id << ")"; | 329 DVLOG(1) << "WebRtcAudioCapturer::SetDevice(" << session_id << ")"; |
| 318 base::AutoLock auto_lock(lock_); | 330 base::AutoLock auto_lock(lock_); |
| 319 if (source_) | 331 if (source_) |
| 320 source_->SetDevice(session_id); | 332 source_->SetDevice(session_id); |
| 321 } | 333 } |
| 322 | 334 |
| 323 void WebRtcAudioCapturer::SetAutomaticGainControl(bool enable) { | 335 void WebRtcAudioCapturer::SetAutomaticGainControl(bool enable) { |
| 324 base::AutoLock auto_lock(lock_); | 336 base::AutoLock auto_lock(lock_); |
| 325 if (source_) | 337 if (source_) |
| 326 source_->SetAutomaticGainControl(enable); | 338 source_->SetAutomaticGainControl(enable); |
| 327 } | 339 } |
| 328 | 340 |
| 329 bool WebRtcAudioCapturer::IsInLoopbackMode() { | 341 bool WebRtcAudioCapturer::IsInLoopbackMode() { |
| 342 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 330 base::AutoLock auto_lock(lock_); | 343 base::AutoLock auto_lock(lock_); |
| 331 return (loopback_fifo_ != NULL); | 344 return (loopback_fifo_ != NULL); |
| 332 } | 345 } |
| 333 | 346 |
| 334 void WebRtcAudioCapturer::Capture(media::AudioBus* audio_source, | 347 void WebRtcAudioCapturer::Capture(media::AudioBus* audio_source, |
| 335 int audio_delay_milliseconds, | 348 int audio_delay_milliseconds, |
| 336 double volume) { | 349 double volume) { |
| 337 // This callback is driven by AudioInputDevice::AudioThreadCallback if | 350 // This callback is driven by AudioInputDevice::AudioThreadCallback if |
| 338 // |source_| is AudioInputDevice, otherwise it is driven by client's | 351 // |source_| is AudioInputDevice, otherwise it is driven by client's |
| 339 // CaptureCallback. | 352 // CaptureCallback. |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 397 // Inform the local renderer about the stopped device. | 410 // Inform the local renderer about the stopped device. |
| 398 // The renderer can then save resources by not asking for more data from | 411 // The renderer can then save resources by not asking for more data from |
| 399 // the stopped source. We are on the IO thread but the callback task will | 412 // the stopped source. We are on the IO thread but the callback task will |
| 400 // be posted on the message loop of the main render thread thanks to | 413 // be posted on the message loop of the main render thread thanks to |
| 401 // usage of BindToLoop() when the callback was initialized. | 414 // usage of BindToLoop() when the callback was initialized. |
| 402 if (!on_device_stopped_cb_.is_null()) | 415 if (!on_device_stopped_cb_.is_null()) |
| 403 on_device_stopped_cb_.Run(); | 416 on_device_stopped_cb_.Run(); |
| 404 } | 417 } |
| 405 | 418 |
| 406 } // namespace content | 419 } // namespace content |
| OLD | NEW |