1*d9f75844SAndroid Build Coastguard Worker /*
2*d9f75844SAndroid Build Coastguard Worker * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
3*d9f75844SAndroid Build Coastguard Worker *
4*d9f75844SAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license
5*d9f75844SAndroid Build Coastguard Worker * that can be found in the LICENSE file in the root of the source
6*d9f75844SAndroid Build Coastguard Worker * tree. An additional intellectual property rights grant can be found
7*d9f75844SAndroid Build Coastguard Worker * in the file PATENTS. All contributing project authors may
8*d9f75844SAndroid Build Coastguard Worker * be found in the AUTHORS file in the root of the source tree.
9*d9f75844SAndroid Build Coastguard Worker */
10*d9f75844SAndroid Build Coastguard Worker
11*d9f75844SAndroid Build Coastguard Worker #include "modules/video_coding/timing/timing.h"
12*d9f75844SAndroid Build Coastguard Worker
13*d9f75844SAndroid Build Coastguard Worker #include <algorithm>
14*d9f75844SAndroid Build Coastguard Worker
15*d9f75844SAndroid Build Coastguard Worker #include "api/units/time_delta.h"
16*d9f75844SAndroid Build Coastguard Worker #include "modules/video_coding/timing/timestamp_extrapolator.h"
17*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/experiments/field_trial_parser.h"
18*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/logging.h"
19*d9f75844SAndroid Build Coastguard Worker #include "system_wrappers/include/clock.h"
20*d9f75844SAndroid Build Coastguard Worker
21*d9f75844SAndroid Build Coastguard Worker namespace webrtc {
22*d9f75844SAndroid Build Coastguard Worker namespace {
23*d9f75844SAndroid Build Coastguard Worker
24*d9f75844SAndroid Build Coastguard Worker // Default pacing that is used for the low-latency renderer path.
25*d9f75844SAndroid Build Coastguard Worker constexpr TimeDelta kZeroPlayoutDelayDefaultMinPacing = TimeDelta::Millis(8);
26*d9f75844SAndroid Build Coastguard Worker constexpr TimeDelta kLowLatencyStreamMaxPlayoutDelayThreshold =
27*d9f75844SAndroid Build Coastguard Worker TimeDelta::Millis(500);
28*d9f75844SAndroid Build Coastguard Worker
CheckDelaysValid(TimeDelta min_delay,TimeDelta max_delay)29*d9f75844SAndroid Build Coastguard Worker void CheckDelaysValid(TimeDelta min_delay, TimeDelta max_delay) {
30*d9f75844SAndroid Build Coastguard Worker if (min_delay > max_delay) {
31*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_ERROR)
32*d9f75844SAndroid Build Coastguard Worker << "Playout delays set incorrectly: min playout delay (" << min_delay
33*d9f75844SAndroid Build Coastguard Worker << ") > max playout delay (" << max_delay
34*d9f75844SAndroid Build Coastguard Worker << "). This is undefined behaviour. Application writers should "
35*d9f75844SAndroid Build Coastguard Worker "ensure that the min delay is always less than or equals max "
36*d9f75844SAndroid Build Coastguard Worker "delay. If trying to use the playout delay header extensions "
37*d9f75844SAndroid Build Coastguard Worker "described in "
38*d9f75844SAndroid Build Coastguard Worker "https://webrtc.googlesource.com/src/+/refs/heads/main/docs/"
39*d9f75844SAndroid Build Coastguard Worker "native-code/rtp-hdrext/playout-delay/, be careful that a playout "
40*d9f75844SAndroid Build Coastguard Worker "delay hint or A/V sync settings may have caused this conflict.";
41*d9f75844SAndroid Build Coastguard Worker }
42*d9f75844SAndroid Build Coastguard Worker }
43*d9f75844SAndroid Build Coastguard Worker
44*d9f75844SAndroid Build Coastguard Worker } // namespace
45*d9f75844SAndroid Build Coastguard Worker
VCMTiming(Clock * clock,const FieldTrialsView & field_trials)46*d9f75844SAndroid Build Coastguard Worker VCMTiming::VCMTiming(Clock* clock, const FieldTrialsView& field_trials)
47*d9f75844SAndroid Build Coastguard Worker : clock_(clock),
48*d9f75844SAndroid Build Coastguard Worker ts_extrapolator_(
49*d9f75844SAndroid Build Coastguard Worker std::make_unique<TimestampExtrapolator>(clock_->CurrentTime())),
50*d9f75844SAndroid Build Coastguard Worker codec_timer_(std::make_unique<CodecTimer>()),
51*d9f75844SAndroid Build Coastguard Worker render_delay_(kDefaultRenderDelay),
52*d9f75844SAndroid Build Coastguard Worker min_playout_delay_(TimeDelta::Zero()),
53*d9f75844SAndroid Build Coastguard Worker max_playout_delay_(TimeDelta::Seconds(10)),
54*d9f75844SAndroid Build Coastguard Worker jitter_delay_(TimeDelta::Zero()),
55*d9f75844SAndroid Build Coastguard Worker current_delay_(TimeDelta::Zero()),
56*d9f75844SAndroid Build Coastguard Worker prev_frame_timestamp_(0),
57*d9f75844SAndroid Build Coastguard Worker num_decoded_frames_(0),
58*d9f75844SAndroid Build Coastguard Worker zero_playout_delay_min_pacing_("min_pacing",
59*d9f75844SAndroid Build Coastguard Worker kZeroPlayoutDelayDefaultMinPacing),
60*d9f75844SAndroid Build Coastguard Worker last_decode_scheduled_(Timestamp::Zero()) {
61*d9f75844SAndroid Build Coastguard Worker ParseFieldTrial({&zero_playout_delay_min_pacing_},
62*d9f75844SAndroid Build Coastguard Worker field_trials.Lookup("WebRTC-ZeroPlayoutDelay"));
63*d9f75844SAndroid Build Coastguard Worker }
64*d9f75844SAndroid Build Coastguard Worker
Reset()65*d9f75844SAndroid Build Coastguard Worker void VCMTiming::Reset() {
66*d9f75844SAndroid Build Coastguard Worker MutexLock lock(&mutex_);
67*d9f75844SAndroid Build Coastguard Worker ts_extrapolator_->Reset(clock_->CurrentTime());
68*d9f75844SAndroid Build Coastguard Worker codec_timer_ = std::make_unique<CodecTimer>();
69*d9f75844SAndroid Build Coastguard Worker render_delay_ = kDefaultRenderDelay;
70*d9f75844SAndroid Build Coastguard Worker min_playout_delay_ = TimeDelta::Zero();
71*d9f75844SAndroid Build Coastguard Worker jitter_delay_ = TimeDelta::Zero();
72*d9f75844SAndroid Build Coastguard Worker current_delay_ = TimeDelta::Zero();
73*d9f75844SAndroid Build Coastguard Worker prev_frame_timestamp_ = 0;
74*d9f75844SAndroid Build Coastguard Worker }
75*d9f75844SAndroid Build Coastguard Worker
set_render_delay(TimeDelta render_delay)76*d9f75844SAndroid Build Coastguard Worker void VCMTiming::set_render_delay(TimeDelta render_delay) {
77*d9f75844SAndroid Build Coastguard Worker MutexLock lock(&mutex_);
78*d9f75844SAndroid Build Coastguard Worker render_delay_ = render_delay;
79*d9f75844SAndroid Build Coastguard Worker }
80*d9f75844SAndroid Build Coastguard Worker
min_playout_delay() const81*d9f75844SAndroid Build Coastguard Worker TimeDelta VCMTiming::min_playout_delay() const {
82*d9f75844SAndroid Build Coastguard Worker MutexLock lock(&mutex_);
83*d9f75844SAndroid Build Coastguard Worker return min_playout_delay_;
84*d9f75844SAndroid Build Coastguard Worker }
85*d9f75844SAndroid Build Coastguard Worker
set_min_playout_delay(TimeDelta min_playout_delay)86*d9f75844SAndroid Build Coastguard Worker void VCMTiming::set_min_playout_delay(TimeDelta min_playout_delay) {
87*d9f75844SAndroid Build Coastguard Worker MutexLock lock(&mutex_);
88*d9f75844SAndroid Build Coastguard Worker if (min_playout_delay_ != min_playout_delay) {
89*d9f75844SAndroid Build Coastguard Worker CheckDelaysValid(min_playout_delay, max_playout_delay_);
90*d9f75844SAndroid Build Coastguard Worker min_playout_delay_ = min_playout_delay;
91*d9f75844SAndroid Build Coastguard Worker }
92*d9f75844SAndroid Build Coastguard Worker }
93*d9f75844SAndroid Build Coastguard Worker
set_max_playout_delay(TimeDelta max_playout_delay)94*d9f75844SAndroid Build Coastguard Worker void VCMTiming::set_max_playout_delay(TimeDelta max_playout_delay) {
95*d9f75844SAndroid Build Coastguard Worker MutexLock lock(&mutex_);
96*d9f75844SAndroid Build Coastguard Worker if (max_playout_delay_ != max_playout_delay) {
97*d9f75844SAndroid Build Coastguard Worker CheckDelaysValid(min_playout_delay_, max_playout_delay);
98*d9f75844SAndroid Build Coastguard Worker max_playout_delay_ = max_playout_delay;
99*d9f75844SAndroid Build Coastguard Worker }
100*d9f75844SAndroid Build Coastguard Worker }
101*d9f75844SAndroid Build Coastguard Worker
SetJitterDelay(TimeDelta jitter_delay)102*d9f75844SAndroid Build Coastguard Worker void VCMTiming::SetJitterDelay(TimeDelta jitter_delay) {
103*d9f75844SAndroid Build Coastguard Worker MutexLock lock(&mutex_);
104*d9f75844SAndroid Build Coastguard Worker if (jitter_delay != jitter_delay_) {
105*d9f75844SAndroid Build Coastguard Worker jitter_delay_ = jitter_delay;
106*d9f75844SAndroid Build Coastguard Worker // When in initial state, set current delay to minimum delay.
107*d9f75844SAndroid Build Coastguard Worker if (current_delay_.IsZero()) {
108*d9f75844SAndroid Build Coastguard Worker current_delay_ = jitter_delay_;
109*d9f75844SAndroid Build Coastguard Worker }
110*d9f75844SAndroid Build Coastguard Worker }
111*d9f75844SAndroid Build Coastguard Worker }
112*d9f75844SAndroid Build Coastguard Worker
UpdateCurrentDelay(uint32_t frame_timestamp)113*d9f75844SAndroid Build Coastguard Worker void VCMTiming::UpdateCurrentDelay(uint32_t frame_timestamp) {
114*d9f75844SAndroid Build Coastguard Worker MutexLock lock(&mutex_);
115*d9f75844SAndroid Build Coastguard Worker TimeDelta target_delay = TargetDelayInternal();
116*d9f75844SAndroid Build Coastguard Worker
117*d9f75844SAndroid Build Coastguard Worker if (current_delay_.IsZero()) {
118*d9f75844SAndroid Build Coastguard Worker // Not initialized, set current delay to target.
119*d9f75844SAndroid Build Coastguard Worker current_delay_ = target_delay;
120*d9f75844SAndroid Build Coastguard Worker } else if (target_delay != current_delay_) {
121*d9f75844SAndroid Build Coastguard Worker TimeDelta delay_diff = target_delay - current_delay_;
122*d9f75844SAndroid Build Coastguard Worker // Never change the delay with more than 100 ms every second. If we're
123*d9f75844SAndroid Build Coastguard Worker // changing the delay in too large steps we will get noticeable freezes. By
124*d9f75844SAndroid Build Coastguard Worker // limiting the change we can increase the delay in smaller steps, which
125*d9f75844SAndroid Build Coastguard Worker // will be experienced as the video is played in slow motion. When lowering
126*d9f75844SAndroid Build Coastguard Worker // the delay the video will be played at a faster pace.
127*d9f75844SAndroid Build Coastguard Worker TimeDelta max_change = TimeDelta::Zero();
128*d9f75844SAndroid Build Coastguard Worker if (frame_timestamp < 0x0000ffff && prev_frame_timestamp_ > 0xffff0000) {
129*d9f75844SAndroid Build Coastguard Worker // wrap
130*d9f75844SAndroid Build Coastguard Worker max_change =
131*d9f75844SAndroid Build Coastguard Worker TimeDelta::Millis(kDelayMaxChangeMsPerS *
132*d9f75844SAndroid Build Coastguard Worker (frame_timestamp + (static_cast<int64_t>(1) << 32) -
133*d9f75844SAndroid Build Coastguard Worker prev_frame_timestamp_) /
134*d9f75844SAndroid Build Coastguard Worker 90000);
135*d9f75844SAndroid Build Coastguard Worker } else {
136*d9f75844SAndroid Build Coastguard Worker max_change =
137*d9f75844SAndroid Build Coastguard Worker TimeDelta::Millis(kDelayMaxChangeMsPerS *
138*d9f75844SAndroid Build Coastguard Worker (frame_timestamp - prev_frame_timestamp_) / 90000);
139*d9f75844SAndroid Build Coastguard Worker }
140*d9f75844SAndroid Build Coastguard Worker
141*d9f75844SAndroid Build Coastguard Worker if (max_change <= TimeDelta::Zero()) {
142*d9f75844SAndroid Build Coastguard Worker // Any changes less than 1 ms are truncated and will be postponed.
143*d9f75844SAndroid Build Coastguard Worker // Negative change will be due to reordering and should be ignored.
144*d9f75844SAndroid Build Coastguard Worker return;
145*d9f75844SAndroid Build Coastguard Worker }
146*d9f75844SAndroid Build Coastguard Worker delay_diff = std::max(delay_diff, -max_change);
147*d9f75844SAndroid Build Coastguard Worker delay_diff = std::min(delay_diff, max_change);
148*d9f75844SAndroid Build Coastguard Worker
149*d9f75844SAndroid Build Coastguard Worker current_delay_ = current_delay_ + delay_diff;
150*d9f75844SAndroid Build Coastguard Worker }
151*d9f75844SAndroid Build Coastguard Worker prev_frame_timestamp_ = frame_timestamp;
152*d9f75844SAndroid Build Coastguard Worker }
153*d9f75844SAndroid Build Coastguard Worker
UpdateCurrentDelay(Timestamp render_time,Timestamp actual_decode_time)154*d9f75844SAndroid Build Coastguard Worker void VCMTiming::UpdateCurrentDelay(Timestamp render_time,
155*d9f75844SAndroid Build Coastguard Worker Timestamp actual_decode_time) {
156*d9f75844SAndroid Build Coastguard Worker MutexLock lock(&mutex_);
157*d9f75844SAndroid Build Coastguard Worker TimeDelta target_delay = TargetDelayInternal();
158*d9f75844SAndroid Build Coastguard Worker TimeDelta delayed =
159*d9f75844SAndroid Build Coastguard Worker (actual_decode_time - render_time) + RequiredDecodeTime() + render_delay_;
160*d9f75844SAndroid Build Coastguard Worker
161*d9f75844SAndroid Build Coastguard Worker // Only consider `delayed` as negative by more than a few microseconds.
162*d9f75844SAndroid Build Coastguard Worker if (delayed.ms() < 0) {
163*d9f75844SAndroid Build Coastguard Worker return;
164*d9f75844SAndroid Build Coastguard Worker }
165*d9f75844SAndroid Build Coastguard Worker if (current_delay_ + delayed <= target_delay) {
166*d9f75844SAndroid Build Coastguard Worker current_delay_ += delayed;
167*d9f75844SAndroid Build Coastguard Worker } else {
168*d9f75844SAndroid Build Coastguard Worker current_delay_ = target_delay;
169*d9f75844SAndroid Build Coastguard Worker }
170*d9f75844SAndroid Build Coastguard Worker }
171*d9f75844SAndroid Build Coastguard Worker
StopDecodeTimer(TimeDelta decode_time,Timestamp now)172*d9f75844SAndroid Build Coastguard Worker void VCMTiming::StopDecodeTimer(TimeDelta decode_time, Timestamp now) {
173*d9f75844SAndroid Build Coastguard Worker MutexLock lock(&mutex_);
174*d9f75844SAndroid Build Coastguard Worker codec_timer_->AddTiming(decode_time.ms(), now.ms());
175*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_GE(decode_time, TimeDelta::Zero());
176*d9f75844SAndroid Build Coastguard Worker ++num_decoded_frames_;
177*d9f75844SAndroid Build Coastguard Worker }
178*d9f75844SAndroid Build Coastguard Worker
IncomingTimestamp(uint32_t rtp_timestamp,Timestamp now)179*d9f75844SAndroid Build Coastguard Worker void VCMTiming::IncomingTimestamp(uint32_t rtp_timestamp, Timestamp now) {
180*d9f75844SAndroid Build Coastguard Worker MutexLock lock(&mutex_);
181*d9f75844SAndroid Build Coastguard Worker ts_extrapolator_->Update(now, rtp_timestamp);
182*d9f75844SAndroid Build Coastguard Worker }
183*d9f75844SAndroid Build Coastguard Worker
RenderTime(uint32_t frame_timestamp,Timestamp now) const184*d9f75844SAndroid Build Coastguard Worker Timestamp VCMTiming::RenderTime(uint32_t frame_timestamp, Timestamp now) const {
185*d9f75844SAndroid Build Coastguard Worker MutexLock lock(&mutex_);
186*d9f75844SAndroid Build Coastguard Worker return RenderTimeInternal(frame_timestamp, now);
187*d9f75844SAndroid Build Coastguard Worker }
188*d9f75844SAndroid Build Coastguard Worker
SetLastDecodeScheduledTimestamp(Timestamp last_decode_scheduled)189*d9f75844SAndroid Build Coastguard Worker void VCMTiming::SetLastDecodeScheduledTimestamp(
190*d9f75844SAndroid Build Coastguard Worker Timestamp last_decode_scheduled) {
191*d9f75844SAndroid Build Coastguard Worker MutexLock lock(&mutex_);
192*d9f75844SAndroid Build Coastguard Worker last_decode_scheduled_ = last_decode_scheduled;
193*d9f75844SAndroid Build Coastguard Worker }
194*d9f75844SAndroid Build Coastguard Worker
RenderTimeInternal(uint32_t frame_timestamp,Timestamp now) const195*d9f75844SAndroid Build Coastguard Worker Timestamp VCMTiming::RenderTimeInternal(uint32_t frame_timestamp,
196*d9f75844SAndroid Build Coastguard Worker Timestamp now) const {
197*d9f75844SAndroid Build Coastguard Worker if (UseLowLatencyRendering()) {
198*d9f75844SAndroid Build Coastguard Worker // Render as soon as possible or with low-latency renderer algorithm.
199*d9f75844SAndroid Build Coastguard Worker return Timestamp::Zero();
200*d9f75844SAndroid Build Coastguard Worker }
201*d9f75844SAndroid Build Coastguard Worker // Note that TimestampExtrapolator::ExtrapolateLocalTime is not a const
202*d9f75844SAndroid Build Coastguard Worker // method; it mutates the object's wraparound state.
203*d9f75844SAndroid Build Coastguard Worker Timestamp estimated_complete_time =
204*d9f75844SAndroid Build Coastguard Worker ts_extrapolator_->ExtrapolateLocalTime(frame_timestamp).value_or(now);
205*d9f75844SAndroid Build Coastguard Worker
206*d9f75844SAndroid Build Coastguard Worker // Make sure the actual delay stays in the range of `min_playout_delay_`
207*d9f75844SAndroid Build Coastguard Worker // and `max_playout_delay_`.
208*d9f75844SAndroid Build Coastguard Worker TimeDelta actual_delay =
209*d9f75844SAndroid Build Coastguard Worker current_delay_.Clamped(min_playout_delay_, max_playout_delay_);
210*d9f75844SAndroid Build Coastguard Worker return estimated_complete_time + actual_delay;
211*d9f75844SAndroid Build Coastguard Worker }
212*d9f75844SAndroid Build Coastguard Worker
RequiredDecodeTime() const213*d9f75844SAndroid Build Coastguard Worker TimeDelta VCMTiming::RequiredDecodeTime() const {
214*d9f75844SAndroid Build Coastguard Worker const int decode_time_ms = codec_timer_->RequiredDecodeTimeMs();
215*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_GE(decode_time_ms, 0);
216*d9f75844SAndroid Build Coastguard Worker return TimeDelta::Millis(decode_time_ms);
217*d9f75844SAndroid Build Coastguard Worker }
218*d9f75844SAndroid Build Coastguard Worker
MaxWaitingTime(Timestamp render_time,Timestamp now,bool too_many_frames_queued) const219*d9f75844SAndroid Build Coastguard Worker TimeDelta VCMTiming::MaxWaitingTime(Timestamp render_time,
220*d9f75844SAndroid Build Coastguard Worker Timestamp now,
221*d9f75844SAndroid Build Coastguard Worker bool too_many_frames_queued) const {
222*d9f75844SAndroid Build Coastguard Worker MutexLock lock(&mutex_);
223*d9f75844SAndroid Build Coastguard Worker
224*d9f75844SAndroid Build Coastguard Worker if (render_time.IsZero() && zero_playout_delay_min_pacing_->us() > 0 &&
225*d9f75844SAndroid Build Coastguard Worker min_playout_delay_.IsZero() && max_playout_delay_ > TimeDelta::Zero()) {
226*d9f75844SAndroid Build Coastguard Worker // `render_time` == 0 indicates that the frame should be decoded and
227*d9f75844SAndroid Build Coastguard Worker // rendered as soon as possible. However, the decoder can be choked if too
228*d9f75844SAndroid Build Coastguard Worker // many frames are sent at once. Therefore, limit the interframe delay to
229*d9f75844SAndroid Build Coastguard Worker // |zero_playout_delay_min_pacing_| unless too many frames are queued in
230*d9f75844SAndroid Build Coastguard Worker // which case the frames are sent to the decoder at once.
231*d9f75844SAndroid Build Coastguard Worker if (too_many_frames_queued) {
232*d9f75844SAndroid Build Coastguard Worker return TimeDelta::Zero();
233*d9f75844SAndroid Build Coastguard Worker }
234*d9f75844SAndroid Build Coastguard Worker Timestamp earliest_next_decode_start_time =
235*d9f75844SAndroid Build Coastguard Worker last_decode_scheduled_ + zero_playout_delay_min_pacing_;
236*d9f75844SAndroid Build Coastguard Worker TimeDelta max_wait_time = now >= earliest_next_decode_start_time
237*d9f75844SAndroid Build Coastguard Worker ? TimeDelta::Zero()
238*d9f75844SAndroid Build Coastguard Worker : earliest_next_decode_start_time - now;
239*d9f75844SAndroid Build Coastguard Worker return max_wait_time;
240*d9f75844SAndroid Build Coastguard Worker }
241*d9f75844SAndroid Build Coastguard Worker return render_time - now - RequiredDecodeTime() - render_delay_;
242*d9f75844SAndroid Build Coastguard Worker }
243*d9f75844SAndroid Build Coastguard Worker
TargetVideoDelay() const244*d9f75844SAndroid Build Coastguard Worker TimeDelta VCMTiming::TargetVideoDelay() const {
245*d9f75844SAndroid Build Coastguard Worker MutexLock lock(&mutex_);
246*d9f75844SAndroid Build Coastguard Worker return TargetDelayInternal();
247*d9f75844SAndroid Build Coastguard Worker }
248*d9f75844SAndroid Build Coastguard Worker
TargetDelayInternal() const249*d9f75844SAndroid Build Coastguard Worker TimeDelta VCMTiming::TargetDelayInternal() const {
250*d9f75844SAndroid Build Coastguard Worker return std::max(min_playout_delay_,
251*d9f75844SAndroid Build Coastguard Worker jitter_delay_ + RequiredDecodeTime() + render_delay_);
252*d9f75844SAndroid Build Coastguard Worker }
253*d9f75844SAndroid Build Coastguard Worker
RenderParameters() const254*d9f75844SAndroid Build Coastguard Worker VideoFrame::RenderParameters VCMTiming::RenderParameters() const {
255*d9f75844SAndroid Build Coastguard Worker MutexLock lock(&mutex_);
256*d9f75844SAndroid Build Coastguard Worker return {.use_low_latency_rendering = UseLowLatencyRendering(),
257*d9f75844SAndroid Build Coastguard Worker .max_composition_delay_in_frames = max_composition_delay_in_frames_};
258*d9f75844SAndroid Build Coastguard Worker }
259*d9f75844SAndroid Build Coastguard Worker
UseLowLatencyRendering() const260*d9f75844SAndroid Build Coastguard Worker bool VCMTiming::UseLowLatencyRendering() const {
261*d9f75844SAndroid Build Coastguard Worker // min_playout_delay_==0,
262*d9f75844SAndroid Build Coastguard Worker // max_playout_delay_<=kLowLatencyStreamMaxPlayoutDelayThreshold indicates
263*d9f75844SAndroid Build Coastguard Worker // that the low-latency path should be used, which means that frames should be
264*d9f75844SAndroid Build Coastguard Worker // decoded and rendered as soon as possible.
265*d9f75844SAndroid Build Coastguard Worker return min_playout_delay_.IsZero() &&
266*d9f75844SAndroid Build Coastguard Worker max_playout_delay_ <= kLowLatencyStreamMaxPlayoutDelayThreshold;
267*d9f75844SAndroid Build Coastguard Worker }
268*d9f75844SAndroid Build Coastguard Worker
GetTimings() const269*d9f75844SAndroid Build Coastguard Worker VCMTiming::VideoDelayTimings VCMTiming::GetTimings() const {
270*d9f75844SAndroid Build Coastguard Worker MutexLock lock(&mutex_);
271*d9f75844SAndroid Build Coastguard Worker return VideoDelayTimings{.max_decode_duration = RequiredDecodeTime(),
272*d9f75844SAndroid Build Coastguard Worker .current_delay = current_delay_,
273*d9f75844SAndroid Build Coastguard Worker .target_delay = TargetDelayInternal(),
274*d9f75844SAndroid Build Coastguard Worker .jitter_buffer_delay = jitter_delay_,
275*d9f75844SAndroid Build Coastguard Worker .min_playout_delay = min_playout_delay_,
276*d9f75844SAndroid Build Coastguard Worker .max_playout_delay = max_playout_delay_,
277*d9f75844SAndroid Build Coastguard Worker .render_delay = render_delay_,
278*d9f75844SAndroid Build Coastguard Worker .num_decoded_frames = num_decoded_frames_};
279*d9f75844SAndroid Build Coastguard Worker }
280*d9f75844SAndroid Build Coastguard Worker
SetTimingFrameInfo(const TimingFrameInfo & info)281*d9f75844SAndroid Build Coastguard Worker void VCMTiming::SetTimingFrameInfo(const TimingFrameInfo& info) {
282*d9f75844SAndroid Build Coastguard Worker MutexLock lock(&mutex_);
283*d9f75844SAndroid Build Coastguard Worker timing_frame_info_.emplace(info);
284*d9f75844SAndroid Build Coastguard Worker }
285*d9f75844SAndroid Build Coastguard Worker
GetTimingFrameInfo()286*d9f75844SAndroid Build Coastguard Worker absl::optional<TimingFrameInfo> VCMTiming::GetTimingFrameInfo() {
287*d9f75844SAndroid Build Coastguard Worker MutexLock lock(&mutex_);
288*d9f75844SAndroid Build Coastguard Worker return timing_frame_info_;
289*d9f75844SAndroid Build Coastguard Worker }
290*d9f75844SAndroid Build Coastguard Worker
SetMaxCompositionDelayInFrames(absl::optional<int> max_composition_delay_in_frames)291*d9f75844SAndroid Build Coastguard Worker void VCMTiming::SetMaxCompositionDelayInFrames(
292*d9f75844SAndroid Build Coastguard Worker absl::optional<int> max_composition_delay_in_frames) {
293*d9f75844SAndroid Build Coastguard Worker MutexLock lock(&mutex_);
294*d9f75844SAndroid Build Coastguard Worker max_composition_delay_in_frames_ = max_composition_delay_in_frames;
295*d9f75844SAndroid Build Coastguard Worker }
296*d9f75844SAndroid Build Coastguard Worker
297*d9f75844SAndroid Build Coastguard Worker } // namespace webrtc
298