Allow multiple send channels for REMB. Current implementation splits the remote estimate evenly between all senders.

This CL will be followed by a CL adding support for several REMB groups.

TEST=video_engine_core_unittests

Review URL: https://webrtc-codereview.appspot.com/394002

git-svn-id: http://webrtc.googlecode.com/svn/trunk@1705 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
mflodman@webrtc.org 2012-02-16 14:50:24 +00:00
parent 439be29445
commit f7b6078f6f
11 changed files with 178 additions and 44 deletions

View File

@ -813,6 +813,10 @@ public:
const WebRtc_UWord8 numberOfSSRC,
const WebRtc_UWord32* SSRC) = 0;
// Used to set maximum bitrate estimate received in a REMB packet.
virtual WebRtc_Word32 SetMaximumBitrateEstimate(
const WebRtc_UWord32 bitrate) = 0;
// Registers an observer to call when the estimate of the incoming channel
// changes.
virtual bool SetRemoteBitrateObserver(

View File

@ -266,8 +266,14 @@ public:
class RtpRemoteBitrateObserver
{
public:
// Called when a receive channel has a new bitrate estimate for the incoming
// stream.
virtual void OnReceiveBitrateChanged(unsigned int ssrc,
unsigned int bitrate) = 0;
// Called when a REMB packet has been received.
virtual void OnReceivedRemb(unsigned int bitrate) = 0;
virtual ~RtpRemoteBitrateObserver() {}
};

View File

@ -204,6 +204,8 @@ class MockRtpRtcp : public RtpRtcp {
WebRtc_Word32(const bool enable));
MOCK_METHOD3(SetREMBData,
WebRtc_Word32(const WebRtc_UWord32 bitrate, const WebRtc_UWord8 numberOfSSRC, const WebRtc_UWord32* SSRC));
MOCK_METHOD1(SetMaximumBitrateEstimate,
WebRtc_Word32(const WebRtc_UWord32 bitrate));
MOCK_METHOD1(SetRemoteBitrateObserver,
bool(RtpRemoteBitrateObserver*));
MOCK_CONST_METHOD0(IJ,

View File

@ -277,6 +277,13 @@ void RTCPSender::UpdateRemoteBitrateEstimate(unsigned int target_bitrate) {
}
}
void RTCPSender::ReceivedRemb(unsigned int estimated_bitrate) {
CriticalSectionScoped lock(_criticalSectionRTCPSender);
if (_bitrate_observer) {
_bitrate_observer->OnReceivedRemb(estimated_bitrate);
}
}
bool
RTCPSender::TMMBR() const
{

View File

@ -91,6 +91,8 @@ public:
void UpdateRemoteBitrateEstimate(unsigned int target_bitrate);
void ReceivedRemb(unsigned int estimated_bitrate);
/*
* TMMBR
*/

View File

@ -1661,6 +1661,17 @@ WebRtc_Word32 ModuleRtpRtcpImpl::SetREMBData(const WebRtc_UWord32 bitrate,
return _rtcpSender.SetREMBData(bitrate, numberOfSSRC, SSRC);
}
WebRtc_Word32 ModuleRtpRtcpImpl::SetMaximumBitrateEstimate(
const WebRtc_UWord32 bitrate) {
if(!_rtcpSender.REMB()) {
WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id,
"SetMaximumBitrateEstimate - REMB not enabled.");
return -1;
}
OnReceivedEstimatedMaxBitrate(bitrate);
return 0;
}
bool ModuleRtpRtcpImpl::SetRemoteBitrateObserver(
RtpRemoteBitrateObserver* observer) {
return _rtcpSender.SetRemoteBitrateObserver(observer);
@ -2499,17 +2510,16 @@ void ModuleRtpRtcpImpl::OnReceivedIntraFrameRequest(const RtpRtcp* caller) {
void ModuleRtpRtcpImpl::OnReceivedEstimatedMaxBitrate(
const WebRtc_UWord32 maxBitrate) {
// TODO(mflodman) Split this function in two parts. One for the child module
// and one for the default module.
// We received a REMB.
if (_defaultModule) {
// Let the default module handle this.
CriticalSectionScoped lock(_criticalSectionModulePtrs);
if (_defaultModule) {
// if we use a default module pass this info to the default module
_defaultModule->OnReceivedEstimatedMaxBitrate(maxBitrate);
return;
}
// Send this update to the REMB instance to take actions.
_rtcpSender.ReceivedRemb(maxBitrate);
return;
}
WebRtc_UWord32 newBitrate = 0;
WebRtc_UWord8 fractionLost = 0;
WebRtc_UWord16 roundTripTime = 0;
@ -2518,8 +2528,6 @@ void ModuleRtpRtcpImpl::OnReceivedEstimatedMaxBitrate(
&newBitrate,
&fractionLost,
&roundTripTime) == 0) {
// TODO(mflodman) When encoding two streams, we need to split the
// bitrate between REMB sending channels.
_rtpReceiver.UpdateBandwidthManagement(newBitrate,
fractionLost,
roundTripTime);

View File

@ -333,6 +333,9 @@ public:
const WebRtc_UWord8 numberOfSSRC,
const WebRtc_UWord32* SSRC);
virtual WebRtc_Word32 SetMaximumBitrateEstimate(
const WebRtc_UWord32 bitrate);
virtual bool SetRemoteBitrateObserver(RtpRemoteBitrateObserver* observer);
/*
* (IJ) Extended jitter report.

View File

@ -226,7 +226,7 @@ int ViEChannelManager::DeleteChannel(int channel_id) {
// Deregister possible remb modules.
RtpRtcp* rtp_module = vie_channel->rtp_rtcp();
remb_->RemoveSendChannel(rtp_module);
remb_->RemoveRembSender(rtp_module);
remb_->RemoveReceiveChannel(rtp_module);
// Deregister the channel from the ViEEncoder to stop the media flow.
@ -238,6 +238,8 @@ int ViEChannelManager::DeleteChannel(int channel_id) {
assert(e_it != vie_encoder_map_.end());
vie_encoder = e_it->second;
remb_->RemoveSendChannel(vie_encoder->SendRtpRtcpModule());
// Check if other channels are using the same encoder.
if (ChannelUsingViEEncoder(channel_id)) {
// Don't delete the ViEEncoder, at least one other channel is using it.
@ -338,6 +340,8 @@ bool ViEChannelManager::SetRembStatus(int channel_id, bool sender,
return false;
}
ViEEncoder* encoder = ViEEncoderPtr(channel_id);
if (sender || receiver) {
if (!channel->EnableRemb(true)) {
return false;
@ -347,15 +351,20 @@ bool ViEChannelManager::SetRembStatus(int channel_id, bool sender,
}
RtpRtcp* rtp_module = channel->rtp_rtcp();
if (sender) {
remb_->AddSendChannel(rtp_module);
remb_->AddRembSender(rtp_module);
remb_->AddSendChannel(encoder->SendRtpRtcpModule());
} else {
remb_->RemoveSendChannel(rtp_module);
remb_->RemoveRembSender(rtp_module);
remb_->RemoveSendChannel(encoder->SendRtpRtcpModule());
}
if (receiver) {
remb_->AddReceiveChannel(rtp_module);
rtp_module->SetRemoteBitrateObserver(remb_.get());
} else {
remb_->RemoveReceiveChannel(rtp_module);
}
if (sender || receiver) {
rtp_module->SetRemoteBitrateObserver(remb_.get());
} else {
rtp_module->SetRemoteBitrateObserver(NULL);
}
return true;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
* 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
@ -10,6 +10,7 @@
#include "video_engine/vie_remb.h"
#include <algorithm>
#include <cassert>
#include "modules/rtp_rtcp/interface/rtp_rtcp.h"
@ -35,16 +36,14 @@ VieRemb::~VieRemb() {
}
void VieRemb::AddReceiveChannel(RtpRtcp* rtp_rtcp) {
WEBRTC_TRACE(kTraceStateInfo, kTraceVideo, engine_id_,
"VieRemb::AddReceiveChannel");
assert(rtp_rtcp);
WEBRTC_TRACE(kTraceStateInfo, kTraceVideo, engine_id_,
"VieRemb::AddReceiveChannel(%p)", rtp_rtcp);
CriticalSectionScoped cs(list_crit_.get());
for (RtpModules::iterator it = receive_modules_.begin();
it != receive_modules_.end(); ++it) {
if ((*it) == rtp_rtcp)
return;
}
if (std::find(receive_modules_.begin(), receive_modules_.end(), rtp_rtcp) !=
receive_modules_.end())
return;
WEBRTC_TRACE(kTraceInfo, kTraceVideo, engine_id_, "AddRembChannel");
// The module probably doesn't have a remote SSRC yet, so don't add it to the
@ -53,9 +52,9 @@ void VieRemb::AddReceiveChannel(RtpRtcp* rtp_rtcp) {
}
void VieRemb::RemoveReceiveChannel(RtpRtcp* rtp_rtcp) {
WEBRTC_TRACE(kTraceStateInfo, kTraceVideo, engine_id_,
"VieRemb::RemoveReceiveChannel");
assert(rtp_rtcp);
WEBRTC_TRACE(kTraceStateInfo, kTraceVideo, engine_id_,
"VieRemb::RemoveReceiveChannel(%p)", rtp_rtcp);
CriticalSectionScoped cs(list_crit_.get());
unsigned int ssrc = rtp_rtcp->RemoteSSRC();
@ -69,27 +68,57 @@ void VieRemb::RemoveReceiveChannel(RtpRtcp* rtp_rtcp) {
bitrates_.erase(ssrc);
}
void VieRemb::AddSendChannel(RtpRtcp* rtp_rtcp) {
WEBRTC_TRACE(kTraceStateInfo, kTraceVideo, engine_id_,
"VieRemb::AddSendChannel");
void VieRemb::AddRembSender(RtpRtcp* rtp_rtcp) {
assert(rtp_rtcp);
WEBRTC_TRACE(kTraceStateInfo, kTraceVideo, engine_id_,
"VieRemb::AddRembSender(%p)", rtp_rtcp);
CriticalSectionScoped cs(list_crit_.get());
// TODO(mflodman) Allow multiple senders.
assert(send_modules_.empty());
// Verify this module hasn't been added earlier.
if (std::find(rtcp_sender_.begin(), rtcp_sender_.end(), rtp_rtcp) !=
rtcp_sender_.end())
return;
rtcp_sender_.push_back(rtp_rtcp);
}
void VieRemb::RemoveRembSender(RtpRtcp* rtp_rtcp) {
assert(rtp_rtcp);
WEBRTC_TRACE(kTraceStateInfo, kTraceVideo, engine_id_,
"VieRemb::RemoveRembSender(%p)", rtp_rtcp);
CriticalSectionScoped cs(list_crit_.get());
for (RtpModules::iterator it = rtcp_sender_.begin();
it != rtcp_sender_.end(); ++it) {
if ((*it) == rtp_rtcp) {
rtcp_sender_.erase(it);
return;
}
}
}
void VieRemb::AddSendChannel(RtpRtcp* rtp_rtcp) {
assert(rtp_rtcp);
WEBRTC_TRACE(kTraceStateInfo, kTraceVideo, engine_id_,
"VieRemb::AddSendChannel(%p)", rtp_rtcp);
CriticalSectionScoped cs(list_crit_.get());
// Verify this module hasn't been added earlier.
if (std::find(send_modules_.begin(), send_modules_.end(), rtp_rtcp) !=
send_modules_.end())
return;
send_modules_.push_back(rtp_rtcp);
}
void VieRemb::RemoveSendChannel(RtpRtcp* rtp_rtcp) {
WEBRTC_TRACE(kTraceStateInfo, kTraceVideo, engine_id_,
"VieRemb::AddSendChannel");
assert(rtp_rtcp);
WEBRTC_TRACE(kTraceStateInfo, kTraceVideo, engine_id_,
"VieRemb::RemoveSendChannel(%p)", rtp_rtcp);
CriticalSectionScoped cs(list_crit_.get());
for (RtpModules::iterator it = send_modules_.begin();
it != send_modules_.end(); ++it) {
it != send_modules_.end(); ++it) {
if ((*it) == rtp_rtcp) {
send_modules_.erase(it);
return;
@ -98,7 +127,7 @@ void VieRemb::RemoveSendChannel(RtpRtcp* rtp_rtcp) {
}
void VieRemb::OnReceiveBitrateChanged(unsigned int ssrc, unsigned int bitrate) {
WEBRTC_TRACE(kTraceStateInfo, kTraceVideo, engine_id_,
WEBRTC_TRACE(kTraceStream, kTraceVideo, engine_id_,
"VieRemb::UpdateBitrateEstimate(ssrc: %u, bitrate: %u)",
ssrc, bitrate);
CriticalSectionScoped cs(list_crit_.get());
@ -117,10 +146,19 @@ void VieRemb::OnReceiveBitrateChanged(unsigned int ssrc, unsigned int bitrate) {
bitrates_[ssrc] = bitrate;
}
WebRtc_Word32 VieRemb::Version(WebRtc_Word8* version,
WebRtc_UWord32& remaining_buffer_in_bytes,
WebRtc_UWord32& position) const {
return 0;
void VieRemb::OnReceivedRemb(unsigned int bitrate) {
WEBRTC_TRACE(kTraceStream, kTraceVideo, engine_id_,
"VieRemb::OnReceivedRemb(bitrate: %u)", bitrate);
// TODO(mflodman) Should be extended to allow different split of bitrate.
// TODO(mflodman) Do we want to call |SetMaximumBitrateEstimate| from
// |Process| instead?
// Split the bitrate estimate between all sending channels.
CriticalSectionScoped cs(list_crit_.get());
for (RtpModules::iterator it = send_modules_.begin();
it != send_modules_.end(); ++it) {
(*it)->SetMaximumBitrateEstimate(bitrate / send_modules_.size());
}
}
WebRtc_Word32 VieRemb::ChangeUniqueId(const WebRtc_Word32 id) {
@ -161,8 +199,8 @@ WebRtc_Word32 VieRemb::Process() {
// Send a REMB packet.
RtpRtcp* sender = NULL;
if (!send_modules_.empty()) {
sender = send_modules_.front();
if (!rtcp_sender_.empty()) {
sender = rtcp_sender_.front();
}
last_send_bitrate_ = total_bitrate;
list_crit_->Leave();

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
* 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
@ -41,7 +41,14 @@ class VieRemb : public RtpRemoteBitrateObserver, public Module {
// Removes the specified channel from REMB estimate.
void RemoveReceiveChannel(RtpRtcp* rtp_rtcp);
// Called to add a send channel to include in the REMB packet.
// Called to add a module that can generate and send REMB RTCP.
void AddRembSender(RtpRtcp* rtp_rtcp);
// Removes a REMB RTCP sender.
void RemoveRembSender(RtpRtcp* rtp_rtcp);
// Called to add a send channel encoding and sending data, affected by
// received REMB packets.
void AddSendChannel(RtpRtcp* rtp_rtcp);
// Removes the specified channel from receiving REMB packet estimates.
@ -54,10 +61,11 @@ class VieRemb : public RtpRemoteBitrateObserver, public Module {
// Implements RtpReceiveBitrateUpdate.
virtual void OnReceiveBitrateChanged(unsigned int ssrc, unsigned int bitrate);
// Called for every new receive REMB packet and distributes the estmate
// between all sending modules.
virtual void OnReceivedRemb(unsigned int bitrate);
// Implements Module.
virtual WebRtc_Word32 Version(WebRtc_Word8* version,
WebRtc_UWord32& remaining_buffer_in_bytes,
WebRtc_UWord32& position) const;
virtual WebRtc_Word32 ChangeUniqueId(const WebRtc_Word32 id);
virtual WebRtc_Word32 TimeUntilNextProcess();
virtual WebRtc_Word32 Process();
@ -79,6 +87,9 @@ class VieRemb : public RtpRemoteBitrateObserver, public Module {
// All modules encoding and sending data.
RtpModules send_modules_;
// All modules that can send REMB RTCP.
RtpModules rtcp_sender_;
// The last bitrate update for each SSRC.
SsrcBitrate bitrates_;
};

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.8
* 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
@ -49,6 +49,7 @@ TEST_F(ViERembTest, OneModuleTestForSendingRemb)
MockRtpRtcp rtp;
vie_remb_->AddReceiveChannel(&rtp);
vie_remb_->AddSendChannel(&rtp);
vie_remb_->AddRembSender(&rtp);
const unsigned int bitrate_estimate = 456;
unsigned int ssrc[] = { 1234 };
@ -71,6 +72,7 @@ TEST_F(ViERembTest, OneModuleTestForSendingRemb)
vie_remb_->RemoveReceiveChannel(&rtp);
vie_remb_->RemoveSendChannel(&rtp);
vie_remb_->RemoveRembSender(&rtp);
}
TEST_F(ViERembTest, LowerEstimateToSendRemb)
@ -78,6 +80,7 @@ TEST_F(ViERembTest, LowerEstimateToSendRemb)
MockRtpRtcp rtp;
vie_remb_->AddReceiveChannel(&rtp);
vie_remb_->AddSendChannel(&rtp);
vie_remb_->AddRembSender(&rtp);
unsigned int bitrate_estimate = 456;
unsigned int ssrc[] = { 1234 };
@ -101,6 +104,7 @@ TEST_F(ViERembTest, VerifyCombinedBitrateEstimate)
MockRtpRtcp rtp_1;
vie_remb_->AddReceiveChannel(&rtp_0);
vie_remb_->AddSendChannel(&rtp_0);
vie_remb_->AddRembSender(&rtp_0);
vie_remb_->AddReceiveChannel(&rtp_1);
unsigned int bitrate_estimate[] = { 456, 789 };
@ -125,15 +129,47 @@ TEST_F(ViERembTest, VerifyCombinedBitrateEstimate)
vie_remb_->RemoveReceiveChannel(&rtp_0);
vie_remb_->RemoveSendChannel(&rtp_0);
vie_remb_->RemoveRembSender(&rtp_0);
vie_remb_->RemoveReceiveChannel(&rtp_1);
}
// Add two senders, and insert a received REMB estimate. Both sending channels
// should get half of the received value.
TEST_F(ViERembTest, IncomingRemb)
{
MockRtpRtcp rtp_0;
MockRtpRtcp rtp_1;
vie_remb_->AddSendChannel(&rtp_0);
vie_remb_->AddSendChannel(&rtp_1);
const unsigned int bitrate_estimate = 1200;
// Fake received REMB and verify both modules get half of the bitrate.
EXPECT_CALL(rtp_0, SetMaximumBitrateEstimate(bitrate_estimate/2))
.Times(1);
EXPECT_CALL(rtp_1, SetMaximumBitrateEstimate(bitrate_estimate/2))
.Times(1);
vie_remb_->OnReceivedRemb(bitrate_estimate);
// Remove one of the modules and verify the other module get the entire
// bitrate.
vie_remb_->RemoveSendChannel(&rtp_0);
EXPECT_CALL(rtp_0, SetMaximumBitrateEstimate(_))
.Times(0);
EXPECT_CALL(rtp_1, SetMaximumBitrateEstimate(bitrate_estimate))
.Times(1);
vie_remb_->OnReceivedRemb(bitrate_estimate);
vie_remb_->RemoveSendChannel(&rtp_1);
}
TEST_F(ViERembTest, NoRembForIncreasedBitrate)
{
MockRtpRtcp rtp_0;
MockRtpRtcp rtp_1;
vie_remb_->AddReceiveChannel(&rtp_0);
vie_remb_->AddSendChannel(&rtp_0);
vie_remb_->AddRembSender(&rtp_0);
vie_remb_->AddReceiveChannel(&rtp_1);
unsigned int bitrate_estimate[] = { 456, 789 };
@ -172,6 +208,7 @@ TEST_F(ViERembTest, NoRembForIncreasedBitrate)
vie_remb_->RemoveReceiveChannel(&rtp_1);
vie_remb_->RemoveReceiveChannel(&rtp_0);
vie_remb_->RemoveSendChannel(&rtp_0);
vie_remb_->RemoveRembSender(&rtp_0);
}
TEST_F(ViERembTest, ChangeSendRtpModule)
@ -180,6 +217,7 @@ TEST_F(ViERembTest, ChangeSendRtpModule)
MockRtpRtcp rtp_1;
vie_remb_->AddReceiveChannel(&rtp_0);
vie_remb_->AddSendChannel(&rtp_0);
vie_remb_->AddRembSender(&rtp_0);
vie_remb_->AddReceiveChannel(&rtp_1);
unsigned int bitrate_estimate[] = { 456, 789 };
@ -206,7 +244,9 @@ TEST_F(ViERembTest, ChangeSendRtpModule)
// Remove the sending module, add it again -> should get remb on the second
// module.
vie_remb_->RemoveSendChannel(&rtp_0);
vie_remb_->RemoveRembSender(&rtp_0);
vie_remb_->AddSendChannel(&rtp_1);
vie_remb_->AddRembSender(&rtp_1);
vie_remb_->OnReceiveBitrateChanged(ssrc[0], bitrate_estimate[0]);
bitrate_estimate[1] = bitrate_estimate[1] - 100;
@ -229,6 +269,7 @@ TEST_F(ViERembTest, OnlyOneRembForDoubleProcess)
vie_remb_->AddReceiveChannel(&rtp);
vie_remb_->AddSendChannel(&rtp);
vie_remb_->AddRembSender(&rtp);
vie_remb_->OnReceiveBitrateChanged(ssrc[0], bitrate_estimate);
EXPECT_CALL(rtp, RemoteSSRC())
.WillRepeatedly(Return(ssrc[0]));
@ -246,6 +287,7 @@ TEST_F(ViERembTest, OnlyOneRembForDoubleProcess)
vie_remb_->Process();
vie_remb_->RemoveReceiveChannel(&rtp);
vie_remb_->RemoveSendChannel(&rtp);
vie_remb_->RemoveRembSender(&rtp);
}
TEST_F(ViERembTest, NoOnReceivedBitrateChangedCall)
@ -256,6 +298,7 @@ TEST_F(ViERembTest, NoOnReceivedBitrateChangedCall)
vie_remb_->AddReceiveChannel(&rtp);
vie_remb_->AddSendChannel(&rtp);
vie_remb_->AddRembSender(&rtp);
// TODO(mflodman) Add fake clock.
TestSleep(1010);
// No bitrate estimate given, no callback expected.
@ -265,6 +308,7 @@ TEST_F(ViERembTest, NoOnReceivedBitrateChangedCall)
vie_remb_->RemoveReceiveChannel(&rtp);
vie_remb_->RemoveSendChannel(&rtp);
vie_remb_->RemoveRembSender(&rtp);
}
TEST_F(ViERembTest, NoSendingRtpModule)