From 58722d13a80152a608b33c6035395ee2f90f7d03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Cervi=C3=B1o?= Date: Mon, 22 Nov 2021 13:37:47 +0100 Subject: [PATCH] Make connection quality level depend on strategy (#1767) --- erizo/src/erizo/MediaStream.h | 4 +- erizo/src/erizo/WebRtcConnection.cpp | 12 +- erizo/src/erizo/WebRtcConnection.h | 9 +- .../BandwidthDistributionAlgorithm.h | 1 + .../bandwidth/ConnectionQualityCheck.cpp | 127 -------------- .../erizo/bandwidth/ConnectionQualityCheck.h | 63 ------- .../erizo/bandwidth/MaxVideoBWDistributor.h | 1 + .../bandwidth/StreamPriorityBWDistributor.cpp | 14 +- .../bandwidth/StreamPriorityBWDistributor.h | 3 + .../bandwidth/TargetVideoBWDistributor.h | 1 + .../bandwidth/StreamPriorityBWDistributor.cpp | 119 ++++++++++--- .../fallback/ConnectionQualityCheckTest.cpp | 160 ------------------ erizo/src/test/utils/Matchers.h | 6 - erizo/src/test/utils/Mocks.h | 2 + .../erizoClient/src/ErizoConnectionManager.js | 8 +- 15 files changed, 133 insertions(+), 397 deletions(-) delete mode 100644 erizo/src/erizo/bandwidth/ConnectionQualityCheck.cpp delete mode 100644 erizo/src/erizo/bandwidth/ConnectionQualityCheck.h delete mode 100644 erizo/src/test/fallback/ConnectionQualityCheckTest.cpp diff --git a/erizo/src/erizo/MediaStream.h b/erizo/src/erizo/MediaStream.h index 04b8c6e6d6..38785e99ac 100644 --- a/erizo/src/erizo/MediaStream.h +++ b/erizo/src/erizo/MediaStream.h @@ -101,8 +101,8 @@ class MediaStream: public MediaSink, public MediaSource, public FeedbackSink, int sendPLI() override; void sendPLIToFeedback(); void setQualityLayer(int spatial_layer, int temporal_layer); - void enableSlideShowBelowSpatialLayer(bool enabled, int spatial_layer); - void enableFallbackBelowMinLayer(bool enabled); + virtual void enableSlideShowBelowSpatialLayer(bool enabled, int spatial_layer); + virtual void enableFallbackBelowMinLayer(bool enabled); void setPeriodicKeyframeRequests(bool activate, uint32_t interval_in_ms = 0); WebRTCEvent getCurrentState(); diff --git a/erizo/src/erizo/WebRtcConnection.cpp b/erizo/src/erizo/WebRtcConnection.cpp index 3261888ec0..aa7693d00a 100644 --- a/erizo/src/erizo/WebRtcConnection.cpp +++ b/erizo/src/erizo/WebRtcConnection.cpp @@ -312,11 +312,10 @@ bool WebRtcConnection::createOfferSync(bool bundle) { } ConnectionQualityLevel WebRtcConnection::getConnectionQualityLevel() { - return connection_quality_check_.getLevel(); -} - -bool WebRtcConnection::werePacketLossesRecently() { - return connection_quality_check_.werePacketLossesRecently(); + if (distributor_->tooLowBandwidthEstimation()) { + return ConnectionQualityLevel::VERY_LOW; + } + return ConnectionQualityLevel::GOOD; } void WebRtcConnection::associateMediaStreamToTransceiver(std::shared_ptr media_stream, @@ -996,9 +995,6 @@ void WebRtcConnection::onREMBFromTransport(RtcpHeader *chead, Transport *transpo } void WebRtcConnection::onRtcpFromTransport(std::shared_ptr packet, Transport *transport) { - if (enable_connection_quality_check_) { - connection_quality_check_.onFeedback(packet, streams_); - } RtpUtils::forEachRtcpBlock(packet, [this, packet, transport](RtcpHeader *chead) { uint32_t ssrc = chead->isFeedback() ? chead->getSourceSSRC() : chead->getSSRC(); if (chead->isREMB()) { diff --git a/erizo/src/erizo/WebRtcConnection.h b/erizo/src/erizo/WebRtcConnection.h index 71e1e3af1f..3ba0f04565 100644 --- a/erizo/src/erizo/WebRtcConnection.h +++ b/erizo/src/erizo/WebRtcConnection.h @@ -15,7 +15,6 @@ #include "./Transport.h" #include "./Stats.h" #include "bandwidth/BandwidthDistributionAlgorithm.h" -#include "bandwidth/ConnectionQualityCheck.h" #include "bandwidth/BwDistributionConfig.h" #include "pipeline/Pipeline.h" #include "thread/Worker.h" @@ -40,6 +39,12 @@ class IceConfig; class MediaStream; class Transceiver; +enum ConnectionQualityLevel { + VERY_LOW = 0, + LOW = 1, + GOOD = 2 +}; + /** * WebRTC Events */ @@ -179,7 +184,6 @@ class WebRtcConnection: public TransportListener, public LogContext, public Hand void write(std::shared_ptr packet); void notifyUpdateToHandlers() override; ConnectionQualityLevel getConnectionQualityLevel(); - bool werePacketLossesRecently(); void getJSONStats(std::function callback); private: @@ -238,7 +242,6 @@ class WebRtcConnection: public TransportListener, public LogContext, public Hand std::unique_ptr distributor_; BwDistributionConfig bw_distribution_config_; - ConnectionQualityCheck connection_quality_check_; bool enable_connection_quality_check_; bool encrypt_transport_; std::atomic connection_target_bw_; diff --git a/erizo/src/erizo/bandwidth/BandwidthDistributionAlgorithm.h b/erizo/src/erizo/bandwidth/BandwidthDistributionAlgorithm.h index 8bb4347724..9a843ac316 100644 --- a/erizo/src/erizo/bandwidth/BandwidthDistributionAlgorithm.h +++ b/erizo/src/erizo/bandwidth/BandwidthDistributionAlgorithm.h @@ -15,6 +15,7 @@ class BandwidthDistributionAlgorithm { virtual ~BandwidthDistributionAlgorithm() {} virtual void distribute(uint32_t remb, uint32_t ssrc, std::vector> streams, Transport *transport) = 0; + virtual bool tooLowBandwidthEstimation() = 0; }; } // namespace erizo diff --git a/erizo/src/erizo/bandwidth/ConnectionQualityCheck.cpp b/erizo/src/erizo/bandwidth/ConnectionQualityCheck.cpp deleted file mode 100644 index 4c003f02f7..0000000000 --- a/erizo/src/erizo/bandwidth/ConnectionQualityCheck.cpp +++ /dev/null @@ -1,127 +0,0 @@ -/* - * ConnectionQualityCheck.cpp - */ -#include "bandwidth/ConnectionQualityCheck.h" - -#include - -#include "MediaStream.h" -#include "rtp/RtpUtils.h" - -namespace erizo { - -DEFINE_LOGGER(ConnectionQualityCheck, "bandwidth.ConnectionQualityCheck"); - -constexpr uint8_t ConnectionQualityCheck::kHighAudioFractionLostThreshold; -constexpr uint8_t ConnectionQualityCheck::kLowAudioFractionLostThreshold; -constexpr uint8_t ConnectionQualityCheck::kHighVideoFractionLostThreshold; -constexpr uint8_t ConnectionQualityCheck::kLowVideoFractionLostThreshold; -constexpr size_t ConnectionQualityCheck::kNumberOfPacketsPerStream; - -ConnectionQualityCheck::ConnectionQualityCheck() - : quality_level_{ConnectionQualityLevel::GOOD}, audio_buffer_{1}, video_buffer_{1}, recent_packet_losses_{false} { -} - -void ConnectionQualityCheck::onFeedback(std::shared_ptr packet, - const std::vector> &streams) { - size_t audios_unmuted = std::count_if(streams.begin(), streams.end(), - [](const std::shared_ptr &stream) { - return !stream->isPublisher() && !stream->isAudioMuted(); - }); - size_t videos_unmuted = std::count_if(streams.begin(), streams.end(), - [](const std::shared_ptr &stream) { - return !stream->isPublisher() && !stream->isVideoMuted(); - }); - - audio_buffer_.set_capacity(kNumberOfPacketsPerStream * audios_unmuted); - video_buffer_.set_capacity(kNumberOfPacketsPerStream * videos_unmuted); - - int reports_count = 0; - int rrs = 0; - RtpUtils::forEachRtcpBlock(packet, [streams, this, &reports_count, &rrs](RtcpHeader *chead) { - reports_count++; - uint32_t ssrc = chead->isFeedback() ? chead->getSourceSSRC() : chead->getSSRC(); - bool is_rr = chead->isReceiverReport(); - if (!is_rr) { - return; - } - rrs++; - uint8_t fraction_lost = chead->getFractionLost(); - std::for_each(streams.begin(), streams.end(), - [ssrc, fraction_lost, this] (const std::shared_ptr &media_stream) { - if (media_stream->isPublisher()) { - return; - } - bool is_audio = media_stream->isAudioSourceSSRC(ssrc) || media_stream->isAudioSinkSSRC(ssrc); - bool is_video = media_stream->isVideoSourceSSRC(ssrc) || media_stream->isVideoSinkSSRC(ssrc); - uint8_t subscriber_fraction_lost = fraction_lost; - uint8_t publisher_fraction_lost = is_audio ? - media_stream->getPublisherInfo().audio_fraction_lost : media_stream->getPublisherInfo().video_fraction_lost; - if (fraction_lost < publisher_fraction_lost) { - subscriber_fraction_lost = 0; - } else { - subscriber_fraction_lost = fraction_lost - publisher_fraction_lost; - } - - if (is_audio) { - audio_buffer_.push_back(subscriber_fraction_lost); - } else if (is_video) { - video_buffer_.push_back(subscriber_fraction_lost); - } - }); - }); - if (rrs > 0) { - maybeNotifyMediaStreamsAboutConnectionQualityLevel(streams); - } -} - -bool ConnectionQualityCheck::werePacketLossesRecently() { - return recent_packet_losses_; -} - -void ConnectionQualityCheck::maybeNotifyMediaStreamsAboutConnectionQualityLevel( - const std::vector> &streams) { - if (!audio_buffer_.full() || !video_buffer_.full()) { - return; - } - size_t audio_buffer_size = audio_buffer_.size(); - size_t video_buffer_size = video_buffer_.size(); - uint16_t total_audio_fraction_lost = 0; - uint16_t total_video_fraction_lost = 0; - for (uint8_t f_lost : audio_buffer_) { - total_audio_fraction_lost += f_lost; - } - for (uint8_t f_lost : video_buffer_) { - total_video_fraction_lost += f_lost; - } - uint8_t audio_fraction_lost = audio_buffer_size > 0 ? total_audio_fraction_lost / audio_buffer_size : 0; - uint8_t video_fraction_lost = video_buffer_size > 0 ? total_video_fraction_lost / video_buffer_size : 0; - - if (audio_fraction_lost == 0 && video_fraction_lost == 0) { - recent_packet_losses_ = false; - } else { - recent_packet_losses_ = true; - } - - ConnectionQualityLevel level = ConnectionQualityLevel::GOOD; - if (audio_fraction_lost >= kHighAudioFractionLostThreshold) { - level = ConnectionQualityLevel::HIGH_LOSSES; - } else if (audio_fraction_lost >= kLowAudioFractionLostThreshold) { - level = ConnectionQualityLevel::LOW_LOSSES; - } - if (video_fraction_lost >= kHighVideoFractionLostThreshold) { - level = std::min(level, ConnectionQualityLevel::HIGH_LOSSES); - } else if (video_fraction_lost >= kLowVideoFractionLostThreshold) { - level = std::min(level, ConnectionQualityLevel::LOW_LOSSES); - } - if (level != quality_level_) { - quality_level_ = level; - std::for_each(streams.begin(), streams.end(), [level] (const std::shared_ptr &stream) { - if (!stream->isPublisher()) { - stream->deliverEvent(std::make_shared(level)); - } - }); - } -} - -} // namespace erizo diff --git a/erizo/src/erizo/bandwidth/ConnectionQualityCheck.h b/erizo/src/erizo/bandwidth/ConnectionQualityCheck.h deleted file mode 100644 index a4b2cbd73a..0000000000 --- a/erizo/src/erizo/bandwidth/ConnectionQualityCheck.h +++ /dev/null @@ -1,63 +0,0 @@ -#ifndef ERIZO_SRC_ERIZO_BANDWIDTH_CONNECTIONQUALITYCHECK_H_ -#define ERIZO_SRC_ERIZO_BANDWIDTH_CONNECTIONQUALITYCHECK_H_ - -#include -#include -#include - -#include "./logger.h" -#include "./MediaDefinitions.h" - -namespace erizo { - -class MediaStream; -class Transport; - -typedef boost::circular_buffer circular_buffer; - -enum ConnectionQualityLevel { - HIGH_LOSSES = 0, - LOW_LOSSES = 1, - GOOD = 2 -}; - -class ConnectionQualityEvent : public MediaEvent { - public: - explicit ConnectionQualityEvent(ConnectionQualityLevel level_) - : level{level_} {} - - std::string getType() const override { - return "ConnectionQualityEvent"; - } - ConnectionQualityLevel level; -}; - -class ConnectionQualityCheck { - DECLARE_LOGGER(); - - public: - static constexpr uint8_t kHighAudioFractionLostThreshold = 20 * 256 / 100; - static constexpr uint8_t kLowAudioFractionLostThreshold = 5 * 256 / 100; - static constexpr uint8_t kHighVideoFractionLostThreshold = 20 * 256 / 100; - static constexpr uint8_t kLowVideoFractionLostThreshold = 5 * 256 / 100; - static constexpr size_t kNumberOfPacketsPerStream = 3; - - public: - ConnectionQualityCheck(); - virtual ~ConnectionQualityCheck() {} - void onFeedback(std::shared_ptr packet, const std::vector> &streams); - ConnectionQualityLevel getLevel() { return quality_level_; } - bool werePacketLossesRecently(); - private: - void maybeNotifyMediaStreamsAboutConnectionQualityLevel( - const std::vector> &streams); - private: - ConnectionQualityLevel quality_level_; - circular_buffer audio_buffer_; - circular_buffer video_buffer_; - bool recent_packet_losses_; -}; - -} // namespace erizo - -#endif // ERIZO_SRC_ERIZO_BANDWIDTH_CONNECTIONQUALITYCHECK_H_ diff --git a/erizo/src/erizo/bandwidth/MaxVideoBWDistributor.h b/erizo/src/erizo/bandwidth/MaxVideoBWDistributor.h index ad4b50433e..098deb79bf 100644 --- a/erizo/src/erizo/bandwidth/MaxVideoBWDistributor.h +++ b/erizo/src/erizo/bandwidth/MaxVideoBWDistributor.h @@ -11,6 +11,7 @@ class MaxVideoBWDistributor : public BandwidthDistributionAlgorithm { virtual ~MaxVideoBWDistributor() {} void distribute(uint32_t remb, uint32_t ssrc, std::vector> streams, Transport *transport) override; + bool tooLowBandwidthEstimation() override { return false; } }; } // namespace erizo diff --git a/erizo/src/erizo/bandwidth/StreamPriorityBWDistributor.cpp b/erizo/src/erizo/bandwidth/StreamPriorityBWDistributor.cpp index 30091f549b..06ca10c3ea 100644 --- a/erizo/src/erizo/bandwidth/StreamPriorityBWDistributor.cpp +++ b/erizo/src/erizo/bandwidth/StreamPriorityBWDistributor.cpp @@ -13,7 +13,7 @@ namespace erizo { DEFINE_LOGGER(StreamPriorityBWDistributor, "bandwidth.StreamPriorityBWDistributor"); StreamPriorityBWDistributor::StreamPriorityBWDistributor(StreamPriorityStrategy strategy, - std::shared_ptrstats): strategy_{strategy}, stats_{stats} { + std::shared_ptrstats): strategy_{strategy}, stats_{stats}, not_using_spatial_layers_{false} { } std::string StreamPriorityBWDistributor::getStrategyId() { @@ -32,6 +32,10 @@ void StreamPriorityBWDistributor::distribute(uint32_t remb, uint32_t ssrc, } ELOG_DEBUG("Starting distribution with bitrate %lu for strategy %s", remaining_bitrate, getStrategyId().c_str()); strategy_.reset(); + + bool has_spatial_levels = false; + bool distribute_bitrate_to_spatial_levels = false; + while (strategy_.hasNextStep()) { StreamPriorityStep step = strategy_.getNextStep(); std::string priority = step.priority; @@ -54,11 +58,16 @@ void StreamPriorityBWDistributor::distribute(uint32_t remb, uint32_t ssrc, } continue; } + + has_spatial_levels = true; + if (remaining_bitrate == 0) { ELOG_DEBUG("No more bitrate to distribute"); break; } + distribute_bitrate_to_spatial_levels = true; + bool is_max = step.isLevelMax(); int layer = step.getSpatialLayer(); ELOG_DEBUG("Step with priority %s, layer %d, is_max %u remaining %lu, bitrate assigned to priority %lu", @@ -106,6 +115,9 @@ void StreamPriorityBWDistributor::distribute(uint32_t remb, uint32_t ssrc, remb, stream_info.stream->getId().c_str(), remaining_bitrate); } } + + not_using_spatial_layers_ = has_spatial_levels && !distribute_bitrate_to_spatial_levels; + stats_->getNode()["total"].insertStat("unnasignedBitrate", CumulativeStat{remaining_bitrate}); for (const auto& kv_pair : stream_infos) { for (MediaStreamPriorityInfo& stream_info : stream_infos[kv_pair.first]) { diff --git a/erizo/src/erizo/bandwidth/StreamPriorityBWDistributor.h b/erizo/src/erizo/bandwidth/StreamPriorityBWDistributor.h index ab4af4f399..4343a21209 100644 --- a/erizo/src/erizo/bandwidth/StreamPriorityBWDistributor.h +++ b/erizo/src/erizo/bandwidth/StreamPriorityBWDistributor.h @@ -25,9 +25,12 @@ DECLARE_LOGGER(); Transport *transport) override; std::string getStrategyId(); + bool tooLowBandwidthEstimation() override { return not_using_spatial_layers_; } + private: StreamPriorityStrategy strategy_; std::shared_ptr stats_; + bool not_using_spatial_layers_; }; } // namespace erizo diff --git a/erizo/src/erizo/bandwidth/TargetVideoBWDistributor.h b/erizo/src/erizo/bandwidth/TargetVideoBWDistributor.h index 5b9069569a..2bb7da3e7d 100644 --- a/erizo/src/erizo/bandwidth/TargetVideoBWDistributor.h +++ b/erizo/src/erizo/bandwidth/TargetVideoBWDistributor.h @@ -24,6 +24,7 @@ class TargetVideoBWDistributor : public BandwidthDistributionAlgorithm { virtual ~TargetVideoBWDistributor() {} void distribute(uint32_t remb, uint32_t ssrc, std::vector> streams, Transport *transport) override; + bool tooLowBandwidthEstimation() override { return false; } }; } // namespace erizo diff --git a/erizo/src/test/bandwidth/StreamPriorityBWDistributor.cpp b/erizo/src/test/bandwidth/StreamPriorityBWDistributor.cpp index fdf43a72ee..3fbfdab98b 100644 --- a/erizo/src/test/bandwidth/StreamPriorityBWDistributor.cpp +++ b/erizo/src/test/bandwidth/StreamPriorityBWDistributor.cpp @@ -95,6 +95,8 @@ class BasicStreamPriorityBWDistributorTest { EXPECT_CALL(*media_stream, getVideoBitrate()).Times(AtLeast(0)).WillRepeatedly(Return(config.bitrate_sent)); EXPECT_CALL(*media_stream, isSlideShowModeEnabled()).Times(AtLeast(0)).WillRepeatedly(Return(config.slideshow)); EXPECT_CALL(*media_stream, isSimulcast()).Times(AtLeast(0)).WillRepeatedly(Return(config.simulcast)); + EXPECT_CALL(*media_stream, enableSlideShowBelowSpatialLayer(_, _)).Times(AtLeast(0)); + EXPECT_CALL(*media_stream, enableFallbackBelowMinLayer(_)).Times(AtLeast(0)); index++; return media_stream; @@ -145,6 +147,7 @@ class BasicStreamPriorityBWDistributorTest { uint32_t bitrate_value; EnabledList add_to_remb_list; ExpectedList expected_bitrates; + bool expected_too_low_bandwidth; IceConfig ice_config; std::vector rtp_maps; std::vector ext_maps; @@ -159,7 +162,8 @@ class StreamPriorityBWDistributorTest : public BasicStreamPriorityBWDistributorT StrategyVector, uint32_t, EnabledList, - ExpectedList>> { + ExpectedList, + bool>> { protected: virtual void SetUp() { index = 0; @@ -168,6 +172,7 @@ class StreamPriorityBWDistributorTest : public BasicStreamPriorityBWDistributorT bitrate_value = std::tr1::get<2>(GetParam()); add_to_remb_list = std::tr1::get<3>(GetParam()); expected_bitrates = std::tr1::get<4>(GetParam()); + expected_too_low_bandwidth = std::tr1::get<5>(GetParam()); stats = std::make_shared(); setUpStrategy(); @@ -197,12 +202,62 @@ TEST_P(StreamPriorityBWDistributorTest, forwardRembToStreams_When_TheyExist) { index++; } onRembReceived(); + EXPECT_EQ(distributor->tooLowBandwidthEstimation(), expected_too_low_bandwidth); } INSTANTIATE_TEST_CASE_P( - REMB_values, StreamPriorityBWDistributorTest, testing::Values( - // StreamConfigList {{max_vide_bw, bitrate_sent, bitrate_for_max,quality_layer, priority, vector<>layer_bitrates, - // slideshow, simulcast}}, StrategyVector, vector<>enabled_streams, vector<>expected_bitrates + StreamPriority, StreamPriorityBWDistributorTest, testing::Values( + // StreamConfigList {{max_video_bw, bitrate_sent, bitrate_for_max,quality_layer, priority, vector<>layer_bitrates, + // slideshow, simulcast}}, StrategyVector, bitreate_received, vector<>enabled_streams, + // vector<>expected_bitrates, expected_too_low_bandwidth + make_tuple(StreamConfigList{{50, 50, 450, "20", + std::vector>({ { 100, 150, 200 }, { 250, 300, 450} }), false, true}}, + StrategyVector{ + StreamPriorityStep("20", "fallback"), + StreamPriorityStep("20", "0"), + StreamPriorityStep("10", "0"), + StreamPriorityStep("0", "0"), + StreamPriorityStep("20", "1") + }, + 0, EnabledList{1}, ExpectedList{ + 0}, + true), + make_tuple(StreamConfigList{{50, 50, 450, "20", + std::vector>({ { 100, 150, 200 }, { 250, 300, 450} }), false, true}}, + StrategyVector{ + StreamPriorityStep("20", "fallback"), + StreamPriorityStep("20", "0"), + StreamPriorityStep("10", "0"), + StreamPriorityStep("0", "0"), + StreamPriorityStep("20", "1") + }, + 500, EnabledList{1}, ExpectedList{ + 50}, + false), + make_tuple(StreamConfigList{{50, 50, 450, "20", + std::vector>({ { 100, 150, 200 }, { 250, 300, 450} }), false, true}}, + StrategyVector{ + StreamPriorityStep("20", "slideshow"), + StreamPriorityStep("20", "0"), + StreamPriorityStep("10", "0"), + StreamPriorityStep("0", "0"), + StreamPriorityStep("20", "1") + }, + 0, EnabledList{1}, ExpectedList{ + 0}, + true), + make_tuple(StreamConfigList{{50, 50, 450, "20", + std::vector>({ { 100, 150, 200 }, { 250, 300, 450} }), false, true}}, + StrategyVector{ + StreamPriorityStep("20", "slideshow"), + StreamPriorityStep("20", "0"), + StreamPriorityStep("10", "0"), + StreamPriorityStep("0", "0"), + StreamPriorityStep("20", "1") + }, + 500, EnabledList{1}, ExpectedList{ + 50}, + false), make_tuple(StreamConfigList{{50, 0, 450, "20", std::vector>({ { 100, 150, 200 }, { 250, 300, 450} }), false, true}}, StrategyVector{ @@ -212,7 +267,8 @@ INSTANTIATE_TEST_CASE_P( StreamPriorityStep("20", "1") }, 500, EnabledList{1}, ExpectedList{ - 50}), + 50}, + false), make_tuple(StreamConfigList{{1000, 0, 450, "20", std::vector>({ { 100, 150, 200 }, { 250, 300, 450} }), false, true}}, StrategyVector{ @@ -222,7 +278,8 @@ INSTANTIATE_TEST_CASE_P( StreamPriorityStep("20", "1") }, 500, EnabledList{1}, ExpectedList{ - static_cast(450 * (1 + QualityManager::kIncreaseLayerBitrateThreshold))}), + static_cast(450 * (1 + QualityManager::kIncreaseLayerBitrateThreshold))}, + false), make_tuple(StreamConfigList{{1000, 0, 450, "20", std::vector>({ { 100, 150, 200 }, { 250, 300, 450} }), false, true}}, StrategyVector{ @@ -233,7 +290,8 @@ INSTANTIATE_TEST_CASE_P( StreamPriorityStep("20", "2") }, 1500, EnabledList{1}, ExpectedList{ - static_cast(450 * (1 + QualityManager::kIncreaseLayerBitrateThreshold))}), + static_cast(450 * (1 + QualityManager::kIncreaseLayerBitrateThreshold))}, + false), make_tuple(StreamConfigList{{1000, 0, 450, "0", std::vector>({ { 100, 150, 200 }, { 250, 300, 450} }), false, true}}, StrategyVector{ @@ -244,7 +302,8 @@ INSTANTIATE_TEST_CASE_P( StreamPriorityStep("20", "2") }, 500, EnabledList{1}, ExpectedList{ - static_cast(200 * (1 + QualityManager::kIncreaseLayerBitrateThreshold))}), + static_cast(200 * (1 + QualityManager::kIncreaseLayerBitrateThreshold))}, + false), make_tuple(StreamConfigList{ {1000, 0, 450, "0", std::vector>({ { 100, 150, 200 }, { 250, 300, 450} }), false, true}, {1000, 0, 450, "0", std::vector>({ { 100, 150, 200 }, { 250, 300, 450} }), false, true} @@ -258,7 +317,8 @@ INSTANTIATE_TEST_CASE_P( }, 500, EnabledList{1, 1}, ExpectedList{ static_cast(200 * (1 + QualityManager::kIncreaseLayerBitrateThreshold)), - static_cast(200 * (1 + QualityManager::kIncreaseLayerBitrateThreshold))}), + static_cast(200 * (1 + QualityManager::kIncreaseLayerBitrateThreshold))}, + false), make_tuple(StreamConfigList{ {450, 0, 450, "10", std::vector>({ { 100, 150, 200 }, { 250, 300, 450} }), false, false}, {1000, 0, 450, "10", std::vector>({ { 100, 150, 200 }, { 250, 300, 450} }), false, true} @@ -272,7 +332,8 @@ INSTANTIATE_TEST_CASE_P( }, 1000, EnabledList{1, 1}, ExpectedList{ 450, - static_cast(450 * (1 + QualityManager::kIncreaseLayerBitrateThreshold))}), + static_cast(450 * (1 + QualityManager::kIncreaseLayerBitrateThreshold))}, + false), make_tuple(StreamConfigList{ {450, 0, 450, "10", std::vector>({ { 100, 150, 200 }, { 250, 300, 450} }), false, false}, {1000, 0, 450, "10", std::vector>({ { 100, 150, 200 }, { 250, 300, 450} }), false, true} @@ -286,7 +347,8 @@ INSTANTIATE_TEST_CASE_P( }, 1000, EnabledList{1, 1}, ExpectedList{ 450, - static_cast(450 * (1 + QualityManager::kIncreaseLayerBitrateThreshold))}), + static_cast(450 * (1 + QualityManager::kIncreaseLayerBitrateThreshold))}, + false), make_tuple(StreamConfigList{ {1000, 0, 450, "0", std::vector>({ { 100, 150, 200 }, { 250, 300, 450} }), false, true}, {1000, 0, 450, "20", std::vector>({ { 100, 150, 200 }, { 250, 300, 450} }), false, true} @@ -300,7 +362,8 @@ INSTANTIATE_TEST_CASE_P( }, 500, EnabledList{1, 1}, ExpectedList{ static_cast(200 * (1 + QualityManager::kIncreaseLayerBitrateThreshold)), - 280}), + 280}, + false), make_tuple(StreamConfigList{ {1000, 0, 450, "0", std::vector>({ { 100, 150, 300 }, { 250, 300, 450} }), false, true}, {1000, 0, 450, "20", std::vector>({ { 100, 150, 200 }, { 250, 300, 450} }), false, true} @@ -314,7 +377,8 @@ INSTANTIATE_TEST_CASE_P( }, 550, EnabledList{1, 1}, ExpectedList{ static_cast(300 * (1 + QualityManager::kIncreaseLayerBitrateThreshold)), - static_cast(200 * (1 + QualityManager::kIncreaseLayerBitrateThreshold))}), + static_cast(200 * (1 + QualityManager::kIncreaseLayerBitrateThreshold))}, + false), make_tuple(StreamConfigList{ {1000, 0, 450, "0", std::vector>({ { 100, 150, 200 }, { 250, 300, 450} }), false, true}, {1000, 0, 450, "20", std::vector>({ { 100, 150, 200 }, { 250, 300, 450} }), false, true} @@ -328,7 +392,8 @@ INSTANTIATE_TEST_CASE_P( }, 1500, EnabledList{1, 1}, ExpectedList{ static_cast(200 * (1 + QualityManager::kIncreaseLayerBitrateThreshold)), - static_cast(450 * (1 + QualityManager::kIncreaseLayerBitrateThreshold))}), + static_cast(450 * (1 + QualityManager::kIncreaseLayerBitrateThreshold))}, + false), make_tuple(StreamConfigList{ {1000, 0, 450, "0", std::vector>({ { 100, 150, 300 }, { 250, 300, 450} }), false, true}, {1000, 0, 450, "20", std::vector>({ { 100, 150, 300 }, { 250, 300, 450} }), false, true} @@ -342,7 +407,8 @@ INSTANTIATE_TEST_CASE_P( }, 500, EnabledList{1, 1}, ExpectedList{ 170, - static_cast(300 * (1 + QualityManager::kIncreaseLayerBitrateThreshold))}), + static_cast(300 * (1 + QualityManager::kIncreaseLayerBitrateThreshold))}, + false), make_tuple(StreamConfigList{ {1000, 0, 450, "20", std::vector>({ { 100, 150, 300 }, { 250, 300, 450} }), false, true}, {300, 0, 450, "20", std::vector>({ { 100, 150, 300 }, { 250, 300, 450} }), false, true}, @@ -360,7 +426,8 @@ INSTANTIATE_TEST_CASE_P( static_cast(450 * (1 + QualityManager::kIncreaseLayerBitrateThreshold)), 300, static_cast(300 * (1 + QualityManager::kIncreaseLayerBitrateThreshold)), - static_cast(300 * (1 + QualityManager::kIncreaseLayerBitrateThreshold))}), + static_cast(300 * (1 + QualityManager::kIncreaseLayerBitrateThreshold))}, + false), make_tuple(StreamConfigList{ {1000, 0, 450, "20", std::vector>({ { 100, 150, 300 }, { 250, 300, 450} }), false, true}, {1000, 0, 450, "20", std::vector>({ { 100, 150, 300 }, { 250, 300, 450} }), false, true}, @@ -378,7 +445,8 @@ INSTANTIATE_TEST_CASE_P( static_cast(300 * (1 + QualityManager::kIncreaseLayerBitrateThreshold)), static_cast(300 * (1 + QualityManager::kIncreaseLayerBitrateThreshold)), 170, - 170}), + 170}, + false), make_tuple(StreamConfigList{ {1000, 0, 450, "20", std::vector>({ { 100, 150, 300 }, { 250, 300, 450} }), false, true}, {1000, 0, 450, "20", std::vector>({ { 100, 150, 300 }, { 250, 300, 450} }), false, true}, @@ -392,8 +460,9 @@ INSTANTIATE_TEST_CASE_P( StreamPriorityStep("20", "1"), StreamPriorityStep("20", "2") }, - 100, EnabledList{1, 1, 1, 1}, ExpectedList{50, 50, 0, 0}), - make_tuple(StreamConfigList{ + 100, EnabledList{1, 1, 1, 1}, ExpectedList{50, 50, 0, 0}, + false), + make_tuple(StreamConfigList{ {1000, 0, 450, "0", std::vector>({ { 100, 150, 200 }, { 250, 300, 450} }), false, true}, {1000, 0, 450, "20", std::vector>({ { 100, 150, 200 }, { 250, 300, 450} }), false, true} }, @@ -406,7 +475,8 @@ INSTANTIATE_TEST_CASE_P( }, 1500, EnabledList{1, 1}, ExpectedList{ 1000, - static_cast(450 * (1 + QualityManager::kIncreaseLayerBitrateThreshold))}), + static_cast(450 * (1 + QualityManager::kIncreaseLayerBitrateThreshold))}, + false), make_tuple(StreamConfigList{ {1000, 0, 450, "20", std::vector>({ { 100, 150, 200 }, { 250, 300, 450} }), false, true}, {1000, 0, 450, "0", std::vector>({ { 100, 150, 200 }, { 250, 300, 450} }), false, true} @@ -418,7 +488,8 @@ INSTANTIATE_TEST_CASE_P( }, 1500, EnabledList{1, 1}, ExpectedList{ 1000, - static_cast(200 * (1 + QualityManager::kIncreaseLayerBitrateThreshold))}), + static_cast(200 * (1 + QualityManager::kIncreaseLayerBitrateThreshold))}, + false), make_tuple(StreamConfigList{ {1000, 0, 600, "20", std::vector>({ { 100, 150, 200 }, { 250, 300, 450} }), false, true}, {1000, 0, 600, "20", std::vector>({ { 100, 150, 200 }, { 250, 300, 450} }), false, true} @@ -430,7 +501,8 @@ INSTANTIATE_TEST_CASE_P( }, 1500, EnabledList{1, 1}, ExpectedList{ 750, - 750}), + 750}, + false), make_tuple(StreamConfigList{ {1000, 0, 600, "20", std::vector>({ { 100, 150, 200 }, { 250, 300, 450} }), false, true}, {1000, 0, 600, "20", std::vector>({ { 100, 150, 200 }, { 250, 300, 450} }), false, true}, @@ -446,5 +518,6 @@ INSTANTIATE_TEST_CASE_P( 1000, 1000, static_cast(200 * (1 + QualityManager::kIncreaseLayerBitrateThreshold)), - static_cast(200 * (1 + QualityManager::kIncreaseLayerBitrateThreshold))}) + static_cast(200 * (1 + QualityManager::kIncreaseLayerBitrateThreshold))}, + false) )); diff --git a/erizo/src/test/fallback/ConnectionQualityCheckTest.cpp b/erizo/src/test/fallback/ConnectionQualityCheckTest.cpp deleted file mode 100644 index 200f08e03f..0000000000 --- a/erizo/src/test/fallback/ConnectionQualityCheckTest.cpp +++ /dev/null @@ -1,160 +0,0 @@ -#include -#include - -#include -#include -#include -#include -#include "rtp/RtcpFeedbackGenerationHandler.h" - -#include -#include - -#include "../utils/Mocks.h" -#include "../utils/Matchers.h" - -using testing::_; -using testing::Return; -using testing::Eq; -using testing::Args; -using testing::AtLeast; -using erizo::DataPacket; -using erizo::ExtMap; -using erizo::IceConfig; -using erizo::RtpMap; -using erizo::RtpUtils; -using erizo::MediaStream; -using erizo::ConnectionQualityCheck; -using erizo::ConnectionQualityLevel; - -using std::make_tuple; - -typedef std::vector FractionLostList; - -class BasicConnectionQualityCheckTest { - protected: - void setUpStreams() { - simulated_clock = std::make_shared(); - simulated_worker = std::make_shared(simulated_clock); - simulated_worker->start(); - for (uint32_t index = 0; index < fraction_lost_list.size(); index++) { - auto mock_stream = addMediaStream(fraction_lost_list[index] >= 0, index); - auto erizo_stream = std::static_pointer_cast(mock_stream); - streams.push_back(mock_stream); - erizo_streams.push_back(erizo_stream); - } - for (uint32_t index = 0; index < publisher_fraction_lost_list.size(); index++) { - auto mock_stream = streams[index]; - uint8_t fraction_lost = publisher_fraction_lost_list[index] * 256 / 100; - EXPECT_CALL(*mock_stream, getPublisherInfo()) - .WillRepeatedly(Return(erizo::PublisherInfo{fraction_lost, fraction_lost})); - } - } - - std::shared_ptr addMediaStream(bool is_muted, uint32_t index) { - std::string id = std::to_string(index); - std::string label = std::to_string(index); - uint32_t video_sink_ssrc = getSsrcFromIndex(index); - uint32_t audio_sink_ssrc = getSsrcFromIndex(index) + 1; - uint32_t video_source_ssrc = getSsrcFromIndex(index) + 2; - uint32_t audio_source_ssrc = getSsrcFromIndex(index) + 3; - auto media_stream = std::make_shared(simulated_worker, nullptr, id, label, - rtp_maps, false); - media_stream->setVideoSinkSSRC(video_sink_ssrc); - media_stream->setAudioSinkSSRC(audio_sink_ssrc); - media_stream->setVideoSourceSSRC(video_source_ssrc); - media_stream->setAudioSourceSSRC(audio_source_ssrc); - - return media_stream; - } - - void onFeedbackReceived() { - for (uint8_t i = 0; i < ConnectionQualityCheck::kNumberOfPacketsPerStream * 10; i++) { - uint32_t index = 0; - for (int16_t fraction_lost : fraction_lost_list) { - if (fraction_lost >= 0) { - uint8_t f_lost = fraction_lost * 256 / 100; - auto packet = RtpUtils::createReceiverReport(getSsrcFromIndex(index) + 1, f_lost); - connection_quality_check->onFeedback(packet, erizo_streams); - auto packet2 = RtpUtils::createReceiverReport(getSsrcFromIndex(index), f_lost); - connection_quality_check->onFeedback(packet2, erizo_streams); - } - index++; - } - } - simulated_worker->executeTasks(); - } - - uint32_t getIndexFromSsrc(uint32_t ssrc) { - return ssrc / 1000; - } - - uint32_t getSsrcFromIndex(uint32_t index) { - return index * 1000; - } - - std::shared_ptr simulated_clock; - std::shared_ptr simulated_worker; - std::vector> streams; - std::vector> erizo_streams; - FractionLostList fraction_lost_list; - FractionLostList publisher_fraction_lost_list; - ConnectionQualityLevel expected_quality_level; - std::vector rtp_maps; - std::vector ext_maps; - std::shared_ptr connection_quality_check; -}; - -class ConnectionQualityCheckTest : public BasicConnectionQualityCheckTest, - public ::testing::TestWithParam> { - protected: - virtual void SetUp() { - fraction_lost_list = std::tr1::get<0>(GetParam()); - publisher_fraction_lost_list = std::tr1::get<1>(GetParam()); - expected_quality_level = std::tr1::get<2>(GetParam()); - - connection_quality_check = std::make_shared(); - - setUpStreams(); - } - - virtual void TearDown() { - streams.clear(); - } -}; - -TEST_P(ConnectionQualityCheckTest, notifyConnectionQualityEvent_When_ItChanges) { - std::for_each(streams.begin(), streams.end(), [this](const std::shared_ptr &stream) { - if (expected_quality_level != ConnectionQualityLevel::GOOD) { - EXPECT_CALL(*stream, deliverEventInternal(_)). - With(Args<0>(erizo::ConnectionQualityEventWithLevel(expected_quality_level))).Times(1); - } else { - EXPECT_CALL(*stream, deliverEventInternal(_)).Times(0); - } - }); - - - onFeedbackReceived(); -} - -INSTANTIATE_TEST_CASE_P( - FractionLost_Values, ConnectionQualityCheckTest, testing::Values( - // fraction_losts (%) publisher_fraction_lost (%) expected_quality_level - make_tuple(FractionLostList{ 99, 99, 99, 99}, FractionLostList{0, 0, 0, 0}, ConnectionQualityLevel::HIGH_LOSSES), - make_tuple(FractionLostList{ -1, 99, 99, 99}, FractionLostList{0, 0, 0, 0}, ConnectionQualityLevel::HIGH_LOSSES), - make_tuple(FractionLostList{ 25, 25, 25, 25}, FractionLostList{0, 0, 0, 0}, ConnectionQualityLevel::HIGH_LOSSES), - make_tuple(FractionLostList{ 0, 0, 41, 41}, FractionLostList{0, 0, 0, 0}, ConnectionQualityLevel::HIGH_LOSSES), - make_tuple(FractionLostList{ 19, 19, 19, 19}, FractionLostList{0, 0, 0, 0}, ConnectionQualityLevel::LOW_LOSSES), - make_tuple(FractionLostList{ 10, 10, 10, 10}, FractionLostList{0, 0, 0, 0}, ConnectionQualityLevel::LOW_LOSSES), - make_tuple(FractionLostList{ 0, 0, 20, 20}, FractionLostList{0, 0, 0, 0}, ConnectionQualityLevel::LOW_LOSSES), - make_tuple(FractionLostList{ 4, 4, 4, 4}, FractionLostList{0, 0, 0, 0}, ConnectionQualityLevel::GOOD), - make_tuple(FractionLostList{ 0, 0, 0, 0}, FractionLostList{0, 0, 0, 0}, ConnectionQualityLevel::GOOD), - make_tuple(FractionLostList{ -1, 0, 0, 0}, FractionLostList{0, 0, 0, 0}, ConnectionQualityLevel::GOOD), - make_tuple(FractionLostList{ 99, 99, 99, 99}, FractionLostList{99, 99, 99, 99}, ConnectionQualityLevel::GOOD), - make_tuple(FractionLostList{ 99, 99, 99, 99}, FractionLostList{80, 80, 80, 80}, ConnectionQualityLevel::LOW_LOSSES), - make_tuple(FractionLostList{ 0, 0, 41, 41}, FractionLostList{0, 0, 21, 21}, ConnectionQualityLevel::LOW_LOSSES), - make_tuple(FractionLostList{ 30, 30, 30, 30}, FractionLostList{5, 5, 5, 5}, ConnectionQualityLevel::HIGH_LOSSES), - make_tuple(FractionLostList{ 45, 45, 45, 45}, FractionLostList{26, 26, 26, 26}, ConnectionQualityLevel::LOW_LOSSES), - make_tuple(FractionLostList{ 45, 45, 45, 45}, FractionLostList{41, 41, 41, 41}, ConnectionQualityLevel::GOOD) -)); diff --git a/erizo/src/test/utils/Matchers.h b/erizo/src/test/utils/Matchers.h index d02e28faad..efb8287d9b 100644 --- a/erizo/src/test/utils/Matchers.h +++ b/erizo/src/test/utils/Matchers.h @@ -99,12 +99,6 @@ MATCHER(IsKeyframeFirstPacket, "") { return false; } -MATCHER_P(ConnectionQualityEventWithLevel, level, "") { - auto media_event = std::get<0>(arg); - auto quality_event = std::static_pointer_cast(media_event); - return quality_event->level == level; -} - } // namespace erizo #endif // ERIZO_SRC_TEST_UTILS_MATCHERS_H_ diff --git a/erizo/src/test/utils/Mocks.h b/erizo/src/test/utils/Mocks.h index 9b8a0343f3..40d3534241 100644 --- a/erizo/src/test/utils/Mocks.h +++ b/erizo/src/test/utils/Mocks.h @@ -126,6 +126,8 @@ class MockMediaStream: public MediaStream { MOCK_METHOD1(setTargetPaddingBitrate, void(uint64_t)); MOCK_METHOD0(getTargetVideoBitrate, uint32_t()); MOCK_METHOD0(getPublisherInfo, erizo::PublisherInfo()); + MOCK_METHOD1(enableFallbackBelowMinLayer, void(bool)); + MOCK_METHOD2(enableSlideShowBelowSpatialLayer, void(bool, int)); int deliverEvent_(MediaEventPtr event) override { deliverEventInternal(event); diff --git a/erizo_controller/erizoClient/src/ErizoConnectionManager.js b/erizo_controller/erizoClient/src/ErizoConnectionManager.js index bb29b15bb5..033da8a413 100644 --- a/erizo_controller/erizoClient/src/ErizoConnectionManager.js +++ b/erizo_controller/erizoClient/src/ErizoConnectionManager.js @@ -12,13 +12,13 @@ const EventEmitterConst = EventEmitter; // makes google-closure-compiler happy let ErizoSessionId = 103; const QUALITY_LEVEL_GOOD = 'good'; -const QUALITY_LEVEL_LOW_PACKET_LOSSES = 'low-packet-losses'; -const QUALITY_LEVEL_HIGH_PACKET_LOSSES = 'high-packet-losses'; +const QUALITY_LEVEL_LOW = 'low'; +const QUALITY_LEVEL_VERY_LOW = 'very-low'; const ICE_DISCONNECTED_TIMEOUT = 2000; const QUALITY_LEVELS = [ - QUALITY_LEVEL_HIGH_PACKET_LOSSES, - QUALITY_LEVEL_LOW_PACKET_LOSSES, + QUALITY_LEVEL_VERY_LOW, + QUALITY_LEVEL_LOW, QUALITY_LEVEL_GOOD, ];