Add support for transport wide sequence numbers
Also refactor packet router to use a map rather than iterate over all
rtp modules for each packet sent.
BUG=webrtc:4311
Review URL: https://codereview.webrtc.org/1247293002
Cr-Commit-Position: refs/heads/master@{#9670}
diff --git a/webrtc/config.cc b/webrtc/config.cc
index c5d29d4..ddff931 100644
--- a/webrtc/config.cc
+++ b/webrtc/config.cc
@@ -35,16 +35,20 @@
const char* RtpExtension::kVideoRotation = "urn:3gpp:video-orientation";
const char* RtpExtension::kAudioLevel =
"urn:ietf:params:rtp-hdrext:ssrc-audio-level";
+const char* RtpExtension::kTransportSequenceNumber =
+ "http://www.webrtc.org/experiments/rtp-hdrext/transport-sequence-number";
bool RtpExtension::IsSupportedForAudio(const std::string& name) {
return name == webrtc::RtpExtension::kAbsSendTime ||
- name == webrtc::RtpExtension::kAudioLevel;
+ name == webrtc::RtpExtension::kAudioLevel ||
+ name == webrtc::RtpExtension::kTransportSequenceNumber;
}
bool RtpExtension::IsSupportedForVideo(const std::string& name) {
return name == webrtc::RtpExtension::kTOffset ||
name == webrtc::RtpExtension::kAbsSendTime ||
- name == webrtc::RtpExtension::kVideoRotation;
+ name == webrtc::RtpExtension::kVideoRotation ||
+ name == webrtc::RtpExtension::kTransportSequenceNumber;
}
VideoStream::VideoStream()
diff --git a/webrtc/config.h b/webrtc/config.h
index 804f54d..5271163 100644
--- a/webrtc/config.h
+++ b/webrtc/config.h
@@ -60,6 +60,7 @@
static const char* kAbsSendTime;
static const char* kVideoRotation;
static const char* kAudioLevel;
+ static const char* kTransportSequenceNumber;
std::string name;
int id;
};
diff --git a/webrtc/modules/bitrate_controller/BUILD.gn b/webrtc/modules/bitrate_controller/BUILD.gn
index 9280f03..4ef536b 100644
--- a/webrtc/modules/bitrate_controller/BUILD.gn
+++ b/webrtc/modules/bitrate_controller/BUILD.gn
@@ -17,8 +17,6 @@
"include/bitrate_controller.h",
"send_side_bandwidth_estimation.cc",
"send_side_bandwidth_estimation.h",
- "send_time_history.cc",
- "send_time_history.h",
]
if (is_win) {
diff --git a/webrtc/modules/bitrate_controller/bitrate_controller.gypi b/webrtc/modules/bitrate_controller/bitrate_controller.gypi
index a0c2fc9..44c1b89 100644
--- a/webrtc/modules/bitrate_controller/bitrate_controller.gypi
+++ b/webrtc/modules/bitrate_controller/bitrate_controller.gypi
@@ -22,8 +22,6 @@
'include/bitrate_allocator.h',
'send_side_bandwidth_estimation.cc',
'send_side_bandwidth_estimation.h',
- 'send_time_history.cc',
- 'send_time_history.h',
],
# TODO(jschuh): Bug 1348: fix size_t to int truncations.
'msvs_disabled_warnings': [ 4267, ],
diff --git a/webrtc/modules/bitrate_controller/bitrate_controller_impl.cc b/webrtc/modules/bitrate_controller/bitrate_controller_impl.cc
index d54da99..4a045d9 100644
--- a/webrtc/modules/bitrate_controller/bitrate_controller_impl.cc
+++ b/webrtc/modules/bitrate_controller/bitrate_controller_impl.cc
@@ -87,7 +87,6 @@
: clock_(clock),
observer_(observer),
last_bitrate_update_ms_(clock_->TimeInMilliseconds()),
- critsect_(CriticalSectionWrapper::CreateCriticalSection()),
bandwidth_estimation_(),
reserved_bitrate_bps_(0),
last_bitrate_bps_(0),
@@ -107,7 +106,7 @@
void BitrateControllerImpl::SetStartBitrate(int start_bitrate_bps) {
{
- CriticalSectionScoped cs(critsect_.get());
+ rtc::CritScope cs(&critsect_);
bandwidth_estimation_.SetSendBitrate(start_bitrate_bps);
}
MaybeTriggerOnNetworkChanged();
@@ -116,7 +115,7 @@
void BitrateControllerImpl::SetMinMaxBitrate(int min_bitrate_bps,
int max_bitrate_bps) {
{
- CriticalSectionScoped cs(critsect_.get());
+ rtc::CritScope cs(&critsect_);
bandwidth_estimation_.SetMinMaxBitrate(min_bitrate_bps, max_bitrate_bps);
}
MaybeTriggerOnNetworkChanged();
@@ -124,7 +123,7 @@
void BitrateControllerImpl::SetReservedBitrate(uint32_t reserved_bitrate_bps) {
{
- CriticalSectionScoped cs(critsect_.get());
+ rtc::CritScope cs(&critsect_);
reserved_bitrate_bps_ = reserved_bitrate_bps;
}
MaybeTriggerOnNetworkChanged();
@@ -132,7 +131,7 @@
void BitrateControllerImpl::OnReceivedEstimatedBitrate(uint32_t bitrate) {
{
- CriticalSectionScoped cs(critsect_.get());
+ rtc::CritScope cs(&critsect_);
bandwidth_estimation_.UpdateReceiverEstimate(bitrate);
}
MaybeTriggerOnNetworkChanged();
@@ -140,7 +139,7 @@
int64_t BitrateControllerImpl::TimeUntilNextProcess() {
const int64_t kBitrateControllerUpdateIntervalMs = 25;
- CriticalSectionScoped cs(critsect_.get());
+ rtc::CritScope cs(&critsect_);
int64_t time_since_update_ms =
clock_->TimeInMilliseconds() - last_bitrate_update_ms_;
return std::max<int64_t>(
@@ -151,7 +150,7 @@
if (TimeUntilNextProcess() > 0)
return 0;
{
- CriticalSectionScoped cs(critsect_.get());
+ rtc::CritScope cs(&critsect_);
bandwidth_estimation_.UpdateEstimate(clock_->TimeInMilliseconds());
}
MaybeTriggerOnNetworkChanged();
@@ -165,7 +164,7 @@
int number_of_packets,
int64_t now_ms) {
{
- CriticalSectionScoped cs(critsect_.get());
+ rtc::CritScope cs(&critsect_);
bandwidth_estimation_.UpdateReceiverBlock(fraction_loss, rtt,
number_of_packets, now_ms);
}
@@ -183,7 +182,7 @@
bool BitrateControllerImpl::GetNetworkParameters(uint32_t* bitrate,
uint8_t* fraction_loss,
int64_t* rtt) {
- CriticalSectionScoped cs(critsect_.get());
+ rtc::CritScope cs(&critsect_);
int current_bitrate;
bandwidth_estimation_.CurrentEstimate(¤t_bitrate, fraction_loss, rtt);
*bitrate = current_bitrate;
@@ -205,7 +204,7 @@
}
bool BitrateControllerImpl::AvailableBandwidth(uint32_t* bandwidth) const {
- CriticalSectionScoped cs(critsect_.get());
+ rtc::CritScope cs(&critsect_);
int bitrate;
uint8_t fraction_loss;
int64_t rtt;
@@ -218,5 +217,4 @@
}
return false;
}
-
} // namespace webrtc
diff --git a/webrtc/modules/bitrate_controller/bitrate_controller_impl.h b/webrtc/modules/bitrate_controller/bitrate_controller_impl.h
index 3d38a54..a0131e2 100644
--- a/webrtc/modules/bitrate_controller/bitrate_controller_impl.h
+++ b/webrtc/modules/bitrate_controller/bitrate_controller_impl.h
@@ -20,9 +20,9 @@
#include <list>
#include <utility>
+#include "webrtc/base/criticalsection.h"
#include "webrtc/base/scoped_ptr.h"
#include "webrtc/modules/bitrate_controller/send_side_bandwidth_estimation.h"
-#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
namespace webrtc {
@@ -64,22 +64,21 @@
void OnNetworkChanged(uint32_t bitrate,
uint8_t fraction_loss, // 0 - 255.
- int64_t rtt)
- EXCLUSIVE_LOCKS_REQUIRED(*critsect_);
+ int64_t rtt) EXCLUSIVE_LOCKS_REQUIRED(critsect_);
// Used by process thread.
Clock* clock_;
BitrateObserver* observer_;
int64_t last_bitrate_update_ms_;
- const rtc::scoped_ptr<CriticalSectionWrapper> critsect_;
- SendSideBandwidthEstimation bandwidth_estimation_ GUARDED_BY(*critsect_);
- uint32_t reserved_bitrate_bps_ GUARDED_BY(*critsect_);
+ mutable rtc::CriticalSection critsect_;
+ SendSideBandwidthEstimation bandwidth_estimation_ GUARDED_BY(critsect_);
+ uint32_t reserved_bitrate_bps_ GUARDED_BY(critsect_);
- uint32_t last_bitrate_bps_ GUARDED_BY(*critsect_);
- uint8_t last_fraction_loss_ GUARDED_BY(*critsect_);
- int64_t last_rtt_ms_ GUARDED_BY(*critsect_);
- uint32_t last_reserved_bitrate_bps_ GUARDED_BY(*critsect_);
+ uint32_t last_bitrate_bps_ GUARDED_BY(critsect_);
+ uint8_t last_fraction_loss_ GUARDED_BY(critsect_);
+ int64_t last_rtt_ms_ GUARDED_BY(critsect_);
+ uint32_t last_reserved_bitrate_bps_ GUARDED_BY(critsect_);
DISALLOW_IMPLICIT_CONSTRUCTORS(BitrateControllerImpl);
};
diff --git a/webrtc/modules/bitrate_controller/include/bitrate_controller.h b/webrtc/modules/bitrate_controller/include/bitrate_controller.h
index 7303d06..bb53288 100644
--- a/webrtc/modules/bitrate_controller/include/bitrate_controller.h
+++ b/webrtc/modules/bitrate_controller/include/bitrate_controller.h
@@ -23,6 +23,7 @@
namespace webrtc {
class CriticalSectionWrapper;
+struct PacketInfo;
class BitrateObserver {
// Observer class for bitrate changes announced due to change in bandwidth
diff --git a/webrtc/modules/modules.gyp b/webrtc/modules/modules.gyp
index a769aa9..f114fea 100644
--- a/webrtc/modules/modules.gyp
+++ b/webrtc/modules/modules.gyp
@@ -194,7 +194,6 @@
'bitrate_controller/bitrate_allocator_unittest.cc',
'bitrate_controller/bitrate_controller_unittest.cc',
'bitrate_controller/send_side_bandwidth_estimation_unittest.cc',
- 'bitrate_controller/send_time_history_unittest.cc',
'desktop_capture/desktop_and_cursor_composer_unittest.cc',
'desktop_capture/desktop_region_unittest.cc',
'desktop_capture/differ_block_unittest.cc',
@@ -222,6 +221,7 @@
'remote_bitrate_estimator/remote_bitrate_estimator_single_stream_unittest.cc',
'remote_bitrate_estimator/remote_bitrate_estimator_unittest_helper.cc',
'remote_bitrate_estimator/remote_bitrate_estimator_unittest_helper.h',
+ 'remote_bitrate_estimator/send_time_history_unittest.cc',
'remote_bitrate_estimator/test/bwe_test_framework_unittest.cc',
'remote_bitrate_estimator/test/bwe_unittest.cc',
'remote_bitrate_estimator/test/metric_recorder_unittest.cc',
diff --git a/webrtc/modules/pacing/BUILD.gn b/webrtc/modules/pacing/BUILD.gn
index 296bf17..69cd6db 100644
--- a/webrtc/modules/pacing/BUILD.gn
+++ b/webrtc/modules/pacing/BUILD.gn
@@ -27,5 +27,6 @@
deps = [
"../../system_wrappers",
+ "../bitrate_controller",
]
}
diff --git a/webrtc/modules/pacing/include/packet_router.h b/webrtc/modules/pacing/include/packet_router.h
index c1b332a..e7d630e 100644
--- a/webrtc/modules/pacing/include/packet_router.h
+++ b/webrtc/modules/pacing/include/packet_router.h
@@ -14,6 +14,7 @@
#include <list>
#include "webrtc/base/constructormagic.h"
+#include "webrtc/base/criticalsection.h"
#include "webrtc/base/scoped_ptr.h"
#include "webrtc/base/thread_annotations.h"
#include "webrtc/common_types.h"
@@ -21,10 +22,7 @@
namespace webrtc {
-class CriticalSectionWrapper;
-class RTPFragmentationHeader;
class RtpRtcp;
-struct RTPVideoHeader;
// PacketRouter routes outgoing data to the correct sending RTP module, based
// on the simulcast layer in RTPVideoHeader.
@@ -44,14 +42,15 @@
size_t TimeToSendPadding(size_t bytes) override;
- private:
- // TODO(holmer): When the new video API has launched, remove crit_ and
- // assume rtp_modules_ will never change during a call. We should then also
- // switch rtp_modules_ to a map from ssrc to rtp module.
- rtc::scoped_ptr<CriticalSectionWrapper> crit_;
+ void SetTransportWideSequenceNumber(uint16_t sequence_number);
+ uint16_t AllocateSequenceNumber();
+ private:
+ rtc::CriticalSection modules_lock_;
// Map from ssrc to sending rtp module.
- std::list<RtpRtcp*> rtp_modules_ GUARDED_BY(crit_.get());
+ std::list<RtpRtcp*> rtp_modules_ GUARDED_BY(modules_lock_);
+
+ volatile int transport_seq_;
DISALLOW_COPY_AND_ASSIGN(PacketRouter);
};
diff --git a/webrtc/modules/pacing/pacing.gypi b/webrtc/modules/pacing/pacing.gypi
index 09be38f..29d9508 100644
--- a/webrtc/modules/pacing/pacing.gypi
+++ b/webrtc/modules/pacing/pacing.gypi
@@ -13,6 +13,7 @@
'type': 'static_library',
'dependencies': [
'<(webrtc_root)/system_wrappers/system_wrappers.gyp:system_wrappers',
+ '<(webrtc_root)/modules/modules.gyp:bitrate_controller',
],
'sources': [
'include/paced_sender.h',
diff --git a/webrtc/modules/pacing/packet_router.cc b/webrtc/modules/pacing/packet_router.cc
index 9e15a71..1b12498 100644
--- a/webrtc/modules/pacing/packet_router.cc
+++ b/webrtc/modules/pacing/packet_router.cc
@@ -10,37 +10,39 @@
#include "webrtc/modules/pacing/include/packet_router.h"
+#include "webrtc/base/atomicops.h"
#include "webrtc/base/checks.h"
#include "webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h"
#include "webrtc/modules/rtp_rtcp/interface/rtp_rtcp_defines.h"
-#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
namespace webrtc {
-PacketRouter::PacketRouter()
- : crit_(CriticalSectionWrapper::CreateCriticalSection()) {
+PacketRouter::PacketRouter() : transport_seq_(0) {
}
PacketRouter::~PacketRouter() {
+ DCHECK(rtp_modules_.empty());
}
void PacketRouter::AddRtpModule(RtpRtcp* rtp_module) {
- CriticalSectionScoped cs(crit_.get());
+ rtc::CritScope cs(&modules_lock_);
DCHECK(std::find(rtp_modules_.begin(), rtp_modules_.end(), rtp_module) ==
rtp_modules_.end());
rtp_modules_.push_back(rtp_module);
}
void PacketRouter::RemoveRtpModule(RtpRtcp* rtp_module) {
- CriticalSectionScoped cs(crit_.get());
- rtp_modules_.remove(rtp_module);
+ rtc::CritScope cs(&modules_lock_);
+ auto it = std::find(rtp_modules_.begin(), rtp_modules_.end(), rtp_module);
+ DCHECK(it != rtp_modules_.end());
+ rtp_modules_.erase(it);
}
bool PacketRouter::TimeToSendPacket(uint32_t ssrc,
uint16_t sequence_number,
int64_t capture_timestamp,
bool retransmission) {
- CriticalSectionScoped cs(crit_.get());
+ rtc::CritScope cs(&modules_lock_);
for (auto* rtp_module : rtp_modules_) {
if (rtp_module->SendingMedia() && ssrc == rtp_module->SSRC()) {
return rtp_module->TimeToSendPacket(ssrc, sequence_number,
@@ -50,12 +52,41 @@
return true;
}
-size_t PacketRouter::TimeToSendPadding(size_t bytes) {
- CriticalSectionScoped cs(crit_.get());
- for (auto* rtp_module : rtp_modules_) {
- if (rtp_module->SendingMedia())
- return rtp_module->TimeToSendPadding(bytes);
+size_t PacketRouter::TimeToSendPadding(size_t bytes_to_send) {
+ size_t total_bytes_sent = 0;
+ rtc::CritScope cs(&modules_lock_);
+ for (RtpRtcp* module : rtp_modules_) {
+ if (module->SendingMedia()) {
+ size_t bytes_sent =
+ module->TimeToSendPadding(bytes_to_send - total_bytes_sent);
+ total_bytes_sent += bytes_sent;
+ if (total_bytes_sent >= bytes_to_send)
+ break;
+ }
}
- return 0;
+ return total_bytes_sent;
}
+
+void PacketRouter::SetTransportWideSequenceNumber(uint16_t sequence_number) {
+ rtc::AtomicOps::ReleaseStore(&transport_seq_, sequence_number);
+}
+
+uint16_t PacketRouter::AllocateSequenceNumber() {
+ int prev_seq = rtc::AtomicOps::AcquireLoad(&transport_seq_);
+ int desired_prev_seq;
+ int new_seq;
+ do {
+ desired_prev_seq = prev_seq;
+ new_seq = (desired_prev_seq + 1) & 0xFFFF;
+ // Note: CompareAndSwap returns the actual value of transport_seq at the
+ // time the CAS operation was executed. Thus, if prev_seq is returned, the
+ // operation was successful - otherwise we need to retry. Saving the
+ // return value saves us a load on retry.
+ prev_seq = rtc::AtomicOps::CompareAndSwap(&transport_seq_, desired_prev_seq,
+ new_seq);
+ } while (prev_seq != desired_prev_seq);
+
+ return new_seq;
+}
+
} // namespace webrtc
diff --git a/webrtc/modules/pacing/packet_router_unittest.cc b/webrtc/modules/pacing/packet_router_unittest.cc
index f7fdf7b..eecb137 100644
--- a/webrtc/modules/pacing/packet_router_unittest.cc
+++ b/webrtc/modules/pacing/packet_router_unittest.cc
@@ -102,20 +102,30 @@
}
TEST_F(PacketRouterTest, TimeToSendPadding) {
+ const uint16_t kSsrc1 = 1234;
+ const uint16_t kSsrc2 = 4567;
+
MockRtpRtcp rtp_1;
+ EXPECT_CALL(rtp_1, SSRC()).WillRepeatedly(Return(kSsrc1));
MockRtpRtcp rtp_2;
+ EXPECT_CALL(rtp_2, SSRC()).WillRepeatedly(Return(kSsrc2));
packet_router_->AddRtpModule(&rtp_1);
packet_router_->AddRtpModule(&rtp_2);
- // Default configuration, sending padding on the first sending module.
+ // Default configuration, sending padding on all modules sending media,
+ // ordered by SSRC.
const size_t requested_padding_bytes = 1000;
const size_t sent_padding_bytes = 890;
EXPECT_CALL(rtp_1, SendingMedia()).Times(1).WillOnce(Return(true));
EXPECT_CALL(rtp_1, TimeToSendPadding(requested_padding_bytes))
.Times(1)
.WillOnce(Return(sent_padding_bytes));
- EXPECT_CALL(rtp_2, TimeToSendPadding(_)).Times(0);
- EXPECT_EQ(sent_padding_bytes,
+ EXPECT_CALL(rtp_2, SendingMedia()).Times(1).WillOnce(Return(true));
+ EXPECT_CALL(rtp_2,
+ TimeToSendPadding(requested_padding_bytes - sent_padding_bytes))
+ .Times(1)
+ .WillOnce(Return(requested_padding_bytes - sent_padding_bytes));
+ EXPECT_EQ(requested_padding_bytes,
packet_router_->TimeToSendPadding(requested_padding_bytes));
// Let only the second module be sending and verify the padding request is
@@ -134,8 +144,7 @@
EXPECT_CALL(rtp_1, TimeToSendPadding(requested_padding_bytes)).Times(0);
EXPECT_CALL(rtp_2, SendingMedia()).Times(1).WillOnce(Return(false));
EXPECT_CALL(rtp_2, TimeToSendPadding(_)).Times(0);
- EXPECT_EQ(static_cast<size_t>(0),
- packet_router_->TimeToSendPadding(requested_padding_bytes));
+ EXPECT_EQ(0u, packet_router_->TimeToSendPadding(requested_padding_bytes));
packet_router_->RemoveRtpModule(&rtp_1);
@@ -143,9 +152,21 @@
// to send by not expecting any calls. Instead verify rtp_2 is called.
EXPECT_CALL(rtp_2, SendingMedia()).Times(1).WillOnce(Return(true));
EXPECT_CALL(rtp_2, TimeToSendPadding(requested_padding_bytes)).Times(1);
- EXPECT_EQ(static_cast<size_t>(0),
- packet_router_->TimeToSendPadding(requested_padding_bytes));
+ EXPECT_EQ(0u, packet_router_->TimeToSendPadding(requested_padding_bytes));
packet_router_->RemoveRtpModule(&rtp_2);
}
+
+TEST_F(PacketRouterTest, AllocateSequenceNumbers) {
+ const uint16_t kStartSeq = 0xFFF0;
+ const size_t kNumPackets = 32;
+
+ packet_router_->SetTransportWideSequenceNumber(kStartSeq - 1);
+
+ for (size_t i = 0; i < kNumPackets; ++i) {
+ uint16_t seq = packet_router_->AllocateSequenceNumber();
+ uint32_t expected_unwrapped_seq = static_cast<uint32_t>(kStartSeq) + i;
+ EXPECT_EQ(static_cast<uint16_t>(expected_unwrapped_seq & 0xFFFF), seq);
+ }
+}
} // namespace webrtc
diff --git a/webrtc/modules/remote_bitrate_estimator/BUILD.gn b/webrtc/modules/remote_bitrate_estimator/BUILD.gn
index b4d4af9..938777e 100644
--- a/webrtc/modules/remote_bitrate_estimator/BUILD.gn
+++ b/webrtc/modules/remote_bitrate_estimator/BUILD.gn
@@ -10,8 +10,10 @@
sources = [
"include/bwe_defines.h",
"include/remote_bitrate_estimator.h",
+ "include/send_time_history.h",
"rate_statistics.cc",
"rate_statistics.h",
+ "send_time_history.cc",
]
configs += [ "../../:common_inherited_config" ]
diff --git a/webrtc/modules/bitrate_controller/send_time_history.h b/webrtc/modules/remote_bitrate_estimator/include/send_time_history.h
similarity index 100%
rename from webrtc/modules/bitrate_controller/send_time_history.h
rename to webrtc/modules/remote_bitrate_estimator/include/send_time_history.h
diff --git a/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator.gypi b/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator.gypi
index f318433..3bbd503 100644
--- a/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator.gypi
+++ b/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator.gypi
@@ -21,6 +21,7 @@
'sources': [
'include/bwe_defines.h',
'include/remote_bitrate_estimator.h',
+ 'include/send_time_history.h',
'aimd_rate_control.cc',
'aimd_rate_control.h',
'inter_arrival.cc',
@@ -35,6 +36,7 @@
'remote_bitrate_estimator_abs_send_time.h',
'remote_bitrate_estimator_single_stream.cc',
'remote_bitrate_estimator_single_stream.h',
+ 'send_time_history.cc',
'test/bwe_test_logging.cc',
'test/bwe_test_logging.h',
], # source
diff --git a/webrtc/modules/bitrate_controller/send_time_history.cc b/webrtc/modules/remote_bitrate_estimator/send_time_history.cc
similarity index 96%
rename from webrtc/modules/bitrate_controller/send_time_history.cc
rename to webrtc/modules/remote_bitrate_estimator/send_time_history.cc
index 7e0c89e..f564573 100644
--- a/webrtc/modules/bitrate_controller/send_time_history.cc
+++ b/webrtc/modules/remote_bitrate_estimator/send_time_history.cc
@@ -10,7 +10,7 @@
#include <assert.h>
-#include "webrtc/modules/bitrate_controller/send_time_history.h"
+#include "webrtc/modules/remote_bitrate_estimator/include/send_time_history.h"
namespace webrtc {
diff --git a/webrtc/modules/bitrate_controller/send_time_history_unittest.cc b/webrtc/modules/remote_bitrate_estimator/send_time_history_unittest.cc
similarity index 98%
rename from webrtc/modules/bitrate_controller/send_time_history_unittest.cc
rename to webrtc/modules/remote_bitrate_estimator/send_time_history_unittest.cc
index fc7099d..8d70852 100644
--- a/webrtc/modules/bitrate_controller/send_time_history_unittest.cc
+++ b/webrtc/modules/remote_bitrate_estimator/send_time_history_unittest.cc
@@ -13,7 +13,7 @@
#include <vector>
#include "testing/gtest/include/gtest/gtest.h"
-#include "webrtc/modules/bitrate_controller/send_time_history.h"
+#include "webrtc/modules/remote_bitrate_estimator/include/send_time_history.h"
#include "webrtc/system_wrappers/interface/clock.h"
namespace webrtc {
diff --git a/webrtc/modules/remote_bitrate_estimator/test/estimators/send_side.h b/webrtc/modules/remote_bitrate_estimator/test/estimators/send_side.h
index c76e360..322dced 100644
--- a/webrtc/modules/remote_bitrate_estimator/test/estimators/send_side.h
+++ b/webrtc/modules/remote_bitrate_estimator/test/estimators/send_side.h
@@ -13,7 +13,7 @@
#include <vector>
-#include "webrtc/modules/bitrate_controller/send_time_history.h"
+#include "webrtc/modules/remote_bitrate_estimator/include/send_time_history.h"
#include "webrtc/modules/remote_bitrate_estimator/test/bwe.h"
namespace webrtc {
diff --git a/webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h b/webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h
index cddaa21..d8f9a94 100644
--- a/webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h
+++ b/webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h
@@ -20,6 +20,7 @@
namespace webrtc {
// Forward declarations.
class PacedSender;
+class PacketRouter;
class ReceiveStatistics;
class RemoteBitrateEstimator;
class RtpReceiver;
@@ -61,11 +62,13 @@
Transport* outgoing_transport;
RtcpIntraFrameObserver* intra_frame_callback;
RtcpBandwidthObserver* bandwidth_callback;
+ SendTimeObserver* send_time_callback;
RtcpRttStats* rtt_stats;
RtcpPacketTypeCounterObserver* rtcp_packet_type_counter_observer;
RtpAudioFeedback* audio_messages;
RemoteBitrateEstimator* remote_bitrate_estimator;
PacedSender* paced_sender;
+ PacketRouter* packet_router;
BitrateStatisticsObserver* send_bitrate_observer;
FrameCountObserver* send_frame_count_observer;
SendSideDelayObserver* send_side_delay_observer;
diff --git a/webrtc/modules/rtp_rtcp/interface/rtp_rtcp_defines.h b/webrtc/modules/rtp_rtcp/interface/rtp_rtcp_defines.h
index ea36687..7642285 100644
--- a/webrtc/modules/rtp_rtcp/interface/rtp_rtcp_defines.h
+++ b/webrtc/modules/rtp_rtcp/interface/rtp_rtcp_defines.h
@@ -293,6 +293,17 @@
virtual ~RtcpBandwidthObserver() {}
};
+class SendTimeObserver {
+ public:
+ SendTimeObserver() {}
+ virtual ~SendTimeObserver() {}
+
+ // Transport-wide sequence number and timestamp (system time in milliseconds),
+ // of when the packet was put on the wire.
+ virtual void OnPacketSent(uint16_t transport_sequence_number,
+ int64_t send_time) = 0;
+};
+
class RtcpRttStats {
public:
virtual void OnRttUpdate(int64_t rtt) = 0;
diff --git a/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc b/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc
index c8b4b33..df5fb65 100644
--- a/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc
+++ b/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc
@@ -30,19 +30,20 @@
: id(-1),
audio(false),
receiver_only(false),
- clock(NULL),
+ clock(nullptr),
receive_statistics(NullObjectReceiveStatistics()),
- outgoing_transport(NULL),
- intra_frame_callback(NULL),
- bandwidth_callback(NULL),
- rtt_stats(NULL),
- rtcp_packet_type_counter_observer(NULL),
+ outgoing_transport(nullptr),
+ intra_frame_callback(nullptr),
+ bandwidth_callback(nullptr),
+ rtt_stats(nullptr),
+ rtcp_packet_type_counter_observer(nullptr),
audio_messages(NullObjectRtpAudioFeedback()),
- remote_bitrate_estimator(NULL),
- paced_sender(NULL),
- send_bitrate_observer(NULL),
- send_frame_count_observer(NULL),
- send_side_delay_observer(NULL) {
+ remote_bitrate_estimator(nullptr),
+ paced_sender(nullptr),
+ packet_router(nullptr),
+ send_bitrate_observer(nullptr),
+ send_frame_count_observer(nullptr),
+ send_side_delay_observer(nullptr) {
}
RtpRtcp* RtpRtcp::CreateRtpRtcp(const RtpRtcp::Configuration& configuration) {
@@ -65,6 +66,8 @@
configuration.outgoing_transport,
configuration.audio_messages,
configuration.paced_sender,
+ configuration.packet_router,
+ configuration.send_time_callback,
configuration.send_bitrate_observer,
configuration.send_frame_count_observer,
configuration.send_side_delay_observer),
diff --git a/webrtc/modules/rtp_rtcp/source/rtp_sender.cc b/webrtc/modules/rtp_rtcp/source/rtp_sender.cc
index e7306a1..cec7e17 100644
--- a/webrtc/modules/rtp_rtcp/source/rtp_sender.cc
+++ b/webrtc/modules/rtp_rtcp/source/rtp_sender.cc
@@ -103,6 +103,8 @@
Transport* transport,
RtpAudioFeedback* audio_feedback,
PacedSender* paced_sender,
+ PacketRouter* packet_router,
+ SendTimeObserver* send_time_observer,
BitrateStatisticsObserver* bitrate_callback,
FrameCountObserver* frame_count_observer,
SendSideDelayObserver* send_side_delay_observer)
@@ -119,6 +121,8 @@
: nullptr),
video_(audio ? nullptr : new RTPSenderVideo(clock, this)),
paced_sender_(paced_sender),
+ packet_router_(packet_router),
+ send_time_observer_(send_time_observer),
last_capture_time_ms_sent_(0),
send_critsect_(CriticalSectionWrapper::CreateCriticalSection()),
transport_(transport),
@@ -603,6 +607,9 @@
size_t bytes) {
size_t padding_bytes_in_packet = 0;
size_t bytes_sent = 0;
+ bool using_transport_seq = rtp_header_extension_map_.IsRegistered(
+ kRtpExtensionTransportSequenceNumber) &&
+ packet_router_;
for (; bytes > 0; bytes -= padding_bytes_in_packet) {
// Always send full padding packets.
if (bytes < kMaxPaddingLength)
@@ -659,8 +666,19 @@
}
UpdateAbsoluteSendTime(padding_packet, length, rtp_header, now_ms);
+
+ uint16_t transport_seq = 0;
+ if (using_transport_seq) {
+ transport_seq =
+ UpdateTransportSequenceNumber(padding_packet, length, rtp_header);
+ }
+
if (!SendPacketToNetwork(padding_packet, length))
break;
+
+ if (using_transport_seq)
+ send_time_observer_->OnPacketSent(transport_seq, now_ms);
+
bytes_sent += padding_bytes_in_packet;
UpdateRtpStats(padding_packet, length, rtp_header, over_rtx, false);
}
@@ -710,9 +728,11 @@
CriticalSectionScoped lock(send_critsect_.get());
rtx = rtx_;
}
- return PrepareAndSendPacket(data_buffer, length, capture_time_ms,
- (rtx & kRtxRetransmitted) > 0, true) ?
- static_cast<int32_t>(length) : -1;
+ if (!PrepareAndSendPacket(data_buffer, length, capture_time_ms,
+ (rtx & kRtxRetransmitted) > 0, true)) {
+ return -1;
+ }
+ return static_cast<int32_t>(length);
}
bool RTPSender::SendPacketToNetwork(const uint8_t *packet, size_t size) {
@@ -897,11 +917,23 @@
UpdateTransmissionTimeOffset(buffer_to_send_ptr, length, rtp_header,
diff_ms);
UpdateAbsoluteSendTime(buffer_to_send_ptr, length, rtp_header, now_ms);
+
+ uint16_t transport_seq = 0;
+ bool using_transport_seq = rtp_header_extension_map_.IsRegistered(
+ kRtpExtensionTransportSequenceNumber) &&
+ packet_router_;
+ if (using_transport_seq) {
+ transport_seq =
+ UpdateTransportSequenceNumber(buffer_to_send_ptr, length, rtp_header);
+ }
+
bool ret = SendPacketToNetwork(buffer_to_send_ptr, length);
if (ret) {
CriticalSectionScoped lock(send_critsect_.get());
media_has_been_sent_ = true;
}
+ if (using_transport_seq)
+ send_time_observer_->OnPacketSent(transport_seq, now_ms);
UpdateRtpStats(buffer_to_send_ptr, length, rtp_header, send_over_rtx,
is_retransmit);
return ret;
@@ -960,7 +992,8 @@
return 0;
{
CriticalSectionScoped cs(send_critsect_.get());
- if (!sending_media_) return 0;
+ if (!sending_media_)
+ return 0;
}
size_t bytes_sent = TrySendRedundantPayloads(bytes);
if (bytes_sent < bytes)
@@ -1212,7 +1245,8 @@
block_length = BuildVideoRotationExtension(extension_data);
break;
case kRtpExtensionTransportSequenceNumber:
- block_length = BuildTransportSequenceNumberExtension(extension_data);
+ block_length = BuildTransportSequenceNumberExtension(
+ extension_data, transport_sequence_number_);
break;
default:
assert(false);
@@ -1365,7 +1399,8 @@
}
uint8_t RTPSender::BuildTransportSequenceNumberExtension(
- uint8_t* data_buffer) const {
+ uint8_t* data_buffer,
+ uint16_t sequence_number) const {
// 0 1 2
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
@@ -1382,8 +1417,7 @@
size_t pos = 0;
const uint8_t len = 1;
data_buffer[pos++] = (id << 4) + len;
- ByteWriter<uint16_t>::WriteBigEndian(data_buffer + pos,
- transport_sequence_number_);
+ ByteWriter<uint16_t>::WriteBigEndian(data_buffer + pos, sequence_number);
pos += 2;
assert(pos == kTransportSequenceNumberLength);
return kTransportSequenceNumberLength;
@@ -1426,35 +1460,62 @@
return true;
}
+RTPSender::ExtensionStatus RTPSender::VerifyExtension(
+ RTPExtensionType extension_type,
+ uint8_t* rtp_packet,
+ size_t rtp_packet_length,
+ const RTPHeader& rtp_header,
+ size_t extension_length_bytes,
+ size_t* extension_offset) const {
+ // Get id.
+ uint8_t id = 0;
+ if (rtp_header_extension_map_.GetId(extension_type, &id) != 0)
+ return ExtensionStatus::kNotRegistered;
+
+ size_t block_pos = 0;
+ if (!FindHeaderExtensionPosition(extension_type, rtp_packet,
+ rtp_packet_length, rtp_header, &block_pos))
+ return ExtensionStatus::kError;
+
+ // Verify that header contains extension.
+ if (!((rtp_packet[kRtpHeaderLength + rtp_header.numCSRCs] == 0xBE) &&
+ (rtp_packet[kRtpHeaderLength + rtp_header.numCSRCs + 1] == 0xDE))) {
+ LOG(LS_WARNING)
+ << "Failed to update absolute send time, hdr extension not found.";
+ return ExtensionStatus::kError;
+ }
+
+ // Verify first byte in block.
+ const uint8_t first_block_byte = (id << 4) + (extension_length_bytes - 2);
+ if (rtp_packet[block_pos] != first_block_byte)
+ return ExtensionStatus::kError;
+
+ *extension_offset = block_pos;
+ return ExtensionStatus::kOk;
+}
+
void RTPSender::UpdateTransmissionTimeOffset(uint8_t* rtp_packet,
size_t rtp_packet_length,
const RTPHeader& rtp_header,
int64_t time_diff_ms) const {
+ size_t offset;
CriticalSectionScoped cs(send_critsect_.get());
- // Get id.
- uint8_t id = 0;
- if (rtp_header_extension_map_.GetId(kRtpExtensionTransmissionTimeOffset,
- &id) != 0) {
- // Not registered.
- return;
+ switch (VerifyExtension(kRtpExtensionTransmissionTimeOffset, rtp_packet,
+ rtp_packet_length, rtp_header,
+ kTransmissionTimeOffsetLength, &offset)) {
+ case ExtensionStatus::kNotRegistered:
+ return;
+ case ExtensionStatus::kError:
+ LOG(LS_WARNING) << "Failed to update transmission time offset.";
+ return;
+ case ExtensionStatus::kOk:
+ break;
+ default:
+ RTC_NOTREACHED();
}
- size_t block_pos = 0;
- if (!FindHeaderExtensionPosition(kRtpExtensionTransmissionTimeOffset,
- rtp_packet, rtp_packet_length, rtp_header,
- &block_pos)) {
- LOG(LS_WARNING) << "Failed to update transmission time offset.";
- return;
- }
-
- // Verify first byte in block.
- const uint8_t first_block_byte = (id << 4) + 2;
- if (rtp_packet[block_pos] != first_block_byte) {
- LOG(LS_WARNING) << "Failed to update transmission time offset.";
- return;
- }
// Update transmission offset field (converting to a 90 kHz timestamp).
- ByteWriter<int32_t, 3>::WriteBigEndian(rtp_packet + block_pos + 1,
+ ByteWriter<int32_t, 3>::WriteBigEndian(rtp_packet + offset + 1,
time_diff_ms * 90); // RTP timestamp.
}
@@ -1463,29 +1524,24 @@
const RTPHeader& rtp_header,
bool is_voiced,
uint8_t dBov) const {
+ size_t offset;
CriticalSectionScoped cs(send_critsect_.get());
- // Get id.
- uint8_t id = 0;
- if (rtp_header_extension_map_.GetId(kRtpExtensionAudioLevel, &id) != 0) {
- // Not registered.
- return false;
+ switch (VerifyExtension(kRtpExtensionAudioLevel, rtp_packet,
+ rtp_packet_length, rtp_header, kAudioLevelLength,
+ &offset)) {
+ case ExtensionStatus::kNotRegistered:
+ return false;
+ case ExtensionStatus::kError:
+ LOG(LS_WARNING) << "Failed to update audio level.";
+ return false;
+ case ExtensionStatus::kOk:
+ break;
+ default:
+ RTC_NOTREACHED();
}
- size_t block_pos = 0;
- if (!FindHeaderExtensionPosition(kRtpExtensionAudioLevel, rtp_packet,
- rtp_packet_length, rtp_header, &block_pos)) {
- LOG(LS_WARNING) << "Failed to update audio level.";
- return false;
- }
-
- // Verify first byte in block.
- const uint8_t first_block_byte = (id << 4) + 0;
- if (rtp_packet[block_pos] != first_block_byte) {
- LOG(LS_WARNING) << "Failed to update audio level.";
- return false;
- }
- rtp_packet[block_pos + 1] = (is_voiced ? 0x80 : 0x00) + (dBov & 0x7f);
+ rtp_packet[offset + 1] = (is_voiced ? 0x80 : 0x00) + (dBov & 0x7f);
return true;
}
@@ -1493,37 +1549,24 @@
size_t rtp_packet_length,
const RTPHeader& rtp_header,
VideoRotation rotation) const {
+ size_t offset;
CriticalSectionScoped cs(send_critsect_.get());
- // Get id.
- uint8_t id = 0;
- if (rtp_header_extension_map_.GetId(kRtpExtensionVideoRotation, &id) != 0) {
- // Not registered.
- return false;
+ switch (VerifyExtension(kRtpExtensionVideoRotation, rtp_packet,
+ rtp_packet_length, rtp_header, kVideoRotationLength,
+ &offset)) {
+ case ExtensionStatus::kNotRegistered:
+ return false;
+ case ExtensionStatus::kError:
+ LOG(LS_WARNING) << "Failed to update CVO.";
+ return false;
+ case ExtensionStatus::kOk:
+ break;
+ default:
+ RTC_NOTREACHED();
}
- size_t block_pos = 0;
- if (!FindHeaderExtensionPosition(kRtpExtensionVideoRotation, rtp_packet,
- rtp_packet_length, rtp_header, &block_pos)) {
- LOG(LS_WARNING) << "Failed to update video rotation (CVO).";
- return false;
- }
- // Get length until start of header extension block.
- int extension_block_pos =
- rtp_header_extension_map_.GetLengthUntilBlockStartInBytes(
- kRtpExtensionVideoRotation);
- if (extension_block_pos < 0) {
- // The feature is not enabled.
- return false;
- }
-
- // Verify first byte in block.
- const uint8_t first_block_byte = (id << 4) + 0;
- if (rtp_packet[block_pos] != first_block_byte) {
- LOG(LS_WARNING) << "Failed to update CVO.";
- return false;
- }
- rtp_packet[block_pos + 1] = ConvertVideoRotationToCVOByte(rotation);
+ rtp_packet[offset + 1] = ConvertVideoRotationToCVOByte(rotation);
return true;
}
@@ -1531,49 +1574,55 @@
size_t rtp_packet_length,
const RTPHeader& rtp_header,
int64_t now_ms) const {
+ size_t offset;
CriticalSectionScoped cs(send_critsect_.get());
- // Get id.
- uint8_t id = 0;
- if (rtp_header_extension_map_.GetId(kRtpExtensionAbsoluteSendTime,
- &id) != 0) {
- // Not registered.
- return;
+ switch (VerifyExtension(kRtpExtensionAbsoluteSendTime, rtp_packet,
+ rtp_packet_length, rtp_header,
+ kAbsoluteSendTimeLength, &offset)) {
+ case ExtensionStatus::kNotRegistered:
+ return;
+ case ExtensionStatus::kError:
+ LOG(LS_WARNING) << "Failed to update absolute send time";
+ return;
+ case ExtensionStatus::kOk:
+ break;
+ default:
+ RTC_NOTREACHED();
}
- // Get length until start of header extension block.
- int extension_block_pos =
- rtp_header_extension_map_.GetLengthUntilBlockStartInBytes(
- kRtpExtensionAbsoluteSendTime);
- if (extension_block_pos < 0) {
- // The feature is not enabled.
- return;
- }
- size_t block_pos =
- kRtpHeaderLength + rtp_header.numCSRCs + extension_block_pos;
- if (rtp_packet_length < block_pos + kAbsoluteSendTimeLength ||
- rtp_header.headerLength < block_pos + kAbsoluteSendTimeLength) {
- LOG(LS_WARNING) << "Failed to update absolute send time, invalid length.";
- return;
- }
- // Verify that header contains extension.
- if (!((rtp_packet[kRtpHeaderLength + rtp_header.numCSRCs] == 0xBE) &&
- (rtp_packet[kRtpHeaderLength + rtp_header.numCSRCs + 1] == 0xDE))) {
- LOG(LS_WARNING)
- << "Failed to update absolute send time, hdr extension not found.";
- return;
- }
- // Verify first byte in block.
- const uint8_t first_block_byte = (id << 4) + 2;
- if (rtp_packet[block_pos] != first_block_byte) {
- LOG(LS_WARNING) << "Failed to update absolute send time.";
- return;
- }
+
// Update absolute send time field (convert ms to 24-bit unsigned with 18 bit
// fractional part).
- ByteWriter<uint32_t, 3>::WriteBigEndian(rtp_packet + block_pos + 1,
+ ByteWriter<uint32_t, 3>::WriteBigEndian(rtp_packet + offset + 1,
((now_ms << 18) / 1000) & 0x00ffffff);
}
+uint16_t RTPSender::UpdateTransportSequenceNumber(
+ uint8_t* rtp_packet,
+ size_t rtp_packet_length,
+ const RTPHeader& rtp_header) const {
+ size_t offset;
+ CriticalSectionScoped cs(send_critsect_.get());
+
+ switch (VerifyExtension(kRtpExtensionTransportSequenceNumber, rtp_packet,
+ rtp_packet_length, rtp_header,
+ kTransportSequenceNumberLength, &offset)) {
+ case ExtensionStatus::kNotRegistered:
+ return 0;
+ case ExtensionStatus::kError:
+ LOG(LS_WARNING) << "Failed to update transport sequence number";
+ return 0;
+ case ExtensionStatus::kOk:
+ break;
+ default:
+ RTC_NOTREACHED();
+ }
+
+ uint16_t seq = packet_router_->AllocateSequenceNumber();
+ BuildTransportSequenceNumberExtension(rtp_packet + offset, seq);
+ return seq;
+}
+
void RTPSender::SetSendingStatus(bool enabled) {
if (enabled) {
uint32_t frequency_hz = SendPayloadFrequency();
diff --git a/webrtc/modules/rtp_rtcp/source/rtp_sender.h b/webrtc/modules/rtp_rtcp/source/rtp_sender.h
index a470398..3b93ae4 100644
--- a/webrtc/modules/rtp_rtcp/source/rtp_sender.h
+++ b/webrtc/modules/rtp_rtcp/source/rtp_sender.h
@@ -18,6 +18,7 @@
#include "webrtc/base/thread_annotations.h"
#include "webrtc/common_types.h"
#include "webrtc/modules/pacing/include/paced_sender.h"
+#include "webrtc/modules/pacing/include/packet_router.h"
#include "webrtc/modules/rtp_rtcp/interface/rtp_rtcp_defines.h"
#include "webrtc/modules/rtp_rtcp/source/bitrate.h"
#include "webrtc/modules/rtp_rtcp/source/rtp_header_extension.h"
@@ -91,6 +92,8 @@
Transport* transport,
RtpAudioFeedback* audio_feedback,
PacedSender* paced_sender,
+ PacketRouter* packet_router,
+ SendTimeObserver* send_time_observer,
BitrateStatisticsObserver* bitrate_callback,
FrameCountObserver* frame_count_observer,
SendSideDelayObserver* send_side_delay_observer);
@@ -171,7 +174,27 @@
uint8_t BuildAudioLevelExtension(uint8_t* data_buffer) const;
uint8_t BuildAbsoluteSendTimeExtension(uint8_t* data_buffer) const;
uint8_t BuildVideoRotationExtension(uint8_t* data_buffer) const;
- uint8_t BuildTransportSequenceNumberExtension(uint8_t* data_buffer) const;
+ uint8_t BuildTransportSequenceNumberExtension(uint8_t* data_buffer,
+ uint16_t sequence_number) const;
+
+ // Verifies that the specified extension is registered, and that it is
+ // present in rtp packet. If extension is not registered kNotRegistered is
+ // returned. If extension cannot be found in the rtp header, or if it is
+ // malformed, kError is returned. Otherwise *extension_offset is set to the
+ // offset of the extension from the beginning of the rtp packet and kOk is
+ // returned.
+ enum class ExtensionStatus {
+ kNotRegistered,
+ kOk,
+ kError,
+ };
+ ExtensionStatus VerifyExtension(RTPExtensionType extension_type,
+ uint8_t* rtp_packet,
+ size_t rtp_packet_length,
+ const RTPHeader& rtp_header,
+ size_t extension_length_bytes,
+ size_t* extension_offset) const
+ EXCLUSIVE_LOCKS_REQUIRED(send_critsect_.get());
bool UpdateAudioLevel(uint8_t* rtp_packet,
size_t rtp_packet_length,
@@ -345,6 +368,12 @@
size_t rtp_packet_length,
const RTPHeader& rtp_header,
int64_t now_ms) const;
+ // Update the transport sequence number of the packet using a new sequence
+ // number allocated by PacketRouter. Returns the assigned sequence number,
+ // or 0 if extension could not be updated.
+ uint16_t UpdateTransportSequenceNumber(uint8_t* rtp_packet,
+ size_t rtp_packet_length,
+ const RTPHeader& rtp_header) const;
void UpdateRtpStats(const uint8_t* buffer,
size_t packet_length,
@@ -365,7 +394,9 @@
rtc::scoped_ptr<RTPSenderAudio> audio_;
rtc::scoped_ptr<RTPSenderVideo> video_;
- PacedSender *paced_sender_;
+ PacedSender* const paced_sender_;
+ PacketRouter* const packet_router_;
+ SendTimeObserver* const send_time_observer_;
int64_t last_capture_time_ms_sent_;
rtc::scoped_ptr<CriticalSectionWrapper> send_critsect_;
diff --git a/webrtc/modules/rtp_rtcp/source/rtp_sender_unittest.cc b/webrtc/modules/rtp_rtcp/source/rtp_sender_unittest.cc
index 23300bb..ea6fb6a 100644
--- a/webrtc/modules/rtp_rtcp/source/rtp_sender_unittest.cc
+++ b/webrtc/modules/rtp_rtcp/source/rtp_sender_unittest.cc
@@ -73,7 +73,7 @@
: packets_sent_(0),
last_sent_packet_len_(0),
total_bytes_sent_(0),
- last_sent_packet_(NULL) {}
+ last_sent_packet_(nullptr) {}
~LoopbackTransportTest() {
STLDeleteContainerPointers(sent_packets_.begin(), sent_packets_.end());
@@ -114,8 +114,9 @@
}
void SetUp() override {
- rtp_sender_.reset(new RTPSender(0, false, &fake_clock_, &transport_, NULL,
- &mock_paced_sender_, NULL, NULL, NULL));
+ rtp_sender_.reset(new RTPSender(0, false, &fake_clock_, &transport_,
+ nullptr, &mock_paced_sender_, nullptr,
+ nullptr, nullptr, nullptr, nullptr));
rtp_sender_->SetSequenceNumber(kSeqNum);
}
@@ -308,7 +309,7 @@
webrtc::RtpUtility::RtpHeaderParser rtp_parser(packet_, length);
webrtc::RTPHeader rtp_header;
- const bool valid_rtp_header = rtp_parser.Parse(rtp_header, NULL);
+ const bool valid_rtp_header = rtp_parser.Parse(rtp_header, nullptr);
ASSERT_TRUE(valid_rtp_header);
ASSERT_FALSE(rtp_parser.RTCP());
@@ -351,7 +352,7 @@
// Parse without map extension
webrtc::RTPHeader rtp_header2;
- const bool valid_rtp_header2 = rtp_parser.Parse(rtp_header2, NULL);
+ const bool valid_rtp_header2 = rtp_parser.Parse(rtp_header2, nullptr);
ASSERT_TRUE(valid_rtp_header2);
VerifyRTPHeaderCommon(rtp_header2);
@@ -415,7 +416,7 @@
// Parse without map extension
webrtc::RTPHeader rtp_header2;
- const bool valid_rtp_header2 = rtp_parser.Parse(rtp_header2, NULL);
+ const bool valid_rtp_header2 = rtp_parser.Parse(rtp_header2, nullptr);
ASSERT_TRUE(valid_rtp_header2);
VerifyRTPHeaderCommon(rtp_header2);
@@ -509,7 +510,7 @@
// Parse without map extension
webrtc::RTPHeader rtp_header2;
- const bool valid_rtp_header2 = rtp_parser.Parse(rtp_header2, NULL);
+ const bool valid_rtp_header2 = rtp_parser.Parse(rtp_header2, nullptr);
ASSERT_TRUE(valid_rtp_header2);
VerifyRTPHeaderCommon(rtp_header2);
@@ -571,7 +572,7 @@
// Parse without map extension
webrtc::RTPHeader rtp_header2;
- const bool valid_rtp_header2 = rtp_parser.Parse(rtp_header2, NULL);
+ const bool valid_rtp_header2 = rtp_parser.Parse(rtp_header2, nullptr);
ASSERT_TRUE(valid_rtp_header2);
VerifyRTPHeaderCommon(rtp_header2);
@@ -724,7 +725,7 @@
// Create and set up parser.
rtc::scoped_ptr<webrtc::RtpHeaderParser> rtp_parser(
webrtc::RtpHeaderParser::Create());
- ASSERT_TRUE(rtp_parser.get() != NULL);
+ ASSERT_TRUE(rtp_parser.get() != nullptr);
rtp_parser->RegisterRtpHeaderExtension(kRtpExtensionTransmissionTimeOffset,
kTransmissionTimeOffsetExtensionId);
rtp_parser->RegisterRtpHeaderExtension(kRtpExtensionAbsoluteSendTime,
@@ -822,8 +823,9 @@
TEST_F(RtpSenderTest, SendRedundantPayloads) {
MockTransport transport;
- rtp_sender_.reset(new RTPSender(0, false, &fake_clock_, &transport, NULL,
- &mock_paced_sender_, NULL, NULL, NULL));
+ rtp_sender_.reset(new RTPSender(0, false, &fake_clock_, &transport, nullptr,
+ &mock_paced_sender_, nullptr, nullptr,
+ nullptr, nullptr, nullptr));
rtp_sender_->SetSequenceNumber(kSeqNum);
rtp_sender_->SetRtxPayloadType(kRtxPayload, kPayload);
// Make all packets go through the pacer.
@@ -845,7 +847,7 @@
// Create and set up parser.
rtc::scoped_ptr<webrtc::RtpHeaderParser> rtp_parser(
webrtc::RtpHeaderParser::Create());
- ASSERT_TRUE(rtp_parser.get() != NULL);
+ ASSERT_TRUE(rtp_parser.get() != nullptr);
rtp_parser->RegisterRtpHeaderExtension(kRtpExtensionTransmissionTimeOffset,
kTransmissionTimeOffsetExtensionId);
rtp_parser->RegisterRtpHeaderExtension(kRtpExtensionAbsoluteSendTime,
@@ -891,9 +893,9 @@
uint8_t payload[] = {47, 11, 32, 93, 89};
// Send keyframe
- ASSERT_EQ(0, rtp_sender_->SendOutgoingData(kVideoFrameKey, payload_type, 1234,
- 4321, payload, sizeof(payload),
- NULL));
+ ASSERT_EQ(
+ 0, rtp_sender_->SendOutgoingData(kVideoFrameKey, payload_type, 1234, 4321,
+ payload, sizeof(payload), nullptr));
RtpUtility::RtpHeaderParser rtp_parser(transport_.last_sent_packet_,
transport_.last_sent_packet_len_);
@@ -919,7 +921,7 @@
ASSERT_EQ(0, rtp_sender_->SendOutgoingData(kVideoFrameDelta, payload_type,
1234, 4321, payload,
- sizeof(payload), NULL));
+ sizeof(payload), nullptr));
RtpUtility::RtpHeaderParser rtp_parser2(transport_.last_sent_packet_,
transport_.last_sent_packet_len_);
@@ -955,8 +957,9 @@
FrameCounts frame_counts_;
} callback;
- rtp_sender_.reset(new RTPSender(0, false, &fake_clock_, &transport_, NULL,
- &mock_paced_sender_, NULL, &callback, NULL));
+ rtp_sender_.reset(new RTPSender(0, false, &fake_clock_, &transport_, nullptr,
+ &mock_paced_sender_, nullptr, nullptr,
+ nullptr, &callback, nullptr));
char payload_name[RTP_PAYLOAD_NAME_SIZE] = "GENERIC";
const uint8_t payload_type = 127;
@@ -966,18 +969,18 @@
rtp_sender_->SetStorePacketsStatus(true, 1);
uint32_t ssrc = rtp_sender_->SSRC();
- ASSERT_EQ(0, rtp_sender_->SendOutgoingData(kVideoFrameKey, payload_type, 1234,
- 4321, payload, sizeof(payload),
- NULL));
+ ASSERT_EQ(
+ 0, rtp_sender_->SendOutgoingData(kVideoFrameKey, payload_type, 1234, 4321,
+ payload, sizeof(payload), nullptr));
EXPECT_EQ(1U, callback.num_calls_);
EXPECT_EQ(ssrc, callback.ssrc_);
EXPECT_EQ(1, callback.frame_counts_.key_frames);
EXPECT_EQ(0, callback.frame_counts_.delta_frames);
- ASSERT_EQ(0, rtp_sender_->SendOutgoingData(kVideoFrameDelta,
- payload_type, 1234, 4321, payload,
- sizeof(payload), NULL));
+ ASSERT_EQ(0, rtp_sender_->SendOutgoingData(kVideoFrameDelta, payload_type,
+ 1234, 4321, payload,
+ sizeof(payload), nullptr));
EXPECT_EQ(2U, callback.num_calls_);
EXPECT_EQ(ssrc, callback.ssrc_);
@@ -1007,8 +1010,9 @@
BitrateStatistics total_stats_;
BitrateStatistics retransmit_stats_;
} callback;
- rtp_sender_.reset(new RTPSender(0, false, &fake_clock_, &transport_, NULL,
- &mock_paced_sender_, &callback, NULL, NULL));
+ rtp_sender_.reset(new RTPSender(0, false, &fake_clock_, &transport_, nullptr,
+ &mock_paced_sender_, nullptr, nullptr,
+ &callback, nullptr, nullptr));
// Simulate kNumPackets sent with kPacketInterval ms intervals.
const uint32_t kNumPackets = 15;
@@ -1065,8 +1069,9 @@
void SetUp() override {
payload_ = kAudioPayload;
- rtp_sender_.reset(new RTPSender(0, true, &fake_clock_, &transport_, NULL,
- &mock_paced_sender_, NULL, NULL, NULL));
+ rtp_sender_.reset(new RTPSender(0, true, &fake_clock_, &transport_, nullptr,
+ &mock_paced_sender_, nullptr, nullptr,
+ nullptr, nullptr, nullptr));
rtp_sender_->SetSequenceNumber(kSeqNum);
}
};
@@ -1117,9 +1122,9 @@
rtp_sender_->RegisterRtpStatisticsCallback(&callback);
// Send a frame.
- ASSERT_EQ(0, rtp_sender_->SendOutgoingData(kVideoFrameKey, payload_type, 1234,
- 4321, payload, sizeof(payload),
- NULL));
+ ASSERT_EQ(
+ 0, rtp_sender_->SendOutgoingData(kVideoFrameKey, payload_type, 1234, 4321,
+ payload, sizeof(payload), nullptr));
StreamDataCounters expected;
expected.transmitted.payload_bytes = 6;
expected.transmitted.header_bytes = 12;
@@ -1162,14 +1167,14 @@
rtp_sender_->SetFecParameters(&fec_params, &fec_params);
ASSERT_EQ(0, rtp_sender_->SendOutgoingData(kVideoFrameDelta, payload_type,
1234, 4321, payload,
- sizeof(payload), NULL));
+ sizeof(payload), nullptr));
expected.transmitted.payload_bytes = 40;
expected.transmitted.header_bytes = 60;
expected.transmitted.packets = 5;
expected.fec.packets = 1;
callback.Matches(ssrc, expected);
- rtp_sender_->RegisterRtpStatisticsCallback(NULL);
+ rtp_sender_->RegisterRtpStatisticsCallback(nullptr);
}
TEST_F(RtpSenderAudioTest, SendAudio) {
@@ -1179,9 +1184,9 @@
0, 1500));
uint8_t payload[] = {47, 11, 32, 93, 89};
- ASSERT_EQ(0, rtp_sender_->SendOutgoingData(kAudioFrameCN, payload_type, 1234,
- 4321, payload, sizeof(payload),
- NULL));
+ ASSERT_EQ(
+ 0, rtp_sender_->SendOutgoingData(kAudioFrameCN, payload_type, 1234, 4321,
+ payload, sizeof(payload), nullptr));
RtpUtility::RtpHeaderParser rtp_parser(transport_.last_sent_packet_,
transport_.last_sent_packet_len_);
@@ -1208,9 +1213,9 @@
0, 1500));
uint8_t payload[] = {47, 11, 32, 93, 89};
- ASSERT_EQ(0, rtp_sender_->SendOutgoingData(kAudioFrameCN, payload_type, 1234,
- 4321, payload, sizeof(payload),
- NULL));
+ ASSERT_EQ(
+ 0, rtp_sender_->SendOutgoingData(kAudioFrameCN, payload_type, 1234, 4321,
+ payload, sizeof(payload), nullptr));
RtpUtility::RtpHeaderParser rtp_parser(transport_.last_sent_packet_,
transport_.last_sent_packet_len_);
@@ -1259,19 +1264,17 @@
// The duration is calculated as the difference of current and last sent
// timestamp. So for first call it will skip since the duration is zero.
ASSERT_EQ(0, rtp_sender_->SendOutgoingData(kFrameEmpty, payload_type,
- capture_time_ms,
- 0, NULL, 0,
- NULL));
+ capture_time_ms, 0, nullptr, 0,
+ nullptr));
// DTMF Sample Length is (Frequency/1000) * Duration.
// So in this case, it is (8000/1000) * 500 = 4000.
// Sending it as two packets.
ASSERT_EQ(0, rtp_sender_->SendOutgoingData(kFrameEmpty, payload_type,
- capture_time_ms+2000,
- 0, NULL, 0,
- NULL));
+ capture_time_ms + 2000, 0, nullptr,
+ 0, nullptr));
rtc::scoped_ptr<webrtc::RtpHeaderParser> rtp_parser(
webrtc::RtpHeaderParser::Create());
- ASSERT_TRUE(rtp_parser.get() != NULL);
+ ASSERT_TRUE(rtp_parser.get() != nullptr);
webrtc::RTPHeader rtp_header;
ASSERT_TRUE(rtp_parser->Parse(transport_.last_sent_packet_,
transport_.last_sent_packet_len_,
@@ -1280,9 +1283,8 @@
EXPECT_TRUE(rtp_header.markerBit);
ASSERT_EQ(0, rtp_sender_->SendOutgoingData(kFrameEmpty, payload_type,
- capture_time_ms+4000,
- 0, NULL, 0,
- NULL));
+ capture_time_ms + 4000, 0, nullptr,
+ 0, nullptr));
ASSERT_TRUE(rtp_parser->Parse(transport_.last_sent_packet_,
transport_.last_sent_packet_len_,
&rtp_header));
@@ -1357,7 +1359,7 @@
rtp_sender_->RtpHeaderExtensionTotalLength());
rtp_sender_video_->SendVideo(kRtpVideoGeneric, kVideoFrameKey, kPayload,
- kTimestamp, 0, packet_, sizeof(packet_), NULL,
+ kTimestamp, 0, packet_, sizeof(packet_), nullptr,
&hdr);
RtpHeaderExtensionMap map;
diff --git a/webrtc/test/frame_generator_capturer.cc b/webrtc/test/frame_generator_capturer.cc
index fcab602..b991414 100644
--- a/webrtc/test/frame_generator_capturer.cc
+++ b/webrtc/test/frame_generator_capturer.cc
@@ -129,5 +129,9 @@
rtc::CritScope cs(&lock_);
sending_ = false;
}
+
+void FrameGeneratorCapturer::ForceFrame() {
+ tick_->Set();
+}
} // test
} // webrtc
diff --git a/webrtc/test/frame_generator_capturer.h b/webrtc/test/frame_generator_capturer.h
index 86df689..aff906d 100644
--- a/webrtc/test/frame_generator_capturer.h
+++ b/webrtc/test/frame_generator_capturer.h
@@ -45,6 +45,7 @@
void Start() override;
void Stop() override;
+ void ForceFrame();
int64_t first_frame_capture_time() const { return first_frame_capture_time_; }
diff --git a/webrtc/video/audio_receive_stream.cc b/webrtc/video/audio_receive_stream.cc
index 9f8bebe..6731ea4 100644
--- a/webrtc/video/audio_receive_stream.cc
+++ b/webrtc/video/audio_receive_stream.cc
@@ -61,6 +61,9 @@
} else if (ext.name == RtpExtension::kAbsSendTime) {
CHECK(rtp_header_parser_->RegisterRtpHeaderExtension(
kRtpExtensionAbsoluteSendTime, ext.id));
+ } else if (ext.name == RtpExtension::kTransportSequenceNumber) {
+ CHECK(rtp_header_parser_->RegisterRtpHeaderExtension(
+ kRtpExtensionTransportSequenceNumber, ext.id));
} else {
RTC_NOTREACHED() << "Unsupported RTP extension.";
}
diff --git a/webrtc/video/call_perf_tests.cc b/webrtc/video/call_perf_tests.cc
index fd159f5..cf65ea0 100644
--- a/webrtc/video/call_perf_tests.cc
+++ b/webrtc/video/call_perf_tests.cc
@@ -528,6 +528,7 @@
static const int kMinAcceptableTransmitBitrate = 130;
static const int kMaxAcceptableTransmitBitrate = 170;
static const int kNumBitrateObservationsInRange = 100;
+ static const int kAcceptableBitrateErrorMargin = 15; // +- 7
class BitrateObserver : public test::EndToEndTest, public PacketReceiver {
public:
explicit BitrateObserver(bool using_min_transmit_bitrate)
@@ -567,8 +568,10 @@
}
} else {
// Expect bitrate stats to roughly match the max encode bitrate.
- if (bitrate_kbps > kMaxEncodeBitrateKbps - 5 &&
- bitrate_kbps < kMaxEncodeBitrateKbps + 5) {
+ if (bitrate_kbps > (kMaxEncodeBitrateKbps -
+ kAcceptableBitrateErrorMargin / 2) &&
+ bitrate_kbps < (kMaxEncodeBitrateKbps +
+ kAcceptableBitrateErrorMargin / 2)) {
++num_bitrate_observations_in_range_;
}
}
@@ -629,7 +632,9 @@
: EndToEndTest(kDefaultTimeoutMs),
FakeEncoder(Clock::GetRealTimeClock()),
time_to_reconfigure_(webrtc::EventWrapper::Create()),
- encoder_inits_(0) {}
+ encoder_inits_(0),
+ last_set_bitrate_(0),
+ send_stream_(nullptr) {}
int32_t InitEncode(const VideoCodec* config,
int32_t number_of_cores,
diff --git a/webrtc/video/end_to_end_tests.cc b/webrtc/video/end_to_end_tests.cc
index 416c8dd..36206fa 100644
--- a/webrtc/video/end_to_end_tests.cc
+++ b/webrtc/video/end_to_end_tests.cc
@@ -1133,120 +1133,304 @@
// Test sets up a Call multiple senders with different resolutions and SSRCs.
// Another is set up to receive all three of these with different renderers.
+class MultiStreamTest {
+ public:
+ static const size_t kNumStreams = 3;
+ struct CodecSettings {
+ uint32_t ssrc;
+ int width;
+ int height;
+ } codec_settings[kNumStreams];
+
+ MultiStreamTest() {
+ // TODO(sprang): Cleanup when msvc supports explicit initializers for array.
+ codec_settings[0] = {1, 640, 480};
+ codec_settings[1] = {2, 320, 240};
+ codec_settings[2] = {3, 240, 160};
+ }
+
+ virtual ~MultiStreamTest() {}
+
+ void RunTest() {
+ rtc::scoped_ptr<test::DirectTransport> sender_transport(
+ CreateSendTransport());
+ rtc::scoped_ptr<test::DirectTransport> receiver_transport(
+ CreateReceiveTransport());
+
+ rtc::scoped_ptr<Call> sender_call(
+ Call::Create(Call::Config(sender_transport.get())));
+ rtc::scoped_ptr<Call> receiver_call(
+ Call::Create(Call::Config(receiver_transport.get())));
+ sender_transport->SetReceiver(receiver_call->Receiver());
+ receiver_transport->SetReceiver(sender_call->Receiver());
+
+ rtc::scoped_ptr<VideoEncoder> encoders[kNumStreams];
+ for (size_t i = 0; i < kNumStreams; ++i)
+ encoders[i].reset(VideoEncoder::Create(VideoEncoder::kVp8));
+
+ VideoSendStream* send_streams[kNumStreams];
+ VideoReceiveStream* receive_streams[kNumStreams];
+
+ test::FrameGeneratorCapturer* frame_generators[kNumStreams];
+ ScopedVector<VideoDecoder> allocated_decoders;
+ for (size_t i = 0; i < kNumStreams; ++i) {
+ uint32_t ssrc = codec_settings[i].ssrc;
+ int width = codec_settings[i].width;
+ int height = codec_settings[i].height;
+
+ VideoSendStream::Config send_config;
+ send_config.rtp.ssrcs.push_back(ssrc);
+ send_config.encoder_settings.encoder = encoders[i].get();
+ send_config.encoder_settings.payload_name = "VP8";
+ send_config.encoder_settings.payload_type = 124;
+ VideoEncoderConfig encoder_config;
+ encoder_config.streams = test::CreateVideoStreams(1);
+ VideoStream* stream = &encoder_config.streams[0];
+ stream->width = width;
+ stream->height = height;
+ stream->max_framerate = 5;
+ stream->min_bitrate_bps = stream->target_bitrate_bps =
+ stream->max_bitrate_bps = 100000;
+
+ UpdateSendConfig(i, &send_config, &encoder_config, &frame_generators[i]);
+
+ send_streams[i] =
+ sender_call->CreateVideoSendStream(send_config, encoder_config);
+ send_streams[i]->Start();
+
+ VideoReceiveStream::Config receive_config;
+ receive_config.rtp.remote_ssrc = ssrc;
+ receive_config.rtp.local_ssrc = test::CallTest::kReceiverLocalSsrc;
+ VideoReceiveStream::Decoder decoder =
+ test::CreateMatchingDecoder(send_config.encoder_settings);
+ allocated_decoders.push_back(decoder.decoder);
+ receive_config.decoders.push_back(decoder);
+
+ UpdateReceiveConfig(i, &receive_config);
+
+ receive_streams[i] =
+ receiver_call->CreateVideoReceiveStream(receive_config);
+ receive_streams[i]->Start();
+
+ frame_generators[i] = test::FrameGeneratorCapturer::Create(
+ send_streams[i]->Input(), width, height, 30,
+ Clock::GetRealTimeClock());
+ frame_generators[i]->Start();
+ }
+
+ Wait();
+
+ for (size_t i = 0; i < kNumStreams; ++i) {
+ frame_generators[i]->Stop();
+ sender_call->DestroyVideoSendStream(send_streams[i]);
+ receiver_call->DestroyVideoReceiveStream(receive_streams[i]);
+ delete frame_generators[i];
+ }
+
+ sender_transport->StopSending();
+ receiver_transport->StopSending();
+ }
+
+ protected:
+ virtual void Wait() = 0;
+ // Note: frame_generator is a point-to-pointer, since the actual instance
+ // hasn't been created at the time of this call. Only when packets/frames
+ // start flowing should this be dereferenced.
+ virtual void UpdateSendConfig(
+ size_t stream_index,
+ VideoSendStream::Config* send_config,
+ VideoEncoderConfig* encoder_config,
+ test::FrameGeneratorCapturer** frame_generator) {}
+ virtual void UpdateReceiveConfig(size_t stream_index,
+ VideoReceiveStream::Config* receive_config) {
+ }
+ virtual test::DirectTransport* CreateSendTransport() {
+ return new test::DirectTransport();
+ }
+ virtual test::DirectTransport* CreateReceiveTransport() {
+ return new test::DirectTransport();
+ }
+};
+
// Each renderer verifies that it receives the expected resolution, and as soon
// as every renderer has received a frame, the test finishes.
TEST_F(EndToEndTest, SendsAndReceivesMultipleStreams) {
- static const size_t kNumStreams = 3;
-
class VideoOutputObserver : public VideoRenderer {
public:
- VideoOutputObserver(test::FrameGeneratorCapturer** capturer,
- int width,
- int height)
- : capturer_(capturer),
- width_(width),
- height_(height),
+ VideoOutputObserver(const MultiStreamTest::CodecSettings& settings,
+ uint32_t ssrc,
+ test::FrameGeneratorCapturer** frame_generator)
+ : settings_(settings),
+ ssrc_(ssrc),
+ frame_generator_(frame_generator),
done_(EventWrapper::Create()) {}
void RenderFrame(const VideoFrame& video_frame,
int time_to_render_ms) override {
- EXPECT_EQ(width_, video_frame.width());
- EXPECT_EQ(height_, video_frame.height());
- (*capturer_)->Stop();
+ EXPECT_EQ(settings_.width, video_frame.width());
+ EXPECT_EQ(settings_.height, video_frame.height());
+ (*frame_generator_)->Stop();
done_->Set();
}
+ uint32_t Ssrc() { return ssrc_; }
+
bool IsTextureSupported() const override { return false; }
EventTypeWrapper Wait() { return done_->Wait(kDefaultTimeoutMs); }
private:
- test::FrameGeneratorCapturer** capturer_;
- int width_;
- int height_;
+ const MultiStreamTest::CodecSettings& settings_;
+ const uint32_t ssrc_;
+ test::FrameGeneratorCapturer** const frame_generator_;
rtc::scoped_ptr<EventWrapper> done_;
};
- struct {
- uint32_t ssrc;
- int width;
- int height;
- } codec_settings[kNumStreams] = {{1, 640, 480}, {2, 320, 240}, {3, 240, 160}};
+ class Tester : public MultiStreamTest {
+ public:
+ Tester() {}
+ virtual ~Tester() {}
- test::DirectTransport sender_transport, receiver_transport;
- rtc::scoped_ptr<Call> sender_call(
- Call::Create(Call::Config(&sender_transport)));
- rtc::scoped_ptr<Call> receiver_call(
- Call::Create(Call::Config(&receiver_transport)));
- sender_transport.SetReceiver(receiver_call->Receiver());
- receiver_transport.SetReceiver(sender_call->Receiver());
+ protected:
+ void Wait() override {
+ for (const auto& observer : observers_) {
+ EXPECT_EQ(EventTypeWrapper::kEventSignaled, observer->Wait())
+ << "Time out waiting for from on ssrc " << observer->Ssrc();
+ }
+ }
- VideoSendStream* send_streams[kNumStreams];
- VideoReceiveStream* receive_streams[kNumStreams];
+ void UpdateSendConfig(
+ size_t stream_index,
+ VideoSendStream::Config* send_config,
+ VideoEncoderConfig* encoder_config,
+ test::FrameGeneratorCapturer** frame_generator) override {
+ observers_[stream_index].reset(new VideoOutputObserver(
+ codec_settings[stream_index], send_config->rtp.ssrcs.front(),
+ frame_generator));
+ }
- VideoOutputObserver* observers[kNumStreams];
- test::FrameGeneratorCapturer* frame_generators[kNumStreams];
+ void UpdateReceiveConfig(
+ size_t stream_index,
+ VideoReceiveStream::Config* receive_config) override {
+ receive_config->renderer = observers_[stream_index].get();
+ }
- rtc::scoped_ptr<VideoEncoder> encoders[kNumStreams];
- for (size_t i = 0; i < kNumStreams; ++i)
- encoders[i].reset(VideoEncoder::Create(VideoEncoder::kVp8));
+ private:
+ rtc::scoped_ptr<VideoOutputObserver> observers_[kNumStreams];
+ } tester;
- ScopedVector<VideoDecoder> allocated_decoders;
- for (size_t i = 0; i < kNumStreams; ++i) {
- uint32_t ssrc = codec_settings[i].ssrc;
- int width = codec_settings[i].width;
- int height = codec_settings[i].height;
- observers[i] = new VideoOutputObserver(&frame_generators[i], width, height);
+ tester.RunTest();
+}
- VideoSendStream::Config send_config;
- send_config.rtp.ssrcs.push_back(ssrc);
- send_config.encoder_settings.encoder = encoders[i].get();
- send_config.encoder_settings.payload_name = "VP8";
- send_config.encoder_settings.payload_type = 124;
- VideoEncoderConfig encoder_config;
- encoder_config.streams = test::CreateVideoStreams(1);
- VideoStream* stream = &encoder_config.streams[0];
- stream->width = width;
- stream->height = height;
- stream->max_framerate = 5;
- stream->min_bitrate_bps = stream->target_bitrate_bps =
- stream->max_bitrate_bps = 100000;
- send_streams[i] =
- sender_call->CreateVideoSendStream(send_config, encoder_config);
- send_streams[i]->Start();
+TEST_F(EndToEndTest, AssignsTransportSequenceNumbers) {
+ // TODO(sprang): Extend this to verify received values once send-side BWE
+ // is in place.
- VideoReceiveStream::Config receive_config;
- receive_config.renderer = observers[i];
- receive_config.rtp.remote_ssrc = ssrc;
- receive_config.rtp.local_ssrc = kReceiverLocalSsrc;
- VideoReceiveStream::Decoder decoder =
- test::CreateMatchingDecoder(send_config.encoder_settings);
- allocated_decoders.push_back(decoder.decoder);
- receive_config.decoders.push_back(decoder);
- receive_streams[i] =
- receiver_call->CreateVideoReceiveStream(receive_config);
- receive_streams[i]->Start();
+ static const int kExtensionId = 5;
- frame_generators[i] = test::FrameGeneratorCapturer::Create(
- send_streams[i]->Input(), width, height, 30, Clock::GetRealTimeClock());
- frame_generators[i]->Start();
- }
+ class RtpExtensionHeaderObserver : public test::DirectTransport {
+ public:
+ RtpExtensionHeaderObserver()
+ : done_(EventWrapper::Create()),
+ parser_(RtpHeaderParser::Create()),
+ last_seq_(0),
+ padding_observed_(false),
+ rtx_padding_observed_(false) {
+ parser_->RegisterRtpHeaderExtension(kRtpExtensionTransportSequenceNumber,
+ kExtensionId);
+ }
+ virtual ~RtpExtensionHeaderObserver() {}
- for (size_t i = 0; i < kNumStreams; ++i) {
- EXPECT_EQ(kEventSignaled, observers[i]->Wait())
- << "Timed out while waiting for observer " << i << " to render.";
- }
+ bool SendRtp(const uint8_t* data, size_t length) override {
+ RTPHeader header;
+ EXPECT_TRUE(parser_->Parse(data, length, &header));
+ if (header.extension.hasTransportSequenceNumber) {
+ if (!streams_observed_.empty()) {
+ EXPECT_EQ(static_cast<uint16_t>(last_seq_ + 1),
+ header.extension.transportSequenceNumber);
+ }
+ last_seq_ = header.extension.transportSequenceNumber;
- for (size_t i = 0; i < kNumStreams; ++i) {
- frame_generators[i]->Stop();
- sender_call->DestroyVideoSendStream(send_streams[i]);
- receiver_call->DestroyVideoReceiveStream(receive_streams[i]);
- delete frame_generators[i];
- delete observers[i];
- }
+ size_t payload_length =
+ length - (header.headerLength + header.paddingLength);
+ if (payload_length == 0) {
+ padding_observed_ = true;
+ } else if (header.payloadType == kSendRtxPayloadType) {
+ rtx_padding_observed_ = true;
+ } else {
+ streams_observed_.insert(header.ssrc);
+ }
- sender_transport.StopSending();
- receiver_transport.StopSending();
+ if (streams_observed_.size() == MultiStreamTest::kNumStreams &&
+ padding_observed_ && rtx_padding_observed_) {
+ done_->Set();
+ }
+ }
+ return test::DirectTransport::SendRtp(data, length);
+ }
+
+ EventTypeWrapper Wait() { return done_->Wait(kDefaultTimeoutMs); }
+
+ rtc::scoped_ptr<EventWrapper> done_;
+ rtc::scoped_ptr<RtpHeaderParser> parser_;
+ uint16_t last_seq_;
+ std::set<uint32_t> streams_observed_;
+ bool padding_observed_;
+ bool rtx_padding_observed_;
+ };
+
+ class TransportSequenceNumberTester : public MultiStreamTest {
+ public:
+ TransportSequenceNumberTester() : observer_(nullptr) {}
+ virtual ~TransportSequenceNumberTester() {}
+
+ protected:
+ void Wait() override {
+ DCHECK(observer_ != nullptr);
+ EXPECT_EQ(EventTypeWrapper::kEventSignaled, observer_->Wait());
+ }
+
+ void UpdateSendConfig(
+ size_t stream_index,
+ VideoSendStream::Config* send_config,
+ VideoEncoderConfig* encoder_config,
+ test::FrameGeneratorCapturer** frame_generator) override {
+ send_config->rtp.extensions.clear();
+ send_config->rtp.extensions.push_back(
+ RtpExtension(RtpExtension::kTransportSequenceNumber, kExtensionId));
+
+ // Force some padding to be sent.
+ const int kPaddingBitrateBps = 50000;
+ int total_target_bitrate = 0;
+ for (const VideoStream& stream : encoder_config->streams)
+ total_target_bitrate += stream.target_bitrate_bps;
+ encoder_config->min_transmit_bitrate_bps =
+ total_target_bitrate + kPaddingBitrateBps;
+
+ // Configure RTX for redundant payload padding.
+ send_config->rtp.nack.rtp_history_ms = kNackRtpHistoryMs;
+ send_config->rtp.rtx.ssrcs.push_back(kSendRtxSsrcs[0]);
+ send_config->rtp.rtx.payload_type = kSendRtxPayloadType;
+ }
+
+ void UpdateReceiveConfig(
+ size_t stream_index,
+ VideoReceiveStream::Config* receive_config) override {
+ receive_config->rtp.extensions.clear();
+ receive_config->rtp.extensions.push_back(
+ RtpExtension(RtpExtension::kTransportSequenceNumber, kExtensionId));
+ }
+
+ virtual test::DirectTransport* CreateSendTransport() {
+ observer_ = new RtpExtensionHeaderObserver();
+ return observer_;
+ }
+
+ private:
+ RtpExtensionHeaderObserver* observer_;
+ } tester;
+
+ tester.RunTest();
}
TEST_F(EndToEndTest, ObserversEncodedFrames) {
@@ -1806,7 +1990,8 @@
num_ssrcs_(num_ssrcs),
send_single_ssrc_first_(send_single_ssrc_first),
ssrcs_to_observe_(num_ssrcs),
- expect_single_ssrc_(send_single_ssrc_first) {
+ expect_single_ssrc_(send_single_ssrc_first),
+ send_stream_(nullptr) {
for (size_t i = 0; i < num_ssrcs; ++i)
valid_ssrcs_[ssrcs[i]] = true;
}
@@ -1898,7 +2083,9 @@
public:
EncoderRateStatsTest()
: EndToEndTest(kDefaultTimeoutMs),
- FakeEncoder(Clock::GetRealTimeClock()) {}
+ FakeEncoder(Clock::GetRealTimeClock()),
+ send_stream_(nullptr),
+ bitrate_kbps_(0) {}
void OnStreamsCreated(
VideoSendStream* send_stream,
@@ -2534,6 +2721,8 @@
FakeEncoder(Clock::GetRealTimeClock()),
encoded_frames_(EventWrapper::Create()),
packet_event_(EventWrapper::Create()),
+ sender_call_(nullptr),
+ receiver_call_(nullptr),
sender_state_(kNetworkUp),
sender_rtp_(0),
sender_rtcp_(0),
diff --git a/webrtc/video/video_receive_stream.cc b/webrtc/video/video_receive_stream.cc
index 57ddee0..f91eac5 100644
--- a/webrtc/video/video_receive_stream.cc
+++ b/webrtc/video/video_receive_stream.cc
@@ -179,6 +179,8 @@
CHECK_EQ(0, vie_channel_->SetReceiveAbsoluteSendTimeStatus(true, id));
} else if (extension == RtpExtension::kVideoRotation) {
CHECK_EQ(0, vie_channel_->SetReceiveVideoRotationStatus(true, id));
+ } else if (extension == RtpExtension::kTransportSequenceNumber) {
+ CHECK_EQ(0, vie_channel_->SetReceiveTransportSequenceNumber(true, id));
} else {
RTC_NOTREACHED() << "Unsupported RTP extension.";
}
diff --git a/webrtc/video/video_send_stream.cc b/webrtc/video/video_send_stream.cc
index f51e0e2..3bf07c9 100644
--- a/webrtc/video/video_send_stream.cc
+++ b/webrtc/video/video_send_stream.cc
@@ -17,6 +17,7 @@
#include "webrtc/base/checks.h"
#include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
+#include "webrtc/modules/pacing/include/packet_router.h"
#include "webrtc/system_wrappers/interface/logging.h"
#include "webrtc/system_wrappers/interface/trace_event.h"
#include "webrtc/video/video_capture_input.h"
@@ -136,6 +137,8 @@
CHECK_EQ(0, vie_channel_->SetSendAbsoluteSendTimeStatus(true, id));
} else if (extension == RtpExtension::kVideoRotation) {
CHECK_EQ(0, vie_channel_->SetSendVideoRotationStatus(true, id));
+ } else if (extension == RtpExtension::kTransportSequenceNumber) {
+ CHECK_EQ(0, vie_channel_->SetSendTransportSequenceNumber(true, id));
} else {
RTC_NOTREACHED() << "Registering unsupported RTP extension.";
}
diff --git a/webrtc/video/video_send_stream_tests.cc b/webrtc/video/video_send_stream_tests.cc
index 83ce92b..8b18622 100644
--- a/webrtc/video/video_send_stream_tests.cc
+++ b/webrtc/video/video_send_stream_tests.cc
@@ -205,6 +205,49 @@
RunBaseTest(&test);
}
+TEST_F(VideoSendStreamTest, SupportsTransportWideSequenceNumbers) {
+ static const uint8_t kExtensionId = 13;
+ class TransportWideSequenceNumberObserver : public test::SendTest {
+ public:
+ TransportWideSequenceNumberObserver()
+ : SendTest(kDefaultTimeoutMs), encoder_(Clock::GetRealTimeClock()) {
+ EXPECT_TRUE(parser_->RegisterRtpHeaderExtension(
+ kRtpExtensionTransportSequenceNumber, kExtensionId));
+ }
+
+ private:
+ Action OnSendRtp(const uint8_t* packet, size_t length) override {
+ RTPHeader header;
+ EXPECT_TRUE(parser_->Parse(packet, length, &header));
+
+ EXPECT_TRUE(header.extension.hasTransportSequenceNumber);
+ EXPECT_FALSE(header.extension.hasTransmissionTimeOffset);
+ EXPECT_FALSE(header.extension.hasAbsoluteSendTime);
+
+ observation_complete_->Set();
+
+ return SEND_PACKET;
+ }
+
+ void ModifyConfigs(VideoSendStream::Config* send_config,
+ std::vector<VideoReceiveStream::Config>* receive_configs,
+ VideoEncoderConfig* encoder_config) override {
+ send_config->encoder_settings.encoder = &encoder_;
+ send_config->rtp.extensions.push_back(
+ RtpExtension(RtpExtension::kTransportSequenceNumber, kExtensionId));
+ }
+
+ void PerformTest() override {
+ EXPECT_EQ(kEventSignaled, Wait())
+ << "Timed out while waiting for a single RTP packet.";
+ }
+
+ test::FakeEncoder encoder_;
+ } test;
+
+ RunBaseTest(&test);
+}
+
class FakeReceiveStatistics : public NullReceiveStatistics {
public:
FakeReceiveStatistics(uint32_t send_ssrc,
diff --git a/webrtc/video_engine/vie_channel.cc b/webrtc/video_engine/vie_channel.cc
index a01a408..df371ed 100644
--- a/webrtc/video_engine/vie_channel.cc
+++ b/webrtc/video_engine/vie_channel.cc
@@ -84,6 +84,7 @@
ProcessThread* module_process_thread,
RtcpIntraFrameObserver* intra_frame_observer,
RtcpBandwidthObserver* bandwidth_observer,
+ SendTimeObserver* send_time_observer,
RemoteBitrateEstimator* remote_bitrate_estimator,
RtcpRttStats* rtt_stats,
PacedSender* paced_sender,
@@ -112,6 +113,7 @@
paced_sender_(paced_sender),
packet_router_(packet_router),
bandwidth_observer_(bandwidth_observer),
+ send_time_observer_(send_time_observer),
decoder_reset_(true),
nack_history_size_sender_(kSendSidePacketHistorySize),
max_nack_reordering_threshold_(kMaxPacketAgeToNack),
@@ -124,10 +126,12 @@
transport,
sender ? intra_frame_observer_ : nullptr,
sender ? bandwidth_observer_.get() : nullptr,
+ sender ? send_time_observer_ : nullptr,
rtt_stats_,
&rtcp_packet_type_counter_observer_,
remote_bitrate_estimator,
paced_sender_,
+ sender_ ? packet_router_ : nullptr,
&send_bitrate_observer_,
&send_frame_count_observer_,
&send_side_delay_observer_,
@@ -176,8 +180,11 @@
module_process_thread_->DeRegisterModule(vcm_);
module_process_thread_->DeRegisterModule(&vie_sync_);
send_payload_router_->SetSendingRtpModules(std::list<RtpRtcp*>());
+ if (sender_ && packet_router_) {
+ for (size_t i = 0; i < num_active_rtp_rtcp_modules_; ++i)
+ packet_router_->RemoveRtpModule(rtp_rtcp_modules_[i]);
+ }
for (RtpRtcp* rtp_rtcp : rtp_rtcp_modules_) {
- packet_router_->RemoveRtpModule(rtp_rtcp);
module_process_thread_->DeRegisterModule(rtp_rtcp);
delete rtp_rtcp;
}
@@ -334,8 +341,6 @@
bool router_was_active = send_payload_router_->active();
send_payload_router_->set_active(false);
send_payload_router_->SetSendingRtpModules(std::list<RtpRtcp*>());
- for (RtpRtcp* module : rtp_rtcp_modules_)
- packet_router_->RemoveRtpModule(module);
std::vector<RtpRtcp*> registered_modules;
std::vector<RtpRtcp*> deregistered_modules;
@@ -376,22 +381,28 @@
vie_receiver_.RegisterRtpRtcpModules(registered_modules);
// Update the packet and payload routers with the sending RtpRtcp modules.
- std::list<RtpRtcp*> active_send_modules;
- for (RtpRtcp* rtp_rtcp : registered_modules) {
- packet_router_->AddRtpModule(rtp_rtcp);
- active_send_modules.push_back(rtp_rtcp);
+ if (sender_) {
+ std::list<RtpRtcp*> active_send_modules;
+ for (RtpRtcp* rtp_rtcp : registered_modules)
+ active_send_modules.push_back(rtp_rtcp);
+ send_payload_router_->SetSendingRtpModules(active_send_modules);
}
- send_payload_router_->SetSendingRtpModules(active_send_modules);
if (router_was_active)
send_payload_router_->set_active(true);
// Deregister previously registered modules.
- for (size_t i = num_active_modules; i < num_prev_active_modules; ++i)
+ for (size_t i = num_active_modules; i < num_prev_active_modules; ++i) {
module_process_thread_->DeRegisterModule(rtp_rtcp_modules_[i]);
+ if (sender_ && packet_router_)
+ packet_router_->RemoveRtpModule(rtp_rtcp_modules_[i]);
+ }
// Register new active modules.
- for (size_t i = num_prev_active_modules; i < num_active_modules; ++i)
+ for (size_t i = num_prev_active_modules; i < num_active_modules; ++i) {
module_process_thread_->RegisterModule(rtp_rtcp_modules_[i]);
+ if (sender_ && packet_router_)
+ packet_router_->AddRtpModule(rtp_rtcp_modules_[i]);
+ }
return 0;
}
@@ -675,6 +686,27 @@
return vie_receiver_.SetReceiveVideoRotationStatus(enable, id) ? 0 : -1;
}
+int ViEChannel::SetSendTransportSequenceNumber(bool enable, int id) {
+ // Disable any previous registrations of this extension to avoid errors.
+ for (RtpRtcp* rtp_rtcp : rtp_rtcp_modules_) {
+ rtp_rtcp->DeregisterSendRtpHeaderExtension(
+ kRtpExtensionTransportSequenceNumber);
+ }
+ if (!enable)
+ return 0;
+ // Enable the extension.
+ int error = 0;
+ for (RtpRtcp* rtp_rtcp : rtp_rtcp_modules_) {
+ error |= rtp_rtcp->RegisterSendRtpHeaderExtension(
+ kRtpExtensionTransportSequenceNumber, id);
+ }
+ return error;
+}
+
+int ViEChannel::SetReceiveTransportSequenceNumber(bool enable, int id) {
+ return vie_receiver_.SetReceiveTransportSequenceNumber(enable, id) ? 0 : -1;
+}
+
void ViEChannel::SetRtcpXrRrtrStatus(bool enable) {
rtp_rtcp_modules_[0]->SetRtcpXrRrtrStatus(enable);
}
@@ -1121,10 +1153,12 @@
Transport* outgoing_transport,
RtcpIntraFrameObserver* intra_frame_callback,
RtcpBandwidthObserver* bandwidth_callback,
+ SendTimeObserver* send_time_callback,
RtcpRttStats* rtt_stats,
RtcpPacketTypeCounterObserver* rtcp_packet_type_counter_observer,
RemoteBitrateEstimator* remote_bitrate_estimator,
PacedSender* paced_sender,
+ PacketRouter* packet_router,
BitrateStatisticsObserver* send_bitrate_observer,
FrameCountObserver* send_frame_count_observer,
SendSideDelayObserver* send_side_delay_observer,
@@ -1142,10 +1176,12 @@
configuration.rtcp_packet_type_counter_observer =
rtcp_packet_type_counter_observer;
configuration.paced_sender = paced_sender;
+ configuration.packet_router = packet_router;
configuration.send_bitrate_observer = send_bitrate_observer;
configuration.send_frame_count_observer = send_frame_count_observer;
configuration.send_side_delay_observer = send_side_delay_observer;
configuration.bandwidth_callback = bandwidth_callback;
+ configuration.send_time_callback = send_time_callback;
std::vector<RtpRtcp*> modules;
for (size_t i = 0; i < num_modules; ++i) {
diff --git a/webrtc/video_engine/vie_channel.h b/webrtc/video_engine/vie_channel.h
index 86969e7..6c5782e 100644
--- a/webrtc/video_engine/vie_channel.h
+++ b/webrtc/video_engine/vie_channel.h
@@ -103,6 +103,7 @@
ProcessThread* module_process_thread,
RtcpIntraFrameObserver* intra_frame_observer,
RtcpBandwidthObserver* bandwidth_observer,
+ SendTimeObserver* send_time_observer,
RemoteBitrateEstimator* remote_bitrate_estimator,
RtcpRttStats* rtt_stats,
PacedSender* paced_sender,
@@ -150,6 +151,8 @@
int SetReceiveAbsoluteSendTimeStatus(bool enable, int id);
int SetSendVideoRotationStatus(bool enable, int id);
int SetReceiveVideoRotationStatus(bool enable, int id);
+ int SetSendTransportSequenceNumber(bool enable, int id);
+ int SetReceiveTransportSequenceNumber(bool enable, int id);
void SetRtcpXrRrtrStatus(bool enable);
void SetTransmissionSmoothingStatus(bool enable);
void EnableTMMBR(bool enable);
@@ -331,10 +334,12 @@
Transport* outgoing_transport,
RtcpIntraFrameObserver* intra_frame_callback,
RtcpBandwidthObserver* bandwidth_callback,
+ SendTimeObserver* send_time_observer,
RtcpRttStats* rtt_stats,
RtcpPacketTypeCounterObserver* rtcp_packet_type_counter_observer,
RemoteBitrateEstimator* remote_bitrate_estimator,
PacedSender* paced_sender,
+ PacketRouter* packet_router,
BitrateStatisticsObserver* send_bitrate_observer,
FrameCountObserver* send_frame_count_observer,
SendSideDelayObserver* send_side_delay_observer,
@@ -470,6 +475,7 @@
PacketRouter* const packet_router_;
const rtc::scoped_ptr<RtcpBandwidthObserver> bandwidth_observer_;
+ SendTimeObserver* const send_time_observer_;
bool decoder_reset_ GUARDED_BY(crit_);
// Current receive codec used for codec change callback.
diff --git a/webrtc/video_engine/vie_channel_group.cc b/webrtc/video_engine/vie_channel_group.cc
index 084ffef..cf6b19c 100644
--- a/webrtc/video_engine/vie_channel_group.cc
+++ b/webrtc/video_engine/vie_channel_group.cc
@@ -15,6 +15,7 @@
#include "webrtc/common.h"
#include "webrtc/modules/pacing/include/paced_sender.h"
#include "webrtc/modules/pacing/include/packet_router.h"
+#include "webrtc/modules/remote_bitrate_estimator/include/send_time_history.h"
#include "webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator_abs_send_time.h"
#include "webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator_single_stream.h"
#include "webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h"
@@ -137,8 +138,21 @@
DISALLOW_IMPLICIT_CONSTRUCTORS(WrappingBitrateEstimator);
};
+
+static const int64_t kSendTimeHistoryWindowMs = 2000;
+
} // namespace
+class AdaptedSendTimeHistory : public SendTimeHistory, public SendTimeObserver {
+ public:
+ AdaptedSendTimeHistory() : SendTimeHistory(kSendTimeHistoryWindowMs) {}
+ virtual ~AdaptedSendTimeHistory() {}
+
+ void OnPacketSent(uint16_t sequence_number, int64_t send_time) override {
+ SendTimeHistory::AddAndRemoveOldSendTimes(sequence_number, send_time);
+ }
+};
+
ChannelGroup::ChannelGroup(ProcessThread* process_thread)
: remb_(new VieRemb()),
bitrate_allocator_(new BitrateAllocator()),
@@ -157,7 +171,8 @@
// construction.
bitrate_controller_(
BitrateController::CreateBitrateController(Clock::GetRealTimeClock(),
- this)) {
+ this)),
+ send_time_history_(new AdaptedSendTimeHistory()) {
remote_bitrate_estimator_.reset(new WrappingBitrateEstimator(
remb_.get(), Clock::GetRealTimeClock()));
@@ -235,8 +250,9 @@
channel_id, engine_id, number_of_cores, transport, process_thread_,
encoder_state_feedback_->GetRtcpIntraFrameObserver(),
bitrate_controller_->CreateRtcpBandwidthObserver(),
- remote_bitrate_estimator_.get(), call_stats_->rtcp_rtt_stats(),
- pacer_.get(), packet_router_.get(), max_rtp_streams, sender));
+ send_time_history_.get(), remote_bitrate_estimator_.get(),
+ call_stats_->rtcp_rtt_stats(), pacer_.get(), packet_router_.get(),
+ max_rtp_streams, sender));
if (channel->Init() != 0) {
return false;
}
diff --git a/webrtc/video_engine/vie_channel_group.h b/webrtc/video_engine/vie_channel_group.h
index 5d4d9af..3c8008f 100644
--- a/webrtc/video_engine/vie_channel_group.h
+++ b/webrtc/video_engine/vie_channel_group.h
@@ -22,6 +22,7 @@
namespace webrtc {
+class AdaptedSendTimeHistory;
class BitrateAllocator;
class CallStats;
class Config;
@@ -100,6 +101,7 @@
rtc::scoped_ptr<ProcessThread> pacer_thread_;
rtc::scoped_ptr<BitrateController> bitrate_controller_;
+ rtc::scoped_ptr<AdaptedSendTimeHistory> send_time_history_;
};
} // namespace webrtc
diff --git a/webrtc/video_engine/vie_receiver.cc b/webrtc/video_engine/vie_receiver.cc
index 9e25080..a3ef2cf 100644
--- a/webrtc/video_engine/vie_receiver.cc
+++ b/webrtc/video_engine/vie_receiver.cc
@@ -58,6 +58,7 @@
restored_packet_in_use_(false),
receiving_ast_enabled_(false),
receiving_cvo_enabled_(false),
+ receiving_tsn_enabled_(false),
last_packet_log_ms_(-1) {
assert(remote_bitrate_estimator);
}
@@ -199,6 +200,22 @@
}
}
+bool ViEReceiver::SetReceiveTransportSequenceNumber(bool enable, int id) {
+ if (enable) {
+ if (rtp_header_parser_->RegisterRtpHeaderExtension(
+ kRtpExtensionTransportSequenceNumber, id)) {
+ receiving_tsn_enabled_ = true;
+ return true;
+ } else {
+ return false;
+ }
+ } else {
+ receiving_tsn_enabled_ = false;
+ return rtp_header_parser_->DeregisterRtpHeaderExtension(
+ kRtpExtensionTransportSequenceNumber);
+ }
+}
+
int ViEReceiver::ReceivedRTPPacket(const void* rtp_packet,
size_t rtp_packet_length,
const PacketTime& packet_time) {
diff --git a/webrtc/video_engine/vie_receiver.h b/webrtc/video_engine/vie_receiver.h
index 62fb225..781f14f 100644
--- a/webrtc/video_engine/vie_receiver.h
+++ b/webrtc/video_engine/vie_receiver.h
@@ -63,6 +63,7 @@
bool SetReceiveTimestampOffsetStatus(bool enable, int id);
bool SetReceiveAbsoluteSendTimeStatus(bool enable, int id);
bool SetReceiveVideoRotationStatus(bool enable, int id);
+ bool SetReceiveTransportSequenceNumber(bool enable, int id);
void StartReceive();
void StopReceive();
@@ -116,6 +117,7 @@
bool restored_packet_in_use_;
bool receiving_ast_enabled_;
bool receiving_cvo_enabled_;
+ bool receiving_tsn_enabled_;
int64_t last_packet_log_ms_;
};