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, |