DecodeSynchronizer: avoid duplicate tick callback registration.
With repeated CreateSynchronizedFrameScheduler/Stop calls, the
DecodeSynchronizer can register & keep multiple callbacks in
the metronome. Fix this to only keep at most one callback
installed.
Fixed: chromium:1434747
Change-Id: I61f67a871339dbcc7560e9d545a5217f361a9b87
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/303840
Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org>
Reviewed-by: Henrik Boström <hbos@webrtc.org>
Commit-Queue: Markus Handell <handellm@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#39964}
diff --git a/video/decode_synchronizer.cc b/video/decode_synchronizer.cc
index 2b9a658..32702c2 100644
--- a/video/decode_synchronizer.cc
+++ b/video/decode_synchronizer.cc
@@ -175,6 +175,10 @@
void DecodeSynchronizer::ScheduleNextTick() {
RTC_DCHECK_RUN_ON(worker_queue_);
+ if (tick_scheduled_) {
+ return;
+ }
+ tick_scheduled_ = true;
metronome_->RequestCallOnNextTick(
SafeTask(safety_.flag(), [this] { OnTick(); }));
}
@@ -182,6 +186,7 @@
void DecodeSynchronizer::OnTick() {
TRACE_EVENT0("webrtc", __func__);
RTC_DCHECK_RUN_ON(worker_queue_);
+ tick_scheduled_ = false;
expected_next_tick_ = clock_->CurrentTime() + metronome_->TickPeriod();
for (auto* scheduler : schedulers_) {
diff --git a/video/decode_synchronizer.h b/video/decode_synchronizer.h
index c6f8efd..1718186 100644
--- a/video/decode_synchronizer.h
+++ b/video/decode_synchronizer.h
@@ -129,6 +129,7 @@
Timestamp expected_next_tick_ = Timestamp::PlusInfinity();
std::set<SynchronizedFrameDecodeScheduler*> schedulers_
RTC_GUARDED_BY(worker_queue_);
+ bool tick_scheduled_ = false;
ScopedTaskSafetyDetached safety_;
};
diff --git a/video/decode_synchronizer_unittest.cc b/video/decode_synchronizer_unittest.cc
index 7a0d833..fb48a7e 100644
--- a/video/decode_synchronizer_unittest.cc
+++ b/video/decode_synchronizer_unittest.cc
@@ -27,6 +27,8 @@
using ::testing::_;
using ::testing::Eq;
using ::testing::Invoke;
+using ::testing::Mock;
+using ::testing::MockFunction;
using ::testing::Return;
namespace webrtc {
@@ -60,10 +62,10 @@
};
TEST_F(DecodeSynchronizerTest, AllFramesReadyBeforeNextTickDecoded) {
- ::testing::MockFunction<void(uint32_t, Timestamp)> mock_callback1;
+ MockFunction<void(uint32_t, Timestamp)> mock_callback1;
auto scheduler1 = decode_synchronizer_.CreateSynchronizedFrameScheduler();
- testing::MockFunction<void(unsigned int, Timestamp)> mock_callback2;
+ MockFunction<void(unsigned int, Timestamp)> mock_callback2;
auto scheduler2 = decode_synchronizer_.CreateSynchronizedFrameScheduler();
{
@@ -97,7 +99,7 @@
}
TEST_F(DecodeSynchronizerTest, FramesNotDecodedIfDecodeTimeIsInNextInterval) {
- ::testing::MockFunction<void(unsigned int, Timestamp)> mock_callback;
+ MockFunction<void(unsigned int, Timestamp)> mock_callback;
auto scheduler = decode_synchronizer_.CreateSynchronizedFrameScheduler();
uint32_t frame_rtp = 90000;
@@ -125,7 +127,7 @@
}
TEST_F(DecodeSynchronizerTest, FrameDecodedOnce) {
- ::testing::MockFunction<void(unsigned int, Timestamp)> mock_callback;
+ MockFunction<void(unsigned int, Timestamp)> mock_callback;
auto scheduler = decode_synchronizer_.CreateSynchronizedFrameScheduler();
uint32_t frame_rtp = 90000;
@@ -149,7 +151,7 @@
}
TEST_F(DecodeSynchronizerTest, FrameWithDecodeTimeInPastDecodedImmediately) {
- ::testing::MockFunction<void(unsigned int, Timestamp)> mock_callback;
+ MockFunction<void(unsigned int, Timestamp)> mock_callback;
auto scheduler = decode_synchronizer_.CreateSynchronizedFrameScheduler();
uint32_t frame_rtp = 90000;
@@ -171,7 +173,7 @@
TEST_F(DecodeSynchronizerTest,
FrameWithDecodeTimeFarBeforeNextTickDecodedImmediately) {
- ::testing::MockFunction<void(unsigned int, Timestamp)> mock_callback;
+ MockFunction<void(unsigned int, Timestamp)> mock_callback;
auto scheduler = decode_synchronizer_.CreateSynchronizedFrameScheduler();
// Frame which would be behind by more than kMaxAllowedFrameDelay after
@@ -210,7 +212,7 @@
}
TEST_F(DecodeSynchronizerTest, FramesNotReleasedAfterStop) {
- ::testing::MockFunction<void(unsigned int, Timestamp)> mock_callback;
+ MockFunction<void(unsigned int, Timestamp)> mock_callback;
auto scheduler = decode_synchronizer_.CreateSynchronizedFrameScheduler();
uint32_t frame_rtp = 90000;
@@ -249,4 +251,21 @@
(std::move)(callback)();
}
+TEST(DecodeSynchronizerStandaloneTest,
+ RegistersCallbackOnceDuringRepeatedRegistrations) {
+ GlobalSimulatedTimeController time_controller(Timestamp::Millis(4711));
+ Clock* clock(time_controller.GetClock());
+ MockMetronome metronome;
+ ON_CALL(metronome, TickPeriod).WillByDefault(Return(TimeDelta::Seconds(1)));
+ DecodeSynchronizer decode_synchronizer_(clock, &metronome,
+ time_controller.GetMainThread());
+ // Expect at most 1 call to register a callback.
+ EXPECT_CALL(metronome, RequestCallOnNextTick);
+ auto scheduler1 = decode_synchronizer_.CreateSynchronizedFrameScheduler();
+ scheduler1->Stop();
+ auto scheduler2 = decode_synchronizer_.CreateSynchronizedFrameScheduler();
+ Mock::VerifyAndClearExpectations(&metronome);
+ scheduler2->Stop();
+}
+
} // namespace webrtc