Callback for send bitrate estimates
BUG=2235
R=mflodman@webrtc.org, pbos@webrtc.org, stefan@webrtc.org
Review URL: https://webrtc-codereview.appspot.com/4459004
git-svn-id: http://webrtc.googlecode.com/svn/trunk@5259 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/webrtc/common_types.h b/webrtc/common_types.h
index 55ba552..49f3a76 100644
--- a/webrtc/common_types.h
+++ b/webrtc/common_types.h
@@ -285,14 +285,11 @@
// Rate statistics for a stream
struct BitrateStatistics {
- BitrateStatistics()
- : bitrate_(0),
- packet_rate(0),
- now(0) {}
+ BitrateStatistics() : bitrate_bps(0), packet_rate(0), timestamp_ms(0) {}
- uint32_t bitrate_;
- uint32_t packet_rate;
- uint64_t now;
+ uint32_t bitrate_bps; // Bitrate in bits per second.
+ uint32_t packet_rate; // Packet rate in packets per second.
+ uint64_t timestamp_ms; // Ntp timestamp in ms at time of rate estimation.
};
// Callback, used to notify an observer whenever new rates have been estimated.
diff --git a/webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h b/webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h
index 19bc470..67dad0d 100644
--- a/webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h
+++ b/webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h
@@ -301,6 +301,13 @@
uint32_t* nackRate) const = 0;
/*
+ * Called on any new send bitrate estimate.
+ */
+ virtual void RegisterVideoBitrateObserver(
+ BitrateStatisticsObserver* observer) = 0;
+ virtual BitrateStatisticsObserver* GetVideoBitrateObserver() const = 0;
+
+ /*
* Used by the codec module to deliver a video or audio frame for
* packetization.
*
diff --git a/webrtc/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h b/webrtc/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h
index 8edb548..42c7b4e 100644
--- a/webrtc/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h
+++ b/webrtc/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h
@@ -100,6 +100,8 @@
bool());
MOCK_CONST_METHOD4(BitrateSent,
void(uint32_t* totalRate, uint32_t* videoRate, uint32_t* fecRate, uint32_t* nackRate));
+ MOCK_METHOD1(RegisterVideoBitrateObserver, void(BitrateStatisticsObserver*));
+ MOCK_CONST_METHOD0(GetVideoBitrateObserver, BitrateStatisticsObserver*(void));
MOCK_CONST_METHOD1(EstimatedReceiveBandwidth,
int(uint32_t* available_bandwidth));
MOCK_METHOD8(SendOutgoingData,
diff --git a/webrtc/modules/rtp_rtcp/source/bitrate.cc b/webrtc/modules/rtp_rtcp/source/bitrate.cc
index d8145d1..42e331b 100644
--- a/webrtc/modules/rtp_rtcp/source/bitrate.cc
+++ b/webrtc/modules/rtp_rtcp/source/bitrate.cc
@@ -15,7 +15,7 @@
namespace webrtc {
-Bitrate::Bitrate(Clock* clock)
+Bitrate::Bitrate(Clock* clock, Observer* observer)
: clock_(clock),
crit_(CriticalSectionWrapper::CreateCriticalSection()),
packet_rate_(0),
@@ -23,12 +23,15 @@
bitrate_next_idx_(0),
time_last_rate_update_(0),
bytes_count_(0),
- packet_count_(0) {
+ packet_count_(0),
+ observer_(observer) {
memset(packet_rate_array_, 0, sizeof(packet_rate_array_));
memset(bitrate_diff_ms_, 0, sizeof(bitrate_diff_ms_));
memset(bitrate_array_, 0, sizeof(bitrate_array_));
}
+Bitrate::~Bitrate() {}
+
void Bitrate::Update(const int32_t bytes) {
CriticalSectionScoped cs(crit_.get());
bytes_count_ += bytes;
@@ -71,7 +74,7 @@
void Bitrate::Process() {
// Triggered by timer.
CriticalSectionScoped cs(crit_.get());
- int64_t now = clock_->TimeInMilliseconds();
+ int64_t now = clock_->CurrentNtpInMilliseconds();
int64_t diff_ms = now - time_last_rate_update_;
if (diff_ms < 100) {
@@ -105,6 +108,14 @@
packet_count_ = 0;
packet_rate_ = static_cast<uint32_t>(sum_packetrateMS / sum_diffMS);
bitrate_ = static_cast<uint32_t>(sum_bitrateMS / sum_diffMS);
+
+ if (observer_) {
+ BitrateStatistics stats;
+ stats.bitrate_bps = bitrate_;
+ stats.packet_rate = packet_rate_;
+ stats.timestamp_ms = now;
+ observer_->BitrateUpdated(stats);
+ }
}
} // namespace webrtc
diff --git a/webrtc/modules/rtp_rtcp/source/bitrate.h b/webrtc/modules/rtp_rtcp/source/bitrate.h
index 17a099a..36fa1d3 100644
--- a/webrtc/modules/rtp_rtcp/source/bitrate.h
+++ b/webrtc/modules/rtp_rtcp/source/bitrate.h
@@ -27,7 +27,9 @@
class Bitrate {
public:
- explicit Bitrate(Clock* clock);
+ class Observer;
+ Bitrate(Clock* clock, Observer* observer);
+ virtual ~Bitrate();
// Calculates rates.
void Process();
@@ -46,6 +48,14 @@
int64_t time_last_rate_update() const;
+ class Observer {
+ public:
+ Observer() {}
+ virtual ~Observer() {}
+
+ virtual void BitrateUpdated(const BitrateStatistics& stats) = 0;
+ };
+
protected:
Clock* clock_;
@@ -60,6 +70,7 @@
int64_t time_last_rate_update_;
uint32_t bytes_count_;
uint32_t packet_count_;
+ Observer* const observer_;
};
} // namespace webrtc
diff --git a/webrtc/modules/rtp_rtcp/source/receive_statistics_impl.cc b/webrtc/modules/rtp_rtcp/source/receive_statistics_impl.cc
index cf18990..3ed44b8 100644
--- a/webrtc/modules/rtp_rtcp/source/receive_statistics_impl.cc
+++ b/webrtc/modules/rtp_rtcp/source/receive_statistics_impl.cc
@@ -27,7 +27,7 @@
StreamStatisticianImpl::StreamStatisticianImpl(Clock* clock)
: clock_(clock),
crit_sect_(CriticalSectionWrapper::CreateCriticalSection()),
- incoming_bitrate_(clock),
+ incoming_bitrate_(clock, NULL),
ssrc_(0),
max_reordering_threshold_(kDefaultMaxReorderingThreshold),
jitter_q4_(0),
diff --git a/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc b/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc
index acc2c26..e9deb3d 100644
--- a/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc
+++ b/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc
@@ -1559,7 +1559,7 @@
return;
}
if (total_rate != NULL)
- *total_rate = rtp_sender_.BitrateLast();
+ *total_rate = rtp_sender_.BitrateSent();
if (video_rate != NULL)
*video_rate = rtp_sender_.VideoBitrateSent();
if (fec_rate != NULL)
@@ -1568,6 +1568,31 @@
*nack_rate = rtp_sender_.NackOverheadRate();
}
+void ModuleRtpRtcpImpl::RegisterVideoBitrateObserver(
+ BitrateStatisticsObserver* observer) {
+ {
+ CriticalSectionScoped cs(critical_section_module_ptrs_.get());
+ if (!child_modules_.empty()) {
+ for (std::list<ModuleRtpRtcpImpl*>::const_iterator it =
+ child_modules_.begin();
+ it != child_modules_.end();
+ ++it) {
+ RtpRtcp* module = *it;
+ if (module)
+ module->RegisterVideoBitrateObserver(observer);
+ ++it;
+ }
+ return;
+ }
+ }
+
+ rtp_sender_.RegisterBitrateObserver(observer);
+}
+
+BitrateStatisticsObserver* ModuleRtpRtcpImpl::GetVideoBitrateObserver() const {
+ return rtp_sender_.GetBitrateObserver();
+}
+
// Bad state of RTP receiver request a keyframe.
void ModuleRtpRtcpImpl::OnRequestIntraFrame() {
RequestKeyFrame();
diff --git a/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h b/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h
index 7e0425f..075770d 100644
--- a/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h
+++ b/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h
@@ -349,6 +349,11 @@
uint32_t* fec_rate,
uint32_t* nackRate) const OVERRIDE;
+ virtual void RegisterVideoBitrateObserver(BitrateStatisticsObserver* observer)
+ OVERRIDE;
+
+ virtual BitrateStatisticsObserver* GetVideoBitrateObserver() const OVERRIDE;
+
virtual uint32_t SendTimeOfSendReport(const uint32_t send_report);
virtual bool SendTimeOfXrRrReport(uint32_t mid_ntp, int64_t* time_ms) const;
diff --git a/webrtc/modules/rtp_rtcp/source/rtp_sender.cc b/webrtc/modules/rtp_rtcp/source/rtp_sender.cc
index 20ebd44..fd32032 100644
--- a/webrtc/modules/rtp_rtcp/source/rtp_sender.cc
+++ b/webrtc/modules/rtp_rtcp/source/rtp_sender.cc
@@ -39,30 +39,56 @@
} // namespace
-RTPSender::RTPSender(const int32_t id, const bool audio, Clock *clock,
- Transport *transport, RtpAudioFeedback *audio_feedback,
- PacedSender *paced_sender)
- : Bitrate(clock), id_(id), audio_configured_(audio), audio_(NULL),
- video_(NULL), paced_sender_(paced_sender),
+RTPSender::RTPSender(const int32_t id,
+ const bool audio,
+ Clock* clock,
+ Transport* transport,
+ RtpAudioFeedback* audio_feedback,
+ PacedSender* paced_sender)
+ : clock_(clock),
+ bitrate_sent_(clock, this),
+ id_(id),
+ audio_configured_(audio),
+ audio_(NULL),
+ video_(NULL),
+ paced_sender_(paced_sender),
send_critsect_(CriticalSectionWrapper::CreateCriticalSection()),
- transport_(transport), sending_media_(true), // Default to sending media.
- max_payload_length_(IP_PACKET_SIZE - 28), // Default is IP-v4/UDP.
- target_send_bitrate_(0), packet_over_head_(28), payload_type_(-1),
- payload_type_map_(), rtp_header_extension_map_(),
- transmission_time_offset_(0), absolute_send_time_(0),
+ transport_(transport),
+ sending_media_(true), // Default to sending media.
+ max_payload_length_(IP_PACKET_SIZE - 28), // Default is IP-v4/UDP.
+ target_send_bitrate_(0),
+ packet_over_head_(28),
+ payload_type_(-1),
+ payload_type_map_(),
+ rtp_header_extension_map_(),
+ transmission_time_offset_(0),
+ absolute_send_time_(0),
// NACK.
- nack_byte_count_times_(), nack_byte_count_(), nack_bitrate_(clock),
+ nack_byte_count_times_(),
+ nack_byte_count_(),
+ nack_bitrate_(clock, NULL),
packet_history_(clock),
// Statistics
statistics_crit_(CriticalSectionWrapper::CreateCriticalSection()),
- frame_count_observer_(NULL), rtp_stats_callback_(NULL),
+ frame_count_observer_(NULL),
+ rtp_stats_callback_(NULL),
+ bitrate_callback_(NULL),
// RTP variables
start_time_stamp_forced_(false),
- start_time_stamp_(0), ssrc_db_(*SSRCDatabase::GetSSRCDatabase()),
- remote_ssrc_(0), sequence_number_forced_(false), ssrc_forced_(false),
- timestamp_(0), capture_time_ms_(0), last_timestamp_time_ms_(0),
- last_packet_marker_bit_(false), num_csrcs_(0), csrcs_(),
- include_csrcs_(true), rtx_(kRtxOff), payload_type_rtx_(-1) {
+ start_time_stamp_(0),
+ ssrc_db_(*SSRCDatabase::GetSSRCDatabase()),
+ remote_ssrc_(0),
+ sequence_number_forced_(false),
+ ssrc_forced_(false),
+ timestamp_(0),
+ capture_time_ms_(0),
+ last_timestamp_time_ms_(0),
+ last_packet_marker_bit_(false),
+ num_csrcs_(0),
+ csrcs_(),
+ include_csrcs_(true),
+ rtx_(kRtxOff),
+ payload_type_rtx_(-1) {
memset(nack_byte_count_times_, 0, sizeof(nack_byte_count_times_));
memset(nack_byte_count_, 0, sizeof(nack_byte_count_));
memset(csrcs_, 0, sizeof(csrcs_));
@@ -108,7 +134,7 @@
}
uint16_t RTPSender::ActualSendBitrateKbit() const {
- return (uint16_t)(Bitrate::BitrateNow() / 1000);
+ return (uint16_t)(bitrate_sent_.BitrateNow() / 1000);
}
uint32_t RTPSender::VideoBitrateSent() const {
@@ -445,7 +471,7 @@
int64_t capture_time_ms) {
// Current bitrate since last estimate(1 second) averaged with the
// estimate since then, to get the most up to date bitrate.
- uint32_t current_bitrate = BitrateNow();
+ uint32_t current_bitrate = bitrate_sent_.BitrateNow();
int bitrate_diff = target_send_bitrate_ * 1000 - current_bitrate;
if (bitrate_diff <= 0) {
return true;
@@ -827,7 +853,7 @@
ssrc = ssrc_;
}
- Bitrate::Update(size);
+ bitrate_sent_.Update(size);
++counters->packets;
if (IsFecPacket(buffer, header)) {
++counters->fec_packets;
@@ -948,7 +974,7 @@
void RTPSender::ProcessBitrate() {
CriticalSectionScoped cs(send_critsect_);
- Bitrate::Process();
+ bitrate_sent_.Process();
nack_bitrate_.Process();
if (audio_configured_) {
return;
@@ -1588,4 +1614,24 @@
return rtp_stats_callback_;
}
+void RTPSender::RegisterBitrateObserver(BitrateStatisticsObserver* observer) {
+ CriticalSectionScoped cs(statistics_crit_.get());
+ if (observer != NULL)
+ assert(bitrate_callback_ == NULL);
+ bitrate_callback_ = observer;
+}
+
+BitrateStatisticsObserver* RTPSender::GetBitrateObserver() const {
+ CriticalSectionScoped cs(statistics_crit_.get());
+ return bitrate_callback_;
+}
+
+uint32_t RTPSender::BitrateSent() const { return bitrate_sent_.BitrateLast(); }
+
+void RTPSender::BitrateUpdated(const BitrateStatistics& stats) {
+ CriticalSectionScoped cs(statistics_crit_.get());
+ if (bitrate_callback_) {
+ bitrate_callback_->Notify(stats, ssrc_);
+ }
+}
} // namespace webrtc
diff --git a/webrtc/modules/rtp_rtcp/source/rtp_sender.h b/webrtc/modules/rtp_rtcp/source/rtp_sender.h
index d0aeb64..e1cc3a18 100644
--- a/webrtc/modules/rtp_rtcp/source/rtp_sender.h
+++ b/webrtc/modules/rtp_rtcp/source/rtp_sender.h
@@ -63,7 +63,7 @@
PacedSender::Priority priority) = 0;
};
-class RTPSender : public Bitrate, public RTPSenderInterface {
+class RTPSender : public RTPSenderInterface, public Bitrate::Observer {
public:
RTPSender(const int32_t id, const bool audio, Clock *clock,
Transport *transport, RtpAudioFeedback *audio_feedback,
@@ -275,6 +275,14 @@
void RegisterRtpStatisticsCallback(StreamDataCountersCallback* callback);
StreamDataCountersCallback* GetRtpStatisticsCallback() const;
+ // Called on new send bitrate estimate.
+ void RegisterBitrateObserver(BitrateStatisticsObserver* observer);
+ BitrateStatisticsObserver* GetBitrateObserver() const;
+
+ uint32_t BitrateSent() const;
+
+ virtual void BitrateUpdated(const BitrateStatistics& stats) OVERRIDE;
+
protected:
int32_t CheckPayloadType(const int8_t payload_type,
RtpVideoCodecTypes *video_type);
@@ -318,6 +326,9 @@
bool is_retransmit);
bool IsFecPacket(const uint8_t* buffer, const RTPHeader& header) const;
+ Clock* clock_;
+ Bitrate bitrate_sent_;
+
int32_t id_;
const bool audio_configured_;
RTPSenderAudio *audio_;
@@ -355,6 +366,7 @@
StreamDataCounters rtp_stats_;
StreamDataCounters rtx_rtp_stats_;
StreamDataCountersCallback* rtp_stats_callback_;
+ BitrateStatisticsObserver* bitrate_callback_;
// RTP variables
bool start_time_stamp_forced_;
diff --git a/webrtc/modules/rtp_rtcp/source/rtp_sender_unittest.cc b/webrtc/modules/rtp_rtcp/source/rtp_sender_unittest.cc
index 863d868..ce615be 100644
--- a/webrtc/modules/rtp_rtcp/source/rtp_sender_unittest.cc
+++ b/webrtc/modules/rtp_rtcp/source/rtp_sender_unittest.cc
@@ -38,6 +38,7 @@
const uint8_t kAudioLevel = 0x5a;
const uint8_t kAudioLevelExtensionId = 9;
const int kAudioPayload = 103;
+const uint64_t kStartTime = 123456789;
} // namespace
using testing::_;
@@ -81,12 +82,12 @@
class RtpSenderTest : public ::testing::Test {
protected:
RtpSenderTest()
- : fake_clock_(123456789),
- mock_paced_sender_(),
- rtp_sender_(),
- payload_(kPayload),
- transport_(),
- kMarkerBit(true) {
+ : fake_clock_(kStartTime),
+ mock_paced_sender_(),
+ rtp_sender_(),
+ payload_(kPayload),
+ transport_(),
+ kMarkerBit(true) {
EXPECT_CALL(mock_paced_sender_,
SendPacket(_, _, _, _, _, _)).WillRepeatedly(testing::Return(true));
}
@@ -779,6 +780,73 @@
rtp_sender_->RegisterFrameCountObserver(NULL);
}
+TEST_F(RtpSenderTest, BitrateCallbacks) {
+ class TestCallback : public BitrateStatisticsObserver {
+ public:
+ TestCallback()
+ : BitrateStatisticsObserver(), num_calls_(0), ssrc_(0), bitrate_() {}
+ virtual ~TestCallback() {}
+
+ virtual void Notify(const BitrateStatistics& stats, uint32_t ssrc) {
+ ++num_calls_;
+ ssrc_ = ssrc;
+ bitrate_ = stats;
+ }
+
+ uint32_t num_calls_;
+ uint32_t ssrc_;
+ BitrateStatistics bitrate_;
+ } callback;
+
+ // Simulate kNumPackets sent with kPacketInterval ms intervals.
+ const uint32_t kNumPackets = 15;
+ const uint32_t kPacketInterval = 20;
+ // Overhead = 12 bytes RTP header + 1 byte generic header.
+ const uint32_t kPacketOverhead = 13;
+
+ char payload_name[RTP_PAYLOAD_NAME_SIZE] = "GENERIC";
+ const uint8_t payload_type = 127;
+ ASSERT_EQ(
+ 0,
+ rtp_sender_->RegisterPayload(payload_name, payload_type, 90000, 0, 1500));
+ uint8_t payload[] = {47, 11, 32, 93, 89};
+ rtp_sender_->SetStorePacketsStatus(true, 1);
+ uint32_t ssrc = rtp_sender_->SSRC();
+
+ rtp_sender_->RegisterBitrateObserver(&callback);
+
+ // Initial process call so we get a new time window.
+ rtp_sender_->ProcessBitrate();
+ uint64_t start_time = fake_clock_.CurrentNtpInMilliseconds();
+
+ // Send a few frames.
+ for (uint32_t i = 0; i < kNumPackets; ++i) {
+ ASSERT_EQ(0,
+ rtp_sender_->SendOutgoingData(kVideoFrameKey,
+ payload_type,
+ 1234,
+ 4321,
+ payload,
+ sizeof(payload),
+ 0));
+ fake_clock_.AdvanceTimeMilliseconds(kPacketInterval);
+ }
+
+ rtp_sender_->ProcessBitrate();
+
+ const uint32_t expected_packet_rate = 1000 / kPacketInterval;
+
+ EXPECT_EQ(1U, callback.num_calls_);
+ EXPECT_EQ(ssrc, callback.ssrc_);
+ EXPECT_EQ(start_time + (kNumPackets * kPacketInterval),
+ callback.bitrate_.timestamp_ms);
+ EXPECT_EQ(expected_packet_rate, callback.bitrate_.packet_rate);
+ EXPECT_EQ((kPacketOverhead + sizeof(payload)) * 8 * expected_packet_rate,
+ callback.bitrate_.bitrate_bps);
+
+ rtp_sender_->RegisterBitrateObserver(NULL);
+}
+
class RtpSenderAudioTest : public RtpSenderTest {
protected:
RtpSenderAudioTest() {}
diff --git a/webrtc/modules/rtp_rtcp/source/rtp_sender_video.cc b/webrtc/modules/rtp_rtcp/source/rtp_sender_video.cc
index 4d0da73..7b36f7c 100644
--- a/webrtc/modules/rtp_rtcp/source/rtp_sender_video.cc
+++ b/webrtc/modules/rtp_rtcp/source/rtp_sender_video.cc
@@ -32,27 +32,26 @@
RTPSenderVideo::RTPSenderVideo(const int32_t id,
Clock* clock,
- RTPSenderInterface* rtpSender) :
- _id(id),
- _rtpSender(*rtpSender),
- _sendVideoCritsect(CriticalSectionWrapper::CreateCriticalSection()),
+ RTPSenderInterface* rtpSender)
+ : _id(id),
+ _rtpSender(*rtpSender),
+ _sendVideoCritsect(CriticalSectionWrapper::CreateCriticalSection()),
+ _videoType(kRtpVideoGeneric),
+ _videoCodecInformation(NULL),
+ _maxBitrate(0),
+ _retransmissionSettings(kRetransmitBaseLayer),
- _videoType(kRtpVideoGeneric),
- _videoCodecInformation(NULL),
- _maxBitrate(0),
- _retransmissionSettings(kRetransmitBaseLayer),
-
- // Generic FEC
- _fec(id),
- _fecEnabled(false),
- _payloadTypeRED(-1),
- _payloadTypeFEC(-1),
- _numberFirstPartition(0),
- delta_fec_params_(),
- key_fec_params_(),
- producer_fec_(&_fec),
- _fecOverheadRate(clock),
- _videoBitrate(clock) {
+ // Generic FEC
+ _fec(id),
+ _fecEnabled(false),
+ _payloadTypeRED(-1),
+ _payloadTypeFEC(-1),
+ _numberFirstPartition(0),
+ delta_fec_params_(),
+ key_fec_params_(),
+ producer_fec_(&_fec),
+ _fecOverheadRate(clock, NULL),
+ _videoBitrate(clock, NULL) {
memset(&delta_fec_params_, 0, sizeof(delta_fec_params_));
memset(&key_fec_params_, 0, sizeof(key_fec_params_));
delta_fec_params_.max_fec_frames = key_fec_params_.max_fec_frames = 1;
diff --git a/webrtc/video_engine/vie_channel.cc b/webrtc/video_engine/vie_channel.cc
index b6d9be1..9d93b3e 100644
--- a/webrtc/video_engine/vie_channel.cc
+++ b/webrtc/video_engine/vie_channel.cc
@@ -359,6 +359,7 @@
rtp_rtcp->RegisterSendFrameCountObserver(NULL);
rtp_rtcp->RegisterSendChannelRtcpStatisticsCallback(NULL);
rtp_rtcp->RegisterSendChannelRtpStatisticsCallback(NULL);
+ rtp_rtcp->RegisterVideoBitrateObserver(NULL);
simulcast_rtp_rtcp_.pop_back();
removed_rtp_rtcp_.push_front(rtp_rtcp);
}
@@ -419,6 +420,8 @@
rtp_rtcp_->GetSendChannelRtcpStatisticsCallback());
rtp_rtcp->RegisterSendChannelRtpStatisticsCallback(
rtp_rtcp_->GetSendChannelRtpStatisticsCallback());
+ rtp_rtcp->RegisterVideoBitrateObserver(
+ rtp_rtcp_->GetVideoBitrateObserver());
}
// |RegisterSimulcastRtpRtcpModules| resets all old weak pointers and old
// modules can be deleted after this step.
@@ -432,6 +435,7 @@
rtp_rtcp->RegisterSendFrameCountObserver(NULL);
rtp_rtcp->RegisterSendChannelRtcpStatisticsCallback(NULL);
rtp_rtcp->RegisterSendChannelRtpStatisticsCallback(NULL);
+ rtp_rtcp->RegisterVideoBitrateObserver(NULL);
simulcast_rtp_rtcp_.pop_back();
removed_rtp_rtcp_.push_front(rtp_rtcp);
}
@@ -1427,6 +1431,17 @@
return valid_estimate;
}
+void ViEChannel::RegisterSendBitrateObserver(
+ BitrateStatisticsObserver* observer) {
+ rtp_rtcp_->RegisterVideoBitrateObserver(observer);
+ CriticalSectionScoped cs(rtp_rtcp_cs_.get());
+ for (std::list<RtpRtcp*>::const_iterator it = simulcast_rtp_rtcp_.begin();
+ it != simulcast_rtp_rtcp_.end();
+ it++) {
+ (*it)->RegisterVideoBitrateObserver(observer);
+ }
+}
+
void ViEChannel::GetEstimatedReceiveBandwidth(
uint32_t* estimated_bandwidth) const {
vie_receiver_.EstimatedReceiveBandwidth(estimated_bandwidth);
diff --git a/webrtc/video_engine/vie_channel.h b/webrtc/video_engine/vie_channel.h
index 0ee677e..a4b3dd0 100644
--- a/webrtc/video_engine/vie_channel.h
+++ b/webrtc/video_engine/vie_channel.h
@@ -202,6 +202,9 @@
bool GetSendSideDelay(int* avg_send_delay, int* max_send_delay) const;
void GetEstimatedReceiveBandwidth(uint32_t* estimated_bandwidth) const;
+ // Called on any new send bitrate estimate.
+ void RegisterSendBitrateObserver(BitrateStatisticsObserver* observer);
+
int32_t StartRTPDump(const char file_nameUTF8[1024],
RTPDirections direction);
int32_t StopRTPDump(RTPDirections direction);
diff --git a/webrtc/video_engine/vie_rtp_rtcp_impl.cc b/webrtc/video_engine/vie_rtp_rtcp_impl.cc
index ce2f434..e07ab6c 100644
--- a/webrtc/video_engine/vie_rtp_rtcp_impl.cc
+++ b/webrtc/video_engine/vie_rtp_rtcp_impl.cc
@@ -1206,16 +1206,38 @@
// TODO(sprang): Implement
return -1;
}
+
+// Called whenever the send bitrate is updated.
int ViERTP_RTCPImpl::RegisterSendBitrateObserver(
- int channel, BitrateStatisticsObserver* callback) {
- // TODO(sprang): Implement
- return -1;
+ const int video_channel,
+ BitrateStatisticsObserver* observer) {
+ WEBRTC_TRACE(kTraceApiCall,
+ kTraceVideo,
+ ViEId(shared_data_->instance_id(), video_channel),
+ "%s(channel: %d)",
+ __FUNCTION__,
+ video_channel);
+ ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
+ ViEChannel* vie_channel = cs.Channel(video_channel);
+ assert(vie_channel != NULL);
+ vie_channel->RegisterSendBitrateObserver(observer);
+ return 0;
}
int ViERTP_RTCPImpl::DeregisterSendBitrateObserver(
- int channel, BitrateStatisticsObserver* callback) {
- // TODO(sprang): Implement
- return -1;
+ const int video_channel,
+ BitrateStatisticsObserver* observer) {
+ WEBRTC_TRACE(kTraceApiCall,
+ kTraceVideo,
+ ViEId(shared_data_->instance_id(), video_channel),
+ "%s(channel: %d)",
+ __FUNCTION__,
+ video_channel);
+ ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
+ ViEChannel* vie_channel = cs.Channel(video_channel);
+ assert(vie_channel != NULL);
+ vie_channel->RegisterSendBitrateObserver(NULL);
+ return 0;
}
int ViERTP_RTCPImpl::RegisterSendFrameCountObserver(