Add RequestKeyFrame with Pli to RtcpTransceiver
Add support for reduced size mode.
Bug: webrtc:8239
Change-Id: I1d646f0d7848af6632c9204ce5b96ae24cfc0ad3
Reviewed-on: https://webrtc-review.googlesource.com/23681
Commit-Queue: Danil Chapovalov <danilchap@webrtc.org>
Reviewed-by: Niels Moller <nisse@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#20812}
diff --git a/modules/rtp_rtcp/source/rtcp_transceiver.cc b/modules/rtp_rtcp/source/rtcp_transceiver.cc
index fa104f1..7c668b9 100644
--- a/modules/rtp_rtcp/source/rtcp_transceiver.cc
+++ b/modules/rtp_rtcp/source/rtcp_transceiver.cc
@@ -90,4 +90,18 @@
});
}
+void RtcpTransceiver::RequestKeyFrame(std::vector<uint32_t> ssrcs) {
+ // TODO(danilchap): Replace with lambda with move capture when available.
+ struct RequestKeyFrameClosure {
+ void operator()() {
+ if (ptr)
+ ptr->RequestKeyFrame(ssrcs);
+ }
+
+ rtc::WeakPtr<RtcpTransceiverImpl> ptr;
+ std::vector<uint32_t> ssrcs;
+ };
+ task_queue_->PostTask(RequestKeyFrameClosure{ptr_, std::move(ssrcs)});
+}
+
} // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtcp_transceiver.h b/modules/rtp_rtcp/source/rtcp_transceiver.h
index 5a9998b..4e571ee 100644
--- a/modules/rtp_rtcp/source/rtcp_transceiver.h
+++ b/modules/rtp_rtcp/source/rtcp_transceiver.h
@@ -44,6 +44,8 @@
// Stops sending REMB in following compound packets.
void UnsetRemb();
+ void RequestKeyFrame(std::vector<uint32_t> ssrcs);
+
private:
rtc::TaskQueue* const task_queue_;
std::unique_ptr<RtcpTransceiverImpl> rtcp_transceiver_;
diff --git a/modules/rtp_rtcp/source/rtcp_transceiver_config.cc b/modules/rtp_rtcp/source/rtcp_transceiver_config.cc
index 9256d24..d6313ae 100644
--- a/modules/rtp_rtcp/source/rtcp_transceiver_config.cc
+++ b/modules/rtp_rtcp/source/rtcp_transceiver_config.cc
@@ -48,6 +48,11 @@
RTC_LOG(LS_ERROR) << debug_id << "outgoing transport must be set";
return false;
}
+ if (initial_report_delay_ms < 0) {
+ RTC_LOG(LS_ERROR) << debug_id << "delay " << initial_report_delay_ms
+ << "ms before first report shouldn't be negative.";
+ return false;
+ }
if (report_period_ms <= 0) {
RTC_LOG(LS_ERROR) << debug_id << "period " << report_period_ms
<< "ms between reports should be positive.";
@@ -58,6 +63,10 @@
<< "missing task queue for periodic compound packets";
return false;
}
+ if (rtcp_mode != RtcpMode::kCompound && rtcp_mode != RtcpMode::kReducedSize) {
+ RTC_LOG(LS_ERROR) << debug_id << "unsupported rtcp mode";
+ return false;
+ }
// TODO(danilchap): Remove or update the warning when RtcpTransceiver supports
// send-only sessions.
if (receive_statistics == nullptr)
diff --git a/modules/rtp_rtcp/source/rtcp_transceiver_config.h b/modules/rtp_rtcp/source/rtcp_transceiver_config.h
index 79f18c8..07f4c51 100644
--- a/modules/rtp_rtcp/source/rtcp_transceiver_config.h
+++ b/modules/rtp_rtcp/source/rtcp_transceiver_config.h
@@ -13,6 +13,7 @@
#include <string>
+#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
#include "rtc_base/task_queue.h"
namespace webrtc {
@@ -51,6 +52,11 @@
// Rtcp report block generator for outgoing receiver reports.
ReceiveStatisticsProvider* receive_statistics = nullptr;
+ // Configures if sending should
+ // enforce compound packets: https://tools.ietf.org/html/rfc4585#section-3.1
+ // or allow reduced size packets: https://tools.ietf.org/html/rfc5506
+ // Receiving accepts both compound and reduced-size packets.
+ RtcpMode rtcp_mode = RtcpMode::kCompound;
//
// Tuning parameters.
//
diff --git a/modules/rtp_rtcp/source/rtcp_transceiver_impl.cc b/modules/rtp_rtcp/source/rtcp_transceiver_impl.cc
index 2c6eb8d..52bc489 100644
--- a/modules/rtp_rtcp/source/rtcp_transceiver_impl.cc
+++ b/modules/rtp_rtcp/source/rtcp_transceiver_impl.cc
@@ -17,6 +17,7 @@
#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
#include "modules/rtp_rtcp/source/rtcp_packet.h"
#include "modules/rtp_rtcp/source/rtcp_packet/common_header.h"
+#include "modules/rtp_rtcp/source/rtcp_packet/pli.h"
#include "modules/rtp_rtcp/source/rtcp_packet/receiver_report.h"
#include "modules/rtp_rtcp/source/rtcp_packet/report_block.h"
#include "modules/rtp_rtcp/source/rtcp_packet/sdes.h"
@@ -28,11 +29,13 @@
#include "rtc_base/timeutils.h"
namespace webrtc {
-namespace {
// Helper to put several RTCP packets into lower layer datagram composing
// Compound or Reduced-Size RTCP packet, as defined by RFC 5506 section 2.
-class PacketSender : public rtcp::RtcpPacket::PacketReadyCallback {
+// TODO(danilchap): When in compound mode and packets are so many that several
+// compound RTCP packets need to be generated, ensure each packet is compound.
+class RtcpTransceiverImpl::PacketSender
+ : public rtcp::RtcpPacket::PacketReadyCallback {
public:
PacketSender(Transport* transport, size_t max_packet_size)
: transport_(transport), max_packet_size_(max_packet_size) {
@@ -56,6 +59,8 @@
}
}
+ bool IsEmpty() const { return index_ == 0; }
+
private:
// Implements RtcpPacket::PacketReadyCallback
void OnPacketReady(uint8_t* data, size_t length) override {
@@ -68,8 +73,6 @@
uint8_t buffer_[IP_PACKET_SIZE];
};
-} // namespace
-
RtcpTransceiverImpl::RtcpTransceiverImpl(const RtcpTransceiverConfig& config)
: config_(config), ptr_factory_(this) {
RTC_CHECK(config_.Validate());
@@ -94,12 +97,8 @@
}
void RtcpTransceiverImpl::SendCompoundPacket() {
- SendPacket();
- if (config_.schedule_periodic_compound_packets) {
- // Stop existent send task.
- ptr_factory_.InvalidateWeakPtrs();
- SchedulePeriodicCompoundPackets(config_.report_period_ms);
- }
+ SendPeriodicCompoundPacket();
+ ReschedulePeriodicCompoundPackets();
}
void RtcpTransceiverImpl::SetRemb(int bitrate_bps,
@@ -117,6 +116,27 @@
remb_.reset();
}
+void RtcpTransceiverImpl::RequestKeyFrame(
+ rtc::ArrayView<const uint32_t> ssrcs) {
+ RTC_DCHECK(!ssrcs.empty());
+ const uint32_t sender_ssrc = config_.feedback_ssrc;
+ PacketSender sender(config_.outgoing_transport, config_.max_packet_size);
+ if (config_.rtcp_mode == RtcpMode::kCompound)
+ CreateCompoundPacket(&sender);
+
+ for (uint32_t media_ssrc : ssrcs) {
+ rtcp::Pli pli;
+ pli.SetSenderSsrc(sender_ssrc);
+ pli.SetMediaSsrc(media_ssrc);
+ sender.AppendPacket(pli);
+ }
+
+ sender.Send();
+
+ if (config_.rtcp_mode == RtcpMode::kCompound)
+ ReschedulePeriodicCompoundPackets();
+}
+
void RtcpTransceiverImpl::HandleReceivedPacket(
const rtcp::CommonHeader& rtcp_packet_header,
int64_t now_us) {
@@ -134,17 +154,25 @@
}
}
+void RtcpTransceiverImpl::ReschedulePeriodicCompoundPackets() {
+ if (!config_.schedule_periodic_compound_packets)
+ return;
+ // Stop existent send task.
+ ptr_factory_.InvalidateWeakPtrs();
+ SchedulePeriodicCompoundPackets(config_.report_period_ms);
+}
+
void RtcpTransceiverImpl::SchedulePeriodicCompoundPackets(int64_t delay_ms) {
- class SendPeriodicCompoundPacket : public rtc::QueuedTask {
+ class SendPeriodicCompoundPacketTask : public rtc::QueuedTask {
public:
- SendPeriodicCompoundPacket(rtc::TaskQueue* task_queue,
- rtc::WeakPtr<RtcpTransceiverImpl> ptr)
+ SendPeriodicCompoundPacketTask(rtc::TaskQueue* task_queue,
+ rtc::WeakPtr<RtcpTransceiverImpl> ptr)
: task_queue_(task_queue), ptr_(std::move(ptr)) {}
bool Run() override {
RTC_DCHECK(task_queue_->IsCurrent());
if (!ptr_)
return true;
- ptr_->SendPacket();
+ ptr_->SendPeriodicCompoundPacket();
task_queue_->PostDelayedTask(rtc::WrapUnique(this),
ptr_->config_.report_period_ms);
return false;
@@ -157,7 +185,7 @@
RTC_DCHECK(config_.schedule_periodic_compound_packets);
- auto task = rtc::MakeUnique<SendPeriodicCompoundPacket>(
+ auto task = rtc::MakeUnique<SendPeriodicCompoundPacketTask>(
config_.task_queue, ptr_factory_.GetWeakPtr());
if (delay_ms > 0)
config_.task_queue->PostDelayedTask(std::move(task), delay_ms);
@@ -165,27 +193,30 @@
config_.task_queue->PostTask(std::move(task));
}
-void RtcpTransceiverImpl::SendPacket() {
- PacketSender sender(config_.outgoing_transport, config_.max_packet_size);
+void RtcpTransceiverImpl::CreateCompoundPacket(PacketSender* sender) {
+ RTC_DCHECK(sender->IsEmpty());
const uint32_t sender_ssrc = config_.feedback_ssrc;
-
rtcp::ReceiverReport receiver_report;
receiver_report.SetSenderSsrc(sender_ssrc);
receiver_report.SetReportBlocks(CreateReportBlocks());
- sender.AppendPacket(receiver_report);
+ sender->AppendPacket(receiver_report);
if (!config_.cname.empty()) {
rtcp::Sdes sdes;
bool added = sdes.AddCName(config_.feedback_ssrc, config_.cname);
RTC_DCHECK(added) << "Failed to add cname " << config_.cname
<< " to rtcp sdes packet.";
- sender.AppendPacket(sdes);
+ sender->AppendPacket(sdes);
}
if (remb_) {
remb_->SetSenderSsrc(sender_ssrc);
- sender.AppendPacket(*remb_);
+ sender->AppendPacket(*remb_);
}
+}
+void RtcpTransceiverImpl::SendPeriodicCompoundPacket() {
+ PacketSender sender(config_.outgoing_transport, config_.max_packet_size);
+ CreateCompoundPacket(&sender);
sender.Send();
}
diff --git a/modules/rtp_rtcp/source/rtcp_transceiver_impl.h b/modules/rtp_rtcp/source/rtcp_transceiver_impl.h
index 689ed1e..aed850b 100644
--- a/modules/rtp_rtcp/source/rtcp_transceiver_impl.h
+++ b/modules/rtp_rtcp/source/rtcp_transceiver_impl.h
@@ -48,7 +48,10 @@
// Stops sending REMB in following compound packets.
void UnsetRemb();
+ void RequestKeyFrame(rtc::ArrayView<const uint32_t> ssrcs);
+
private:
+ class PacketSender;
struct SenderReportTimes {
int64_t local_received_time_us;
NtpTime remote_sent_time;
@@ -57,9 +60,13 @@
void HandleReceivedPacket(const rtcp::CommonHeader& rtcp_packet_header,
int64_t now_us);
+ void ReschedulePeriodicCompoundPackets();
void SchedulePeriodicCompoundPackets(int64_t delay_ms);
+ // Creates compound RTCP packet, as defined in
+ // https://tools.ietf.org/html/rfc5506#section-2
+ void CreateCompoundPacket(PacketSender* sender);
// Sends RTCP packets.
- void SendPacket();
+ void SendPeriodicCompoundPacket();
// Generate Report Blocks to be send in Sender or Receiver Report.
std::vector<rtcp::ReportBlock> CreateReportBlocks();
diff --git a/modules/rtp_rtcp/source/rtcp_transceiver_impl_unittest.cc b/modules/rtp_rtcp/source/rtcp_transceiver_impl_unittest.cc
index b144ec4..e5f7a65 100644
--- a/modules/rtp_rtcp/source/rtcp_transceiver_impl_unittest.cc
+++ b/modules/rtp_rtcp/source/rtcp_transceiver_impl_unittest.cc
@@ -447,4 +447,69 @@
EXPECT_EQ(CompactNtpRttToMs(report_blocks[1].delay_since_last_sr()), 100);
}
+TEST(RtcpTransceiverImplTest, RequestKeyFrameWithPictureLossIndication) {
+ const uint32_t kSenderSsrc = 1234;
+ const uint32_t kRemoteSsrcs[] = {4321, 5321};
+ MockTransport outgoing_transport;
+ RtcpTransceiverConfig config;
+ config.feedback_ssrc = kSenderSsrc;
+ config.schedule_periodic_compound_packets = false;
+ config.outgoing_transport = &outgoing_transport;
+ RtcpTransceiverImpl rtcp_transceiver(config);
+ RtcpPacketParser rtcp_parser;
+ EXPECT_CALL(outgoing_transport, SendRtcp(_, _))
+ .WillOnce(Invoke(&rtcp_parser, &RtcpPacketParser::Parse));
+
+ rtcp_transceiver.RequestKeyFrame(kRemoteSsrcs);
+
+ // Expect a pli packet per ssrc in the sent single compound packet.
+ EXPECT_EQ(rtcp_parser.pli()->num_packets(), 2);
+ EXPECT_EQ(rtcp_parser.pli()->sender_ssrc(), kSenderSsrc);
+ // test::RtcpPacketParser overwrites first pli packet with second one.
+ EXPECT_EQ(rtcp_parser.pli()->media_ssrc(), kRemoteSsrcs[1]);
+}
+
+TEST(RtcpTransceiverImplTest, KeyFrameRequestCreatesCompoundPacket) {
+ const uint32_t kRemoteSsrcs[] = {4321};
+ MockTransport outgoing_transport;
+ RtcpTransceiverConfig config;
+ // Turn periodic off to ensure sent rtcp packet is explicitly requested.
+ config.schedule_periodic_compound_packets = false;
+ config.outgoing_transport = &outgoing_transport;
+
+ config.rtcp_mode = webrtc::RtcpMode::kCompound;
+
+ RtcpTransceiverImpl rtcp_transceiver(config);
+ RtcpPacketParser rtcp_parser;
+ EXPECT_CALL(outgoing_transport, SendRtcp(_, _))
+ .WillOnce(Invoke(&rtcp_parser, &RtcpPacketParser::Parse));
+
+ rtcp_transceiver.RequestKeyFrame(kRemoteSsrcs);
+
+ // Test sent packet is compound by expecting presense of receiver report.
+ EXPECT_EQ(rtcp_parser.receiver_report()->num_packets(), 1);
+}
+
+TEST(RtcpTransceiverImplTest, KeyFrameRequestCreatesReducedSizePacket) {
+ const uint32_t kRemoteSsrcs[] = {4321};
+ MockTransport outgoing_transport;
+ RtcpTransceiverConfig config;
+ // Turn periodic off to ensure sent rtcp packet is explicitly requested.
+ config.schedule_periodic_compound_packets = false;
+ config.outgoing_transport = &outgoing_transport;
+
+ config.rtcp_mode = webrtc::RtcpMode::kReducedSize;
+
+ RtcpTransceiverImpl rtcp_transceiver(config);
+ RtcpPacketParser rtcp_parser;
+ // Expect some rtcp packet is triggered by the RequestKeyFrame.
+ EXPECT_CALL(outgoing_transport, SendRtcp(_, _))
+ .WillOnce(Invoke(&rtcp_parser, &RtcpPacketParser::Parse));
+
+ rtcp_transceiver.RequestKeyFrame(kRemoteSsrcs);
+
+ // Test sent packet is reduced size by expecting absense of receiver report.
+ EXPECT_EQ(rtcp_parser.receiver_report()->num_packets(), 0);
+}
+
} // namespace