Wire up RTCP XR target bitrate in rtp/rtcp module
This is breakout of the rtcp parts of https://codereview.webrtc.org/2531383002/ BUG=webrtc:6301 Review-Url: https://codereview.webrtc.org/2546713002 Cr-Commit-Position: refs/heads/master@{#15358}
This commit is contained in:
@ -424,6 +424,8 @@ class RtpRtcp : public Module {
|
||||
// BWE feedback packets.
|
||||
virtual bool SendFeedbackPacket(const rtcp::TransportFeedback& packet) = 0;
|
||||
|
||||
virtual void SetVideoBitrateAllocation(const BitrateAllocation& bitrate) = 0;
|
||||
|
||||
// **************************************************************************
|
||||
// Audio
|
||||
// **************************************************************************
|
||||
|
||||
@ -102,6 +102,7 @@ enum RTCPPacketType : uint32_t {
|
||||
kRtcpXrReceiverReferenceTime = 0x40000,
|
||||
kRtcpXrDlrrReportBlock = 0x80000,
|
||||
kRtcpTransportFeedback = 0x100000,
|
||||
kRtcpXrTargetBitrate = 0x200000
|
||||
};
|
||||
|
||||
enum KeyFrameRequestMethod { kKeyFrameReqPliRtcp, kKeyFrameReqFirRtcp };
|
||||
|
||||
@ -204,6 +204,7 @@ class MockRtpRtcp : public RtpRtcp {
|
||||
void(StreamDataCountersCallback*));
|
||||
MOCK_CONST_METHOD0(GetSendChannelRtpStatisticsCallback,
|
||||
StreamDataCountersCallback*(void));
|
||||
MOCK_METHOD1(SetVideoBitrateAllocation, void(const BitrateAllocation&));
|
||||
// Members.
|
||||
unsigned int remote_ssrc_;
|
||||
};
|
||||
|
||||
@ -42,6 +42,12 @@
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
namespace {
|
||||
const uint32_t kRtcpAnyExtendedReports =
|
||||
kRtcpXrVoipMetric | kRtcpXrReceiverReferenceTime | kRtcpXrDlrrReportBlock |
|
||||
kRtcpXrTargetBitrate;
|
||||
} // namespace
|
||||
|
||||
NACKStringBuilder::NACKStringBuilder()
|
||||
: stream_(""), count_(0), prevNack_(0), consecutive_(false) {}
|
||||
|
||||
@ -197,10 +203,7 @@ RTCPSender::RTCPSender(
|
||||
builders_[kRtcpTmmbr] = &RTCPSender::BuildTMMBR;
|
||||
builders_[kRtcpTmmbn] = &RTCPSender::BuildTMMBN;
|
||||
builders_[kRtcpNack] = &RTCPSender::BuildNACK;
|
||||
builders_[kRtcpXrVoipMetric] = &RTCPSender::BuildVoIPMetric;
|
||||
builders_[kRtcpXrReceiverReferenceTime] =
|
||||
&RTCPSender::BuildReceiverReferenceTime;
|
||||
builders_[kRtcpXrDlrrReportBlock] = &RTCPSender::BuildDlrr;
|
||||
builders_[kRtcpAnyExtendedReports] = &RTCPSender::BuildExtendedReports;
|
||||
}
|
||||
|
||||
RTCPSender::~RTCPSender() {}
|
||||
@ -692,44 +695,47 @@ std::unique_ptr<rtcp::RtcpPacket> RTCPSender::BuildBYE(const RtcpContext& ctx) {
|
||||
return std::unique_ptr<rtcp::RtcpPacket>(bye);
|
||||
}
|
||||
|
||||
std::unique_ptr<rtcp::RtcpPacket> RTCPSender::BuildReceiverReferenceTime(
|
||||
std::unique_ptr<rtcp::RtcpPacket> RTCPSender::BuildExtendedReports(
|
||||
const RtcpContext& ctx) {
|
||||
|
||||
rtcp::ExtendedReports* xr = new rtcp::ExtendedReports();
|
||||
std::unique_ptr<rtcp::ExtendedReports> xr(new rtcp::ExtendedReports());
|
||||
xr->SetSenderSsrc(ssrc_);
|
||||
|
||||
rtcp::Rrtr rrtr;
|
||||
rrtr.SetNtp(NtpTime(ctx.ntp_sec_, ctx.ntp_frac_));
|
||||
if (!sending_ && xr_send_receiver_reference_time_enabled_) {
|
||||
rtcp::Rrtr rrtr;
|
||||
rrtr.SetNtp(NtpTime(ctx.ntp_sec_, ctx.ntp_frac_));
|
||||
xr->SetRrtr(rrtr);
|
||||
}
|
||||
|
||||
xr->SetRrtr(rrtr);
|
||||
if (ctx.feedback_state_.has_last_xr_rr) {
|
||||
xr->AddDlrrItem(ctx.feedback_state_.last_xr_rr);
|
||||
}
|
||||
|
||||
// TODO(sprang): Merge XR report sending to contain all of RRTR, DLRR, VOIP?
|
||||
if (video_bitrate_allocation_) {
|
||||
rtcp::TargetBitrate target_bitrate;
|
||||
|
||||
return std::unique_ptr<rtcp::RtcpPacket>(xr);
|
||||
}
|
||||
for (int sl = 0; sl < kMaxSpatialLayers; ++sl) {
|
||||
for (int tl = 0; tl < kMaxTemporalStreams; ++tl) {
|
||||
uint32_t layer_bitrate_bps =
|
||||
video_bitrate_allocation_->GetBitrate(sl, tl);
|
||||
if (layer_bitrate_bps > 0)
|
||||
target_bitrate.AddTargetBitrate(sl, tl, layer_bitrate_bps / 1000);
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<rtcp::RtcpPacket> RTCPSender::BuildDlrr(
|
||||
const RtcpContext& ctx) {
|
||||
rtcp::ExtendedReports* xr = new rtcp::ExtendedReports();
|
||||
xr->SetSenderSsrc(ssrc_);
|
||||
RTC_DCHECK(ctx.feedback_state_.has_last_xr_rr);
|
||||
xr->AddDlrrItem(ctx.feedback_state_.last_xr_rr);
|
||||
xr->SetTargetBitrate(target_bitrate);
|
||||
video_bitrate_allocation_.reset();
|
||||
}
|
||||
|
||||
return std::unique_ptr<rtcp::RtcpPacket>(xr);
|
||||
}
|
||||
if (xr_voip_metric_) {
|
||||
rtcp::VoipMetric voip;
|
||||
voip.SetMediaSsrc(remote_ssrc_);
|
||||
voip.SetVoipMetric(*xr_voip_metric_);
|
||||
xr_voip_metric_.reset();
|
||||
|
||||
std::unique_ptr<rtcp::RtcpPacket> RTCPSender::BuildVoIPMetric(
|
||||
const RtcpContext& context) {
|
||||
rtcp::ExtendedReports* xr = new rtcp::ExtendedReports();
|
||||
xr->SetSenderSsrc(ssrc_);
|
||||
xr->SetVoipMetric(voip);
|
||||
}
|
||||
|
||||
rtcp::VoipMetric voip;
|
||||
voip.SetMediaSsrc(remote_ssrc_);
|
||||
voip.SetVoipMetric(xr_voip_metric_);
|
||||
|
||||
xr->SetVoipMetric(voip);
|
||||
|
||||
return std::unique_ptr<rtcp::RtcpPacket>(xr);
|
||||
return std::move(xr);
|
||||
}
|
||||
|
||||
int32_t RTCPSender::SendRTCP(const FeedbackState& feedback_state,
|
||||
@ -794,7 +800,8 @@ int32_t RTCPSender::SendCompoundRTCP(
|
||||
auto it = report_flags_.begin();
|
||||
while (it != report_flags_.end()) {
|
||||
auto builder_it = builders_.find(it->type);
|
||||
RTC_DCHECK(builder_it != builders_.end());
|
||||
RTC_DCHECK(builder_it != builders_.end())
|
||||
<< "Could not find builder for packet type " << it->type;
|
||||
if (it->is_volatile) {
|
||||
report_flags_.erase(it++);
|
||||
} else {
|
||||
@ -849,10 +856,10 @@ void RTCPSender::PrepareReport(const FeedbackState& feedback_state) {
|
||||
SetFlag(kRtcpSdes, true);
|
||||
|
||||
if (generate_report) {
|
||||
if (!sending_ && xr_send_receiver_reference_time_enabled_)
|
||||
SetFlag(kRtcpXrReceiverReferenceTime, true);
|
||||
if (feedback_state.has_last_xr_rr)
|
||||
SetFlag(kRtcpXrDlrrReportBlock, true);
|
||||
if ((!sending_ && xr_send_receiver_reference_time_enabled_) ||
|
||||
feedback_state.has_last_xr_rr || video_bitrate_allocation_) {
|
||||
SetFlag(kRtcpAnyExtendedReports, true);
|
||||
}
|
||||
|
||||
// generate next time to send an RTCP report
|
||||
uint32_t minIntervalMs = RTCP_INTERVAL_AUDIO_MS;
|
||||
@ -959,9 +966,9 @@ int32_t RTCPSender::SetApplicationSpecificData(uint8_t subType,
|
||||
|
||||
int32_t RTCPSender::SetRTCPVoIPMetrics(const RTCPVoIPMetric* VoIPMetric) {
|
||||
rtc::CritScope lock(&critical_section_rtcp_sender_);
|
||||
memcpy(&xr_voip_metric_, VoIPMetric, sizeof(RTCPVoIPMetric));
|
||||
xr_voip_metric_.emplace(*VoIPMetric);
|
||||
|
||||
SetFlag(kRtcpXrVoipMetric, true);
|
||||
SetFlag(kRtcpAnyExtendedReports, true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -981,8 +988,12 @@ void RTCPSender::SetTmmbn(std::vector<rtcp::TmmbItem> bounding_set) {
|
||||
SetFlag(kRtcpTmmbn, true);
|
||||
}
|
||||
|
||||
void RTCPSender::SetFlag(RTCPPacketType type, bool is_volatile) {
|
||||
report_flags_.insert(ReportFlag(type, is_volatile));
|
||||
void RTCPSender::SetFlag(uint32_t type, bool is_volatile) {
|
||||
if (type & kRtcpAnyExtendedReports) {
|
||||
report_flags_.insert(ReportFlag(kRtcpAnyExtendedReports, is_volatile));
|
||||
} else {
|
||||
report_flags_.insert(ReportFlag(type, is_volatile));
|
||||
}
|
||||
}
|
||||
|
||||
void RTCPSender::SetFlags(const std::set<RTCPPacketType>& types,
|
||||
@ -991,11 +1002,11 @@ void RTCPSender::SetFlags(const std::set<RTCPPacketType>& types,
|
||||
SetFlag(type, is_volatile);
|
||||
}
|
||||
|
||||
bool RTCPSender::IsFlagPresent(RTCPPacketType type) const {
|
||||
bool RTCPSender::IsFlagPresent(uint32_t type) const {
|
||||
return report_flags_.find(ReportFlag(type, false)) != report_flags_.end();
|
||||
}
|
||||
|
||||
bool RTCPSender::ConsumeFlag(RTCPPacketType type, bool forced) {
|
||||
bool RTCPSender::ConsumeFlag(uint32_t type, bool forced) {
|
||||
auto it = report_flags_.find(ReportFlag(type, false));
|
||||
if (it == report_flags_.end())
|
||||
return false;
|
||||
@ -1012,6 +1023,12 @@ bool RTCPSender::AllVolatileFlagsConsumed() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
void RTCPSender::SetVideoBitrateAllocation(const BitrateAllocation& bitrate) {
|
||||
rtc::CritScope lock(&critical_section_rtcp_sender_);
|
||||
video_bitrate_allocation_.emplace(bitrate);
|
||||
SetFlag(kRtcpAnyExtendedReports, true);
|
||||
}
|
||||
|
||||
bool RTCPSender::SendFeedbackPacket(const rtcp::TransportFeedback& packet) {
|
||||
class Sender : public rtcp::RtcpPacket::PacketReadyCallback {
|
||||
public:
|
||||
|
||||
@ -21,6 +21,7 @@
|
||||
#include "webrtc/api/call/transport.h"
|
||||
#include "webrtc/base/constructormagic.h"
|
||||
#include "webrtc/base/criticalsection.h"
|
||||
#include "webrtc/base/optional.h"
|
||||
#include "webrtc/base/random.h"
|
||||
#include "webrtc/base/thread_annotations.h"
|
||||
#include "webrtc/modules/remote_bitrate_estimator/include/bwe_defines.h"
|
||||
@ -150,6 +151,7 @@ class RTCPSender {
|
||||
void SetCsrcs(const std::vector<uint32_t>& csrcs);
|
||||
|
||||
void SetTargetBitrate(unsigned int target_bitrate);
|
||||
void SetVideoBitrateAllocation(const BitrateAllocation& bitrate);
|
||||
bool SendFeedbackPacket(const rtcp::TransportFeedback& packet);
|
||||
|
||||
private:
|
||||
@ -180,7 +182,8 @@ class RTCPSender {
|
||||
EXCLUSIVE_LOCKS_REQUIRED(critical_section_rtcp_sender_);
|
||||
std::unique_ptr<rtcp::RtcpPacket> BuildAPP(const RtcpContext& context)
|
||||
EXCLUSIVE_LOCKS_REQUIRED(critical_section_rtcp_sender_);
|
||||
std::unique_ptr<rtcp::RtcpPacket> BuildVoIPMetric(const RtcpContext& context)
|
||||
std::unique_ptr<rtcp::RtcpPacket> BuildExtendedReports(
|
||||
const RtcpContext& context)
|
||||
EXCLUSIVE_LOCKS_REQUIRED(critical_section_rtcp_sender_);
|
||||
std::unique_ptr<rtcp::RtcpPacket> BuildBYE(const RtcpContext& context)
|
||||
EXCLUSIVE_LOCKS_REQUIRED(critical_section_rtcp_sender_);
|
||||
@ -192,11 +195,6 @@ class RTCPSender {
|
||||
EXCLUSIVE_LOCKS_REQUIRED(critical_section_rtcp_sender_);
|
||||
std::unique_ptr<rtcp::RtcpPacket> BuildNACK(const RtcpContext& context)
|
||||
EXCLUSIVE_LOCKS_REQUIRED(critical_section_rtcp_sender_);
|
||||
std::unique_ptr<rtcp::RtcpPacket> BuildReceiverReferenceTime(
|
||||
const RtcpContext& context)
|
||||
EXCLUSIVE_LOCKS_REQUIRED(critical_section_rtcp_sender_);
|
||||
std::unique_ptr<rtcp::RtcpPacket> BuildDlrr(const RtcpContext& context)
|
||||
EXCLUSIVE_LOCKS_REQUIRED(critical_section_rtcp_sender_);
|
||||
|
||||
private:
|
||||
const bool audio_;
|
||||
@ -257,7 +255,8 @@ class RTCPSender {
|
||||
GUARDED_BY(critical_section_rtcp_sender_);
|
||||
|
||||
// XR VoIP metric
|
||||
RTCPVoIPMetric xr_voip_metric_ GUARDED_BY(critical_section_rtcp_sender_);
|
||||
rtc::Optional<RTCPVoIPMetric> xr_voip_metric_
|
||||
GUARDED_BY(critical_section_rtcp_sender_);
|
||||
|
||||
RtcpPacketTypeCounterObserver* const packet_type_counter_observer_;
|
||||
RtcpPacketTypeCounter packet_type_counter_
|
||||
@ -265,22 +264,25 @@ class RTCPSender {
|
||||
|
||||
RTCPUtility::NackStats nack_stats_ GUARDED_BY(critical_section_rtcp_sender_);
|
||||
|
||||
void SetFlag(RTCPPacketType type, bool is_volatile)
|
||||
rtc::Optional<BitrateAllocation> video_bitrate_allocation_
|
||||
GUARDED_BY(critical_section_rtcp_sender_);
|
||||
|
||||
void SetFlag(uint32_t type, bool is_volatile)
|
||||
EXCLUSIVE_LOCKS_REQUIRED(critical_section_rtcp_sender_);
|
||||
void SetFlags(const std::set<RTCPPacketType>& types, bool is_volatile)
|
||||
EXCLUSIVE_LOCKS_REQUIRED(critical_section_rtcp_sender_);
|
||||
bool IsFlagPresent(RTCPPacketType type) const
|
||||
bool IsFlagPresent(uint32_t type) const
|
||||
EXCLUSIVE_LOCKS_REQUIRED(critical_section_rtcp_sender_);
|
||||
bool ConsumeFlag(RTCPPacketType type, bool forced = false)
|
||||
bool ConsumeFlag(uint32_t type, bool forced = false)
|
||||
EXCLUSIVE_LOCKS_REQUIRED(critical_section_rtcp_sender_);
|
||||
bool AllVolatileFlagsConsumed() const
|
||||
EXCLUSIVE_LOCKS_REQUIRED(critical_section_rtcp_sender_);
|
||||
struct ReportFlag {
|
||||
ReportFlag(RTCPPacketType type, bool is_volatile)
|
||||
ReportFlag(uint32_t type, bool is_volatile)
|
||||
: type(type), is_volatile(is_volatile) {}
|
||||
bool operator<(const ReportFlag& flag) const { return type < flag.type; }
|
||||
bool operator==(const ReportFlag& flag) const { return type == flag.type; }
|
||||
const RTCPPacketType type;
|
||||
const uint32_t type;
|
||||
const bool is_volatile;
|
||||
};
|
||||
|
||||
@ -288,7 +290,8 @@ class RTCPSender {
|
||||
|
||||
typedef std::unique_ptr<rtcp::RtcpPacket> (RTCPSender::*BuilderFunc)(
|
||||
const RtcpContext&);
|
||||
std::map<RTCPPacketType, BuilderFunc> builders_;
|
||||
// Map from RTCPPacketType to builder.
|
||||
std::map<uint32_t, BuilderFunc> builders_;
|
||||
|
||||
RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(RTCPSender);
|
||||
};
|
||||
|
||||
@ -821,4 +821,39 @@ TEST_F(RtcpSenderTest, ByeMustBeLast) {
|
||||
EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state(), kRtcpBye));
|
||||
}
|
||||
|
||||
TEST_F(RtcpSenderTest, SendXrWithTargetBitrate) {
|
||||
rtcp_sender_->SetRTCPStatus(RtcpMode::kCompound);
|
||||
const size_t kNumSpatialLayers = 2;
|
||||
const size_t kNumTemporalLayers = 2;
|
||||
BitrateAllocation allocation;
|
||||
for (size_t sl = 0; sl < kNumSpatialLayers; ++sl) {
|
||||
uint32_t start_bitrate_bps = (sl + 1) * 100000;
|
||||
for (size_t tl = 0; tl < kNumTemporalLayers; ++tl)
|
||||
allocation.SetBitrate(sl, tl, start_bitrate_bps + (tl * 20000));
|
||||
}
|
||||
rtcp_sender_->SetVideoBitrateAllocation(allocation);
|
||||
|
||||
EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state(), kRtcpReport));
|
||||
EXPECT_EQ(1, parser()->xr()->num_packets());
|
||||
EXPECT_EQ(kSenderSsrc, parser()->xr()->sender_ssrc());
|
||||
const rtc::Optional<rtcp::TargetBitrate>& target_bitrate =
|
||||
parser()->xr()->target_bitrate();
|
||||
ASSERT_TRUE(target_bitrate);
|
||||
const std::vector<rtcp::TargetBitrate::BitrateItem>& bitrates =
|
||||
target_bitrate->GetTargetBitrates();
|
||||
EXPECT_EQ(kNumSpatialLayers * kNumTemporalLayers, bitrates.size());
|
||||
|
||||
for (size_t sl = 0; sl < kNumSpatialLayers; ++sl) {
|
||||
uint32_t start_bitrate_bps = (sl + 1) * 100000;
|
||||
for (size_t tl = 0; tl < kNumTemporalLayers; ++tl) {
|
||||
size_t index = (sl * kNumSpatialLayers) + tl;
|
||||
const rtcp::TargetBitrate::BitrateItem& item = bitrates[index];
|
||||
EXPECT_EQ(sl, item.spatial_layer);
|
||||
EXPECT_EQ(tl, item.temporal_layer);
|
||||
EXPECT_EQ(start_bitrate_bps + (tl * 20000),
|
||||
item.target_bitrate_kbps * 1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
@ -953,4 +953,9 @@ StreamDataCountersCallback*
|
||||
ModuleRtpRtcpImpl::GetSendChannelRtpStatisticsCallback() const {
|
||||
return rtp_sender_.GetRtpStatisticsCallback();
|
||||
}
|
||||
|
||||
void ModuleRtpRtcpImpl::SetVideoBitrateAllocation(
|
||||
const BitrateAllocation& bitrate) {
|
||||
rtcp_sender_.SetVideoBitrateAllocation(bitrate);
|
||||
}
|
||||
} // namespace webrtc
|
||||
|
||||
@ -313,6 +313,8 @@ class ModuleRtpRtcpImpl : public RtpRtcp, public RTCPReceiver::ModuleRtpRtcp {
|
||||
const ReportBlockList& report_blocks) override;
|
||||
void OnRequestSendReport() override;
|
||||
|
||||
void SetVideoBitrateAllocation(const BitrateAllocation& bitrate) override;
|
||||
|
||||
protected:
|
||||
bool UpdateRTCPReceiveInformationTimers();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user