Add overhead per packet observer to the rtp_sender.

BUG=webrtc:6638

Review-Url: https://codereview.webrtc.org/2495553002
Cr-Commit-Position: refs/heads/master@{#15124}
This commit is contained in:
michaelt
2016-11-17 01:38:43 -08:00
committed by Commit bot
parent 4a4b3cfc01
commit 4da304407c
6 changed files with 158 additions and 44 deletions

View File

@ -299,6 +299,14 @@ class SendPacketObserver {
uint32_t ssrc) = 0; uint32_t ssrc) = 0;
}; };
// Callback, used to notify an observer when the overhead per packet
// has changed.
class OverheadObserver {
public:
virtual ~OverheadObserver() = default;
virtual void OnOverheadChanged(size_t overhead_bytes_per_packet) = 0;
};
// ================================================================== // ==================================================================
// Voice specific types // Voice specific types
// ================================================================== // ==================================================================

View File

@ -27,6 +27,7 @@
namespace webrtc { namespace webrtc {
// Forward declarations. // Forward declarations.
class OverheadObserver;
class RateLimiter; class RateLimiter;
class ReceiveStatistics; class ReceiveStatistics;
class RemoteBitrateEstimator; class RemoteBitrateEstimator;
@ -89,6 +90,7 @@ class RtpRtcp : public Module {
RtcEventLog* event_log = nullptr; RtcEventLog* event_log = nullptr;
SendPacketObserver* send_packet_observer = nullptr; SendPacketObserver* send_packet_observer = nullptr;
RateLimiter* retransmission_rate_limiter = nullptr; RateLimiter* retransmission_rate_limiter = nullptr;
OverheadObserver* overhead_observer = nullptr;
private: private:
RTC_DISALLOW_COPY_AND_ASSIGN(Configuration); RTC_DISALLOW_COPY_AND_ASSIGN(Configuration);

View File

@ -82,7 +82,8 @@ ModuleRtpRtcpImpl::ModuleRtpRtcpImpl(const Configuration& configuration)
configuration.send_side_delay_observer, configuration.send_side_delay_observer,
configuration.event_log, configuration.event_log,
configuration.send_packet_observer, configuration.send_packet_observer,
configuration.retransmission_rate_limiter), configuration.retransmission_rate_limiter,
configuration.overhead_observer),
rtcp_sender_(configuration.audio, rtcp_sender_(configuration.audio,
configuration.clock, configuration.clock,
configuration.receive_statistics, configuration.receive_statistics,
@ -460,6 +461,7 @@ void ModuleRtpRtcpImpl::SetTransportOverhead(
RTC_DCHECK_LT(transport_overhead_per_packet, mtu); RTC_DCHECK_LT(transport_overhead_per_packet, mtu);
size_t max_payload_length = mtu - transport_overhead_per_packet; size_t max_payload_length = mtu - transport_overhead_per_packet;
packet_overhead_ = transport_overhead_per_packet; packet_overhead_ = transport_overhead_per_packet;
rtp_sender_.SetTransportOverhead(packet_overhead_);
rtcp_sender_.SetMaxPayloadLength(max_payload_length); rtcp_sender_.SetMaxPayloadLength(max_payload_length);
rtp_sender_.SetMaxPayloadLength(max_payload_length); rtp_sender_.SetMaxPayloadLength(max_payload_length);
} }

View File

@ -77,7 +77,8 @@ RTPSender::RTPSender(
SendSideDelayObserver* send_side_delay_observer, SendSideDelayObserver* send_side_delay_observer,
RtcEventLog* event_log, RtcEventLog* event_log,
SendPacketObserver* send_packet_observer, SendPacketObserver* send_packet_observer,
RateLimiter* retransmission_rate_limiter) RateLimiter* retransmission_rate_limiter,
OverheadObserver* overhead_observer)
: clock_(clock), : clock_(clock),
// TODO(holmer): Remove this conversion? // TODO(holmer): Remove this conversion?
clock_delta_ms_(clock_->TimeInMilliseconds() - rtc::TimeMillis()), clock_delta_ms_(clock_->TimeInMilliseconds() - rtc::TimeMillis()),
@ -119,7 +120,10 @@ RTPSender::RTPSender(
last_packet_marker_bit_(false), last_packet_marker_bit_(false),
csrcs_(), csrcs_(),
rtx_(kRtxOff), rtx_(kRtxOff),
retransmission_rate_limiter_(retransmission_rate_limiter) { transport_overhead_bytes_per_packet_(0),
rtp_overhead_bytes_per_packet_(0),
retransmission_rate_limiter_(retransmission_rate_limiter),
overhead_observer_(overhead_observer) {
ssrc_ = ssrc_db_->CreateSSRC(); ssrc_ = ssrc_db_->CreateSSRC();
RTC_DCHECK(ssrc_ != 0); RTC_DCHECK(ssrc_ != 0);
ssrc_rtx_ = ssrc_db_->CreateSSRC(); ssrc_rtx_ = ssrc_db_->CreateSSRC();
@ -571,18 +575,15 @@ size_t RTPSender::DeprecatedSendPadData(size_t bytes,
kTimestampTicksPerMs * (now_ms - capture_time_ms)); kTimestampTicksPerMs * (now_ms - capture_time_ms));
} }
padding_packet.SetExtension<AbsoluteSendTime>(now_ms); padding_packet.SetExtension<AbsoluteSendTime>(now_ms);
PacketOptions options; PacketOptions options;
bool has_transport_seq_no = bool has_transport_seq_num =
UpdateTransportSequenceNumber(&padding_packet, &options.packet_id); UpdateTransportSequenceNumber(&padding_packet, &options.packet_id);
padding_packet.SetPadding(padding_bytes_in_packet, &random_); padding_packet.SetPadding(padding_bytes_in_packet, &random_);
if (has_transport_seq_no && transport_feedback_observer_) if (has_transport_seq_num) {
transport_feedback_observer_->AddPacket( AddPacketToTransportFeedback(options.packet_id, padding_packet,
options.packet_id,
padding_packet.payload_size() + padding_packet.padding_size(),
probe_cluster_id); probe_cluster_id);
}
if (!SendPacketToNetwork(padding_packet, options)) if (!SendPacketToNetwork(padding_packet, options))
break; break;
@ -640,6 +641,7 @@ bool RTPSender::SendPacketToNetwork(const RtpPacketToSend& packet,
const PacketOptions& options) { const PacketOptions& options) {
int bytes_sent = -1; int bytes_sent = -1;
if (transport_) { if (transport_) {
UpdateRtpOverhead(packet);
bytes_sent = transport_->SendRtp(packet.data(), packet.size(), options) bytes_sent = transport_->SendRtp(packet.data(), packet.size(), options)
? static_cast<int>(packet.size()) ? static_cast<int>(packet.size())
: -1; : -1;
@ -755,11 +757,8 @@ bool RTPSender::PrepareAndSendPacket(std::unique_ptr<RtpPacketToSend> packet,
packet_to_send->SetExtension<AbsoluteSendTime>(now_ms); packet_to_send->SetExtension<AbsoluteSendTime>(now_ms);
PacketOptions options; PacketOptions options;
if (UpdateTransportSequenceNumber(packet_to_send, &options.packet_id) && if (UpdateTransportSequenceNumber(packet_to_send, &options.packet_id)) {
transport_feedback_observer_) { AddPacketToTransportFeedback(options.packet_id, *packet_to_send,
transport_feedback_observer_->AddPacket(
options.packet_id,
packet_to_send->payload_size() + packet_to_send->padding_size(),
probe_cluster_id); probe_cluster_id);
} }
@ -889,10 +888,8 @@ bool RTPSender::SendToNetwork(std::unique_ptr<RtpPacketToSend> packet,
} }
PacketOptions options; PacketOptions options;
if (UpdateTransportSequenceNumber(packet.get(), &options.packet_id) && if (UpdateTransportSequenceNumber(packet.get(), &options.packet_id)) {
transport_feedback_observer_) { AddPacketToTransportFeedback(options.packet_id, *packet.get(),
transport_feedback_observer_->AddPacket(
options.packet_id, packet->payload_size() + packet->padding_size(),
PacketInfo::kNotAProbe); PacketInfo::kNotAProbe);
} }
@ -1280,4 +1277,47 @@ RtpState RTPSender::GetRtxRtpState() const {
return state; return state;
} }
void RTPSender::SetTransportOverhead(int transport_overhead) {
if (!overhead_observer_)
return;
size_t overhead_bytes_per_packet = 0;
{
rtc::CritScope lock(&send_critsect_);
if (transport_overhead_bytes_per_packet_ ==
static_cast<size_t>(transport_overhead)) {
return;
}
transport_overhead_bytes_per_packet_ = transport_overhead;
overhead_bytes_per_packet =
rtp_overhead_bytes_per_packet_ + transport_overhead_bytes_per_packet_;
}
overhead_observer_->OnOverheadChanged(overhead_bytes_per_packet);
}
void RTPSender::AddPacketToTransportFeedback(uint16_t packet_id,
const RtpPacketToSend& packet,
int probe_cluster_id) {
if (transport_feedback_observer_) {
transport_feedback_observer_->AddPacket(
packet_id, packet.payload_size() + packet.padding_size(),
probe_cluster_id);
}
}
void RTPSender::UpdateRtpOverhead(const RtpPacketToSend& packet) {
if (!overhead_observer_)
return;
size_t overhead_bytes_per_packet = 0;
{
rtc::CritScope lock(&send_critsect_);
if (rtp_overhead_bytes_per_packet_ == packet.headers_size()) {
return;
}
rtp_overhead_bytes_per_packet_ = packet.headers_size();
overhead_bytes_per_packet =
rtp_overhead_bytes_per_packet_ + transport_overhead_bytes_per_packet_;
}
overhead_observer_->OnOverheadChanged(overhead_bytes_per_packet);
}
} // namespace webrtc } // namespace webrtc

View File

@ -36,6 +36,7 @@
namespace webrtc { namespace webrtc {
class OverheadObserver;
class RateLimiter; class RateLimiter;
class RtcEventLog; class RtcEventLog;
class RtpPacketToSend; class RtpPacketToSend;
@ -58,7 +59,8 @@ class RTPSender {
SendSideDelayObserver* send_side_delay_observer, SendSideDelayObserver* send_side_delay_observer,
RtcEventLog* event_log, RtcEventLog* event_log,
SendPacketObserver* send_packet_observer, SendPacketObserver* send_packet_observer,
RateLimiter* nack_rate_limiter); RateLimiter* nack_rate_limiter,
OverheadObserver* overhead_observer);
~RTPSender(); ~RTPSender();
@ -214,6 +216,8 @@ class RTPSender {
void SetRtxRtpState(const RtpState& rtp_state); void SetRtxRtpState(const RtpState& rtp_state);
RtpState GetRtxRtpState() const; RtpState GetRtxRtpState() const;
void SetTransportOverhead(int transport_overhead);
protected: protected:
int32_t CheckPayloadType(int8_t payload_type, RtpVideoCodecTypes* video_type); int32_t CheckPayloadType(int8_t payload_type, RtpVideoCodecTypes* video_type);
@ -259,6 +263,12 @@ class RTPSender {
bool is_retransmit); bool is_retransmit);
bool IsFecPacket(const RtpPacketToSend& packet) const; bool IsFecPacket(const RtpPacketToSend& packet) const;
void AddPacketToTransportFeedback(uint16_t packet_id,
const RtpPacketToSend& packet,
int probe_cluster_id);
void UpdateRtpOverhead(const RtpPacketToSend& packet);
Clock* const clock_; Clock* const clock_;
const int64_t clock_delta_ms_; const int64_t clock_delta_ms_;
Random random_ GUARDED_BY(send_critsect_); Random random_ GUARDED_BY(send_critsect_);
@ -327,8 +337,11 @@ class RTPSender {
uint32_t ssrc_rtx_ GUARDED_BY(send_critsect_); uint32_t ssrc_rtx_ GUARDED_BY(send_critsect_);
// Mapping rtx_payload_type_map_[associated] = rtx. // Mapping rtx_payload_type_map_[associated] = rtx.
std::map<int8_t, int8_t> rtx_payload_type_map_ GUARDED_BY(send_critsect_); std::map<int8_t, int8_t> rtx_payload_type_map_ GUARDED_BY(send_critsect_);
size_t transport_overhead_bytes_per_packet_ GUARDED_BY(send_critsect_);
size_t rtp_overhead_bytes_per_packet_ GUARDED_BY(send_critsect_);
RateLimiter* const retransmission_rate_limiter_; RateLimiter* const retransmission_rate_limiter_;
OverheadObserver* overhead_observer_;
RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(RTPSender); RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(RTPSender);
}; };

View File

@ -150,7 +150,7 @@ class RtpSenderTest : public ::testing::Test {
false, &fake_clock_, &transport_, pacer ? &mock_paced_sender_ : nullptr, false, &fake_clock_, &transport_, pacer ? &mock_paced_sender_ : nullptr,
nullptr, &seq_num_allocator_, nullptr, nullptr, nullptr, nullptr, nullptr, &seq_num_allocator_, nullptr, nullptr, nullptr, nullptr,
&mock_rtc_event_log_, &send_packet_observer_, &mock_rtc_event_log_, &send_packet_observer_,
&retransmission_rate_limiter_)); &retransmission_rate_limiter_, nullptr));
rtp_sender_->SetSendPayloadType(kPayload); rtp_sender_->SetSendPayloadType(kPayload);
rtp_sender_->SetSequenceNumber(kSeqNum); rtp_sender_->SetSequenceNumber(kSeqNum);
rtp_sender_->SetTimestampOffset(0); rtp_sender_->SetTimestampOffset(0);
@ -444,7 +444,7 @@ TEST_F(RtpSenderTestWithoutPacer, SendsPacketsWithTransportSequenceNumber) {
rtp_sender_.reset(new RTPSender( rtp_sender_.reset(new RTPSender(
false, &fake_clock_, &transport_, nullptr, nullptr, &seq_num_allocator_, false, &fake_clock_, &transport_, nullptr, nullptr, &seq_num_allocator_,
&feedback_observer_, nullptr, nullptr, nullptr, &mock_rtc_event_log_, &feedback_observer_, nullptr, nullptr, nullptr, &mock_rtc_event_log_,
&send_packet_observer_, &retransmission_rate_limiter_)); &send_packet_observer_, &retransmission_rate_limiter_, nullptr));
EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension( EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
kRtpExtensionTransportSequenceNumber, kRtpExtensionTransportSequenceNumber,
kTransportSequenceNumberExtensionId)); kTransportSequenceNumberExtensionId));
@ -487,11 +487,11 @@ TEST_F(RtpSenderTestWithoutPacer, OnSendPacketUpdated) {
} }
TEST_F(RtpSenderTest, SendsPacketsWithTransportSequenceNumber) { TEST_F(RtpSenderTest, SendsPacketsWithTransportSequenceNumber) {
rtp_sender_.reset( rtp_sender_.reset(new RTPSender(
new RTPSender(false, &fake_clock_, &transport_, &mock_paced_sender_, false, &fake_clock_, &transport_, &mock_paced_sender_, nullptr,
nullptr, &seq_num_allocator_, &feedback_observer_, nullptr, &seq_num_allocator_, &feedback_observer_, nullptr, nullptr, nullptr,
nullptr, nullptr, &mock_rtc_event_log_, &mock_rtc_event_log_, &send_packet_observer_,
&send_packet_observer_, &retransmission_rate_limiter_)); &retransmission_rate_limiter_, nullptr));
rtp_sender_->SetSequenceNumber(kSeqNum); rtp_sender_->SetSequenceNumber(kSeqNum);
rtp_sender_->SetSSRC(kSsrc); rtp_sender_->SetSSRC(kSsrc);
rtp_sender_->SetStorePacketsStatus(true, 10); rtp_sender_->SetStorePacketsStatus(true, 10);
@ -775,7 +775,8 @@ TEST_F(RtpSenderTest, OnSendPacketNotUpdatedWithoutSeqNumAllocator) {
rtp_sender_.reset(new RTPSender( rtp_sender_.reset(new RTPSender(
false, &fake_clock_, &transport_, &mock_paced_sender_, nullptr, false, &fake_clock_, &transport_, &mock_paced_sender_, nullptr,
nullptr /* TransportSequenceNumberAllocator */, nullptr, nullptr, nullptr, nullptr /* TransportSequenceNumberAllocator */, nullptr, nullptr, nullptr,
nullptr, nullptr, &send_packet_observer_, &retransmission_rate_limiter_)); nullptr, nullptr, &send_packet_observer_, &retransmission_rate_limiter_,
nullptr));
rtp_sender_->SetSequenceNumber(kSeqNum); rtp_sender_->SetSequenceNumber(kSeqNum);
rtp_sender_->SetSSRC(kSsrc); rtp_sender_->SetSSRC(kSsrc);
EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension( EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
@ -801,7 +802,7 @@ TEST_F(RtpSenderTest, SendRedundantPayloads) {
rtp_sender_.reset(new RTPSender( rtp_sender_.reset(new RTPSender(
false, &fake_clock_, &transport, &mock_paced_sender_, nullptr, nullptr, false, &fake_clock_, &transport, &mock_paced_sender_, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, &mock_rtc_event_log_, nullptr, nullptr, nullptr, nullptr, nullptr, &mock_rtc_event_log_, nullptr,
&retransmission_rate_limiter_)); &retransmission_rate_limiter_, nullptr));
rtp_sender_->SetSequenceNumber(kSeqNum); rtp_sender_->SetSequenceNumber(kSeqNum);
rtp_sender_->SetSSRC(kSsrc); rtp_sender_->SetSSRC(kSsrc);
rtp_sender_->SetRtxPayloadType(kRtxPayload, kPayload); rtp_sender_->SetRtxPayloadType(kRtxPayload, kPayload);
@ -919,11 +920,11 @@ TEST_F(RtpSenderTest, SendFlexfecPackets) {
kNoRtpExtensions, &fake_clock_); kNoRtpExtensions, &fake_clock_);
// Reset |rtp_sender_| to use FlexFEC. // Reset |rtp_sender_| to use FlexFEC.
rtp_sender_.reset( rtp_sender_.reset(new RTPSender(
new RTPSender(false, &fake_clock_, &transport_, &mock_paced_sender_, false, &fake_clock_, &transport_, &mock_paced_sender_, &flexfec_sender,
&flexfec_sender, &seq_num_allocator_, nullptr, nullptr, &seq_num_allocator_, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, &mock_rtc_event_log_, &mock_rtc_event_log_, &send_packet_observer_,
&send_packet_observer_, &retransmission_rate_limiter_)); &retransmission_rate_limiter_, nullptr));
rtp_sender_->SetSSRC(kMediaSsrc); rtp_sender_->SetSSRC(kMediaSsrc);
rtp_sender_->SetSequenceNumber(kSeqNum); rtp_sender_->SetSequenceNumber(kSeqNum);
rtp_sender_->SetSendPayloadType(kMediaPayloadType); rtp_sender_->SetSendPayloadType(kMediaPayloadType);
@ -977,7 +978,7 @@ TEST_F(RtpSenderTestWithoutPacer, SendFlexfecPackets) {
&flexfec_sender, &seq_num_allocator_, nullptr, &flexfec_sender, &seq_num_allocator_, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
&mock_rtc_event_log_, &send_packet_observer_, &mock_rtc_event_log_, &send_packet_observer_,
&retransmission_rate_limiter_)); &retransmission_rate_limiter_, nullptr));
rtp_sender_->SetSSRC(kMediaSsrc); rtp_sender_->SetSSRC(kMediaSsrc);
rtp_sender_->SetSequenceNumber(kSeqNum); rtp_sender_->SetSequenceNumber(kSeqNum);
rtp_sender_->SetSendPayloadType(kMediaPayloadType); rtp_sender_->SetSendPayloadType(kMediaPayloadType);
@ -1020,10 +1021,10 @@ TEST_F(RtpSenderTest, FrameCountCallbacks) {
FrameCounts frame_counts_; FrameCounts frame_counts_;
} callback; } callback;
rtp_sender_.reset(new RTPSender(false, &fake_clock_, &transport_, rtp_sender_.reset(
&mock_paced_sender_, nullptr, nullptr, new RTPSender(false, &fake_clock_, &transport_, &mock_paced_sender_,
nullptr, nullptr, &callback, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, &callback, nullptr,
nullptr, &retransmission_rate_limiter_)); nullptr, nullptr, &retransmission_rate_limiter_, nullptr));
char payload_name[RTP_PAYLOAD_NAME_SIZE] = "GENERIC"; char payload_name[RTP_PAYLOAD_NAME_SIZE] = "GENERIC";
const uint8_t payload_type = 127; const uint8_t payload_type = 127;
@ -1085,7 +1086,7 @@ TEST_F(RtpSenderTest, BitrateCallbacks) {
rtp_sender_.reset(new RTPSender(false, &fake_clock_, &transport_, nullptr, rtp_sender_.reset(new RTPSender(false, &fake_clock_, &transport_, nullptr,
nullptr, nullptr, nullptr, &callback, nullptr, nullptr, nullptr, nullptr, &callback, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
&retransmission_rate_limiter_)); &retransmission_rate_limiter_, nullptr));
// Simulate kNumPackets sent with kPacketInterval ms intervals, with the // Simulate kNumPackets sent with kPacketInterval ms intervals, with the
// number of packets selected so that we fill (but don't overflow) the one // number of packets selected so that we fill (but don't overflow) the one
@ -1143,7 +1144,7 @@ class RtpSenderAudioTest : public RtpSenderTest {
rtp_sender_.reset(new RTPSender(true, &fake_clock_, &transport_, nullptr, rtp_sender_.reset(new RTPSender(true, &fake_clock_, &transport_, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
&retransmission_rate_limiter_)); &retransmission_rate_limiter_, nullptr));
rtp_sender_->SetSequenceNumber(kSeqNum); rtp_sender_->SetSequenceNumber(kSeqNum);
} }
}; };
@ -1494,4 +1495,52 @@ TEST_F(RtpSenderVideoTest, SendVideoWithCameraAndFlipCVO) {
ConvertCVOByteToVideoRotation(flip_bit | camera_bit | 3)); ConvertCVOByteToVideoRotation(flip_bit | camera_bit | 3));
} }
namespace {
class MockOverheadObserver : public OverheadObserver {
public:
MOCK_METHOD1(OnOverheadChanged, void(size_t overhead_bytes_per_packet));
};
} // namespace
TEST_F(RtpSenderTest, OnOverheadChanged) {
MockOverheadObserver mock_overhead_observer;
rtp_sender_.reset(
new RTPSender(false, &fake_clock_, &transport_, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
&retransmission_rate_limiter_, &mock_overhead_observer));
// Transport overhead is set to 28B.
EXPECT_CALL(mock_overhead_observer, OnOverheadChanged(28)).Times(1);
rtp_sender_->SetTransportOverhead(28);
// RTP overhead is 12B.
// 28B + 12B = 40B
EXPECT_CALL(mock_overhead_observer, OnOverheadChanged(40)).Times(1);
SendGenericPayload();
rtp_sender_->RegisterRtpHeaderExtension(kRtpExtensionTransmissionTimeOffset,
kTransmissionTimeOffsetExtensionId);
// TransmissionTimeOffset extension has a size of 8B.
// 28B + 12B + 8B = 48B
EXPECT_CALL(mock_overhead_observer, OnOverheadChanged(48)).Times(1);
SendGenericPayload();
}
TEST_F(RtpSenderTest, DoesNotUpdateOverheadOnEqualSize) {
MockOverheadObserver mock_overhead_observer;
rtp_sender_.reset(
new RTPSender(false, &fake_clock_, &transport_, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
&retransmission_rate_limiter_, &mock_overhead_observer));
EXPECT_CALL(mock_overhead_observer, OnOverheadChanged(_)).Times(1);
rtp_sender_->SetTransportOverhead(28);
rtp_sender_->SetTransportOverhead(28);
EXPECT_CALL(mock_overhead_observer, OnOverheadChanged(_)).Times(1);
SendGenericPayload();
SendGenericPayload();
}
} // namespace webrtc } // namespace webrtc