aboutsummaryrefslogtreecommitdiff
path: root/webrtc/call
diff options
context:
space:
mode:
Diffstat (limited to 'webrtc/call')
-rw-r--r--webrtc/call/BUILD.gn1
-rw-r--r--webrtc/call/bitrate_allocator.cc194
-rw-r--r--webrtc/call/bitrate_allocator.h102
-rw-r--r--webrtc/call/bitrate_allocator_unittest.cc212
-rw-r--r--webrtc/call/bitrate_estimator_tests.cc201
-rw-r--r--webrtc/call/call.cc209
-rw-r--r--webrtc/call/call_perf_tests.cc208
-rw-r--r--webrtc/call/call_unittest.cc11
-rw-r--r--webrtc/call/congestion_controller.cc50
-rw-r--r--webrtc/call/congestion_controller.h66
-rw-r--r--webrtc/call/mock/mock_congestion_controller.h52
-rw-r--r--webrtc/call/packet_injection_tests.cc12
-rw-r--r--webrtc/call/rampup_tests.cc587
-rw-r--r--webrtc/call/rampup_tests.h137
-rw-r--r--webrtc/call/rtc_event_log.cc92
-rw-r--r--webrtc/call/rtc_event_log.h5
-rw-r--r--webrtc/call/rtc_event_log.proto62
-rw-r--r--webrtc/call/rtc_event_log_unittest.cc237
-rw-r--r--webrtc/call/webrtc_call.gypi1
19 files changed, 2006 insertions, 433 deletions
diff --git a/webrtc/call/BUILD.gn b/webrtc/call/BUILD.gn
index 3abc762a77..498c724900 100644
--- a/webrtc/call/BUILD.gn
+++ b/webrtc/call/BUILD.gn
@@ -10,6 +10,7 @@ import("../build/webrtc.gni")
source_set("call") {
sources = [
+ "bitrate_allocator.cc",
"call.cc",
"congestion_controller.cc",
"transport_adapter.cc",
diff --git a/webrtc/call/bitrate_allocator.cc b/webrtc/call/bitrate_allocator.cc
new file mode 100644
index 0000000000..b3789d3bb6
--- /dev/null
+++ b/webrtc/call/bitrate_allocator.cc
@@ -0,0 +1,194 @@
+/*
+ * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ *
+ */
+
+#include "webrtc/call/bitrate_allocator.h"
+
+#include <algorithm>
+#include <utility>
+
+#include "webrtc/modules/bitrate_controller/include/bitrate_controller.h"
+
+namespace webrtc {
+
+// Allow packets to be transmitted in up to 2 times max video bitrate if the
+// bandwidth estimate allows it.
+const int kTransmissionMaxBitrateMultiplier = 2;
+const int kDefaultBitrateBps = 300000;
+
+BitrateAllocator::BitrateAllocator()
+ : crit_sect_(CriticalSectionWrapper::CreateCriticalSection()),
+ bitrate_observers_(),
+ bitrate_observers_modified_(false),
+ enforce_min_bitrate_(true),
+ last_bitrate_bps_(kDefaultBitrateBps),
+ last_fraction_loss_(0),
+ last_rtt_(0) {}
+
+uint32_t BitrateAllocator::OnNetworkChanged(uint32_t bitrate,
+ uint8_t fraction_loss,
+ int64_t rtt) {
+ CriticalSectionScoped lock(crit_sect_.get());
+ last_bitrate_bps_ = bitrate;
+ last_fraction_loss_ = fraction_loss;
+ last_rtt_ = rtt;
+ uint32_t allocated_bitrate_bps = 0;
+ ObserverBitrateMap allocation = AllocateBitrates();
+ for (const auto& kv : allocation) {
+ kv.first->OnNetworkChanged(kv.second, last_fraction_loss_, last_rtt_);
+ allocated_bitrate_bps += kv.second;
+ }
+ return allocated_bitrate_bps;
+}
+
+BitrateAllocator::ObserverBitrateMap BitrateAllocator::AllocateBitrates() {
+ if (bitrate_observers_.empty())
+ return ObserverBitrateMap();
+
+ uint32_t sum_min_bitrates = 0;
+ for (const auto& observer : bitrate_observers_)
+ sum_min_bitrates += observer.second.min_bitrate;
+ if (last_bitrate_bps_ <= sum_min_bitrates)
+ return LowRateAllocation(last_bitrate_bps_);
+ else
+ return NormalRateAllocation(last_bitrate_bps_, sum_min_bitrates);
+}
+
+int BitrateAllocator::AddBitrateObserver(BitrateObserver* observer,
+ uint32_t min_bitrate_bps,
+ uint32_t max_bitrate_bps) {
+ CriticalSectionScoped lock(crit_sect_.get());
+
+ BitrateObserverConfList::iterator it =
+ FindObserverConfigurationPair(observer);
+
+ // Allow the max bitrate to be exceeded for FEC and retransmissions.
+ // TODO(holmer): We have to get rid of this hack as it makes it difficult to
+ // properly allocate bitrate. The allocator should instead distribute any
+ // extra bitrate after all streams have maxed out.
+ max_bitrate_bps *= kTransmissionMaxBitrateMultiplier;
+ if (it != bitrate_observers_.end()) {
+ // Update current configuration.
+ it->second.min_bitrate = min_bitrate_bps;
+ it->second.max_bitrate = max_bitrate_bps;
+ } else {
+ // Add new settings.
+ bitrate_observers_.push_back(BitrateObserverConfiguration(
+ observer, BitrateConfiguration(min_bitrate_bps, max_bitrate_bps)));
+ bitrate_observers_modified_ = true;
+ }
+
+ ObserverBitrateMap allocation = AllocateBitrates();
+ int new_observer_bitrate_bps = 0;
+ for (auto& kv : allocation) {
+ kv.first->OnNetworkChanged(kv.second, last_fraction_loss_, last_rtt_);
+ if (kv.first == observer)
+ new_observer_bitrate_bps = kv.second;
+ }
+ return new_observer_bitrate_bps;
+}
+
+void BitrateAllocator::RemoveBitrateObserver(BitrateObserver* observer) {
+ CriticalSectionScoped lock(crit_sect_.get());
+ BitrateObserverConfList::iterator it =
+ FindObserverConfigurationPair(observer);
+ if (it != bitrate_observers_.end()) {
+ bitrate_observers_.erase(it);
+ bitrate_observers_modified_ = true;
+ }
+}
+
+void BitrateAllocator::GetMinMaxBitrateSumBps(int* min_bitrate_sum_bps,
+ int* max_bitrate_sum_bps) const {
+ *min_bitrate_sum_bps = 0;
+ *max_bitrate_sum_bps = 0;
+
+ CriticalSectionScoped lock(crit_sect_.get());
+ for (const auto& observer : bitrate_observers_) {
+ *min_bitrate_sum_bps += observer.second.min_bitrate;
+ *max_bitrate_sum_bps += observer.second.max_bitrate;
+ }
+}
+
+BitrateAllocator::BitrateObserverConfList::iterator
+BitrateAllocator::FindObserverConfigurationPair(
+ const BitrateObserver* observer) {
+ for (auto it = bitrate_observers_.begin(); it != bitrate_observers_.end();
+ ++it) {
+ if (it->first == observer)
+ return it;
+ }
+ return bitrate_observers_.end();
+}
+
+void BitrateAllocator::EnforceMinBitrate(bool enforce_min_bitrate) {
+ CriticalSectionScoped lock(crit_sect_.get());
+ enforce_min_bitrate_ = enforce_min_bitrate;
+}
+
+BitrateAllocator::ObserverBitrateMap BitrateAllocator::NormalRateAllocation(
+ uint32_t bitrate,
+ uint32_t sum_min_bitrates) {
+ uint32_t number_of_observers =
+ static_cast<uint32_t>(bitrate_observers_.size());
+ uint32_t bitrate_per_observer =
+ (bitrate - sum_min_bitrates) / number_of_observers;
+ // Use map to sort list based on max bitrate.
+ ObserverSortingMap list_max_bitrates;
+ for (const auto& observer : bitrate_observers_) {
+ list_max_bitrates.insert(std::pair<uint32_t, ObserverConfiguration>(
+ observer.second.max_bitrate,
+ ObserverConfiguration(observer.first, observer.second.min_bitrate)));
+ }
+ ObserverBitrateMap allocation;
+ ObserverSortingMap::iterator max_it = list_max_bitrates.begin();
+ while (max_it != list_max_bitrates.end()) {
+ number_of_observers--;
+ uint32_t observer_allowance =
+ max_it->second.min_bitrate + bitrate_per_observer;
+ if (max_it->first < observer_allowance) {
+ // We have more than enough for this observer.
+ // Carry the remainder forward.
+ uint32_t remainder = observer_allowance - max_it->first;
+ if (number_of_observers != 0) {
+ bitrate_per_observer += remainder / number_of_observers;
+ }
+ allocation[max_it->second.observer] = max_it->first;
+ } else {
+ allocation[max_it->second.observer] = observer_allowance;
+ }
+ list_max_bitrates.erase(max_it);
+ // Prepare next iteration.
+ max_it = list_max_bitrates.begin();
+ }
+ return allocation;
+}
+
+BitrateAllocator::ObserverBitrateMap BitrateAllocator::LowRateAllocation(
+ uint32_t bitrate) {
+ ObserverBitrateMap allocation;
+ if (enforce_min_bitrate_) {
+ // Min bitrate to all observers.
+ for (const auto& observer : bitrate_observers_)
+ allocation[observer.first] = observer.second.min_bitrate;
+ } else {
+ // Allocate up to |min_bitrate| to one observer at a time, until
+ // |bitrate| is depleted.
+ uint32_t remainder = bitrate;
+ for (const auto& observer : bitrate_observers_) {
+ uint32_t allocated_bitrate =
+ std::min(remainder, observer.second.min_bitrate);
+ allocation[observer.first] = allocated_bitrate;
+ remainder -= allocated_bitrate;
+ }
+ }
+ return allocation;
+}
+} // namespace webrtc
diff --git a/webrtc/call/bitrate_allocator.h b/webrtc/call/bitrate_allocator.h
new file mode 100644
index 0000000000..4a3fd59d49
--- /dev/null
+++ b/webrtc/call/bitrate_allocator.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ *
+ * Usage: this class will register multiple RtcpBitrateObserver's one at each
+ * RTCP module. It will aggregate the results and run one bandwidth estimation
+ * and push the result to the encoders via BitrateObserver(s).
+ */
+
+#ifndef WEBRTC_CALL_BITRATE_ALLOCATOR_H_
+#define WEBRTC_CALL_BITRATE_ALLOCATOR_H_
+
+#include <list>
+#include <map>
+#include <utility>
+
+#include "webrtc/base/scoped_ptr.h"
+#include "webrtc/base/thread_annotations.h"
+#include "webrtc/system_wrappers/include/critical_section_wrapper.h"
+
+namespace webrtc {
+
+class BitrateObserver;
+
+class BitrateAllocator {
+ public:
+ BitrateAllocator();
+
+ // Allocate target_bitrate across the registered BitrateObservers.
+ // Returns actual bitrate allocated (might be higher than target_bitrate if
+ // for instance EnforceMinBitrate() is enabled.
+ uint32_t OnNetworkChanged(uint32_t target_bitrate,
+ uint8_t fraction_loss,
+ int64_t rtt);
+
+ // Set the start and max send bitrate used by the bandwidth management.
+ //
+ // |observer| updates bitrates if already in use.
+ // |min_bitrate_bps| = 0 equals no min bitrate.
+ // |max_bitrate_bps| = 0 equals no max bitrate.
+ // Returns bitrate allocated for the bitrate observer.
+ int AddBitrateObserver(BitrateObserver* observer,
+ uint32_t min_bitrate_bps,
+ uint32_t max_bitrate_bps);
+
+ void RemoveBitrateObserver(BitrateObserver* observer);
+
+ void GetMinMaxBitrateSumBps(int* min_bitrate_sum_bps,
+ int* max_bitrate_sum_bps) const;
+
+ // This method controls the behavior when the available bitrate is lower than
+ // the minimum bitrate, or the sum of minimum bitrates.
+ // When true, the bitrate will never be set lower than the minimum bitrate(s).
+ // When false, the bitrate observers will be allocated rates up to their
+ // respective minimum bitrate, satisfying one observer after the other.
+ void EnforceMinBitrate(bool enforce_min_bitrate);
+
+ private:
+ struct BitrateConfiguration {
+ BitrateConfiguration(uint32_t min_bitrate, uint32_t max_bitrate)
+ : min_bitrate(min_bitrate), max_bitrate(max_bitrate) {}
+ uint32_t min_bitrate;
+ uint32_t max_bitrate;
+ };
+ struct ObserverConfiguration {
+ ObserverConfiguration(BitrateObserver* observer, uint32_t bitrate)
+ : observer(observer), min_bitrate(bitrate) {}
+ BitrateObserver* const observer;
+ uint32_t min_bitrate;
+ };
+ typedef std::pair<BitrateObserver*, BitrateConfiguration>
+ BitrateObserverConfiguration;
+ typedef std::list<BitrateObserverConfiguration> BitrateObserverConfList;
+ typedef std::multimap<uint32_t, ObserverConfiguration> ObserverSortingMap;
+ typedef std::map<BitrateObserver*, int> ObserverBitrateMap;
+
+ BitrateObserverConfList::iterator FindObserverConfigurationPair(
+ const BitrateObserver* observer) EXCLUSIVE_LOCKS_REQUIRED(crit_sect_);
+ ObserverBitrateMap AllocateBitrates() EXCLUSIVE_LOCKS_REQUIRED(crit_sect_);
+ ObserverBitrateMap NormalRateAllocation(uint32_t bitrate,
+ uint32_t sum_min_bitrates)
+ EXCLUSIVE_LOCKS_REQUIRED(crit_sect_);
+
+ ObserverBitrateMap LowRateAllocation(uint32_t bitrate)
+ EXCLUSIVE_LOCKS_REQUIRED(crit_sect_);
+
+ rtc::scoped_ptr<CriticalSectionWrapper> crit_sect_;
+ // Stored in a list to keep track of the insertion order.
+ BitrateObserverConfList bitrate_observers_ GUARDED_BY(crit_sect_);
+ bool bitrate_observers_modified_ GUARDED_BY(crit_sect_);
+ bool enforce_min_bitrate_ GUARDED_BY(crit_sect_);
+ uint32_t last_bitrate_bps_ GUARDED_BY(crit_sect_);
+ uint8_t last_fraction_loss_ GUARDED_BY(crit_sect_);
+ int64_t last_rtt_ GUARDED_BY(crit_sect_);
+};
+} // namespace webrtc
+#endif // WEBRTC_CALL_BITRATE_ALLOCATOR_H_
diff --git a/webrtc/call/bitrate_allocator_unittest.cc b/webrtc/call/bitrate_allocator_unittest.cc
new file mode 100644
index 0000000000..86f75a4380
--- /dev/null
+++ b/webrtc/call/bitrate_allocator_unittest.cc
@@ -0,0 +1,212 @@
+/*
+ * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include <algorithm>
+#include <vector>
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "webrtc/call/bitrate_allocator.h"
+#include "webrtc/modules/bitrate_controller/include/bitrate_controller.h"
+
+namespace webrtc {
+
+class TestBitrateObserver : public BitrateObserver {
+ public:
+ TestBitrateObserver()
+ : last_bitrate_(0), last_fraction_loss_(0), last_rtt_(0) {}
+
+ virtual void OnNetworkChanged(uint32_t bitrate,
+ uint8_t fraction_loss,
+ int64_t rtt) {
+ last_bitrate_ = bitrate;
+ last_fraction_loss_ = fraction_loss;
+ last_rtt_ = rtt;
+ }
+ uint32_t last_bitrate_;
+ uint8_t last_fraction_loss_;
+ int64_t last_rtt_;
+};
+
+class BitrateAllocatorTest : public ::testing::Test {
+ protected:
+ BitrateAllocatorTest() : allocator_(new BitrateAllocator()) {
+ allocator_->OnNetworkChanged(300000u, 0, 0);
+ }
+ ~BitrateAllocatorTest() {}
+
+ rtc::scoped_ptr<BitrateAllocator> allocator_;
+};
+
+TEST_F(BitrateAllocatorTest, UpdatingBitrateObserver) {
+ TestBitrateObserver bitrate_observer;
+ int start_bitrate =
+ allocator_->AddBitrateObserver(&bitrate_observer, 100000, 1500000);
+ EXPECT_EQ(300000, start_bitrate);
+ allocator_->OnNetworkChanged(200000, 0, 0);
+ EXPECT_EQ(200000u, bitrate_observer.last_bitrate_);
+
+ // TODO(pbos): Expect capping to 1.5M instead of 3M when not boosting the max
+ // bitrate for FEC/retransmissions (see todo in BitrateAllocator).
+ allocator_->OnNetworkChanged(4000000, 0, 0);
+ EXPECT_EQ(3000000u, bitrate_observer.last_bitrate_);
+ start_bitrate =
+ allocator_->AddBitrateObserver(&bitrate_observer, 100000, 4000000);
+ EXPECT_EQ(4000000, start_bitrate);
+
+ start_bitrate =
+ allocator_->AddBitrateObserver(&bitrate_observer, 100000, 1500000);
+ EXPECT_EQ(3000000, start_bitrate);
+ EXPECT_EQ(3000000u, bitrate_observer.last_bitrate_);
+ allocator_->OnNetworkChanged(1500000, 0, 0);
+ EXPECT_EQ(1500000u, bitrate_observer.last_bitrate_);
+}
+
+TEST_F(BitrateAllocatorTest, TwoBitrateObserversOneRtcpObserver) {
+ TestBitrateObserver bitrate_observer_1;
+ TestBitrateObserver bitrate_observer_2;
+ int start_bitrate =
+ allocator_->AddBitrateObserver(&bitrate_observer_1, 100000, 300000);
+ EXPECT_EQ(300000, start_bitrate);
+ start_bitrate =
+ allocator_->AddBitrateObserver(&bitrate_observer_2, 200000, 300000);
+ EXPECT_EQ(200000, start_bitrate);
+
+ // Test too low start bitrate, hence lower than sum of min. Min bitrates will
+ // be allocated to all observers.
+ allocator_->OnNetworkChanged(200000, 0, 50);
+ EXPECT_EQ(100000u, bitrate_observer_1.last_bitrate_);
+ EXPECT_EQ(0, bitrate_observer_1.last_fraction_loss_);
+ EXPECT_EQ(50, bitrate_observer_1.last_rtt_);
+ EXPECT_EQ(200000u, bitrate_observer_2.last_bitrate_);
+ EXPECT_EQ(0, bitrate_observer_2.last_fraction_loss_);
+ EXPECT_EQ(50, bitrate_observer_2.last_rtt_);
+
+ // Test a bitrate which should be distributed equally.
+ allocator_->OnNetworkChanged(500000, 0, 50);
+ const uint32_t kBitrateToShare = 500000 - 200000 - 100000;
+ EXPECT_EQ(100000u + kBitrateToShare / 2, bitrate_observer_1.last_bitrate_);
+ EXPECT_EQ(200000u + kBitrateToShare / 2, bitrate_observer_2.last_bitrate_);
+
+ // Limited by 2x max bitrates since we leave room for FEC and retransmissions.
+ allocator_->OnNetworkChanged(1500000, 0, 50);
+ EXPECT_EQ(600000u, bitrate_observer_1.last_bitrate_);
+ EXPECT_EQ(600000u, bitrate_observer_2.last_bitrate_);
+}
+
+class BitrateAllocatorTestNoEnforceMin : public ::testing::Test {
+ protected:
+ BitrateAllocatorTestNoEnforceMin() : allocator_(new BitrateAllocator()) {
+ allocator_->EnforceMinBitrate(false);
+ allocator_->OnNetworkChanged(300000u, 0, 0);
+ }
+ ~BitrateAllocatorTestNoEnforceMin() {}
+
+ rtc::scoped_ptr<BitrateAllocator> allocator_;
+};
+
+// The following three tests verify that the EnforceMinBitrate() method works
+// as intended.
+TEST_F(BitrateAllocatorTestNoEnforceMin, OneBitrateObserver) {
+ TestBitrateObserver bitrate_observer_1;
+ int start_bitrate =
+ allocator_->AddBitrateObserver(&bitrate_observer_1, 100000, 400000);
+ EXPECT_EQ(300000, start_bitrate);
+
+ // High REMB.
+ allocator_->OnNetworkChanged(150000, 0, 0);
+ EXPECT_EQ(150000u, bitrate_observer_1.last_bitrate_);
+
+ // Low REMB.
+ allocator_->OnNetworkChanged(10000, 0, 0);
+ EXPECT_EQ(10000u, bitrate_observer_1.last_bitrate_);
+
+ allocator_->RemoveBitrateObserver(&bitrate_observer_1);
+}
+
+TEST_F(BitrateAllocatorTestNoEnforceMin, ThreeBitrateObservers) {
+ TestBitrateObserver bitrate_observer_1;
+ TestBitrateObserver bitrate_observer_2;
+ TestBitrateObserver bitrate_observer_3;
+ // Set up the observers with min bitrates at 100000, 200000, and 300000.
+ int start_bitrate =
+ allocator_->AddBitrateObserver(&bitrate_observer_1, 100000, 400000);
+ EXPECT_EQ(300000, start_bitrate);
+
+ start_bitrate =
+ allocator_->AddBitrateObserver(&bitrate_observer_2, 200000, 400000);
+ EXPECT_EQ(200000, start_bitrate);
+ EXPECT_EQ(100000u, bitrate_observer_1.last_bitrate_);
+
+ start_bitrate =
+ allocator_->AddBitrateObserver(&bitrate_observer_3, 300000, 400000);
+ EXPECT_EQ(0, start_bitrate);
+ EXPECT_EQ(100000u, bitrate_observer_1.last_bitrate_);
+ EXPECT_EQ(200000u, bitrate_observer_2.last_bitrate_);
+
+ // High REMB. Make sure the controllers get a fair share of the surplus
+ // (i.e., what is left after each controller gets its min rate).
+ allocator_->OnNetworkChanged(690000, 0, 0);
+ // Verify that each observer gets its min rate (sum of min rates is 600000),
+ // and that the remaining 90000 is divided equally among the three.
+ uint32_t bitrate_to_share = 690000u - 100000u - 200000u - 300000u;
+ EXPECT_EQ(100000u + bitrate_to_share / 3, bitrate_observer_1.last_bitrate_);
+ EXPECT_EQ(200000u + bitrate_to_share / 3, bitrate_observer_2.last_bitrate_);
+ EXPECT_EQ(300000u + bitrate_to_share / 3, bitrate_observer_3.last_bitrate_);
+
+ // High REMB, but below the sum of min bitrates.
+ allocator_->OnNetworkChanged(500000, 0, 0);
+ // Verify that the first and second observers get their min bitrates, and the
+ // third gets the remainder.
+ EXPECT_EQ(100000u, bitrate_observer_1.last_bitrate_); // Min bitrate.
+ EXPECT_EQ(200000u, bitrate_observer_2.last_bitrate_); // Min bitrate.
+ EXPECT_EQ(200000u, bitrate_observer_3.last_bitrate_); // Remainder.
+
+ // Low REMB.
+ allocator_->OnNetworkChanged(10000, 0, 0);
+ // Verify that the first observer gets all the rate, and the rest get zero.
+ EXPECT_EQ(10000u, bitrate_observer_1.last_bitrate_);
+ EXPECT_EQ(0u, bitrate_observer_2.last_bitrate_);
+ EXPECT_EQ(0u, bitrate_observer_3.last_bitrate_);
+
+ allocator_->RemoveBitrateObserver(&bitrate_observer_1);
+ allocator_->RemoveBitrateObserver(&bitrate_observer_2);
+ allocator_->RemoveBitrateObserver(&bitrate_observer_3);
+}
+
+TEST_F(BitrateAllocatorTest, ThreeBitrateObserversLowRembEnforceMin) {
+ TestBitrateObserver bitrate_observer_1;
+ TestBitrateObserver bitrate_observer_2;
+ TestBitrateObserver bitrate_observer_3;
+ int start_bitrate =
+ allocator_->AddBitrateObserver(&bitrate_observer_1, 100000, 400000);
+ EXPECT_EQ(300000, start_bitrate);
+
+ start_bitrate =
+ allocator_->AddBitrateObserver(&bitrate_observer_2, 200000, 400000);
+ EXPECT_EQ(200000, start_bitrate);
+ EXPECT_EQ(100000u, bitrate_observer_1.last_bitrate_);
+
+ start_bitrate =
+ allocator_->AddBitrateObserver(&bitrate_observer_3, 300000, 400000);
+ EXPECT_EQ(300000, start_bitrate);
+ EXPECT_EQ(100000, static_cast<int>(bitrate_observer_1.last_bitrate_));
+ EXPECT_EQ(200000, static_cast<int>(bitrate_observer_2.last_bitrate_));
+
+ // Low REMB. Verify that all observers still get their respective min bitrate.
+ allocator_->OnNetworkChanged(1000, 0, 0);
+ EXPECT_EQ(100000u, bitrate_observer_1.last_bitrate_); // Min cap.
+ EXPECT_EQ(200000u, bitrate_observer_2.last_bitrate_); // Min cap.
+ EXPECT_EQ(300000u, bitrate_observer_3.last_bitrate_); // Min cap.
+
+ allocator_->RemoveBitrateObserver(&bitrate_observer_1);
+ allocator_->RemoveBitrateObserver(&bitrate_observer_2);
+ allocator_->RemoveBitrateObserver(&bitrate_observer_3);
+}
+} // namespace webrtc
diff --git a/webrtc/call/bitrate_estimator_tests.cc b/webrtc/call/bitrate_estimator_tests.cc
index 685f3fd665..4b24bbd5ef 100644
--- a/webrtc/call/bitrate_estimator_tests.cc
+++ b/webrtc/call/bitrate_estimator_tests.cc
@@ -13,66 +13,54 @@
#include "testing/gtest/include/gtest/gtest.h"
+#include "webrtc/audio_state.h"
#include "webrtc/base/checks.h"
+#include "webrtc/base/event.h"
+#include "webrtc/base/logging.h"
#include "webrtc/base/scoped_ptr.h"
#include "webrtc/base/thread_annotations.h"
#include "webrtc/call.h"
#include "webrtc/system_wrappers/include/critical_section_wrapper.h"
-#include "webrtc/system_wrappers/include/event_wrapper.h"
#include "webrtc/system_wrappers/include/trace.h"
#include "webrtc/test/call_test.h"
#include "webrtc/test/direct_transport.h"
#include "webrtc/test/encoder_settings.h"
#include "webrtc/test/fake_decoder.h"
#include "webrtc/test/fake_encoder.h"
-#include "webrtc/test/fake_voice_engine.h"
+#include "webrtc/test/mock_voice_engine.h"
#include "webrtc/test/frame_generator_capturer.h"
namespace webrtc {
namespace {
// Note: If you consider to re-use this class, think twice and instead consider
-// writing tests that don't depend on the trace system.
-class TraceObserver {
+// writing tests that don't depend on the logging system.
+class LogObserver {
public:
- TraceObserver() {
- Trace::set_level_filter(kTraceTerseInfo);
-
- Trace::CreateTrace();
- Trace::SetTraceCallback(&callback_);
-
- // Call webrtc trace to initialize the tracer that would otherwise trigger a
- // data-race if left to be initialized by multiple threads (i.e. threads
- // spawned by test::DirectTransport members in BitrateEstimatorTest).
- WEBRTC_TRACE(kTraceStateInfo,
- kTraceUtility,
- -1,
- "Instantiate without data races.");
- }
+ LogObserver() { rtc::LogMessage::AddLogToStream(&callback_, rtc::LS_INFO); }
- ~TraceObserver() {
- Trace::SetTraceCallback(nullptr);
- Trace::ReturnTrace();
- }
+ ~LogObserver() { rtc::LogMessage::RemoveLogToStream(&callback_); }
void PushExpectedLogLine(const std::string& expected_log_line) {
callback_.PushExpectedLogLine(expected_log_line);
}
- EventTypeWrapper Wait() {
- return callback_.Wait();
- }
+ bool Wait() { return callback_.Wait(); }
private:
- class Callback : public TraceCallback {
+ class Callback : public rtc::LogSink {
public:
- Callback() : done_(EventWrapper::Create()) {}
+ Callback() : done_(false, false) {}
- void Print(TraceLevel level, const char* message, int length) override {
+ void OnLogMessage(const std::string& message) override {
rtc::CritScope lock(&crit_sect_);
- std::string msg(message);
- if (msg.find("BitrateEstimator") != std::string::npos) {
- received_log_lines_.push_back(msg);
+ // Ignore log lines that are due to missing AST extensions, these are
+ // logged when we switch back from AST to TOF until the wrapping bitrate
+ // estimator gives up on using AST.
+ if (message.find("BitrateEstimator") != std::string::npos &&
+ message.find("packet is missing") == std::string::npos) {
+ received_log_lines_.push_back(message);
}
+
int num_popped = 0;
while (!received_log_lines_.empty() && !expected_log_lines_.empty()) {
std::string a = received_log_lines_.front();
@@ -80,19 +68,17 @@ class TraceObserver {
received_log_lines_.pop_front();
expected_log_lines_.pop_front();
num_popped++;
- EXPECT_TRUE(a.find(b) != std::string::npos);
+ EXPECT_TRUE(a.find(b) != std::string::npos) << a << " != " << b;
}
if (expected_log_lines_.size() <= 0) {
if (num_popped > 0) {
- done_->Set();
+ done_.Set();
}
return;
}
}
- EventTypeWrapper Wait() {
- return done_->Wait(test::CallTest::kDefaultTimeoutMs);
- }
+ bool Wait() { return done_.Wait(test::CallTest::kDefaultTimeoutMs); }
void PushExpectedLogLine(const std::string& expected_log_line) {
rtc::CritScope lock(&crit_sect_);
@@ -104,7 +90,7 @@ class TraceObserver {
rtc::CriticalSection crit_sect_;
Strings received_log_lines_ GUARDED_BY(crit_sect_);
Strings expected_log_lines_ GUARDED_BY(crit_sect_);
- rtc::scoped_ptr<EventWrapper> done_;
+ rtc::Event done_;
};
Callback callback_;
@@ -118,13 +104,13 @@ class BitrateEstimatorTest : public test::CallTest {
public:
BitrateEstimatorTest() : receive_config_(nullptr) {}
- virtual ~BitrateEstimatorTest() {
- EXPECT_TRUE(streams_.empty());
- }
+ virtual ~BitrateEstimatorTest() { EXPECT_TRUE(streams_.empty()); }
virtual void SetUp() {
+ AudioState::Config audio_state_config;
+ audio_state_config.voice_engine = &mock_voice_engine_;
Call::Config config;
- config.voice_engine = &fake_voice_engine_;
+ config.audio_state = AudioState::Create(audio_state_config);
receiver_call_.reset(Call::Create(config));
sender_call_.reset(Call::Create(config));
@@ -133,18 +119,19 @@ class BitrateEstimatorTest : public test::CallTest {
receive_transport_.reset(new test::DirectTransport(receiver_call_.get()));
receive_transport_->SetReceiver(sender_call_->Receiver());
- send_config_ = VideoSendStream::Config(send_transport_.get());
- send_config_.rtp.ssrcs.push_back(kSendSsrcs[0]);
+ video_send_config_ = VideoSendStream::Config(send_transport_.get());
+ video_send_config_.rtp.ssrcs.push_back(kVideoSendSsrcs[0]);
// Encoders will be set separately per stream.
- send_config_.encoder_settings.encoder = nullptr;
- send_config_.encoder_settings.payload_name = "FAKE";
- send_config_.encoder_settings.payload_type = kFakeSendPayloadType;
- encoder_config_.streams = test::CreateVideoStreams(1);
+ video_send_config_.encoder_settings.encoder = nullptr;
+ video_send_config_.encoder_settings.payload_name = "FAKE";
+ video_send_config_.encoder_settings.payload_type =
+ kFakeVideoSendPayloadType;
+ video_encoder_config_.streams = test::CreateVideoStreams(1);
receive_config_ = VideoReceiveStream::Config(receive_transport_.get());
// receive_config_.decoders will be set by every stream separately.
- receive_config_.rtp.remote_ssrc = send_config_.rtp.ssrcs[0];
- receive_config_.rtp.local_ssrc = kReceiverLocalSsrc;
+ receive_config_.rtp.remote_ssrc = video_send_config_.rtp.ssrcs[0];
+ receive_config_.rtp.local_ssrc = kReceiverLocalVideoSsrc;
receive_config_.rtp.remb = true;
receive_config_.rtp.extensions.push_back(
RtpExtension(RtpExtension::kTOffset, kTOFExtensionId));
@@ -154,7 +141,7 @@ class BitrateEstimatorTest : public test::CallTest {
virtual void TearDown() {
std::for_each(streams_.begin(), streams_.end(),
- std::mem_fun(&Stream::StopSending));
+ std::mem_fun(&Stream::StopSending));
send_transport_->StopSending();
receive_transport_->StopSending();
@@ -165,6 +152,7 @@ class BitrateEstimatorTest : public test::CallTest {
}
receiver_call_.reset();
+ sender_call_.reset();
}
protected:
@@ -181,23 +169,21 @@ class BitrateEstimatorTest : public test::CallTest {
frame_generator_capturer_(),
fake_encoder_(Clock::GetRealTimeClock()),
fake_decoder_() {
- test_->send_config_.rtp.ssrcs[0]++;
- test_->send_config_.encoder_settings.encoder = &fake_encoder_;
+ test_->video_send_config_.rtp.ssrcs[0]++;
+ test_->video_send_config_.encoder_settings.encoder = &fake_encoder_;
send_stream_ = test_->sender_call_->CreateVideoSendStream(
- test_->send_config_, test_->encoder_config_);
- RTC_DCHECK_EQ(1u, test_->encoder_config_.streams.size());
+ test_->video_send_config_, test_->video_encoder_config_);
+ RTC_DCHECK_EQ(1u, test_->video_encoder_config_.streams.size());
frame_generator_capturer_.reset(test::FrameGeneratorCapturer::Create(
- send_stream_->Input(),
- test_->encoder_config_.streams[0].width,
- test_->encoder_config_.streams[0].height,
- 30,
+ send_stream_->Input(), test_->video_encoder_config_.streams[0].width,
+ test_->video_encoder_config_.streams[0].height, 30,
Clock::GetRealTimeClock()));
send_stream_->Start();
frame_generator_capturer_->Start();
if (receive_audio) {
AudioReceiveStream::Config receive_config;
- receive_config.rtp.remote_ssrc = test_->send_config_.rtp.ssrcs[0];
+ receive_config.rtp.remote_ssrc = test_->video_send_config_.rtp.ssrcs[0];
// Bogus non-default id to prevent hitting a RTC_DCHECK when creating
// the AudioReceiveStream. Every receive stream has to correspond to
// an underlying channel id.
@@ -211,12 +197,13 @@ class BitrateEstimatorTest : public test::CallTest {
VideoReceiveStream::Decoder decoder;
decoder.decoder = &fake_decoder_;
decoder.payload_type =
- test_->send_config_.encoder_settings.payload_type;
+ test_->video_send_config_.encoder_settings.payload_type;
decoder.payload_name =
- test_->send_config_.encoder_settings.payload_name;
+ test_->video_send_config_.encoder_settings.payload_name;
+ test_->receive_config_.decoders.clear();
test_->receive_config_.decoders.push_back(decoder);
test_->receive_config_.rtp.remote_ssrc =
- test_->send_config_.rtp.ssrcs[0];
+ test_->video_send_config_.rtp.ssrcs[0];
test_->receive_config_.rtp.local_ssrc++;
video_receive_stream_ = test_->receiver_call_->CreateVideoReceiveStream(
test_->receive_config_);
@@ -262,8 +249,8 @@ class BitrateEstimatorTest : public test::CallTest {
test::FakeDecoder fake_decoder_;
};
- test::FakeVoiceEngine fake_voice_engine_;
- TraceObserver receiver_trace_;
+ testing::NiceMock<test::MockVoiceEngine> mock_voice_engine_;
+ LogObserver receiver_log_;
rtc::scoped_ptr<test::DirectTransport> send_transport_;
rtc::scoped_ptr<test::DirectTransport> receive_transport_;
rtc::scoped_ptr<Call> sender_call_;
@@ -278,89 +265,89 @@ static const char* kSingleStreamLog =
"RemoteBitrateEstimatorSingleStream: Instantiating.";
TEST_F(BitrateEstimatorTest, InstantiatesTOFPerDefaultForVideo) {
- send_config_.rtp.extensions.push_back(
+ video_send_config_.rtp.extensions.push_back(
RtpExtension(RtpExtension::kTOffset, kTOFExtensionId));
- receiver_trace_.PushExpectedLogLine(kSingleStreamLog);
- receiver_trace_.PushExpectedLogLine(kSingleStreamLog);
+ receiver_log_.PushExpectedLogLine(kSingleStreamLog);
+ receiver_log_.PushExpectedLogLine(kSingleStreamLog);
streams_.push_back(new Stream(this, false));
- EXPECT_EQ(kEventSignaled, receiver_trace_.Wait());
+ EXPECT_TRUE(receiver_log_.Wait());
}
TEST_F(BitrateEstimatorTest, ImmediatelySwitchToASTForAudio) {
- send_config_.rtp.extensions.push_back(
+ video_send_config_.rtp.extensions.push_back(
RtpExtension(RtpExtension::kAbsSendTime, kASTExtensionId));
- receiver_trace_.PushExpectedLogLine(kSingleStreamLog);
- receiver_trace_.PushExpectedLogLine(kSingleStreamLog);
- receiver_trace_.PushExpectedLogLine("Switching to absolute send time RBE.");
- receiver_trace_.PushExpectedLogLine(kAbsSendTimeLog);
+ receiver_log_.PushExpectedLogLine(kSingleStreamLog);
+ receiver_log_.PushExpectedLogLine(kSingleStreamLog);
+ receiver_log_.PushExpectedLogLine("Switching to absolute send time RBE.");
+ receiver_log_.PushExpectedLogLine(kAbsSendTimeLog);
streams_.push_back(new Stream(this, true));
- EXPECT_EQ(kEventSignaled, receiver_trace_.Wait());
+ EXPECT_TRUE(receiver_log_.Wait());
}
TEST_F(BitrateEstimatorTest, ImmediatelySwitchToASTForVideo) {
- send_config_.rtp.extensions.push_back(
+ video_send_config_.rtp.extensions.push_back(
RtpExtension(RtpExtension::kAbsSendTime, kASTExtensionId));
- receiver_trace_.PushExpectedLogLine(kSingleStreamLog);
- receiver_trace_.PushExpectedLogLine(kSingleStreamLog);
- receiver_trace_.PushExpectedLogLine("Switching to absolute send time RBE.");
- receiver_trace_.PushExpectedLogLine(kAbsSendTimeLog);
+ receiver_log_.PushExpectedLogLine(kSingleStreamLog);
+ receiver_log_.PushExpectedLogLine(kSingleStreamLog);
+ receiver_log_.PushExpectedLogLine("Switching to absolute send time RBE.");
+ receiver_log_.PushExpectedLogLine(kAbsSendTimeLog);
streams_.push_back(new Stream(this, false));
- EXPECT_EQ(kEventSignaled, receiver_trace_.Wait());
+ EXPECT_TRUE(receiver_log_.Wait());
}
TEST_F(BitrateEstimatorTest, SwitchesToASTForAudio) {
- receiver_trace_.PushExpectedLogLine(kSingleStreamLog);
- receiver_trace_.PushExpectedLogLine(kSingleStreamLog);
+ receiver_log_.PushExpectedLogLine(kSingleStreamLog);
+ receiver_log_.PushExpectedLogLine(kSingleStreamLog);
streams_.push_back(new Stream(this, true));
- EXPECT_EQ(kEventSignaled, receiver_trace_.Wait());
+ EXPECT_TRUE(receiver_log_.Wait());
- send_config_.rtp.extensions.push_back(
+ video_send_config_.rtp.extensions.push_back(
RtpExtension(RtpExtension::kAbsSendTime, kASTExtensionId));
- receiver_trace_.PushExpectedLogLine("Switching to absolute send time RBE.");
- receiver_trace_.PushExpectedLogLine(kAbsSendTimeLog);
+ receiver_log_.PushExpectedLogLine("Switching to absolute send time RBE.");
+ receiver_log_.PushExpectedLogLine(kAbsSendTimeLog);
streams_.push_back(new Stream(this, true));
- EXPECT_EQ(kEventSignaled, receiver_trace_.Wait());
+ EXPECT_TRUE(receiver_log_.Wait());
}
TEST_F(BitrateEstimatorTest, SwitchesToASTForVideo) {
- send_config_.rtp.extensions.push_back(
+ video_send_config_.rtp.extensions.push_back(
RtpExtension(RtpExtension::kTOffset, kTOFExtensionId));
- receiver_trace_.PushExpectedLogLine(kSingleStreamLog);
- receiver_trace_.PushExpectedLogLine(kSingleStreamLog);
+ receiver_log_.PushExpectedLogLine(kSingleStreamLog);
+ receiver_log_.PushExpectedLogLine(kSingleStreamLog);
streams_.push_back(new Stream(this, false));
- EXPECT_EQ(kEventSignaled, receiver_trace_.Wait());
+ EXPECT_TRUE(receiver_log_.Wait());
- send_config_.rtp.extensions[0] =
+ video_send_config_.rtp.extensions[0] =
RtpExtension(RtpExtension::kAbsSendTime, kASTExtensionId);
- receiver_trace_.PushExpectedLogLine("Switching to absolute send time RBE.");
- receiver_trace_.PushExpectedLogLine(kAbsSendTimeLog);
+ receiver_log_.PushExpectedLogLine("Switching to absolute send time RBE.");
+ receiver_log_.PushExpectedLogLine(kAbsSendTimeLog);
streams_.push_back(new Stream(this, false));
- EXPECT_EQ(kEventSignaled, receiver_trace_.Wait());
+ EXPECT_TRUE(receiver_log_.Wait());
}
TEST_F(BitrateEstimatorTest, SwitchesToASTThenBackToTOFForVideo) {
- send_config_.rtp.extensions.push_back(
+ video_send_config_.rtp.extensions.push_back(
RtpExtension(RtpExtension::kTOffset, kTOFExtensionId));
- receiver_trace_.PushExpectedLogLine(kSingleStreamLog);
- receiver_trace_.PushExpectedLogLine(kSingleStreamLog);
+ receiver_log_.PushExpectedLogLine(kSingleStreamLog);
+ receiver_log_.PushExpectedLogLine(kSingleStreamLog);
streams_.push_back(new Stream(this, false));
- EXPECT_EQ(kEventSignaled, receiver_trace_.Wait());
+ EXPECT_TRUE(receiver_log_.Wait());
- send_config_.rtp.extensions[0] =
+ video_send_config_.rtp.extensions[0] =
RtpExtension(RtpExtension::kAbsSendTime, kASTExtensionId);
- receiver_trace_.PushExpectedLogLine("Switching to absolute send time RBE.");
- receiver_trace_.PushExpectedLogLine(kAbsSendTimeLog);
+ receiver_log_.PushExpectedLogLine("Switching to absolute send time RBE.");
+ receiver_log_.PushExpectedLogLine(kAbsSendTimeLog);
streams_.push_back(new Stream(this, false));
- EXPECT_EQ(kEventSignaled, receiver_trace_.Wait());
+ EXPECT_TRUE(receiver_log_.Wait());
- send_config_.rtp.extensions[0] =
+ video_send_config_.rtp.extensions[0] =
RtpExtension(RtpExtension::kTOffset, kTOFExtensionId);
- receiver_trace_.PushExpectedLogLine(
+ receiver_log_.PushExpectedLogLine(
"WrappingBitrateEstimator: Switching to transmission time offset RBE.");
- receiver_trace_.PushExpectedLogLine(kSingleStreamLog);
+ receiver_log_.PushExpectedLogLine(kSingleStreamLog);
streams_.push_back(new Stream(this, false));
streams_[0]->StopSending();
streams_[1]->StopSending();
- EXPECT_EQ(kEventSignaled, receiver_trace_.Wait());
+ EXPECT_TRUE(receiver_log_.Wait());
}
} // namespace webrtc
diff --git a/webrtc/call/call.cc b/webrtc/call/call.cc
index 594ddf5c97..5c46a48f14 100644
--- a/webrtc/call/call.cc
+++ b/webrtc/call/call.cc
@@ -15,27 +15,33 @@
#include "webrtc/audio/audio_receive_stream.h"
#include "webrtc/audio/audio_send_stream.h"
+#include "webrtc/audio/audio_state.h"
+#include "webrtc/audio/scoped_voe_interface.h"
#include "webrtc/base/checks.h"
+#include "webrtc/base/logging.h"
#include "webrtc/base/scoped_ptr.h"
#include "webrtc/base/thread_annotations.h"
#include "webrtc/base/thread_checker.h"
#include "webrtc/base/trace_event.h"
#include "webrtc/call.h"
+#include "webrtc/call/bitrate_allocator.h"
#include "webrtc/call/congestion_controller.h"
#include "webrtc/call/rtc_event_log.h"
#include "webrtc/common.h"
#include "webrtc/config.h"
-#include "webrtc/modules/rtp_rtcp/interface/rtp_header_parser.h"
+#include "webrtc/modules/bitrate_controller/include/bitrate_controller.h"
+#include "webrtc/modules/pacing/paced_sender.h"
+#include "webrtc/modules/rtp_rtcp/include/rtp_header_parser.h"
#include "webrtc/modules/rtp_rtcp/source/byte_io.h"
-#include "webrtc/modules/utility/interface/process_thread.h"
+#include "webrtc/modules/utility/include/process_thread.h"
#include "webrtc/system_wrappers/include/cpu_info.h"
#include "webrtc/system_wrappers/include/critical_section_wrapper.h"
-#include "webrtc/system_wrappers/include/logging.h"
+#include "webrtc/system_wrappers/include/metrics.h"
#include "webrtc/system_wrappers/include/rw_lock_wrapper.h"
#include "webrtc/system_wrappers/include/trace.h"
+#include "webrtc/video/call_stats.h"
#include "webrtc/video/video_receive_stream.h"
#include "webrtc/video/video_send_stream.h"
-#include "webrtc/video_engine/call_stats.h"
#include "webrtc/voice_engine/include/voe_codec.h"
namespace webrtc {
@@ -44,7 +50,8 @@ const int Call::Config::kDefaultStartBitrateBps = 300000;
namespace internal {
-class Call : public webrtc::Call, public PacketReceiver {
+class Call : public webrtc::Call, public PacketReceiver,
+ public BitrateObserver {
public:
explicit Call(const Call::Config& config);
virtual ~Call();
@@ -83,6 +90,10 @@ class Call : public webrtc::Call, public PacketReceiver {
void OnSentPacket(const rtc::SentPacket& sent_packet) override;
+ // Implements BitrateObserver.
+ void OnNetworkChanged(uint32_t bitrate_bps, uint8_t fraction_loss,
+ int64_t rtt_ms) override;
+
private:
DeliveryStatus DeliverRtcp(MediaType media_type, const uint8_t* packet,
size_t length);
@@ -94,14 +105,28 @@ class Call : public webrtc::Call, public PacketReceiver {
void ConfigureSync(const std::string& sync_group)
EXCLUSIVE_LOCKS_REQUIRED(receive_crit_);
+ VoiceEngine* voice_engine() {
+ internal::AudioState* audio_state =
+ static_cast<internal::AudioState*>(config_.audio_state.get());
+ if (audio_state)
+ return audio_state->voice_engine();
+ else
+ return nullptr;
+ }
+
+ void UpdateSendHistograms() EXCLUSIVE_LOCKS_REQUIRED(&bitrate_crit_);
+ void UpdateReceiveHistograms();
+
+ Clock* const clock_;
+
const int num_cpu_cores_;
const rtc::scoped_ptr<ProcessThread> module_process_thread_;
const rtc::scoped_ptr<CallStats> call_stats_;
- const rtc::scoped_ptr<CongestionController> congestion_controller_;
+ const rtc::scoped_ptr<BitrateAllocator> bitrate_allocator_;
Call::Config config_;
rtc::ThreadChecker configuration_thread_checker_;
- bool network_enabled_;
+ bool network_enabled_;
rtc::scoped_ptr<RWLockWrapper> receive_crit_;
// Audio and Video receive streams are owned by the client that creates them.
@@ -123,7 +148,25 @@ class Call : public webrtc::Call, public PacketReceiver {
VideoSendStream::RtpStateMap suspended_video_send_ssrcs_;
RtcEventLog* event_log_ = nullptr;
- VoECodec* voe_codec_ = nullptr;
+
+ // The following members are only accessed (exclusively) from one thread and
+ // from the destructor, and therefore doesn't need any explicit
+ // synchronization.
+ int64_t received_video_bytes_;
+ int64_t received_audio_bytes_;
+ int64_t received_rtcp_bytes_;
+ int64_t first_rtp_packet_received_ms_;
+ int64_t last_rtp_packet_received_ms_;
+ int64_t first_packet_sent_ms_;
+
+ // TODO(holmer): Remove this lock once BitrateController no longer calls
+ // OnNetworkChanged from multiple threads.
+ rtc::CriticalSection bitrate_crit_;
+ int64_t estimated_send_bitrate_sum_kbits_ GUARDED_BY(&bitrate_crit_);
+ int64_t pacer_bitrate_sum_kbits_ GUARDED_BY(&bitrate_crit_);
+ int64_t num_bitrate_updates_ GUARDED_BY(&bitrate_crit_);
+
+ const rtc::scoped_ptr<CongestionController> congestion_controller_;
RTC_DISALLOW_COPY_AND_ASSIGN(Call);
};
@@ -136,15 +179,29 @@ Call* Call::Create(const Call::Config& config) {
namespace internal {
Call::Call(const Call::Config& config)
- : num_cpu_cores_(CpuInfo::DetectNumberOfCores()),
+ : clock_(Clock::GetRealTimeClock()),
+ num_cpu_cores_(CpuInfo::DetectNumberOfCores()),
module_process_thread_(ProcessThread::Create("ModuleProcessThread")),
- call_stats_(new CallStats()),
- congestion_controller_(new CongestionController(
- module_process_thread_.get(), call_stats_.get())),
+ call_stats_(new CallStats(clock_)),
+ bitrate_allocator_(new BitrateAllocator()),
config_(config),
network_enabled_(true),
receive_crit_(RWLockWrapper::CreateRWLock()),
- send_crit_(RWLockWrapper::CreateRWLock()) {
+ send_crit_(RWLockWrapper::CreateRWLock()),
+ received_video_bytes_(0),
+ received_audio_bytes_(0),
+ received_rtcp_bytes_(0),
+ first_rtp_packet_received_ms_(-1),
+ last_rtp_packet_received_ms_(-1),
+ first_packet_sent_ms_(-1),
+ estimated_send_bitrate_sum_kbits_(0),
+ pacer_bitrate_sum_kbits_(0),
+ num_bitrate_updates_(0),
+ congestion_controller_(
+ new CongestionController(module_process_thread_.get(),
+ call_stats_.get(),
+ this)) {
+ RTC_DCHECK(configuration_thread_checker_.CalledOnValidThread());
RTC_DCHECK_GE(config.bitrate_config.min_bitrate_bps, 0);
RTC_DCHECK_GE(config.bitrate_config.start_bitrate_bps,
config.bitrate_config.min_bitrate_bps);
@@ -152,12 +209,9 @@ Call::Call(const Call::Config& config)
RTC_DCHECK_GE(config.bitrate_config.max_bitrate_bps,
config.bitrate_config.start_bitrate_bps);
}
- if (config.voice_engine) {
- // Keep a reference to VoECodec, so we're sure the VoiceEngine lives for the
- // duration of the call.
- voe_codec_ = VoECodec::GetInterface(config.voice_engine);
- if (voe_codec_)
- event_log_ = voe_codec_->GetEventLog();
+ if (config.audio_state.get()) {
+ ScopedVoEInterface<VoECodec> voe_codec(voice_engine());
+ event_log_ = voe_codec->GetEventLog();
}
Trace::CreateTrace();
@@ -168,10 +222,14 @@ Call::Call(const Call::Config& config)
config_.bitrate_config.min_bitrate_bps,
config_.bitrate_config.start_bitrate_bps,
config_.bitrate_config.max_bitrate_bps);
+
+ congestion_controller_->GetBitrateController()->SetEventLog(event_log_);
}
Call::~Call() {
RTC_DCHECK(configuration_thread_checker_.CalledOnValidThread());
+ UpdateSendHistograms();
+ UpdateReceiveHistograms();
RTC_CHECK(audio_send_ssrcs_.empty());
RTC_CHECK(video_send_ssrcs_.empty());
RTC_CHECK(video_send_streams_.empty());
@@ -182,9 +240,53 @@ Call::~Call() {
module_process_thread_->DeRegisterModule(call_stats_.get());
module_process_thread_->Stop();
Trace::ReturnTrace();
+}
+
+void Call::UpdateSendHistograms() {
+ if (num_bitrate_updates_ == 0 || first_packet_sent_ms_ == -1)
+ return;
+ int64_t elapsed_sec =
+ (clock_->TimeInMilliseconds() - first_packet_sent_ms_) / 1000;
+ if (elapsed_sec < metrics::kMinRunTimeInSeconds)
+ return;
+ int send_bitrate_kbps =
+ estimated_send_bitrate_sum_kbits_ / num_bitrate_updates_;
+ int pacer_bitrate_kbps = pacer_bitrate_sum_kbits_ / num_bitrate_updates_;
+ if (send_bitrate_kbps > 0) {
+ RTC_HISTOGRAM_COUNTS_SPARSE_100000("WebRTC.Call.EstimatedSendBitrateInKbps",
+ send_bitrate_kbps);
+ }
+ if (pacer_bitrate_kbps > 0) {
+ RTC_HISTOGRAM_COUNTS_SPARSE_100000("WebRTC.Call.PacerBitrateInKbps",
+ pacer_bitrate_kbps);
+ }
+}
- if (voe_codec_)
- voe_codec_->Release();
+void Call::UpdateReceiveHistograms() {
+ if (first_rtp_packet_received_ms_ == -1)
+ return;
+ int64_t elapsed_sec =
+ (last_rtp_packet_received_ms_ - first_rtp_packet_received_ms_) / 1000;
+ if (elapsed_sec < metrics::kMinRunTimeInSeconds)
+ return;
+ int audio_bitrate_kbps = received_audio_bytes_ * 8 / elapsed_sec / 1000;
+ int video_bitrate_kbps = received_video_bytes_ * 8 / elapsed_sec / 1000;
+ int rtcp_bitrate_bps = received_rtcp_bytes_ * 8 / elapsed_sec;
+ if (video_bitrate_kbps > 0) {
+ RTC_HISTOGRAM_COUNTS_SPARSE_100000("WebRTC.Call.VideoBitrateReceivedInKbps",
+ video_bitrate_kbps);
+ }
+ if (audio_bitrate_kbps > 0) {
+ RTC_HISTOGRAM_COUNTS_SPARSE_100000("WebRTC.Call.AudioBitrateReceivedInKbps",
+ audio_bitrate_kbps);
+ }
+ if (rtcp_bitrate_bps > 0) {
+ RTC_HISTOGRAM_COUNTS_SPARSE_100000("WebRTC.Call.RtcpBitrateReceivedInBps",
+ rtcp_bitrate_bps);
+ }
+ RTC_HISTOGRAM_COUNTS_SPARSE_100000(
+ "WebRTC.Call.BitrateReceivedInKbps",
+ audio_bitrate_kbps + video_bitrate_kbps + rtcp_bitrate_bps / 1000);
}
PacketReceiver* Call::Receiver() {
@@ -198,8 +300,8 @@ webrtc::AudioSendStream* Call::CreateAudioSendStream(
const webrtc::AudioSendStream::Config& config) {
TRACE_EVENT0("webrtc", "Call::CreateAudioSendStream");
RTC_DCHECK(configuration_thread_checker_.CalledOnValidThread());
- AudioSendStream* send_stream =
- new AudioSendStream(config, config_.voice_engine);
+ AudioSendStream* send_stream = new AudioSendStream(
+ config, config_.audio_state, congestion_controller_.get());
if (!network_enabled_)
send_stream->SignalNetworkState(kNetworkDown);
{
@@ -234,8 +336,7 @@ webrtc::AudioReceiveStream* Call::CreateAudioReceiveStream(
TRACE_EVENT0("webrtc", "Call::CreateAudioReceiveStream");
RTC_DCHECK(configuration_thread_checker_.CalledOnValidThread());
AudioReceiveStream* receive_stream = new AudioReceiveStream(
- congestion_controller_->GetRemoteBitrateEstimator(false), config,
- config_.voice_engine);
+ congestion_controller_.get(), config, config_.audio_state);
{
WriteLockScoped write_lock(*receive_crit_);
RTC_DCHECK(audio_receive_ssrcs_.find(config.rtp.remote_ssrc) ==
@@ -279,8 +380,8 @@ webrtc::VideoSendStream* Call::CreateVideoSendStream(
// the call has already started.
VideoSendStream* send_stream = new VideoSendStream(
num_cpu_cores_, module_process_thread_.get(), call_stats_.get(),
- congestion_controller_.get(), config, encoder_config,
- suspended_video_send_ssrcs_);
+ congestion_controller_.get(), bitrate_allocator_.get(), config,
+ encoder_config, suspended_video_send_ssrcs_);
if (!network_enabled_)
send_stream->SignalNetworkState(kNetworkDown);
@@ -338,7 +439,7 @@ webrtc::VideoReceiveStream* Call::CreateVideoReceiveStream(
RTC_DCHECK(configuration_thread_checker_.CalledOnValidThread());
VideoReceiveStream* receive_stream = new VideoReceiveStream(
num_cpu_cores_, congestion_controller_.get(), config,
- config_.voice_engine, module_process_thread_.get(), call_stats_.get());
+ voice_engine(), module_process_thread_.get(), call_stats_.get());
WriteLockScoped write_lock(*receive_crit_);
RTC_DCHECK(video_receive_ssrcs_.find(config.rtp.remote_ssrc) ==
@@ -463,12 +564,48 @@ void Call::SignalNetworkState(NetworkState state) {
}
void Call::OnSentPacket(const rtc::SentPacket& sent_packet) {
+ if (first_packet_sent_ms_ == -1)
+ first_packet_sent_ms_ = clock_->TimeInMilliseconds();
congestion_controller_->OnSentPacket(sent_packet);
}
+void Call::OnNetworkChanged(uint32_t target_bitrate_bps, uint8_t fraction_loss,
+ int64_t rtt_ms) {
+ uint32_t allocated_bitrate_bps = bitrate_allocator_->OnNetworkChanged(
+ target_bitrate_bps, fraction_loss, rtt_ms);
+
+ int pad_up_to_bitrate_bps = 0;
+ {
+ ReadLockScoped read_lock(*send_crit_);
+ // No need to update as long as we're not sending.
+ if (video_send_streams_.empty())
+ return;
+
+ for (VideoSendStream* stream : video_send_streams_)
+ pad_up_to_bitrate_bps += stream->GetPaddingNeededBps();
+ }
+ // Allocated bitrate might be higher than bitrate estimate if enforcing min
+ // bitrate, or lower if estimate is higher than the sum of max bitrates, so
+ // set the pacer bitrate to the maximum of the two.
+ uint32_t pacer_bitrate_bps =
+ std::max(target_bitrate_bps, allocated_bitrate_bps);
+ {
+ rtc::CritScope lock(&bitrate_crit_);
+ // We only update these stats if we have send streams, and assume that
+ // OnNetworkChanged is called roughly with a fixed frequency.
+ estimated_send_bitrate_sum_kbits_ += target_bitrate_bps / 1000;
+ pacer_bitrate_sum_kbits_ += pacer_bitrate_bps / 1000;
+ ++num_bitrate_updates_;
+ }
+ congestion_controller_->UpdatePacerBitrate(
+ target_bitrate_bps / 1000,
+ PacedSender::kDefaultPaceMultiplier * pacer_bitrate_bps / 1000,
+ pad_up_to_bitrate_bps / 1000);
+}
+
void Call::ConfigureSync(const std::string& sync_group) {
// Set sync only if there was no previous one.
- if (config_.voice_engine == nullptr || sync_group.empty())
+ if (voice_engine() == nullptr || sync_group.empty())
return;
AudioReceiveStream* sync_audio_stream = nullptr;
@@ -506,10 +643,10 @@ void Call::ConfigureSync(const std::string& sync_group) {
}
// Only sync the first A/V pair within this sync group.
if (sync_audio_stream != nullptr && num_synced_streams == 1) {
- video_stream->SetSyncChannel(config_.voice_engine,
+ video_stream->SetSyncChannel(voice_engine(),
sync_audio_stream->config().voe_channel_id);
} else {
- video_stream->SetSyncChannel(config_.voice_engine, -1);
+ video_stream->SetSyncChannel(voice_engine(), -1);
}
}
}
@@ -517,10 +654,12 @@ void Call::ConfigureSync(const std::string& sync_group) {
PacketReceiver::DeliveryStatus Call::DeliverRtcp(MediaType media_type,
const uint8_t* packet,
size_t length) {
+ TRACE_EVENT0("webrtc", "Call::DeliverRtcp");
// TODO(pbos): Figure out what channel needs it actually.
// Do NOT broadcast! Also make sure it's a valid packet.
// Return DELIVERY_UNKNOWN_SSRC if it can be determined that
// there's no receiver of the packet.
+ received_rtcp_bytes_ += length;
bool rtcp_delivered = false;
if (media_type == MediaType::ANY || media_type == MediaType::VIDEO) {
ReadLockScoped read_lock(*receive_crit_);
@@ -549,16 +688,21 @@ PacketReceiver::DeliveryStatus Call::DeliverRtp(MediaType media_type,
const uint8_t* packet,
size_t length,
const PacketTime& packet_time) {
+ TRACE_EVENT0("webrtc", "Call::DeliverRtp");
// Minimum RTP header size.
if (length < 12)
return DELIVERY_PACKET_ERROR;
- uint32_t ssrc = ByteReader<uint32_t>::ReadBigEndian(&packet[8]);
+ last_rtp_packet_received_ms_ = clock_->TimeInMilliseconds();
+ if (first_rtp_packet_received_ms_ == -1)
+ first_rtp_packet_received_ms_ = last_rtp_packet_received_ms_;
+ uint32_t ssrc = ByteReader<uint32_t>::ReadBigEndian(&packet[8]);
ReadLockScoped read_lock(*receive_crit_);
if (media_type == MediaType::ANY || media_type == MediaType::AUDIO) {
auto it = audio_receive_ssrcs_.find(ssrc);
if (it != audio_receive_ssrcs_.end()) {
+ received_audio_bytes_ += length;
auto status = it->second->DeliverRtp(packet, length, packet_time)
? DELIVERY_OK
: DELIVERY_PACKET_ERROR;
@@ -570,6 +714,7 @@ PacketReceiver::DeliveryStatus Call::DeliverRtp(MediaType media_type,
if (media_type == MediaType::ANY || media_type == MediaType::VIDEO) {
auto it = video_receive_ssrcs_.find(ssrc);
if (it != video_receive_ssrcs_.end()) {
+ received_video_bytes_ += length;
auto status = it->second->DeliverRtp(packet, length, packet_time)
? DELIVERY_OK
: DELIVERY_PACKET_ERROR;
diff --git a/webrtc/call/call_perf_tests.cc b/webrtc/call/call_perf_tests.cc
index c37b83bab4..3adcb10b09 100644
--- a/webrtc/call/call_perf_tests.cc
+++ b/webrtc/call/call_perf_tests.cc
@@ -18,8 +18,10 @@
#include "webrtc/base/thread_annotations.h"
#include "webrtc/call.h"
#include "webrtc/call/transport_adapter.h"
-#include "webrtc/modules/audio_coding/main/include/audio_coding_module.h"
-#include "webrtc/modules/rtp_rtcp/interface/rtp_header_parser.h"
+#include "webrtc/common.h"
+#include "webrtc/config.h"
+#include "webrtc/modules/audio_coding/include/audio_coding_module.h"
+#include "webrtc/modules/rtp_rtcp/include/rtp_header_parser.h"
#include "webrtc/modules/rtp_rtcp/source/rtcp_utility.h"
#include "webrtc/system_wrappers/include/critical_section_wrapper.h"
#include "webrtc/system_wrappers/include/rtp_to_ntp.h"
@@ -172,7 +174,7 @@ class VideoRtcpAndSyncObserver : public SyncRtcpObserver, public VideoRenderer {
false);
}
if (time_since_creation > kMinRunTimeMs)
- observation_complete_->Set();
+ observation_complete_.Set();
}
}
@@ -189,6 +191,8 @@ class VideoRtcpAndSyncObserver : public SyncRtcpObserver, public VideoRenderer {
void CallPerfTest::TestAudioVideoSync(bool fec, bool create_audio_first) {
const char* kSyncGroup = "av_sync";
+ const uint32_t kAudioSendSsrc = 1234;
+ const uint32_t kAudioRecvSsrc = 5678;
class AudioPacketReceiver : public PacketReceiver {
public:
AudioPacketReceiver(int channel, VoENetwork* voe_network)
@@ -228,35 +232,45 @@ void CallPerfTest::TestAudioVideoSync(bool fec, bool create_audio_first) {
test::FakeAudioDevice fake_audio_device(Clock::GetRealTimeClock(),
audio_filename);
EXPECT_EQ(0, voe_base->Init(&fake_audio_device, nullptr));
- int channel = voe_base->CreateChannel();
+ Config voe_config;
+ voe_config.Set<VoicePacing>(new VoicePacing(true));
+ int send_channel_id = voe_base->CreateChannel(voe_config);
+ int recv_channel_id = voe_base->CreateChannel();
SyncRtcpObserver audio_observer;
+ AudioState::Config send_audio_state_config;
+ send_audio_state_config.voice_engine = voice_engine;
+ Call::Config sender_config;
+ sender_config.audio_state = AudioState::Create(send_audio_state_config);
Call::Config receiver_config;
- receiver_config.voice_engine = voice_engine;
- CreateCalls(Call::Config(), receiver_config);
+ receiver_config.audio_state = sender_config.audio_state;
+ CreateCalls(sender_config, receiver_config);
- CodecInst isac = {103, "ISAC", 16000, 480, 1, 32000};
- EXPECT_EQ(0, voe_codec->SetSendCodec(channel, isac));
-
- AudioPacketReceiver voe_packet_receiver(channel, voe_network);
+ AudioPacketReceiver voe_send_packet_receiver(send_channel_id, voe_network);
+ AudioPacketReceiver voe_recv_packet_receiver(recv_channel_id, voe_network);
FakeNetworkPipe::Config net_config;
net_config.queue_delay_ms = 500;
net_config.loss_percent = 5;
test::PacketTransport audio_send_transport(
nullptr, &audio_observer, test::PacketTransport::kSender, net_config);
- audio_send_transport.SetReceiver(&voe_packet_receiver);
+ audio_send_transport.SetReceiver(&voe_recv_packet_receiver);
test::PacketTransport audio_receive_transport(
nullptr, &audio_observer, test::PacketTransport::kReceiver, net_config);
- audio_receive_transport.SetReceiver(&voe_packet_receiver);
+ audio_receive_transport.SetReceiver(&voe_send_packet_receiver);
+
+ internal::TransportAdapter send_transport_adapter(&audio_send_transport);
+ send_transport_adapter.Enable();
+ EXPECT_EQ(0, voe_network->RegisterExternalTransport(send_channel_id,
+ send_transport_adapter));
- internal::TransportAdapter transport_adapter(&audio_send_transport);
- transport_adapter.Enable();
- EXPECT_EQ(0,
- voe_network->RegisterExternalTransport(channel, transport_adapter));
+ internal::TransportAdapter recv_transport_adapter(&audio_receive_transport);
+ recv_transport_adapter.Enable();
+ EXPECT_EQ(0, voe_network->RegisterExternalTransport(recv_channel_id,
+ recv_transport_adapter));
- VideoRtcpAndSyncObserver observer(Clock::GetRealTimeClock(), channel,
+ VideoRtcpAndSyncObserver observer(Clock::GetRealTimeClock(), recv_channel_id,
voe_sync, &audio_observer);
test::PacketTransport sync_send_transport(sender_call_.get(), &observer,
@@ -270,34 +284,45 @@ void CallPerfTest::TestAudioVideoSync(bool fec, bool create_audio_first) {
test::FakeDecoder fake_decoder;
- CreateSendConfig(1, &sync_send_transport);
+ CreateSendConfig(1, 0, &sync_send_transport);
CreateMatchingReceiveConfigs(&sync_receive_transport);
- send_config_.rtp.nack.rtp_history_ms = kNackRtpHistoryMs;
+ AudioSendStream::Config audio_send_config(&audio_send_transport);
+ audio_send_config.voe_channel_id = send_channel_id;
+ audio_send_config.rtp.ssrc = kAudioSendSsrc;
+ AudioSendStream* audio_send_stream =
+ sender_call_->CreateAudioSendStream(audio_send_config);
+
+ CodecInst isac = {103, "ISAC", 16000, 480, 1, 32000};
+ EXPECT_EQ(0, voe_codec->SetSendCodec(send_channel_id, isac));
+
+ video_send_config_.rtp.nack.rtp_history_ms = kNackRtpHistoryMs;
if (fec) {
- send_config_.rtp.fec.red_payload_type = kRedPayloadType;
- send_config_.rtp.fec.ulpfec_payload_type = kUlpfecPayloadType;
- receive_configs_[0].rtp.fec.red_payload_type = kRedPayloadType;
- receive_configs_[0].rtp.fec.ulpfec_payload_type = kUlpfecPayloadType;
+ video_send_config_.rtp.fec.red_payload_type = kRedPayloadType;
+ video_send_config_.rtp.fec.ulpfec_payload_type = kUlpfecPayloadType;
+ video_receive_configs_[0].rtp.fec.red_payload_type = kRedPayloadType;
+ video_receive_configs_[0].rtp.fec.ulpfec_payload_type = kUlpfecPayloadType;
}
- receive_configs_[0].rtp.nack.rtp_history_ms = 1000;
- receive_configs_[0].renderer = &observer;
- receive_configs_[0].sync_group = kSyncGroup;
+ video_receive_configs_[0].rtp.nack.rtp_history_ms = 1000;
+ video_receive_configs_[0].renderer = &observer;
+ video_receive_configs_[0].sync_group = kSyncGroup;
- AudioReceiveStream::Config audio_config;
- audio_config.voe_channel_id = channel;
- audio_config.sync_group = kSyncGroup;
+ AudioReceiveStream::Config audio_recv_config;
+ audio_recv_config.rtp.remote_ssrc = kAudioSendSsrc;
+ audio_recv_config.rtp.local_ssrc = kAudioRecvSsrc;
+ audio_recv_config.voe_channel_id = recv_channel_id;
+ audio_recv_config.sync_group = kSyncGroup;
- AudioReceiveStream* audio_receive_stream = nullptr;
+ AudioReceiveStream* audio_receive_stream;
if (create_audio_first) {
audio_receive_stream =
- receiver_call_->CreateAudioReceiveStream(audio_config);
- CreateStreams();
+ receiver_call_->CreateAudioReceiveStream(audio_recv_config);
+ CreateVideoStreams();
} else {
- CreateStreams();
+ CreateVideoStreams();
audio_receive_stream =
- receiver_call_->CreateAudioReceiveStream(audio_config);
+ receiver_call_->CreateAudioReceiveStream(audio_recv_config);
}
CreateFrameGeneratorCapturer();
@@ -305,16 +330,16 @@ void CallPerfTest::TestAudioVideoSync(bool fec, bool create_audio_first) {
Start();
fake_audio_device.Start();
- EXPECT_EQ(0, voe_base->StartPlayout(channel));
- EXPECT_EQ(0, voe_base->StartReceive(channel));
- EXPECT_EQ(0, voe_base->StartSend(channel));
+ EXPECT_EQ(0, voe_base->StartPlayout(recv_channel_id));
+ EXPECT_EQ(0, voe_base->StartReceive(recv_channel_id));
+ EXPECT_EQ(0, voe_base->StartSend(send_channel_id));
- EXPECT_EQ(kEventSignaled, observer.Wait())
+ EXPECT_TRUE(observer.Wait())
<< "Timed out while waiting for audio and video to be synchronized.";
- EXPECT_EQ(0, voe_base->StopSend(channel));
- EXPECT_EQ(0, voe_base->StopReceive(channel));
- EXPECT_EQ(0, voe_base->StopPlayout(channel));
+ EXPECT_EQ(0, voe_base->StopSend(send_channel_id));
+ EXPECT_EQ(0, voe_base->StopReceive(recv_channel_id));
+ EXPECT_EQ(0, voe_base->StopPlayout(recv_channel_id));
fake_audio_device.Stop();
Stop();
@@ -323,16 +348,18 @@ void CallPerfTest::TestAudioVideoSync(bool fec, bool create_audio_first) {
audio_send_transport.StopSending();
audio_receive_transport.StopSending();
- voe_base->DeleteChannel(channel);
+ DestroyStreams();
+
+ sender_call_->DestroyAudioSendStream(audio_send_stream);
+ receiver_call_->DestroyAudioReceiveStream(audio_receive_stream);
+
+ voe_base->DeleteChannel(send_channel_id);
+ voe_base->DeleteChannel(recv_channel_id);
voe_base->Release();
voe_codec->Release();
voe_network->Release();
voe_sync->Release();
- DestroyStreams();
-
- receiver_call_->DestroyAudioReceiveStream(audio_receive_stream);
-
DestroyCalls();
VoiceEngine::Delete(voice_engine);
@@ -357,8 +384,12 @@ void CallPerfTest::TestCaptureNtpTime(const FakeNetworkPipe::Config& net_config,
class CaptureNtpTimeObserver : public test::EndToEndTest,
public VideoRenderer {
public:
- CaptureNtpTimeObserver(int threshold_ms, int start_time_ms, int run_time_ms)
+ CaptureNtpTimeObserver(const FakeNetworkPipe::Config& net_config,
+ int threshold_ms,
+ int start_time_ms,
+ int run_time_ms)
: EndToEndTest(kLongTimeoutMs),
+ net_config_(net_config),
clock_(Clock::GetRealTimeClock()),
threshold_ms_(threshold_ms),
start_time_ms_(start_time_ms),
@@ -369,6 +400,16 @@ void CallPerfTest::TestCaptureNtpTime(const FakeNetworkPipe::Config& net_config,
rtp_start_timestamp_(0) {}
private:
+ test::PacketTransport* CreateSendTransport(Call* sender_call) override {
+ return new test::PacketTransport(
+ sender_call, this, test::PacketTransport::kSender, net_config_);
+ }
+
+ test::PacketTransport* CreateReceiveTransport() override {
+ return new test::PacketTransport(
+ nullptr, this, test::PacketTransport::kReceiver, net_config_);
+ }
+
void RenderFrame(const VideoFrame& video_frame,
int time_to_render_ms) override {
rtc::CritScope lock(&crit_);
@@ -386,7 +427,7 @@ void CallPerfTest::TestCaptureNtpTime(const FakeNetworkPipe::Config& net_config,
}
if (time_since_creation > run_time_ms_) {
- observation_complete_->Set();
+ observation_complete_.Set();
}
FrameCaptureTimeList::iterator iter =
@@ -437,21 +478,23 @@ void CallPerfTest::TestCaptureNtpTime(const FakeNetworkPipe::Config& net_config,
capturer_ = frame_generator_capturer;
}
- void ModifyConfigs(VideoSendStream::Config* send_config,
- std::vector<VideoReceiveStream::Config>* receive_configs,
- VideoEncoderConfig* encoder_config) override {
+ void ModifyVideoConfigs(
+ VideoSendStream::Config* send_config,
+ std::vector<VideoReceiveStream::Config>* receive_configs,
+ VideoEncoderConfig* encoder_config) override {
(*receive_configs)[0].renderer = this;
// Enable the receiver side rtt calculation.
(*receive_configs)[0].rtp.rtcp_xr.receiver_reference_time_report = true;
}
void PerformTest() override {
- EXPECT_EQ(kEventSignaled, Wait()) << "Timed out while waiting for "
- "estimated capture NTP time to be "
- "within bounds.";
+ EXPECT_TRUE(Wait()) << "Timed out while waiting for "
+ "estimated capture NTP time to be "
+ "within bounds.";
}
rtc::CriticalSection crit_;
+ const FakeNetworkPipe::Config net_config_;
Clock* const clock_;
int threshold_ms_;
int start_time_ms_;
@@ -462,9 +505,9 @@ void CallPerfTest::TestCaptureNtpTime(const FakeNetworkPipe::Config& net_config,
uint32_t rtp_start_timestamp_;
typedef std::map<uint32_t, uint32_t> FrameCaptureTimeList;
FrameCaptureTimeList capture_time_list_ GUARDED_BY(&crit_);
- } test(threshold_ms, start_time_ms, run_time_ms);
+ } test(net_config, threshold_ms, start_time_ms, run_time_ms);
- RunBaseTest(&test, net_config);
+ RunBaseTest(&test);
}
TEST_F(CallPerfTest, CaptureNtpTimeWithNetworkDelay) {
@@ -501,26 +544,26 @@ void CallPerfTest::TestCpuOveruse(LoadObserver::Load tested_load,
void OnLoadUpdate(Load load) override {
if (load == tested_load_)
- observation_complete_->Set();
+ observation_complete_.Set();
}
- void ModifyConfigs(VideoSendStream::Config* send_config,
- std::vector<VideoReceiveStream::Config>* receive_configs,
- VideoEncoderConfig* encoder_config) override {
+ void ModifyVideoConfigs(
+ VideoSendStream::Config* send_config,
+ std::vector<VideoReceiveStream::Config>* receive_configs,
+ VideoEncoderConfig* encoder_config) override {
send_config->overuse_callback = this;
send_config->encoder_settings.encoder = &encoder_;
}
void PerformTest() override {
- EXPECT_EQ(kEventSignaled, Wait())
- << "Timed out before receiving an overuse callback.";
+ EXPECT_TRUE(Wait()) << "Timed out before receiving an overuse callback.";
}
LoadObserver::Load tested_load_;
test::DelayedEncoder encoder_;
} test(tested_load, encode_delay_ms);
- RunBaseTest(&test, FakeNetworkPipe::Config());
+ RunBaseTest(&test);
}
TEST_F(CallPerfTest, ReceivesCpuUnderuse) {
@@ -581,21 +624,22 @@ void CallPerfTest::TestMinTransmitBitrate(bool pad_to_min_bitrate) {
}
if (num_bitrate_observations_in_range_ ==
kNumBitrateObservationsInRange)
- observation_complete_->Set();
+ observation_complete_.Set();
}
}
return SEND_PACKET;
}
- void OnStreamsCreated(
+ void OnVideoStreamsCreated(
VideoSendStream* send_stream,
const std::vector<VideoReceiveStream*>& receive_streams) override {
send_stream_ = send_stream;
}
- void ModifyConfigs(VideoSendStream::Config* send_config,
- std::vector<VideoReceiveStream::Config>* receive_configs,
- VideoEncoderConfig* encoder_config) override {
+ void ModifyVideoConfigs(
+ VideoSendStream::Config* send_config,
+ std::vector<VideoReceiveStream::Config>* receive_configs,
+ VideoEncoderConfig* encoder_config) override {
if (pad_to_min_bitrate_) {
encoder_config->min_transmit_bitrate_bps = kMinTransmitBitrateBps;
} else {
@@ -604,8 +648,7 @@ void CallPerfTest::TestMinTransmitBitrate(bool pad_to_min_bitrate) {
}
void PerformTest() override {
- EXPECT_EQ(kEventSignaled, Wait())
- << "Timeout while waiting for send-bitrate stats.";
+ EXPECT_TRUE(Wait()) << "Timeout while waiting for send-bitrate stats.";
}
VideoSendStream* send_stream_;
@@ -614,7 +657,7 @@ void CallPerfTest::TestMinTransmitBitrate(bool pad_to_min_bitrate) {
} test(pad_to_min_bitrate);
fake_encoder_.SetMaxBitrate(kMaxEncodeBitrateKbps);
- RunBaseTest(&test, FakeNetworkPipe::Config());
+ RunBaseTest(&test);
}
TEST_F(CallPerfTest, PadsToMinTransmitBitrate) { TestMinTransmitBitrate(true); }
@@ -633,7 +676,7 @@ TEST_F(CallPerfTest, KeepsHighBitrateWhenReconfiguringSender) {
BitrateObserver()
: EndToEndTest(kDefaultTimeoutMs),
FakeEncoder(Clock::GetRealTimeClock()),
- time_to_reconfigure_(webrtc::EventWrapper::Create()),
+ time_to_reconfigure_(false, false),
encoder_inits_(0),
last_set_bitrate_(0),
send_stream_(nullptr) {}
@@ -652,7 +695,7 @@ TEST_F(CallPerfTest, KeepsHighBitrateWhenReconfiguringSender) {
last_set_bitrate_,
kPermittedReconfiguredBitrateDiffKbps)
<< "Encoder reconfigured with bitrate too far away from last set.";
- observation_complete_->Set();
+ observation_complete_.Set();
}
return FakeEncoder::InitEncode(config, number_of_cores, max_payload_size);
}
@@ -662,7 +705,7 @@ TEST_F(CallPerfTest, KeepsHighBitrateWhenReconfiguringSender) {
last_set_bitrate_ = new_target_bitrate_kbps;
if (encoder_inits_ == 1 &&
new_target_bitrate_kbps > kReconfigureThresholdKbps) {
- time_to_reconfigure_->Set();
+ time_to_reconfigure_.Set();
}
return FakeEncoder::SetRates(new_target_bitrate_kbps, framerate);
}
@@ -673,9 +716,10 @@ TEST_F(CallPerfTest, KeepsHighBitrateWhenReconfiguringSender) {
return config;
}
- void ModifyConfigs(VideoSendStream::Config* send_config,
- std::vector<VideoReceiveStream::Config>* receive_configs,
- VideoEncoderConfig* encoder_config) override {
+ void ModifyVideoConfigs(
+ VideoSendStream::Config* send_config,
+ std::vector<VideoReceiveStream::Config>* receive_configs,
+ VideoEncoderConfig* encoder_config) override {
send_config->encoder_settings.encoder = this;
encoder_config->streams[0].min_bitrate_bps = 50000;
encoder_config->streams[0].target_bitrate_bps =
@@ -684,32 +728,32 @@ TEST_F(CallPerfTest, KeepsHighBitrateWhenReconfiguringSender) {
encoder_config_ = *encoder_config;
}
- void OnStreamsCreated(
+ void OnVideoStreamsCreated(
VideoSendStream* send_stream,
const std::vector<VideoReceiveStream*>& receive_streams) override {
send_stream_ = send_stream;
}
void PerformTest() override {
- ASSERT_EQ(kEventSignaled, time_to_reconfigure_->Wait(kDefaultTimeoutMs))
+ ASSERT_TRUE(time_to_reconfigure_.Wait(kDefaultTimeoutMs))
<< "Timed out before receiving an initial high bitrate.";
encoder_config_.streams[0].width *= 2;
encoder_config_.streams[0].height *= 2;
EXPECT_TRUE(send_stream_->ReconfigureVideoEncoder(encoder_config_));
- EXPECT_EQ(kEventSignaled, Wait())
+ EXPECT_TRUE(Wait())
<< "Timed out while waiting for a couple of high bitrate estimates "
"after reconfiguring the send stream.";
}
private:
- rtc::scoped_ptr<webrtc::EventWrapper> time_to_reconfigure_;
+ rtc::Event time_to_reconfigure_;
int encoder_inits_;
uint32_t last_set_bitrate_;
VideoSendStream* send_stream_;
VideoEncoderConfig encoder_config_;
} test;
- RunBaseTest(&test, FakeNetworkPipe::Config());
+ RunBaseTest(&test);
}
} // namespace webrtc
diff --git a/webrtc/call/call_unittest.cc b/webrtc/call/call_unittest.cc
index 9819b538f8..75c8238a5b 100644
--- a/webrtc/call/call_unittest.cc
+++ b/webrtc/call/call_unittest.cc
@@ -12,22 +12,25 @@
#include "testing/gtest/include/gtest/gtest.h"
+#include "webrtc/audio_state.h"
#include "webrtc/call.h"
-#include "webrtc/test/fake_voice_engine.h"
+#include "webrtc/test/mock_voice_engine.h"
namespace {
struct CallHelper {
- CallHelper() : voice_engine_(new webrtc::test::FakeVoiceEngine()) {
+ CallHelper() {
+ webrtc::AudioState::Config audio_state_config;
+ audio_state_config.voice_engine = &voice_engine_;
webrtc::Call::Config config;
- config.voice_engine = voice_engine_.get();
+ config.audio_state = webrtc::AudioState::Create(audio_state_config);
call_.reset(webrtc::Call::Create(config));
}
webrtc::Call* operator->() { return call_.get(); }
private:
- rtc::scoped_ptr<webrtc::test::FakeVoiceEngine> voice_engine_;
+ testing::NiceMock<webrtc::test::MockVoiceEngine> voice_engine_;
rtc::scoped_ptr<webrtc::Call> call_;
};
} // namespace
diff --git a/webrtc/call/congestion_controller.cc b/webrtc/call/congestion_controller.cc
index 1ec361e898..c442667ae0 100644
--- a/webrtc/call/congestion_controller.cc
+++ b/webrtc/call/congestion_controller.cc
@@ -11,23 +11,24 @@
#include "webrtc/call/congestion_controller.h"
#include "webrtc/base/checks.h"
+#include "webrtc/base/logging.h"
#include "webrtc/base/thread_annotations.h"
#include "webrtc/common.h"
-#include "webrtc/modules/pacing/include/paced_sender.h"
-#include "webrtc/modules/pacing/include/packet_router.h"
+#include "webrtc/modules/bitrate_controller/include/bitrate_controller.h"
+#include "webrtc/modules/pacing/paced_sender.h"
+#include "webrtc/modules/pacing/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/remote_bitrate_estimator/remote_estimator_proxy.h"
#include "webrtc/modules/remote_bitrate_estimator/transport_feedback_adapter.h"
-#include "webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h"
-#include "webrtc/modules/utility/interface/process_thread.h"
+#include "webrtc/modules/rtp_rtcp/include/rtp_rtcp.h"
+#include "webrtc/modules/utility/include/process_thread.h"
#include "webrtc/system_wrappers/include/critical_section_wrapper.h"
-#include "webrtc/system_wrappers/include/logging.h"
-#include "webrtc/video_engine/call_stats.h"
-#include "webrtc/video_engine/payload_router.h"
-#include "webrtc/video_engine/vie_encoder.h"
-#include "webrtc/video_engine/vie_remb.h"
+#include "webrtc/video/call_stats.h"
+#include "webrtc/video/payload_router.h"
+#include "webrtc/video/vie_encoder.h"
+#include "webrtc/video/vie_remb.h"
#include "webrtc/voice_engine/include/voe_video_sync.h"
namespace webrtc {
@@ -144,9 +145,9 @@ class WrappingBitrateEstimator : public RemoteBitrateEstimator {
} // namespace
CongestionController::CongestionController(ProcessThread* process_thread,
- CallStats* call_stats)
- : remb_(new VieRemb()),
- bitrate_allocator_(new BitrateAllocator()),
+ CallStats* call_stats,
+ BitrateObserver* bitrate_observer)
+ : remb_(new VieRemb(Clock::GetRealTimeClock())),
packet_router_(new PacketRouter()),
pacer_(new PacedSender(Clock::GetRealTimeClock(),
packet_router_.get(),
@@ -166,7 +167,7 @@ CongestionController::CongestionController(ProcessThread* process_thread,
// construction.
bitrate_controller_(
BitrateController::CreateBitrateController(Clock::GetRealTimeClock(),
- this)),
+ bitrate_observer)),
min_bitrate_bps_(RemoteBitrateEstimator::kDefaultMinBitrateBps) {
call_stats_->RegisterStatsObserver(remote_bitrate_estimator_.get());
@@ -249,6 +250,12 @@ CongestionController::GetTransportFeedbackObserver() {
return transport_feedback_adapter_.get();
}
+void CongestionController::UpdatePacerBitrate(int bitrate_kbps,
+ int max_bitrate_kbps,
+ int min_bitrate_kbps) {
+ pacer_->UpdateBitrate(bitrate_kbps, max_bitrate_kbps, min_bitrate_kbps);
+}
+
int64_t CongestionController::GetPacerQueuingDelayMs() const {
return pacer_->QueueInMs();
}
@@ -278,23 +285,6 @@ void CongestionController::SignalNetworkState(NetworkState state) {
}
}
-// TODO(mflodman): Move this logic out from CongestionController.
-void CongestionController::OnNetworkChanged(uint32_t target_bitrate_bps,
- uint8_t fraction_loss,
- int64_t rtt) {
- bitrate_allocator_->OnNetworkChanged(target_bitrate_bps, fraction_loss, rtt);
- int pad_up_to_bitrate_bps = 0;
- {
- rtc::CritScope lock(&encoder_crit_);
- for (const auto& encoder : encoders_)
- pad_up_to_bitrate_bps += encoder->GetPaddingNeededBps();
- }
- pacer_->UpdateBitrate(
- target_bitrate_bps / 1000,
- PacedSender::kDefaultPaceMultiplier * target_bitrate_bps / 1000,
- pad_up_to_bitrate_bps / 1000);
-}
-
void CongestionController::OnSentPacket(const rtc::SentPacket& sent_packet) {
if (transport_feedback_adapter_) {
transport_feedback_adapter_->OnSentPacket(sent_packet.packet_id,
diff --git a/webrtc/call/congestion_controller.h b/webrtc/call/congestion_controller.h
index b424234123..b77c46faa3 100644
--- a/webrtc/call/congestion_controller.h
+++ b/webrtc/call/congestion_controller.h
@@ -16,12 +16,12 @@
#include "webrtc/base/criticalsection.h"
#include "webrtc/base/scoped_ptr.h"
#include "webrtc/base/socket.h"
-#include "webrtc/modules/bitrate_controller/include/bitrate_controller.h"
#include "webrtc/stream.h"
namespace webrtc {
-class BitrateAllocator;
+class BitrateController;
+class BitrateObserver;
class CallStats;
class Config;
class PacedSender;
@@ -32,43 +32,43 @@ class RemoteEstimatorProxy;
class RtpRtcp;
class SendStatisticsProxy;
class TransportFeedbackAdapter;
+class TransportFeedbackObserver;
class ViEEncoder;
class VieRemb;
-class CongestionController : public BitrateObserver {
+class CongestionController {
public:
- CongestionController(ProcessThread* process_thread, CallStats* call_stats);
- ~CongestionController();
- void AddEncoder(ViEEncoder* encoder);
- void RemoveEncoder(ViEEncoder* encoder);
- void SetBweBitrates(int min_bitrate_bps,
- int start_bitrate_bps,
- int max_bitrate_bps);
-
- void SetChannelRembStatus(bool sender, bool receiver, RtpRtcp* rtp_module);
-
- void SignalNetworkState(NetworkState state);
-
- BitrateController* GetBitrateController() const;
- RemoteBitrateEstimator* GetRemoteBitrateEstimator(bool send_side_bwe) const;
- int64_t GetPacerQueuingDelayMs() const;
- PacedSender* pacer() const { return pacer_.get(); }
- PacketRouter* packet_router() const { return packet_router_.get(); }
- BitrateAllocator* bitrate_allocator() const {
- return bitrate_allocator_.get(); }
- TransportFeedbackObserver* GetTransportFeedbackObserver();
-
- // Implements BitrateObserver.
- void OnNetworkChanged(uint32_t target_bitrate_bps,
- uint8_t fraction_loss,
- int64_t rtt) override;
-
- void OnSentPacket(const rtc::SentPacket& sent_packet);
+ CongestionController(ProcessThread* process_thread, CallStats* call_stats,
+ BitrateObserver* bitrate_observer);
+ virtual ~CongestionController();
+ virtual void AddEncoder(ViEEncoder* encoder);
+ virtual void RemoveEncoder(ViEEncoder* encoder);
+ virtual void SetBweBitrates(int min_bitrate_bps,
+ int start_bitrate_bps,
+ int max_bitrate_bps);
+
+ virtual void SetChannelRembStatus(bool sender,
+ bool receiver,
+ RtpRtcp* rtp_module);
+
+ virtual void SignalNetworkState(NetworkState state);
+
+ virtual BitrateController* GetBitrateController() const;
+ virtual RemoteBitrateEstimator* GetRemoteBitrateEstimator(
+ bool send_side_bwe) const;
+ virtual int64_t GetPacerQueuingDelayMs() const;
+ virtual PacedSender* pacer() const { return pacer_.get(); }
+ virtual PacketRouter* packet_router() const { return packet_router_.get(); }
+ virtual TransportFeedbackObserver* GetTransportFeedbackObserver();
+
+ virtual void UpdatePacerBitrate(int bitrate_kbps,
+ int max_bitrate_kbps,
+ int min_bitrate_kbps);
+
+ virtual void OnSentPacket(const rtc::SentPacket& sent_packet);
private:
rtc::scoped_ptr<VieRemb> remb_;
- // TODO(mflodman): Move bitrate_allocator_ to Call.
- rtc::scoped_ptr<BitrateAllocator> bitrate_allocator_;
rtc::scoped_ptr<PacketRouter> packet_router_;
rtc::scoped_ptr<PacedSender> pacer_;
rtc::scoped_ptr<RemoteBitrateEstimator> remote_bitrate_estimator_;
@@ -86,6 +86,8 @@ class CongestionController : public BitrateObserver {
rtc::scoped_ptr<BitrateController> bitrate_controller_;
rtc::scoped_ptr<TransportFeedbackAdapter> transport_feedback_adapter_;
int min_bitrate_bps_;
+
+ RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(CongestionController);
};
} // namespace webrtc
diff --git a/webrtc/call/mock/mock_congestion_controller.h b/webrtc/call/mock/mock_congestion_controller.h
new file mode 100644
index 0000000000..54014da339
--- /dev/null
+++ b/webrtc/call/mock/mock_congestion_controller.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef WEBRTC_CALL_MOCK_MOCK_CONGESTION_CONTROLLER_H_
+#define WEBRTC_CALL_MOCK_MOCK_CONGESTION_CONTROLLER_H_
+
+#include "testing/gmock/include/gmock/gmock.h"
+#include "webrtc/call/congestion_controller.h"
+
+namespace webrtc {
+namespace test {
+
+class MockCongestionController : public CongestionController {
+ public:
+ MockCongestionController(ProcessThread* process_thread,
+ CallStats* call_stats,
+ BitrateObserver* bitrate_observer)
+ : CongestionController(process_thread, call_stats, bitrate_observer) {}
+ MOCK_METHOD1(AddEncoder, void(ViEEncoder* encoder));
+ MOCK_METHOD1(RemoveEncoder, void(ViEEncoder* encoder));
+ MOCK_METHOD3(SetBweBitrates,
+ void(int min_bitrate_bps,
+ int start_bitrate_bps,
+ int max_bitrate_bps));
+ MOCK_METHOD3(SetChannelRembStatus,
+ void(bool sender, bool receiver, RtpRtcp* rtp_module));
+ MOCK_METHOD1(SignalNetworkState, void(NetworkState state));
+ MOCK_CONST_METHOD0(GetBitrateController, BitrateController*());
+ MOCK_CONST_METHOD1(GetRemoteBitrateEstimator,
+ RemoteBitrateEstimator*(bool send_side_bwe));
+ MOCK_CONST_METHOD0(GetPacerQueuingDelayMs, int64_t());
+ MOCK_CONST_METHOD0(pacer, PacedSender*());
+ MOCK_CONST_METHOD0(packet_router, PacketRouter*());
+ MOCK_METHOD0(GetTransportFeedbackObserver, TransportFeedbackObserver*());
+ MOCK_METHOD3(UpdatePacerBitrate,
+ void(int bitrate_kbps,
+ int max_bitrate_kbps,
+ int min_bitrate_kbps));
+ MOCK_METHOD1(OnSentPacket, void(const rtc::SentPacket& sent_packet));
+
+ RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(MockCongestionController);
+};
+} // namespace test
+} // namespace webrtc
+#endif // WEBRTC_CALL_MOCK_MOCK_CONGESTION_CONTROLLER_H_
diff --git a/webrtc/call/packet_injection_tests.cc b/webrtc/call/packet_injection_tests.cc
index 18ca0581d1..277cd3e4df 100644
--- a/webrtc/call/packet_injection_tests.cc
+++ b/webrtc/call/packet_injection_tests.cc
@@ -40,22 +40,22 @@ void PacketInjectionTest::InjectIncorrectPacket(CodecType codec_type,
CreateReceiverCall(Call::Config());
test::NullTransport null_transport;
- CreateSendConfig(1, &null_transport);
+ CreateSendConfig(1, 0, &null_transport);
CreateMatchingReceiveConfigs(&null_transport);
- receive_configs_[0].decoders[0].payload_type = payload_type;
+ video_receive_configs_[0].decoders[0].payload_type = payload_type;
switch (codec_type) {
case CodecType::kVp8:
- receive_configs_[0].decoders[0].payload_name = "VP8";
+ video_receive_configs_[0].decoders[0].payload_name = "VP8";
break;
case CodecType::kH264:
- receive_configs_[0].decoders[0].payload_name = "H264";
+ video_receive_configs_[0].decoders[0].payload_name = "H264";
break;
}
- CreateStreams();
+ CreateVideoStreams();
RTPHeader header;
EXPECT_TRUE(rtp_header_parser_->Parse(packet, length, &header));
- EXPECT_EQ(kSendSsrcs[0], header.ssrc)
+ EXPECT_EQ(kVideoSendSsrcs[0], header.ssrc)
<< "Packet should have configured SSRC to not be dropped early.";
EXPECT_EQ(payload_type, header.payloadType);
Start();
diff --git a/webrtc/call/rampup_tests.cc b/webrtc/call/rampup_tests.cc
new file mode 100644
index 0000000000..81f1e81c68
--- /dev/null
+++ b/webrtc/call/rampup_tests.cc
@@ -0,0 +1,587 @@
+/*
+ * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "webrtc/call/rampup_tests.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "webrtc/base/checks.h"
+#include "webrtc/base/platform_thread.h"
+#include "webrtc/test/testsupport/perf_test.h"
+
+namespace webrtc {
+namespace {
+
+static const int64_t kPollIntervalMs = 20;
+
+std::vector<uint32_t> GenerateSsrcs(size_t num_streams, uint32_t ssrc_offset) {
+ std::vector<uint32_t> ssrcs;
+ for (size_t i = 0; i != num_streams; ++i)
+ ssrcs.push_back(static_cast<uint32_t>(ssrc_offset + i));
+ return ssrcs;
+}
+} // namespace
+
+RampUpTester::RampUpTester(size_t num_video_streams,
+ size_t num_audio_streams,
+ unsigned int start_bitrate_bps,
+ const std::string& extension_type,
+ bool rtx,
+ bool red)
+ : EndToEndTest(test::CallTest::kLongTimeoutMs),
+ event_(false, false),
+ clock_(Clock::GetRealTimeClock()),
+ num_video_streams_(num_video_streams),
+ num_audio_streams_(num_audio_streams),
+ rtx_(rtx),
+ red_(red),
+ send_stream_(nullptr),
+ start_bitrate_bps_(start_bitrate_bps),
+ start_bitrate_verified_(false),
+ expected_bitrate_bps_(0),
+ test_start_ms_(-1),
+ ramp_up_finished_ms_(-1),
+ extension_type_(extension_type),
+ video_ssrcs_(GenerateSsrcs(num_video_streams_, 100)),
+ video_rtx_ssrcs_(GenerateSsrcs(num_video_streams_, 200)),
+ audio_ssrcs_(GenerateSsrcs(num_audio_streams_, 300)),
+ poller_thread_(&BitrateStatsPollingThread,
+ this,
+ "BitrateStatsPollingThread"),
+ sender_call_(nullptr) {
+ EXPECT_LE(num_audio_streams_, 1u);
+ if (rtx_) {
+ for (size_t i = 0; i < video_ssrcs_.size(); ++i)
+ rtx_ssrc_map_[video_rtx_ssrcs_[i]] = video_ssrcs_[i];
+ }
+}
+
+RampUpTester::~RampUpTester() {
+ event_.Set();
+}
+
+Call::Config RampUpTester::GetSenderCallConfig() {
+ Call::Config call_config;
+ if (start_bitrate_bps_ != 0) {
+ call_config.bitrate_config.start_bitrate_bps = start_bitrate_bps_;
+ }
+ call_config.bitrate_config.min_bitrate_bps = 10000;
+ return call_config;
+}
+
+void RampUpTester::OnVideoStreamsCreated(
+ VideoSendStream* send_stream,
+ const std::vector<VideoReceiveStream*>& receive_streams) {
+ send_stream_ = send_stream;
+}
+
+test::PacketTransport* RampUpTester::CreateSendTransport(Call* sender_call) {
+ send_transport_ = new test::PacketTransport(sender_call, this,
+ test::PacketTransport::kSender,
+ forward_transport_config_);
+ return send_transport_;
+}
+
+size_t RampUpTester::GetNumVideoStreams() const {
+ return num_video_streams_;
+}
+
+size_t RampUpTester::GetNumAudioStreams() const {
+ return num_audio_streams_;
+}
+
+void RampUpTester::ModifyVideoConfigs(
+ VideoSendStream::Config* send_config,
+ std::vector<VideoReceiveStream::Config>* receive_configs,
+ VideoEncoderConfig* encoder_config) {
+ send_config->suspend_below_min_bitrate = true;
+
+ if (num_video_streams_ == 1) {
+ encoder_config->streams[0].target_bitrate_bps =
+ encoder_config->streams[0].max_bitrate_bps = 2000000;
+ // For single stream rampup until 1mbps
+ expected_bitrate_bps_ = kSingleStreamTargetBps;
+ } else {
+ // For multi stream rampup until all streams are being sent. That means
+ // enough birate to send all the target streams plus the min bitrate of
+ // the last one.
+ expected_bitrate_bps_ = encoder_config->streams.back().min_bitrate_bps;
+ for (size_t i = 0; i < encoder_config->streams.size() - 1; ++i) {
+ expected_bitrate_bps_ += encoder_config->streams[i].target_bitrate_bps;
+ }
+ }
+
+ send_config->rtp.extensions.clear();
+
+ bool remb;
+ bool transport_cc;
+ if (extension_type_ == RtpExtension::kAbsSendTime) {
+ remb = true;
+ transport_cc = false;
+ send_config->rtp.extensions.push_back(
+ RtpExtension(extension_type_.c_str(), kAbsSendTimeExtensionId));
+ } else if (extension_type_ == RtpExtension::kTransportSequenceNumber) {
+ remb = false;
+ transport_cc = true;
+ send_config->rtp.extensions.push_back(RtpExtension(
+ extension_type_.c_str(), kTransportSequenceNumberExtensionId));
+ } else {
+ remb = true;
+ transport_cc = false;
+ send_config->rtp.extensions.push_back(RtpExtension(
+ extension_type_.c_str(), kTransmissionTimeOffsetExtensionId));
+ }
+
+ send_config->rtp.nack.rtp_history_ms = test::CallTest::kNackRtpHistoryMs;
+ send_config->rtp.ssrcs = video_ssrcs_;
+ if (rtx_) {
+ send_config->rtp.rtx.payload_type = test::CallTest::kSendRtxPayloadType;
+ send_config->rtp.rtx.ssrcs = video_rtx_ssrcs_;
+ }
+ if (red_) {
+ send_config->rtp.fec.ulpfec_payload_type =
+ test::CallTest::kUlpfecPayloadType;
+ send_config->rtp.fec.red_payload_type = test::CallTest::kRedPayloadType;
+ }
+
+ size_t i = 0;
+ for (VideoReceiveStream::Config& recv_config : *receive_configs) {
+ recv_config.rtp.remb = remb;
+ recv_config.rtp.transport_cc = transport_cc;
+ recv_config.rtp.extensions = send_config->rtp.extensions;
+
+ recv_config.rtp.remote_ssrc = video_ssrcs_[i];
+ recv_config.rtp.nack.rtp_history_ms = send_config->rtp.nack.rtp_history_ms;
+
+ if (red_) {
+ recv_config.rtp.fec.red_payload_type =
+ send_config->rtp.fec.red_payload_type;
+ recv_config.rtp.fec.ulpfec_payload_type =
+ send_config->rtp.fec.ulpfec_payload_type;
+ }
+
+ if (rtx_) {
+ recv_config.rtp.rtx[send_config->encoder_settings.payload_type].ssrc =
+ video_rtx_ssrcs_[i];
+ recv_config.rtp.rtx[send_config->encoder_settings.payload_type]
+ .payload_type = send_config->rtp.rtx.payload_type;
+ }
+ ++i;
+ }
+}
+
+void RampUpTester::ModifyAudioConfigs(
+ AudioSendStream::Config* send_config,
+ std::vector<AudioReceiveStream::Config>* receive_configs) {
+ if (num_audio_streams_ == 0)
+ return;
+
+ EXPECT_NE(RtpExtension::kTOffset, extension_type_)
+ << "Audio BWE not supported with toffset.";
+
+ send_config->rtp.ssrc = audio_ssrcs_[0];
+ send_config->rtp.extensions.clear();
+
+ bool transport_cc = false;
+ if (extension_type_ == RtpExtension::kAbsSendTime) {
+ transport_cc = false;
+ send_config->rtp.extensions.push_back(
+ RtpExtension(extension_type_.c_str(), kAbsSendTimeExtensionId));
+ } else if (extension_type_ == RtpExtension::kTransportSequenceNumber) {
+ transport_cc = true;
+ send_config->rtp.extensions.push_back(RtpExtension(
+ extension_type_.c_str(), kTransportSequenceNumberExtensionId));
+ }
+
+ for (AudioReceiveStream::Config& recv_config : *receive_configs) {
+ recv_config.combined_audio_video_bwe = true;
+ recv_config.rtp.transport_cc = transport_cc;
+ recv_config.rtp.extensions = send_config->rtp.extensions;
+ recv_config.rtp.remote_ssrc = send_config->rtp.ssrc;
+ }
+}
+
+void RampUpTester::OnCallsCreated(Call* sender_call, Call* receiver_call) {
+ sender_call_ = sender_call;
+}
+
+bool RampUpTester::BitrateStatsPollingThread(void* obj) {
+ return static_cast<RampUpTester*>(obj)->PollStats();
+}
+
+bool RampUpTester::PollStats() {
+ if (sender_call_) {
+ Call::Stats stats = sender_call_->GetStats();
+
+ RTC_DCHECK_GT(expected_bitrate_bps_, 0);
+ if (!start_bitrate_verified_ && start_bitrate_bps_ != 0) {
+ // For tests with an explicitly set start bitrate, verify the first
+ // bitrate estimate is close to the start bitrate and lower than the
+ // test target bitrate. This is to verify a call respects the configured
+ // start bitrate, but due to the BWE implementation we can't guarantee the
+ // first estimate really is as high as the start bitrate.
+ EXPECT_GT(stats.send_bandwidth_bps, 0.9 * start_bitrate_bps_);
+ start_bitrate_verified_ = true;
+ }
+ if (stats.send_bandwidth_bps >= expected_bitrate_bps_) {
+ ramp_up_finished_ms_ = clock_->TimeInMilliseconds();
+ observation_complete_.Set();
+ }
+ }
+
+ return !event_.Wait(kPollIntervalMs);
+}
+
+void RampUpTester::ReportResult(const std::string& measurement,
+ size_t value,
+ const std::string& units) const {
+ webrtc::test::PrintResult(
+ measurement, "",
+ ::testing::UnitTest::GetInstance()->current_test_info()->name(), value,
+ units, false);
+}
+
+void RampUpTester::AccumulateStats(const VideoSendStream::StreamStats& stream,
+ size_t* total_packets_sent,
+ size_t* total_sent,
+ size_t* padding_sent,
+ size_t* media_sent) const {
+ *total_packets_sent += stream.rtp_stats.transmitted.packets +
+ stream.rtp_stats.retransmitted.packets +
+ stream.rtp_stats.fec.packets;
+ *total_sent += stream.rtp_stats.transmitted.TotalBytes() +
+ stream.rtp_stats.retransmitted.TotalBytes() +
+ stream.rtp_stats.fec.TotalBytes();
+ *padding_sent += stream.rtp_stats.transmitted.padding_bytes +
+ stream.rtp_stats.retransmitted.padding_bytes +
+ stream.rtp_stats.fec.padding_bytes;
+ *media_sent += stream.rtp_stats.MediaPayloadBytes();
+}
+
+void RampUpTester::TriggerTestDone() {
+ RTC_DCHECK_GE(test_start_ms_, 0);
+
+ // TODO(holmer): Add audio send stats here too when those APIs are available.
+ VideoSendStream::Stats send_stats = send_stream_->GetStats();
+
+ size_t total_packets_sent = 0;
+ size_t total_sent = 0;
+ size_t padding_sent = 0;
+ size_t media_sent = 0;
+ for (uint32_t ssrc : video_ssrcs_) {
+ AccumulateStats(send_stats.substreams[ssrc], &total_packets_sent,
+ &total_sent, &padding_sent, &media_sent);
+ }
+
+ size_t rtx_total_packets_sent = 0;
+ size_t rtx_total_sent = 0;
+ size_t rtx_padding_sent = 0;
+ size_t rtx_media_sent = 0;
+ for (uint32_t rtx_ssrc : video_rtx_ssrcs_) {
+ AccumulateStats(send_stats.substreams[rtx_ssrc], &rtx_total_packets_sent,
+ &rtx_total_sent, &rtx_padding_sent, &rtx_media_sent);
+ }
+
+ ReportResult("ramp-up-total-packets-sent", total_packets_sent, "packets");
+ ReportResult("ramp-up-total-sent", total_sent, "bytes");
+ ReportResult("ramp-up-media-sent", media_sent, "bytes");
+ ReportResult("ramp-up-padding-sent", padding_sent, "bytes");
+ ReportResult("ramp-up-rtx-total-packets-sent", rtx_total_packets_sent,
+ "packets");
+ ReportResult("ramp-up-rtx-total-sent", rtx_total_sent, "bytes");
+ ReportResult("ramp-up-rtx-media-sent", rtx_media_sent, "bytes");
+ ReportResult("ramp-up-rtx-padding-sent", rtx_padding_sent, "bytes");
+ if (ramp_up_finished_ms_ >= 0) {
+ ReportResult("ramp-up-time", ramp_up_finished_ms_ - test_start_ms_,
+ "milliseconds");
+ }
+ ReportResult("ramp-up-average-network-latency",
+ send_transport_->GetAverageDelayMs(), "milliseconds");
+}
+
+void RampUpTester::PerformTest() {
+ test_start_ms_ = clock_->TimeInMilliseconds();
+ poller_thread_.Start();
+ EXPECT_TRUE(Wait()) << "Timed out while waiting for ramp-up to complete.";
+ TriggerTestDone();
+ poller_thread_.Stop();
+}
+
+RampUpDownUpTester::RampUpDownUpTester(size_t num_video_streams,
+ size_t num_audio_streams,
+ unsigned int start_bitrate_bps,
+ const std::string& extension_type,
+ bool rtx,
+ bool red)
+ : RampUpTester(num_video_streams,
+ num_audio_streams,
+ start_bitrate_bps,
+ extension_type,
+ rtx,
+ red),
+ test_state_(kFirstRampup),
+ state_start_ms_(clock_->TimeInMilliseconds()),
+ interval_start_ms_(clock_->TimeInMilliseconds()),
+ sent_bytes_(0) {
+ forward_transport_config_.link_capacity_kbps = kHighBandwidthLimitBps / 1000;
+}
+
+RampUpDownUpTester::~RampUpDownUpTester() {}
+
+bool RampUpDownUpTester::PollStats() {
+ if (send_stream_) {
+ webrtc::VideoSendStream::Stats stats = send_stream_->GetStats();
+ int transmit_bitrate_bps = 0;
+ for (auto it : stats.substreams) {
+ transmit_bitrate_bps += it.second.total_bitrate_bps;
+ }
+
+ EvolveTestState(transmit_bitrate_bps, stats.suspended);
+ }
+
+ return !event_.Wait(kPollIntervalMs);
+}
+
+Call::Config RampUpDownUpTester::GetReceiverCallConfig() {
+ Call::Config config;
+ config.bitrate_config.min_bitrate_bps = 10000;
+ return config;
+}
+
+std::string RampUpDownUpTester::GetModifierString() const {
+ std::string str("_");
+ if (num_video_streams_ > 0) {
+ std::ostringstream s;
+ s << num_video_streams_;
+ str += s.str();
+ str += "stream";
+ str += (num_video_streams_ > 1 ? "s" : "");
+ str += "_";
+ }
+ if (num_audio_streams_ > 0) {
+ std::ostringstream s;
+ s << num_audio_streams_;
+ str += s.str();
+ str += "stream";
+ str += (num_audio_streams_ > 1 ? "s" : "");
+ str += "_";
+ }
+ str += (rtx_ ? "" : "no");
+ str += "rtx";
+ return str;
+}
+
+void RampUpDownUpTester::EvolveTestState(int bitrate_bps, bool suspended) {
+ int64_t now = clock_->TimeInMilliseconds();
+ switch (test_state_) {
+ case kFirstRampup: {
+ EXPECT_FALSE(suspended);
+ if (bitrate_bps > kExpectedHighBitrateBps) {
+ // The first ramp-up has reached the target bitrate. Change the
+ // channel limit, and move to the next test state.
+ forward_transport_config_.link_capacity_kbps =
+ kLowBandwidthLimitBps / 1000;
+ send_transport_->SetConfig(forward_transport_config_);
+ test_state_ = kLowRate;
+ webrtc::test::PrintResult("ramp_up_down_up", GetModifierString(),
+ "first_rampup", now - state_start_ms_, "ms",
+ false);
+ state_start_ms_ = now;
+ interval_start_ms_ = now;
+ sent_bytes_ = 0;
+ }
+ break;
+ }
+ case kLowRate: {
+ if (bitrate_bps < kExpectedLowBitrateBps && suspended) {
+ // The ramp-down was successful. Change the channel limit back to a
+ // high value, and move to the next test state.
+ forward_transport_config_.link_capacity_kbps =
+ kHighBandwidthLimitBps / 1000;
+ send_transport_->SetConfig(forward_transport_config_);
+ test_state_ = kSecondRampup;
+ webrtc::test::PrintResult("ramp_up_down_up", GetModifierString(),
+ "rampdown", now - state_start_ms_, "ms",
+ false);
+ state_start_ms_ = now;
+ interval_start_ms_ = now;
+ sent_bytes_ = 0;
+ }
+ break;
+ }
+ case kSecondRampup: {
+ if (bitrate_bps > kExpectedHighBitrateBps && !suspended) {
+ webrtc::test::PrintResult("ramp_up_down_up", GetModifierString(),
+ "second_rampup", now - state_start_ms_, "ms",
+ false);
+ ReportResult("ramp-up-down-up-average-network-latency",
+ send_transport_->GetAverageDelayMs(), "milliseconds");
+ observation_complete_.Set();
+ }
+ break;
+ }
+ }
+}
+
+class RampUpTest : public test::CallTest {
+ public:
+ RampUpTest() {}
+
+ virtual ~RampUpTest() {
+ EXPECT_EQ(nullptr, video_send_stream_);
+ EXPECT_TRUE(video_receive_streams_.empty());
+ }
+};
+
+TEST_F(RampUpTest, SingleStream) {
+ RampUpTester test(1, 0, 0, RtpExtension::kTOffset, false, false);
+ RunBaseTest(&test);
+}
+
+TEST_F(RampUpTest, Simulcast) {
+ RampUpTester test(3, 0, 0, RtpExtension::kTOffset, false, false);
+ RunBaseTest(&test);
+}
+
+TEST_F(RampUpTest, SimulcastWithRtx) {
+ RampUpTester test(3, 0, 0, RtpExtension::kTOffset, true, false);
+ RunBaseTest(&test);
+}
+
+TEST_F(RampUpTest, SimulcastByRedWithRtx) {
+ RampUpTester test(3, 0, 0, RtpExtension::kTOffset, true, true);
+ RunBaseTest(&test);
+}
+
+TEST_F(RampUpTest, SingleStreamWithHighStartBitrate) {
+ RampUpTester test(1, 0, 0.9 * kSingleStreamTargetBps, RtpExtension::kTOffset,
+ false, false);
+ RunBaseTest(&test);
+}
+
+// Disabled on Mac due to flakiness, see
+// https://bugs.chromium.org/p/webrtc/issues/detail?id=5407
+#ifndef WEBRTC_MAC
+
+static const uint32_t kStartBitrateBps = 60000;
+
+TEST_F(RampUpTest, UpDownUpOneStream) {
+ RampUpDownUpTester test(1, 0, kStartBitrateBps, RtpExtension::kAbsSendTime,
+ false, false);
+ RunBaseTest(&test);
+}
+
+TEST_F(RampUpTest, UpDownUpThreeStreams) {
+ RampUpDownUpTester test(3, 0, kStartBitrateBps, RtpExtension::kAbsSendTime,
+ false, false);
+ RunBaseTest(&test);
+}
+
+TEST_F(RampUpTest, UpDownUpOneStreamRtx) {
+ RampUpDownUpTester test(1, 0, kStartBitrateBps, RtpExtension::kAbsSendTime,
+ true, false);
+ RunBaseTest(&test);
+}
+
+TEST_F(RampUpTest, UpDownUpThreeStreamsRtx) {
+ RampUpDownUpTester test(3, 0, kStartBitrateBps, RtpExtension::kAbsSendTime,
+ true, false);
+ RunBaseTest(&test);
+}
+
+TEST_F(RampUpTest, UpDownUpOneStreamByRedRtx) {
+ RampUpDownUpTester test(1, 0, kStartBitrateBps, RtpExtension::kAbsSendTime,
+ true, true);
+ RunBaseTest(&test);
+}
+
+TEST_F(RampUpTest, UpDownUpThreeStreamsByRedRtx) {
+ RampUpDownUpTester test(3, 0, kStartBitrateBps, RtpExtension::kAbsSendTime,
+ true, true);
+ RunBaseTest(&test);
+}
+
+TEST_F(RampUpTest, SendSideVideoUpDownUpRtx) {
+ RampUpDownUpTester test(3, 0, kStartBitrateBps,
+ RtpExtension::kTransportSequenceNumber, true, false);
+ RunBaseTest(&test);
+}
+
+// TODO(holmer): Enable when audio bitrates are included in the bitrate
+// allocation.
+TEST_F(RampUpTest, DISABLED_SendSideAudioVideoUpDownUpRtx) {
+ RampUpDownUpTester test(3, 1, kStartBitrateBps,
+ RtpExtension::kTransportSequenceNumber, true, false);
+ RunBaseTest(&test);
+}
+
+#endif
+
+TEST_F(RampUpTest, AbsSendTimeSingleStream) {
+ RampUpTester test(1, 0, 0, RtpExtension::kAbsSendTime, false, false);
+ RunBaseTest(&test);
+}
+
+TEST_F(RampUpTest, AbsSendTimeSimulcast) {
+ RampUpTester test(3, 0, 0, RtpExtension::kAbsSendTime, false, false);
+ RunBaseTest(&test);
+}
+
+TEST_F(RampUpTest, AbsSendTimeSimulcastWithRtx) {
+ RampUpTester test(3, 0, 0, RtpExtension::kAbsSendTime, true, false);
+ RunBaseTest(&test);
+}
+
+TEST_F(RampUpTest, AbsSendTimeSimulcastByRedWithRtx) {
+ RampUpTester test(3, 0, 0, RtpExtension::kAbsSendTime, true, true);
+ RunBaseTest(&test);
+}
+
+TEST_F(RampUpTest, AbsSendTimeSingleStreamWithHighStartBitrate) {
+ RampUpTester test(1, 0, 0.9 * kSingleStreamTargetBps,
+ RtpExtension::kAbsSendTime, false, false);
+ RunBaseTest(&test);
+}
+
+TEST_F(RampUpTest, TransportSequenceNumberSingleStream) {
+ RampUpTester test(1, 0, 0, RtpExtension::kTransportSequenceNumber, false,
+ false);
+ RunBaseTest(&test);
+}
+
+TEST_F(RampUpTest, TransportSequenceNumberSimulcast) {
+ RampUpTester test(3, 0, 0, RtpExtension::kTransportSequenceNumber, false,
+ false);
+ RunBaseTest(&test);
+}
+
+TEST_F(RampUpTest, TransportSequenceNumberSimulcastWithRtx) {
+ RampUpTester test(3, 0, 0, RtpExtension::kTransportSequenceNumber, true,
+ false);
+ RunBaseTest(&test);
+}
+
+TEST_F(RampUpTest, AudioVideoTransportSequenceNumberSimulcastWithRtx) {
+ RampUpTester test(3, 1, 0, RtpExtension::kTransportSequenceNumber, true,
+ false);
+ RunBaseTest(&test);
+}
+
+TEST_F(RampUpTest, TransportSequenceNumberSimulcastByRedWithRtx) {
+ RampUpTester test(3, 0, 0, RtpExtension::kTransportSequenceNumber, true,
+ true);
+ RunBaseTest(&test);
+}
+
+TEST_F(RampUpTest, TransportSequenceNumberSingleStreamWithHighStartBitrate) {
+ RampUpTester test(1, 0, 0.9 * kSingleStreamTargetBps,
+ RtpExtension::kTransportSequenceNumber, false, false);
+ RunBaseTest(&test);
+}
+} // namespace webrtc
diff --git a/webrtc/call/rampup_tests.h b/webrtc/call/rampup_tests.h
new file mode 100644
index 0000000000..31a0a0296e
--- /dev/null
+++ b/webrtc/call/rampup_tests.h
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef WEBRTC_CALL_RAMPUP_TESTS_H_
+#define WEBRTC_CALL_RAMPUP_TESTS_H_
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "webrtc/base/event.h"
+#include "webrtc/base/scoped_ptr.h"
+#include "webrtc/call.h"
+#include "webrtc/test/call_test.h"
+
+namespace webrtc {
+
+static const int kTransmissionTimeOffsetExtensionId = 6;
+static const int kAbsSendTimeExtensionId = 7;
+static const int kTransportSequenceNumberExtensionId = 8;
+static const unsigned int kSingleStreamTargetBps = 1000000;
+
+class Clock;
+
+class RampUpTester : public test::EndToEndTest {
+ public:
+ RampUpTester(size_t num_video_streams,
+ size_t num_audio_streams,
+ unsigned int start_bitrate_bps,
+ const std::string& extension_type,
+ bool rtx,
+ bool red);
+ ~RampUpTester() override;
+
+ size_t GetNumVideoStreams() const override;
+ size_t GetNumAudioStreams() const override;
+
+ void PerformTest() override;
+
+ protected:
+ virtual bool PollStats();
+
+ void AccumulateStats(const VideoSendStream::StreamStats& stream,
+ size_t* total_packets_sent,
+ size_t* total_sent,
+ size_t* padding_sent,
+ size_t* media_sent) const;
+
+ void ReportResult(const std::string& measurement,
+ size_t value,
+ const std::string& units) const;
+ void TriggerTestDone();
+
+ rtc::Event event_;
+ Clock* const clock_;
+ FakeNetworkPipe::Config forward_transport_config_;
+ const size_t num_video_streams_;
+ const size_t num_audio_streams_;
+ const bool rtx_;
+ const bool red_;
+ VideoSendStream* send_stream_;
+ test::PacketTransport* send_transport_;
+
+ private:
+ typedef std::map<uint32_t, uint32_t> SsrcMap;
+
+ Call::Config GetSenderCallConfig() override;
+ void OnVideoStreamsCreated(
+ VideoSendStream* send_stream,
+ const std::vector<VideoReceiveStream*>& receive_streams) override;
+ test::PacketTransport* CreateSendTransport(Call* sender_call) override;
+ void ModifyVideoConfigs(
+ VideoSendStream::Config* send_config,
+ std::vector<VideoReceiveStream::Config>* receive_configs,
+ VideoEncoderConfig* encoder_config) override;
+ void ModifyAudioConfigs(
+ AudioSendStream::Config* send_config,
+ std::vector<AudioReceiveStream::Config>* receive_configs) override;
+ void OnCallsCreated(Call* sender_call, Call* receiver_call) override;
+
+ static bool BitrateStatsPollingThread(void* obj);
+
+ const int start_bitrate_bps_;
+ bool start_bitrate_verified_;
+ int expected_bitrate_bps_;
+ int64_t test_start_ms_;
+ int64_t ramp_up_finished_ms_;
+
+ const std::string extension_type_;
+ std::vector<uint32_t> video_ssrcs_;
+ std::vector<uint32_t> video_rtx_ssrcs_;
+ std::vector<uint32_t> audio_ssrcs_;
+ SsrcMap rtx_ssrc_map_;
+
+ rtc::PlatformThread poller_thread_;
+ Call* sender_call_;
+};
+
+class RampUpDownUpTester : public RampUpTester {
+ public:
+ RampUpDownUpTester(size_t num_video_streams,
+ size_t num_audio_streams,
+ unsigned int start_bitrate_bps,
+ const std::string& extension_type,
+ bool rtx,
+ bool red);
+ ~RampUpDownUpTester() override;
+
+ protected:
+ bool PollStats() override;
+
+ private:
+ static const int kHighBandwidthLimitBps = 80000;
+ static const int kExpectedHighBitrateBps = 60000;
+ static const int kLowBandwidthLimitBps = 20000;
+ static const int kExpectedLowBitrateBps = 20000;
+ enum TestStates { kFirstRampup, kLowRate, kSecondRampup };
+
+ Call::Config GetReceiverCallConfig() override;
+
+ std::string GetModifierString() const;
+ void EvolveTestState(int bitrate_bps, bool suspended);
+
+ TestStates test_state_;
+ int64_t state_start_ms_;
+ int64_t interval_start_ms_;
+ int sent_bytes_;
+};
+} // namespace webrtc
+#endif // WEBRTC_CALL_RAMPUP_TESTS_H_
diff --git a/webrtc/call/rtc_event_log.cc b/webrtc/call/rtc_event_log.cc
index 550b556e80..9f592ce479 100644
--- a/webrtc/call/rtc_event_log.cc
+++ b/webrtc/call/rtc_event_log.cc
@@ -17,7 +17,9 @@
#include "webrtc/base/criticalsection.h"
#include "webrtc/base/thread_annotations.h"
#include "webrtc/call.h"
+#include "webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h"
#include "webrtc/modules/rtp_rtcp/source/byte_io.h"
+#include "webrtc/modules/rtp_rtcp/source/rtcp_utility.h"
#include "webrtc/system_wrappers/include/clock.h"
#include "webrtc/system_wrappers/include/file_wrapper.h"
@@ -54,6 +56,9 @@ class RtcEventLogImpl final : public RtcEventLog {
const uint8_t* packet,
size_t length) override {}
void LogAudioPlayout(uint32_t ssrc) override {}
+ void LogBwePacketLossEvent(int32_t bitrate,
+ uint8_t fraction_loss,
+ int32_t total_packets) override {}
};
#else // ENABLE_RTC_EVENT_LOG is defined
@@ -78,6 +83,9 @@ class RtcEventLogImpl final : public RtcEventLog {
const uint8_t* packet,
size_t length) override;
void LogAudioPlayout(uint32_t ssrc) override;
+ void LogBwePacketLossEvent(int32_t bitrate,
+ uint8_t fraction_loss,
+ int32_t total_packets) override;
private:
// Starts logging. This function assumes the file_ has been opened succesfully
@@ -254,8 +262,7 @@ void RtcEventLogImpl::LogVideoReceiveStreamConfig(
rtc::CritScope lock(&crit_);
rtclog::Event event;
- const int64_t timestamp = clock_->TimeInMicroseconds();
- event.set_timestamp_us(timestamp);
+ event.set_timestamp_us(clock_->TimeInMicroseconds());
event.set_type(rtclog::Event::VIDEO_RECEIVER_CONFIG_EVENT);
rtclog::VideoReceiveConfig* receiver_config =
@@ -264,9 +271,6 @@ void RtcEventLogImpl::LogVideoReceiveStreamConfig(
receiver_config->set_local_ssrc(config.rtp.local_ssrc);
receiver_config->set_rtcp_mode(ConvertRtcpMode(config.rtp.rtcp_mode));
-
- receiver_config->set_receiver_reference_time_report(
- config.rtp.rtcp_xr.receiver_reference_time_report);
receiver_config->set_remb(config.rtp.remb);
for (const auto& kv : config.rtp.rtx) {
@@ -296,8 +300,7 @@ void RtcEventLogImpl::LogVideoSendStreamConfig(
rtc::CritScope lock(&crit_);
rtclog::Event event;
- const int64_t timestamp = clock_->TimeInMicroseconds();
- event.set_timestamp_us(timestamp);
+ event.set_timestamp_us(clock_->TimeInMicroseconds());
event.set_type(rtclog::Event::VIDEO_SENDER_CONFIG_EVENT);
rtclog::VideoSendConfig* sender_config = event.mutable_video_sender_config();
@@ -318,8 +321,6 @@ void RtcEventLogImpl::LogVideoSendStreamConfig(
}
sender_config->set_rtx_payload_type(config.rtp.rtx.payload_type);
- sender_config->set_c_name(config.rtp.c_name);
-
rtclog::EncoderConfig* encoder = sender_config->mutable_encoder();
encoder->set_name(config.encoder_settings.payload_name);
encoder->set_payload_type(config.encoder_settings.payload_type);
@@ -348,8 +349,7 @@ void RtcEventLogImpl::LogRtpHeader(bool incoming,
rtc::CritScope lock(&crit_);
rtclog::Event rtp_event;
- const int64_t timestamp = clock_->TimeInMicroseconds();
- rtp_event.set_timestamp_us(timestamp);
+ rtp_event.set_timestamp_us(clock_->TimeInMicroseconds());
rtp_event.set_type(rtclog::Event::RTP_EVENT);
rtp_event.mutable_rtp_packet()->set_incoming(incoming);
rtp_event.mutable_rtp_packet()->set_type(ConvertMediaType(media_type));
@@ -364,33 +364,89 @@ void RtcEventLogImpl::LogRtcpPacket(bool incoming,
size_t length) {
rtc::CritScope lock(&crit_);
rtclog::Event rtcp_event;
- const int64_t timestamp = clock_->TimeInMicroseconds();
- rtcp_event.set_timestamp_us(timestamp);
+ rtcp_event.set_timestamp_us(clock_->TimeInMicroseconds());
rtcp_event.set_type(rtclog::Event::RTCP_EVENT);
rtcp_event.mutable_rtcp_packet()->set_incoming(incoming);
rtcp_event.mutable_rtcp_packet()->set_type(ConvertMediaType(media_type));
- rtcp_event.mutable_rtcp_packet()->set_packet_data(packet, length);
+
+ RTCPUtility::RtcpCommonHeader header;
+ const uint8_t* block_begin = packet;
+ const uint8_t* packet_end = packet + length;
+ RTC_DCHECK(length <= IP_PACKET_SIZE);
+ uint8_t buffer[IP_PACKET_SIZE];
+ uint32_t buffer_length = 0;
+ while (block_begin < packet_end) {
+ if (!RtcpParseCommonHeader(block_begin, packet_end - block_begin,
+ &header)) {
+ break; // Incorrect message header.
+ }
+ uint32_t block_size = header.BlockSize();
+ switch (header.packet_type) {
+ case RTCPUtility::PT_SR:
+ FALLTHROUGH();
+ case RTCPUtility::PT_RR:
+ FALLTHROUGH();
+ case RTCPUtility::PT_BYE:
+ FALLTHROUGH();
+ case RTCPUtility::PT_IJ:
+ FALLTHROUGH();
+ case RTCPUtility::PT_RTPFB:
+ FALLTHROUGH();
+ case RTCPUtility::PT_PSFB:
+ FALLTHROUGH();
+ case RTCPUtility::PT_XR:
+ // We log sender reports, receiver reports, bye messages
+ // inter-arrival jitter, third-party loss reports, payload-specific
+ // feedback and extended reports.
+ memcpy(buffer + buffer_length, block_begin, block_size);
+ buffer_length += block_size;
+ break;
+ case RTCPUtility::PT_SDES:
+ FALLTHROUGH();
+ case RTCPUtility::PT_APP:
+ FALLTHROUGH();
+ default:
+ // We don't log sender descriptions, application defined messages
+ // or message blocks of unknown type.
+ break;
+ }
+
+ block_begin += block_size;
+ }
+ rtcp_event.mutable_rtcp_packet()->set_packet_data(buffer, buffer_length);
HandleEvent(&rtcp_event);
}
void RtcEventLogImpl::LogAudioPlayout(uint32_t ssrc) {
rtc::CritScope lock(&crit_);
rtclog::Event event;
- const int64_t timestamp = clock_->TimeInMicroseconds();
- event.set_timestamp_us(timestamp);
+ event.set_timestamp_us(clock_->TimeInMicroseconds());
event.set_type(rtclog::Event::AUDIO_PLAYOUT_EVENT);
auto playout_event = event.mutable_audio_playout_event();
playout_event->set_local_ssrc(ssrc);
HandleEvent(&event);
}
+void RtcEventLogImpl::LogBwePacketLossEvent(int32_t bitrate,
+ uint8_t fraction_loss,
+ int32_t total_packets) {
+ rtc::CritScope lock(&crit_);
+ rtclog::Event event;
+ event.set_timestamp_us(clock_->TimeInMicroseconds());
+ event.set_type(rtclog::Event::BWE_PACKET_LOSS_EVENT);
+ auto bwe_event = event.mutable_bwe_packet_loss_event();
+ bwe_event->set_bitrate(bitrate);
+ bwe_event->set_fraction_loss(fraction_loss);
+ bwe_event->set_total_packets(total_packets);
+ HandleEvent(&event);
+}
+
void RtcEventLogImpl::StopLoggingLocked() {
if (currently_logging_) {
currently_logging_ = false;
// Create a LogEnd event
rtclog::Event event;
- int64_t timestamp = clock_->TimeInMicroseconds();
- event.set_timestamp_us(timestamp);
+ event.set_timestamp_us(clock_->TimeInMicroseconds());
event.set_type(rtclog::Event::LOG_END);
// Store the event and close the file
RTC_DCHECK(file_->Open());
diff --git a/webrtc/call/rtc_event_log.h b/webrtc/call/rtc_event_log.h
index 85d7525752..489687a195 100644
--- a/webrtc/call/rtc_event_log.h
+++ b/webrtc/call/rtc_event_log.h
@@ -77,6 +77,11 @@ class RtcEventLog {
// Logs an audio playout event
virtual void LogAudioPlayout(uint32_t ssrc) = 0;
+ // Logs a bitrate update from the bandwidth estimator based on packet loss.
+ virtual void LogBwePacketLossEvent(int32_t bitrate,
+ uint8_t fraction_loss,
+ int32_t total_packets) = 0;
+
// Reads an RtcEventLog file and returns true when reading was successful.
// The result is stored in the given EventStream object.
static bool ParseRtcEventLog(const std::string& file_name,
diff --git a/webrtc/call/rtc_event_log.proto b/webrtc/call/rtc_event_log.proto
index 6bdea7bd2f..b14306e362 100644
--- a/webrtc/call/rtc_event_log.proto
+++ b/webrtc/call/rtc_event_log.proto
@@ -34,10 +34,12 @@ message Event {
RTP_EVENT = 3;
RTCP_EVENT = 4;
AUDIO_PLAYOUT_EVENT = 5;
- VIDEO_RECEIVER_CONFIG_EVENT = 6;
- VIDEO_SENDER_CONFIG_EVENT = 7;
- AUDIO_RECEIVER_CONFIG_EVENT = 8;
- AUDIO_SENDER_CONFIG_EVENT = 9;
+ BWE_PACKET_LOSS_EVENT = 6;
+ BWE_PACKET_DELAY_EVENT = 7;
+ VIDEO_RECEIVER_CONFIG_EVENT = 8;
+ VIDEO_SENDER_CONFIG_EVENT = 9;
+ AUDIO_RECEIVER_CONFIG_EVENT = 10;
+ AUDIO_SENDER_CONFIG_EVENT = 11;
}
// required - Indicates the type of this event
@@ -52,17 +54,20 @@ message Event {
// optional - but required if type == AUDIO_PLAYOUT_EVENT
optional AudioPlayoutEvent audio_playout_event = 5;
+ // optional - but required if type == BWE_PACKET_LOSS_EVENT
+ optional BwePacketLossEvent bwe_packet_loss_event = 6;
+
// optional - but required if type == VIDEO_RECEIVER_CONFIG_EVENT
- optional VideoReceiveConfig video_receiver_config = 6;
+ optional VideoReceiveConfig video_receiver_config = 8;
// optional - but required if type == VIDEO_SENDER_CONFIG_EVENT
- optional VideoSendConfig video_sender_config = 7;
+ optional VideoSendConfig video_sender_config = 9;
// optional - but required if type == AUDIO_RECEIVER_CONFIG_EVENT
- optional AudioReceiveConfig audio_receiver_config = 8;
+ optional AudioReceiveConfig audio_receiver_config = 10;
// optional - but required if type == AUDIO_SENDER_CONFIG_EVENT
- optional AudioSendConfig audio_sender_config = 9;
+ optional AudioSendConfig audio_sender_config = 11;
}
@@ -99,6 +104,19 @@ message AudioPlayoutEvent {
optional uint32 local_ssrc = 2;
}
+message BwePacketLossEvent {
+ // required - Bandwidth estimate (in bps) after the update.
+ optional int32 bitrate = 1;
+
+ // required - Fraction of lost packets since last receiver report
+ // computed as floor( 256 * (#lost_packets / #total_packets) ).
+ // The possible values range from 0 to 255.
+ optional uint32 fraction_loss = 2;
+
+ // TODO(terelius): Is this really needed? Remove or make optional?
+ // required - Total number of packets that the BWE update is based on.
+ optional int32 total_packets = 3;
+}
// TODO(terelius): Video and audio streams could in principle share SSRC,
// so identifying a stream based only on SSRC might not work.
@@ -119,20 +137,17 @@ message VideoReceiveConfig {
// required - RTCP mode to use.
optional RtcpMode rtcp_mode = 3;
- // required - Extended RTCP settings.
- optional bool receiver_reference_time_report = 4;
-
// required - Receiver estimated maximum bandwidth.
- optional bool remb = 5;
+ optional bool remb = 4;
// Map from video RTP payload type -> RTX config.
- repeated RtxMap rtx_map = 6;
+ repeated RtxMap rtx_map = 5;
// RTP header extensions used for the received stream.
- repeated RtpHeaderExtension header_extensions = 7;
+ repeated RtpHeaderExtension header_extensions = 6;
// List of decoders associated with the stream.
- repeated DecoderConfig decoders = 8;
+ repeated DecoderConfig decoders = 7;
}
@@ -142,7 +157,7 @@ message DecoderConfig {
optional string name = 1;
// required
- optional sint32 payload_type = 2;
+ optional int32 payload_type = 2;
}
@@ -152,7 +167,7 @@ message RtpHeaderExtension {
optional string name = 1;
// required
- optional sint32 id = 2;
+ optional int32 id = 2;
}
@@ -163,13 +178,13 @@ message RtxConfig {
optional uint32 rtx_ssrc = 1;
// required - Payload type to use for the RTX stream.
- optional sint32 rtx_payload_type = 2;
+ optional int32 rtx_payload_type = 2;
}
message RtxMap {
// required
- optional sint32 payload_type = 1;
+ optional int32 payload_type = 1;
// required
optional RtxConfig config = 2;
@@ -189,13 +204,10 @@ message VideoSendConfig {
repeated uint32 rtx_ssrcs = 3;
// required if rtx_ssrcs is used - Payload type for retransmitted packets.
- optional sint32 rtx_payload_type = 4;
-
- // required - Canonical end-point identifier.
- optional string c_name = 5;
+ optional int32 rtx_payload_type = 4;
// required - Encoder associated with the stream.
- optional EncoderConfig encoder = 6;
+ optional EncoderConfig encoder = 5;
}
@@ -205,7 +217,7 @@ message EncoderConfig {
optional string name = 1;
// required
- optional sint32 payload_type = 2;
+ optional int32 payload_type = 2;
}
diff --git a/webrtc/call/rtc_event_log_unittest.cc b/webrtc/call/rtc_event_log_unittest.cc
index a4fdd13512..f590f669a2 100644
--- a/webrtc/call/rtc_event_log_unittest.cc
+++ b/webrtc/call/rtc_event_log_unittest.cc
@@ -10,22 +10,23 @@
#ifdef ENABLE_RTC_EVENT_LOG
-#include <stdio.h>
#include <string>
+#include <utility>
#include <vector>
#include "testing/gtest/include/gtest/gtest.h"
#include "webrtc/base/buffer.h"
#include "webrtc/base/checks.h"
+#include "webrtc/base/random.h"
#include "webrtc/base/scoped_ptr.h"
#include "webrtc/base/thread.h"
#include "webrtc/call.h"
#include "webrtc/call/rtc_event_log.h"
+#include "webrtc/modules/rtp_rtcp/source/rtcp_packet.h"
#include "webrtc/modules/rtp_rtcp/source/rtp_sender.h"
#include "webrtc/system_wrappers/include/clock.h"
#include "webrtc/test/test_suite.h"
#include "webrtc/test/testsupport/fileutils.h"
-#include "webrtc/test/testsupport/gtest_disable.h"
// Files generated at build-time by the protobuf compiler.
#ifdef WEBRTC_ANDROID_PLATFORM_BUILD
@@ -138,9 +139,6 @@ void VerifyReceiveStreamConfig(const rtclog::Event& event,
else
EXPECT_EQ(rtclog::VideoReceiveConfig::RTCP_REDUCEDSIZE,
receiver_config.rtcp_mode());
- ASSERT_TRUE(receiver_config.has_receiver_reference_time_report());
- EXPECT_EQ(config.rtp.rtcp_xr.receiver_reference_time_report,
- receiver_config.receiver_reference_time_report());
ASSERT_TRUE(receiver_config.has_remb());
EXPECT_EQ(config.rtp.remb, receiver_config.remb());
// Check RTX map.
@@ -214,9 +212,6 @@ void VerifySendStreamConfig(const rtclog::Event& event,
ASSERT_TRUE(sender_config.has_rtx_payload_type());
EXPECT_EQ(config.rtp.rtx.payload_type, sender_config.rtx_payload_type());
}
- // Check CNAME.
- ASSERT_TRUE(sender_config.has_c_name());
- EXPECT_EQ(config.rtp.c_name, sender_config.c_name());
// Check encoder.
ASSERT_TRUE(sender_config.has_encoder());
ASSERT_TRUE(sender_config.encoder().has_name());
@@ -230,7 +225,7 @@ void VerifySendStreamConfig(const rtclog::Event& event,
void VerifyRtpEvent(const rtclog::Event& event,
bool incoming,
MediaType media_type,
- uint8_t* header,
+ const uint8_t* header,
size_t header_size,
size_t total_size) {
ASSERT_TRUE(IsValidBasicEvent(event));
@@ -252,7 +247,7 @@ void VerifyRtpEvent(const rtclog::Event& event,
void VerifyRtcpEvent(const rtclog::Event& event,
bool incoming,
MediaType media_type,
- uint8_t* packet,
+ const uint8_t* packet,
size_t total_size) {
ASSERT_TRUE(IsValidBasicEvent(event));
ASSERT_EQ(rtclog::Event::RTCP_EVENT, event.type());
@@ -276,6 +271,21 @@ void VerifyPlayoutEvent(const rtclog::Event& event, uint32_t ssrc) {
EXPECT_EQ(ssrc, playout_event.local_ssrc());
}
+void VerifyBweLossEvent(const rtclog::Event& event,
+ int32_t bitrate,
+ uint8_t fraction_loss,
+ int32_t total_packets) {
+ ASSERT_TRUE(IsValidBasicEvent(event));
+ ASSERT_EQ(rtclog::Event::BWE_PACKET_LOSS_EVENT, event.type());
+ const rtclog::BwePacketLossEvent& bwe_event = event.bwe_packet_loss_event();
+ ASSERT_TRUE(bwe_event.has_bitrate());
+ EXPECT_EQ(bitrate, bwe_event.bitrate());
+ ASSERT_TRUE(bwe_event.has_fraction_loss());
+ EXPECT_EQ(fraction_loss, bwe_event.fraction_loss());
+ ASSERT_TRUE(bwe_event.has_total_packets());
+ EXPECT_EQ(total_packets, bwe_event.total_packets());
+}
+
void VerifyLogStartEvent(const rtclog::Event& event) {
ASSERT_TRUE(IsValidBasicEvent(event));
EXPECT_EQ(rtclog::Event::LOG_START, event.type());
@@ -289,7 +299,8 @@ void VerifyLogStartEvent(const rtclog::Event& event) {
size_t GenerateRtpPacket(uint32_t extensions_bitvector,
uint32_t csrcs_count,
uint8_t* packet,
- size_t packet_size) {
+ size_t packet_size,
+ Random* prng) {
RTC_CHECK_GE(packet_size, 16 + 4 * csrcs_count + 4 * kNumExtensions);
Clock* clock = Clock::GetRealTimeClock();
@@ -306,12 +317,12 @@ size_t GenerateRtpPacket(uint32_t extensions_bitvector,
std::vector<uint32_t> csrcs;
for (unsigned i = 0; i < csrcs_count; i++) {
- csrcs.push_back(rand());
+ csrcs.push_back(prng->Rand<uint32_t>());
}
rtp_sender.SetCsrcs(csrcs);
- rtp_sender.SetSSRC(rand());
- rtp_sender.SetStartTimestamp(rand(), true);
- rtp_sender.SetSequenceNumber(rand());
+ rtp_sender.SetSSRC(prng->Rand<uint32_t>());
+ rtp_sender.SetStartTimestamp(prng->Rand<uint32_t>(), true);
+ rtp_sender.SetSequenceNumber(prng->Rand<uint16_t>());
for (unsigned i = 0; i < kNumExtensions; i++) {
if (extensions_bitvector & (1u << i)) {
@@ -319,76 +330,84 @@ size_t GenerateRtpPacket(uint32_t extensions_bitvector,
}
}
- int8_t payload_type = rand() % 128;
- bool marker_bit = (rand() % 2 == 1);
- uint32_t capture_timestamp = rand();
- int64_t capture_time_ms = rand();
- bool timestamp_provided = (rand() % 2 == 1);
- bool inc_sequence_number = (rand() % 2 == 1);
+ int8_t payload_type = prng->Rand(0, 127);
+ bool marker_bit = prng->Rand<bool>();
+ uint32_t capture_timestamp = prng->Rand<uint32_t>();
+ int64_t capture_time_ms = prng->Rand<uint32_t>();
+ bool timestamp_provided = prng->Rand<bool>();
+ bool inc_sequence_number = prng->Rand<bool>();
size_t header_size = rtp_sender.BuildRTPheader(
packet, payload_type, marker_bit, capture_timestamp, capture_time_ms,
timestamp_provided, inc_sequence_number);
for (size_t i = header_size; i < packet_size; i++) {
- packet[i] = rand();
+ packet[i] = prng->Rand<uint8_t>();
}
return header_size;
}
-void GenerateRtcpPacket(uint8_t* packet, size_t packet_size) {
- for (size_t i = 0; i < packet_size; i++) {
- packet[i] = rand();
- }
+rtc::scoped_ptr<rtcp::RawPacket> GenerateRtcpPacket(Random* prng) {
+ rtcp::ReportBlock report_block;
+ report_block.To(prng->Rand<uint32_t>()); // Remote SSRC.
+ report_block.WithFractionLost(prng->Rand(50));
+
+ rtcp::SenderReport sender_report;
+ sender_report.From(prng->Rand<uint32_t>()); // Sender SSRC.
+ sender_report.WithNtpSec(prng->Rand<uint32_t>());
+ sender_report.WithNtpFrac(prng->Rand<uint32_t>());
+ sender_report.WithPacketCount(prng->Rand<uint32_t>());
+ sender_report.WithReportBlock(report_block);
+
+ return sender_report.Build();
}
void GenerateVideoReceiveConfig(uint32_t extensions_bitvector,
- VideoReceiveStream::Config* config) {
+ VideoReceiveStream::Config* config,
+ Random* prng) {
// Create a map from a payload type to an encoder name.
VideoReceiveStream::Decoder decoder;
- decoder.payload_type = rand();
- decoder.payload_name = (rand() % 2 ? "VP8" : "H264");
+ decoder.payload_type = prng->Rand(0, 127);
+ decoder.payload_name = (prng->Rand<bool>() ? "VP8" : "H264");
config->decoders.push_back(decoder);
// Add SSRCs for the stream.
- config->rtp.remote_ssrc = rand();
- config->rtp.local_ssrc = rand();
+ config->rtp.remote_ssrc = prng->Rand<uint32_t>();
+ config->rtp.local_ssrc = prng->Rand<uint32_t>();
// Add extensions and settings for RTCP.
config->rtp.rtcp_mode =
- rand() % 2 ? RtcpMode::kCompound : RtcpMode::kReducedSize;
- config->rtp.rtcp_xr.receiver_reference_time_report = (rand() % 2 == 1);
- config->rtp.remb = (rand() % 2 == 1);
+ prng->Rand<bool>() ? RtcpMode::kCompound : RtcpMode::kReducedSize;
+ config->rtp.remb = prng->Rand<bool>();
// Add a map from a payload type to a new ssrc and a new payload type for RTX.
VideoReceiveStream::Config::Rtp::Rtx rtx_pair;
- rtx_pair.ssrc = rand();
- rtx_pair.payload_type = rand();
- config->rtp.rtx.insert(std::make_pair(rand(), rtx_pair));
+ rtx_pair.ssrc = prng->Rand<uint32_t>();
+ rtx_pair.payload_type = prng->Rand(0, 127);
+ config->rtp.rtx.insert(std::make_pair(prng->Rand(0, 127), rtx_pair));
// Add header extensions.
for (unsigned i = 0; i < kNumExtensions; i++) {
if (extensions_bitvector & (1u << i)) {
config->rtp.extensions.push_back(
- RtpExtension(kExtensionNames[i], rand()));
+ RtpExtension(kExtensionNames[i], prng->Rand<int>()));
}
}
}
void GenerateVideoSendConfig(uint32_t extensions_bitvector,
- VideoSendStream::Config* config) {
+ VideoSendStream::Config* config,
+ Random* prng) {
// Create a map from a payload type to an encoder name.
- config->encoder_settings.payload_type = rand();
- config->encoder_settings.payload_name = (rand() % 2 ? "VP8" : "H264");
+ config->encoder_settings.payload_type = prng->Rand(0, 127);
+ config->encoder_settings.payload_name = (prng->Rand<bool>() ? "VP8" : "H264");
// Add SSRCs for the stream.
- config->rtp.ssrcs.push_back(rand());
+ config->rtp.ssrcs.push_back(prng->Rand<uint32_t>());
// Add a map from a payload type to new ssrcs and a new payload type for RTX.
- config->rtp.rtx.ssrcs.push_back(rand());
- config->rtp.rtx.payload_type = rand();
- // Add a CNAME.
- config->rtp.c_name = "some.user@some.host";
+ config->rtp.rtx.ssrcs.push_back(prng->Rand<uint32_t>());
+ config->rtp.rtx.payload_type = prng->Rand(0, 127);
// Add header extensions.
for (unsigned i = 0; i < kNumExtensions; i++) {
if (extensions_bitvector & (1u << i)) {
config->rtp.extensions.push_back(
- RtpExtension(kExtensionNames[i], rand()));
+ RtpExtension(kExtensionNames[i], prng->Rand<int>()));
}
}
}
@@ -398,42 +417,49 @@ void GenerateVideoSendConfig(uint32_t extensions_bitvector,
void LogSessionAndReadBack(size_t rtp_count,
size_t rtcp_count,
size_t playout_count,
+ size_t bwe_loss_count,
uint32_t extensions_bitvector,
uint32_t csrcs_count,
unsigned int random_seed) {
ASSERT_LE(rtcp_count, rtp_count);
ASSERT_LE(playout_count, rtp_count);
+ ASSERT_LE(bwe_loss_count, rtp_count);
std::vector<rtc::Buffer> rtp_packets;
- std::vector<rtc::Buffer> rtcp_packets;
+ std::vector<rtc::scoped_ptr<rtcp::RawPacket> > rtcp_packets;
std::vector<size_t> rtp_header_sizes;
std::vector<uint32_t> playout_ssrcs;
+ std::vector<std::pair<int32_t, uint8_t> > bwe_loss_updates;
VideoReceiveStream::Config receiver_config(nullptr);
VideoSendStream::Config sender_config(nullptr);
- srand(random_seed);
+ Random prng(random_seed);
// Create rtp_count RTP packets containing random data.
for (size_t i = 0; i < rtp_count; i++) {
- size_t packet_size = 1000 + rand() % 64;
+ size_t packet_size = prng.Rand(1000, 1100);
rtp_packets.push_back(rtc::Buffer(packet_size));
- size_t header_size = GenerateRtpPacket(extensions_bitvector, csrcs_count,
- rtp_packets[i].data(), packet_size);
+ size_t header_size =
+ GenerateRtpPacket(extensions_bitvector, csrcs_count,
+ rtp_packets[i].data(), packet_size, &prng);
rtp_header_sizes.push_back(header_size);
}
// Create rtcp_count RTCP packets containing random data.
for (size_t i = 0; i < rtcp_count; i++) {
- size_t packet_size = 1000 + rand() % 64;
- rtcp_packets.push_back(rtc::Buffer(packet_size));
- GenerateRtcpPacket(rtcp_packets[i].data(), packet_size);
+ rtcp_packets.push_back(GenerateRtcpPacket(&prng));
}
// Create playout_count random SSRCs to use when logging AudioPlayout events.
for (size_t i = 0; i < playout_count; i++) {
- playout_ssrcs.push_back(static_cast<uint32_t>(rand()));
+ playout_ssrcs.push_back(prng.Rand<uint32_t>());
+ }
+ // Create bwe_loss_count random bitrate updates for BwePacketLoss.
+ for (size_t i = 0; i < bwe_loss_count; i++) {
+ bwe_loss_updates.push_back(
+ std::make_pair(prng.Rand<int32_t>(), prng.Rand<uint8_t>()));
}
// Create configurations for the video streams.
- GenerateVideoReceiveConfig(extensions_bitvector, &receiver_config);
- GenerateVideoSendConfig(extensions_bitvector, &sender_config);
+ GenerateVideoReceiveConfig(extensions_bitvector, &receiver_config, &prng);
+ GenerateVideoSendConfig(extensions_bitvector, &sender_config, &prng);
const int config_count = 2;
// Find the name of the current test, in order to use it as a temporary
@@ -448,7 +474,9 @@ void LogSessionAndReadBack(size_t rtp_count,
rtc::scoped_ptr<RtcEventLog> log_dumper(RtcEventLog::Create());
log_dumper->LogVideoReceiveStreamConfig(receiver_config);
log_dumper->LogVideoSendStreamConfig(sender_config);
- size_t rtcp_index = 1, playout_index = 1;
+ size_t rtcp_index = 1;
+ size_t playout_index = 1;
+ size_t bwe_loss_index = 1;
for (size_t i = 1; i <= rtp_count; i++) {
log_dumper->LogRtpHeader(
(i % 2 == 0), // Every second packet is incoming.
@@ -458,14 +486,20 @@ void LogSessionAndReadBack(size_t rtp_count,
log_dumper->LogRtcpPacket(
rtcp_index % 2 == 0, // Every second packet is incoming
rtcp_index % 3 == 0 ? MediaType::AUDIO : MediaType::VIDEO,
- rtcp_packets[rtcp_index - 1].data(),
- rtcp_packets[rtcp_index - 1].size());
+ rtcp_packets[rtcp_index - 1]->Buffer(),
+ rtcp_packets[rtcp_index - 1]->Length());
rtcp_index++;
}
if (i * playout_count >= playout_index * rtp_count) {
log_dumper->LogAudioPlayout(playout_ssrcs[playout_index - 1]);
playout_index++;
}
+ if (i * bwe_loss_count >= bwe_loss_index * rtp_count) {
+ log_dumper->LogBwePacketLossEvent(
+ bwe_loss_updates[bwe_loss_index - 1].first,
+ bwe_loss_updates[bwe_loss_index - 1].second, i);
+ bwe_loss_index++;
+ }
if (i == rtp_count / 2) {
log_dumper->StartLogging(temp_filename, 10000000);
}
@@ -480,12 +514,15 @@ void LogSessionAndReadBack(size_t rtp_count,
// Verify that what we read back from the event log is the same as
// what we wrote down. For RTCP we log the full packets, but for
// RTP we should only log the header.
- const int event_count =
- config_count + playout_count + rtcp_count + rtp_count + 1;
+ const int event_count = config_count + playout_count + bwe_loss_count +
+ rtcp_count + rtp_count + 1;
EXPECT_EQ(event_count, parsed_stream.stream_size());
VerifyReceiveStreamConfig(parsed_stream.stream(0), receiver_config);
VerifySendStreamConfig(parsed_stream.stream(1), sender_config);
- size_t event_index = config_count, rtcp_index = 1, playout_index = 1;
+ size_t event_index = config_count;
+ size_t rtcp_index = 1;
+ size_t playout_index = 1;
+ size_t bwe_loss_index = 1;
for (size_t i = 1; i <= rtp_count; i++) {
VerifyRtpEvent(parsed_stream.stream(event_index),
(i % 2 == 0), // Every second packet is incoming.
@@ -497,8 +534,8 @@ void LogSessionAndReadBack(size_t rtp_count,
VerifyRtcpEvent(parsed_stream.stream(event_index),
rtcp_index % 2 == 0, // Every second packet is incoming.
rtcp_index % 3 == 0 ? MediaType::AUDIO : MediaType::VIDEO,
- rtcp_packets[rtcp_index - 1].data(),
- rtcp_packets[rtcp_index - 1].size());
+ rtcp_packets[rtcp_index - 1]->Buffer(),
+ rtcp_packets[rtcp_index - 1]->Length());
event_index++;
rtcp_index++;
}
@@ -508,6 +545,13 @@ void LogSessionAndReadBack(size_t rtp_count,
event_index++;
playout_index++;
}
+ if (i * bwe_loss_count >= bwe_loss_index * rtp_count) {
+ VerifyBweLossEvent(parsed_stream.stream(event_index),
+ bwe_loss_updates[bwe_loss_index - 1].first,
+ bwe_loss_updates[bwe_loss_index - 1].second, i);
+ event_index++;
+ bwe_loss_index++;
+ }
if (i == rtp_count / 2) {
VerifyLogStartEvent(parsed_stream.stream(event_index));
event_index++;
@@ -519,10 +563,11 @@ void LogSessionAndReadBack(size_t rtp_count,
}
TEST(RtcEventLogTest, LogSessionAndReadBack) {
- // Log 5 RTP, 2 RTCP, and 0 playout events with no header extensions or CSRCS.
- LogSessionAndReadBack(5, 2, 0, 0, 0, 321);
+ // Log 5 RTP, 2 RTCP, 0 playout events and 0 BWE events
+ // with no header extensions or CSRCS.
+ LogSessionAndReadBack(5, 2, 0, 0, 0, 0, 321);
- // Enable AbsSendTime and TransportSequenceNumbers
+ // Enable AbsSendTime and TransportSequenceNumbers.
uint32_t extensions = 0;
for (uint32_t i = 0; i < kNumExtensions; i++) {
if (kExtensionTypes[i] == RTPExtensionType::kRtpExtensionAbsoluteSendTime ||
@@ -531,20 +576,21 @@ TEST(RtcEventLogTest, LogSessionAndReadBack) {
extensions |= 1u << i;
}
}
- LogSessionAndReadBack(8, 2, 0, extensions, 0, 3141592653u);
+ LogSessionAndReadBack(8, 2, 0, 0, extensions, 0, 3141592653u);
- extensions = (1u << kNumExtensions) - 1; // Enable all header extensions
- LogSessionAndReadBack(9, 2, 3, extensions, 2, 2718281828u);
+ extensions = (1u << kNumExtensions) - 1; // Enable all header extensions.
+ LogSessionAndReadBack(9, 2, 3, 2, extensions, 2, 2718281828u);
// Try all combinations of header extensions and up to 2 CSRCS.
for (extensions = 0; extensions < (1u << kNumExtensions); extensions++) {
for (uint32_t csrcs_count = 0; csrcs_count < 3; csrcs_count++) {
LogSessionAndReadBack(5 + extensions, // Number of RTP packets.
2 + csrcs_count, // Number of RTCP packets.
- 3 + csrcs_count, // Number of playout events
- extensions, // Bit vector choosing extensions
- csrcs_count, // Number of contributing sources
- rand());
+ 3 + csrcs_count, // Number of playout events.
+ 1 + csrcs_count, // Number of BWE loss events.
+ extensions, // Bit vector choosing extensions.
+ csrcs_count, // Number of contributing sources.
+ extensions * 3 + csrcs_count + 1); // Random seed.
}
}
}
@@ -556,35 +602,32 @@ void DropOldEvents(uint32_t extensions_bitvector,
unsigned int random_seed) {
rtc::Buffer old_rtp_packet;
rtc::Buffer recent_rtp_packet;
- rtc::Buffer old_rtcp_packet;
- rtc::Buffer recent_rtcp_packet;
+ rtc::scoped_ptr<rtcp::RawPacket> old_rtcp_packet;
+ rtc::scoped_ptr<rtcp::RawPacket> recent_rtcp_packet;
VideoReceiveStream::Config receiver_config(nullptr);
VideoSendStream::Config sender_config(nullptr);
- srand(random_seed);
+ Random prng(random_seed);
// Create two RTP packets containing random data.
- size_t packet_size = 1000 + rand() % 64;
+ size_t packet_size = prng.Rand(1000, 1100);
old_rtp_packet.SetSize(packet_size);
GenerateRtpPacket(extensions_bitvector, csrcs_count, old_rtp_packet.data(),
- packet_size);
- packet_size = 1000 + rand() % 64;
+ packet_size, &prng);
+ packet_size = prng.Rand(1000, 1100);
recent_rtp_packet.SetSize(packet_size);
- size_t recent_header_size = GenerateRtpPacket(
- extensions_bitvector, csrcs_count, recent_rtp_packet.data(), packet_size);
+ size_t recent_header_size =
+ GenerateRtpPacket(extensions_bitvector, csrcs_count,
+ recent_rtp_packet.data(), packet_size, &prng);
// Create two RTCP packets containing random data.
- packet_size = 1000 + rand() % 64;
- old_rtcp_packet.SetSize(packet_size);
- GenerateRtcpPacket(old_rtcp_packet.data(), packet_size);
- packet_size = 1000 + rand() % 64;
- recent_rtcp_packet.SetSize(packet_size);
- GenerateRtcpPacket(recent_rtcp_packet.data(), packet_size);
+ old_rtcp_packet = GenerateRtcpPacket(&prng);
+ recent_rtcp_packet = GenerateRtcpPacket(&prng);
// Create configurations for the video streams.
- GenerateVideoReceiveConfig(extensions_bitvector, &receiver_config);
- GenerateVideoSendConfig(extensions_bitvector, &sender_config);
+ GenerateVideoReceiveConfig(extensions_bitvector, &receiver_config, &prng);
+ GenerateVideoSendConfig(extensions_bitvector, &sender_config, &prng);
// Find the name of the current test, in order to use it as a temporary
// filename.
@@ -601,16 +644,16 @@ void DropOldEvents(uint32_t extensions_bitvector,
log_dumper->LogVideoSendStreamConfig(sender_config);
log_dumper->LogRtpHeader(false, MediaType::AUDIO, old_rtp_packet.data(),
old_rtp_packet.size());
- log_dumper->LogRtcpPacket(true, MediaType::AUDIO, old_rtcp_packet.data(),
- old_rtcp_packet.size());
+ log_dumper->LogRtcpPacket(true, MediaType::AUDIO, old_rtcp_packet->Buffer(),
+ old_rtcp_packet->Length());
// Sleep 55 ms to let old events be removed from the queue.
rtc::Thread::SleepMs(55);
log_dumper->StartLogging(temp_filename, 10000000);
log_dumper->LogRtpHeader(true, MediaType::VIDEO, recent_rtp_packet.data(),
recent_rtp_packet.size());
log_dumper->LogRtcpPacket(false, MediaType::VIDEO,
- recent_rtcp_packet.data(),
- recent_rtcp_packet.size());
+ recent_rtcp_packet->Buffer(),
+ recent_rtcp_packet->Length());
}
// Read the generated file from disk.
@@ -628,7 +671,7 @@ void DropOldEvents(uint32_t extensions_bitvector,
recent_rtp_packet.data(), recent_header_size,
recent_rtp_packet.size());
VerifyRtcpEvent(parsed_stream.stream(4), false, MediaType::VIDEO,
- recent_rtcp_packet.data(), recent_rtcp_packet.size());
+ recent_rtcp_packet->Buffer(), recent_rtcp_packet->Length());
// Clean up temporary file - can be pretty slow.
remove(temp_filename.c_str());
diff --git a/webrtc/call/webrtc_call.gypi b/webrtc/call/webrtc_call.gypi
index fd70ae81f4..0c3efff43a 100644
--- a/webrtc/call/webrtc_call.gypi
+++ b/webrtc/call/webrtc_call.gypi
@@ -14,6 +14,7 @@
'<(webrtc_root)/webrtc.gyp:rtc_event_log',
],
'webrtc_call_sources': [
+ 'call/bitrate_allocator.cc',
'call/call.cc',
'call/congestion_controller.cc',
'call/transport_adapter.cc',