Index: third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.cc |
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.cc b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.cc |
index 5a17f616dcb971ae9f4446b8c1cd466aa65370f2..35fc86a16e8049edf03a84e688206967e2d393ee 100644 |
--- a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.cc |
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.cc |
@@ -12,6 +12,7 @@ |
#include "base/trace_event/trace_event.h" |
#include "base/trace_event/trace_event_argument.h" |
#include "cc/output/begin_frame_args.h" |
+#include "platform/scheduler/base/real_time_domain.h" |
#include "platform/scheduler/base/task_queue_impl.h" |
#include "platform/scheduler/base/task_queue_selector.h" |
#include "platform/scheduler/base/virtual_time_domain.h" |
@@ -41,6 +42,9 @@ constexpr base::TimeDelta kThreadLoadTrackerReportingInterval = |
base::TimeDelta::FromMinutes(1); |
constexpr base::TimeDelta kThreadLoadTrackerWaitingPeriodBeforeReporting = |
base::TimeDelta::FromMinutes(2); |
+// We do not throttle anything while audio is played and shortly after that. |
+constexpr base::TimeDelta kThrottlingDelayAfterAudioIsPlayed = |
+ base::TimeDelta::FromSeconds(5); |
void ReportForegroundRendererTaskLoad(base::TimeTicks time, double load) { |
int load_percentage = static_cast<int>(load * 100); |
@@ -185,6 +189,7 @@ RendererSchedulerImpl::MainThreadOnly::MainThreadOnly( |
begin_frame_not_expected_soon(false), |
in_idle_period_for_testing(false), |
use_virtual_time(false), |
+ is_audio_playing(false), |
rail_mode_observer(nullptr) {} |
RendererSchedulerImpl::MainThreadOnly::~MainThreadOnly() {} |
@@ -484,6 +489,23 @@ void RendererSchedulerImpl::OnRendererForegrounded() { |
ResumeTimerQueueWhenForegrounded(); |
} |
+void RendererSchedulerImpl::OnAudioStateChanged() { |
+ bool is_audio_playing = false; |
+ for (WebViewSchedulerImpl* web_view_scheduler : |
+ MainThreadOnly().web_view_schedulers) { |
+ is_audio_playing = is_audio_playing || web_view_scheduler->IsAudioPlaying(); |
+ } |
+ |
+ if (is_audio_playing == MainThreadOnly().is_audio_playing) |
+ return; |
+ |
+ MainThreadOnly().last_audio_state_change = |
+ helper_.scheduler_tqm_delegate()->NowTicks(); |
+ MainThreadOnly().is_audio_playing = is_audio_playing; |
+ |
+ UpdatePolicy(); |
+} |
+ |
void RendererSchedulerImpl::SuspendRenderer() { |
helper_.CheckOnValidThread(); |
DCHECK(MainThreadOnly().renderer_backgrounded); |
@@ -818,6 +840,27 @@ void RendererSchedulerImpl::UpdatePolicyLocked(UpdateType update_type) { |
new_policy_duration = touchstart_expected_flag_valid_for_duration; |
} |
+ // Do not throttle while audio is playing or for a short period after that |
+ // to make sure that pages playing short audio clips powered by timers |
+ // work. |
+ if (MainThreadOnly().last_audio_state_change && |
+ !MainThreadOnly().is_audio_playing) { |
+ base::TimeTicks audio_will_expire = |
+ MainThreadOnly().last_audio_state_change.value() + |
+ kThrottlingDelayAfterAudioIsPlayed; |
+ |
+ base::TimeDelta audio_will_expire_after = audio_will_expire - now; |
+ |
+ if (audio_will_expire_after > base::TimeDelta()) { |
+ if (new_policy_duration.is_zero()) { |
+ new_policy_duration = audio_will_expire_after; |
+ } else { |
+ new_policy_duration = |
+ std::min(new_policy_duration, audio_will_expire_after); |
+ } |
+ } |
+ } |
+ |
if (new_policy_duration > base::TimeDelta()) { |
MainThreadOnly().current_policy_expiration_time = now + new_policy_duration; |
delayed_update_policy_runner_.SetDeadline(FROM_HERE, new_policy_duration, |
@@ -973,6 +1016,10 @@ void RendererSchedulerImpl::UpdatePolicyLocked(UpdateType update_type) { |
new_policy.timer_queue_policy.time_domain_type = TimeDomainType::VIRTUAL; |
} |
+ new_policy.should_disable_throttling = |
+ ShouldDisableThrottlingBecauseOfAudio(now) || |
+ MainThreadOnly().use_virtual_time; |
+ |
// Tracing is done before the early out check, because it's quite possible we |
// will otherwise miss this information in traces. |
CreateTraceEventObjectSnapshotLocked(); |
@@ -1028,6 +1075,15 @@ void RendererSchedulerImpl::UpdatePolicyLocked(UpdateType update_type) { |
new_policy.rail_mode); |
} |
+ if (new_policy.should_disable_throttling != |
+ MainThreadOnly().current_policy.should_disable_throttling) { |
+ if (new_policy.should_disable_throttling) { |
+ task_queue_throttler()->DisableThrottling(); |
+ } else { |
+ task_queue_throttler()->EnableThrottling(); |
+ } |
+ } |
+ |
DCHECK(compositor_task_runner_->IsQueueEnabled()); |
MainThreadOnly().current_policy = new_policy; |
} |
@@ -1550,11 +1606,30 @@ void RendererSchedulerImpl::EnableVirtualTime() { |
for (const scoped_refptr<TaskQueue>& task_queue : unthrottled_task_runners_) |
task_queue->SetTimeDomain(time_domain); |
- task_queue_throttler_->EnableVirtualTime(); |
- |
ForceUpdatePolicy(); |
} |
+bool RendererSchedulerImpl::ShouldDisableThrottlingBecauseOfAudio( |
+ base::TimeTicks now) { |
+ if (!MainThreadOnly().last_audio_state_change) |
+ return false; |
+ |
+ if (MainThreadOnly().is_audio_playing) |
+ return true; |
+ |
+ return MainThreadOnly().last_audio_state_change.value() + |
+ kThrottlingDelayAfterAudioIsPlayed > |
+ now; |
+} |
+ |
+TimeDomain* RendererSchedulerImpl::GetActiveTimeDomain() { |
+ if (MainThreadOnly().use_virtual_time) { |
+ return GetVirtualTimeDomain(); |
+ } else { |
+ return real_time_domain(); |
+ } |
+} |
+ |
// static |
const char* RendererSchedulerImpl::UseCaseToString(UseCase use_case) { |
switch (use_case) { |