Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Estimate bandwidth in connection and don't limit by REMBs #1726

Merged
merged 17 commits into from
Jun 18, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions erizo/src/erizo/MediaStream.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
#include "rtp/RtcpForwarder.h"
#include "rtp/RtpSlideShowHandler.h"
#include "rtp/RtpTrackMuteHandler.h"
#include "rtp/BandwidthEstimationHandler.h"
#include "rtp/FecReceiverHandler.h"
#include "rtp/RtcpProcessorHandler.h"
#include "rtp/RtpRetransmissionHandler.h"
Expand Down Expand Up @@ -470,7 +469,6 @@ void MediaStream::initializePipeline() {
addHandlerInPosition(MIDDLE, handler_pointer_dic, handler_order);
pipeline_->addFront(std::make_shared<PliPacerHandler>());
pipeline_->addFront(std::make_shared<RtpPaddingRemovalHandler>());
pipeline_->addFront(std::make_shared<BandwidthEstimationHandler>());
pipeline_->addFront(std::make_shared<RtcpFeedbackGenerationHandler>());
pipeline_->addFront(std::make_shared<RtpRetransmissionHandler>());
pipeline_->addFront(std::make_shared<SRPacketHandler>());
Expand Down
2 changes: 1 addition & 1 deletion erizo/src/erizo/MediaStream.h
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ class MediaStream: public MediaSink, public MediaSource, public FeedbackSink,

bool isPipelineInitialized() { return pipeline_initialized_; }
bool isRunning() { return pipeline_initialized_ && sending_; }
bool isReady() { return ready_; }
virtual bool isReady() { return ready_; }
Pipeline::Ptr getPipeline() { return pipeline_; }
bool isPublisher() { return is_publisher_; }
void setBitrateFromMaxQualityLayer(uint64_t bitrate) { bitrate_from_max_quality_layer_ = bitrate; }
Expand Down
4 changes: 4 additions & 0 deletions erizo/src/erizo/WebRtcConnection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "bandwidth/TargetVideoBWDistributor.h"
#include "rtp/RtpHeaders.h"
#include "rtp/SenderBandwidthEstimationHandler.h"
#include "rtp/BandwidthEstimationHandler.h"
#include "rtp/RtpPaddingManagerHandler.h"
#include "rtp/RtpUtils.h"

Expand Down Expand Up @@ -113,6 +114,8 @@ void WebRtcConnection::initializePipeline() {

pipeline_->addFront(std::make_shared<ConnectionPacketReader>(this));

pipeline_->addFront(std::make_shared<BandwidthEstimationHandler>());

pipeline_->addFront(std::make_shared<SenderBandwidthEstimationHandler>());
pipeline_->addFront(std::make_shared<RtpPaddingManagerHandler>());

Expand Down Expand Up @@ -769,6 +772,7 @@ boost::future<void> WebRtcConnection::processRemoteSdp() {

local_sdp_->setOfferSdp(remote_sdp_);
extension_processor_.setSdpInfo(local_sdp_);
notifyUpdateToHandlers();
local_sdp_->updateSupportedExtensionMap(extension_processor_.getSupportedExtensionMap());

if (first_remote_sdp_processed_) {
Expand Down
71 changes: 42 additions & 29 deletions erizo/src/erizo/rtp/BandwidthEstimationHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include <vector>

#include "./WebRtcConnection.h"
#include "./MediaStream.h"
#include "lib/Clock.h"
#include "lib/ClockUtils.h"
Expand Down Expand Up @@ -39,11 +40,11 @@ std::unique_ptr<RemoteBitrateEstimator> RemoteBitrateEstimatorPicker::pickEstima
}

BandwidthEstimationHandler::BandwidthEstimationHandler(std::shared_ptr<RemoteBitrateEstimatorPicker> picker) :
stream_{nullptr}, clock_{webrtc::Clock::GetRealTimeClock()},
connection_{nullptr}, clock_{webrtc::Clock::GetRealTimeClock()},
picker_{picker},
using_absolute_send_time_{false}, packets_since_absolute_send_time_{0},
min_bitrate_bps_{kMinBitRateAllowed},
bitrate_{0}, last_send_bitrate_{0}, max_video_bw_{kDefaultMaxVideoBWInKbps}, last_remb_time_{0},
bitrate_{0}, last_send_bitrate_{0}, last_remb_time_{0},
running_{false}, active_{true}, initialized_{false} {
rtc::LogMessage::SetLogToStderr(false);
}
Expand All @@ -58,31 +59,23 @@ void BandwidthEstimationHandler::disable() {

void BandwidthEstimationHandler::notifyUpdate() {
auto pipeline = getContext()->getPipelineShared();

if (pipeline) {
auto rtcp_processor = pipeline->getService<RtcpProcessor>();
if (rtcp_processor) {
max_video_bw_ = rtcp_processor->getMaxVideoBW();
}
if (pipeline && !connection_) {
connection_ = pipeline->getService<WebRtcConnection>().get();
}

if (initialized_) {
if (!connection_) {
ELOG_ERROR("Returning because there is no connection");
return;
}

if (pipeline && !stream_) {
stream_ = pipeline->getService<MediaStream>().get();
}
if (!stream_) {
RtpExtensionProcessor& ext_processor = connection_->getRtpExtensionProcessor();
updateExtensionMaps(ext_processor.getVideoExtensionMap(), ext_processor.getAudioExtensionMap());

if (initialized_) {
return;
}
worker_ = stream_->getWorker();
worker_ = connection_->getWorker();
stats_ = pipeline->getService<Stats>();
RtpExtensionProcessor& ext_processor = stream_->getRtpExtensionProcessor();
if (ext_processor.getVideoExtensionMap().size() == 0) {
return;
}
updateExtensionMaps(ext_processor.getVideoExtensionMap(), ext_processor.getAudioExtensionMap());

pickEstimator();
initialized_ = true;
Expand Down Expand Up @@ -229,19 +222,40 @@ void BandwidthEstimationHandler::pickEstimator() {
}

void BandwidthEstimationHandler::sendREMBPacket() {
uint32_t sink_ssrc = 0;
source_ssrcs_.clear();
ELOG_DEBUG("Update MediaStream SSRCs");
connection_->forEachMediaStream([this, &sink_ssrc] (const std::shared_ptr<MediaStream> &media_stream) {
ELOG_DEBUG("MediaStream %s, publisher %u, sink %u, source %u, isReady %d", media_stream->getId().c_str(),
media_stream->isPublisher(), media_stream->getVideoSinkSSRC(), media_stream->getVideoSourceSSRC(),
media_stream->isReady());
if (media_stream->isReady() && media_stream->isPublisher()) {
sink_ssrc = media_stream->getVideoSinkSSRC();
}
source_ssrcs_.push_back(media_stream->getVideoSourceSSRC());
});

if (sink_ssrc == 0) {
ELOG_DEBUG("No SSRC available to send REMB");
return;
}
remb_packet_.setPacketType(RTCP_PS_Feedback_PT);
remb_packet_.setBlockCount(RTCP_AFB);
memcpy(&remb_packet_.report.rembPacket.uniqueid, "REMB", 4);

remb_packet_.setSSRC(stream_->getVideoSinkSSRC());
// todo(pedro) figure out which sourceSSRC to use here
remb_packet_.setSourceSSRC(stream_->getVideoSourceSSRC());
remb_packet_.setLength(5);
uint32_t capped_bitrate = max_video_bw_ > 0 ? std::min(max_video_bw_, bitrate_) : bitrate_;
ELOG_DEBUG("Bitrates min(%u,%u) = %u", bitrate_, max_video_bw_, capped_bitrate);
remb_packet_.setSSRC(sink_ssrc);
remb_packet_.setSourceSSRC(0);
remb_packet_.setLength(4 + source_ssrcs_.size());
uint32_t capped_bitrate = bitrate_;
ELOG_DEBUG("Bitrates min(%u) = %u", bitrate_, capped_bitrate);
remb_packet_.setREMBBitRate(capped_bitrate);
remb_packet_.setREMBNumSSRC(1);
remb_packet_.setREMBFeedSSRC(0, stream_->getVideoSourceSSRC());
remb_packet_.setREMBNumSSRC(source_ssrcs_.size());

for (std::size_t i = 0; i < source_ssrcs_.size(); i++) {
ELOG_DEBUG("Setting REMBFeedSSRC %u to ssrc %u, size %u", i, source_ssrcs_[i], source_ssrcs_.size());
remb_packet_.setREMBFeedSSRC(i, source_ssrcs_[i]);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💯

}

int remb_length = (remb_packet_.getLength() + 1) * 4;
if (active_) {
ELOG_DEBUG("BWE Estimation is %d", last_send_bitrate_);
Expand Down Expand Up @@ -274,8 +288,7 @@ void BandwidthEstimationHandler::OnReceiveBitrateChanged(const std::vector<uint3
}
last_remb_time_ = now;
last_send_bitrate_ = bitrate_;
stats_->getNode()
[stream_->getVideoSourceSSRC()].insertStat("erizoBandwidth", CumulativeStat{last_send_bitrate_});
stats_->getNode().insertStat("erizoBandwidth", CumulativeStat{last_send_bitrate_});
sendREMBPacket();
}

Expand Down
6 changes: 3 additions & 3 deletions erizo/src/erizo/rtp/BandwidthEstimationHandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@

namespace erizo {

class MediaStream;
class WebRtcConnection;
using webrtc::RemoteBitrateEstimator;
using webrtc::RemoteBitrateObserver;
using webrtc::RtpHeaderExtensionMap;
Expand Down Expand Up @@ -68,7 +68,7 @@ class BandwidthEstimationHandler: public Handler, public RemoteBitrateObserver,

void updateExtensionMap(bool video, std::array<RTPExtensions, 15> map);

MediaStream *stream_;
WebRtcConnection *connection_;
std::shared_ptr<Worker> worker_;
std::shared_ptr<Stats> stats_;
webrtc::Clock* const clock_;
Expand All @@ -82,8 +82,8 @@ class BandwidthEstimationHandler: public Handler, public RemoteBitrateObserver,
RtpHeaderExtensionMap ext_map_audio_, ext_map_video_;
uint32_t bitrate_;
uint32_t last_send_bitrate_;
uint32_t max_video_bw_;
uint64_t last_remb_time_;
std::vector<uint32_t> source_ssrcs_;
bool running_;
bool active_;
bool initialized_;
Expand Down
42 changes: 34 additions & 8 deletions erizo/src/test/rtp/BandwidthEstimationHandlerTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ using ::testing::_;
using ::testing::IsNull;
using ::testing::Args;
using ::testing::Return;
using ::testing::AtLeast;
using erizo::DataPacket;
using erizo::packetType;
using erizo::AUDIO_PACKET;
Expand All @@ -46,14 +47,37 @@ class BandwidthEstimationHandlerTest : public erizo::HandlerTest {
picker = std::make_shared<erizo::MockRemoteBitrateEstimatorPicker>();
EXPECT_CALL(*picker.get(), pickEstimatorProxy(_, _, _))
.WillRepeatedly(Return(new erizo::RemoteBitrateEstimatorProxy(&estimator)));

bwe_handler = std::make_shared<BandwidthEstimationHandler>(picker);
pipeline->addBack(bwe_handler);
}

void afterPipelineSetup() {
}

std::shared_ptr<erizo::MockMediaStream> addMediaStreamToConnection(std::string id,
bool is_publisher, bool ready) {
auto media_stream =
std::make_shared<erizo::MockMediaStream>(simulated_worker, connection, id, id, rtp_maps, is_publisher);
std::shared_ptr<erizo::MediaStream> stream_ptr = std::dynamic_pointer_cast<erizo::MediaStream>(media_stream);
connection->addMediaStream(stream_ptr);
simulated_worker->executeTasks();
EXPECT_CALL(*media_stream.get(), isReady()).WillRepeatedly(Return(ready));
streams.push_back(media_stream);
return media_stream;
}

void internalTearDown() {
std::for_each(streams.begin(), streams.end(),
[this](const std::shared_ptr<erizo::MockMediaStream> &stream) {
connection->removeMediaStream(stream->getId());
});
simulated_worker->executeTasks();
}

std::shared_ptr<BandwidthEstimationHandler> bwe_handler;
std::shared_ptr<erizo::MockRemoteBitrateEstimatorPicker> picker;
erizo::MockRemoteBitrateEstimator estimator;
std::vector<std::shared_ptr<erizo::MockMediaStream>> streams;
};

TEST_F(BandwidthEstimationHandlerTest, basicBehaviourShouldWritePackets) {
Expand All @@ -78,8 +102,11 @@ TEST_F(BandwidthEstimationHandlerTest, basicBehaviourShouldReadPackets) {
pipeline->read(packet2);
}

TEST_F(BandwidthEstimationHandlerTest, shouldSendRembPacketWithEstimatedBitrate) {
TEST_F(BandwidthEstimationHandlerTest, shouldSendRembPacketWithEstimatedBitrateIfThereIsAPublisherReady) {
uint32_t kArbitraryBitrate = 100000;

addMediaStreamToConnection("test1", true, true);

auto packet = erizo::PacketTools::createDataPacket(erizo::kArbitrarySeqNumber, VIDEO_PACKET);

EXPECT_CALL(estimator, Process());
Expand All @@ -93,21 +120,20 @@ TEST_F(BandwidthEstimationHandlerTest, shouldSendRembPacketWithEstimatedBitrate)
picker->observer_->OnReceiveBitrateChanged(std::vector<uint32_t>(), kArbitraryBitrate);
}

TEST_F(BandwidthEstimationHandlerTest, shouldSendRembPacketWithCappedBitrate) {
TEST_F(BandwidthEstimationHandlerTest, shouldNotSendRembPacketWithEstimatedBitrateIfThePublisherIsNotReady) {
uint32_t kArbitraryBitrate = 100000;
uint32_t kArbitraryCappedBitrate = kArbitraryBitrate - 100;

addMediaStreamToConnection("test1", true, false);

auto packet = erizo::PacketTools::createDataPacket(erizo::kArbitrarySeqNumber, VIDEO_PACKET);

EXPECT_CALL(estimator, Process());
EXPECT_CALL(estimator, TimeUntilNextProcess()).WillRepeatedly(Return(1000));
EXPECT_CALL(estimator, IncomingPacket(_, _, _));
EXPECT_CALL(*reader.get(), read(_, _)).
With(Args<1>(erizo::RtpHasSequenceNumber(erizo::kArbitrarySeqNumber))).Times(1);
EXPECT_CALL(*processor.get(), getMaxVideoBW()).WillRepeatedly(Return(kArbitraryCappedBitrate));
pipeline->notifyUpdate();
pipeline->read(packet);

EXPECT_CALL(*writer.get(), write(_, _)).With(Args<1>(erizo::RembHasBitrateValue(kArbitraryCappedBitrate))).Times(1);

EXPECT_CALL(*writer.get(), write(_, _)).With(Args<1>(erizo::RembHasBitrateValue(kArbitraryBitrate))).Times(0);
picker->observer_->OnReceiveBitrateChanged(std::vector<uint32_t>(), kArbitraryBitrate);
}
1 change: 1 addition & 0 deletions erizo/src/test/utils/Mocks.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ class MockMediaStream: public MediaStream {
MOCK_METHOD0(getBitrateFromMaxQualityLayer, uint32_t());
MOCK_METHOD0(isSlideShowModeEnabled, bool());
MOCK_METHOD0(isSimulcast, bool());
MOCK_METHOD0(isReady, bool());
MOCK_METHOD2(onTransportData, void(std::shared_ptr<DataPacket>, Transport*));
MOCK_METHOD1(deliverEventInternal, void(MediaEventPtr));
MOCK_METHOD0(getTargetPaddingBitrate, uint64_t());
Expand Down
32 changes: 1 addition & 31 deletions erizo_controller/erizoClient/src/ErizoConnectionManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ class ErizoConnection extends EventEmitterConst {
log.debug(`message: Adding stream to Connection, ${this.toLog()}, ${stream.toLog()}`);
this.streamsMap.add(stream.getID(), stream);
if (stream.local) {
this.stack.addStream(stream.stream, stream.hasScreen());
this.stack.addStream(stream);
}
}

Expand All @@ -148,30 +148,10 @@ class ErizoConnection extends EventEmitterConst {
this.stack.sendSignalingMessage(msg);
}

setSimulcast(enable) {
this.stack.setSimulcast(enable);
}

setVideo(video) {
this.stack.setVideo(video);
}

setAudio(audio) {
this.stack.setAudio(audio);
}

updateSpec(configInput, streamId, callback) {
this.stack.updateSpec(configInput, streamId, callback);
}

updateSimulcastLayersBitrate(bitrates) {
this.stack.updateSimulcastLayersBitrate(bitrates);
}

updateSimulcastActiveLayers(layersInfo) {
this.stack.updateSimulcastActiveLayers(layersInfo);
}

setQualityLevel(level) {
this.qualityLevel = QUALITY_LEVELS[level];
}
Expand Down Expand Up @@ -229,16 +209,6 @@ class ErizoConnectionManager {
this.ErizoConnectionsMap.set(erizoId, connectionEntry);
}
}
if (specInput.simulcast) {
connection.setSimulcast(specInput.simulcast);
}
if (specInput.video) {
connection.setVideo(specInput.video);
}
if (specInput.audio) {
connection.setVideo(specInput.audio);
}

return connection;
}

Expand Down
Loading