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:
Elad Alon 2019-02-25 13:00:51 +01:00 committed by Commit Bot
parent a497d12a02
commit 7d6a4c045c
13 changed files with 159 additions and 15 deletions

View File

@ -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

View File

@ -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*));

View File

@ -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;

View File

@ -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;

View File

@ -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();

View File

@ -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_

View File

@ -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);

View File

@ -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_);

View File

@ -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,

View File

@ -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)

View File

@ -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_;

View File

@ -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,

View File

@ -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_;