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 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
71 public WebRtcAudioCapturerSink { | 71 public WebRtcAudioCapturerSink { |
72 public: | 72 public: |
73 explicit SinkOwner(WebRtcAudioCapturerSink* sink); | 73 explicit SinkOwner(WebRtcAudioCapturerSink* sink); |
74 | 74 |
75 virtual void CaptureData(const int16* audio_data, | 75 virtual void CaptureData(const int16* audio_data, |
76 int number_of_channels, | 76 int number_of_channels, |
77 int number_of_frames, | 77 int number_of_frames, |
78 int audio_delay_milliseconds, | 78 int audio_delay_milliseconds, |
79 double volume) OVERRIDE; | 79 double volume) OVERRIDE; |
80 virtual void SetCaptureFormat(const media::AudioParameters& params) OVERRIDE; | 80 virtual void SetCaptureFormat(const media::AudioParameters& params) OVERRIDE; |
81 virtual void OnCaptureDeviceStopped() OVERRIDE; | |
82 | 81 |
83 bool IsEqual(const WebRtcAudioCapturerSink* other) const; | 82 bool IsEqual(const WebRtcAudioCapturerSink* other) const; |
84 void Reset(); | 83 void Reset(); |
85 | 84 |
86 // Wrapper which allows to use std::find_if() when adding and removing | 85 // Wrapper which allows to use std::find_if() when adding and removing |
87 // sinks to/from the list. | 86 // sinks to/from the list. |
88 struct WrapsSink { | 87 struct WrapsSink { |
89 WrapsSink(WebRtcAudioCapturerSink* sink) : sink_(sink) {} | 88 WrapsSink(WebRtcAudioCapturerSink* sink) : sink_(sink) {} |
90 bool operator()( | 89 bool operator()( |
91 const scoped_refptr<WebRtcAudioCapturer::SinkOwner>& owner) { | 90 const scoped_refptr<WebRtcAudioCapturer::SinkOwner>& owner) { |
(...skipping 27 matching lines...) Expand all Loading... |
119 } | 118 } |
120 } | 119 } |
121 | 120 |
122 void WebRtcAudioCapturer::SinkOwner::SetCaptureFormat( | 121 void WebRtcAudioCapturer::SinkOwner::SetCaptureFormat( |
123 const media::AudioParameters& params) { | 122 const media::AudioParameters& params) { |
124 base::AutoLock lock(lock_); | 123 base::AutoLock lock(lock_); |
125 if (delegate_) | 124 if (delegate_) |
126 delegate_->SetCaptureFormat(params); | 125 delegate_->SetCaptureFormat(params); |
127 } | 126 } |
128 | 127 |
129 void WebRtcAudioCapturer::SinkOwner::OnCaptureDeviceStopped() { | |
130 base::AutoLock lock(lock_); | |
131 if (delegate_) | |
132 delegate_->OnCaptureDeviceStopped(); | |
133 } | |
134 | |
135 bool WebRtcAudioCapturer::SinkOwner::IsEqual( | 128 bool WebRtcAudioCapturer::SinkOwner::IsEqual( |
136 const WebRtcAudioCapturerSink* other) const { | 129 const WebRtcAudioCapturerSink* other) const { |
137 base::AutoLock lock(lock_); | 130 base::AutoLock lock(lock_); |
138 return (other == delegate_); | 131 return (other == delegate_); |
139 } | 132 } |
140 | 133 |
141 void WebRtcAudioCapturer::SinkOwner::Reset() { | 134 void WebRtcAudioCapturer::SinkOwner::Reset() { |
142 base::AutoLock lock(lock_); | 135 base::AutoLock lock(lock_); |
143 delegate_ = NULL; | 136 delegate_ = NULL; |
144 } | 137 } |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
205 } | 198 } |
206 | 199 |
207 // Tell all sinks which format we use. | 200 // Tell all sinks which format we use. |
208 for (SinkList::const_iterator it = sinks.begin(); it != sinks.end(); ++it) | 201 for (SinkList::const_iterator it = sinks.begin(); it != sinks.end(); ++it) |
209 (*it)->SetCaptureFormat(new_buffer->params()); | 202 (*it)->SetCaptureFormat(new_buffer->params()); |
210 | 203 |
211 return true; | 204 return true; |
212 } | 205 } |
213 | 206 |
214 bool WebRtcAudioCapturer::Initialize(media::ChannelLayout channel_layout, | 207 bool WebRtcAudioCapturer::Initialize(media::ChannelLayout channel_layout, |
215 int sample_rate) { | 208 int sample_rate, |
| 209 int session_id) { |
216 DCHECK(thread_checker_.CalledOnValidThread()); | 210 DCHECK(thread_checker_.CalledOnValidThread()); |
217 DCHECK(!sinks_.empty()); | 211 DCHECK(!sinks_.empty()); |
218 DVLOG(1) << "WebRtcAudioCapturer::Initialize()"; | 212 DVLOG(1) << "WebRtcAudioCapturer::Initialize()"; |
219 | 213 |
220 DVLOG(1) << "Audio input hardware channel layout: " << channel_layout; | 214 DVLOG(1) << "Audio input hardware channel layout: " << channel_layout; |
221 UMA_HISTOGRAM_ENUMERATION("WebRTC.AudioInputChannelLayout", | 215 UMA_HISTOGRAM_ENUMERATION("WebRTC.AudioInputChannelLayout", |
222 channel_layout, media::CHANNEL_LAYOUT_MAX); | 216 channel_layout, media::CHANNEL_LAYOUT_MAX); |
223 | 217 |
| 218 session_id_ = session_id; |
| 219 |
224 // Verify that the reported input channel configuration is supported. | 220 // Verify that the reported input channel configuration is supported. |
225 if (channel_layout != media::CHANNEL_LAYOUT_MONO && | 221 if (channel_layout != media::CHANNEL_LAYOUT_MONO && |
226 channel_layout != media::CHANNEL_LAYOUT_STEREO) { | 222 channel_layout != media::CHANNEL_LAYOUT_STEREO) { |
227 DLOG(ERROR) << channel_layout | 223 DLOG(ERROR) << channel_layout |
228 << " is not a supported input channel configuration."; | 224 << " is not a supported input channel configuration."; |
229 return false; | 225 return false; |
230 } | 226 } |
231 | 227 |
232 DVLOG(1) << "Audio input hardware sample rate: " << sample_rate; | 228 DVLOG(1) << "Audio input hardware sample rate: " << sample_rate; |
233 UMA_HISTOGRAM_ENUMERATION("WebRTC.AudioInputSampleRate", | 229 UMA_HISTOGRAM_ENUMERATION("WebRTC.AudioInputSampleRate", |
234 sample_rate, media::kUnexpectedAudioSampleRate); | 230 sample_rate, media::kUnexpectedAudioSampleRate); |
235 | 231 |
236 // Verify that the reported input hardware sample rate is supported | 232 // Verify that the reported input hardware sample rate is supported |
237 // on the current platform. | 233 // on the current platform. |
238 if (std::find(&kValidInputRates[0], | 234 if (std::find(&kValidInputRates[0], |
239 &kValidInputRates[0] + arraysize(kValidInputRates), | 235 &kValidInputRates[0] + arraysize(kValidInputRates), |
240 sample_rate) == | 236 sample_rate) == |
241 &kValidInputRates[arraysize(kValidInputRates)]) { | 237 &kValidInputRates[arraysize(kValidInputRates)]) { |
242 DLOG(ERROR) << sample_rate << " is not a supported input rate."; | 238 DLOG(ERROR) << sample_rate << " is not a supported input rate."; |
243 return false; | 239 return false; |
244 } | 240 } |
245 | 241 |
246 if (!Reconfigure(sample_rate, channel_layout)) | 242 if (!Reconfigure(sample_rate, channel_layout)) |
247 return false; | 243 return false; |
248 | 244 |
249 // Create and configure the default audio capturing source. The |source_| | 245 // Create and configure the default audio capturing source. The |source_| |
250 // will be overwritten if an external client later calls SetCapturerSource() | 246 // will be overwritten if an external client later calls SetCapturerSource() |
251 // providing an alternaive media::AudioCapturerSource. | 247 // providing an alternative media::AudioCapturerSource. |
252 SetCapturerSource(AudioDeviceFactory::NewInputDevice(), | 248 SetCapturerSource(AudioDeviceFactory::NewInputDevice(), |
253 channel_layout, | 249 channel_layout, |
254 static_cast<float>(sample_rate)); | 250 static_cast<float>(sample_rate)); |
255 | 251 |
256 return true; | 252 return true; |
257 } | 253 } |
258 | 254 |
259 WebRtcAudioCapturer::WebRtcAudioCapturer() | 255 WebRtcAudioCapturer::WebRtcAudioCapturer() |
260 : main_loop_(base::MessageLoopProxy::current()), | 256 : source_(NULL), |
261 source_(NULL), | |
262 running_(false), | 257 running_(false), |
263 agc_is_enabled_(false) { | 258 agc_is_enabled_(false), |
| 259 session_id_(0) { |
264 DVLOG(1) << "WebRtcAudioCapturer::WebRtcAudioCapturer()"; | 260 DVLOG(1) << "WebRtcAudioCapturer::WebRtcAudioCapturer()"; |
265 } | 261 } |
266 | 262 |
267 WebRtcAudioCapturer::~WebRtcAudioCapturer() { | 263 WebRtcAudioCapturer::~WebRtcAudioCapturer() { |
268 DCHECK(thread_checker_.CalledOnValidThread()); | 264 DCHECK(thread_checker_.CalledOnValidThread()); |
269 DCHECK(sinks_.empty()); | 265 DCHECK(sinks_.empty()); |
270 DCHECK(!running_); | 266 DCHECK(!running_); |
271 DVLOG(1) << "WebRtcAudioCapturer::~WebRtcAudioCapturer()"; | 267 DVLOG(1) << "WebRtcAudioCapturer::~WebRtcAudioCapturer()"; |
272 } | 268 } |
273 | 269 |
(...skipping 26 matching lines...) Expand all Loading... |
300 (*it)->Reset(); | 296 (*it)->Reset(); |
301 sinks_.erase(it); | 297 sinks_.erase(it); |
302 } | 298 } |
303 } | 299 } |
304 | 300 |
305 void WebRtcAudioCapturer::SetCapturerSource( | 301 void WebRtcAudioCapturer::SetCapturerSource( |
306 const scoped_refptr<media::AudioCapturerSource>& source, | 302 const scoped_refptr<media::AudioCapturerSource>& source, |
307 media::ChannelLayout channel_layout, | 303 media::ChannelLayout channel_layout, |
308 float sample_rate) { | 304 float sample_rate) { |
309 DCHECK(thread_checker_.CalledOnValidThread()); | 305 DCHECK(thread_checker_.CalledOnValidThread()); |
| 306 CHECK_GT(session_id_, 0); |
310 DVLOG(1) << "SetCapturerSource(channel_layout=" << channel_layout << "," | 307 DVLOG(1) << "SetCapturerSource(channel_layout=" << channel_layout << "," |
311 << "sample_rate=" << sample_rate << ")"; | 308 << "sample_rate=" << sample_rate << ")"; |
312 scoped_refptr<media::AudioCapturerSource> old_source; | 309 scoped_refptr<media::AudioCapturerSource> old_source; |
313 scoped_refptr<ConfiguredBuffer> current_buffer; | 310 scoped_refptr<ConfiguredBuffer> current_buffer; |
314 { | 311 { |
315 base::AutoLock auto_lock(lock_); | 312 base::AutoLock auto_lock(lock_); |
316 if (source_ == source) | 313 if (source_ == source) |
317 return; | 314 return; |
318 | 315 |
319 source_.swap(old_source); | 316 source_.swap(old_source); |
(...skipping 19 matching lines...) Expand all Loading... |
339 return; | 336 return; |
340 } else { | 337 } else { |
341 // The buffer has been reconfigured. Update |current_buffer|. | 338 // The buffer has been reconfigured. Update |current_buffer|. |
342 base::AutoLock auto_lock(lock_); | 339 base::AutoLock auto_lock(lock_); |
343 current_buffer = buffer_; | 340 current_buffer = buffer_; |
344 } | 341 } |
345 } | 342 } |
346 | 343 |
347 if (source) { | 344 if (source) { |
348 // Make sure to grab the new parameters in case they were reconfigured. | 345 // Make sure to grab the new parameters in case they were reconfigured. |
349 source->Initialize(current_buffer->params(), this, this); | 346 source->Initialize(current_buffer->params(), this, session_id_); |
350 } | 347 } |
351 } | 348 } |
352 | 349 |
353 void WebRtcAudioCapturer::Start() { | 350 void WebRtcAudioCapturer::Start() { |
354 DVLOG(1) << "WebRtcAudioCapturer::Start()"; | 351 DVLOG(1) << "WebRtcAudioCapturer::Start()"; |
355 base::AutoLock auto_lock(lock_); | 352 base::AutoLock auto_lock(lock_); |
356 if (running_) | 353 if (running_) |
357 return; | 354 return; |
358 | 355 |
359 // Start the data source, i.e., start capturing data from the current source. | 356 // Start the data source, i.e., start capturing data from the current source. |
(...skipping 23 matching lines...) Expand all Loading... |
383 source->Stop(); | 380 source->Stop(); |
384 } | 381 } |
385 | 382 |
386 void WebRtcAudioCapturer::SetVolume(double volume) { | 383 void WebRtcAudioCapturer::SetVolume(double volume) { |
387 DVLOG(1) << "WebRtcAudioCapturer::SetVolume()"; | 384 DVLOG(1) << "WebRtcAudioCapturer::SetVolume()"; |
388 base::AutoLock auto_lock(lock_); | 385 base::AutoLock auto_lock(lock_); |
389 if (source_) | 386 if (source_) |
390 source_->SetVolume(volume); | 387 source_->SetVolume(volume); |
391 } | 388 } |
392 | 389 |
393 void WebRtcAudioCapturer::SetDevice(int session_id) { | |
394 DCHECK(thread_checker_.CalledOnValidThread()); | |
395 DVLOG(1) << "WebRtcAudioCapturer::SetDevice(" << session_id << ")"; | |
396 base::AutoLock auto_lock(lock_); | |
397 if (source_) | |
398 source_->SetDevice(session_id); | |
399 } | |
400 | |
401 void WebRtcAudioCapturer::SetAutomaticGainControl(bool enable) { | 390 void WebRtcAudioCapturer::SetAutomaticGainControl(bool enable) { |
402 base::AutoLock auto_lock(lock_); | 391 base::AutoLock auto_lock(lock_); |
403 // Store the setting since SetAutomaticGainControl() can be called before | 392 // Store the setting since SetAutomaticGainControl() can be called before |
404 // Initialize(), in this case stored setting will be applied in Start(). | 393 // Initialize(), in this case stored setting will be applied in Start(). |
405 agc_is_enabled_ = enable; | 394 agc_is_enabled_ = enable; |
406 | 395 |
407 if (source_) | 396 if (source_) |
408 source_->SetAutomaticGainControl(enable); | 397 source_->SetAutomaticGainControl(enable); |
409 } | 398 } |
410 | 399 |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
443 (*it)->CaptureData(buffer_ref_while_calling->buffer(), | 432 (*it)->CaptureData(buffer_ref_while_calling->buffer(), |
444 audio_source->channels(), audio_source->frames(), | 433 audio_source->channels(), audio_source->frames(), |
445 audio_delay_milliseconds, volume); | 434 audio_delay_milliseconds, volume); |
446 } | 435 } |
447 } | 436 } |
448 | 437 |
449 void WebRtcAudioCapturer::OnCaptureError() { | 438 void WebRtcAudioCapturer::OnCaptureError() { |
450 NOTIMPLEMENTED(); | 439 NOTIMPLEMENTED(); |
451 } | 440 } |
452 | 441 |
453 void WebRtcAudioCapturer::OnDeviceStarted(const std::string& device_id) { | |
454 device_id_ = device_id; | |
455 } | |
456 | |
457 void WebRtcAudioCapturer::OnDeviceStopped() { | |
458 DCHECK_EQ(MessageLoop::current(), ChildProcess::current()->io_message_loop()); | |
459 main_loop_->PostTask( | |
460 FROM_HERE, base::Bind(&WebRtcAudioCapturer::DoOnDeviceStopped, this)); | |
461 } | |
462 | |
463 // TODO(henrika): this implementation should be removed as soon as we add | |
464 // suppport for proper handling of LocalMediaStream::stop(). | |
465 void WebRtcAudioCapturer::DoOnDeviceStopped() { | |
466 DCHECK(thread_checker_.CalledOnValidThread()); | |
467 DVLOG(1) << "WebRtcAudioCapturer::DoOnDeviceStopped()"; | |
468 SinkList sinks; | |
469 { | |
470 base::AutoLock auto_lock(lock_); | |
471 running_ = false; | |
472 sinks = sinks_; | |
473 } | |
474 | |
475 // Inform registered sinks about the stopped device so they can take | |
476 // appropriate actions. | |
477 for (SinkList::const_iterator it = sinks.begin(); it != sinks.end(); ++it) | |
478 (*it)->OnCaptureDeviceStopped(); | |
479 } | |
480 | |
481 media::AudioParameters WebRtcAudioCapturer::audio_parameters() const { | 442 media::AudioParameters WebRtcAudioCapturer::audio_parameters() const { |
482 base::AutoLock auto_lock(lock_); | 443 base::AutoLock auto_lock(lock_); |
483 return buffer_->params(); | 444 return buffer_->params(); |
484 } | 445 } |
485 | 446 |
486 } // namespace content | 447 } // namespace content |
OLD | NEW |