Switch VideoReceiveStream2 internals to Time units

Change-Id: Ifcee6372120e968499acbdf3bf2c0d002d1c4724
Bug: webrtc:13756
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/259777
Reviewed-by: Erik Språng <sprang@webrtc.org>
Commit-Queue: Evan Shrubsole <eshr@webrtc.org>
Reviewed-by: Tomas Gunnarsson <tommi@webrtc.org>
Reviewed-by: Johannes Kron <kron@google.com>
Cr-Commit-Position: refs/heads/main@{#36685}
This commit is contained in:
Evan Shrubsole 2022-04-28 10:18:12 +02:00 committed by WebRTC LUCI CQ
parent 72efd91d1f
commit d425f506ad
6 changed files with 123 additions and 110 deletions

View File

@ -32,6 +32,11 @@ namespace webrtc {
// microseconds (us).
class TimeDelta final : public rtc_units_impl::RelativeUnit<TimeDelta> {
public:
template <typename T>
static constexpr TimeDelta Minutes(T value) {
static_assert(std::is_arithmetic<T>::value, "");
return Seconds(value * 60);
}
template <typename T>
static constexpr TimeDelta Seconds(T value) {
static_assert(std::is_arithmetic<T>::value, "");

View File

@ -28,10 +28,12 @@ TEST(TimeDeltaTest, ConstExpr) {
static_assert(kTimeDeltaPlusInf > kTimeDeltaZero, "");
constexpr TimeDelta kTimeDeltaMinutes = TimeDelta::Minutes(kValue);
constexpr TimeDelta kTimeDeltaSeconds = TimeDelta::Seconds(kValue);
constexpr TimeDelta kTimeDeltaMs = TimeDelta::Millis(kValue);
constexpr TimeDelta kTimeDeltaUs = TimeDelta::Micros(kValue);
static_assert(kTimeDeltaMinutes.seconds_or(0) == kValue * 60, "");
static_assert(kTimeDeltaSeconds.seconds_or(0) == kValue, "");
static_assert(kTimeDeltaMs.ms_or(0) == kValue, "");
static_assert(kTimeDeltaUs.us_or(0) == kValue, "");
@ -54,10 +56,12 @@ TEST(TimeDeltaTest, GetDifferentPrefix) {
EXPECT_EQ(TimeDelta::Micros(kValue).seconds(), kValue / 1000000);
EXPECT_EQ(TimeDelta::Millis(kValue).seconds(), kValue / 1000);
EXPECT_EQ(TimeDelta::Micros(kValue).ms(), kValue / 1000);
EXPECT_EQ(TimeDelta::Minutes(kValue / 60).seconds(), kValue);
EXPECT_EQ(TimeDelta::Millis(kValue).us(), kValue * 1000);
EXPECT_EQ(TimeDelta::Seconds(kValue).ms(), kValue * 1000);
EXPECT_EQ(TimeDelta::Seconds(kValue).us(), kValue * 1000000);
EXPECT_EQ(TimeDelta::Minutes(kValue / 60).seconds(), kValue);
}
TEST(TimeDeltaTest, IdentityChecks) {

View File

@ -72,6 +72,7 @@ rtc_library("video") {
"../api/crypto:options",
"../api/rtc_event_log",
"../api/task_queue",
"../api/units:frequency",
"../api/units:time_delta",
"../api/units:timestamp",
"../api/video:encoded_image",

View File

@ -28,7 +28,9 @@
#include "api/scoped_refptr.h"
#include "api/sequence_checker.h"
#include "api/task_queue/task_queue_base.h"
#include "api/units/frequency.h"
#include "api/units/time_delta.h"
#include "api/units/timestamp.h"
#include "api/video/encoded_image.h"
#include "api/video_codecs/h264_profile_level_id.h"
#include "api/video_codecs/sdp_video_format.h"
@ -70,14 +72,14 @@
namespace webrtc {
namespace internal {
constexpr int VideoReceiveStream2::kMaxWaitForKeyFrameMs;
namespace {
constexpr int kMinBaseMinimumDelayMs = 0;
constexpr int kMaxBaseMinimumDelayMs = 10000;
constexpr int kMaxWaitForFrameMs = 3000;
// The default delay before re-requesting a key frame to be sent.
constexpr TimeDelta kMaxWaitForKeyFrame = TimeDelta::Millis(200);
constexpr TimeDelta kMinBaseMinimumDelay = TimeDelta::Zero();
constexpr TimeDelta kMaxBaseMinimumDelay = TimeDelta::Seconds(10);
constexpr TimeDelta kMaxWaitForFrame = TimeDelta::Seconds(3);
// Create a decoder for the preferred codec before the stream starts and any
// other decoder lazily on demand.
@ -178,25 +180,25 @@ bool IsKeyFrameAndUnspecifiedResolution(const EncodedFrame& frame) {
// TODO(https://bugs.webrtc.org/9974): Consider removing this workaround.
// Maximum time between frames before resetting the FrameBuffer to avoid RTP
// timestamps wraparound to affect FrameBuffer.
constexpr int kInactiveStreamThresholdMs = 600000; // 10 minutes.
constexpr TimeDelta kInactiveStreamThreshold = TimeDelta::Minutes(10);
} // namespace
int DetermineMaxWaitForFrame(const VideoReceiveStream::Config& config,
bool is_keyframe) {
TimeDelta DetermineMaxWaitForFrame(const VideoReceiveStream::Config& config,
bool is_keyframe) {
// A (arbitrary) conversion factor between the remotely signalled NACK buffer
// time (if not present defaults to 1000ms) and the maximum time we wait for a
// remote frame. Chosen to not change existing defaults when using not
// rtx-time.
const int conversion_factor = 3;
const TimeDelta rtp_history =
TimeDelta::Millis(config.rtp.nack.rtp_history_ms);
if (config.rtp.nack.rtp_history_ms > 0 &&
conversion_factor * config.rtp.nack.rtp_history_ms < kMaxWaitForFrameMs) {
return is_keyframe ? config.rtp.nack.rtp_history_ms
: conversion_factor * config.rtp.nack.rtp_history_ms;
if (rtp_history > TimeDelta::Zero() &&
conversion_factor * rtp_history < kMaxWaitForFrame) {
return is_keyframe ? rtp_history : conversion_factor * rtp_history;
}
return is_keyframe ? VideoReceiveStream2::kMaxWaitForKeyFrameMs
: kMaxWaitForFrameMs;
return is_keyframe ? kMaxWaitForKeyFrame : kMaxWaitForFrame;
}
VideoReceiveStream2::VideoReceiveStream2(
@ -242,8 +244,8 @@ VideoReceiveStream2::VideoReceiveStream2(
std::move(config_.frame_transformer),
call->trials()),
rtp_stream_sync_(call->worker_thread(), this),
max_wait_for_keyframe_ms_(DetermineMaxWaitForFrame(config_, true)),
max_wait_for_frame_ms_(DetermineMaxWaitForFrame(config_, false)),
max_wait_for_keyframe_(DetermineMaxWaitForFrame(config_, true)),
max_wait_for_frame_(DetermineMaxWaitForFrame(config_, false)),
maximum_pre_stream_decoders_("max", kDefaultMaximumPreStreamDecoders),
decode_sync_(decode_sync),
decode_queue_(task_queue_factory_->CreateTaskQueue(
@ -271,8 +273,8 @@ VideoReceiveStream2::VideoReceiveStream2(
frame_buffer_ = FrameBufferProxy::CreateFromFieldTrial(
clock_, call_->worker_thread(), timing_.get(), &stats_proxy_,
&decode_queue_, this, TimeDelta::Millis(max_wait_for_keyframe_ms_),
TimeDelta::Millis(max_wait_for_frame_ms_), decode_sync_, call_->trials());
&decode_queue_, this, max_wait_for_keyframe_, max_wait_for_frame_,
decode_sync_, call_->trials());
if (config_.rtp.rtx_ssrc) {
rtx_receive_stream_ = std::make_unique<RtxReceiveStream>(
@ -566,18 +568,22 @@ void VideoReceiveStream2::UpdateHistograms() {
bool VideoReceiveStream2::SetBaseMinimumPlayoutDelayMs(int delay_ms) {
RTC_DCHECK_RUN_ON(&worker_sequence_checker_);
if (delay_ms < kMinBaseMinimumDelayMs || delay_ms > kMaxBaseMinimumDelayMs) {
TimeDelta delay = TimeDelta::Millis(delay_ms);
if (delay < kMinBaseMinimumDelay || delay > kMaxBaseMinimumDelay) {
return false;
}
base_minimum_playout_delay_ms_ = delay_ms;
base_minimum_playout_delay_ = delay;
UpdatePlayoutDelays();
return true;
}
int VideoReceiveStream2::GetBaseMinimumPlayoutDelayMs() const {
RTC_DCHECK_RUN_ON(&worker_sequence_checker_);
return base_minimum_playout_delay_ms_;
constexpr TimeDelta kDefaultBaseMinPlayoutDelay = TimeDelta::Millis(-1);
// Unset must be -1.
static_assert(-1 == kDefaultBaseMinPlayoutDelay.ms(), "");
return base_minimum_playout_delay_.value_or(kDefaultBaseMinPlayoutDelay).ms();
}
void VideoReceiveStream2::OnFrame(const VideoFrame& video_frame) {
@ -640,14 +646,14 @@ void VideoReceiveStream2::SendNack(
rtp_video_stream_receiver_.RequestPacketRetransmit(sequence_numbers);
}
void VideoReceiveStream2::RequestKeyFrame(int64_t timestamp_ms) {
void VideoReceiveStream2::RequestKeyFrame(Timestamp now) {
// Running on worker_sequence_checker_.
// Called from RtpVideoStreamReceiver (rtp_video_stream_receiver_ is
// ultimately responsible).
rtp_video_stream_receiver_.RequestKeyFrame();
decode_queue_.PostTask([this, timestamp_ms]() {
decode_queue_.PostTask([this, now]() {
RTC_DCHECK_RUN_ON(&decode_queue_);
last_keyframe_request_ms_ = timestamp_ms;
last_keyframe_request_ = now;
});
}
@ -658,21 +664,20 @@ void VideoReceiveStream2::OnCompleteFrame(std::unique_ptr<EncodedFrame> frame) {
// TODO(https://bugs.webrtc.org/13343): Remove this check when FrameBuffer3 is
// deployed. With FrameBuffer3, this case is properly handled and tested in
// the FrameBufferProxyTest.PausedStream unit test.
int64_t time_now_ms = clock_->TimeInMilliseconds();
if (last_complete_frame_time_ms_ > 0 &&
time_now_ms - last_complete_frame_time_ms_ > kInactiveStreamThresholdMs) {
Timestamp time_now = clock_->CurrentTime();
if (last_complete_frame_time_ &&
time_now - *last_complete_frame_time_ > kInactiveStreamThreshold) {
frame_buffer_->Clear();
}
last_complete_frame_time_ms_ = time_now_ms;
last_complete_frame_time_ = time_now;
const VideoPlayoutDelay& playout_delay = frame->EncodedImage().playout_delay_;
if (playout_delay.min_ms >= 0) {
frame_minimum_playout_delay_ms_ = playout_delay.min_ms;
frame_minimum_playout_delay_ = TimeDelta::Millis(playout_delay.min_ms);
UpdatePlayoutDelays();
}
if (playout_delay.max_ms >= 0) {
frame_maximum_playout_delay_ms_ = playout_delay.max_ms;
frame_maximum_playout_delay_ = TimeDelta::Millis(playout_delay.max_ms);
UpdatePlayoutDelays();
}
@ -725,14 +730,13 @@ void VideoReceiveStream2::SetEstimatedPlayoutNtpTimestampMs(
bool VideoReceiveStream2::SetMinimumPlayoutDelay(int delay_ms) {
RTC_DCHECK_RUN_ON(&worker_sequence_checker_);
syncable_minimum_playout_delay_ms_ = delay_ms;
syncable_minimum_playout_delay_ = TimeDelta::Millis(delay_ms);
UpdatePlayoutDelays();
return true;
}
int64_t VideoReceiveStream2::GetMaxWaitMs() const {
return keyframe_required_ ? max_wait_for_keyframe_ms_
: max_wait_for_frame_ms_;
TimeDelta VideoReceiveStream2::GetMaxWait() const {
return keyframe_required_ ? max_wait_for_keyframe_ : max_wait_for_frame_;
}
void VideoReceiveStream2::OnEncodedFrame(std::unique_ptr<EncodedFrame> frame) {
@ -759,8 +763,7 @@ void VideoReceiveStream2::OnDecodableFrameTimeout(TimeDelta wait_time) {
// TODO(bugs.webrtc.org/11993): PostTask to the network thread.
RTC_DCHECK_RUN_ON(&packet_sequence_checker_);
int64_t now_ms = clock_->TimeInMilliseconds();
HandleFrameBufferTimeout(now_ms, wait_time.ms());
HandleFrameBufferTimeout(clock_->CurrentTime(), wait_time);
decode_queue_.PostTask([this] {
RTC_DCHECK_RUN_ON(&decode_queue_);
@ -771,7 +774,7 @@ void VideoReceiveStream2::OnDecodableFrameTimeout(TimeDelta wait_time) {
void VideoReceiveStream2::HandleEncodedFrame(
std::unique_ptr<EncodedFrame> frame) {
// Running on `decode_queue_`.
int64_t now_ms = clock_->TimeInMilliseconds();
Timestamp now = clock_->CurrentTime();
// Current OnPreDecode only cares about QP for VP8.
int qp = -1;
@ -786,7 +789,8 @@ void VideoReceiveStream2::HandleEncodedFrame(
int64_t decoded_frame_picture_id = -1;
const bool keyframe_request_is_due =
now_ms >= (last_keyframe_request_ms_ + max_wait_for_keyframe_ms_);
!last_keyframe_request_ ||
now >= (*last_keyframe_request_ + max_wait_for_keyframe_);
if (!video_receiver_.IsExternalDecoderRegistered(frame->PayloadType())) {
// Look for the decoder with this payload type.
@ -823,14 +827,14 @@ void VideoReceiveStream2::HandleEncodedFrame(
// TODO(bugs.webrtc.org/11993): Make this PostTask to the network thread.
call_->worker_thread()->PostTask(ToQueuedTask(
task_safety_,
[this, now_ms, received_frame_is_keyframe, force_request_key_frame,
[this, now, received_frame_is_keyframe, force_request_key_frame,
decoded_frame_picture_id, keyframe_request_is_due]() {
RTC_DCHECK_RUN_ON(&packet_sequence_checker_);
if (decoded_frame_picture_id != -1)
rtp_video_stream_receiver_.FrameDecoded(decoded_frame_picture_id);
HandleKeyFrameGeneration(received_frame_is_keyframe, now_ms,
HandleKeyFrameGeneration(received_frame_is_keyframe, now,
force_request_key_frame,
keyframe_request_is_due);
}));
@ -900,7 +904,7 @@ int VideoReceiveStream2::DecodeAndMaybeDispatchEncodedFrame(
// RTC_RUN_ON(packet_sequence_checker_)
void VideoReceiveStream2::HandleKeyFrameGeneration(
bool received_frame_is_keyframe,
int64_t now_ms,
Timestamp now,
bool always_request_key_frame,
bool keyframe_request_is_due) {
bool request_key_frame = always_request_key_frame;
@ -910,7 +914,7 @@ void VideoReceiveStream2::HandleKeyFrameGeneration(
if (received_frame_is_keyframe) {
keyframe_generation_requested_ = false;
} else if (keyframe_request_is_due) {
if (!IsReceivingKeyFrame(now_ms)) {
if (!IsReceivingKeyFrame(now)) {
request_key_frame = true;
}
} else {
@ -919,74 +923,75 @@ void VideoReceiveStream2::HandleKeyFrameGeneration(
}
if (request_key_frame) {
// HandleKeyFrameGeneration is initated from the decode thread -
// HandleKeyFrameGeneration is initiated from the decode thread -
// RequestKeyFrame() triggers a call back to the decode thread.
// Perhaps there's a way to avoid that.
RequestKeyFrame(now_ms);
RequestKeyFrame(now);
}
}
// RTC_RUN_ON(packet_sequence_checker_)
void VideoReceiveStream2::HandleFrameBufferTimeout(int64_t now_ms,
int64_t wait_ms) {
void VideoReceiveStream2::HandleFrameBufferTimeout(Timestamp now,
TimeDelta wait) {
absl::optional<int64_t> last_packet_ms =
rtp_video_stream_receiver_.LastReceivedPacketMs();
// To avoid spamming keyframe requests for a stream that is not active we
// check if we have received a packet within the last 5 seconds.
constexpr TimeDelta kInactiveDuraction = TimeDelta::Seconds(5);
const bool stream_is_active =
last_packet_ms && now_ms - *last_packet_ms < 5000;
last_packet_ms &&
now - Timestamp::Millis(*last_packet_ms) < kInactiveDuraction;
if (!stream_is_active)
stats_proxy_.OnStreamInactive();
if (stream_is_active && !IsReceivingKeyFrame(now_ms) &&
if (stream_is_active && !IsReceivingKeyFrame(now) &&
(!config_.crypto_options.sframe.require_frame_encryption ||
rtp_video_stream_receiver_.IsDecryptable())) {
RTC_LOG(LS_WARNING) << "No decodable frame in " << wait_ms
<< " ms, requesting keyframe.";
RequestKeyFrame(now_ms);
RTC_LOG(LS_WARNING) << "No decodable frame in " << wait
<< ", requesting keyframe.";
RequestKeyFrame(now);
}
}
// RTC_RUN_ON(packet_sequence_checker_)
bool VideoReceiveStream2::IsReceivingKeyFrame(int64_t timestamp_ms) const {
bool VideoReceiveStream2::IsReceivingKeyFrame(Timestamp now) const {
absl::optional<int64_t> last_keyframe_packet_ms =
rtp_video_stream_receiver_.LastReceivedKeyframePacketMs();
// If we recently have been receiving packets belonging to a keyframe then
// we assume a keyframe is currently being received.
bool receiving_keyframe =
last_keyframe_packet_ms &&
timestamp_ms - *last_keyframe_packet_ms < max_wait_for_keyframe_ms_;
bool receiving_keyframe = last_keyframe_packet_ms &&
now - Timestamp::Millis(*last_keyframe_packet_ms) <
max_wait_for_keyframe_;
return receiving_keyframe;
}
void VideoReceiveStream2::UpdatePlayoutDelays() const {
// Running on worker_sequence_checker_.
const int minimum_delay_ms =
std::max({frame_minimum_playout_delay_ms_, base_minimum_playout_delay_ms_,
syncable_minimum_playout_delay_ms_});
if (minimum_delay_ms >= 0) {
timing_->set_min_playout_delay(TimeDelta::Millis(minimum_delay_ms));
if (frame_minimum_playout_delay_ms_ == 0 &&
frame_maximum_playout_delay_ms_ > 0) {
// Since nullopt < anything, this will return the largest of the minumum
// delays, or nullopt if all are nullopt.
absl::optional<TimeDelta> minimum_delay =
std::max({frame_minimum_playout_delay_, base_minimum_playout_delay_,
syncable_minimum_playout_delay_});
if (minimum_delay) {
timing_->set_min_playout_delay(*minimum_delay);
if (frame_minimum_playout_delay_ == TimeDelta::Zero() &&
frame_maximum_playout_delay_ > TimeDelta::Zero()) {
// TODO(kron): Estimate frame rate from video stream.
constexpr double kFrameRate = 60.0;
constexpr Frequency kFrameRate = Frequency::Hertz(60);
// Convert playout delay in ms to number of frames.
int max_composition_delay_in_frames = std::lrint(
static_cast<double>(frame_maximum_playout_delay_ms_ * kFrameRate) /
rtc::kNumMillisecsPerSec);
int max_composition_delay_in_frames =
std::lrint(*frame_maximum_playout_delay_ * kFrameRate);
// Subtract frames in buffer.
max_composition_delay_in_frames = std::max<int16_t>(
max_composition_delay_in_frames - frame_buffer_->Size(), 0);
timing_->SetMaxCompositionDelayInFrames(
absl::make_optional(max_composition_delay_in_frames));
max_composition_delay_in_frames =
std::max(max_composition_delay_in_frames - frame_buffer_->Size(), 0);
timing_->SetMaxCompositionDelayInFrames(max_composition_delay_in_frames);
}
}
const int maximum_delay_ms = frame_maximum_playout_delay_ms_;
if (maximum_delay_ms >= 0) {
timing_->set_max_playout_delay(TimeDelta::Millis(maximum_delay_ms));
if (frame_maximum_playout_delay_) {
timing_->set_max_playout_delay(*frame_maximum_playout_delay_);
}
}
@ -1006,15 +1011,16 @@ VideoReceiveStream2::SetAndGetRecordingState(RecordingState state,
decode_queue_.PostTask(
[this, &event, &old_state, callback = std::move(state.callback),
generate_key_frame,
last_keyframe_request = state.last_keyframe_request_ms.value_or(0)] {
last_keyframe_request =
Timestamp::Millis(state.last_keyframe_request_ms.value_or(0))] {
RTC_DCHECK_RUN_ON(&decode_queue_);
old_state.callback = std::move(encoded_frame_buffer_function_);
encoded_frame_buffer_function_ = std::move(callback);
old_state.last_keyframe_request_ms = last_keyframe_request_ms_;
last_keyframe_request_ms_ = generate_key_frame
? clock_->TimeInMilliseconds()
: last_keyframe_request;
old_state.last_keyframe_request_ms =
last_keyframe_request_.value_or(Timestamp::Zero()).ms();
last_keyframe_request_ =
generate_key_frame ? clock_->CurrentTime() : last_keyframe_request;
event.Set();
});
@ -1034,7 +1040,7 @@ VideoReceiveStream2::SetAndGetRecordingState(RecordingState state,
void VideoReceiveStream2::GenerateKeyFrame() {
RTC_DCHECK_RUN_ON(&packet_sequence_checker_);
RequestKeyFrame(clock_->TimeInMilliseconds());
RequestKeyFrame(clock_->CurrentTime());
keyframe_generation_requested_ = true;
}

View File

@ -17,6 +17,7 @@
#include "api/sequence_checker.h"
#include "api/task_queue/task_queue_factory.h"
#include "api/units/time_delta.h"
#include "api/units/timestamp.h"
#include "api/video/recordable_encoded_frame.h"
#include "call/call.h"
@ -53,7 +54,7 @@ class CallStats;
// Utility struct for grabbing metadata from a VideoFrame and processing it
// asynchronously without needing the actual frame data.
// Additionally the caller can bundle information from the current clock
// when the metadata is captured, for accurate reporting and not needeing
// when the metadata is captured, for accurate reporting and not needing
// multiple calls to clock->Now().
struct VideoFrameMetaData {
VideoFrameMetaData(const webrtc::VideoFrame& frame, Timestamp now)
@ -86,9 +87,6 @@ class VideoReceiveStream2
public CallStatsObserver,
public FrameSchedulingReceiver {
public:
// The default number of milliseconds to pass before re-requesting a key frame
// to be sent.
static constexpr int kMaxWaitForKeyFrameMs = 200;
// The maximum number of buffered encoded frames when encoded output is
// configured.
static constexpr size_t kBufferedEncodedFramesMaxSize = 60;
@ -189,21 +187,20 @@ class VideoReceiveStream2
void OnEncodedFrame(std::unique_ptr<EncodedFrame> frame) override;
void OnDecodableFrameTimeout(TimeDelta wait_time) override;
void CreateAndRegisterExternalDecoder(const Decoder& decoder);
int64_t GetMaxWaitMs() const RTC_RUN_ON(decode_queue_);
TimeDelta GetMaxWait() const RTC_RUN_ON(decode_queue_);
void HandleEncodedFrame(std::unique_ptr<EncodedFrame> frame)
RTC_RUN_ON(decode_queue_);
void HandleFrameBufferTimeout(int64_t now_ms, int64_t wait_ms)
void HandleFrameBufferTimeout(Timestamp now, TimeDelta wait)
RTC_RUN_ON(packet_sequence_checker_);
void UpdatePlayoutDelays() const
RTC_EXCLUSIVE_LOCKS_REQUIRED(worker_sequence_checker_);
void RequestKeyFrame(int64_t timestamp_ms)
RTC_RUN_ON(packet_sequence_checker_);
void RequestKeyFrame(Timestamp now) RTC_RUN_ON(packet_sequence_checker_);
void HandleKeyFrameGeneration(bool received_frame_is_keyframe,
int64_t now_ms,
Timestamp now,
bool always_request_key_frame,
bool keyframe_request_is_due)
RTC_RUN_ON(packet_sequence_checker_);
bool IsReceivingKeyFrame(int64_t timestamp_ms) const
bool IsReceivingKeyFrame(Timestamp timestamp) const
RTC_RUN_ON(packet_sequence_checker_);
int DecodeAndMaybeDispatchEncodedFrame(std::unique_ptr<EncodedFrame> frame)
RTC_RUN_ON(decode_queue_);
@ -266,31 +263,32 @@ class VideoReceiveStream2
// If we have successfully decoded any frame.
bool frame_decoded_ RTC_GUARDED_BY(decode_queue_) = false;
int64_t last_keyframe_request_ms_ RTC_GUARDED_BY(decode_queue_) = 0;
int64_t last_complete_frame_time_ms_
RTC_GUARDED_BY(worker_sequence_checker_) = 0;
absl::optional<Timestamp> last_keyframe_request_
RTC_GUARDED_BY(decode_queue_);
absl::optional<Timestamp> last_complete_frame_time_
RTC_GUARDED_BY(worker_sequence_checker_);
// Keyframe request intervals are configurable through field trials.
const int max_wait_for_keyframe_ms_;
const int max_wait_for_frame_ms_;
const TimeDelta max_wait_for_keyframe_;
const TimeDelta max_wait_for_frame_;
// All of them tries to change current min_playout_delay on `timing_` but
// source of the change request is different in each case. Among them the
// biggest delay is used. -1 means use default value from the `timing_`.
//
// Minimum delay as decided by the RTP playout delay extension.
int frame_minimum_playout_delay_ms_ RTC_GUARDED_BY(worker_sequence_checker_) =
-1;
absl::optional<TimeDelta> frame_minimum_playout_delay_
RTC_GUARDED_BY(worker_sequence_checker_);
// Minimum delay as decided by the setLatency function in "webrtc/api".
int base_minimum_playout_delay_ms_ RTC_GUARDED_BY(worker_sequence_checker_) =
-1;
absl::optional<TimeDelta> base_minimum_playout_delay_
RTC_GUARDED_BY(worker_sequence_checker_);
// Minimum delay as decided by the A/V synchronization feature.
int syncable_minimum_playout_delay_ms_
RTC_GUARDED_BY(worker_sequence_checker_) = -1;
absl::optional<TimeDelta> syncable_minimum_playout_delay_
RTC_GUARDED_BY(worker_sequence_checker_);
// Maximum delay as decided by the RTP playout delay extension.
int frame_maximum_playout_delay_ms_ RTC_GUARDED_BY(worker_sequence_checker_) =
-1;
absl::optional<TimeDelta> frame_maximum_playout_delay_
RTC_GUARDED_BY(worker_sequence_checker_);
// Function that is triggered with encoded frames, if not empty.
std::function<void(const RecordableEncodedFrame&)>

View File

@ -483,7 +483,7 @@ TEST_F(VideoReceiveStream2TestWithFakeDecoder,
}
class VideoReceiveStream2TestWithSimulatedClock
: public ::testing::TestWithParam<std::tuple<int, bool>> {
: public ::testing::TestWithParam<std::tuple<TimeDelta, bool>> {
public:
class FakeRenderer : public rtc::VideoSinkInterface<webrtc::VideoFrame> {
public:
@ -531,7 +531,7 @@ class VideoReceiveStream2TestWithSimulatedClock
VideoReceiveStream::Config config(transport, decoder_factory);
config.rtp.remote_ssrc = 1111;
config.rtp.local_ssrc = 2222;
config.rtp.nack.rtp_history_ms = std::get<0>(GetParam()); // rtx-time.
config.rtp.nack.rtp_history_ms = std::get<0>(GetParam()).ms(); // rtx-time.
config.renderer = renderer;
VideoReceiveStream::Decoder fake_decoder;
fake_decoder.payload_type = 99;
@ -606,7 +606,7 @@ class VideoReceiveStream2TestWithSimulatedClock
TEST_P(VideoReceiveStream2TestWithSimulatedClock,
RequestsKeyFramesUntilKeyFrameReceived) {
auto tick = TimeDelta::Millis(std::get<0>(GetParam()) / 2);
auto tick = std::get<0>(GetParam()) / 2;
bool sent_rtcp = false;
EXPECT_CALL(mock_transport_, SendRtcp)
.Times(1)
@ -711,10 +711,9 @@ TEST_P(VideoReceiveStream2TestWithSimulatedClock,
INSTANTIATE_TEST_SUITE_P(
RtxTime,
VideoReceiveStream2TestWithSimulatedClock,
::testing::Combine(
::testing::Values(internal::VideoReceiveStream2::kMaxWaitForKeyFrameMs,
50 /*ms*/),
::testing::Bool()));
::testing::Combine(::testing::Values(TimeDelta::Millis(200),
TimeDelta::Millis(50)),
::testing::Bool()));
class VideoReceiveStream2TestWithLazyDecoderCreation : public ::testing::Test {
public: