Chromium Code Reviews| Index: media/blink/webaudiosourceprovider_impl.cc |
| diff --git a/media/blink/webaudiosourceprovider_impl.cc b/media/blink/webaudiosourceprovider_impl.cc |
| index 8d320c8eb208a99ffb0b7ccfd2accc1faff8db30..1fd5ce745f144af3be1f5ced08e7bb0b54d1b830 100644 |
| --- a/media/blink/webaudiosourceprovider_impl.cc |
| +++ b/media/blink/webaudiosourceprovider_impl.cc |
| @@ -11,8 +11,12 @@ |
| #include "base/logging.h" |
| #include "base/macros.h" |
| #include "base/memory/ptr_util.h" |
| +#include "base/metrics/histogram_macros.h" |
| +#include "base/single_thread_task_runner.h" |
| +#include "media/audio/null_audio_sink.h" |
| #include "media/base/audio_timestamp_helper.h" |
| #include "media/base/bind_to_current_loop.h" |
| +#include "media/base/media_log.h" |
| #include "third_party/WebKit/public/platform/WebAudioSourceProviderClient.h" |
| using blink::WebVector; |
| @@ -94,12 +98,14 @@ class WebAudioSourceProviderImpl::TeeFilter |
| }; |
| WebAudioSourceProviderImpl::WebAudioSourceProviderImpl( |
| - const scoped_refptr<SwitchableAudioRendererSink>& sink) |
| + const scoped_refptr<SwitchableAudioRendererSink>& sink, |
| + scoped_refptr<MediaLog> media_log) |
| : volume_(1.0), |
| state_(kStopped), |
| client_(nullptr), |
| sink_(sink), |
| tee_filter_(new TeeFilter()), |
| + media_log_(media_log), |
|
dcheng
2016/12/02 18:25:03
Nit: std::move()
o1ka
2016/12/05 09:54:13
Done.
|
| weak_factory_(this) {} |
| WebAudioSourceProviderImpl::~WebAudioSourceProviderImpl() { |
| @@ -115,7 +121,8 @@ void WebAudioSourceProviderImpl::setClient( |
| base::AutoLock auto_lock(sink_lock_); |
| if (client) { |
| // Detach the audio renderer from normal playback. |
| - sink_->Stop(); |
| + if (sink_) |
| + sink_->Stop(); |
| // The client will now take control by calling provideInput() periodically. |
| client_ = client; |
| @@ -134,11 +141,13 @@ void WebAudioSourceProviderImpl::setClient( |
| // Restore normal playback. |
| client_ = nullptr; |
| - sink_->SetVolume(volume_); |
| - if (state_ >= kStarted) |
| - sink_->Start(); |
| - if (state_ >= kPlaying) |
| - sink_->Play(); |
| + if (sink_) { |
| + sink_->SetVolume(volume_); |
| + if (state_ >= kStarted) |
| + sink_->Start(); |
| + if (state_ >= kPlaying) |
| + sink_->Play(); |
| + } |
| } |
| void WebAudioSourceProviderImpl::provideInput( |
| @@ -177,6 +186,22 @@ void WebAudioSourceProviderImpl::Initialize(const AudioParameters& params, |
| base::AutoLock auto_lock(sink_lock_); |
| DCHECK_EQ(state_, kStopped); |
| + OutputDeviceStatus device_status = |
| + sink_ ? sink_->GetOutputDeviceInfo().device_status() |
| + : OUTPUT_DEVICE_STATUS_ERROR_NOT_FOUND; |
| + |
| + UMA_HISTOGRAM_ENUMERATION("Media.WebMediaPlayer.SinkStatus", device_status, |
|
DaleCurtis
2016/12/02 18:28:56
WebAudioSourceProvider?
o1ka
2016/12/05 09:54:13
Done.
|
| + OUTPUT_DEVICE_STATUS_MAX + 1); |
| + |
| + if (device_status != OUTPUT_DEVICE_STATUS_OK) { |
| + // Since null sink is always OK, we will fall back to it once and forever. |
| + if (sink_) |
| + sink_->Stop(); |
| + sink_ = CreateFallbackSink(); |
| + MEDIA_LOG(ERROR, media_log_) |
| + << "Output device error, falling back to null sink"; |
| + } |
| + |
| tee_filter_->Initialize(renderer, params.channels(), params.sample_rate()); |
| sink_->Initialize(params, tee_filter_.get()); |
| @@ -220,14 +245,15 @@ void WebAudioSourceProviderImpl::Pause() { |
| bool WebAudioSourceProviderImpl::SetVolume(double volume) { |
| base::AutoLock auto_lock(sink_lock_); |
| volume_ = volume; |
| - if (!client_) |
| + if (!client_ && sink_) |
| sink_->SetVolume(volume); |
| return true; |
| } |
| -media::OutputDeviceInfo WebAudioSourceProviderImpl::GetOutputDeviceInfo() { |
| +OutputDeviceInfo WebAudioSourceProviderImpl::GetOutputDeviceInfo() { |
| base::AutoLock auto_lock(sink_lock_); |
| - return sink_->GetOutputDeviceInfo(); |
| + return sink_ ? sink_->GetOutputDeviceInfo() |
| + : OutputDeviceInfo(OUTPUT_DEVICE_STATUS_ERROR_NOT_FOUND); |
| } |
| bool WebAudioSourceProviderImpl::CurrentThreadIsRenderingThread() { |
| @@ -240,8 +266,8 @@ void WebAudioSourceProviderImpl::SwitchOutputDevice( |
| const url::Origin& security_origin, |
| const OutputDeviceStatusCB& callback) { |
| base::AutoLock auto_lock(sink_lock_); |
| - if (client_) |
| - callback.Run(media::OUTPUT_DEVICE_STATUS_ERROR_INTERNAL); |
| + if (client_ || !sink_) |
| + callback.Run(OUTPUT_DEVICE_STATUS_ERROR_INTERNAL); |
| else |
| sink_->SwitchOutputDevice(device_id, security_origin, callback); |
| } |
| @@ -276,6 +302,12 @@ void WebAudioSourceProviderImpl::OnSetFormat() { |
| client_->setFormat(tee_filter_->channels(), tee_filter_->sample_rate()); |
| } |
| +scoped_refptr<SwitchableAudioRendererSink> |
| +WebAudioSourceProviderImpl::CreateFallbackSink() { |
| + // Assuming it is called on media thread. |
| + return new NullAudioSink(base::ThreadTaskRunnerHandle::Get()); |
| +} |
| + |
| int WebAudioSourceProviderImpl::TeeFilter::Render( |
| base::TimeDelta delay, |
| base::TimeTicks delay_timestamp, |