From e1795f41589a39c8e9348cb35efdffe1b777a613 Mon Sep 17 00:00:00 2001 From: Sebastian Jansson Date: Wed, 24 Jul 2019 11:38:03 +0200 Subject: [PATCH] Adds remote estimate RTCP packet. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds the RemoteEstimate rtcp packet and wires it up to GoogCC where it's used to improve congestion controller behavior. The functionality is negotiated using SDP. It's added with a field trial that allow disabling the functionality in case there's any issues. Bug: webrtc:10742 Change-Id: I1ea8e4216a27cd2b00505c99b42d1e38726256c8 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/146602 Reviewed-by: Stefan Holmer Reviewed-by: Erik Språng Commit-Queue: Sebastian Jansson Cr-Commit-Position: refs/heads/master@{#28654} --- call/rtp_transport_controller_send.cc | 15 ++ call/rtp_transport_controller_send.h | 7 +- .../rtp_transport_controller_send_interface.h | 1 + call/rtp_video_sender.cc | 2 + .../test/mock_rtp_transport_controller_send.h | 2 + media/base/media_channel.h | 1 + modules/rtp_rtcp/BUILD.gn | 3 + modules/rtp_rtcp/include/rtp_rtcp.h | 1 + modules/rtp_rtcp/include/rtp_rtcp_defines.h | 8 + modules/rtp_rtcp/mocks/mock_rtp_rtcp.h | 2 + modules/rtp_rtcp/source/rtcp_packet/app.h | 6 + .../source/rtcp_packet/remote_estimate.cc | 157 ++++++++++++++++++ .../source/rtcp_packet/remote_estimate.h | 56 +++++++ .../rtcp_packet/remote_estimate_unittest.cc | 56 +++++++ modules/rtp_rtcp/source/rtcp_receiver.cc | 24 +++ modules/rtp_rtcp/source/rtcp_receiver.h | 5 + modules/rtp_rtcp/source/rtcp_sender.cc | 18 ++ modules/rtp_rtcp/source/rtcp_sender.h | 1 + modules/rtp_rtcp/source/rtcp_transceiver.cc | 12 ++ modules/rtp_rtcp/source/rtcp_transceiver.h | 2 + modules/rtp_rtcp/source/rtp_rtcp_impl.cc | 5 + modules/rtp_rtcp/source/rtp_rtcp_impl.h | 2 + pc/channel.cc | 1 + pc/media_session.cc | 2 + pc/session_description.h | 6 + pc/webrtc_sdp.cc | 9 + 26 files changed, 403 insertions(+), 1 deletion(-) create mode 100644 modules/rtp_rtcp/source/rtcp_packet/remote_estimate.cc create mode 100644 modules/rtp_rtcp/source/rtcp_packet/remote_estimate.h create mode 100644 modules/rtp_rtcp/source/rtcp_packet/remote_estimate_unittest.cc diff --git a/call/rtp_transport_controller_send.cc b/call/rtp_transport_controller_send.cc index 842afd79fa..a1a42e1de5 100644 --- a/call/rtp_transport_controller_send.cc +++ b/call/rtp_transport_controller_send.cc @@ -157,6 +157,11 @@ PacketRouter* RtpTransportControllerSend::packet_router() { return &packet_router_; } +NetworkStateEstimateObserver* +RtpTransportControllerSend::network_state_estimate_observer() { + return this; +} + TransportFeedbackObserver* RtpTransportControllerSend::transport_feedback_observer() { return this; @@ -451,6 +456,16 @@ void RtpTransportControllerSend::OnTransportFeedback( transport_feedback_adapter_.GetOutstandingData().bytes()); } +void RtpTransportControllerSend::OnRemoteNetworkEstimate( + NetworkStateEstimate estimate) { + estimate.update_time = Timestamp::ms(clock_->TimeInMilliseconds()); + task_queue_.PostTask([this, estimate] { + RTC_DCHECK_RUN_ON(&task_queue_); + if (controller_) + controller_->OnNetworkStateEstimate(estimate); + }); +} + void RtpTransportControllerSend::MaybeCreateControllers() { RTC_DCHECK(!controller_); RTC_DCHECK(!control_handler_); diff --git a/call/rtp_transport_controller_send.h b/call/rtp_transport_controller_send.h index 235fc152d9..e7e1610032 100644 --- a/call/rtp_transport_controller_send.h +++ b/call/rtp_transport_controller_send.h @@ -43,7 +43,8 @@ class RtcEventLog; class RtpTransportControllerSend final : public RtpTransportControllerSendInterface, public RtcpBandwidthObserver, - public TransportFeedbackObserver { + public TransportFeedbackObserver, + public NetworkStateEstimateObserver { public: RtpTransportControllerSend( Clock* clock, @@ -73,6 +74,7 @@ class RtpTransportControllerSend final rtc::TaskQueue* GetWorkerQueue() override; PacketRouter* packet_router() override; + NetworkStateEstimateObserver* network_state_estimate_observer() override; TransportFeedbackObserver* transport_feedback_observer() override; RtpPacketPacer* packet_sender() override; @@ -114,6 +116,9 @@ class RtpTransportControllerSend final void OnAddPacket(const RtpPacketSendInfo& packet_info) override; void OnTransportFeedback(const rtcp::TransportFeedback& feedback) override; + // Implements NetworkStateEstimateObserver interface + void OnRemoteNetworkEstimate(NetworkStateEstimate estimate) override; + private: void MaybeCreateControllers() RTC_RUN_ON(task_queue_); void UpdateInitialConstraints(TargetRateConstraints new_contraints) diff --git a/call/rtp_transport_controller_send_interface.h b/call/rtp_transport_controller_send_interface.h index 4cfe7c9647..0178758a47 100644 --- a/call/rtp_transport_controller_send_interface.h +++ b/call/rtp_transport_controller_send_interface.h @@ -116,6 +116,7 @@ class RtpTransportControllerSendInterface { virtual void DestroyRtpVideoSender( RtpVideoSenderInterface* rtp_video_sender) = 0; + virtual NetworkStateEstimateObserver* network_state_estimate_observer() = 0; virtual TransportFeedbackObserver* transport_feedback_observer() = 0; virtual RtpPacketPacer* packet_sender() = 0; diff --git a/call/rtp_video_sender.cc b/call/rtp_video_sender.cc index 529e0ad98c..70fe82157a 100644 --- a/call/rtp_video_sender.cc +++ b/call/rtp_video_sender.cc @@ -86,6 +86,8 @@ std::vector CreateRtpStreamSenders( configuration.rtcp_loss_notification_observer = rtcp_loss_notification_observer; configuration.bandwidth_callback = bandwidth_callback; + configuration.network_state_estimate_observer = + transport->network_state_estimate_observer(); configuration.transport_feedback_callback = transport->transport_feedback_observer(); configuration.rtt_stats = rtt_stats; diff --git a/call/test/mock_rtp_transport_controller_send.h b/call/test/mock_rtp_transport_controller_send.h index 2e813963a0..81db5878ca 100644 --- a/call/test/mock_rtp_transport_controller_send.h +++ b/call/test/mock_rtp_transport_controller_send.h @@ -45,6 +45,8 @@ class MockRtpTransportControllerSend MOCK_METHOD1(DestroyRtpVideoSender, void(RtpVideoSenderInterface*)); MOCK_METHOD0(GetWorkerQueue, rtc::TaskQueue*()); MOCK_METHOD0(packet_router, PacketRouter*()); + MOCK_METHOD0(network_state_estimate_observer, + NetworkStateEstimateObserver*()); MOCK_METHOD0(transport_feedback_observer, TransportFeedbackObserver*()); MOCK_METHOD0(packet_sender, RtpPacketPacer*()); MOCK_METHOD3(SetAllocatedSendBitrateLimits, void(int, int, int)); diff --git a/media/base/media_channel.h b/media/base/media_channel.h index 8c4e8b8e2c..856dba4251 100644 --- a/media/base/media_channel.h +++ b/media/base/media_channel.h @@ -719,6 +719,7 @@ struct DataMediaInfo { struct RtcpParameters { bool reduced_size = false; + bool remote_estimate = false; }; template diff --git a/modules/rtp_rtcp/BUILD.gn b/modules/rtp_rtcp/BUILD.gn index 791cdd350c..98a512e252 100644 --- a/modules/rtp_rtcp/BUILD.gn +++ b/modules/rtp_rtcp/BUILD.gn @@ -34,6 +34,7 @@ rtc_source_set("rtp_rtcp_format") { "source/rtcp_packet/rapid_resync_request.h", "source/rtcp_packet/receiver_report.h", "source/rtcp_packet/remb.h", + "source/rtcp_packet/remote_estimate.h", "source/rtcp_packet/report_block.h", "source/rtcp_packet/rrtr.h", "source/rtcp_packet/rtpfb.h", @@ -73,6 +74,7 @@ rtc_source_set("rtp_rtcp_format") { "source/rtcp_packet/rapid_resync_request.cc", "source/rtcp_packet/receiver_report.cc", "source/rtcp_packet/remb.cc", + "source/rtcp_packet/remote_estimate.cc", "source/rtcp_packet/report_block.cc", "source/rtcp_packet/rrtr.cc", "source/rtcp_packet/rtpfb.cc", @@ -411,6 +413,7 @@ if (rtc_include_tests) { "source/rtcp_packet/rapid_resync_request_unittest.cc", "source/rtcp_packet/receiver_report_unittest.cc", "source/rtcp_packet/remb_unittest.cc", + "source/rtcp_packet/remote_estimate_unittest.cc", "source/rtcp_packet/report_block_unittest.cc", "source/rtcp_packet/rrtr_unittest.cc", "source/rtcp_packet/sdes_unittest.cc", diff --git a/modules/rtp_rtcp/include/rtp_rtcp.h b/modules/rtp_rtcp/include/rtp_rtcp.h index 83c4cfc9cb..f4a8c9d29b 100644 --- a/modules/rtp_rtcp/include/rtp_rtcp.h +++ b/modules/rtp_rtcp/include/rtp_rtcp.h @@ -78,6 +78,7 @@ class RtpRtcp : public Module, public RtcpFeedbackSenderInterface { // stream. RtcpBandwidthObserver* bandwidth_callback = nullptr; + NetworkStateEstimateObserver* network_state_estimate_observer = nullptr; TransportFeedbackObserver* transport_feedback_callback = nullptr; VideoBitrateAllocationObserver* bitrate_allocation_observer = nullptr; RtcpRttStats* rtt_stats = nullptr; diff --git a/modules/rtp_rtcp/include/rtp_rtcp_defines.h b/modules/rtp_rtcp/include/rtp_rtcp_defines.h index 2b46764f54..a7796338a3 100644 --- a/modules/rtp_rtcp/include/rtp_rtcp_defines.h +++ b/modules/rtp_rtcp/include/rtp_rtcp_defines.h @@ -24,6 +24,7 @@ #include "api/rtp_headers.h" #include "api/transport/network_types.h" #include "modules/include/module_common_types.h" +#include "modules/rtp_rtcp/source/rtcp_packet/remote_estimate.h" #include "system_wrappers/include/clock.h" #define RTCP_CNAME_SIZE 256 // RFC 3550 page 44, including null termination @@ -291,6 +292,11 @@ struct RtpPacketSendInfo { size_t length = 0; PacedPacketInfo pacing_info; }; +class NetworkStateEstimateObserver { + public: + virtual void OnRemoteNetworkEstimate(NetworkStateEstimate estimate) = 0; + virtual ~NetworkStateEstimateObserver() = default; +}; class TransportFeedbackObserver { public: @@ -310,6 +316,8 @@ class RtcpFeedbackSenderInterface { virtual ~RtcpFeedbackSenderInterface() = default; virtual uint32_t SSRC() const = 0; virtual bool SendFeedbackPacket(const rtcp::TransportFeedback& feedback) = 0; + virtual bool SendNetworkStateEstimatePacket( + const rtcp::RemoteEstimate& packet) = 0; virtual void SetRemb(int64_t bitrate_bps, std::vector ssrcs) = 0; virtual void UnsetRemb() = 0; }; diff --git a/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h b/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h index 68ded28afc..1cb488c169 100644 --- a/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h +++ b/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h @@ -155,6 +155,8 @@ class MockRtpRtcp : public RtpRtcp { MOCK_METHOD0(GetRtcpStatisticsCallback, RtcpStatisticsCallback*()); MOCK_METHOD1(SetReportBlockDataObserver, void(ReportBlockDataObserver*)); MOCK_METHOD1(SendFeedbackPacket, bool(const rtcp::TransportFeedback& packet)); + MOCK_METHOD1(SendNetworkStateEstimatePacket, + bool(const rtcp::RemoteEstimate& packet)); MOCK_METHOD1(SetTargetSendBitrate, void(uint32_t bitrate_bps)); MOCK_METHOD4(SendLossNotification, int32_t(uint16_t last_decoded_seq_num, diff --git a/modules/rtp_rtcp/source/rtcp_packet/app.h b/modules/rtp_rtcp/source/rtcp_packet/app.h index a9602a80cf..ff5f52dbf8 100644 --- a/modules/rtp_rtcp/source/rtcp_packet/app.h +++ b/modules/rtp_rtcp/source/rtcp_packet/app.h @@ -48,6 +48,12 @@ class App : public RtcpPacket { size_t max_length, PacketReadyCallback callback) const override; + static inline constexpr uint32_t NameToInt(const char name[5]) { + return static_cast(name[0]) << 24 | + static_cast(name[1]) << 16 | + static_cast(name[2]) << 8 | static_cast(name[3]); + } + private: static constexpr size_t kAppBaseLength = 8; // Ssrc and Name. static constexpr size_t kMaxDataSize = 0xffff * 4 - kAppBaseLength; diff --git a/modules/rtp_rtcp/source/rtcp_packet/remote_estimate.cc b/modules/rtp_rtcp/source/rtcp_packet/remote_estimate.cc new file mode 100644 index 0000000000..81d1a1abfb --- /dev/null +++ b/modules/rtp_rtcp/source/rtcp_packet/remote_estimate.cc @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ +#include "modules/rtp_rtcp/source/rtcp_packet/remote_estimate.h" + +#include +#include +#include +#include + +#include "modules/rtp_rtcp/source/byte_io.h" +#include "modules/rtp_rtcp/source/rtcp_packet/common_header.h" +#include "rtc_base/logging.h" + +namespace webrtc { +namespace rtcp { +namespace { + +static constexpr int kFieldValueSize = 3; +static constexpr int kFieldSize = 1 + kFieldValueSize; +static constexpr DataRate kDataRateResolution = DataRate::KilobitsPerSec<1>(); +constexpr int64_t kMaxEncoded = (1 << (kFieldValueSize * 8)) - 1; + +class DataRateSerializer { + public: + DataRateSerializer( + uint8_t id, + std::function field_getter) + : id_(id), field_getter_(field_getter) {} + + uint8_t id() const { return id_; } + + void Read(const uint8_t* src, NetworkStateEstimate* target) const { + int64_t scaled = ByteReader::ReadBigEndian(src); + if (scaled == kMaxEncoded) { + *field_getter_(target) = DataRate::PlusInfinity(); + } else { + *field_getter_(target) = kDataRateResolution * scaled; + } + } + + bool Write(const NetworkStateEstimate& src, uint8_t* target) const { + auto value = *field_getter_(const_cast(&src)); + if (value.IsMinusInfinity()) { + RTC_LOG(LS_WARNING) << "Trying to serialize MinusInfinity"; + return false; + } + ByteWriter::WriteBigEndian(target++, id_); + int64_t scaled; + if (value.IsPlusInfinity()) { + scaled = kMaxEncoded; + } else { + scaled = value / kDataRateResolution; + if (scaled >= kMaxEncoded) { + scaled = kMaxEncoded; + RTC_LOG(LS_WARNING) << ToString(value) << " is larger than max (" + << ToString(kMaxEncoded * kDataRateResolution) + << "), encoded as PlusInfinity."; + } + } + ByteWriter::WriteBigEndian(target, scaled); + return true; + } + + private: + const uint8_t id_; + const std::function field_getter_; +}; + +class RemoteEstimateSerializerImpl : public RemoteEstimateSerializer { + public: + explicit RemoteEstimateSerializerImpl(std::vector fields) + : fields_(fields) {} + + rtc::Buffer Serialize(const NetworkStateEstimate& src) const override { + size_t max_size = fields_.size() * kFieldSize; + size_t size = 0; + rtc::Buffer buf(max_size); + for (const auto& field : fields_) { + if (field.Write(src, buf.data() + size)) { + size += kFieldSize; + } + } + buf.SetSize(size); + return buf; + } + + bool Parse(rtc::ArrayView src, + NetworkStateEstimate* target) const override { + if (src.size() % kFieldSize != 0) + return false; + RTC_DCHECK_EQ(src.size() % kFieldSize, 0); + for (const uint8_t* data_ptr = src.data(); data_ptr < src.end(); + data_ptr += kFieldSize) { + uint8_t field_id = ByteReader::ReadBigEndian(data_ptr); + for (const auto& field : fields_) { + if (field.id() == field_id) { + field.Read(data_ptr + 1, target); + break; + } + } + } + return true; + } + + private: + const std::vector fields_; +}; + +} // namespace + +const RemoteEstimateSerializer* GetRemoteEstimateSerializer() { + using E = NetworkStateEstimate; + static auto* serializer = new RemoteEstimateSerializerImpl({ + {1, [](E* e) { return &e->link_capacity_lower; }}, + {2, [](E* e) { return &e->link_capacity_upper; }}, + }); + return serializer; +} + +RemoteEstimate::RemoteEstimate() : serializer_(GetRemoteEstimateSerializer()) { + SetSubType(kSubType); + SetName(kName); + SetSsrc(0); +} + +bool RemoteEstimate::IsNetworkEstimate(const CommonHeader& packet) { + if (packet.fmt() != kSubType) + return false; + size_t kNameSize = sizeof(uint32_t); + if (packet.packet_size() < CommonHeader::kHeaderSizeBytes + kNameSize) + return false; + if (ByteReader::ReadBigEndian(&packet.payload()[4]) != kName) + return false; + return true; +} + +bool RemoteEstimate::Parse(const CommonHeader& packet) { + if (!App::Parse(packet)) + return false; + return serializer_->Parse({data(), data_size()}, &estimate_); +} + +void RemoteEstimate::SetEstimate(NetworkStateEstimate estimate) { + estimate_ = estimate; + auto buf = serializer_->Serialize(estimate); + SetData(buf.data(), buf.size()); +} + +} // namespace rtcp +} // namespace webrtc diff --git a/modules/rtp_rtcp/source/rtcp_packet/remote_estimate.h b/modules/rtp_rtcp/source/rtcp_packet/remote_estimate.h new file mode 100644 index 0000000000..a63b62475f --- /dev/null +++ b/modules/rtp_rtcp/source/rtcp_packet/remote_estimate.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ +#ifndef MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_REMOTE_ESTIMATE_H_ +#define MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_REMOTE_ESTIMATE_H_ + +#include +#include + +#include "api/transport/network_types.h" +#include "modules/rtp_rtcp/source/rtcp_packet/app.h" + +namespace webrtc { +namespace rtcp { + +class CommonHeader; +class RemoteEstimateSerializer { + public: + virtual bool Parse(rtc::ArrayView src, + NetworkStateEstimate* target) const = 0; + virtual rtc::Buffer Serialize(const NetworkStateEstimate& src) const = 0; + virtual ~RemoteEstimateSerializer() = default; +}; + +// Using a static global implementation to avoid incurring initialization +// overhead of the serializer every time RemoteEstimate is created. +const RemoteEstimateSerializer* GetRemoteEstimateSerializer(); + +class RemoteEstimate : public App { + public: + RemoteEstimate(); + // Note, sub type must be unique among all app messages with "goog" name. + static constexpr uint8_t kSubType = 13; + static constexpr uint32_t kName = NameToInt("goog"); + static TimeDelta GetTimestampPeriod(); + + static bool IsNetworkEstimate(const CommonHeader& packet); + bool Parse(const CommonHeader& packet); + void SetEstimate(NetworkStateEstimate estimate); + NetworkStateEstimate estimate() const { return estimate_; } + + private: + NetworkStateEstimate estimate_; + const RemoteEstimateSerializer* const serializer_; +}; + +} // namespace rtcp +} // namespace webrtc + +#endif // MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_REMOTE_ESTIMATE_H_ diff --git a/modules/rtp_rtcp/source/rtcp_packet/remote_estimate_unittest.cc b/modules/rtp_rtcp/source/rtcp_packet/remote_estimate_unittest.cc new file mode 100644 index 0000000000..bbeb227714 --- /dev/null +++ b/modules/rtp_rtcp/source/rtcp_packet/remote_estimate_unittest.cc @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ +#include "modules/rtp_rtcp/source/rtcp_packet/remote_estimate.h" + +#include "test/gtest.h" + +namespace webrtc { +namespace rtcp { +TEST(RemoteEstimateTest, EncodesCapacityBounds) { + NetworkStateEstimate src; + src.link_capacity_lower = DataRate::kbps(10); + src.link_capacity_upper = DataRate::kbps(1000000); + rtc::Buffer data = GetRemoteEstimateSerializer()->Serialize(src); + NetworkStateEstimate dst; + EXPECT_TRUE(GetRemoteEstimateSerializer()->Parse(data, &dst)); + EXPECT_EQ(src.link_capacity_lower, dst.link_capacity_lower); + EXPECT_EQ(src.link_capacity_upper, dst.link_capacity_upper); +} + +TEST(RemoteEstimateTest, ExpandsToPlusInfinity) { + NetworkStateEstimate src; + // White box testing: We know that the value is stored in an unsigned 24 int + // with kbps resolution. We expected it be represented as plus infinity. + src.link_capacity_lower = DataRate::kbps(2 << 24); + src.link_capacity_upper = DataRate::PlusInfinity(); + rtc::Buffer data = GetRemoteEstimateSerializer()->Serialize(src); + + NetworkStateEstimate dst; + EXPECT_TRUE(GetRemoteEstimateSerializer()->Parse(data, &dst)); + EXPECT_TRUE(dst.link_capacity_lower.IsPlusInfinity()); + EXPECT_TRUE(dst.link_capacity_upper.IsPlusInfinity()); +} + +TEST(RemoteEstimateTest, DoesNotEncodeNegative) { + NetworkStateEstimate src; + src.link_capacity_lower = DataRate::MinusInfinity(); + src.link_capacity_upper = DataRate::MinusInfinity(); + rtc::Buffer data = GetRemoteEstimateSerializer()->Serialize(src); + // Since MinusInfinity can't be represented, the buffer should be empty. + EXPECT_EQ(data.size(), 0u); + NetworkStateEstimate dst; + dst.link_capacity_lower = DataRate::kbps(300); + EXPECT_TRUE(GetRemoteEstimateSerializer()->Parse(data, &dst)); + // The fields will be left unchanged by the parser as they were not encoded. + EXPECT_EQ(dst.link_capacity_lower, DataRate::kbps(300)); + EXPECT_TRUE(dst.link_capacity_upper.IsMinusInfinity()); +} +} // namespace rtcp +} // namespace webrtc diff --git a/modules/rtp_rtcp/source/rtcp_receiver.cc b/modules/rtp_rtcp/source/rtcp_receiver.cc index 99b55efb49..c73c7adf3b 100644 --- a/modules/rtp_rtcp/source/rtcp_receiver.cc +++ b/modules/rtp_rtcp/source/rtcp_receiver.cc @@ -32,6 +32,7 @@ #include "modules/rtp_rtcp/source/rtcp_packet/rapid_resync_request.h" #include "modules/rtp_rtcp/source/rtcp_packet/receiver_report.h" #include "modules/rtp_rtcp/source/rtcp_packet/remb.h" +#include "modules/rtp_rtcp/source/rtcp_packet/remote_estimate.h" #include "modules/rtp_rtcp/source/rtcp_packet/sdes.h" #include "modules/rtp_rtcp/source/rtcp_packet/sender_report.h" #include "modules/rtp_rtcp/source/rtcp_packet/tmmbn.h" @@ -79,6 +80,7 @@ struct RTCPReceiver::PacketInformation { uint32_t receiver_estimated_max_bitrate_bps = 0; std::unique_ptr transport_feedback; absl::optional target_bitrate_allocation; + absl::optional network_state_estimate; std::unique_ptr loss_notification; }; @@ -128,6 +130,7 @@ RTCPReceiver::RTCPReceiver(const RtpRtcp::Configuration& config, rtcp_bandwidth_observer_(config.bandwidth_callback), rtcp_intra_frame_observer_(config.intra_frame_callback), rtcp_loss_notification_observer_(config.rtcp_loss_notification_observer), + network_state_estimate_observer_(config.network_state_estimate_observer), transport_feedback_observer_(config.transport_feedback_callback), bitrate_allocation_observer_(config.bitrate_allocation_observer), report_interval_ms_(config.rtcp_report_interval_ms > 0 @@ -360,6 +363,9 @@ bool RTCPReceiver::ParseCompoundPacket(const uint8_t* packet_begin, case rtcp::Bye::kPacketType: HandleBye(rtcp_block); break; + case rtcp::App::kPacketType: + HandleApp(rtcp_block, packet_information); + break; case rtcp::Rtpfb::kPacketType: switch (rtcp_block.fmt()) { case rtcp::Nack::kFeedbackMessageType: @@ -690,6 +696,18 @@ void RTCPReceiver::HandleNack(const CommonHeader& rtcp_block, } } +void RTCPReceiver::HandleApp(const rtcp::CommonHeader& rtcp_block, + PacketInformation* packet_information) { + if (rtcp::RemoteEstimate::IsNetworkEstimate(rtcp_block)) { + rtcp::RemoteEstimate estimate; + if (estimate.Parse(rtcp_block)) { + packet_information->network_state_estimate = estimate.estimate(); + return; + } + } + ++num_skipped_packets_; +} + void RTCPReceiver::HandleBye(const CommonHeader& rtcp_block) { rtcp::Bye bye; if (!bye.Parse(rtcp_block)) { @@ -1074,6 +1092,12 @@ void RTCPReceiver::TriggerCallbacksFromRtcpPacket( } } + if (network_state_estimate_observer_ && + packet_information.network_state_estimate) { + network_state_estimate_observer_->OnRemoteNetworkEstimate( + *packet_information.network_state_estimate); + } + if (bitrate_allocation_observer_ && packet_information.target_bitrate_allocation) { bitrate_allocation_observer_->OnBitrateAllocationUpdated( diff --git a/modules/rtp_rtcp/source/rtcp_receiver.h b/modules/rtp_rtcp/source/rtcp_receiver.h index f49b7480c5..7d684cb778 100644 --- a/modules/rtp_rtcp/source/rtcp_receiver.h +++ b/modules/rtp_rtcp/source/rtcp_receiver.h @@ -176,6 +176,10 @@ class RTCPReceiver { PacketInformation* packet_information) RTC_EXCLUSIVE_LOCKS_REQUIRED(rtcp_receiver_lock_); + void HandleApp(const rtcp::CommonHeader& rtcp_block, + PacketInformation* packet_information) + RTC_EXCLUSIVE_LOCKS_REQUIRED(rtcp_receiver_lock_); + void HandleBye(const rtcp::CommonHeader& rtcp_block) RTC_EXCLUSIVE_LOCKS_REQUIRED(rtcp_receiver_lock_); @@ -215,6 +219,7 @@ class RTCPReceiver { RtcpBandwidthObserver* const rtcp_bandwidth_observer_; RtcpIntraFrameObserver* const rtcp_intra_frame_observer_; RtcpLossNotificationObserver* const rtcp_loss_notification_observer_; + NetworkStateEstimateObserver* const network_state_estimate_observer_; TransportFeedbackObserver* const transport_feedback_observer_; VideoBitrateAllocationObserver* const bitrate_allocation_observer_; const int report_interval_ms_; diff --git a/modules/rtp_rtcp/source/rtcp_sender.cc b/modules/rtp_rtcp/source/rtcp_sender.cc index 8c5f8216b7..ffa5e9027a 100644 --- a/modules/rtp_rtcp/source/rtcp_sender.cc +++ b/modules/rtp_rtcp/source/rtcp_sender.cc @@ -997,4 +997,22 @@ bool RTCPSender::SendFeedbackPacket(const rtcp::TransportFeedback& packet) { return packet.Build(max_packet_size, callback) && !send_failure; } +bool RTCPSender::SendNetworkStateEstimatePacket( + const rtcp::RemoteEstimate& packet) { + size_t max_packet_size; + { + rtc::CritScope lock(&critical_section_rtcp_sender_); + if (method_ == RtcpMode::kOff) + return false; + max_packet_size = max_packet_size_; + } + + RTC_DCHECK_LE(max_packet_size, IP_PACKET_SIZE); + bool send_success = false; + auto callback = [&](rtc::ArrayView packet) { + send_success = transport_->SendRtcp(packet.data(), packet.size()); + }; + return packet.Build(max_packet_size, callback) && send_success; +} + } // namespace webrtc diff --git a/modules/rtp_rtcp/source/rtcp_sender.h b/modules/rtp_rtcp/source/rtcp_sender.h index 628121ea4e..33db97ad94 100644 --- a/modules/rtp_rtcp/source/rtcp_sender.h +++ b/modules/rtp_rtcp/source/rtcp_sender.h @@ -141,6 +141,7 @@ class RTCPSender { void SetTargetBitrate(unsigned int target_bitrate); void SetVideoBitrateAllocation(const VideoBitrateAllocation& bitrate); bool SendFeedbackPacket(const rtcp::TransportFeedback& packet); + bool SendNetworkStateEstimatePacket(const rtcp::RemoteEstimate& packet); private: class RtcpContext; diff --git a/modules/rtp_rtcp/source/rtcp_transceiver.cc b/modules/rtp_rtcp/source/rtcp_transceiver.cc index a378b3669d..9fb20d6c00 100644 --- a/modules/rtp_rtcp/source/rtcp_transceiver.cc +++ b/modules/rtp_rtcp/source/rtcp_transceiver.cc @@ -129,6 +129,18 @@ bool RtcpTransceiver::SendFeedbackPacket( return true; } +bool RtcpTransceiver::SendNetworkStateEstimatePacket( + const rtcp::RemoteEstimate& packet) { + RTC_CHECK(rtcp_transceiver_); + struct Closure { + void operator()() { ptr->SendRawPacket(raw_packet); } + RtcpTransceiverImpl* ptr; + rtc::Buffer raw_packet; + }; + task_queue_->PostTask(Closure{rtcp_transceiver_.get(), packet.Build()}); + return true; +} + void RtcpTransceiver::SendNack(uint32_t ssrc, std::vector sequence_numbers) { RTC_CHECK(rtcp_transceiver_); diff --git a/modules/rtp_rtcp/source/rtcp_transceiver.h b/modules/rtp_rtcp/source/rtcp_transceiver.h index 16fd5a7fdb..8b70c6d987 100644 --- a/modules/rtp_rtcp/source/rtcp_transceiver.h +++ b/modules/rtp_rtcp/source/rtcp_transceiver.h @@ -79,6 +79,8 @@ class RtcpTransceiver : public RtcpFeedbackSenderInterface { // Returns ssrc to put as sender ssrc into rtcp::TransportFeedback. uint32_t SSRC() const override; bool SendFeedbackPacket(const rtcp::TransportFeedback& packet) override; + bool SendNetworkStateEstimatePacket( + const rtcp::RemoteEstimate& packet) override; // Reports missing packets, https://tools.ietf.org/html/rfc4585#section-6.2.1 void SendNack(uint32_t ssrc, std::vector sequence_numbers); diff --git a/modules/rtp_rtcp/source/rtp_rtcp_impl.cc b/modules/rtp_rtcp/source/rtp_rtcp_impl.cc index 1fdb35650d..9252de385c 100644 --- a/modules/rtp_rtcp/source/rtp_rtcp_impl.cc +++ b/modules/rtp_rtcp/source/rtp_rtcp_impl.cc @@ -676,6 +676,11 @@ bool ModuleRtpRtcpImpl::SendFeedbackPacket( return rtcp_sender_.SendFeedbackPacket(packet); } +bool ModuleRtpRtcpImpl::SendNetworkStateEstimatePacket( + const rtcp::RemoteEstimate& packet) { + return rtcp_sender_.SendNetworkStateEstimatePacket(packet); +} + int32_t ModuleRtpRtcpImpl::SendLossNotification(uint16_t last_decoded_seq_num, uint16_t last_received_seq_num, bool decodability_flag, diff --git a/modules/rtp_rtcp/source/rtp_rtcp_impl.h b/modules/rtp_rtcp/source/rtp_rtcp_impl.h index 8cb01be914..1c8ef9c2ec 100644 --- a/modules/rtp_rtcp/source/rtp_rtcp_impl.h +++ b/modules/rtp_rtcp/source/rtp_rtcp_impl.h @@ -245,6 +245,8 @@ class ModuleRtpRtcpImpl : public RtpRtcp, public RTCPReceiver::ModuleRtpRtcp { void SetReportBlockDataObserver(ReportBlockDataObserver* observer) override; bool SendFeedbackPacket(const rtcp::TransportFeedback& packet) override; + bool SendNetworkStateEstimatePacket( + const rtcp::RemoteEstimate& packet) override; // (APP) Application specific data. int32_t SetRTCPApplicationSpecificData(uint8_t sub_type, uint32_t name, diff --git a/pc/channel.cc b/pc/channel.cc index 54839631cc..caf8c93956 100644 --- a/pc/channel.cc +++ b/pc/channel.cc @@ -111,6 +111,7 @@ void RtpParametersFromMediaDescription( params->extensions = extensions; } params->rtcp.reduced_size = desc->rtcp_reduced_size(); + params->rtcp.remote_estimate = desc->remote_estimate(); } template diff --git a/pc/media_session.cc b/pc/media_session.cc index fff2a40092..f4f1554a62 100644 --- a/pc/media_session.cc +++ b/pc/media_session.cc @@ -1159,6 +1159,8 @@ static bool CreateMediaContentAnswer( answer->set_rtcp_reduced_size(offer->rtcp_reduced_size()); } + answer->set_remote_estimate(offer->remote_estimate()); + if (sdes_policy != SEC_DISABLED) { CryptoParams crypto; if (SelectCrypto(offer, bundle_enabled, session_options.crypto_options, diff --git a/pc/session_description.h b/pc/session_description.h index bc847401a8..229d331eb3 100644 --- a/pc/session_description.h +++ b/pc/session_description.h @@ -113,6 +113,11 @@ class MediaContentDescription { rtcp_reduced_size_ = reduced_size; } + virtual bool remote_estimate() const { return remote_estimate_; } + virtual void set_remote_estimate(bool remote_estimate) { + remote_estimate_ = remote_estimate; + } + virtual int bandwidth() const { return bandwidth_; } virtual void set_bandwidth(int bandwidth) { bandwidth_ = bandwidth; } @@ -245,6 +250,7 @@ class MediaContentDescription { protected: bool rtcp_mux_ = false; bool rtcp_reduced_size_ = false; + bool remote_estimate_ = false; int bandwidth_ = kAutoBandwidth; std::string protocol_; std::vector cryptos_; diff --git a/pc/webrtc_sdp.cc b/pc/webrtc_sdp.cc index a022e5642d..3e0cf42d17 100644 --- a/pc/webrtc_sdp.cc +++ b/pc/webrtc_sdp.cc @@ -185,6 +185,8 @@ static const char kAttributePacketization[] = "packetization"; static const char kAttributeXGoogleFlag[] = "x-google-flag"; static const char kValueConference[] = "conference"; +static const char kAttributeRtcpRemoteEstimate[] = "remote-net-estimate"; + // Candidate static const char kCandidateHost[] = "host"; static const char kCandidateSrflx[] = "srflx"; @@ -1666,6 +1668,11 @@ void BuildRtpContentAttributes(const MediaContentDescription* media_desc, AddLine(os.str(), message); } + if (media_desc->remote_estimate()) { + InitAttrLine(kAttributeRtcpRemoteEstimate, &os); + AddLine(os.str(), message); + } + // RFC 4568 // a=crypto: [] for (const CryptoParams& crypto_params : media_desc->cryptos()) { @@ -3238,6 +3245,8 @@ bool ParseContent(const std::string& message, media_desc->set_rtcp_mux(true); } else if (HasAttribute(line, kAttributeRtcpReducedSize)) { media_desc->set_rtcp_reduced_size(true); + } else if (HasAttribute(line, kAttributeRtcpRemoteEstimate)) { + media_desc->set_remote_estimate(true); } else if (HasAttribute(line, kAttributeSsrcGroup)) { if (!ParseSsrcGroupAttribute(line, &ssrc_groups, error)) { return false;