FrameCadenceAdapter: account for encode sequence contention.
The synthetic delay added in ZeroHzAdapterMode::OnFrame does not account for delay with respect to the initial frame post from FrameCadenceAdapter::OnFrame. Fix this to account for time spent in contention on the encode sequence. Bug: webrtc:15456 Change-Id: I63446e8dfe8f62b09d972434a705e912f8a73d69 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/318420 Commit-Queue: Markus Handell <handellm@webrtc.org> Reviewed-by: Erik Språng <sprang@webrtc.org> Reviewed-by: Mirko Bonadei <mbonadei@webrtc.org> Cr-Commit-Position: refs/heads/main@{#40675}
This commit is contained in:
parent
58240ed964
commit
8fa8619d7e
@ -211,6 +211,18 @@ void GlobalSimulatedTimeController::AdvanceTime(TimeDelta duration) {
|
|||||||
impl_.RunReadyRunners();
|
impl_.RunReadyRunners();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GlobalSimulatedTimeController::SkipForwardBy(TimeDelta duration) {
|
||||||
|
rtc::ScopedYieldPolicy yield_policy(&impl_);
|
||||||
|
Timestamp current_time = impl_.CurrentTime();
|
||||||
|
Timestamp target_time = current_time + duration;
|
||||||
|
impl_.AdvanceTime(target_time);
|
||||||
|
sim_clock_.AdvanceTimeMicroseconds(duration.us());
|
||||||
|
global_clock_.AdvanceTime(duration);
|
||||||
|
|
||||||
|
// Run tasks that were pending during the skip.
|
||||||
|
impl_.RunReadyRunners();
|
||||||
|
}
|
||||||
|
|
||||||
void GlobalSimulatedTimeController::Register(
|
void GlobalSimulatedTimeController::Register(
|
||||||
sim_time_impl::SimulatedSequenceRunner* runner) {
|
sim_time_impl::SimulatedSequenceRunner* runner) {
|
||||||
impl_.Register(runner);
|
impl_.Register(runner);
|
||||||
|
|||||||
@ -138,6 +138,11 @@ class GlobalSimulatedTimeController : public TimeController {
|
|||||||
|
|
||||||
void AdvanceTime(TimeDelta duration) override;
|
void AdvanceTime(TimeDelta duration) override;
|
||||||
|
|
||||||
|
// Advances time by `duration`and do not run delayed tasks in the meantime.
|
||||||
|
// Runs any pending tasks at the end.
|
||||||
|
// Useful for simulating contention on destination queues.
|
||||||
|
void SkipForwardBy(TimeDelta duration);
|
||||||
|
|
||||||
// Makes the simulated time controller aware of a custom
|
// Makes the simulated time controller aware of a custom
|
||||||
// SimulatedSequenceRunner.
|
// SimulatedSequenceRunner.
|
||||||
// TODO(bugs.webrtc.org/11581): remove method once the ModuleRtpRtcpImpl2 unit
|
// TODO(bugs.webrtc.org/11581): remove method once the ModuleRtpRtcpImpl2 unit
|
||||||
|
|||||||
@ -13,6 +13,7 @@
|
|||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
#include "api/units/time_delta.h"
|
||||||
#include "rtc_base/event.h"
|
#include "rtc_base/event.h"
|
||||||
#include "rtc_base/task_queue.h"
|
#include "rtc_base/task_queue.h"
|
||||||
#include "rtc_base/task_queue_for_test.h"
|
#include "rtc_base/task_queue_for_test.h"
|
||||||
@ -146,4 +147,18 @@ TEST(SimulatedTimeControllerTest, ThreadYeildsOnSynchronousCall) {
|
|||||||
ASSERT_TRUE(task_has_run);
|
ASSERT_TRUE(task_has_run);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(SimulatedTimeControllerTest, SkipsDelayedTaskForward) {
|
||||||
|
GlobalSimulatedTimeController sim(kStartTime);
|
||||||
|
auto main_thread = sim.GetMainThread();
|
||||||
|
constexpr auto duration_during_which_nothing_runs = TimeDelta::Seconds(2);
|
||||||
|
constexpr auto shorter_duration = TimeDelta::Seconds(1);
|
||||||
|
MockFunction<void()> fun;
|
||||||
|
EXPECT_CALL(fun, Call).WillOnce(Invoke([&] {
|
||||||
|
ASSERT_EQ(sim.GetClock()->CurrentTime(),
|
||||||
|
kStartTime + duration_during_which_nothing_runs);
|
||||||
|
}));
|
||||||
|
main_thread->PostDelayedTask(fun.AsStdFunction(), shorter_duration);
|
||||||
|
sim.SkipForwardBy(duration_during_which_nothing_runs);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace webrtc
|
} // namespace webrtc
|
||||||
|
|||||||
@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
#include "video/frame_cadence_adapter.h"
|
#include "video/frame_cadence_adapter.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <deque>
|
#include <deque>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
@ -377,13 +378,14 @@ void ZeroHertzAdapterMode::OnFrame(Timestamp post_time,
|
|||||||
queued_frames_.push_back(frame);
|
queued_frames_.push_back(frame);
|
||||||
current_frame_id_++;
|
current_frame_id_++;
|
||||||
scheduled_repeat_ = absl::nullopt;
|
scheduled_repeat_ = absl::nullopt;
|
||||||
|
TimeDelta time_spent_since_post = clock_->CurrentTime() - post_time;
|
||||||
queue_->PostDelayedHighPrecisionTask(
|
queue_->PostDelayedHighPrecisionTask(
|
||||||
SafeTask(safety_.flag(),
|
SafeTask(safety_.flag(),
|
||||||
[this] {
|
[this] {
|
||||||
RTC_DCHECK_RUN_ON(&sequence_checker_);
|
RTC_DCHECK_RUN_ON(&sequence_checker_);
|
||||||
ProcessOnDelayedCadence();
|
ProcessOnDelayedCadence();
|
||||||
}),
|
}),
|
||||||
frame_delay_);
|
std::max(frame_delay_ - time_spent_since_post, TimeDelta::Zero()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ZeroHertzAdapterMode::OnDiscardedFrame() {
|
void ZeroHertzAdapterMode::OnDiscardedFrame() {
|
||||||
|
|||||||
@ -38,6 +38,7 @@ namespace {
|
|||||||
using ::testing::_;
|
using ::testing::_;
|
||||||
using ::testing::ElementsAre;
|
using ::testing::ElementsAre;
|
||||||
using ::testing::Invoke;
|
using ::testing::Invoke;
|
||||||
|
using ::testing::InvokeWithoutArgs;
|
||||||
using ::testing::Mock;
|
using ::testing::Mock;
|
||||||
using ::testing::Pair;
|
using ::testing::Pair;
|
||||||
using ::testing::Values;
|
using ::testing::Values;
|
||||||
@ -241,6 +242,50 @@ TEST(FrameCadenceAdapterTest, ForwardsFramesDelayed) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(FrameCadenceAdapterTest, DelayedProcessingUnderSlightContention) {
|
||||||
|
ZeroHertzFieldTrialEnabler enabler;
|
||||||
|
GlobalSimulatedTimeController time_controller(Timestamp::Zero());
|
||||||
|
auto adapter = CreateAdapter(enabler, time_controller.GetClock());
|
||||||
|
MockCallback callback;
|
||||||
|
adapter->Initialize(&callback);
|
||||||
|
adapter->SetZeroHertzModeEnabled(
|
||||||
|
FrameCadenceAdapterInterface::ZeroHertzModeParams{});
|
||||||
|
adapter->OnConstraintsChanged(VideoTrackSourceConstraints{0, 1});
|
||||||
|
|
||||||
|
// Expect frame delivery at 1 sec despite target sequence not running
|
||||||
|
// callbacks for the time skipped.
|
||||||
|
constexpr TimeDelta time_skipped = TimeDelta::Millis(999);
|
||||||
|
EXPECT_CALL(callback, OnFrame).WillOnce(InvokeWithoutArgs([&] {
|
||||||
|
EXPECT_EQ(time_controller.GetClock()->CurrentTime(),
|
||||||
|
Timestamp::Zero() + TimeDelta::Seconds(1));
|
||||||
|
}));
|
||||||
|
adapter->OnFrame(CreateFrame());
|
||||||
|
time_controller.SkipForwardBy(time_skipped);
|
||||||
|
time_controller.AdvanceTime(TimeDelta::Seconds(1) - time_skipped);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(FrameCadenceAdapterTest, DelayedProcessingUnderHeavyContention) {
|
||||||
|
ZeroHertzFieldTrialEnabler enabler;
|
||||||
|
GlobalSimulatedTimeController time_controller(Timestamp::Zero());
|
||||||
|
auto adapter = CreateAdapter(enabler, time_controller.GetClock());
|
||||||
|
MockCallback callback;
|
||||||
|
adapter->Initialize(&callback);
|
||||||
|
adapter->SetZeroHertzModeEnabled(
|
||||||
|
FrameCadenceAdapterInterface::ZeroHertzModeParams{});
|
||||||
|
adapter->OnConstraintsChanged(VideoTrackSourceConstraints{0, 1});
|
||||||
|
|
||||||
|
// Expect frame delivery at origin + `time_skipped` when the target sequence
|
||||||
|
// is not running callbacks for the initial 1+ sec.
|
||||||
|
constexpr TimeDelta time_skipped =
|
||||||
|
TimeDelta::Seconds(1) + TimeDelta::Micros(1);
|
||||||
|
EXPECT_CALL(callback, OnFrame).WillOnce(InvokeWithoutArgs([&] {
|
||||||
|
EXPECT_EQ(time_controller.GetClock()->CurrentTime(),
|
||||||
|
Timestamp::Zero() + time_skipped);
|
||||||
|
}));
|
||||||
|
adapter->OnFrame(CreateFrame());
|
||||||
|
time_controller.SkipForwardBy(time_skipped);
|
||||||
|
}
|
||||||
|
|
||||||
TEST(FrameCadenceAdapterTest, RepeatsFramesDelayed) {
|
TEST(FrameCadenceAdapterTest, RepeatsFramesDelayed) {
|
||||||
// Logic in the frame cadence adapter avoids modifying frame NTP and render
|
// Logic in the frame cadence adapter avoids modifying frame NTP and render
|
||||||
// timestamps if these timestamps looks unset, which is the case when the
|
// timestamps if these timestamps looks unset, which is the case when the
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user