diff --git a/webrtc/common_types.h b/webrtc/common_types.h index 55ba5525fc..49f3a76d83 100644 --- a/webrtc/common_types.h +++ b/webrtc/common_types.h @@ -285,14 +285,11 @@ class StreamDataCountersCallback { // 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 19bc470ee3..67dad0d977 100644 --- a/webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h +++ b/webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h @@ -300,6 +300,13 @@ class RtpRtcp : public Module { uint32_t* fecRate, 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 8edb548a3a..42c7b4eab9 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 @@ class MockRtpRtcp : public RtpRtcp { 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 d8145d16d7..42e331bef7 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::Bitrate(Clock* clock) 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 @@ int64_t Bitrate::time_last_rate_update() const { 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 @@ void Bitrate::Process() { packet_count_ = 0; packet_rate_ = static_cast(sum_packetrateMS / sum_diffMS); bitrate_ = static_cast(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 17a099a86a..36fa1d3717 100644 --- a/webrtc/modules/rtp_rtcp/source/bitrate.h +++ b/webrtc/modules/rtp_rtcp/source/bitrate.h @@ -27,7 +27,9 @@ class CriticalSectionWrapper; class Bitrate { public: - explicit Bitrate(Clock* clock); + class Observer; + Bitrate(Clock* clock, Observer* observer); + virtual ~Bitrate(); // Calculates rates. void Process(); @@ -46,6 +48,14 @@ class Bitrate { 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 @@ class Bitrate { 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 cf189903d1..3ed44b8370 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 @@ StreamStatistician::~StreamStatistician() {} 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 acc2c266e3..e9deb3d1f1 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 @@ void ModuleRtpRtcpImpl::BitrateSent(uint32_t* total_rate, 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 @@ void ModuleRtpRtcpImpl::BitrateSent(uint32_t* total_rate, *nack_rate = rtp_sender_.NackOverheadRate(); } +void ModuleRtpRtcpImpl::RegisterVideoBitrateObserver( + BitrateStatisticsObserver* observer) { + { + CriticalSectionScoped cs(critical_section_module_ptrs_.get()); + if (!child_modules_.empty()) { + for (std::list::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 7e0425f3b2..075770dd23 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 @@ class ModuleRtpRtcpImpl : public RtpRtcp { 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 20ebd4451c..fd320324b8 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_sender.cc +++ b/webrtc/modules/rtp_rtcp/source/rtp_sender.cc @@ -39,30 +39,56 @@ const char* FrameTypeToString(const FrameType frame_type) { } // 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 @@ void RTPSender::SetTargetSendBitrate(const uint32_t bits) { } 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 @@ bool RTPSender::SendPaddingAccordingToBitrate( 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 @@ void RTPSender::UpdateRtpStats(const uint8_t* buffer, ssrc = ssrc_; } - Bitrate::Update(size); + bitrate_sent_.Update(size); ++counters->packets; if (IsFecPacket(buffer, header)) { ++counters->fec_packets; @@ -948,7 +974,7 @@ void RTPSender::UpdateDelayStatistics(int64_t capture_time_ms, int64_t now_ms) { void RTPSender::ProcessBitrate() { CriticalSectionScoped cs(send_critsect_); - Bitrate::Process(); + bitrate_sent_.Process(); nack_bitrate_.Process(); if (audio_configured_) { return; @@ -1588,4 +1614,24 @@ StreamDataCountersCallback* RTPSender::GetRtpStatisticsCallback() const { 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 d0aeb64cf4..e1cc3a182a 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_sender.h +++ b/webrtc/modules/rtp_rtcp/source/rtp_sender.h @@ -63,7 +63,7 @@ class RTPSenderInterface { 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 @@ class RTPSender : public Bitrate, public RTPSenderInterface { 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 @@ class RTPSender : public Bitrate, public RTPSenderInterface { 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 @@ class RTPSender : public Bitrate, public RTPSenderInterface { 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 863d868fc3..ce615be049 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 uint32_t kAbsoluteSendTime = 0x00aabbcc; 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 LoopbackTransportTest : public webrtc::Transport { 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 @@ TEST_F(RtpSenderTest, FrameCountCallbacks) { 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 4d0da736c0..7b36f7cced 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 @@ struct RtpPacket { 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 b6d9be1dd8..9d93b3e58f 100644 --- a/webrtc/video_engine/vie_channel.cc +++ b/webrtc/video_engine/vie_channel.cc @@ -359,6 +359,7 @@ int32_t ViEChannel::SetSendCodec(const VideoCodec& video_codec, 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 @@ int32_t ViEChannel::SetSendCodec(const VideoCodec& video_codec, 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 @@ int32_t ViEChannel::SetSendCodec(const VideoCodec& video_codec, 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 @@ bool ViEChannel::GetSendSideDelay(int* avg_send_delay, return valid_estimate; } +void ViEChannel::RegisterSendBitrateObserver( + BitrateStatisticsObserver* observer) { + rtp_rtcp_->RegisterVideoBitrateObserver(observer); + CriticalSectionScoped cs(rtp_rtcp_cs_.get()); + for (std::list::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 0ee677eb56..a4b3dd0579 100644 --- a/webrtc/video_engine/vie_channel.h +++ b/webrtc/video_engine/vie_channel.h @@ -202,6 +202,9 @@ class ViEChannel 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 ce2f434438..e07ab6c1f8 100644 --- a/webrtc/video_engine/vie_rtp_rtcp_impl.cc +++ b/webrtc/video_engine/vie_rtp_rtcp_impl.cc @@ -1206,16 +1206,38 @@ int ViERTP_RTCPImpl::DeregisterReceiveChannelRtpStatisticsCallback( // 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(