Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(12)

Side by Side Diff: content/renderer/media/webrtc_audio_renderer.cc

Issue 1809093003: Moving SwitchOutputDevice out of OutputDevice interface, eliminating OutputDevice (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: rebase Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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_renderer.h" 5 #include "content/renderer/media/webrtc_audio_renderer.h"
6 6
7 #include <utility> 7 #include <utility>
8 8
9 #include "base/logging.h" 9 #include "base/logging.h"
10 #include "base/metrics/histogram.h" 10 #include "base/metrics/histogram.h"
11 #include "base/strings/string_util.h" 11 #include "base/strings/string_util.h"
12 #include "base/strings/stringprintf.h" 12 #include "base/strings/stringprintf.h"
13 #include "build/build_config.h" 13 #include "build/build_config.h"
14 #include "content/renderer/media/audio_device_factory.h" 14 #include "content/renderer/media/audio_device_factory.h"
15 #include "content/renderer/media/media_stream_audio_track.h" 15 #include "content/renderer/media/media_stream_audio_track.h"
16 #include "content/renderer/media/media_stream_dispatcher.h" 16 #include "content/renderer/media/media_stream_dispatcher.h"
17 #include "content/renderer/media/media_stream_track.h" 17 #include "content/renderer/media/media_stream_track.h"
18 #include "content/renderer/media/webrtc_audio_device_impl.h" 18 #include "content/renderer/media/webrtc_audio_device_impl.h"
19 #include "content/renderer/media/webrtc_logging.h" 19 #include "content/renderer/media/webrtc_logging.h"
20 #include "content/renderer/render_frame_impl.h" 20 #include "content/renderer/render_frame_impl.h"
21 #include "media/audio/audio_parameters.h" 21 #include "media/audio/audio_parameters.h"
22 #include "media/audio/sample_rates.h" 22 #include "media/audio/sample_rates.h"
23 #include "media/base/audio_capturer_source.h"
23 #include "third_party/WebKit/public/platform/WebMediaStreamTrack.h" 24 #include "third_party/WebKit/public/platform/WebMediaStreamTrack.h"
24 #include "third_party/webrtc/api/mediastreaminterface.h" 25 #include "third_party/webrtc/api/mediastreaminterface.h"
25 #include "third_party/webrtc/media/base/audiorenderer.h" 26 #include "third_party/webrtc/media/base/audiorenderer.h"
26 27
27 #if defined(OS_WIN) 28 #if defined(OS_WIN)
28 #include "base/win/windows_version.h" 29 #include "base/win/windows_version.h"
29 #include "media/audio/win/core_audio_util_win.h" 30 #include "media/audio/win/core_audio_util_win.h"
30 #endif 31 #endif
31 32
32 namespace content { 33 namespace content {
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
111 delegate_->Stop(); 112 delegate_->Stop();
112 } 113 }
113 114
114 void SetVolume(float volume) override { 115 void SetVolume(float volume) override {
115 DCHECK(thread_checker_.CalledOnValidThread()); 116 DCHECK(thread_checker_.CalledOnValidThread());
116 DCHECK(volume >= 0.0f && volume <= 1.0f); 117 DCHECK(volume >= 0.0f && volume <= 1.0f);
117 playing_state_.set_volume(volume); 118 playing_state_.set_volume(volume);
118 on_play_state_changed_.Run(media_stream_, &playing_state_); 119 on_play_state_changed_.Run(media_stream_, &playing_state_);
119 } 120 }
120 121
121 media::OutputDevice* GetOutputDevice() override { 122 media::OutputDeviceInfo GetOutputDeviceInfo() override {
122 DCHECK(thread_checker_.CalledOnValidThread()); 123 DCHECK(thread_checker_.CalledOnValidThread());
123 return delegate_->GetOutputDevice(); 124 return delegate_->GetOutputDeviceInfo();
125 }
126
127 void SwitchOutputDevice(
128 const std::string& device_id,
129 const url::Origin& security_origin,
130 const media::OutputDeviceStatusCB& callback) override {
131 DCHECK(thread_checker_.CalledOnValidThread());
132 return delegate_->SwitchOutputDevice(device_id, security_origin, callback);
124 } 133 }
125 134
126 base::TimeDelta GetCurrentRenderTime() const override { 135 base::TimeDelta GetCurrentRenderTime() const override {
127 DCHECK(thread_checker_.CalledOnValidThread()); 136 DCHECK(thread_checker_.CalledOnValidThread());
128 return delegate_->GetCurrentRenderTime(); 137 return delegate_->GetCurrentRenderTime();
129 } 138 }
130 139
131 bool IsLocalRenderer() const override { 140 bool IsLocalRenderer() const override {
132 DCHECK(thread_checker_.CalledOnValidThread()); 141 DCHECK(thread_checker_.CalledOnValidThread());
133 return delegate_->IsLocalRenderer(); 142 return delegate_->IsLocalRenderer();
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after
217 { 226 {
218 base::AutoLock auto_lock(lock_); 227 base::AutoLock auto_lock(lock_);
219 DCHECK_EQ(state_, UNINITIALIZED); 228 DCHECK_EQ(state_, UNINITIALIZED);
220 DCHECK(!source_); 229 DCHECK(!source_);
221 } 230 }
222 231
223 sink_ = AudioDeviceFactory::NewAudioRendererSink( 232 sink_ = AudioDeviceFactory::NewAudioRendererSink(
224 AudioDeviceFactory::kSourceWebRtc, source_render_frame_id_, session_id_, 233 AudioDeviceFactory::kSourceWebRtc, source_render_frame_id_, session_id_,
225 output_device_id_, security_origin_); 234 output_device_id_, security_origin_);
226 235
227 if (sink_->GetOutputDevice()->GetDeviceStatus() != 236 if (sink_->GetOutputDeviceInfo().device_status() !=
228 media::OUTPUT_DEVICE_STATUS_OK) { 237 media::OUTPUT_DEVICE_STATUS_OK) {
229 return false; 238 return false;
230 } 239 }
231 240
232 PrepareSink(); 241 PrepareSink();
233 { 242 {
234 // No need to reassert the preconditions because the other thread accessing 243 // No need to reassert the preconditions because the other thread accessing
235 // the fields (checked by |audio_renderer_thread_checker_|) only reads them. 244 // the fields (checked by |audio_renderer_thread_checker_|) only reads them.
236 base::AutoLock auto_lock(lock_); 245 base::AutoLock auto_lock(lock_);
237 source_ = source; 246 source_ = source;
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after
348 } 357 }
349 358
350 void WebRtcAudioRenderer::SetVolume(float volume) { 359 void WebRtcAudioRenderer::SetVolume(float volume) {
351 DCHECK(thread_checker_.CalledOnValidThread()); 360 DCHECK(thread_checker_.CalledOnValidThread());
352 DCHECK(volume >= 0.0f && volume <= 1.0f); 361 DCHECK(volume >= 0.0f && volume <= 1.0f);
353 362
354 playing_state_.set_volume(volume); 363 playing_state_.set_volume(volume);
355 OnPlayStateChanged(media_stream_, &playing_state_); 364 OnPlayStateChanged(media_stream_, &playing_state_);
356 } 365 }
357 366
358 media::OutputDevice* WebRtcAudioRenderer::GetOutputDevice() { 367 media::OutputDeviceInfo WebRtcAudioRenderer::GetOutputDeviceInfo() {
359 DCHECK(thread_checker_.CalledOnValidThread()); 368 DCHECK(thread_checker_.CalledOnValidThread());
360 return this; 369 return sink_ ? sink_->GetOutputDeviceInfo() : media::OutputDeviceInfo();
361 } 370 }
362 371
363 base::TimeDelta WebRtcAudioRenderer::GetCurrentRenderTime() const { 372 base::TimeDelta WebRtcAudioRenderer::GetCurrentRenderTime() const {
364 DCHECK(thread_checker_.CalledOnValidThread()); 373 DCHECK(thread_checker_.CalledOnValidThread());
365 base::AutoLock auto_lock(lock_); 374 base::AutoLock auto_lock(lock_);
366 return current_time_; 375 return current_time_;
367 } 376 }
368 377
369 bool WebRtcAudioRenderer::IsLocalRenderer() const { 378 bool WebRtcAudioRenderer::IsLocalRenderer() const {
370 return false; 379 return false;
371 } 380 }
372 381
373 void WebRtcAudioRenderer::SwitchOutputDevice( 382 void WebRtcAudioRenderer::SwitchOutputDevice(
374 const std::string& device_id, 383 const std::string& device_id,
375 const url::Origin& security_origin, 384 const url::Origin& security_origin,
376 const media::SwitchOutputDeviceCB& callback) { 385 const media::OutputDeviceStatusCB& callback) {
377 DVLOG(1) << "WebRtcAudioRenderer::SwitchOutputDevice()"; 386 DVLOG(1) << "WebRtcAudioRenderer::SwitchOutputDevice()";
378 DCHECK(thread_checker_.CalledOnValidThread()); 387 DCHECK(thread_checker_.CalledOnValidThread());
379 DCHECK_GE(session_id_, 0); 388 DCHECK_GE(session_id_, 0);
380 { 389 {
381 base::AutoLock auto_lock(lock_); 390 base::AutoLock auto_lock(lock_);
382 DCHECK(source_); 391 DCHECK(source_);
383 DCHECK_NE(state_, UNINITIALIZED); 392 DCHECK_NE(state_, UNINITIALIZED);
384 } 393 }
385 394
386 scoped_refptr<media::AudioRendererSink> new_sink = 395 scoped_refptr<media::AudioRendererSink> new_sink =
387 AudioDeviceFactory::NewAudioRendererSink( 396 AudioDeviceFactory::NewAudioRendererSink(
388 AudioDeviceFactory::kSourceWebRtc, source_render_frame_id_, 397 AudioDeviceFactory::kSourceWebRtc, source_render_frame_id_,
389 session_id_, device_id, security_origin); 398 session_id_, device_id, security_origin);
390 if (new_sink->GetOutputDevice()->GetDeviceStatus() != 399 media::OutputDeviceStatus status =
391 media::OUTPUT_DEVICE_STATUS_OK) { 400 new_sink->GetOutputDeviceInfo().device_status();
392 callback.Run(new_sink->GetOutputDevice()->GetDeviceStatus()); 401 if (status != media::OUTPUT_DEVICE_STATUS_OK) {
402 callback.Run(status);
393 return; 403 return;
394 } 404 }
395 405
396 // Make sure to stop the sink while _not_ holding the lock since the Render() 406 // Make sure to stop the sink while _not_ holding the lock since the Render()
397 // callback may currently be executing and trying to grab the lock while we're 407 // callback may currently be executing and trying to grab the lock while we're
398 // stopping the thread on which it runs. 408 // stopping the thread on which it runs.
399 sink_->Stop(); 409 sink_->Stop();
400 audio_renderer_thread_checker_.DetachFromThread(); 410 audio_renderer_thread_checker_.DetachFromThread();
401 sink_ = new_sink; 411 sink_ = new_sink;
402 output_device_id_ = device_id; 412 output_device_id_ = device_id;
403 security_origin_ = security_origin; 413 security_origin_ = security_origin;
404 { 414 {
405 base::AutoLock auto_lock(lock_); 415 base::AutoLock auto_lock(lock_);
406 source_->AudioRendererThreadStopped(); 416 source_->AudioRendererThreadStopped();
407 } 417 }
408 PrepareSink(); 418 PrepareSink();
409 sink_->Start(); 419 sink_->Start();
410 420
411 callback.Run(media::OUTPUT_DEVICE_STATUS_OK); 421 callback.Run(media::OUTPUT_DEVICE_STATUS_OK);
412 } 422 }
413 423
414 media::AudioParameters WebRtcAudioRenderer::GetOutputParameters() {
415 DCHECK(thread_checker_.CalledOnValidThread());
416 if (!sink_.get())
417 return media::AudioParameters();
418
419 return sink_->GetOutputDevice()->GetOutputParameters();
420 }
421
422 media::OutputDeviceStatus WebRtcAudioRenderer::GetDeviceStatus() {
423 DCHECK(thread_checker_.CalledOnValidThread());
424 if (!sink_.get())
425 return media::OUTPUT_DEVICE_STATUS_ERROR_INTERNAL;
426
427 return sink_->GetOutputDevice()->GetDeviceStatus();
428 }
429
430 int WebRtcAudioRenderer::Render(media::AudioBus* audio_bus, 424 int WebRtcAudioRenderer::Render(media::AudioBus* audio_bus,
431 uint32_t frames_delayed, 425 uint32_t frames_delayed,
432 uint32_t frames_skipped) { 426 uint32_t frames_skipped) {
433 DCHECK(audio_renderer_thread_checker_.CalledOnValidThread()); 427 DCHECK(audio_renderer_thread_checker_.CalledOnValidThread());
434 base::AutoLock auto_lock(lock_); 428 base::AutoLock auto_lock(lock_);
435 if (!source_) 429 if (!source_)
436 return 0; 430 return 0;
437 431
438 // TODO(grunell): Converting from frames to milliseconds will potentially lose 432 // TODO(grunell): Converting from frames to milliseconds will potentially lose
439 // hundreds of microseconds which may cause audio video drift. Update 433 // hundreds of microseconds which may cause audio video drift. Update
(...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after
620 } 614 }
621 } 615 }
622 616
623 void WebRtcAudioRenderer::PrepareSink() { 617 void WebRtcAudioRenderer::PrepareSink() {
624 DCHECK(thread_checker_.CalledOnValidThread()); 618 DCHECK(thread_checker_.CalledOnValidThread());
625 media::AudioParameters new_sink_params; 619 media::AudioParameters new_sink_params;
626 { 620 {
627 base::AutoLock lock(lock_); 621 base::AutoLock lock(lock_);
628 new_sink_params = sink_params_; 622 new_sink_params = sink_params_;
629 } 623 }
624
625 const media::OutputDeviceInfo& device_info = sink_->GetOutputDeviceInfo();
626 DCHECK_EQ(device_info.device_status(), media::OUTPUT_DEVICE_STATUS_OK);
627
630 // WebRTC does not yet support higher rates than 96000 on the client side 628 // WebRTC does not yet support higher rates than 96000 on the client side
631 // and 48000 is the preferred sample rate. Therefore, if 192000 is detected, 629 // and 48000 is the preferred sample rate. Therefore, if 192000 is detected,
632 // we change the rate to 48000 instead. The consequence is that the native 630 // we change the rate to 48000 instead. The consequence is that the native
633 // layer will be opened up at 192kHz but WebRTC will provide data at 48kHz 631 // layer will be opened up at 192kHz but WebRTC will provide data at 48kHz
634 // which will then be resampled by the audio converted on the browser side 632 // which will then be resampled by the audio converted on the browser side
635 // to match the native audio layer. 633 // to match the native audio layer.
636 int sample_rate = 634 int sample_rate = device_info.output_params().sample_rate();
637 sink_->GetOutputDevice()->GetOutputParameters().sample_rate();
638 DVLOG(1) << "Audio output hardware sample rate: " << sample_rate; 635 DVLOG(1) << "Audio output hardware sample rate: " << sample_rate;
639 if (sample_rate >= 192000) { 636 if (sample_rate >= 192000) {
640 DVLOG(1) << "Resampling from 48000 to " << sample_rate << " is required"; 637 DVLOG(1) << "Resampling from 48000 to " << sample_rate << " is required";
641 sample_rate = 48000; 638 sample_rate = 48000;
642 } 639 }
643 media::AudioSampleRate asr; 640 media::AudioSampleRate asr;
644 if (media::ToAudioSampleRate(sample_rate, &asr)) { 641 if (media::ToAudioSampleRate(sample_rate, &asr)) {
645 UMA_HISTOGRAM_ENUMERATION("WebRTC.AudioOutputSampleRate", asr, 642 UMA_HISTOGRAM_ENUMERATION("WebRTC.AudioOutputSampleRate", asr,
646 media::kAudioSampleRateMax + 1); 643 media::kAudioSampleRateMax + 1);
647 } else { 644 } else {
648 UMA_HISTOGRAM_COUNTS("WebRTC.AudioOutputSampleRateUnexpected", sample_rate); 645 UMA_HISTOGRAM_COUNTS("WebRTC.AudioOutputSampleRateUnexpected", sample_rate);
649 } 646 }
650 647
651 // Calculate the frames per buffer for the source, i.e. the WebRTC client. We 648 // Calculate the frames per buffer for the source, i.e. the WebRTC client. We
652 // use 10 ms of data since the WebRTC client only supports multiples of 10 ms 649 // use 10 ms of data since the WebRTC client only supports multiples of 10 ms
653 // as buffer size where 10 ms is preferred for lowest possible delay. 650 // as buffer size where 10 ms is preferred for lowest possible delay.
654 const int source_frames_per_buffer = (sample_rate / 100); 651 const int source_frames_per_buffer = (sample_rate / 100);
655 DVLOG(1) << "Using WebRTC output buffer size: " << source_frames_per_buffer; 652 DVLOG(1) << "Using WebRTC output buffer size: " << source_frames_per_buffer;
656 653
657 // Setup sink parameters. 654 // Setup sink parameters.
658 const int sink_frames_per_buffer = GetOptimalBufferSize( 655 const int sink_frames_per_buffer = GetOptimalBufferSize(
659 sample_rate, 656 sample_rate, device_info.output_params().frames_per_buffer());
660 sink_->GetOutputDevice()->GetOutputParameters().frames_per_buffer());
661 new_sink_params.set_sample_rate(sample_rate); 657 new_sink_params.set_sample_rate(sample_rate);
662 new_sink_params.set_frames_per_buffer(sink_frames_per_buffer); 658 new_sink_params.set_frames_per_buffer(sink_frames_per_buffer);
663 659
664 // Create a FIFO if re-buffering is required to match the source input with 660 // Create a FIFO if re-buffering is required to match the source input with
665 // the sink request. The source acts as provider here and the sink as 661 // the sink request. The source acts as provider here and the sink as
666 // consumer. 662 // consumer.
667 const bool different_source_sink_frames = 663 const bool different_source_sink_frames =
668 source_frames_per_buffer != new_sink_params.frames_per_buffer(); 664 source_frames_per_buffer != new_sink_params.frames_per_buffer();
669 if (different_source_sink_frames) { 665 if (different_source_sink_frames) {
670 DVLOG(1) << "Rebuffering from " << source_frames_per_buffer << " to " 666 DVLOG(1) << "Rebuffering from " << source_frames_per_buffer << " to "
671 << new_sink_params.frames_per_buffer(); 667 << new_sink_params.frames_per_buffer();
672 } 668 }
673 { 669 {
674 base::AutoLock lock(lock_); 670 base::AutoLock lock(lock_);
675 if ((!audio_fifo_ && different_source_sink_frames) || 671 if ((!audio_fifo_ && different_source_sink_frames) ||
676 (audio_fifo_ && 672 (audio_fifo_ &&
677 audio_fifo_->SizeInFrames() != source_frames_per_buffer)) { 673 audio_fifo_->SizeInFrames() != source_frames_per_buffer)) {
678 audio_fifo_.reset(new media::AudioPullFifo( 674 audio_fifo_.reset(new media::AudioPullFifo(
679 kChannels, source_frames_per_buffer, 675 kChannels, source_frames_per_buffer,
680 base::Bind(&WebRtcAudioRenderer::SourceCallback, 676 base::Bind(&WebRtcAudioRenderer::SourceCallback,
681 base::Unretained(this)))); 677 base::Unretained(this))));
682 } 678 }
683 sink_params_ = new_sink_params; 679 sink_params_ = new_sink_params;
684 } 680 }
685 681
686 sink_->Initialize(new_sink_params, this); 682 sink_->Initialize(new_sink_params, this);
687 } 683 }
688 684
689 } // namespace content 685 } // namespace content
OLDNEW
« no previous file with comments | « content/renderer/media/webrtc_audio_renderer.h ('k') | content/renderer/media/webrtc_audio_renderer_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698