1 /*
2 * Copyright (c) 2022 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
11 #include "video/video_receive_stream_timeout_tracker.h"
12
13 #include <algorithm>
14 #include <utility>
15
16 #include "rtc_base/logging.h"
17
18 namespace webrtc {
19
VideoReceiveStreamTimeoutTracker(Clock * clock,TaskQueueBase * const bookkeeping_queue,const Timeouts & timeouts,TimeoutCallback callback)20 VideoReceiveStreamTimeoutTracker::VideoReceiveStreamTimeoutTracker(
21 Clock* clock,
22 TaskQueueBase* const bookkeeping_queue,
23 const Timeouts& timeouts,
24 TimeoutCallback callback)
25 : clock_(clock),
26 bookkeeping_queue_(bookkeeping_queue),
27 timeouts_(timeouts),
28 timeout_cb_(std::move(callback)) {}
29
~VideoReceiveStreamTimeoutTracker()30 VideoReceiveStreamTimeoutTracker::~VideoReceiveStreamTimeoutTracker() {
31 RTC_DCHECK(!timeout_task_.Running());
32 }
33
Running() const34 bool VideoReceiveStreamTimeoutTracker::Running() const {
35 return timeout_task_.Running();
36 }
37
TimeUntilTimeout() const38 TimeDelta VideoReceiveStreamTimeoutTracker::TimeUntilTimeout() const {
39 return std::max(timeout_ - clock_->CurrentTime(), TimeDelta::Zero());
40 }
41
Start(bool waiting_for_keyframe)42 void VideoReceiveStreamTimeoutTracker::Start(bool waiting_for_keyframe) {
43 RTC_DCHECK_RUN_ON(bookkeeping_queue_);
44 RTC_DCHECK(!timeout_task_.Running());
45 waiting_for_keyframe_ = waiting_for_keyframe;
46 TimeDelta timeout_delay = TimeoutForNextFrame();
47 last_frame_ = clock_->CurrentTime();
48 timeout_ = last_frame_ + timeout_delay;
49 timeout_task_ =
50 RepeatingTaskHandle::DelayedStart(bookkeeping_queue_, timeout_delay,
51 [this] { return HandleTimeoutTask(); });
52 }
53
Stop()54 void VideoReceiveStreamTimeoutTracker::Stop() {
55 timeout_task_.Stop();
56 }
57
SetWaitingForKeyframe()58 void VideoReceiveStreamTimeoutTracker::SetWaitingForKeyframe() {
59 RTC_DCHECK_RUN_ON(bookkeeping_queue_);
60 waiting_for_keyframe_ = true;
61 TimeDelta timeout_delay = TimeoutForNextFrame();
62 if (clock_->CurrentTime() + timeout_delay < timeout_) {
63 Stop();
64 Start(waiting_for_keyframe_);
65 }
66 }
67
OnEncodedFrameReleased()68 void VideoReceiveStreamTimeoutTracker::OnEncodedFrameReleased() {
69 RTC_DCHECK_RUN_ON(bookkeeping_queue_);
70 // If we were waiting for a keyframe, then it has just been released.
71 waiting_for_keyframe_ = false;
72 last_frame_ = clock_->CurrentTime();
73 timeout_ = last_frame_ + TimeoutForNextFrame();
74 }
75
HandleTimeoutTask()76 TimeDelta VideoReceiveStreamTimeoutTracker::HandleTimeoutTask() {
77 RTC_DCHECK_RUN_ON(bookkeeping_queue_);
78 Timestamp now = clock_->CurrentTime();
79 // `timeout_` is hit and we have timed out. Schedule the next timeout at
80 // the timeout delay.
81 if (now >= timeout_) {
82 RTC_DLOG(LS_VERBOSE) << "Stream timeout at " << now;
83 TimeDelta timeout_delay = TimeoutForNextFrame();
84 timeout_ = now + timeout_delay;
85 timeout_cb_(now - last_frame_);
86 return timeout_delay;
87 }
88 // Otherwise, `timeout_` changed since we scheduled a timeout. Reschedule
89 // a timeout check.
90 return timeout_ - now;
91 }
92
SetTimeouts(Timeouts timeouts)93 void VideoReceiveStreamTimeoutTracker::SetTimeouts(Timeouts timeouts) {
94 RTC_DCHECK_RUN_ON(bookkeeping_queue_);
95 timeouts_ = timeouts;
96 }
97
98 } // namespace webrtc
99