| 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) {
|
|
|