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}
This commit is contained in:
parent
cfe1ab7ed2
commit
3900f21702
@ -298,6 +298,11 @@ class VideoReceiveStreamInterface : public MediaReceiveStreamInterface {
|
|||||||
// thread.
|
// thread.
|
||||||
virtual void SetLossNotificationEnabled(bool enabled) = 0;
|
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:
|
protected:
|
||||||
virtual ~VideoReceiveStreamInterface() {}
|
virtual ~VideoReceiveStreamInterface() {}
|
||||||
};
|
};
|
||||||
|
|||||||
@ -293,6 +293,10 @@ class FakeVideoReceiveStream final
|
|||||||
config_.rtp.lntf.enabled = enabled;
|
config_.rtp.lntf.enabled = enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SetNackHistory(webrtc::TimeDelta history) override {
|
||||||
|
config_.rtp.nack.rtp_history_ms = history.ms();
|
||||||
|
}
|
||||||
|
|
||||||
void Start() override;
|
void Start() override;
|
||||||
void Stop() override;
|
void Stop() override;
|
||||||
|
|
||||||
|
|||||||
@ -2991,26 +2991,32 @@ bool WebRtcVideoChannel::WebRtcVideoReceiveStream::ReconfigureCodecs(
|
|||||||
stream_->SetLossNotificationEnabled(has_lntf);
|
stream_->SetLossNotificationEnabled(has_lntf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int new_history_ms = config_.rtp.nack.rtp_history_ms;
|
||||||
const int rtp_history_ms = HasNack(codec.codec) ? kNackHistoryMs : 0;
|
const int rtp_history_ms = HasNack(codec.codec) ? kNackHistoryMs : 0;
|
||||||
if (rtp_history_ms != config_.rtp.nack.rtp_history_ms) {
|
if (rtp_history_ms != config_.rtp.nack.rtp_history_ms) {
|
||||||
config_.rtp.nack.rtp_history_ms = rtp_history_ms;
|
new_history_ms = rtp_history_ms;
|
||||||
recreate_needed = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// The rtx-time parameter can be used to override the hardcoded default for
|
// The rtx-time parameter can be used to override the hardcoded default for
|
||||||
// the NACK buffer length.
|
// the NACK buffer length.
|
||||||
if (codec.rtx_time != -1 && config_.rtp.nack.rtp_history_ms != 0) {
|
if (codec.rtx_time != -1 && new_history_ms != 0) {
|
||||||
config_.rtp.nack.rtp_history_ms = codec.rtx_time;
|
new_history_ms = codec.rtx_time;
|
||||||
recreate_needed = true;
|
}
|
||||||
|
|
||||||
|
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);
|
const bool has_rtr = HasRrtr(codec.codec);
|
||||||
if (has_rtr != config_.rtp.rtcp_xr.receiver_reference_time_report) {
|
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;
|
config_.rtp.rtcp_xr.receiver_reference_time_report = has_rtr;
|
||||||
recreate_needed = true;
|
recreate_needed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (codec.ulpfec.red_rtx_payload_type != -1) {
|
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] =
|
rtx_associated_payload_types[codec.ulpfec.red_rtx_payload_type] =
|
||||||
codec.ulpfec.red_payload_type;
|
codec.ulpfec.red_payload_type;
|
||||||
}
|
}
|
||||||
@ -3068,22 +3074,8 @@ void WebRtcVideoChannel::WebRtcVideoReceiveStream::SetFeedbackParameters(
|
|||||||
|
|
||||||
int nack_history_ms =
|
int nack_history_ms =
|
||||||
nack_enabled ? rtx_time != -1 ? rtx_time : kNackHistoryMs : 0;
|
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;
|
config_.rtp.nack.rtp_history_ms = nack_history_ms;
|
||||||
|
stream_->SetNackHistory(webrtc::TimeDelta::Millis(nack_history_ms));
|
||||||
RecreateReceiveStream();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebRtcVideoChannel::WebRtcVideoReceiveStream::SetFlexFecPayload(
|
void WebRtcVideoChannel::WebRtcVideoReceiveStream::SetFlexFecPayload(
|
||||||
|
|||||||
@ -173,6 +173,14 @@ class FrameBuffer3Proxy : public FrameBufferProxy {
|
|||||||
jitter_estimator_.UpdateRtt(TimeDelta::Millis(max_rtt_ms));
|
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 {
|
void StartNextDecode(bool keyframe_required) override {
|
||||||
if (!worker_queue_->IsCurrent()) {
|
if (!worker_queue_->IsCurrent()) {
|
||||||
worker_queue_->PostTask(SafeTask(
|
worker_queue_->PostTask(SafeTask(
|
||||||
|
|||||||
@ -59,6 +59,8 @@ class FrameBufferProxy {
|
|||||||
std::unique_ptr<EncodedFrame> frame) = 0;
|
std::unique_ptr<EncodedFrame> frame) = 0;
|
||||||
virtual void UpdateRtt(int64_t max_rtt_ms) = 0;
|
virtual void UpdateRtt(int64_t max_rtt_ms) = 0;
|
||||||
virtual int Size() = 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.
|
// Run on either the worker thread or the decode thread.
|
||||||
virtual void StartNextDecode(bool keyframe_required) = 0;
|
virtual void StartNextDecode(bool keyframe_required) = 0;
|
||||||
|
|||||||
@ -56,6 +56,8 @@ namespace {
|
|||||||
constexpr int kPacketBufferStartSize = 512;
|
constexpr int kPacketBufferStartSize = 512;
|
||||||
constexpr int kPacketBufferMaxSize = 2048;
|
constexpr int kPacketBufferMaxSize = 2048;
|
||||||
|
|
||||||
|
constexpr int kMaxPacketAgeToNack = 450;
|
||||||
|
|
||||||
int PacketBufferMaxSize(const FieldTrialsView& field_trials) {
|
int PacketBufferMaxSize(const FieldTrialsView& field_trials) {
|
||||||
// The group here must be a positive power of 2, in which case that is used as
|
// 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.
|
// size. All other values shall result in the default value being used.
|
||||||
@ -105,12 +107,12 @@ std::unique_ptr<ModuleRtpRtcpImpl2> CreateRtpRtcpModule(
|
|||||||
std::unique_ptr<NackRequester> MaybeConstructNackModule(
|
std::unique_ptr<NackRequester> MaybeConstructNackModule(
|
||||||
TaskQueueBase* current_queue,
|
TaskQueueBase* current_queue,
|
||||||
NackPeriodicProcessor* nack_periodic_processor,
|
NackPeriodicProcessor* nack_periodic_processor,
|
||||||
const VideoReceiveStreamInterface::Config& config,
|
const NackConfig& nack,
|
||||||
Clock* clock,
|
Clock* clock,
|
||||||
NackSender* nack_sender,
|
NackSender* nack_sender,
|
||||||
KeyFrameRequestSender* keyframe_request_sender,
|
KeyFrameRequestSender* keyframe_request_sender,
|
||||||
const FieldTrialsView& field_trials) {
|
const FieldTrialsView& field_trials) {
|
||||||
if (config.rtp.nack.rtp_history_ms == 0)
|
if (nack.rtp_history_ms == 0)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
// TODO(bugs.webrtc.org/12420): pass rtp_history_ms to the nack module.
|
// TODO(bugs.webrtc.org/12420): pass rtp_history_ms to the nack module.
|
||||||
@ -223,6 +225,7 @@ RtpVideoStreamReceiver2::RtpVideoStreamReceiver2(
|
|||||||
rtc::scoped_refptr<FrameTransformerInterface> frame_transformer,
|
rtc::scoped_refptr<FrameTransformerInterface> frame_transformer,
|
||||||
const FieldTrialsView& field_trials)
|
const FieldTrialsView& field_trials)
|
||||||
: field_trials_(field_trials),
|
: field_trials_(field_trials),
|
||||||
|
worker_queue_(current_queue),
|
||||||
clock_(clock),
|
clock_(clock),
|
||||||
config_(*config),
|
config_(*config),
|
||||||
packet_router_(packet_router),
|
packet_router_(packet_router),
|
||||||
@ -246,6 +249,7 @@ RtpVideoStreamReceiver2::RtpVideoStreamReceiver2(
|
|||||||
rtcp_cname_callback,
|
rtcp_cname_callback,
|
||||||
config_.rtp.rtcp_xr.receiver_reference_time_report,
|
config_.rtp.rtcp_xr.receiver_reference_time_report,
|
||||||
config_.rtp.local_ssrc)),
|
config_.rtp.local_ssrc)),
|
||||||
|
nack_periodic_processor_(nack_periodic_processor),
|
||||||
complete_frame_callback_(complete_frame_callback),
|
complete_frame_callback_(complete_frame_callback),
|
||||||
keyframe_request_method_(config_.rtp.keyframe_method),
|
keyframe_request_method_(config_.rtp.keyframe_method),
|
||||||
// TODO(bugs.webrtc.org/10336): Let `rtcp_feedback_buffer_` communicate
|
// TODO(bugs.webrtc.org/10336): Let `rtcp_feedback_buffer_` communicate
|
||||||
@ -253,7 +257,7 @@ RtpVideoStreamReceiver2::RtpVideoStreamReceiver2(
|
|||||||
rtcp_feedback_buffer_(this, this, this),
|
rtcp_feedback_buffer_(this, this, this),
|
||||||
nack_module_(MaybeConstructNackModule(current_queue,
|
nack_module_(MaybeConstructNackModule(current_queue,
|
||||||
nack_periodic_processor,
|
nack_periodic_processor,
|
||||||
config_,
|
config_.rtp.nack,
|
||||||
clock_,
|
clock_,
|
||||||
&rtcp_feedback_buffer_,
|
&rtcp_feedback_buffer_,
|
||||||
&rtcp_feedback_buffer_,
|
&rtcp_feedback_buffer_,
|
||||||
@ -280,7 +284,6 @@ RtpVideoStreamReceiver2::RtpVideoStreamReceiver2(
|
|||||||
rtp_rtcp_->SetRemoteSSRC(config_.rtp.remote_ssrc);
|
rtp_rtcp_->SetRemoteSSRC(config_.rtp.remote_ssrc);
|
||||||
|
|
||||||
if (config_.rtp.nack.rtp_history_ms > 0) {
|
if (config_.rtp.nack.rtp_history_ms > 0) {
|
||||||
static constexpr int kMaxPacketAgeToNack = 450;
|
|
||||||
rtp_receive_statistics_->SetMaxReorderingThreshold(config_.rtp.remote_ssrc,
|
rtp_receive_statistics_->SetMaxReorderingThreshold(config_.rtp.remote_ssrc,
|
||||||
kMaxPacketAgeToNack);
|
kMaxPacketAgeToNack);
|
||||||
}
|
}
|
||||||
@ -704,10 +707,6 @@ bool RtpVideoStreamReceiver2::IsUlpfecEnabled() const {
|
|||||||
return config_.rtp.ulpfec_payload_type != -1;
|
return config_.rtp.ulpfec_payload_type != -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RtpVideoStreamReceiver2::IsRetransmissionsEnabled() const {
|
|
||||||
return config_.rtp.nack.rtp_history_ms > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool RtpVideoStreamReceiver2::IsDecryptable() const {
|
bool RtpVideoStreamReceiver2::IsDecryptable() const {
|
||||||
RTC_DCHECK_RUN_ON(&worker_task_checker_);
|
RTC_DCHECK_RUN_ON(&worker_task_checker_);
|
||||||
return frames_decryptable_;
|
return frames_decryptable_;
|
||||||
@ -919,7 +918,7 @@ const RtpHeaderExtensionMap& RtpVideoStreamReceiver2::GetRtpExtensions() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void RtpVideoStreamReceiver2::UpdateRtt(int64_t max_rtt_ms) {
|
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_)
|
if (nack_module_)
|
||||||
nack_module_->UpdateRtt(max_rtt_ms);
|
nack_module_->UpdateRtt(max_rtt_ms);
|
||||||
}
|
}
|
||||||
@ -952,6 +951,21 @@ void RtpVideoStreamReceiver2::SetLossNotificationEnabled(bool enabled) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 {
|
absl::optional<int64_t> RtpVideoStreamReceiver2::LastReceivedPacketMs() const {
|
||||||
RTC_DCHECK_RUN_ON(&packet_sequence_checker_);
|
RTC_DCHECK_RUN_ON(&packet_sequence_checker_);
|
||||||
if (last_received_rtp_system_time_) {
|
if (last_received_rtp_system_time_) {
|
||||||
@ -978,7 +992,7 @@ void RtpVideoStreamReceiver2::ManageFrame(
|
|||||||
|
|
||||||
void RtpVideoStreamReceiver2::ReceivePacket(const RtpPacketReceived& packet) {
|
void RtpVideoStreamReceiver2::ReceivePacket(const RtpPacketReceived& packet) {
|
||||||
RTC_DCHECK_RUN_ON(&packet_sequence_checker_);
|
RTC_DCHECK_RUN_ON(&packet_sequence_checker_);
|
||||||
RTC_DCHECK_RUN_ON(&worker_task_checker_);
|
|
||||||
if (packet.payload_size() == 0) {
|
if (packet.payload_size() == 0) {
|
||||||
// Padding or keep-alive packet.
|
// Padding or keep-alive packet.
|
||||||
// TODO(nisse): Could drop empty packets earlier, but need to figure out how
|
// TODO(nisse): Could drop empty packets earlier, but need to figure out how
|
||||||
|
|||||||
@ -149,7 +149,6 @@ class RtpVideoStreamReceiver2 : public LossNotificationSender,
|
|||||||
bool buffering_allowed) override;
|
bool buffering_allowed) override;
|
||||||
|
|
||||||
bool IsUlpfecEnabled() const;
|
bool IsUlpfecEnabled() const;
|
||||||
bool IsRetransmissionsEnabled() const;
|
|
||||||
|
|
||||||
// Returns true if a decryptor is attached and frames can be decrypted.
|
// Returns true if a decryptor is attached and frames can be decrypted.
|
||||||
// Updated by OnDecryptionStatusChangeCallback. Note this refers to Frame
|
// Updated by OnDecryptionStatusChangeCallback. Note this refers to Frame
|
||||||
@ -198,6 +197,8 @@ class RtpVideoStreamReceiver2 : public LossNotificationSender,
|
|||||||
// thread.
|
// thread.
|
||||||
void SetLossNotificationEnabled(bool enabled);
|
void SetLossNotificationEnabled(bool enabled);
|
||||||
|
|
||||||
|
void SetNackHistory(TimeDelta history);
|
||||||
|
|
||||||
absl::optional<int64_t> LastReceivedPacketMs() const;
|
absl::optional<int64_t> LastReceivedPacketMs() const;
|
||||||
absl::optional<int64_t> LastReceivedKeyframePacketMs() const;
|
absl::optional<int64_t> LastReceivedKeyframePacketMs() const;
|
||||||
|
|
||||||
@ -305,6 +306,7 @@ class RtpVideoStreamReceiver2 : public LossNotificationSender,
|
|||||||
RTC_RUN_ON(packet_sequence_checker_);
|
RTC_RUN_ON(packet_sequence_checker_);
|
||||||
|
|
||||||
const FieldTrialsView& field_trials_;
|
const FieldTrialsView& field_trials_;
|
||||||
|
TaskQueueBase* const worker_queue_;
|
||||||
Clock* const clock_;
|
Clock* const clock_;
|
||||||
// Ownership of this object lies with VideoReceiveStreamInterface, which owns
|
// Ownership of this object lies with VideoReceiveStreamInterface, which owns
|
||||||
// `this`.
|
// `this`.
|
||||||
@ -337,11 +339,15 @@ class RtpVideoStreamReceiver2 : public LossNotificationSender,
|
|||||||
|
|
||||||
const std::unique_ptr<ModuleRtpRtcpImpl2> rtp_rtcp_;
|
const std::unique_ptr<ModuleRtpRtcpImpl2> rtp_rtcp_;
|
||||||
|
|
||||||
|
NackPeriodicProcessor* const nack_periodic_processor_;
|
||||||
OnCompleteFrameCallback* complete_frame_callback_;
|
OnCompleteFrameCallback* complete_frame_callback_;
|
||||||
const KeyFrameReqMethod keyframe_request_method_;
|
const KeyFrameReqMethod keyframe_request_method_;
|
||||||
|
|
||||||
RtcpFeedbackBuffer rtcp_feedback_buffer_;
|
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_
|
std::unique_ptr<LossNotificationController> loss_notification_controller_
|
||||||
RTC_GUARDED_BY(packet_sequence_checker_);
|
RTC_GUARDED_BY(packet_sequence_checker_);
|
||||||
|
|
||||||
|
|||||||
@ -182,17 +182,12 @@ std::string OptionalDelayToLogString(const absl::optional<TimeDelta> opt) {
|
|||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
TimeDelta DetermineMaxWaitForFrame(
|
TimeDelta DetermineMaxWaitForFrame(TimeDelta rtp_history, bool is_keyframe) {
|
||||||
const VideoReceiveStreamInterface::Config& config,
|
|
||||||
bool is_keyframe) {
|
|
||||||
// A (arbitrary) conversion factor between the remotely signalled NACK buffer
|
// 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
|
// 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
|
// remote frame. Chosen to not change existing defaults when using not
|
||||||
// rtx-time.
|
// rtx-time.
|
||||||
const int conversion_factor = 3;
|
const int conversion_factor = 3;
|
||||||
const TimeDelta rtp_history =
|
|
||||||
TimeDelta::Millis(config.rtp.nack.rtp_history_ms);
|
|
||||||
|
|
||||||
if (rtp_history > TimeDelta::Zero() &&
|
if (rtp_history > TimeDelta::Zero() &&
|
||||||
conversion_factor * rtp_history < kMaxWaitForFrame) {
|
conversion_factor * rtp_history < kMaxWaitForFrame) {
|
||||||
return is_keyframe ? rtp_history : conversion_factor * rtp_history;
|
return is_keyframe ? rtp_history : conversion_factor * rtp_history;
|
||||||
@ -238,8 +233,12 @@ VideoReceiveStream2::VideoReceiveStream2(
|
|||||||
std::move(config_.frame_transformer),
|
std::move(config_.frame_transformer),
|
||||||
call->trials()),
|
call->trials()),
|
||||||
rtp_stream_sync_(call->worker_thread(), this),
|
rtp_stream_sync_(call->worker_thread(), this),
|
||||||
max_wait_for_keyframe_(DetermineMaxWaitForFrame(config_, true)),
|
max_wait_for_keyframe_(DetermineMaxWaitForFrame(
|
||||||
max_wait_for_frame_(DetermineMaxWaitForFrame(config_, false)),
|
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),
|
maximum_pre_stream_decoders_("max", kDefaultMaximumPreStreamDecoders),
|
||||||
decode_sync_(decode_sync),
|
decode_sync_(decode_sync),
|
||||||
decode_queue_(task_queue_factory_->CreateTaskQueue(
|
decode_queue_(task_queue_factory_->CreateTaskQueue(
|
||||||
@ -355,8 +354,7 @@ void VideoReceiveStream2::Start() {
|
|||||||
const bool protected_by_fec = config_.rtp.protected_by_flexfec ||
|
const bool protected_by_fec = config_.rtp.protected_by_flexfec ||
|
||||||
rtp_video_stream_receiver_.IsUlpfecEnabled();
|
rtp_video_stream_receiver_.IsUlpfecEnabled();
|
||||||
|
|
||||||
if (rtp_video_stream_receiver_.IsRetransmissionsEnabled() &&
|
if (config_.rtp.nack.rtp_history_ms > 0 && protected_by_fec) {
|
||||||
protected_by_fec) {
|
|
||||||
frame_buffer_->SetProtectionMode(kProtectionNackFEC);
|
frame_buffer_->SetProtectionMode(kProtectionNackFEC);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -524,6 +522,36 @@ void VideoReceiveStream2::SetLossNotificationEnabled(bool enabled) {
|
|||||||
rtp_video_stream_receiver_.SetLossNotificationEnabled(enabled);
|
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(
|
void VideoReceiveStream2::CreateAndRegisterExternalDecoder(
|
||||||
const Decoder& decoder) {
|
const Decoder& decoder) {
|
||||||
TRACE_EVENT0("webrtc",
|
TRACE_EVENT0("webrtc",
|
||||||
@ -765,6 +793,7 @@ bool VideoReceiveStream2::SetMinimumPlayoutDelay(int delay_ms) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TimeDelta VideoReceiveStream2::GetMaxWait() const {
|
TimeDelta VideoReceiveStream2::GetMaxWait() const {
|
||||||
|
RTC_DCHECK_RUN_ON(&decode_queue_);
|
||||||
return keyframe_required_ ? max_wait_for_keyframe_ : max_wait_for_frame_;
|
return keyframe_required_ ? max_wait_for_keyframe_ : max_wait_for_frame_;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -780,10 +809,11 @@ void VideoReceiveStream2::OnDecodableFrameTimeout(TimeDelta wait_time) {
|
|||||||
RTC_DCHECK_RUN_ON(&decode_queue_);
|
RTC_DCHECK_RUN_ON(&decode_queue_);
|
||||||
Timestamp now = clock_->CurrentTime();
|
Timestamp now = clock_->CurrentTime();
|
||||||
// TODO(bugs.webrtc.org/11993): PostTask to the network thread.
|
// TODO(bugs.webrtc.org/11993): PostTask to the network thread.
|
||||||
call_->worker_thread()->PostTask(
|
call_->worker_thread()->PostTask(SafeTask(
|
||||||
SafeTask(task_safety_.flag(), [this, wait_time, now] {
|
task_safety_.flag(),
|
||||||
|
[this, wait_time, now, max_wait_for_keyframe = max_wait_for_keyframe_] {
|
||||||
RTC_DCHECK_RUN_ON(&packet_sequence_checker_);
|
RTC_DCHECK_RUN_ON(&packet_sequence_checker_);
|
||||||
HandleFrameBufferTimeout(now, wait_time);
|
HandleFrameBufferTimeout(now, wait_time, max_wait_for_keyframe);
|
||||||
|
|
||||||
decode_queue_.PostTask([this] {
|
decode_queue_.PostTask([this] {
|
||||||
RTC_DCHECK_RUN_ON(&decode_queue_);
|
RTC_DCHECK_RUN_ON(&decode_queue_);
|
||||||
@ -849,15 +879,16 @@ void VideoReceiveStream2::HandleEncodedFrame(
|
|||||||
call_->worker_thread()->PostTask(SafeTask(
|
call_->worker_thread()->PostTask(SafeTask(
|
||||||
task_safety_.flag(),
|
task_safety_.flag(),
|
||||||
[this, now, 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]() {
|
decoded_frame_picture_id, keyframe_request_is_due,
|
||||||
|
max_wait_for_keyframe = max_wait_for_keyframe_]() {
|
||||||
RTC_DCHECK_RUN_ON(&packet_sequence_checker_);
|
RTC_DCHECK_RUN_ON(&packet_sequence_checker_);
|
||||||
|
|
||||||
if (decoded_frame_picture_id != -1)
|
if (decoded_frame_picture_id != -1)
|
||||||
rtp_video_stream_receiver_.FrameDecoded(decoded_frame_picture_id);
|
rtp_video_stream_receiver_.FrameDecoded(decoded_frame_picture_id);
|
||||||
|
|
||||||
HandleKeyFrameGeneration(received_frame_is_keyframe, now,
|
HandleKeyFrameGeneration(
|
||||||
force_request_key_frame,
|
received_frame_is_keyframe, now, force_request_key_frame,
|
||||||
keyframe_request_is_due);
|
keyframe_request_is_due, max_wait_for_keyframe);
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -926,7 +957,8 @@ void VideoReceiveStream2::HandleKeyFrameGeneration(
|
|||||||
bool received_frame_is_keyframe,
|
bool received_frame_is_keyframe,
|
||||||
Timestamp now,
|
Timestamp now,
|
||||||
bool always_request_key_frame,
|
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_);
|
RTC_DCHECK_RUN_ON(&packet_sequence_checker_);
|
||||||
bool request_key_frame = always_request_key_frame;
|
bool request_key_frame = always_request_key_frame;
|
||||||
|
|
||||||
@ -935,7 +967,7 @@ void VideoReceiveStream2::HandleKeyFrameGeneration(
|
|||||||
if (received_frame_is_keyframe) {
|
if (received_frame_is_keyframe) {
|
||||||
keyframe_generation_requested_ = false;
|
keyframe_generation_requested_ = false;
|
||||||
} else if (keyframe_request_is_due) {
|
} else if (keyframe_request_is_due) {
|
||||||
if (!IsReceivingKeyFrame(now)) {
|
if (!IsReceivingKeyFrame(now, max_wait_for_keyframe)) {
|
||||||
request_key_frame = true;
|
request_key_frame = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -951,9 +983,12 @@ void VideoReceiveStream2::HandleKeyFrameGeneration(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VideoReceiveStream2::HandleFrameBufferTimeout(Timestamp now,
|
void VideoReceiveStream2::HandleFrameBufferTimeout(
|
||||||
TimeDelta wait) {
|
Timestamp now,
|
||||||
|
TimeDelta wait,
|
||||||
|
TimeDelta max_wait_for_keyframe) {
|
||||||
RTC_DCHECK_RUN_ON(&packet_sequence_checker_);
|
RTC_DCHECK_RUN_ON(&packet_sequence_checker_);
|
||||||
|
|
||||||
absl::optional<int64_t> last_packet_ms =
|
absl::optional<int64_t> last_packet_ms =
|
||||||
rtp_video_stream_receiver_.LastReceivedPacketMs();
|
rtp_video_stream_receiver_.LastReceivedPacketMs();
|
||||||
|
|
||||||
@ -966,7 +1001,7 @@ void VideoReceiveStream2::HandleFrameBufferTimeout(Timestamp now,
|
|||||||
if (!stream_is_active)
|
if (!stream_is_active)
|
||||||
stats_proxy_.OnStreamInactive();
|
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 ||
|
(!config_.crypto_options.sframe.require_frame_encryption ||
|
||||||
rtp_video_stream_receiver_.IsDecryptable())) {
|
rtp_video_stream_receiver_.IsDecryptable())) {
|
||||||
RTC_LOG(LS_WARNING) << "No decodable frame in " << wait
|
RTC_LOG(LS_WARNING) << "No decodable frame in " << wait
|
||||||
@ -975,16 +1010,18 @@ void VideoReceiveStream2::HandleFrameBufferTimeout(Timestamp now,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VideoReceiveStream2::IsReceivingKeyFrame(Timestamp now) const {
|
bool VideoReceiveStream2::IsReceivingKeyFrame(
|
||||||
|
Timestamp now,
|
||||||
|
TimeDelta max_wait_for_keyframe) const {
|
||||||
RTC_DCHECK_RUN_ON(&packet_sequence_checker_);
|
RTC_DCHECK_RUN_ON(&packet_sequence_checker_);
|
||||||
absl::optional<int64_t> last_keyframe_packet_ms =
|
absl::optional<int64_t> last_keyframe_packet_ms =
|
||||||
rtp_video_stream_receiver_.LastReceivedKeyframePacketMs();
|
rtp_video_stream_receiver_.LastReceivedKeyframePacketMs();
|
||||||
|
|
||||||
// If we recently have been receiving packets belonging to a keyframe then
|
// If we recently have been receiving packets belonging to a keyframe then
|
||||||
// we assume a keyframe is currently being received.
|
// we assume a keyframe is currently being received.
|
||||||
bool receiving_keyframe = last_keyframe_packet_ms &&
|
bool receiving_keyframe =
|
||||||
now - Timestamp::Millis(*last_keyframe_packet_ms) <
|
last_keyframe_packet_ms &&
|
||||||
max_wait_for_keyframe_;
|
now - Timestamp::Millis(*last_keyframe_packet_ms) < max_wait_for_keyframe;
|
||||||
return receiving_keyframe;
|
return receiving_keyframe;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -148,6 +148,7 @@ class VideoReceiveStream2
|
|||||||
void SetRtcpMode(RtcpMode mode) override;
|
void SetRtcpMode(RtcpMode mode) override;
|
||||||
void SetFlexFecProtection(RtpPacketSinkInterface* flexfec_sink) override;
|
void SetFlexFecProtection(RtpPacketSinkInterface* flexfec_sink) override;
|
||||||
void SetLossNotificationEnabled(bool enabled) override;
|
void SetLossNotificationEnabled(bool enabled) override;
|
||||||
|
void SetNackHistory(TimeDelta history) override;
|
||||||
|
|
||||||
webrtc::VideoReceiveStreamInterface::Stats GetStats() const override;
|
webrtc::VideoReceiveStreamInterface::Stats GetStats() const override;
|
||||||
|
|
||||||
@ -195,7 +196,9 @@ class VideoReceiveStream2
|
|||||||
TimeDelta GetMaxWait() const RTC_RUN_ON(decode_queue_);
|
TimeDelta GetMaxWait() const RTC_RUN_ON(decode_queue_);
|
||||||
void HandleEncodedFrame(std::unique_ptr<EncodedFrame> frame)
|
void HandleEncodedFrame(std::unique_ptr<EncodedFrame> frame)
|
||||||
RTC_RUN_ON(decode_queue_);
|
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_);
|
RTC_RUN_ON(packet_sequence_checker_);
|
||||||
void UpdatePlayoutDelays() const
|
void UpdatePlayoutDelays() const
|
||||||
RTC_EXCLUSIVE_LOCKS_REQUIRED(worker_sequence_checker_);
|
RTC_EXCLUSIVE_LOCKS_REQUIRED(worker_sequence_checker_);
|
||||||
@ -203,9 +206,11 @@ class VideoReceiveStream2
|
|||||||
void HandleKeyFrameGeneration(bool received_frame_is_keyframe,
|
void HandleKeyFrameGeneration(bool received_frame_is_keyframe,
|
||||||
Timestamp now,
|
Timestamp now,
|
||||||
bool always_request_key_frame,
|
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_);
|
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_);
|
RTC_RUN_ON(packet_sequence_checker_);
|
||||||
int DecodeAndMaybeDispatchEncodedFrame(std::unique_ptr<EncodedFrame> frame)
|
int DecodeAndMaybeDispatchEncodedFrame(std::unique_ptr<EncodedFrame> frame)
|
||||||
RTC_RUN_ON(decode_queue_);
|
RTC_RUN_ON(decode_queue_);
|
||||||
@ -274,8 +279,8 @@ class VideoReceiveStream2
|
|||||||
RTC_GUARDED_BY(worker_sequence_checker_);
|
RTC_GUARDED_BY(worker_sequence_checker_);
|
||||||
|
|
||||||
// Keyframe request intervals are configurable through field trials.
|
// Keyframe request intervals are configurable through field trials.
|
||||||
const TimeDelta max_wait_for_keyframe_;
|
TimeDelta max_wait_for_keyframe_ RTC_GUARDED_BY(decode_queue_);
|
||||||
const TimeDelta max_wait_for_frame_;
|
TimeDelta max_wait_for_frame_ RTC_GUARDED_BY(decode_queue_);
|
||||||
|
|
||||||
// All of them tries to change current min_playout_delay on `timing_` but
|
// 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
|
// source of the change request is different in each case. Among them the
|
||||||
|
|||||||
@ -40,6 +40,7 @@ TimeDelta VideoReceiveStreamTimeoutTracker::TimeUntilTimeout() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void VideoReceiveStreamTimeoutTracker::Start(bool waiting_for_keyframe) {
|
void VideoReceiveStreamTimeoutTracker::Start(bool waiting_for_keyframe) {
|
||||||
|
RTC_DCHECK_RUN_ON(bookkeeping_queue_);
|
||||||
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();
|
||||||
@ -55,6 +56,7 @@ void VideoReceiveStreamTimeoutTracker::Stop() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void VideoReceiveStreamTimeoutTracker::SetWaitingForKeyframe() {
|
void VideoReceiveStreamTimeoutTracker::SetWaitingForKeyframe() {
|
||||||
|
RTC_DCHECK_RUN_ON(bookkeeping_queue_);
|
||||||
waiting_for_keyframe_ = true;
|
waiting_for_keyframe_ = true;
|
||||||
TimeDelta timeout_delay = TimeoutForNextFrame();
|
TimeDelta timeout_delay = TimeoutForNextFrame();
|
||||||
if (clock_->CurrentTime() + timeout_delay < timeout_) {
|
if (clock_->CurrentTime() + timeout_delay < timeout_) {
|
||||||
@ -64,6 +66,7 @@ void VideoReceiveStreamTimeoutTracker::SetWaitingForKeyframe() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void VideoReceiveStreamTimeoutTracker::OnEncodedFrameReleased() {
|
void VideoReceiveStreamTimeoutTracker::OnEncodedFrameReleased() {
|
||||||
|
RTC_DCHECK_RUN_ON(bookkeeping_queue_);
|
||||||
// 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;
|
||||||
last_frame_ = clock_->CurrentTime();
|
last_frame_ = clock_->CurrentTime();
|
||||||
@ -71,6 +74,7 @@ void VideoReceiveStreamTimeoutTracker::OnEncodedFrameReleased() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TimeDelta VideoReceiveStreamTimeoutTracker::HandleTimeoutTask() {
|
TimeDelta VideoReceiveStreamTimeoutTracker::HandleTimeoutTask() {
|
||||||
|
RTC_DCHECK_RUN_ON(bookkeeping_queue_);
|
||||||
Timestamp now = clock_->CurrentTime();
|
Timestamp now = clock_->CurrentTime();
|
||||||
// `timeout_` is hit and we have timed out. Schedule the next timeout at
|
// `timeout_` is hit and we have timed out. Schedule the next timeout at
|
||||||
// the timeout delay.
|
// the timeout delay.
|
||||||
@ -86,4 +90,9 @@ TimeDelta VideoReceiveStreamTimeoutTracker::HandleTimeoutTask() {
|
|||||||
return timeout_ - now;
|
return timeout_ - now;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VideoReceiveStreamTimeoutTracker::SetTimeouts(Timeouts timeouts) {
|
||||||
|
RTC_DCHECK_RUN_ON(bookkeeping_queue_);
|
||||||
|
timeouts_ = timeouts;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace webrtc
|
} // namespace webrtc
|
||||||
|
|||||||
@ -46,8 +46,10 @@ class VideoReceiveStreamTimeoutTracker {
|
|||||||
void OnEncodedFrameReleased();
|
void OnEncodedFrameReleased();
|
||||||
TimeDelta TimeUntilTimeout() const;
|
TimeDelta TimeUntilTimeout() const;
|
||||||
|
|
||||||
|
void SetTimeouts(Timeouts timeouts);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
TimeDelta TimeoutForNextFrame() const {
|
TimeDelta TimeoutForNextFrame() const RTC_RUN_ON(bookkeeping_queue_) {
|
||||||
return waiting_for_keyframe_ ? timeouts_.max_wait_for_keyframe
|
return waiting_for_keyframe_ ? timeouts_.max_wait_for_keyframe
|
||||||
: timeouts_.max_wait_for_frame;
|
: timeouts_.max_wait_for_frame;
|
||||||
}
|
}
|
||||||
@ -55,7 +57,7 @@ class VideoReceiveStreamTimeoutTracker {
|
|||||||
|
|
||||||
Clock* const clock_;
|
Clock* const clock_;
|
||||||
TaskQueueBase* const bookkeeping_queue_;
|
TaskQueueBase* const bookkeeping_queue_;
|
||||||
const Timeouts timeouts_;
|
Timeouts timeouts_ RTC_GUARDED_BY(bookkeeping_queue_);
|
||||||
const TimeoutCallback timeout_cb_;
|
const TimeoutCallback timeout_cb_;
|
||||||
RepeatingTaskHandle timeout_task_;
|
RepeatingTaskHandle timeout_task_;
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user