Adds remote estimate RTCP packet.
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 <stefan@webrtc.org> Reviewed-by: Erik Språng <sprang@webrtc.org> Commit-Queue: Sebastian Jansson <srte@webrtc.org> Cr-Commit-Position: refs/heads/master@{#28654}
This commit is contained in:
committed by
Commit Bot
parent
1796a820f6
commit
e1795f4158
@ -157,6 +157,11 @@ PacketRouter* RtpTransportControllerSend::packet_router() {
|
|||||||
return &packet_router_;
|
return &packet_router_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NetworkStateEstimateObserver*
|
||||||
|
RtpTransportControllerSend::network_state_estimate_observer() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
TransportFeedbackObserver*
|
TransportFeedbackObserver*
|
||||||
RtpTransportControllerSend::transport_feedback_observer() {
|
RtpTransportControllerSend::transport_feedback_observer() {
|
||||||
return this;
|
return this;
|
||||||
@ -451,6 +456,16 @@ void RtpTransportControllerSend::OnTransportFeedback(
|
|||||||
transport_feedback_adapter_.GetOutstandingData().bytes());
|
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() {
|
void RtpTransportControllerSend::MaybeCreateControllers() {
|
||||||
RTC_DCHECK(!controller_);
|
RTC_DCHECK(!controller_);
|
||||||
RTC_DCHECK(!control_handler_);
|
RTC_DCHECK(!control_handler_);
|
||||||
|
|||||||
@ -43,7 +43,8 @@ class RtcEventLog;
|
|||||||
class RtpTransportControllerSend final
|
class RtpTransportControllerSend final
|
||||||
: public RtpTransportControllerSendInterface,
|
: public RtpTransportControllerSendInterface,
|
||||||
public RtcpBandwidthObserver,
|
public RtcpBandwidthObserver,
|
||||||
public TransportFeedbackObserver {
|
public TransportFeedbackObserver,
|
||||||
|
public NetworkStateEstimateObserver {
|
||||||
public:
|
public:
|
||||||
RtpTransportControllerSend(
|
RtpTransportControllerSend(
|
||||||
Clock* clock,
|
Clock* clock,
|
||||||
@ -73,6 +74,7 @@ class RtpTransportControllerSend final
|
|||||||
rtc::TaskQueue* GetWorkerQueue() override;
|
rtc::TaskQueue* GetWorkerQueue() override;
|
||||||
PacketRouter* packet_router() override;
|
PacketRouter* packet_router() override;
|
||||||
|
|
||||||
|
NetworkStateEstimateObserver* network_state_estimate_observer() override;
|
||||||
TransportFeedbackObserver* transport_feedback_observer() override;
|
TransportFeedbackObserver* transport_feedback_observer() override;
|
||||||
RtpPacketPacer* packet_sender() override;
|
RtpPacketPacer* packet_sender() override;
|
||||||
|
|
||||||
@ -114,6 +116,9 @@ class RtpTransportControllerSend final
|
|||||||
void OnAddPacket(const RtpPacketSendInfo& packet_info) override;
|
void OnAddPacket(const RtpPacketSendInfo& packet_info) override;
|
||||||
void OnTransportFeedback(const rtcp::TransportFeedback& feedback) override;
|
void OnTransportFeedback(const rtcp::TransportFeedback& feedback) override;
|
||||||
|
|
||||||
|
// Implements NetworkStateEstimateObserver interface
|
||||||
|
void OnRemoteNetworkEstimate(NetworkStateEstimate estimate) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void MaybeCreateControllers() RTC_RUN_ON(task_queue_);
|
void MaybeCreateControllers() RTC_RUN_ON(task_queue_);
|
||||||
void UpdateInitialConstraints(TargetRateConstraints new_contraints)
|
void UpdateInitialConstraints(TargetRateConstraints new_contraints)
|
||||||
|
|||||||
@ -116,6 +116,7 @@ class RtpTransportControllerSendInterface {
|
|||||||
virtual void DestroyRtpVideoSender(
|
virtual void DestroyRtpVideoSender(
|
||||||
RtpVideoSenderInterface* rtp_video_sender) = 0;
|
RtpVideoSenderInterface* rtp_video_sender) = 0;
|
||||||
|
|
||||||
|
virtual NetworkStateEstimateObserver* network_state_estimate_observer() = 0;
|
||||||
virtual TransportFeedbackObserver* transport_feedback_observer() = 0;
|
virtual TransportFeedbackObserver* transport_feedback_observer() = 0;
|
||||||
|
|
||||||
virtual RtpPacketPacer* packet_sender() = 0;
|
virtual RtpPacketPacer* packet_sender() = 0;
|
||||||
|
|||||||
@ -86,6 +86,8 @@ std::vector<RtpStreamSender> CreateRtpStreamSenders(
|
|||||||
configuration.rtcp_loss_notification_observer =
|
configuration.rtcp_loss_notification_observer =
|
||||||
rtcp_loss_notification_observer;
|
rtcp_loss_notification_observer;
|
||||||
configuration.bandwidth_callback = bandwidth_callback;
|
configuration.bandwidth_callback = bandwidth_callback;
|
||||||
|
configuration.network_state_estimate_observer =
|
||||||
|
transport->network_state_estimate_observer();
|
||||||
configuration.transport_feedback_callback =
|
configuration.transport_feedback_callback =
|
||||||
transport->transport_feedback_observer();
|
transport->transport_feedback_observer();
|
||||||
configuration.rtt_stats = rtt_stats;
|
configuration.rtt_stats = rtt_stats;
|
||||||
|
|||||||
@ -45,6 +45,8 @@ class MockRtpTransportControllerSend
|
|||||||
MOCK_METHOD1(DestroyRtpVideoSender, void(RtpVideoSenderInterface*));
|
MOCK_METHOD1(DestroyRtpVideoSender, void(RtpVideoSenderInterface*));
|
||||||
MOCK_METHOD0(GetWorkerQueue, rtc::TaskQueue*());
|
MOCK_METHOD0(GetWorkerQueue, rtc::TaskQueue*());
|
||||||
MOCK_METHOD0(packet_router, PacketRouter*());
|
MOCK_METHOD0(packet_router, PacketRouter*());
|
||||||
|
MOCK_METHOD0(network_state_estimate_observer,
|
||||||
|
NetworkStateEstimateObserver*());
|
||||||
MOCK_METHOD0(transport_feedback_observer, TransportFeedbackObserver*());
|
MOCK_METHOD0(transport_feedback_observer, TransportFeedbackObserver*());
|
||||||
MOCK_METHOD0(packet_sender, RtpPacketPacer*());
|
MOCK_METHOD0(packet_sender, RtpPacketPacer*());
|
||||||
MOCK_METHOD3(SetAllocatedSendBitrateLimits, void(int, int, int));
|
MOCK_METHOD3(SetAllocatedSendBitrateLimits, void(int, int, int));
|
||||||
|
|||||||
@ -719,6 +719,7 @@ struct DataMediaInfo {
|
|||||||
|
|
||||||
struct RtcpParameters {
|
struct RtcpParameters {
|
||||||
bool reduced_size = false;
|
bool reduced_size = false;
|
||||||
|
bool remote_estimate = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class Codec>
|
template <class Codec>
|
||||||
|
|||||||
@ -34,6 +34,7 @@ rtc_source_set("rtp_rtcp_format") {
|
|||||||
"source/rtcp_packet/rapid_resync_request.h",
|
"source/rtcp_packet/rapid_resync_request.h",
|
||||||
"source/rtcp_packet/receiver_report.h",
|
"source/rtcp_packet/receiver_report.h",
|
||||||
"source/rtcp_packet/remb.h",
|
"source/rtcp_packet/remb.h",
|
||||||
|
"source/rtcp_packet/remote_estimate.h",
|
||||||
"source/rtcp_packet/report_block.h",
|
"source/rtcp_packet/report_block.h",
|
||||||
"source/rtcp_packet/rrtr.h",
|
"source/rtcp_packet/rrtr.h",
|
||||||
"source/rtcp_packet/rtpfb.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/rapid_resync_request.cc",
|
||||||
"source/rtcp_packet/receiver_report.cc",
|
"source/rtcp_packet/receiver_report.cc",
|
||||||
"source/rtcp_packet/remb.cc",
|
"source/rtcp_packet/remb.cc",
|
||||||
|
"source/rtcp_packet/remote_estimate.cc",
|
||||||
"source/rtcp_packet/report_block.cc",
|
"source/rtcp_packet/report_block.cc",
|
||||||
"source/rtcp_packet/rrtr.cc",
|
"source/rtcp_packet/rrtr.cc",
|
||||||
"source/rtcp_packet/rtpfb.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/rapid_resync_request_unittest.cc",
|
||||||
"source/rtcp_packet/receiver_report_unittest.cc",
|
"source/rtcp_packet/receiver_report_unittest.cc",
|
||||||
"source/rtcp_packet/remb_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/report_block_unittest.cc",
|
||||||
"source/rtcp_packet/rrtr_unittest.cc",
|
"source/rtcp_packet/rrtr_unittest.cc",
|
||||||
"source/rtcp_packet/sdes_unittest.cc",
|
"source/rtcp_packet/sdes_unittest.cc",
|
||||||
|
|||||||
@ -78,6 +78,7 @@ class RtpRtcp : public Module, public RtcpFeedbackSenderInterface {
|
|||||||
// stream.
|
// stream.
|
||||||
RtcpBandwidthObserver* bandwidth_callback = nullptr;
|
RtcpBandwidthObserver* bandwidth_callback = nullptr;
|
||||||
|
|
||||||
|
NetworkStateEstimateObserver* network_state_estimate_observer = nullptr;
|
||||||
TransportFeedbackObserver* transport_feedback_callback = nullptr;
|
TransportFeedbackObserver* transport_feedback_callback = nullptr;
|
||||||
VideoBitrateAllocationObserver* bitrate_allocation_observer = nullptr;
|
VideoBitrateAllocationObserver* bitrate_allocation_observer = nullptr;
|
||||||
RtcpRttStats* rtt_stats = nullptr;
|
RtcpRttStats* rtt_stats = nullptr;
|
||||||
|
|||||||
@ -24,6 +24,7 @@
|
|||||||
#include "api/rtp_headers.h"
|
#include "api/rtp_headers.h"
|
||||||
#include "api/transport/network_types.h"
|
#include "api/transport/network_types.h"
|
||||||
#include "modules/include/module_common_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"
|
#include "system_wrappers/include/clock.h"
|
||||||
|
|
||||||
#define RTCP_CNAME_SIZE 256 // RFC 3550 page 44, including null termination
|
#define RTCP_CNAME_SIZE 256 // RFC 3550 page 44, including null termination
|
||||||
@ -291,6 +292,11 @@ struct RtpPacketSendInfo {
|
|||||||
size_t length = 0;
|
size_t length = 0;
|
||||||
PacedPacketInfo pacing_info;
|
PacedPacketInfo pacing_info;
|
||||||
};
|
};
|
||||||
|
class NetworkStateEstimateObserver {
|
||||||
|
public:
|
||||||
|
virtual void OnRemoteNetworkEstimate(NetworkStateEstimate estimate) = 0;
|
||||||
|
virtual ~NetworkStateEstimateObserver() = default;
|
||||||
|
};
|
||||||
|
|
||||||
class TransportFeedbackObserver {
|
class TransportFeedbackObserver {
|
||||||
public:
|
public:
|
||||||
@ -310,6 +316,8 @@ class RtcpFeedbackSenderInterface {
|
|||||||
virtual ~RtcpFeedbackSenderInterface() = default;
|
virtual ~RtcpFeedbackSenderInterface() = default;
|
||||||
virtual uint32_t SSRC() const = 0;
|
virtual uint32_t SSRC() const = 0;
|
||||||
virtual bool SendFeedbackPacket(const rtcp::TransportFeedback& feedback) = 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<uint32_t> ssrcs) = 0;
|
virtual void SetRemb(int64_t bitrate_bps, std::vector<uint32_t> ssrcs) = 0;
|
||||||
virtual void UnsetRemb() = 0;
|
virtual void UnsetRemb() = 0;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -155,6 +155,8 @@ class MockRtpRtcp : public RtpRtcp {
|
|||||||
MOCK_METHOD0(GetRtcpStatisticsCallback, RtcpStatisticsCallback*());
|
MOCK_METHOD0(GetRtcpStatisticsCallback, RtcpStatisticsCallback*());
|
||||||
MOCK_METHOD1(SetReportBlockDataObserver, void(ReportBlockDataObserver*));
|
MOCK_METHOD1(SetReportBlockDataObserver, void(ReportBlockDataObserver*));
|
||||||
MOCK_METHOD1(SendFeedbackPacket, bool(const rtcp::TransportFeedback& packet));
|
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_METHOD1(SetTargetSendBitrate, void(uint32_t bitrate_bps));
|
||||||
MOCK_METHOD4(SendLossNotification,
|
MOCK_METHOD4(SendLossNotification,
|
||||||
int32_t(uint16_t last_decoded_seq_num,
|
int32_t(uint16_t last_decoded_seq_num,
|
||||||
|
|||||||
@ -48,6 +48,12 @@ class App : public RtcpPacket {
|
|||||||
size_t max_length,
|
size_t max_length,
|
||||||
PacketReadyCallback callback) const override;
|
PacketReadyCallback callback) const override;
|
||||||
|
|
||||||
|
static inline constexpr uint32_t NameToInt(const char name[5]) {
|
||||||
|
return static_cast<uint32_t>(name[0]) << 24 |
|
||||||
|
static_cast<uint32_t>(name[1]) << 16 |
|
||||||
|
static_cast<uint32_t>(name[2]) << 8 | static_cast<uint32_t>(name[3]);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static constexpr size_t kAppBaseLength = 8; // Ssrc and Name.
|
static constexpr size_t kAppBaseLength = 8; // Ssrc and Name.
|
||||||
static constexpr size_t kMaxDataSize = 0xffff * 4 - kAppBaseLength;
|
static constexpr size_t kMaxDataSize = 0xffff * 4 - kAppBaseLength;
|
||||||
|
|||||||
157
modules/rtp_rtcp/source/rtcp_packet/remote_estimate.cc
Normal file
157
modules/rtp_rtcp/source/rtcp_packet/remote_estimate.cc
Normal file
@ -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 <algorithm>
|
||||||
|
#include <cmath>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#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<DataRate*(NetworkStateEstimate*)> 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<uint32_t, kFieldValueSize>::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<NetworkStateEstimate*>(&src));
|
||||||
|
if (value.IsMinusInfinity()) {
|
||||||
|
RTC_LOG(LS_WARNING) << "Trying to serialize MinusInfinity";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ByteWriter<uint8_t>::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<uint32_t, kFieldValueSize>::WriteBigEndian(target, scaled);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const uint8_t id_;
|
||||||
|
const std::function<DataRate*(NetworkStateEstimate*)> field_getter_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class RemoteEstimateSerializerImpl : public RemoteEstimateSerializer {
|
||||||
|
public:
|
||||||
|
explicit RemoteEstimateSerializerImpl(std::vector<DataRateSerializer> 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<const uint8_t> 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<uint8_t>::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<DataRateSerializer> 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<uint32_t>::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
|
||||||
56
modules/rtp_rtcp/source/rtcp_packet/remote_estimate.h
Normal file
56
modules/rtp_rtcp/source/rtcp_packet/remote_estimate.h
Normal file
@ -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 <memory>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#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<const uint8_t> 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_
|
||||||
@ -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
|
||||||
@ -32,6 +32,7 @@
|
|||||||
#include "modules/rtp_rtcp/source/rtcp_packet/rapid_resync_request.h"
|
#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/receiver_report.h"
|
||||||
#include "modules/rtp_rtcp/source/rtcp_packet/remb.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/sdes.h"
|
||||||
#include "modules/rtp_rtcp/source/rtcp_packet/sender_report.h"
|
#include "modules/rtp_rtcp/source/rtcp_packet/sender_report.h"
|
||||||
#include "modules/rtp_rtcp/source/rtcp_packet/tmmbn.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;
|
uint32_t receiver_estimated_max_bitrate_bps = 0;
|
||||||
std::unique_ptr<rtcp::TransportFeedback> transport_feedback;
|
std::unique_ptr<rtcp::TransportFeedback> transport_feedback;
|
||||||
absl::optional<VideoBitrateAllocation> target_bitrate_allocation;
|
absl::optional<VideoBitrateAllocation> target_bitrate_allocation;
|
||||||
|
absl::optional<NetworkStateEstimate> network_state_estimate;
|
||||||
std::unique_ptr<rtcp::LossNotification> loss_notification;
|
std::unique_ptr<rtcp::LossNotification> loss_notification;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -128,6 +130,7 @@ RTCPReceiver::RTCPReceiver(const RtpRtcp::Configuration& config,
|
|||||||
rtcp_bandwidth_observer_(config.bandwidth_callback),
|
rtcp_bandwidth_observer_(config.bandwidth_callback),
|
||||||
rtcp_intra_frame_observer_(config.intra_frame_callback),
|
rtcp_intra_frame_observer_(config.intra_frame_callback),
|
||||||
rtcp_loss_notification_observer_(config.rtcp_loss_notification_observer),
|
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),
|
transport_feedback_observer_(config.transport_feedback_callback),
|
||||||
bitrate_allocation_observer_(config.bitrate_allocation_observer),
|
bitrate_allocation_observer_(config.bitrate_allocation_observer),
|
||||||
report_interval_ms_(config.rtcp_report_interval_ms > 0
|
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:
|
case rtcp::Bye::kPacketType:
|
||||||
HandleBye(rtcp_block);
|
HandleBye(rtcp_block);
|
||||||
break;
|
break;
|
||||||
|
case rtcp::App::kPacketType:
|
||||||
|
HandleApp(rtcp_block, packet_information);
|
||||||
|
break;
|
||||||
case rtcp::Rtpfb::kPacketType:
|
case rtcp::Rtpfb::kPacketType:
|
||||||
switch (rtcp_block.fmt()) {
|
switch (rtcp_block.fmt()) {
|
||||||
case rtcp::Nack::kFeedbackMessageType:
|
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) {
|
void RTCPReceiver::HandleBye(const CommonHeader& rtcp_block) {
|
||||||
rtcp::Bye bye;
|
rtcp::Bye bye;
|
||||||
if (!bye.Parse(rtcp_block)) {
|
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_ &&
|
if (bitrate_allocation_observer_ &&
|
||||||
packet_information.target_bitrate_allocation) {
|
packet_information.target_bitrate_allocation) {
|
||||||
bitrate_allocation_observer_->OnBitrateAllocationUpdated(
|
bitrate_allocation_observer_->OnBitrateAllocationUpdated(
|
||||||
|
|||||||
@ -176,6 +176,10 @@ class RTCPReceiver {
|
|||||||
PacketInformation* packet_information)
|
PacketInformation* packet_information)
|
||||||
RTC_EXCLUSIVE_LOCKS_REQUIRED(rtcp_receiver_lock_);
|
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)
|
void HandleBye(const rtcp::CommonHeader& rtcp_block)
|
||||||
RTC_EXCLUSIVE_LOCKS_REQUIRED(rtcp_receiver_lock_);
|
RTC_EXCLUSIVE_LOCKS_REQUIRED(rtcp_receiver_lock_);
|
||||||
|
|
||||||
@ -215,6 +219,7 @@ class RTCPReceiver {
|
|||||||
RtcpBandwidthObserver* const rtcp_bandwidth_observer_;
|
RtcpBandwidthObserver* const rtcp_bandwidth_observer_;
|
||||||
RtcpIntraFrameObserver* const rtcp_intra_frame_observer_;
|
RtcpIntraFrameObserver* const rtcp_intra_frame_observer_;
|
||||||
RtcpLossNotificationObserver* const rtcp_loss_notification_observer_;
|
RtcpLossNotificationObserver* const rtcp_loss_notification_observer_;
|
||||||
|
NetworkStateEstimateObserver* const network_state_estimate_observer_;
|
||||||
TransportFeedbackObserver* const transport_feedback_observer_;
|
TransportFeedbackObserver* const transport_feedback_observer_;
|
||||||
VideoBitrateAllocationObserver* const bitrate_allocation_observer_;
|
VideoBitrateAllocationObserver* const bitrate_allocation_observer_;
|
||||||
const int report_interval_ms_;
|
const int report_interval_ms_;
|
||||||
|
|||||||
@ -997,4 +997,22 @@ bool RTCPSender::SendFeedbackPacket(const rtcp::TransportFeedback& packet) {
|
|||||||
return packet.Build(max_packet_size, callback) && !send_failure;
|
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<const uint8_t> packet) {
|
||||||
|
send_success = transport_->SendRtcp(packet.data(), packet.size());
|
||||||
|
};
|
||||||
|
return packet.Build(max_packet_size, callback) && send_success;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace webrtc
|
} // namespace webrtc
|
||||||
|
|||||||
@ -141,6 +141,7 @@ class RTCPSender {
|
|||||||
void SetTargetBitrate(unsigned int target_bitrate);
|
void SetTargetBitrate(unsigned int target_bitrate);
|
||||||
void SetVideoBitrateAllocation(const VideoBitrateAllocation& bitrate);
|
void SetVideoBitrateAllocation(const VideoBitrateAllocation& bitrate);
|
||||||
bool SendFeedbackPacket(const rtcp::TransportFeedback& packet);
|
bool SendFeedbackPacket(const rtcp::TransportFeedback& packet);
|
||||||
|
bool SendNetworkStateEstimatePacket(const rtcp::RemoteEstimate& packet);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class RtcpContext;
|
class RtcpContext;
|
||||||
|
|||||||
@ -129,6 +129,18 @@ bool RtcpTransceiver::SendFeedbackPacket(
|
|||||||
return true;
|
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,
|
void RtcpTransceiver::SendNack(uint32_t ssrc,
|
||||||
std::vector<uint16_t> sequence_numbers) {
|
std::vector<uint16_t> sequence_numbers) {
|
||||||
RTC_CHECK(rtcp_transceiver_);
|
RTC_CHECK(rtcp_transceiver_);
|
||||||
|
|||||||
@ -79,6 +79,8 @@ class RtcpTransceiver : public RtcpFeedbackSenderInterface {
|
|||||||
// Returns ssrc to put as sender ssrc into rtcp::TransportFeedback.
|
// Returns ssrc to put as sender ssrc into rtcp::TransportFeedback.
|
||||||
uint32_t SSRC() const override;
|
uint32_t SSRC() const override;
|
||||||
bool SendFeedbackPacket(const rtcp::TransportFeedback& packet) 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
|
// Reports missing packets, https://tools.ietf.org/html/rfc4585#section-6.2.1
|
||||||
void SendNack(uint32_t ssrc, std::vector<uint16_t> sequence_numbers);
|
void SendNack(uint32_t ssrc, std::vector<uint16_t> sequence_numbers);
|
||||||
|
|||||||
@ -676,6 +676,11 @@ bool ModuleRtpRtcpImpl::SendFeedbackPacket(
|
|||||||
return rtcp_sender_.SendFeedbackPacket(packet);
|
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,
|
int32_t ModuleRtpRtcpImpl::SendLossNotification(uint16_t last_decoded_seq_num,
|
||||||
uint16_t last_received_seq_num,
|
uint16_t last_received_seq_num,
|
||||||
bool decodability_flag,
|
bool decodability_flag,
|
||||||
|
|||||||
@ -245,6 +245,8 @@ class ModuleRtpRtcpImpl : public RtpRtcp, public RTCPReceiver::ModuleRtpRtcp {
|
|||||||
void SetReportBlockDataObserver(ReportBlockDataObserver* observer) override;
|
void SetReportBlockDataObserver(ReportBlockDataObserver* observer) override;
|
||||||
|
|
||||||
bool SendFeedbackPacket(const rtcp::TransportFeedback& packet) override;
|
bool SendFeedbackPacket(const rtcp::TransportFeedback& packet) override;
|
||||||
|
bool SendNetworkStateEstimatePacket(
|
||||||
|
const rtcp::RemoteEstimate& packet) override;
|
||||||
// (APP) Application specific data.
|
// (APP) Application specific data.
|
||||||
int32_t SetRTCPApplicationSpecificData(uint8_t sub_type,
|
int32_t SetRTCPApplicationSpecificData(uint8_t sub_type,
|
||||||
uint32_t name,
|
uint32_t name,
|
||||||
|
|||||||
@ -111,6 +111,7 @@ void RtpParametersFromMediaDescription(
|
|||||||
params->extensions = extensions;
|
params->extensions = extensions;
|
||||||
}
|
}
|
||||||
params->rtcp.reduced_size = desc->rtcp_reduced_size();
|
params->rtcp.reduced_size = desc->rtcp_reduced_size();
|
||||||
|
params->rtcp.remote_estimate = desc->remote_estimate();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Codec>
|
template <class Codec>
|
||||||
|
|||||||
@ -1159,6 +1159,8 @@ static bool CreateMediaContentAnswer(
|
|||||||
answer->set_rtcp_reduced_size(offer->rtcp_reduced_size());
|
answer->set_rtcp_reduced_size(offer->rtcp_reduced_size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
answer->set_remote_estimate(offer->remote_estimate());
|
||||||
|
|
||||||
if (sdes_policy != SEC_DISABLED) {
|
if (sdes_policy != SEC_DISABLED) {
|
||||||
CryptoParams crypto;
|
CryptoParams crypto;
|
||||||
if (SelectCrypto(offer, bundle_enabled, session_options.crypto_options,
|
if (SelectCrypto(offer, bundle_enabled, session_options.crypto_options,
|
||||||
|
|||||||
@ -113,6 +113,11 @@ class MediaContentDescription {
|
|||||||
rtcp_reduced_size_ = reduced_size;
|
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 int bandwidth() const { return bandwidth_; }
|
||||||
virtual void set_bandwidth(int bandwidth) { bandwidth_ = bandwidth; }
|
virtual void set_bandwidth(int bandwidth) { bandwidth_ = bandwidth; }
|
||||||
|
|
||||||
@ -245,6 +250,7 @@ class MediaContentDescription {
|
|||||||
protected:
|
protected:
|
||||||
bool rtcp_mux_ = false;
|
bool rtcp_mux_ = false;
|
||||||
bool rtcp_reduced_size_ = false;
|
bool rtcp_reduced_size_ = false;
|
||||||
|
bool remote_estimate_ = false;
|
||||||
int bandwidth_ = kAutoBandwidth;
|
int bandwidth_ = kAutoBandwidth;
|
||||||
std::string protocol_;
|
std::string protocol_;
|
||||||
std::vector<CryptoParams> cryptos_;
|
std::vector<CryptoParams> cryptos_;
|
||||||
|
|||||||
@ -185,6 +185,8 @@ static const char kAttributePacketization[] = "packetization";
|
|||||||
static const char kAttributeXGoogleFlag[] = "x-google-flag";
|
static const char kAttributeXGoogleFlag[] = "x-google-flag";
|
||||||
static const char kValueConference[] = "conference";
|
static const char kValueConference[] = "conference";
|
||||||
|
|
||||||
|
static const char kAttributeRtcpRemoteEstimate[] = "remote-net-estimate";
|
||||||
|
|
||||||
// Candidate
|
// Candidate
|
||||||
static const char kCandidateHost[] = "host";
|
static const char kCandidateHost[] = "host";
|
||||||
static const char kCandidateSrflx[] = "srflx";
|
static const char kCandidateSrflx[] = "srflx";
|
||||||
@ -1666,6 +1668,11 @@ void BuildRtpContentAttributes(const MediaContentDescription* media_desc,
|
|||||||
AddLine(os.str(), message);
|
AddLine(os.str(), message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (media_desc->remote_estimate()) {
|
||||||
|
InitAttrLine(kAttributeRtcpRemoteEstimate, &os);
|
||||||
|
AddLine(os.str(), message);
|
||||||
|
}
|
||||||
|
|
||||||
// RFC 4568
|
// RFC 4568
|
||||||
// a=crypto:<tag> <crypto-suite> <key-params> [<session-params>]
|
// a=crypto:<tag> <crypto-suite> <key-params> [<session-params>]
|
||||||
for (const CryptoParams& crypto_params : media_desc->cryptos()) {
|
for (const CryptoParams& crypto_params : media_desc->cryptos()) {
|
||||||
@ -3238,6 +3245,8 @@ bool ParseContent(const std::string& message,
|
|||||||
media_desc->set_rtcp_mux(true);
|
media_desc->set_rtcp_mux(true);
|
||||||
} else if (HasAttribute(line, kAttributeRtcpReducedSize)) {
|
} else if (HasAttribute(line, kAttributeRtcpReducedSize)) {
|
||||||
media_desc->set_rtcp_reduced_size(true);
|
media_desc->set_rtcp_reduced_size(true);
|
||||||
|
} else if (HasAttribute(line, kAttributeRtcpRemoteEstimate)) {
|
||||||
|
media_desc->set_remote_estimate(true);
|
||||||
} else if (HasAttribute(line, kAttributeSsrcGroup)) {
|
} else if (HasAttribute(line, kAttributeSsrcGroup)) {
|
||||||
if (!ParseSsrcGroupAttribute(line, &ssrc_groups, error)) {
|
if (!ParseSsrcGroupAttribute(line, &ssrc_groups, error)) {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
Reference in New Issue
Block a user