Video stream timeout tracker returns the total delay

This will later be used when merging FrameBuffer3Proxy into
VideoReceiveStream2.

Bug: webrtc:14003
Change-Id: Ieb97767c40f494510873abe775fc339125036dc0
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/265923
Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org>
Commit-Queue: Evan Shrubsole <eshr@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#37237}
This commit is contained in:
Evan Shrubsole 2022-06-16 11:52:09 +00:00 committed by WebRTC LUCI CQ
parent 6e4d7e606c
commit a1d3ada96b
5 changed files with 46 additions and 44 deletions

View File

@ -416,6 +416,7 @@ rtc_library("video_receive_stream_timeout_tracker") {
deps = [ deps = [
"../api/task_queue", "../api/task_queue",
"../api/units:time_delta", "../api/units:time_delta",
"../api/units:timestamp",
"../rtc_base/task_utils:repeating_task", "../rtc_base/task_utils:repeating_task",
"../system_wrappers", "../system_wrappers",
] ]

View File

@ -369,14 +369,14 @@ class FrameBuffer3Proxy : public FrameBufferProxy {
})); }));
} }
void OnTimeout() { void OnTimeout(TimeDelta delay) {
RTC_DCHECK_RUN_ON(&worker_sequence_checker_); RTC_DCHECK_RUN_ON(&worker_sequence_checker_);
// If the stream is paused then ignore the timeout. // If the stream is paused then ignore the timeout.
if (!decoder_ready_for_new_frame_) { if (!decoder_ready_for_new_frame_) {
timeout_tracker_.Stop(); timeout_tracker_.Stop();
return; return;
} }
receiver_->OnDecodableFrameTimeout(MaxWait()); receiver_->OnDecodableFrameTimeout(delay);
// Stop sending timeouts until receive starts waiting for a new frame. // Stop sending timeouts until receive starts waiting for a new frame.
timeout_tracker_.Stop(); timeout_tracker_.Stop();
decoder_ready_for_new_frame_ = false; decoder_ready_for_new_frame_ = false;

View File

@ -22,7 +22,7 @@ VideoReceiveStreamTimeoutTracker::VideoReceiveStreamTimeoutTracker(
: clock_(clock), : clock_(clock),
bookkeeping_queue_(bookkeeping_queue), bookkeeping_queue_(bookkeeping_queue),
timeouts_(timeouts), timeouts_(timeouts),
callback_(std::move(callback)) {} timeout_cb_(std::move(callback)) {}
VideoReceiveStreamTimeoutTracker::~VideoReceiveStreamTimeoutTracker() { VideoReceiveStreamTimeoutTracker::~VideoReceiveStreamTimeoutTracker() {
RTC_DCHECK(!timeout_task_.Running()); RTC_DCHECK(!timeout_task_.Running());
@ -36,12 +36,11 @@ void VideoReceiveStreamTimeoutTracker::Start(bool waiting_for_keyframe) {
RTC_DCHECK(!timeout_task_.Running()); RTC_DCHECK(!timeout_task_.Running());
waiting_for_keyframe_ = waiting_for_keyframe; waiting_for_keyframe_ = waiting_for_keyframe;
TimeDelta timeout_delay = TimeoutForNextFrame(); TimeDelta timeout_delay = TimeoutForNextFrame();
timeout_ = clock_->CurrentTime() + timeout_delay; last_frame_ = clock_->CurrentTime();
timeout_task_ = RepeatingTaskHandle::DelayedStart( timeout_ = last_frame_ + timeout_delay;
bookkeeping_queue_, timeout_delay, [this] { timeout_task_ =
RTC_DCHECK_RUN_ON(bookkeeping_queue_); RepeatingTaskHandle::DelayedStart(bookkeeping_queue_, timeout_delay,
return HandleTimeoutTask(); [this] { return HandleTimeoutTask(); });
});
} }
void VideoReceiveStreamTimeoutTracker::Stop() { void VideoReceiveStreamTimeoutTracker::Stop() {
@ -60,7 +59,8 @@ void VideoReceiveStreamTimeoutTracker::SetWaitingForKeyframe() {
void VideoReceiveStreamTimeoutTracker::OnEncodedFrameReleased() { void VideoReceiveStreamTimeoutTracker::OnEncodedFrameReleased() {
// If we were waiting for a keyframe, then it has just been released. // If we were waiting for a keyframe, then it has just been released.
waiting_for_keyframe_ = false; waiting_for_keyframe_ = false;
timeout_ = clock_->CurrentTime() + TimeoutForNextFrame(); last_frame_ = clock_->CurrentTime();
timeout_ = last_frame_ + TimeoutForNextFrame();
} }
TimeDelta VideoReceiveStreamTimeoutTracker::HandleTimeoutTask() { TimeDelta VideoReceiveStreamTimeoutTracker::HandleTimeoutTask() {
@ -70,7 +70,7 @@ TimeDelta VideoReceiveStreamTimeoutTracker::HandleTimeoutTask() {
if (now >= timeout_) { if (now >= timeout_) {
TimeDelta timeout_delay = TimeoutForNextFrame(); TimeDelta timeout_delay = TimeoutForNextFrame();
timeout_ = now + timeout_delay; timeout_ = now + timeout_delay;
callback_(); timeout_cb_(now - last_frame_);
return timeout_delay; return timeout_delay;
} }
// Otherwise, `timeout_` changed since we scheduled a timeout. Reschedule // Otherwise, `timeout_` changed since we scheduled a timeout. Reschedule

View File

@ -15,6 +15,7 @@
#include "api/task_queue/task_queue_base.h" #include "api/task_queue/task_queue_base.h"
#include "api/units/time_delta.h" #include "api/units/time_delta.h"
#include "api/units/timestamp.h"
#include "rtc_base/task_utils/repeating_task.h" #include "rtc_base/task_utils/repeating_task.h"
#include "system_wrappers/include/clock.h" #include "system_wrappers/include/clock.h"
@ -27,7 +28,7 @@ class VideoReceiveStreamTimeoutTracker {
TimeDelta max_wait_for_frame; TimeDelta max_wait_for_frame;
}; };
using TimeoutCallback = std::function<void()>; using TimeoutCallback = std::function<void(TimeDelta wait)>;
VideoReceiveStreamTimeoutTracker(Clock* clock, VideoReceiveStreamTimeoutTracker(Clock* clock,
TaskQueueBase* const bookkeeping_queue, TaskQueueBase* const bookkeeping_queue,
const Timeouts& timeouts, const Timeouts& timeouts,
@ -54,9 +55,10 @@ class VideoReceiveStreamTimeoutTracker {
Clock* const clock_; Clock* const clock_;
TaskQueueBase* const bookkeeping_queue_; TaskQueueBase* const bookkeeping_queue_;
const Timeouts timeouts_; const Timeouts timeouts_;
const TimeoutCallback callback_; const TimeoutCallback timeout_cb_;
RepeatingTaskHandle timeout_task_; RepeatingTaskHandle timeout_task_;
Timestamp last_frame_ = Timestamp::MinusInfinity();
Timestamp timeout_ = Timestamp::MinusInfinity(); Timestamp timeout_ = Timestamp::MinusInfinity();
bool waiting_for_keyframe_; bool waiting_for_keyframe_;
}; };

View File

@ -11,9 +11,9 @@
#include "video/video_receive_stream_timeout_tracker.h" #include "video/video_receive_stream_timeout_tracker.h"
#include <utility> #include <utility>
#include <vector>
#include "api/task_queue/task_queue_base.h" #include "api/task_queue/task_queue_base.h"
#include "rtc_base/task_queue.h"
#include "test/gmock.h" #include "test/gmock.h"
#include "test/gtest.h" #include "test/gtest.h"
#include "test/time_controller/simulated_time_controller.h" #include "test/time_controller/simulated_time_controller.h"
@ -32,64 +32,63 @@ class VideoReceiveStreamTimeoutTrackerTest : public ::testing::Test {
public: public:
VideoReceiveStreamTimeoutTrackerTest() VideoReceiveStreamTimeoutTrackerTest()
: time_controller_(Timestamp::Millis(2000)), : time_controller_(Timestamp::Millis(2000)),
task_queue_(time_controller_.GetTaskQueueFactory()->CreateTaskQueue(
"scheduler",
TaskQueueFactory::Priority::NORMAL)),
timeout_tracker_(time_controller_.GetClock(), timeout_tracker_(time_controller_.GetClock(),
task_queue_.Get(), time_controller_.GetMainThread(),
config, config,
[this] { OnTimeout(); }) {} [this](TimeDelta delay) { OnTimeout(delay); }) {}
protected: protected:
template <class Task>
void OnQueue(Task&& t) {
task_queue_.PostTask(std::forward<Task>(t));
time_controller_.AdvanceTime(TimeDelta::Zero());
}
GlobalSimulatedTimeController time_controller_; GlobalSimulatedTimeController time_controller_;
rtc::TaskQueue task_queue_;
VideoReceiveStreamTimeoutTracker timeout_tracker_; VideoReceiveStreamTimeoutTracker timeout_tracker_;
int timeouts_ = 0; std::vector<TimeDelta> timeouts_;
private: private:
void OnTimeout() { ++timeouts_; } void OnTimeout(TimeDelta delay) { timeouts_.push_back(delay); }
}; };
TEST_F(VideoReceiveStreamTimeoutTrackerTest, TimeoutAfterInitialPeriod) { TEST_F(VideoReceiveStreamTimeoutTrackerTest, TimeoutAfterInitialPeriod) {
OnQueue([&] { timeout_tracker_.Start(true); }); timeout_tracker_.Start(true);
time_controller_.AdvanceTime(kMaxWaitForKeyframe); time_controller_.AdvanceTime(kMaxWaitForKeyframe);
EXPECT_EQ(1, timeouts_); EXPECT_THAT(timeouts_, testing::ElementsAre(kMaxWaitForKeyframe));
OnQueue([&] { timeout_tracker_.Stop(); }); timeout_tracker_.Stop();
} }
TEST_F(VideoReceiveStreamTimeoutTrackerTest, NoTimeoutAfterStop) { TEST_F(VideoReceiveStreamTimeoutTrackerTest, NoTimeoutAfterStop) {
OnQueue([&] { timeout_tracker_.Start(true); }); timeout_tracker_.Start(true);
time_controller_.AdvanceTime(kMaxWaitForKeyframe / 2); time_controller_.AdvanceTime(kMaxWaitForKeyframe / 2);
OnQueue([&] { timeout_tracker_.Stop(); }); timeout_tracker_.Stop();
time_controller_.AdvanceTime(kMaxWaitForKeyframe); time_controller_.AdvanceTime(kMaxWaitForKeyframe);
EXPECT_EQ(0, timeouts_); EXPECT_THAT(timeouts_, testing::IsEmpty());
} }
TEST_F(VideoReceiveStreamTimeoutTrackerTest, TimeoutForDeltaFrame) { TEST_F(VideoReceiveStreamTimeoutTrackerTest, TimeoutForDeltaFrame) {
OnQueue([&] { timeout_tracker_.Start(true); }); timeout_tracker_.Start(true);
time_controller_.AdvanceTime(TimeDelta::Millis(5)); time_controller_.AdvanceTime(TimeDelta::Millis(5));
OnQueue([&] { timeout_tracker_.OnEncodedFrameReleased(); }); timeout_tracker_.OnEncodedFrameReleased();
time_controller_.AdvanceTime(kMaxWaitForFrame); time_controller_.AdvanceTime(kMaxWaitForFrame);
EXPECT_EQ(1, timeouts_); EXPECT_THAT(timeouts_, testing::ElementsAre(kMaxWaitForFrame));
timeout_tracker_.Stop();
OnQueue([&] { timeout_tracker_.Stop(); });
} }
TEST_F(VideoReceiveStreamTimeoutTrackerTest, TimeoutForKeyframeWhenForced) { TEST_F(VideoReceiveStreamTimeoutTrackerTest, TimeoutForKeyframeWhenForced) {
OnQueue([&] { timeout_tracker_.Start(true); }); timeout_tracker_.Start(true);
time_controller_.AdvanceTime(TimeDelta::Millis(5)); time_controller_.AdvanceTime(TimeDelta::Millis(5));
OnQueue([&] { timeout_tracker_.OnEncodedFrameReleased(); }); timeout_tracker_.OnEncodedFrameReleased();
OnQueue([&] { timeout_tracker_.SetWaitingForKeyframe(); }); timeout_tracker_.SetWaitingForKeyframe();
time_controller_.AdvanceTime(kMaxWaitForKeyframe); time_controller_.AdvanceTime(kMaxWaitForKeyframe);
EXPECT_EQ(1, timeouts_); EXPECT_THAT(timeouts_, testing::ElementsAre(kMaxWaitForKeyframe));
timeout_tracker_.Stop();
}
OnQueue([&] { timeout_tracker_.Stop(); }); TEST_F(VideoReceiveStreamTimeoutTrackerTest, TotalTimeoutUsedInCallback) {
timeout_tracker_.Start(true);
time_controller_.AdvanceTime(kMaxWaitForKeyframe * 2);
timeout_tracker_.OnEncodedFrameReleased();
time_controller_.AdvanceTime(kMaxWaitForFrame * 2);
EXPECT_THAT(timeouts_,
testing::ElementsAre(kMaxWaitForKeyframe, kMaxWaitForKeyframe * 2,
kMaxWaitForFrame, kMaxWaitForFrame * 2));
timeout_tracker_.Stop();
} }
} // namespace webrtc } // namespace webrtc