OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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_device_impl.h" | 5 #include "content/renderer/media/webrtc_audio_device_impl.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/metrics/histogram.h" | 8 #include "base/metrics/histogram.h" |
9 #include "base/string_util.h" | 9 #include "base/string_util.h" |
10 #include "base/win/windows_version.h" | 10 #include "base/win/windows_version.h" |
(...skipping 202 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
213 return 0; | 213 return 0; |
214 } | 214 } |
215 | 215 |
216 int32_t WebRtcAudioDeviceImpl::Init() { | 216 int32_t WebRtcAudioDeviceImpl::Init() { |
217 DVLOG(1) << "WebRtcAudioDeviceImpl::Init()"; | 217 DVLOG(1) << "WebRtcAudioDeviceImpl::Init()"; |
218 DCHECK(thread_checker_.CalledOnValidThread()); | 218 DCHECK(thread_checker_.CalledOnValidThread()); |
219 | 219 |
220 if (initialized_) | 220 if (initialized_) |
221 return 0; | 221 return 0; |
222 | 222 |
223 DCHECK(!capturer_); | 223 DCHECK(!capturer_.get()); |
224 capturer_ = WebRtcAudioCapturer::CreateCapturer(); | 224 capturer_ = WebRtcAudioCapturer::CreateCapturer(); |
225 // Add itself as an audio track to the |capturer_|. This is because WebRTC | 225 // Add itself as an audio track to the |capturer_|. This is because WebRTC |
226 // supports only one ADM but multiple audio tracks, so the ADM can't be the | 226 // supports only one ADM but multiple audio tracks, so the ADM can't be the |
227 // sink of certain audio track now. | 227 // sink of certain audio track now. |
228 // TODO(xians): Register the ADM as the sink of the audio track if WebRTC | 228 // TODO(xians): Register the ADM as the sink of the audio track if WebRTC |
229 // supports one ADM for each audio track. | 229 // supports one ADM for each audio track. |
230 if (capturer_) | 230 if (capturer_.get()) |
231 capturer_->AddSink(this); | 231 capturer_->AddSink(this); |
232 | 232 |
233 // We need to return a success to continue the initialization of WebRtc VoE | 233 // We need to return a success to continue the initialization of WebRtc VoE |
234 // because failure on the capturer_ initialization should not prevent WebRTC | 234 // because failure on the capturer_ initialization should not prevent WebRTC |
235 // from working. See issue http://crbug.com/144421 for details. | 235 // from working. See issue http://crbug.com/144421 for details. |
236 initialized_ = true; | 236 initialized_ = true; |
237 | 237 |
238 return 0; | 238 return 0; |
239 } | 239 } |
240 | 240 |
241 int32_t WebRtcAudioDeviceImpl::Terminate() { | 241 int32_t WebRtcAudioDeviceImpl::Terminate() { |
242 DVLOG(1) << "WebRtcAudioDeviceImpl::Terminate()"; | 242 DVLOG(1) << "WebRtcAudioDeviceImpl::Terminate()"; |
243 DCHECK(thread_checker_.CalledOnValidThread()); | 243 DCHECK(thread_checker_.CalledOnValidThread()); |
244 | 244 |
245 // Calling Terminate() multiple times in a row is OK. | 245 // Calling Terminate() multiple times in a row is OK. |
246 if (!initialized_) | 246 if (!initialized_) |
247 return 0; | 247 return 0; |
248 | 248 |
249 StopRecording(); | 249 StopRecording(); |
250 StopPlayout(); | 250 StopPlayout(); |
251 | 251 |
252 // It is necessary to stop the |renderer_| before going away. | 252 // It is necessary to stop the |renderer_| before going away. |
253 if (renderer_) { | 253 if (renderer_.get()) { |
254 // Grab a local reference while we call Stop(), which will trigger a call to | 254 // Grab a local reference while we call Stop(), which will trigger a call to |
255 // RemoveAudioRenderer that clears our reference to the audio renderer. | 255 // RemoveAudioRenderer that clears our reference to the audio renderer. |
256 scoped_refptr<WebRtcAudioRenderer> local_renderer(renderer_); | 256 scoped_refptr<WebRtcAudioRenderer> local_renderer(renderer_); |
257 local_renderer->Stop(); | 257 local_renderer->Stop(); |
258 DCHECK(!renderer_); | 258 DCHECK(!renderer_.get()); |
259 } | 259 } |
260 | 260 |
261 if (capturer_) { | 261 if (capturer_.get()) { |
262 // |capturer_| is stopped by the media stream, so do not need to | 262 // |capturer_| is stopped by the media stream, so do not need to |
263 // call Stop() here. | 263 // call Stop() here. |
264 capturer_->RemoveSink(this); | 264 capturer_->RemoveSink(this); |
265 capturer_ = NULL; | 265 capturer_ = NULL; |
266 } | 266 } |
267 | 267 |
268 initialized_ = false; | 268 initialized_ = false; |
269 return 0; | 269 return 0; |
270 } | 270 } |
271 | 271 |
272 bool WebRtcAudioDeviceImpl::Initialized() const { | 272 bool WebRtcAudioDeviceImpl::Initialized() const { |
273 return initialized_; | 273 return initialized_; |
274 } | 274 } |
275 | 275 |
276 int32_t WebRtcAudioDeviceImpl::PlayoutIsAvailable(bool* available) { | 276 int32_t WebRtcAudioDeviceImpl::PlayoutIsAvailable(bool* available) { |
277 *available = initialized_; | 277 *available = initialized_; |
278 return 0; | 278 return 0; |
279 } | 279 } |
280 | 280 |
281 bool WebRtcAudioDeviceImpl::PlayoutIsInitialized() const { | 281 bool WebRtcAudioDeviceImpl::PlayoutIsInitialized() const { |
282 return initialized_; | 282 return initialized_; |
283 } | 283 } |
284 | 284 |
285 int32_t WebRtcAudioDeviceImpl::RecordingIsAvailable(bool* available) { | 285 int32_t WebRtcAudioDeviceImpl::RecordingIsAvailable(bool* available) { |
286 *available = (capturer_ != NULL); | 286 *available = (capturer_.get() != NULL); |
287 return 0; | 287 return 0; |
288 } | 288 } |
289 | 289 |
290 bool WebRtcAudioDeviceImpl::RecordingIsInitialized() const { | 290 bool WebRtcAudioDeviceImpl::RecordingIsInitialized() const { |
291 DVLOG(1) << "WebRtcAudioDeviceImpl::RecordingIsInitialized()"; | 291 DVLOG(1) << "WebRtcAudioDeviceImpl::RecordingIsInitialized()"; |
292 DCHECK(thread_checker_.CalledOnValidThread()); | 292 DCHECK(thread_checker_.CalledOnValidThread()); |
293 return (capturer_ != NULL); | 293 return (capturer_.get() != NULL); |
294 } | 294 } |
295 | 295 |
296 int32_t WebRtcAudioDeviceImpl::StartPlayout() { | 296 int32_t WebRtcAudioDeviceImpl::StartPlayout() { |
297 DVLOG(1) << "WebRtcAudioDeviceImpl::StartPlayout()"; | 297 DVLOG(1) << "WebRtcAudioDeviceImpl::StartPlayout()"; |
298 LOG_IF(ERROR, !audio_transport_callback_) << "Audio transport is missing"; | 298 LOG_IF(ERROR, !audio_transport_callback_) << "Audio transport is missing"; |
299 { | 299 { |
300 base::AutoLock auto_lock(lock_); | 300 base::AutoLock auto_lock(lock_); |
301 if (!audio_transport_callback_) | 301 if (!audio_transport_callback_) |
302 return 0; | 302 return 0; |
303 } | 303 } |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
379 DVLOG(1) << "WebRtcAudioDeviceImpl::SetAGC(enable=" << enable << ")"; | 379 DVLOG(1) << "WebRtcAudioDeviceImpl::SetAGC(enable=" << enable << ")"; |
380 DCHECK(initialized_); | 380 DCHECK(initialized_); |
381 | 381 |
382 // Return early if we are not changing the AGC state. | 382 // Return early if we are not changing the AGC state. |
383 if (enable == agc_is_enabled_) | 383 if (enable == agc_is_enabled_) |
384 return 0; | 384 return 0; |
385 | 385 |
386 // The current implementation does not support changing the AGC state while | 386 // The current implementation does not support changing the AGC state while |
387 // recording. Using this approach simplifies the design and it is also | 387 // recording. Using this approach simplifies the design and it is also |
388 // inline with the latest WebRTC standard. | 388 // inline with the latest WebRTC standard. |
389 if (!capturer_ || capturer_->is_recording()) | 389 if (!capturer_.get() || capturer_->is_recording()) |
390 return -1; | 390 return -1; |
391 | 391 |
392 capturer_->SetAutomaticGainControl(enable); | 392 capturer_->SetAutomaticGainControl(enable); |
393 agc_is_enabled_ = enable; | 393 agc_is_enabled_ = enable; |
394 return 0; | 394 return 0; |
395 } | 395 } |
396 | 396 |
397 bool WebRtcAudioDeviceImpl::AGC() const { | 397 bool WebRtcAudioDeviceImpl::AGC() const { |
398 DVLOG(1) << "WebRtcAudioDeviceImpl::AGC()"; | 398 DVLOG(1) << "WebRtcAudioDeviceImpl::AGC()"; |
399 DCHECK(thread_checker_.CalledOnValidThread()); | 399 DCHECK(thread_checker_.CalledOnValidThread()); |
400 // To reduce the usage of IPC messages, an internal AGC state is used. | 400 // To reduce the usage of IPC messages, an internal AGC state is used. |
401 // TODO(henrika): investigate if there is a need for a "deeper" getter. | 401 // TODO(henrika): investigate if there is a need for a "deeper" getter. |
402 return agc_is_enabled_; | 402 return agc_is_enabled_; |
403 } | 403 } |
404 | 404 |
405 int32_t WebRtcAudioDeviceImpl::SetMicrophoneVolume(uint32_t volume) { | 405 int32_t WebRtcAudioDeviceImpl::SetMicrophoneVolume(uint32_t volume) { |
406 DVLOG(1) << "WebRtcAudioDeviceImpl::SetMicrophoneVolume(" << volume << ")"; | 406 DVLOG(1) << "WebRtcAudioDeviceImpl::SetMicrophoneVolume(" << volume << ")"; |
407 DCHECK(initialized_); | 407 DCHECK(initialized_); |
408 if (!capturer_) | 408 if (!capturer_.get()) |
409 return -1; | 409 return -1; |
410 | 410 |
411 if (volume > kMaxVolumeLevel) | 411 if (volume > kMaxVolumeLevel) |
412 return -1; | 412 return -1; |
413 | 413 |
414 // WebRTC uses a range of [0, 255] to represent the level of the microphone | 414 // WebRTC uses a range of [0, 255] to represent the level of the microphone |
415 // volume. The IPC channel between the renderer and browser process works | 415 // volume. The IPC channel between the renderer and browser process works |
416 // with doubles in the [0.0, 1.0] range and we have to compensate for that. | 416 // with doubles in the [0.0, 1.0] range and we have to compensate for that. |
417 double normalized_volume = static_cast<double>(volume) / kMaxVolumeLevel; | 417 double normalized_volume = static_cast<double>(volume) / kMaxVolumeLevel; |
418 capturer_->SetVolume(normalized_volume); | 418 capturer_->SetVolume(normalized_volume); |
419 return 0; | 419 return 0; |
420 } | 420 } |
421 | 421 |
422 // TODO(henrika): sort out calling thread once we start using this API. | 422 // TODO(henrika): sort out calling thread once we start using this API. |
423 int32_t WebRtcAudioDeviceImpl::MicrophoneVolume(uint32_t* volume) const { | 423 int32_t WebRtcAudioDeviceImpl::MicrophoneVolume(uint32_t* volume) const { |
424 DVLOG(1) << "WebRtcAudioDeviceImpl::MicrophoneVolume()"; | 424 DVLOG(1) << "WebRtcAudioDeviceImpl::MicrophoneVolume()"; |
425 // The microphone level is fed to this class using the Capture() callback | 425 // The microphone level is fed to this class using the Capture() callback |
426 // and cached in the same method, i.e. we don't ask the native audio layer | 426 // and cached in the same method, i.e. we don't ask the native audio layer |
427 // for the actual micropone level here. | 427 // for the actual micropone level here. |
428 DCHECK(initialized_); | 428 DCHECK(initialized_); |
429 if (!capturer_) | 429 if (!capturer_.get()) |
430 return -1; | 430 return -1; |
431 base::AutoLock auto_lock(lock_); | 431 base::AutoLock auto_lock(lock_); |
432 *volume = microphone_volume_; | 432 *volume = microphone_volume_; |
433 return 0; | 433 return 0; |
434 } | 434 } |
435 | 435 |
436 int32_t WebRtcAudioDeviceImpl::MaxMicrophoneVolume(uint32_t* max_volume) const { | 436 int32_t WebRtcAudioDeviceImpl::MaxMicrophoneVolume(uint32_t* max_volume) const { |
437 *max_volume = kMaxVolumeLevel; | 437 *max_volume = kMaxVolumeLevel; |
438 return 0; | 438 return 0; |
439 } | 439 } |
440 | 440 |
441 int32_t WebRtcAudioDeviceImpl::MinMicrophoneVolume(uint32_t* min_volume) const { | 441 int32_t WebRtcAudioDeviceImpl::MinMicrophoneVolume(uint32_t* min_volume) const { |
442 *min_volume = 0; | 442 *min_volume = 0; |
443 return 0; | 443 return 0; |
444 } | 444 } |
445 | 445 |
446 int32_t WebRtcAudioDeviceImpl::StereoPlayoutIsAvailable(bool* available) const { | 446 int32_t WebRtcAudioDeviceImpl::StereoPlayoutIsAvailable(bool* available) const { |
447 DCHECK(initialized_); | 447 DCHECK(initialized_); |
448 *available = (output_channels() == 2); | 448 *available = (output_channels() == 2); |
449 return 0; | 449 return 0; |
450 } | 450 } |
451 | 451 |
452 int32_t WebRtcAudioDeviceImpl::StereoRecordingIsAvailable( | 452 int32_t WebRtcAudioDeviceImpl::StereoRecordingIsAvailable( |
453 bool* available) const { | 453 bool* available) const { |
454 DCHECK(initialized_); | 454 DCHECK(initialized_); |
455 if (!capturer_) | 455 if (!capturer_.get()) |
456 return -1; | 456 return -1; |
457 *available = (input_channels() == 2); | 457 *available = (input_channels() == 2); |
458 return 0; | 458 return 0; |
459 } | 459 } |
460 | 460 |
461 int32_t WebRtcAudioDeviceImpl::PlayoutDelay(uint16_t* delay_ms) const { | 461 int32_t WebRtcAudioDeviceImpl::PlayoutDelay(uint16_t* delay_ms) const { |
462 base::AutoLock auto_lock(lock_); | 462 base::AutoLock auto_lock(lock_); |
463 *delay_ms = static_cast<uint16_t>(output_delay_ms_); | 463 *delay_ms = static_cast<uint16_t>(output_delay_ms_); |
464 return 0; | 464 return 0; |
465 } | 465 } |
(...skipping 14 matching lines...) Expand all Loading... |
480 uint32_t* samples_per_sec) const { | 480 uint32_t* samples_per_sec) const { |
481 *samples_per_sec = static_cast<uint32_t>(output_sample_rate()); | 481 *samples_per_sec = static_cast<uint32_t>(output_sample_rate()); |
482 return 0; | 482 return 0; |
483 } | 483 } |
484 | 484 |
485 bool WebRtcAudioDeviceImpl::SetAudioRenderer(WebRtcAudioRenderer* renderer) { | 485 bool WebRtcAudioDeviceImpl::SetAudioRenderer(WebRtcAudioRenderer* renderer) { |
486 DCHECK(thread_checker_.CalledOnValidThread()); | 486 DCHECK(thread_checker_.CalledOnValidThread()); |
487 DCHECK(renderer); | 487 DCHECK(renderer); |
488 | 488 |
489 base::AutoLock auto_lock(lock_); | 489 base::AutoLock auto_lock(lock_); |
490 if (renderer_) | 490 if (renderer_.get()) |
491 return false; | 491 return false; |
492 | 492 |
493 if (!renderer->Initialize(this)) | 493 if (!renderer->Initialize(this)) |
494 return false; | 494 return false; |
495 | 495 |
496 renderer_ = renderer; | 496 renderer_ = renderer; |
497 return true; | 497 return true; |
498 } | 498 } |
499 | 499 |
500 } // namespace content | 500 } // namespace content |
OLD | NEW |