Make nack history configurable.
This allows for `config_.rtp.nack.rtp_history_ms` to be modified
without deleting and recreating video receive streams.
Bug: webrtc:11993
Change-Id: I8ba132b22fe0e6de03d1c42fc38a570cbe138817
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/269301
Reviewed-by: Danil Chapovalov <danilchap@webrtc.org>
Commit-Queue: Tomas Gunnarsson <tommi@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#37701}
diff --git a/call/video_receive_stream.h b/call/video_receive_stream.h
index 998710d..451203b 100644
--- a/call/video_receive_stream.h
+++ b/call/video_receive_stream.h
@@ -298,6 +298,11 @@
// thread.
virtual void SetLossNotificationEnabled(bool enabled) = 0;
+ // Modify `rtp.nack.rtp_history_ms` post construction. Setting this value
+ // to 0 disables nack.
+ // Must be called on the packet delivery thread.
+ virtual void SetNackHistory(TimeDelta history) = 0;
+
protected:
virtual ~VideoReceiveStreamInterface() {}
};
diff --git a/media/engine/fake_webrtc_call.h b/media/engine/fake_webrtc_call.h
index 9276a78..c807d31 100644
--- a/media/engine/fake_webrtc_call.h
+++ b/media/engine/fake_webrtc_call.h
@@ -293,6 +293,10 @@
config_.rtp.lntf.enabled = enabled;
}
+ void SetNackHistory(webrtc::TimeDelta history) override {
+ config_.rtp.nack.rtp_history_ms = history.ms();
+ }
+
void Start() override;
void Stop() override;
diff --git a/media/engine/webrtc_video_engine.cc b/media/engine/webrtc_video_engine.cc
index 4cc18fb..c562abe 100644
--- a/media/engine/webrtc_video_engine.cc
+++ b/media/engine/webrtc_video_engine.cc
@@ -2991,26 +2991,32 @@
stream_->SetLossNotificationEnabled(has_lntf);
}
+ int new_history_ms = config_.rtp.nack.rtp_history_ms;
const int rtp_history_ms = HasNack(codec.codec) ? kNackHistoryMs : 0;
if (rtp_history_ms != config_.rtp.nack.rtp_history_ms) {
- config_.rtp.nack.rtp_history_ms = rtp_history_ms;
- recreate_needed = true;
+ new_history_ms = rtp_history_ms;
}
// The rtx-time parameter can be used to override the hardcoded default for
// the NACK buffer length.
- if (codec.rtx_time != -1 && config_.rtp.nack.rtp_history_ms != 0) {
- config_.rtp.nack.rtp_history_ms = codec.rtx_time;
- recreate_needed = true;
+ if (codec.rtx_time != -1 && new_history_ms != 0) {
+ new_history_ms = codec.rtx_time;
+ }
+
+ if (config_.rtp.nack.rtp_history_ms != new_history_ms) {
+ config_.rtp.nack.rtp_history_ms = new_history_ms;
+ stream_->SetNackHistory(webrtc::TimeDelta::Millis(new_history_ms));
}
const bool has_rtr = HasRrtr(codec.codec);
if (has_rtr != config_.rtp.rtcp_xr.receiver_reference_time_report) {
+ // TODO(tommi): Look into if/when this happens in practice.
config_.rtp.rtcp_xr.receiver_reference_time_report = has_rtr;
recreate_needed = true;
}
if (codec.ulpfec.red_rtx_payload_type != -1) {
+ // TODO(tommi): Look into if/when this happens in practice.
rtx_associated_payload_types[codec.ulpfec.red_rtx_payload_type] =
codec.ulpfec.red_payload_type;
}
@@ -3068,22 +3074,8 @@
int nack_history_ms =
nack_enabled ? rtx_time != -1 ? rtx_time : kNackHistoryMs : 0;
- if (config_.rtp.nack.rtp_history_ms == nack_history_ms) {
- RTC_LOG(LS_INFO)
- << "Ignoring call to SetFeedbackParameters because parameters are "
- "unchanged; nack="
- << nack_enabled << ", rtx_time=" << rtx_time;
- return;
- }
-
- RTC_LOG_F(LS_INFO) << "(recv) because of SetFeedbackParameters; nack="
- << nack_enabled << ". rtp_history_ms "
- << config_.rtp.nack.rtp_history_ms << "->"
- << nack_history_ms;
-
config_.rtp.nack.rtp_history_ms = nack_history_ms;
-
- RecreateReceiveStream();
+ stream_->SetNackHistory(webrtc::TimeDelta::Millis(nack_history_ms));
}
void WebRtcVideoChannel::WebRtcVideoReceiveStream::SetFlexFecPayload(
diff --git a/video/frame_buffer_proxy.cc b/video/frame_buffer_proxy.cc
index 9f79c92..f8901ae 100644
--- a/video/frame_buffer_proxy.cc
+++ b/video/frame_buffer_proxy.cc
@@ -173,6 +173,14 @@
jitter_estimator_.UpdateRtt(TimeDelta::Millis(max_rtt_ms));
}
+ void SetMaxWaits(TimeDelta max_wait_for_keyframe,
+ TimeDelta max_wait_for_frame) override {
+ RTC_DCHECK_RUN_ON(&worker_sequence_checker_);
+ timeout_tracker_.SetTimeouts(
+ {.max_wait_for_keyframe = max_wait_for_keyframe,
+ .max_wait_for_frame = max_wait_for_frame});
+ }
+
void StartNextDecode(bool keyframe_required) override {
if (!worker_queue_->IsCurrent()) {
worker_queue_->PostTask(SafeTask(
diff --git a/video/frame_buffer_proxy.h b/video/frame_buffer_proxy.h
index 1d440ed..a616d49 100644
--- a/video/frame_buffer_proxy.h
+++ b/video/frame_buffer_proxy.h
@@ -59,6 +59,8 @@
std::unique_ptr<EncodedFrame> frame) = 0;
virtual void UpdateRtt(int64_t max_rtt_ms) = 0;
virtual int Size() = 0;
+ virtual void SetMaxWaits(TimeDelta max_wait_for_keyframe,
+ TimeDelta max_wait_for_frame) = 0;
// Run on either the worker thread or the decode thread.
virtual void StartNextDecode(bool keyframe_required) = 0;
diff --git a/video/rtp_video_stream_receiver2.cc b/video/rtp_video_stream_receiver2.cc
index 2fe72d1..1f31c41 100644
--- a/video/rtp_video_stream_receiver2.cc
+++ b/video/rtp_video_stream_receiver2.cc
@@ -56,6 +56,8 @@
constexpr int kPacketBufferStartSize = 512;
constexpr int kPacketBufferMaxSize = 2048;
+constexpr int kMaxPacketAgeToNack = 450;
+
int PacketBufferMaxSize(const FieldTrialsView& field_trials) {
// The group here must be a positive power of 2, in which case that is used as
// size. All other values shall result in the default value being used.
@@ -105,12 +107,12 @@
std::unique_ptr<NackRequester> MaybeConstructNackModule(
TaskQueueBase* current_queue,
NackPeriodicProcessor* nack_periodic_processor,
- const VideoReceiveStreamInterface::Config& config,
+ const NackConfig& nack,
Clock* clock,
NackSender* nack_sender,
KeyFrameRequestSender* keyframe_request_sender,
const FieldTrialsView& field_trials) {
- if (config.rtp.nack.rtp_history_ms == 0)
+ if (nack.rtp_history_ms == 0)
return nullptr;
// TODO(bugs.webrtc.org/12420): pass rtp_history_ms to the nack module.
@@ -223,6 +225,7 @@
rtc::scoped_refptr<FrameTransformerInterface> frame_transformer,
const FieldTrialsView& field_trials)
: field_trials_(field_trials),
+ worker_queue_(current_queue),
clock_(clock),
config_(*config),
packet_router_(packet_router),
@@ -246,6 +249,7 @@
rtcp_cname_callback,
config_.rtp.rtcp_xr.receiver_reference_time_report,
config_.rtp.local_ssrc)),
+ nack_periodic_processor_(nack_periodic_processor),
complete_frame_callback_(complete_frame_callback),
keyframe_request_method_(config_.rtp.keyframe_method),
// TODO(bugs.webrtc.org/10336): Let `rtcp_feedback_buffer_` communicate
@@ -253,7 +257,7 @@
rtcp_feedback_buffer_(this, this, this),
nack_module_(MaybeConstructNackModule(current_queue,
nack_periodic_processor,
- config_,
+ config_.rtp.nack,
clock_,
&rtcp_feedback_buffer_,
&rtcp_feedback_buffer_,
@@ -280,7 +284,6 @@
rtp_rtcp_->SetRemoteSSRC(config_.rtp.remote_ssrc);
if (config_.rtp.nack.rtp_history_ms > 0) {
- static constexpr int kMaxPacketAgeToNack = 450;
rtp_receive_statistics_->SetMaxReorderingThreshold(config_.rtp.remote_ssrc,
kMaxPacketAgeToNack);
}
@@ -704,10 +707,6 @@
return config_.rtp.ulpfec_payload_type != -1;
}
-bool RtpVideoStreamReceiver2::IsRetransmissionsEnabled() const {
- return config_.rtp.nack.rtp_history_ms > 0;
-}
-
bool RtpVideoStreamReceiver2::IsDecryptable() const {
RTC_DCHECK_RUN_ON(&worker_task_checker_);
return frames_decryptable_;
@@ -919,7 +918,7 @@
}
void RtpVideoStreamReceiver2::UpdateRtt(int64_t max_rtt_ms) {
- RTC_DCHECK_RUN_ON(&worker_task_checker_);
+ RTC_DCHECK_RUN_ON(&packet_sequence_checker_);
if (nack_module_)
nack_module_->UpdateRtt(max_rtt_ms);
}
@@ -952,6 +951,21 @@
}
}
+void RtpVideoStreamReceiver2::SetNackHistory(TimeDelta history) {
+ RTC_DCHECK_RUN_ON(&packet_sequence_checker_);
+ if (history.ms() == 0) {
+ nack_module_.reset();
+ } else if (!nack_module_) {
+ nack_module_ = std::make_unique<NackRequester>(
+ worker_queue_, nack_periodic_processor_, clock_, &rtcp_feedback_buffer_,
+ &rtcp_feedback_buffer_, field_trials_);
+ }
+
+ rtp_receive_statistics_->SetMaxReorderingThreshold(
+ config_.rtp.remote_ssrc,
+ history.ms() > 0 ? kMaxPacketAgeToNack : kDefaultMaxReorderingThreshold);
+}
+
absl::optional<int64_t> RtpVideoStreamReceiver2::LastReceivedPacketMs() const {
RTC_DCHECK_RUN_ON(&packet_sequence_checker_);
if (last_received_rtp_system_time_) {
@@ -978,7 +992,7 @@
void RtpVideoStreamReceiver2::ReceivePacket(const RtpPacketReceived& packet) {
RTC_DCHECK_RUN_ON(&packet_sequence_checker_);
- RTC_DCHECK_RUN_ON(&worker_task_checker_);
+
if (packet.payload_size() == 0) {
// Padding or keep-alive packet.
// TODO(nisse): Could drop empty packets earlier, but need to figure out how
diff --git a/video/rtp_video_stream_receiver2.h b/video/rtp_video_stream_receiver2.h
index dff3bfc..4fc11da 100644
--- a/video/rtp_video_stream_receiver2.h
+++ b/video/rtp_video_stream_receiver2.h
@@ -149,7 +149,6 @@
bool buffering_allowed) override;
bool IsUlpfecEnabled() const;
- bool IsRetransmissionsEnabled() const;
// Returns true if a decryptor is attached and frames can be decrypted.
// Updated by OnDecryptionStatusChangeCallback. Note this refers to Frame
@@ -198,6 +197,8 @@
// thread.
void SetLossNotificationEnabled(bool enabled);
+ void SetNackHistory(TimeDelta history);
+
absl::optional<int64_t> LastReceivedPacketMs() const;
absl::optional<int64_t> LastReceivedKeyframePacketMs() const;
@@ -305,6 +306,7 @@
RTC_RUN_ON(packet_sequence_checker_);
const FieldTrialsView& field_trials_;
+ TaskQueueBase* const worker_queue_;
Clock* const clock_;
// Ownership of this object lies with VideoReceiveStreamInterface, which owns
// `this`.
@@ -337,11 +339,15 @@
const std::unique_ptr<ModuleRtpRtcpImpl2> rtp_rtcp_;
+ NackPeriodicProcessor* const nack_periodic_processor_;
OnCompleteFrameCallback* complete_frame_callback_;
const KeyFrameReqMethod keyframe_request_method_;
RtcpFeedbackBuffer rtcp_feedback_buffer_;
- const std::unique_ptr<NackRequester> nack_module_;
+ // TODO(tommi): Consider absl::optional<NackRequester> instead of unique_ptr
+ // since nack is usually configured.
+ std::unique_ptr<NackRequester> nack_module_
+ RTC_GUARDED_BY(packet_sequence_checker_);
std::unique_ptr<LossNotificationController> loss_notification_controller_
RTC_GUARDED_BY(packet_sequence_checker_);
diff --git a/video/video_receive_stream2.cc b/video/video_receive_stream2.cc
index f84b981..ec40b41 100644
--- a/video/video_receive_stream2.cc
+++ b/video/video_receive_stream2.cc
@@ -182,17 +182,12 @@
} // namespace
-TimeDelta DetermineMaxWaitForFrame(
- const VideoReceiveStreamInterface::Config& config,
- bool is_keyframe) {
+TimeDelta DetermineMaxWaitForFrame(TimeDelta rtp_history, 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 (rtp_history > TimeDelta::Zero() &&
conversion_factor * rtp_history < kMaxWaitForFrame) {
return is_keyframe ? rtp_history : conversion_factor * rtp_history;
@@ -238,8 +233,12 @@
std::move(config_.frame_transformer),
call->trials()),
rtp_stream_sync_(call->worker_thread(), this),
- max_wait_for_keyframe_(DetermineMaxWaitForFrame(config_, true)),
- max_wait_for_frame_(DetermineMaxWaitForFrame(config_, false)),
+ max_wait_for_keyframe_(DetermineMaxWaitForFrame(
+ TimeDelta::Millis(config_.rtp.nack.rtp_history_ms),
+ true)),
+ max_wait_for_frame_(DetermineMaxWaitForFrame(
+ TimeDelta::Millis(config_.rtp.nack.rtp_history_ms),
+ false)),
maximum_pre_stream_decoders_("max", kDefaultMaximumPreStreamDecoders),
decode_sync_(decode_sync),
decode_queue_(task_queue_factory_->CreateTaskQueue(
@@ -355,8 +354,7 @@
const bool protected_by_fec = config_.rtp.protected_by_flexfec ||
rtp_video_stream_receiver_.IsUlpfecEnabled();
- if (rtp_video_stream_receiver_.IsRetransmissionsEnabled() &&
- protected_by_fec) {
+ if (config_.rtp.nack.rtp_history_ms > 0 && protected_by_fec) {
frame_buffer_->SetProtectionMode(kProtectionNackFEC);
}
@@ -524,6 +522,36 @@
rtp_video_stream_receiver_.SetLossNotificationEnabled(enabled);
}
+void VideoReceiveStream2::SetNackHistory(TimeDelta history) {
+ RTC_DCHECK_RUN_ON(&packet_sequence_checker_);
+ RTC_DCHECK_GE(history.ms(), 0);
+
+ if (config_.rtp.nack.rtp_history_ms == history.ms())
+ return;
+
+ // TODO(tommi): Stop using the config struct for the internal state.
+ const_cast<int&>(config_.rtp.nack.rtp_history_ms) = history.ms();
+
+ const bool protected_by_fec = config_.rtp.protected_by_flexfec ||
+ rtp_video_stream_receiver_.IsUlpfecEnabled();
+
+ frame_buffer_->SetProtectionMode(history.ms() > 0 && protected_by_fec
+ ? kProtectionNackFEC
+ : kProtectionNack);
+
+ rtp_video_stream_receiver_.SetNackHistory(history);
+ TimeDelta max_wait_for_keyframe = DetermineMaxWaitForFrame(history, true);
+ TimeDelta max_wait_for_frame = DetermineMaxWaitForFrame(history, false);
+
+ decode_queue_.PostTask([this, max_wait_for_keyframe, max_wait_for_frame]() {
+ RTC_DCHECK_RUN_ON(&decode_queue_);
+ max_wait_for_keyframe_ = max_wait_for_keyframe;
+ max_wait_for_frame_ = max_wait_for_frame;
+ });
+
+ frame_buffer_->SetMaxWaits(max_wait_for_keyframe, max_wait_for_frame);
+}
+
void VideoReceiveStream2::CreateAndRegisterExternalDecoder(
const Decoder& decoder) {
TRACE_EVENT0("webrtc",
@@ -765,6 +793,7 @@
}
TimeDelta VideoReceiveStream2::GetMaxWait() const {
+ RTC_DCHECK_RUN_ON(&decode_queue_);
return keyframe_required_ ? max_wait_for_keyframe_ : max_wait_for_frame_;
}
@@ -780,10 +809,11 @@
RTC_DCHECK_RUN_ON(&decode_queue_);
Timestamp now = clock_->CurrentTime();
// TODO(bugs.webrtc.org/11993): PostTask to the network thread.
- call_->worker_thread()->PostTask(
- SafeTask(task_safety_.flag(), [this, wait_time, now] {
+ call_->worker_thread()->PostTask(SafeTask(
+ task_safety_.flag(),
+ [this, wait_time, now, max_wait_for_keyframe = max_wait_for_keyframe_] {
RTC_DCHECK_RUN_ON(&packet_sequence_checker_);
- HandleFrameBufferTimeout(now, wait_time);
+ HandleFrameBufferTimeout(now, wait_time, max_wait_for_keyframe);
decode_queue_.PostTask([this] {
RTC_DCHECK_RUN_ON(&decode_queue_);
@@ -849,15 +879,16 @@
call_->worker_thread()->PostTask(SafeTask(
task_safety_.flag(),
[this, now, received_frame_is_keyframe, force_request_key_frame,
- decoded_frame_picture_id, keyframe_request_is_due]() {
+ decoded_frame_picture_id, keyframe_request_is_due,
+ max_wait_for_keyframe = max_wait_for_keyframe_]() {
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,
- force_request_key_frame,
- keyframe_request_is_due);
+ HandleKeyFrameGeneration(
+ received_frame_is_keyframe, now, force_request_key_frame,
+ keyframe_request_is_due, max_wait_for_keyframe);
}));
}
}
@@ -926,7 +957,8 @@
bool received_frame_is_keyframe,
Timestamp now,
bool always_request_key_frame,
- bool keyframe_request_is_due) {
+ bool keyframe_request_is_due,
+ TimeDelta max_wait_for_keyframe) {
RTC_DCHECK_RUN_ON(&packet_sequence_checker_);
bool request_key_frame = always_request_key_frame;
@@ -935,7 +967,7 @@
if (received_frame_is_keyframe) {
keyframe_generation_requested_ = false;
} else if (keyframe_request_is_due) {
- if (!IsReceivingKeyFrame(now)) {
+ if (!IsReceivingKeyFrame(now, max_wait_for_keyframe)) {
request_key_frame = true;
}
} else {
@@ -951,9 +983,12 @@
}
}
-void VideoReceiveStream2::HandleFrameBufferTimeout(Timestamp now,
- TimeDelta wait) {
+void VideoReceiveStream2::HandleFrameBufferTimeout(
+ Timestamp now,
+ TimeDelta wait,
+ TimeDelta max_wait_for_keyframe) {
RTC_DCHECK_RUN_ON(&packet_sequence_checker_);
+
absl::optional<int64_t> last_packet_ms =
rtp_video_stream_receiver_.LastReceivedPacketMs();
@@ -966,7 +1001,7 @@
if (!stream_is_active)
stats_proxy_.OnStreamInactive();
- if (stream_is_active && !IsReceivingKeyFrame(now) &&
+ if (stream_is_active && !IsReceivingKeyFrame(now, max_wait_for_keyframe) &&
(!config_.crypto_options.sframe.require_frame_encryption ||
rtp_video_stream_receiver_.IsDecryptable())) {
RTC_LOG(LS_WARNING) << "No decodable frame in " << wait
@@ -975,16 +1010,18 @@
}
}
-bool VideoReceiveStream2::IsReceivingKeyFrame(Timestamp now) const {
+bool VideoReceiveStream2::IsReceivingKeyFrame(
+ Timestamp now,
+ TimeDelta max_wait_for_keyframe) const {
RTC_DCHECK_RUN_ON(&packet_sequence_checker_);
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 &&
- now - Timestamp::Millis(*last_keyframe_packet_ms) <
- max_wait_for_keyframe_;
+ bool receiving_keyframe =
+ last_keyframe_packet_ms &&
+ now - Timestamp::Millis(*last_keyframe_packet_ms) < max_wait_for_keyframe;
return receiving_keyframe;
}
diff --git a/video/video_receive_stream2.h b/video/video_receive_stream2.h
index 79bd6ca..686e3af 100644
--- a/video/video_receive_stream2.h
+++ b/video/video_receive_stream2.h
@@ -148,6 +148,7 @@
void SetRtcpMode(RtcpMode mode) override;
void SetFlexFecProtection(RtpPacketSinkInterface* flexfec_sink) override;
void SetLossNotificationEnabled(bool enabled) override;
+ void SetNackHistory(TimeDelta history) override;
webrtc::VideoReceiveStreamInterface::Stats GetStats() const override;
@@ -195,7 +196,9 @@
TimeDelta GetMaxWait() const RTC_RUN_ON(decode_queue_);
void HandleEncodedFrame(std::unique_ptr<EncodedFrame> frame)
RTC_RUN_ON(decode_queue_);
- void HandleFrameBufferTimeout(Timestamp now, TimeDelta wait)
+ void HandleFrameBufferTimeout(Timestamp now,
+ TimeDelta wait,
+ TimeDelta max_wait_for_keyframe)
RTC_RUN_ON(packet_sequence_checker_);
void UpdatePlayoutDelays() const
RTC_EXCLUSIVE_LOCKS_REQUIRED(worker_sequence_checker_);
@@ -203,9 +206,11 @@
void HandleKeyFrameGeneration(bool received_frame_is_keyframe,
Timestamp now,
bool always_request_key_frame,
- bool keyframe_request_is_due)
+ bool keyframe_request_is_due,
+ TimeDelta max_wait_for_keyframe)
RTC_RUN_ON(packet_sequence_checker_);
- bool IsReceivingKeyFrame(Timestamp timestamp) const
+ bool IsReceivingKeyFrame(Timestamp timestamp,
+ TimeDelta max_wait_for_keyframe) const
RTC_RUN_ON(packet_sequence_checker_);
int DecodeAndMaybeDispatchEncodedFrame(std::unique_ptr<EncodedFrame> frame)
RTC_RUN_ON(decode_queue_);
@@ -274,8 +279,8 @@
RTC_GUARDED_BY(worker_sequence_checker_);
// Keyframe request intervals are configurable through field trials.
- const TimeDelta max_wait_for_keyframe_;
- const TimeDelta max_wait_for_frame_;
+ TimeDelta max_wait_for_keyframe_ RTC_GUARDED_BY(decode_queue_);
+ TimeDelta max_wait_for_frame_ RTC_GUARDED_BY(decode_queue_);
// 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
diff --git a/video/video_receive_stream_timeout_tracker.cc b/video/video_receive_stream_timeout_tracker.cc
index 32e8bf8..0409f26 100644
--- a/video/video_receive_stream_timeout_tracker.cc
+++ b/video/video_receive_stream_timeout_tracker.cc
@@ -40,6 +40,7 @@
}
void VideoReceiveStreamTimeoutTracker::Start(bool waiting_for_keyframe) {
+ RTC_DCHECK_RUN_ON(bookkeeping_queue_);
RTC_DCHECK(!timeout_task_.Running());
waiting_for_keyframe_ = waiting_for_keyframe;
TimeDelta timeout_delay = TimeoutForNextFrame();
@@ -55,6 +56,7 @@
}
void VideoReceiveStreamTimeoutTracker::SetWaitingForKeyframe() {
+ RTC_DCHECK_RUN_ON(bookkeeping_queue_);
waiting_for_keyframe_ = true;
TimeDelta timeout_delay = TimeoutForNextFrame();
if (clock_->CurrentTime() + timeout_delay < timeout_) {
@@ -64,6 +66,7 @@
}
void VideoReceiveStreamTimeoutTracker::OnEncodedFrameReleased() {
+ RTC_DCHECK_RUN_ON(bookkeeping_queue_);
// If we were waiting for a keyframe, then it has just been released.
waiting_for_keyframe_ = false;
last_frame_ = clock_->CurrentTime();
@@ -71,6 +74,7 @@
}
TimeDelta VideoReceiveStreamTimeoutTracker::HandleTimeoutTask() {
+ RTC_DCHECK_RUN_ON(bookkeeping_queue_);
Timestamp now = clock_->CurrentTime();
// `timeout_` is hit and we have timed out. Schedule the next timeout at
// the timeout delay.
@@ -86,4 +90,9 @@
return timeout_ - now;
}
+void VideoReceiveStreamTimeoutTracker::SetTimeouts(Timeouts timeouts) {
+ RTC_DCHECK_RUN_ON(bookkeeping_queue_);
+ timeouts_ = timeouts;
+}
+
} // namespace webrtc
diff --git a/video/video_receive_stream_timeout_tracker.h b/video/video_receive_stream_timeout_tracker.h
index c5a1c73..c15aa70 100644
--- a/video/video_receive_stream_timeout_tracker.h
+++ b/video/video_receive_stream_timeout_tracker.h
@@ -46,8 +46,10 @@
void OnEncodedFrameReleased();
TimeDelta TimeUntilTimeout() const;
+ void SetTimeouts(Timeouts timeouts);
+
private:
- TimeDelta TimeoutForNextFrame() const {
+ TimeDelta TimeoutForNextFrame() const RTC_RUN_ON(bookkeeping_queue_) {
return waiting_for_keyframe_ ? timeouts_.max_wait_for_keyframe
: timeouts_.max_wait_for_frame;
}
@@ -55,7 +57,7 @@
Clock* const clock_;
TaskQueueBase* const bookkeeping_queue_;
- const Timeouts timeouts_;
+ Timeouts timeouts_ RTC_GUARDED_BY(bookkeeping_queue_);
const TimeoutCallback timeout_cb_;
RepeatingTaskHandle timeout_task_;