Connect LossNotificationController to RtpRtcp
* LossNotificationController is the class that decides when to issue LossNotification RTCP messages. * RtpRtcp handles the technicalities of producing RTCP messages. Bug: webrtc:10336 Change-Id: I292536257a984ca85d21d9cfa38e7ff2569cbb39 Reviewed-on: https://webrtc-review.googlesource.com/c/124123 Reviewed-by: Erik Språng <sprang@webrtc.org> Reviewed-by: Danil Chapovalov <danilchap@webrtc.org> Commit-Queue: Elad Alon <eladalon@webrtc.org> Cr-Commit-Position: refs/heads/master@{#26840}
This commit is contained in:
parent
a497d12a02
commit
7d6a4c045c
@ -462,6 +462,12 @@ class RtpRtcp : public Module, public RtcpFeedbackSenderInterface {
|
||||
// Sends a request for a keyframe.
|
||||
// Returns -1 on failure else 0.
|
||||
virtual int32_t RequestKeyFrame() = 0;
|
||||
|
||||
// Sends a LossNotification RTCP message.
|
||||
// Returns -1 on failure else 0.
|
||||
virtual int32_t SendLossNotification(uint16_t last_decoded_seq_num,
|
||||
uint16_t last_received_seq_num,
|
||||
bool decodability_flag) = 0;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
@ -172,6 +172,10 @@ class MockRtpRtcp : public RtpRtcp {
|
||||
const FecProtectionParams& key_params));
|
||||
MOCK_METHOD1(SetKeyFrameRequestMethod, int32_t(KeyFrameRequestMethod method));
|
||||
MOCK_METHOD0(RequestKeyFrame, int32_t());
|
||||
MOCK_METHOD3(SendLossNotification,
|
||||
int32_t(uint16_t last_decoded_seq_num,
|
||||
uint16_t last_received_seq_num,
|
||||
bool decodability_flag));
|
||||
MOCK_METHOD0(Process, void());
|
||||
MOCK_METHOD1(RegisterSendChannelRtpStatisticsCallback,
|
||||
void(StreamDataCountersCallback*));
|
||||
|
||||
@ -37,6 +37,13 @@ namespace rtcp {
|
||||
LossNotification::LossNotification()
|
||||
: last_decoded_(0), last_received_(0), decodability_flag_(false) {}
|
||||
|
||||
LossNotification::LossNotification(uint16_t last_decoded,
|
||||
uint16_t last_received,
|
||||
bool decodability_flag)
|
||||
: last_decoded_(last_decoded),
|
||||
last_received_(last_received),
|
||||
decodability_flag_(decodability_flag) {}
|
||||
|
||||
LossNotification::LossNotification(const LossNotification& rhs) = default;
|
||||
|
||||
LossNotification::~LossNotification() = default;
|
||||
|
||||
@ -21,6 +21,9 @@ namespace rtcp {
|
||||
class LossNotification : public Psfb {
|
||||
public:
|
||||
LossNotification();
|
||||
LossNotification(uint16_t last_decoded,
|
||||
uint16_t last_received,
|
||||
bool decodability_flag);
|
||||
LossNotification(const LossNotification& other);
|
||||
~LossNotification() override;
|
||||
|
||||
|
||||
@ -24,6 +24,7 @@
|
||||
#include "modules/rtp_rtcp/source/rtcp_packet/compound_packet.h"
|
||||
#include "modules/rtp_rtcp/source/rtcp_packet/extended_reports.h"
|
||||
#include "modules/rtp_rtcp/source/rtcp_packet/fir.h"
|
||||
#include "modules/rtp_rtcp/source/rtcp_packet/loss_notification.h"
|
||||
#include "modules/rtp_rtcp/source/rtcp_packet/nack.h"
|
||||
#include "modules/rtp_rtcp/source/rtcp_packet/pli.h"
|
||||
#include "modules/rtp_rtcp/source/rtcp_packet/receiver_report.h"
|
||||
@ -163,6 +164,7 @@ RTCPSender::RTCPSender(
|
||||
builders_[kRtcpRemb] = &RTCPSender::BuildREMB;
|
||||
builders_[kRtcpBye] = &RTCPSender::BuildBYE;
|
||||
builders_[kRtcpApp] = &RTCPSender::BuildAPP;
|
||||
builders_[kRtcpLossNotification] = &RTCPSender::BuildLossNotification;
|
||||
builders_[kRtcpTmmbr] = &RTCPSender::BuildTMMBR;
|
||||
builders_[kRtcpTmmbn] = &RTCPSender::BuildTMMBN;
|
||||
builders_[kRtcpNack] = &RTCPSender::BuildNACK;
|
||||
@ -211,6 +213,23 @@ int32_t RTCPSender::SetSendingStatus(const FeedbackState& feedback_state,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t RTCPSender::SendLossNotification(const FeedbackState& feedback_state,
|
||||
uint16_t last_decoded_seq_num,
|
||||
uint16_t last_received_seq_num,
|
||||
bool decodability_flag) {
|
||||
rtc::CritScope lock(&critical_section_rtcp_sender_);
|
||||
|
||||
loss_notification_state_.last_decoded_seq_num = last_decoded_seq_num;
|
||||
loss_notification_state_.last_received_seq_num = last_received_seq_num;
|
||||
loss_notification_state_.decodability_flag = decodability_flag;
|
||||
|
||||
SetFlag(kRtcpLossNotification, /*is_volatile=*/true);
|
||||
|
||||
// Send immediately.
|
||||
return SendCompoundRTCP(feedback_state,
|
||||
{RTCPPacketType::kRtcpLossNotification});
|
||||
}
|
||||
|
||||
void RTCPSender::SetRemb(int64_t bitrate_bps, std::vector<uint32_t> ssrcs) {
|
||||
RTC_CHECK_GE(bitrate_bps, 0);
|
||||
rtc::CritScope lock(&critical_section_rtcp_sender_);
|
||||
@ -583,6 +602,17 @@ std::unique_ptr<rtcp::RtcpPacket> RTCPSender::BuildAPP(const RtcpContext& ctx) {
|
||||
return std::unique_ptr<rtcp::RtcpPacket>(app);
|
||||
}
|
||||
|
||||
std::unique_ptr<rtcp::RtcpPacket> RTCPSender::BuildLossNotification(
|
||||
const RtcpContext& ctx) {
|
||||
auto loss_notification = absl::make_unique<rtcp::LossNotification>(
|
||||
loss_notification_state_.last_decoded_seq_num,
|
||||
loss_notification_state_.last_received_seq_num,
|
||||
loss_notification_state_.decodability_flag);
|
||||
loss_notification->SetSenderSsrc(ssrc_);
|
||||
loss_notification->SetMediaSsrc(remote_ssrc_);
|
||||
return std::move(loss_notification);
|
||||
}
|
||||
|
||||
std::unique_ptr<rtcp::RtcpPacket> RTCPSender::BuildNACK(
|
||||
const RtcpContext& ctx) {
|
||||
rtcp::Nack* nack = new rtcp::Nack();
|
||||
|
||||
@ -114,6 +114,11 @@ class RTCPSender {
|
||||
int32_t nackSize = 0,
|
||||
const uint16_t* nackList = 0);
|
||||
|
||||
int32_t SendLossNotification(const FeedbackState& feedback_state,
|
||||
uint16_t last_decoded_seq_num,
|
||||
uint16_t last_received_seq_num,
|
||||
bool decodability_flag);
|
||||
|
||||
void SetRemb(int64_t bitrate_bps, std::vector<uint32_t> ssrcs);
|
||||
|
||||
void UnsetRemb();
|
||||
@ -168,6 +173,9 @@ class RTCPSender {
|
||||
RTC_EXCLUSIVE_LOCKS_REQUIRED(critical_section_rtcp_sender_);
|
||||
std::unique_ptr<rtcp::RtcpPacket> BuildAPP(const RtcpContext& context)
|
||||
RTC_EXCLUSIVE_LOCKS_REQUIRED(critical_section_rtcp_sender_);
|
||||
std::unique_ptr<rtcp::RtcpPacket> BuildLossNotification(
|
||||
const RtcpContext& context)
|
||||
RTC_EXCLUSIVE_LOCKS_REQUIRED(critical_section_rtcp_sender_);
|
||||
std::unique_ptr<rtcp::RtcpPacket> BuildExtendedReports(
|
||||
const RtcpContext& context)
|
||||
RTC_EXCLUSIVE_LOCKS_REQUIRED(critical_section_rtcp_sender_);
|
||||
@ -214,6 +222,15 @@ class RTCPSender {
|
||||
// Full intra request
|
||||
uint8_t sequence_number_fir_ RTC_GUARDED_BY(critical_section_rtcp_sender_);
|
||||
|
||||
// Loss Notification
|
||||
struct LossNotificationState {
|
||||
uint16_t last_decoded_seq_num;
|
||||
uint16_t last_received_seq_num;
|
||||
bool decodability_flag;
|
||||
};
|
||||
LossNotificationState loss_notification_state_
|
||||
RTC_GUARDED_BY(critical_section_rtcp_sender_);
|
||||
|
||||
// REMB
|
||||
int64_t remb_bitrate_ RTC_GUARDED_BY(critical_section_rtcp_sender_);
|
||||
std::vector<uint32_t> remb_ssrcs_
|
||||
|
||||
@ -376,6 +376,19 @@ TEST_F(RtcpSenderTest, SendNack) {
|
||||
EXPECT_THAT(parser()->nack()->packet_ids(), ElementsAre(0, 1, 16));
|
||||
}
|
||||
|
||||
TEST_F(RtcpSenderTest, SendLossNotification) {
|
||||
rtcp_sender_->SetRTCPStatus(RtcpMode::kReducedSize);
|
||||
constexpr uint16_t kLastDecoded = 0x1234;
|
||||
constexpr uint16_t kLastReceived = 0x4321;
|
||||
constexpr bool kDecodabilityFlag = true;
|
||||
const int32_t result = rtcp_sender_->SendLossNotification(
|
||||
feedback_state(), kLastDecoded, kLastReceived, kDecodabilityFlag);
|
||||
EXPECT_EQ(result, 0);
|
||||
EXPECT_EQ(1, parser()->loss_notification()->num_packets());
|
||||
EXPECT_EQ(kSenderSsrc, parser()->loss_notification()->sender_ssrc());
|
||||
EXPECT_EQ(kRemoteSsrc, parser()->loss_notification()->media_ssrc());
|
||||
}
|
||||
|
||||
TEST_F(RtcpSenderTest, RembNotIncludedBeforeSet) {
|
||||
rtcp_sender_->SetRTCPStatus(RtcpMode::kReducedSize);
|
||||
|
||||
|
||||
@ -813,6 +813,14 @@ int32_t ModuleRtpRtcpImpl::RequestKeyFrame() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int32_t ModuleRtpRtcpImpl::SendLossNotification(uint16_t last_decoded_seq_num,
|
||||
uint16_t last_received_seq_num,
|
||||
bool decodability_flag) {
|
||||
return rtcp_sender_.SendLossNotification(
|
||||
GetFeedbackState(), last_decoded_seq_num, last_received_seq_num,
|
||||
decodability_flag);
|
||||
}
|
||||
|
||||
void ModuleRtpRtcpImpl::SetUlpfecConfig(int red_payload_type,
|
||||
int ulpfec_payload_type) {
|
||||
RTC_DCHECK(video_);
|
||||
|
||||
@ -282,6 +282,10 @@ class ModuleRtpRtcpImpl : public RtpRtcp, public RTCPReceiver::ModuleRtpRtcp {
|
||||
// Send a request for a keyframe.
|
||||
int32_t RequestKeyFrame() override;
|
||||
|
||||
int32_t SendLossNotification(uint16_t last_decoded_seq_num,
|
||||
uint16_t last_received_seq_num,
|
||||
bool decodability_flag) override;
|
||||
|
||||
void SetUlpfecConfig(int red_payload_type, int ulpfec_payload_type) override;
|
||||
|
||||
bool SetFecParameters(const FecProtectionParams& delta_params,
|
||||
|
||||
@ -56,7 +56,10 @@ bool RtcpPacketParser::Parse(const void* data, size_t length) {
|
||||
pli_.Parse(header, &sender_ssrc_);
|
||||
break;
|
||||
case rtcp::Psfb::kAfbMessageType:
|
||||
remb_.Parse(header, &sender_ssrc_);
|
||||
if (!loss_notification_.Parse(header, &sender_ssrc_) &&
|
||||
!remb_.Parse(header, &sender_ssrc_)) {
|
||||
RTC_LOG(LS_WARNING) << "Unknown application layer FB message.";
|
||||
}
|
||||
break;
|
||||
default:
|
||||
RTC_LOG(LS_WARNING)
|
||||
|
||||
@ -22,6 +22,7 @@
|
||||
#include "modules/rtp_rtcp/source/rtcp_packet/extended_jitter_report.h"
|
||||
#include "modules/rtp_rtcp/source/rtcp_packet/extended_reports.h"
|
||||
#include "modules/rtp_rtcp/source/rtcp_packet/fir.h"
|
||||
#include "modules/rtp_rtcp/source/rtcp_packet/loss_notification.h"
|
||||
#include "modules/rtp_rtcp/source/rtcp_packet/nack.h"
|
||||
#include "modules/rtp_rtcp/source/rtcp_packet/pli.h"
|
||||
#include "modules/rtp_rtcp/source/rtcp_packet/rapid_resync_request.h"
|
||||
@ -62,12 +63,14 @@ class RtcpPacketParser {
|
||||
if (TypedRtcpPacket::Parse(header))
|
||||
++num_packets_;
|
||||
}
|
||||
void Parse(const rtcp::CommonHeader& header, uint32_t* sender_ssrc) {
|
||||
if (TypedRtcpPacket::Parse(header)) {
|
||||
bool Parse(const rtcp::CommonHeader& header, uint32_t* sender_ssrc) {
|
||||
const bool result = TypedRtcpPacket::Parse(header);
|
||||
if (result) {
|
||||
++num_packets_;
|
||||
if (*sender_ssrc == 0) // Use first sender ssrc in compound packet.
|
||||
*sender_ssrc = TypedRtcpPacket::sender_ssrc();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
@ -90,6 +93,9 @@ class RtcpPacketParser {
|
||||
PacketCounter<rtcp::ReceiverReport>* receiver_report() {
|
||||
return &receiver_report_;
|
||||
}
|
||||
PacketCounter<rtcp::LossNotification>* loss_notification() {
|
||||
return &loss_notification_;
|
||||
}
|
||||
PacketCounter<rtcp::Remb>* remb() { return &remb_; }
|
||||
PacketCounter<rtcp::Sdes>* sdes() { return &sdes_; }
|
||||
PacketCounter<rtcp::SenderReport>* sender_report() { return &sender_report_; }
|
||||
@ -110,6 +116,7 @@ class RtcpPacketParser {
|
||||
PacketCounter<rtcp::Pli> pli_;
|
||||
PacketCounter<rtcp::RapidResyncRequest> rrr_;
|
||||
PacketCounter<rtcp::ReceiverReport> receiver_report_;
|
||||
PacketCounter<rtcp::LossNotification> loss_notification_;
|
||||
PacketCounter<rtcp::Remb> remb_;
|
||||
PacketCounter<rtcp::Sdes> sdes_;
|
||||
PacketCounter<rtcp::SenderReport> sender_report_;
|
||||
|
||||
@ -15,7 +15,6 @@
|
||||
#include <vector>
|
||||
|
||||
#include "absl/memory/memory.h"
|
||||
|
||||
#include "media/base/media_constants.h"
|
||||
#include "modules/pacing/packet_router.h"
|
||||
#include "modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h"
|
||||
@ -143,7 +142,11 @@ RtpVideoStreamReceiver::RtpVideoStreamReceiver(
|
||||
|
||||
process_thread_->RegisterModule(rtp_rtcp_.get(), RTC_FROM_HERE);
|
||||
|
||||
if (config_.rtp.nack.rtp_history_ms != 0) {
|
||||
if (webrtc::field_trial::IsEnabled("WebRTC-RtcpLossNotification")) {
|
||||
loss_notification_controller_ =
|
||||
absl::make_unique<LossNotificationController>(keyframe_request_sender_,
|
||||
this);
|
||||
} else if (config_.rtp.nack.rtp_history_ms != 0) {
|
||||
nack_module_ = absl::make_unique<NackModule>(clock_, nack_sender,
|
||||
keyframe_request_sender);
|
||||
process_thread_->RegisterModule(nack_module_.get(), RTC_FROM_HERE);
|
||||
@ -234,6 +237,8 @@ int32_t RtpVideoStreamReceiver::OnReceivedPayloadData(
|
||||
ntp_estimator_.Estimate(rtp_header->header.timestamp);
|
||||
|
||||
VCMPacket packet(payload_data, payload_size, rtp_header_with_ntp);
|
||||
packet.generic_descriptor = generic_descriptor;
|
||||
|
||||
if (nack_module_) {
|
||||
const bool is_keyframe =
|
||||
rtp_header->video_header().is_first_packet_in_frame &&
|
||||
@ -247,6 +252,16 @@ int32_t RtpVideoStreamReceiver::OnReceivedPayloadData(
|
||||
}
|
||||
packet.receive_time_ms = clock_->TimeInMilliseconds();
|
||||
|
||||
if (loss_notification_controller_) {
|
||||
if (is_recovered) {
|
||||
// TODO(bugs.webrtc.org/10336): Implement support for reordering.
|
||||
RTC_LOG(LS_WARNING)
|
||||
<< "LossNotificationController does not support reordering.";
|
||||
} else {
|
||||
loss_notification_controller_->OnReceivedPacket(packet);
|
||||
}
|
||||
}
|
||||
|
||||
if (packet.sizeBytes == 0) {
|
||||
NotifyReceiverOfEmptyPacket(packet.seqNum);
|
||||
return 0;
|
||||
@ -277,8 +292,6 @@ int32_t RtpVideoStreamReceiver::OnReceivedPayloadData(
|
||||
packet.dataPtr = data;
|
||||
}
|
||||
|
||||
packet.generic_descriptor = generic_descriptor;
|
||||
|
||||
packet_buffer_->InsertPacket(&packet);
|
||||
return 0;
|
||||
}
|
||||
@ -364,6 +377,14 @@ int32_t RtpVideoStreamReceiver::RequestKeyFrame() {
|
||||
return rtp_rtcp_->RequestKeyFrame();
|
||||
}
|
||||
|
||||
void RtpVideoStreamReceiver::SendLossNotification(
|
||||
uint16_t last_decoded_seq_num,
|
||||
uint16_t last_received_seq_num,
|
||||
bool decodability_flag) {
|
||||
rtp_rtcp_->SendLossNotification(last_decoded_seq_num, last_received_seq_num,
|
||||
decodability_flag);
|
||||
}
|
||||
|
||||
bool RtpVideoStreamReceiver::IsUlpfecEnabled() const {
|
||||
return config_.rtp.ulpfec_payload_type != -1;
|
||||
}
|
||||
@ -385,15 +406,25 @@ int32_t RtpVideoStreamReceiver::ResendPackets(const uint16_t* sequence_numbers,
|
||||
void RtpVideoStreamReceiver::OnAssembledFrame(
|
||||
std::unique_ptr<video_coding::RtpFrameObject> frame) {
|
||||
RTC_DCHECK_RUN_ON(&network_tc_);
|
||||
// Request a key frame as soon as possible.
|
||||
bool key_frame_requested = false;
|
||||
if (!has_received_frame_) {
|
||||
has_received_frame_ = true;
|
||||
RTC_DCHECK(frame);
|
||||
|
||||
absl::optional<RtpGenericFrameDescriptor> descriptor =
|
||||
frame->GetGenericFrameDescriptor();
|
||||
|
||||
if (loss_notification_controller_ && descriptor) {
|
||||
loss_notification_controller_->OnAssembledFrame(
|
||||
frame->first_seq_num(), descriptor->FrameId(),
|
||||
descriptor->Discardable().value_or(false),
|
||||
descriptor->FrameDependenciesDiffs());
|
||||
} else if (!has_received_frame_) {
|
||||
// Request a key frame as soon as possible.
|
||||
if (frame->FrameType() != kVideoFrameKey) {
|
||||
key_frame_requested = true;
|
||||
keyframe_request_sender_->RequestKeyFrame();
|
||||
}
|
||||
}
|
||||
|
||||
has_received_frame_ = true;
|
||||
|
||||
if (buffered_frame_decryptor_ == nullptr) {
|
||||
reference_finder_->ManageFrame(std::move(frame));
|
||||
} else {
|
||||
@ -607,6 +638,10 @@ void RtpVideoStreamReceiver::NotifyReceiverOfEmptyPacket(uint16_t seq_num) {
|
||||
nack_module_->OnReceivedPacket(seq_num, /* is_keyframe = */ false,
|
||||
/* is _recovered = */ false);
|
||||
}
|
||||
if (loss_notification_controller_) {
|
||||
RTC_LOG(LS_WARNING)
|
||||
<< "LossNotificationController does not expect empty packets.";
|
||||
}
|
||||
}
|
||||
|
||||
bool RtpVideoStreamReceiver::DeliverRtcp(const uint8_t* rtcp_packet,
|
||||
|
||||
@ -18,7 +18,6 @@
|
||||
#include <vector>
|
||||
|
||||
#include "absl/types/optional.h"
|
||||
|
||||
#include "api/crypto/frame_decryptor_interface.h"
|
||||
#include "api/video/color_space.h"
|
||||
#include "api/video_codecs/video_codec.h"
|
||||
@ -33,6 +32,7 @@
|
||||
#include "modules/rtp_rtcp/source/contributing_sources.h"
|
||||
#include "modules/video_coding/h264_sps_pps_tracker.h"
|
||||
#include "modules/video_coding/include/video_coding_defines.h"
|
||||
#include "modules/video_coding/loss_notification_controller.h"
|
||||
#include "modules/video_coding/packet_buffer.h"
|
||||
#include "modules/video_coding/rtp_frame_reference_finder.h"
|
||||
#include "rtc_base/constructor_magic.h"
|
||||
@ -55,7 +55,8 @@ class RtpPacketReceived;
|
||||
class Transport;
|
||||
class UlpfecReceiver;
|
||||
|
||||
class RtpVideoStreamReceiver : public RecoveredPacketReceiver,
|
||||
class RtpVideoStreamReceiver : public LossNotificationSender,
|
||||
public RecoveredPacketReceiver,
|
||||
public RtpPacketSinkInterface,
|
||||
public VCMFrameTypeCallback,
|
||||
public VCMPacketRequestCallback,
|
||||
@ -118,6 +119,11 @@ class RtpVideoStreamReceiver : public RecoveredPacketReceiver,
|
||||
// Implements VCMFrameTypeCallback.
|
||||
int32_t RequestKeyFrame() override;
|
||||
|
||||
// Implements LossNotificationSender.
|
||||
void SendLossNotification(uint16_t last_decoded_seq_num,
|
||||
uint16_t last_received_seq_num,
|
||||
bool decodability_flag) override;
|
||||
|
||||
bool IsUlpfecEnabled() const;
|
||||
bool IsRetransmissionsEnabled() const;
|
||||
// Don't use, still experimental.
|
||||
@ -186,8 +192,9 @@ class RtpVideoStreamReceiver : public RecoveredPacketReceiver,
|
||||
|
||||
// Members for the new jitter buffer experiment.
|
||||
video_coding::OnCompleteFrameCallback* complete_frame_callback_;
|
||||
KeyFrameRequestSender* keyframe_request_sender_;
|
||||
KeyFrameRequestSender* const keyframe_request_sender_;
|
||||
std::unique_ptr<NackModule> nack_module_;
|
||||
std::unique_ptr<LossNotificationController> loss_notification_controller_;
|
||||
rtc::scoped_refptr<video_coding::PacketBuffer> packet_buffer_;
|
||||
std::unique_ptr<video_coding::RtpFrameReferenceFinder> reference_finder_;
|
||||
rtc::CriticalSection last_seq_num_cs_;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user