stefan@webrtc.org | 9f557c1 | 2013-05-17 12:55:07 +0000 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. |
| 3 | * |
| 4 | * Use of this source code is governed by a BSD-style license |
| 5 | * that can be found in the LICENSE file in the root of the source |
| 6 | * tree. An additional intellectual property rights grant can be found |
| 7 | * in the file PATENTS. All contributing project authors may |
| 8 | * be found in the AUTHORS file in the root of the source tree. |
| 9 | */ |
| 10 | |
Rasmus Brandt | c4d253c | 2022-05-25 12:03:35 +0200 | [diff] [blame] | 11 | #include "modules/video_coding/timing/timing.h" |
Jonas Olsson | a4d8737 | 2019-07-05 19:08:33 +0200 | [diff] [blame] | 12 | |
Evan Shrubsole | d6cdf80 | 2022-03-02 15:13:55 +0100 | [diff] [blame] | 13 | #include "api/units/frequency.h" |
| 14 | #include "api/units/time_delta.h" |
Mirko Bonadei | 92ea95e | 2017-09-15 06:47:31 +0200 | [diff] [blame] | 15 | #include "system_wrappers/include/clock.h" |
| 16 | #include "test/gtest.h" |
Jonas Oreland | e02f9ee | 2022-03-25 12:43:14 +0100 | [diff] [blame] | 17 | #include "test/scoped_key_value_config.h" |
stefan@webrtc.org | 9f557c1 | 2013-05-17 12:55:07 +0000 | [diff] [blame] | 18 | |
| 19 | namespace webrtc { |
Åsa Persson | 8368d1a | 2018-01-05 12:44:45 +0100 | [diff] [blame] | 20 | namespace { |
Evan Shrubsole | d6cdf80 | 2022-03-02 15:13:55 +0100 | [diff] [blame] | 21 | |
| 22 | constexpr Frequency k25Fps = Frequency::Hertz(25); |
| 23 | constexpr Frequency k90kHz = Frequency::KiloHertz(90); |
| 24 | |
Åsa Persson | 8368d1a | 2018-01-05 12:44:45 +0100 | [diff] [blame] | 25 | } // namespace |
stefan@webrtc.org | 9f557c1 | 2013-05-17 12:55:07 +0000 | [diff] [blame] | 26 | |
Johannes Kron | 985905d | 2021-06-29 11:37:06 +0200 | [diff] [blame] | 27 | TEST(ReceiverTimingTest, JitterDelay) { |
Jonas Oreland | e02f9ee | 2022-03-25 12:43:14 +0100 | [diff] [blame] | 28 | test::ScopedKeyValueConfig field_trials; |
stefan@webrtc.org | 9f557c1 | 2013-05-17 12:55:07 +0000 | [diff] [blame] | 29 | SimulatedClock clock(0); |
Jonas Oreland | e02f9ee | 2022-03-25 12:43:14 +0100 | [diff] [blame] | 30 | VCMTiming timing(&clock, field_trials); |
Åsa Persson | 8368d1a | 2018-01-05 12:44:45 +0100 | [diff] [blame] | 31 | timing.Reset(); |
| 32 | |
| 33 | uint32_t timestamp = 0; |
| 34 | timing.UpdateCurrentDelay(timestamp); |
stefan@webrtc.org | 9f557c1 | 2013-05-17 12:55:07 +0000 | [diff] [blame] | 35 | |
| 36 | timing.Reset(); |
| 37 | |
Evan Shrubsole | d6cdf80 | 2022-03-02 15:13:55 +0100 | [diff] [blame] | 38 | timing.IncomingTimestamp(timestamp, clock.CurrentTime()); |
| 39 | TimeDelta jitter_delay = TimeDelta::Millis(20); |
| 40 | timing.SetJitterDelay(jitter_delay); |
Åsa Persson | 8368d1a | 2018-01-05 12:44:45 +0100 | [diff] [blame] | 41 | timing.UpdateCurrentDelay(timestamp); |
Evan Shrubsole | d6cdf80 | 2022-03-02 15:13:55 +0100 | [diff] [blame] | 42 | timing.set_render_delay(TimeDelta::Zero()); |
| 43 | auto wait_time = timing.MaxWaitingTime( |
| 44 | timing.RenderTime(timestamp, clock.CurrentTime()), clock.CurrentTime(), |
| 45 | /*too_many_frames_queued=*/false); |
stefan@webrtc.org | 9f557c1 | 2013-05-17 12:55:07 +0000 | [diff] [blame] | 46 | // First update initializes the render time. Since we have no decode delay |
Evan Shrubsole | d6cdf80 | 2022-03-02 15:13:55 +0100 | [diff] [blame] | 47 | // we get wait_time = renderTime - now - renderDelay = jitter. |
| 48 | EXPECT_EQ(jitter_delay, wait_time); |
stefan@webrtc.org | 9f557c1 | 2013-05-17 12:55:07 +0000 | [diff] [blame] | 49 | |
Evan Shrubsole | d6cdf80 | 2022-03-02 15:13:55 +0100 | [diff] [blame] | 50 | jitter_delay += TimeDelta::Millis(VCMTiming::kDelayMaxChangeMsPerS + 10); |
Åsa Persson | 8368d1a | 2018-01-05 12:44:45 +0100 | [diff] [blame] | 51 | timestamp += 90000; |
stefan@webrtc.org | 9f557c1 | 2013-05-17 12:55:07 +0000 | [diff] [blame] | 52 | clock.AdvanceTimeMilliseconds(1000); |
Evan Shrubsole | d6cdf80 | 2022-03-02 15:13:55 +0100 | [diff] [blame] | 53 | timing.SetJitterDelay(jitter_delay); |
Åsa Persson | 8368d1a | 2018-01-05 12:44:45 +0100 | [diff] [blame] | 54 | timing.UpdateCurrentDelay(timestamp); |
Evan Shrubsole | d6cdf80 | 2022-03-02 15:13:55 +0100 | [diff] [blame] | 55 | wait_time = timing.MaxWaitingTime( |
| 56 | timing.RenderTime(timestamp, clock.CurrentTime()), clock.CurrentTime(), |
| 57 | /*too_many_frames_queued=*/false); |
stefan@webrtc.org | 9f557c1 | 2013-05-17 12:55:07 +0000 | [diff] [blame] | 58 | // Since we gradually increase the delay we only get 100 ms every second. |
Evan Shrubsole | d6cdf80 | 2022-03-02 15:13:55 +0100 | [diff] [blame] | 59 | EXPECT_EQ(jitter_delay - TimeDelta::Millis(10), wait_time); |
stefan@webrtc.org | 9f557c1 | 2013-05-17 12:55:07 +0000 | [diff] [blame] | 60 | |
Åsa Persson | 8368d1a | 2018-01-05 12:44:45 +0100 | [diff] [blame] | 61 | timestamp += 90000; |
stefan@webrtc.org | 9f557c1 | 2013-05-17 12:55:07 +0000 | [diff] [blame] | 62 | clock.AdvanceTimeMilliseconds(1000); |
Åsa Persson | 8368d1a | 2018-01-05 12:44:45 +0100 | [diff] [blame] | 63 | timing.UpdateCurrentDelay(timestamp); |
Evan Shrubsole | d6cdf80 | 2022-03-02 15:13:55 +0100 | [diff] [blame] | 64 | wait_time = timing.MaxWaitingTime( |
| 65 | timing.RenderTime(timestamp, clock.CurrentTime()), clock.CurrentTime(), |
| 66 | /*too_many_frames_queued=*/false); |
| 67 | EXPECT_EQ(jitter_delay, wait_time); |
stefan@webrtc.org | 9f557c1 | 2013-05-17 12:55:07 +0000 | [diff] [blame] | 68 | |
Åsa Persson | 8368d1a | 2018-01-05 12:44:45 +0100 | [diff] [blame] | 69 | // Insert frames without jitter, verify that this gives the exact wait time. |
| 70 | const int kNumFrames = 300; |
| 71 | for (int i = 0; i < kNumFrames; i++) { |
Evan Shrubsole | d6cdf80 | 2022-03-02 15:13:55 +0100 | [diff] [blame] | 72 | clock.AdvanceTime(1 / k25Fps); |
| 73 | timestamp += k90kHz / k25Fps; |
| 74 | timing.IncomingTimestamp(timestamp, clock.CurrentTime()); |
stefan@webrtc.org | 9f557c1 | 2013-05-17 12:55:07 +0000 | [diff] [blame] | 75 | } |
Åsa Persson | 8368d1a | 2018-01-05 12:44:45 +0100 | [diff] [blame] | 76 | timing.UpdateCurrentDelay(timestamp); |
Evan Shrubsole | d6cdf80 | 2022-03-02 15:13:55 +0100 | [diff] [blame] | 77 | wait_time = timing.MaxWaitingTime( |
| 78 | timing.RenderTime(timestamp, clock.CurrentTime()), clock.CurrentTime(), |
| 79 | /*too_many_frames_queued=*/false); |
| 80 | EXPECT_EQ(jitter_delay, wait_time); |
stefan@webrtc.org | 9f557c1 | 2013-05-17 12:55:07 +0000 | [diff] [blame] | 81 | |
Åsa Persson | 8368d1a | 2018-01-05 12:44:45 +0100 | [diff] [blame] | 82 | // Add decode time estimates for 1 second. |
Evan Shrubsole | d6cdf80 | 2022-03-02 15:13:55 +0100 | [diff] [blame] | 83 | const TimeDelta kDecodeTime = TimeDelta::Millis(10); |
| 84 | for (int i = 0; i < k25Fps.hertz(); i++) { |
| 85 | clock.AdvanceTime(kDecodeTime); |
| 86 | timing.StopDecodeTimer(kDecodeTime, clock.CurrentTime()); |
| 87 | timestamp += k90kHz / k25Fps; |
| 88 | clock.AdvanceTime(1 / k25Fps - kDecodeTime); |
| 89 | timing.IncomingTimestamp(timestamp, clock.CurrentTime()); |
stefan@webrtc.org | 9f557c1 | 2013-05-17 12:55:07 +0000 | [diff] [blame] | 90 | } |
Åsa Persson | 8368d1a | 2018-01-05 12:44:45 +0100 | [diff] [blame] | 91 | timing.UpdateCurrentDelay(timestamp); |
Evan Shrubsole | d6cdf80 | 2022-03-02 15:13:55 +0100 | [diff] [blame] | 92 | wait_time = timing.MaxWaitingTime( |
| 93 | timing.RenderTime(timestamp, clock.CurrentTime()), clock.CurrentTime(), |
| 94 | /*too_many_frames_queued=*/false); |
| 95 | EXPECT_EQ(jitter_delay, wait_time); |
stefan@webrtc.org | 9f557c1 | 2013-05-17 12:55:07 +0000 | [diff] [blame] | 96 | |
Evan Shrubsole | d6cdf80 | 2022-03-02 15:13:55 +0100 | [diff] [blame] | 97 | const TimeDelta kMinTotalDelay = TimeDelta::Millis(200); |
| 98 | timing.set_min_playout_delay(kMinTotalDelay); |
stefan@webrtc.org | 9f557c1 | 2013-05-17 12:55:07 +0000 | [diff] [blame] | 99 | clock.AdvanceTimeMilliseconds(5000); |
Åsa Persson | 8368d1a | 2018-01-05 12:44:45 +0100 | [diff] [blame] | 100 | timestamp += 5 * 90000; |
| 101 | timing.UpdateCurrentDelay(timestamp); |
Evan Shrubsole | d6cdf80 | 2022-03-02 15:13:55 +0100 | [diff] [blame] | 102 | const TimeDelta kRenderDelay = TimeDelta::Millis(10); |
| 103 | timing.set_render_delay(kRenderDelay); |
| 104 | wait_time = timing.MaxWaitingTime( |
| 105 | timing.RenderTime(timestamp, clock.CurrentTime()), clock.CurrentTime(), |
| 106 | /*too_many_frames_queued=*/false); |
Åsa Persson | 8368d1a | 2018-01-05 12:44:45 +0100 | [diff] [blame] | 107 | // We should at least have kMinTotalDelayMs - decodeTime (10) - renderTime |
stefan@webrtc.org | 9f557c1 | 2013-05-17 12:55:07 +0000 | [diff] [blame] | 108 | // (10) to wait. |
Evan Shrubsole | d6cdf80 | 2022-03-02 15:13:55 +0100 | [diff] [blame] | 109 | EXPECT_EQ(kMinTotalDelay - kDecodeTime - kRenderDelay, wait_time); |
stefan@webrtc.org | 9f557c1 | 2013-05-17 12:55:07 +0000 | [diff] [blame] | 110 | // The total video delay should be equal to the min total delay. |
Evan Shrubsole | d6cdf80 | 2022-03-02 15:13:55 +0100 | [diff] [blame] | 111 | EXPECT_EQ(kMinTotalDelay, timing.TargetVideoDelay()); |
stefan@webrtc.org | 9f557c1 | 2013-05-17 12:55:07 +0000 | [diff] [blame] | 112 | |
mikhal@webrtc.org | adc64a7 | 2013-05-30 16:20:18 +0000 | [diff] [blame] | 113 | // Reset playout delay. |
Evan Shrubsole | d6cdf80 | 2022-03-02 15:13:55 +0100 | [diff] [blame] | 114 | timing.set_min_playout_delay(TimeDelta::Zero()); |
stefan@webrtc.org | 9f557c1 | 2013-05-17 12:55:07 +0000 | [diff] [blame] | 115 | clock.AdvanceTimeMilliseconds(5000); |
Åsa Persson | 8368d1a | 2018-01-05 12:44:45 +0100 | [diff] [blame] | 116 | timestamp += 5 * 90000; |
| 117 | timing.UpdateCurrentDelay(timestamp); |
stefan@webrtc.org | 9f557c1 | 2013-05-17 12:55:07 +0000 | [diff] [blame] | 118 | } |
| 119 | |
Johannes Kron | 985905d | 2021-06-29 11:37:06 +0200 | [diff] [blame] | 120 | TEST(ReceiverTimingTest, TimestampWrapAround) { |
Evan Shrubsole | d6cdf80 | 2022-03-02 15:13:55 +0100 | [diff] [blame] | 121 | constexpr auto kStartTime = Timestamp::Millis(1337); |
Jonas Oreland | e02f9ee | 2022-03-25 12:43:14 +0100 | [diff] [blame] | 122 | test::ScopedKeyValueConfig field_trials; |
Evan Shrubsole | d6cdf80 | 2022-03-02 15:13:55 +0100 | [diff] [blame] | 123 | SimulatedClock clock(kStartTime); |
Jonas Oreland | e02f9ee | 2022-03-25 12:43:14 +0100 | [diff] [blame] | 124 | VCMTiming timing(&clock, field_trials); |
Evan Shrubsole | d6cdf80 | 2022-03-02 15:13:55 +0100 | [diff] [blame] | 125 | |
Åsa Persson | 8368d1a | 2018-01-05 12:44:45 +0100 | [diff] [blame] | 126 | // Provoke a wrap-around. The fifth frame will have wrapped at 25 fps. |
Evan Shrubsole | d6cdf80 | 2022-03-02 15:13:55 +0100 | [diff] [blame] | 127 | constexpr uint32_t kRtpTicksPerFrame = k90kHz / k25Fps; |
| 128 | uint32_t timestamp = 0xFFFFFFFFu - 3 * kRtpTicksPerFrame; |
Åsa Persson | 8368d1a | 2018-01-05 12:44:45 +0100 | [diff] [blame] | 129 | for (int i = 0; i < 5; ++i) { |
Evan Shrubsole | d6cdf80 | 2022-03-02 15:13:55 +0100 | [diff] [blame] | 130 | timing.IncomingTimestamp(timestamp, clock.CurrentTime()); |
| 131 | clock.AdvanceTime(1 / k25Fps); |
| 132 | timestamp += kRtpTicksPerFrame; |
| 133 | EXPECT_EQ(kStartTime + 3 / k25Fps, |
| 134 | timing.RenderTime(0xFFFFFFFFu, clock.CurrentTime())); |
| 135 | // One ms later in 90 kHz. |
| 136 | EXPECT_EQ(kStartTime + 3 / k25Fps + TimeDelta::Millis(1), |
| 137 | timing.RenderTime(89u, clock.CurrentTime())); |
stefan@webrtc.org | 9f557c1 | 2013-05-17 12:55:07 +0000 | [diff] [blame] | 138 | } |
| 139 | } |
| 140 | |
Johannes Kron | bbf639e | 2022-06-15 12:27:23 +0200 | [diff] [blame^] | 141 | TEST(ReceiverTimingTest, UseLowLatencyRenderer) { |
| 142 | test::ScopedKeyValueConfig field_trials; |
| 143 | SimulatedClock clock(0); |
| 144 | VCMTiming timing(&clock, field_trials); |
| 145 | timing.Reset(); |
| 146 | // Default is false. |
| 147 | EXPECT_FALSE(timing.RenderParameters().use_low_latency_rendering); |
| 148 | // False if min playout delay > 0. |
| 149 | timing.set_min_playout_delay(TimeDelta::Millis(10)); |
| 150 | timing.set_max_playout_delay(TimeDelta::Millis(20)); |
| 151 | EXPECT_FALSE(timing.RenderParameters().use_low_latency_rendering); |
| 152 | // True if min==0, max > 0. |
| 153 | timing.set_min_playout_delay(TimeDelta::Millis(0)); |
| 154 | EXPECT_TRUE(timing.RenderParameters().use_low_latency_rendering); |
| 155 | // True if min==max==0. |
| 156 | timing.set_max_playout_delay(TimeDelta::Millis(0)); |
| 157 | EXPECT_TRUE(timing.RenderParameters().use_low_latency_rendering); |
| 158 | // True also for max playout delay==500 ms. |
| 159 | timing.set_max_playout_delay(TimeDelta::Millis(500)); |
| 160 | EXPECT_TRUE(timing.RenderParameters().use_low_latency_rendering); |
| 161 | // False if max playout delay > 500 ms. |
| 162 | timing.set_max_playout_delay(TimeDelta::Millis(501)); |
| 163 | EXPECT_FALSE(timing.RenderParameters().use_low_latency_rendering); |
| 164 | } |
| 165 | |
Johannes Kron | 985905d | 2021-06-29 11:37:06 +0200 | [diff] [blame] | 166 | TEST(ReceiverTimingTest, MaxWaitingTimeIsZeroForZeroRenderTime) { |
| 167 | // This is the default path when the RTP playout delay header extension is set |
Johannes Kron | 23bfff3 | 2021-09-28 21:31:46 +0200 | [diff] [blame] | 168 | // to min==0 and max==0. |
Johannes Kron | 985905d | 2021-06-29 11:37:06 +0200 | [diff] [blame] | 169 | constexpr int64_t kStartTimeUs = 3.15e13; // About one year in us. |
Evan Shrubsole | d6cdf80 | 2022-03-02 15:13:55 +0100 | [diff] [blame] | 170 | constexpr TimeDelta kTimeDelta = 1 / Frequency::Hertz(60); |
| 171 | constexpr Timestamp kZeroRenderTime = Timestamp::Zero(); |
Johannes Kron | 985905d | 2021-06-29 11:37:06 +0200 | [diff] [blame] | 172 | SimulatedClock clock(kStartTimeUs); |
Jonas Oreland | e02f9ee | 2022-03-25 12:43:14 +0100 | [diff] [blame] | 173 | test::ScopedKeyValueConfig field_trials; |
| 174 | VCMTiming timing(&clock, field_trials); |
Johannes Kron | 985905d | 2021-06-29 11:37:06 +0200 | [diff] [blame] | 175 | timing.Reset(); |
Evan Shrubsole | d6cdf80 | 2022-03-02 15:13:55 +0100 | [diff] [blame] | 176 | timing.set_max_playout_delay(TimeDelta::Zero()); |
Johannes Kron | 985905d | 2021-06-29 11:37:06 +0200 | [diff] [blame] | 177 | for (int i = 0; i < 10; ++i) { |
Evan Shrubsole | d6cdf80 | 2022-03-02 15:13:55 +0100 | [diff] [blame] | 178 | clock.AdvanceTime(kTimeDelta); |
| 179 | Timestamp now = clock.CurrentTime(); |
| 180 | EXPECT_LT(timing.MaxWaitingTime(kZeroRenderTime, now, |
Johannes Kron | 2ddc39e | 2021-08-10 16:56:12 +0200 | [diff] [blame] | 181 | /*too_many_frames_queued=*/false), |
Evan Shrubsole | d6cdf80 | 2022-03-02 15:13:55 +0100 | [diff] [blame] | 182 | TimeDelta::Zero()); |
Johannes Kron | 985905d | 2021-06-29 11:37:06 +0200 | [diff] [blame] | 183 | } |
| 184 | // Another frame submitted at the same time also returns a negative max |
| 185 | // waiting time. |
Evan Shrubsole | d6cdf80 | 2022-03-02 15:13:55 +0100 | [diff] [blame] | 186 | Timestamp now = clock.CurrentTime(); |
| 187 | EXPECT_LT(timing.MaxWaitingTime(kZeroRenderTime, now, |
Johannes Kron | 2ddc39e | 2021-08-10 16:56:12 +0200 | [diff] [blame] | 188 | /*too_many_frames_queued=*/false), |
Evan Shrubsole | d6cdf80 | 2022-03-02 15:13:55 +0100 | [diff] [blame] | 189 | TimeDelta::Zero()); |
Johannes Kron | 985905d | 2021-06-29 11:37:06 +0200 | [diff] [blame] | 190 | // MaxWaitingTime should be less than zero even if there's a burst of frames. |
Evan Shrubsole | d6cdf80 | 2022-03-02 15:13:55 +0100 | [diff] [blame] | 191 | EXPECT_LT(timing.MaxWaitingTime(kZeroRenderTime, now, |
Johannes Kron | 2ddc39e | 2021-08-10 16:56:12 +0200 | [diff] [blame] | 192 | /*too_many_frames_queued=*/false), |
Evan Shrubsole | d6cdf80 | 2022-03-02 15:13:55 +0100 | [diff] [blame] | 193 | TimeDelta::Zero()); |
| 194 | EXPECT_LT(timing.MaxWaitingTime(kZeroRenderTime, now, |
Johannes Kron | 2ddc39e | 2021-08-10 16:56:12 +0200 | [diff] [blame] | 195 | /*too_many_frames_queued=*/false), |
Evan Shrubsole | d6cdf80 | 2022-03-02 15:13:55 +0100 | [diff] [blame] | 196 | TimeDelta::Zero()); |
| 197 | EXPECT_LT(timing.MaxWaitingTime(kZeroRenderTime, now, |
Johannes Kron | 2ddc39e | 2021-08-10 16:56:12 +0200 | [diff] [blame] | 198 | /*too_many_frames_queued=*/false), |
Evan Shrubsole | d6cdf80 | 2022-03-02 15:13:55 +0100 | [diff] [blame] | 199 | TimeDelta::Zero()); |
Johannes Kron | 985905d | 2021-06-29 11:37:06 +0200 | [diff] [blame] | 200 | } |
| 201 | |
| 202 | TEST(ReceiverTimingTest, MaxWaitingTimeZeroDelayPacingExperiment) { |
| 203 | // The minimum pacing is enabled by a field trial and active if the RTP |
| 204 | // playout delay header extension is set to min==0. |
Evan Shrubsole | d6cdf80 | 2022-03-02 15:13:55 +0100 | [diff] [blame] | 205 | constexpr TimeDelta kMinPacing = TimeDelta::Millis(3); |
Jonas Oreland | e02f9ee | 2022-03-25 12:43:14 +0100 | [diff] [blame] | 206 | test::ScopedKeyValueConfig field_trials( |
Johannes Kron | 985905d | 2021-06-29 11:37:06 +0200 | [diff] [blame] | 207 | "WebRTC-ZeroPlayoutDelay/min_pacing:3ms/"); |
| 208 | constexpr int64_t kStartTimeUs = 3.15e13; // About one year in us. |
Evan Shrubsole | d6cdf80 | 2022-03-02 15:13:55 +0100 | [diff] [blame] | 209 | constexpr TimeDelta kTimeDelta = 1 / Frequency::Hertz(60); |
| 210 | constexpr auto kZeroRenderTime = Timestamp::Zero(); |
Johannes Kron | 985905d | 2021-06-29 11:37:06 +0200 | [diff] [blame] | 211 | SimulatedClock clock(kStartTimeUs); |
Jonas Oreland | e02f9ee | 2022-03-25 12:43:14 +0100 | [diff] [blame] | 212 | VCMTiming timing(&clock, field_trials); |
Johannes Kron | 985905d | 2021-06-29 11:37:06 +0200 | [diff] [blame] | 213 | timing.Reset(); |
| 214 | // MaxWaitingTime() returns zero for evenly spaced video frames. |
| 215 | for (int i = 0; i < 10; ++i) { |
Evan Shrubsole | d6cdf80 | 2022-03-02 15:13:55 +0100 | [diff] [blame] | 216 | clock.AdvanceTime(kTimeDelta); |
| 217 | Timestamp now = clock.CurrentTime(); |
| 218 | EXPECT_EQ(timing.MaxWaitingTime(kZeroRenderTime, now, |
Johannes Kron | 2ddc39e | 2021-08-10 16:56:12 +0200 | [diff] [blame] | 219 | /*too_many_frames_queued=*/false), |
Evan Shrubsole | d6cdf80 | 2022-03-02 15:13:55 +0100 | [diff] [blame] | 220 | TimeDelta::Zero()); |
| 221 | timing.SetLastDecodeScheduledTimestamp(now); |
Johannes Kron | 985905d | 2021-06-29 11:37:06 +0200 | [diff] [blame] | 222 | } |
| 223 | // Another frame submitted at the same time is paced according to the field |
| 224 | // trial setting. |
Evan Shrubsole | d6cdf80 | 2022-03-02 15:13:55 +0100 | [diff] [blame] | 225 | auto now = clock.CurrentTime(); |
| 226 | EXPECT_EQ(timing.MaxWaitingTime(kZeroRenderTime, now, |
Johannes Kron | 2ddc39e | 2021-08-10 16:56:12 +0200 | [diff] [blame] | 227 | /*too_many_frames_queued=*/false), |
Evan Shrubsole | d6cdf80 | 2022-03-02 15:13:55 +0100 | [diff] [blame] | 228 | kMinPacing); |
Rezaul Barbhuiya | 82c2248 | 2021-08-05 17:54:11 -0700 | [diff] [blame] | 229 | // If there's a burst of frames, the wait time is calculated based on next |
| 230 | // decode time. |
Evan Shrubsole | d6cdf80 | 2022-03-02 15:13:55 +0100 | [diff] [blame] | 231 | EXPECT_EQ(timing.MaxWaitingTime(kZeroRenderTime, now, |
Johannes Kron | 2ddc39e | 2021-08-10 16:56:12 +0200 | [diff] [blame] | 232 | /*too_many_frames_queued=*/false), |
Evan Shrubsole | d6cdf80 | 2022-03-02 15:13:55 +0100 | [diff] [blame] | 233 | kMinPacing); |
| 234 | EXPECT_EQ(timing.MaxWaitingTime(kZeroRenderTime, now, |
Johannes Kron | 2ddc39e | 2021-08-10 16:56:12 +0200 | [diff] [blame] | 235 | /*too_many_frames_queued=*/false), |
Evan Shrubsole | d6cdf80 | 2022-03-02 15:13:55 +0100 | [diff] [blame] | 236 | kMinPacing); |
Johannes Kron | 985905d | 2021-06-29 11:37:06 +0200 | [diff] [blame] | 237 | // Allow a few ms to pass, this should be subtracted from the MaxWaitingTime. |
Evan Shrubsole | d6cdf80 | 2022-03-02 15:13:55 +0100 | [diff] [blame] | 238 | constexpr TimeDelta kTwoMs = TimeDelta::Millis(2); |
| 239 | clock.AdvanceTime(kTwoMs); |
| 240 | now = clock.CurrentTime(); |
| 241 | EXPECT_EQ(timing.MaxWaitingTime(kZeroRenderTime, now, |
Johannes Kron | 2ddc39e | 2021-08-10 16:56:12 +0200 | [diff] [blame] | 242 | /*too_many_frames_queued=*/false), |
Evan Shrubsole | d6cdf80 | 2022-03-02 15:13:55 +0100 | [diff] [blame] | 243 | kMinPacing - kTwoMs); |
Rezaul Barbhuiya | 82c2248 | 2021-08-05 17:54:11 -0700 | [diff] [blame] | 244 | // A frame is decoded at the current time, the wait time should be restored to |
| 245 | // pacing delay. |
Evan Shrubsole | d6cdf80 | 2022-03-02 15:13:55 +0100 | [diff] [blame] | 246 | timing.SetLastDecodeScheduledTimestamp(now); |
| 247 | EXPECT_EQ(timing.MaxWaitingTime(kZeroRenderTime, now, |
Johannes Kron | 2ddc39e | 2021-08-10 16:56:12 +0200 | [diff] [blame] | 248 | /*too_many_frames_queued=*/false), |
Evan Shrubsole | d6cdf80 | 2022-03-02 15:13:55 +0100 | [diff] [blame] | 249 | kMinPacing); |
Johannes Kron | 985905d | 2021-06-29 11:37:06 +0200 | [diff] [blame] | 250 | } |
| 251 | |
| 252 | TEST(ReceiverTimingTest, DefaultMaxWaitingTimeUnaffectedByPacingExperiment) { |
| 253 | // The minimum pacing is enabled by a field trial but should not have any |
| 254 | // effect if render_time_ms is greater than 0; |
Jonas Oreland | e02f9ee | 2022-03-25 12:43:14 +0100 | [diff] [blame] | 255 | test::ScopedKeyValueConfig field_trials( |
Johannes Kron | 985905d | 2021-06-29 11:37:06 +0200 | [diff] [blame] | 256 | "WebRTC-ZeroPlayoutDelay/min_pacing:3ms/"); |
| 257 | constexpr int64_t kStartTimeUs = 3.15e13; // About one year in us. |
Evan Shrubsole | d6cdf80 | 2022-03-02 15:13:55 +0100 | [diff] [blame] | 258 | const TimeDelta kTimeDelta = TimeDelta::Millis(1000.0 / 60.0); |
Johannes Kron | 985905d | 2021-06-29 11:37:06 +0200 | [diff] [blame] | 259 | SimulatedClock clock(kStartTimeUs); |
Jonas Oreland | e02f9ee | 2022-03-25 12:43:14 +0100 | [diff] [blame] | 260 | VCMTiming timing(&clock, field_trials); |
Johannes Kron | 985905d | 2021-06-29 11:37:06 +0200 | [diff] [blame] | 261 | timing.Reset(); |
Evan Shrubsole | d6cdf80 | 2022-03-02 15:13:55 +0100 | [diff] [blame] | 262 | clock.AdvanceTime(kTimeDelta); |
| 263 | auto now = clock.CurrentTime(); |
| 264 | Timestamp render_time = now + TimeDelta::Millis(30); |
Johannes Kron | 985905d | 2021-06-29 11:37:06 +0200 | [diff] [blame] | 265 | // Estimate the internal processing delay from the first frame. |
Evan Shrubsole | d6cdf80 | 2022-03-02 15:13:55 +0100 | [diff] [blame] | 266 | TimeDelta estimated_processing_delay = |
| 267 | (render_time - now) - |
| 268 | timing.MaxWaitingTime(render_time, now, |
Johannes Kron | 2ddc39e | 2021-08-10 16:56:12 +0200 | [diff] [blame] | 269 | /*too_many_frames_queued=*/false); |
Evan Shrubsole | d6cdf80 | 2022-03-02 15:13:55 +0100 | [diff] [blame] | 270 | EXPECT_GT(estimated_processing_delay, TimeDelta::Zero()); |
Johannes Kron | 985905d | 2021-06-29 11:37:06 +0200 | [diff] [blame] | 271 | |
| 272 | // Any other frame submitted at the same time should be scheduled according to |
| 273 | // its render time. |
| 274 | for (int i = 0; i < 5; ++i) { |
Evan Shrubsole | d6cdf80 | 2022-03-02 15:13:55 +0100 | [diff] [blame] | 275 | render_time += kTimeDelta; |
| 276 | EXPECT_EQ(timing.MaxWaitingTime(render_time, now, |
Johannes Kron | 2ddc39e | 2021-08-10 16:56:12 +0200 | [diff] [blame] | 277 | /*too_many_frames_queued=*/false), |
Evan Shrubsole | d6cdf80 | 2022-03-02 15:13:55 +0100 | [diff] [blame] | 278 | render_time - now - estimated_processing_delay); |
Johannes Kron | 985905d | 2021-06-29 11:37:06 +0200 | [diff] [blame] | 279 | } |
| 280 | } |
| 281 | |
Evan Shrubsole | d6cdf80 | 2022-03-02 15:13:55 +0100 | [diff] [blame] | 282 | TEST(ReceiverTimingTest, MaxWaitingTimeReturnsZeroIfTooManyFramesQueuedIsTrue) { |
Johannes Kron | 2ddc39e | 2021-08-10 16:56:12 +0200 | [diff] [blame] | 283 | // The minimum pacing is enabled by a field trial and active if the RTP |
| 284 | // playout delay header extension is set to min==0. |
Evan Shrubsole | d6cdf80 | 2022-03-02 15:13:55 +0100 | [diff] [blame] | 285 | constexpr TimeDelta kMinPacing = TimeDelta::Millis(3); |
Jonas Oreland | e02f9ee | 2022-03-25 12:43:14 +0100 | [diff] [blame] | 286 | test::ScopedKeyValueConfig field_trials( |
Johannes Kron | 2ddc39e | 2021-08-10 16:56:12 +0200 | [diff] [blame] | 287 | "WebRTC-ZeroPlayoutDelay/min_pacing:3ms/"); |
| 288 | constexpr int64_t kStartTimeUs = 3.15e13; // About one year in us. |
Evan Shrubsole | d6cdf80 | 2022-03-02 15:13:55 +0100 | [diff] [blame] | 289 | const TimeDelta kTimeDelta = TimeDelta::Millis(1000.0 / 60.0); |
| 290 | constexpr auto kZeroRenderTime = Timestamp::Zero(); |
Johannes Kron | 2ddc39e | 2021-08-10 16:56:12 +0200 | [diff] [blame] | 291 | SimulatedClock clock(kStartTimeUs); |
Jonas Oreland | e02f9ee | 2022-03-25 12:43:14 +0100 | [diff] [blame] | 292 | VCMTiming timing(&clock, field_trials); |
Johannes Kron | 2ddc39e | 2021-08-10 16:56:12 +0200 | [diff] [blame] | 293 | timing.Reset(); |
| 294 | // MaxWaitingTime() returns zero for evenly spaced video frames. |
| 295 | for (int i = 0; i < 10; ++i) { |
Evan Shrubsole | d6cdf80 | 2022-03-02 15:13:55 +0100 | [diff] [blame] | 296 | clock.AdvanceTime(kTimeDelta); |
| 297 | auto now = clock.CurrentTime(); |
| 298 | EXPECT_EQ(timing.MaxWaitingTime(kZeroRenderTime, now, |
Johannes Kron | 2ddc39e | 2021-08-10 16:56:12 +0200 | [diff] [blame] | 299 | /*too_many_frames_queued=*/false), |
Evan Shrubsole | d6cdf80 | 2022-03-02 15:13:55 +0100 | [diff] [blame] | 300 | TimeDelta::Zero()); |
| 301 | timing.SetLastDecodeScheduledTimestamp(now); |
Johannes Kron | 2ddc39e | 2021-08-10 16:56:12 +0200 | [diff] [blame] | 302 | } |
| 303 | // Another frame submitted at the same time is paced according to the field |
| 304 | // trial setting. |
Evan Shrubsole | d6cdf80 | 2022-03-02 15:13:55 +0100 | [diff] [blame] | 305 | auto now_ms = clock.CurrentTime(); |
| 306 | EXPECT_EQ(timing.MaxWaitingTime(kZeroRenderTime, now_ms, |
Johannes Kron | 2ddc39e | 2021-08-10 16:56:12 +0200 | [diff] [blame] | 307 | /*too_many_frames_queued=*/false), |
Evan Shrubsole | d6cdf80 | 2022-03-02 15:13:55 +0100 | [diff] [blame] | 308 | kMinPacing); |
Johannes Kron | 2ddc39e | 2021-08-10 16:56:12 +0200 | [diff] [blame] | 309 | // MaxWaitingTime returns 0 even if there's a burst of frames if |
| 310 | // too_many_frames_queued is set to true. |
Evan Shrubsole | d6cdf80 | 2022-03-02 15:13:55 +0100 | [diff] [blame] | 311 | EXPECT_EQ(timing.MaxWaitingTime(kZeroRenderTime, now_ms, |
Johannes Kron | 2ddc39e | 2021-08-10 16:56:12 +0200 | [diff] [blame] | 312 | /*too_many_frames_queued=*/true), |
Evan Shrubsole | d6cdf80 | 2022-03-02 15:13:55 +0100 | [diff] [blame] | 313 | TimeDelta::Zero()); |
| 314 | EXPECT_EQ(timing.MaxWaitingTime(kZeroRenderTime, now_ms, |
Johannes Kron | 2ddc39e | 2021-08-10 16:56:12 +0200 | [diff] [blame] | 315 | /*too_many_frames_queued=*/true), |
Evan Shrubsole | d6cdf80 | 2022-03-02 15:13:55 +0100 | [diff] [blame] | 316 | TimeDelta::Zero()); |
Johannes Kron | 2ddc39e | 2021-08-10 16:56:12 +0200 | [diff] [blame] | 317 | } |
| 318 | |
stefan@webrtc.org | 9f557c1 | 2013-05-17 12:55:07 +0000 | [diff] [blame] | 319 | } // namespace webrtc |