Wire up bandwidth stats to the new API and webrtcvideoengine2.

Adds stats to verify bandwidth and pacer stats.

BUG=1788
R=mflodman@webrtc.org, pbos@webrtc.org

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

git-svn-id: http://webrtc.googlecode.com/svn/trunk@7634 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
stefan@webrtc.org 2014-11-05 14:05:29 +00:00
parent a22a628356
commit 0bae1fab4a
26 changed files with 315 additions and 129 deletions

View File

@ -1202,7 +1202,21 @@ void WebRtcVideoChannel2::FillReceiverStats(VideoMediaInfo* video_media_info) {
void WebRtcVideoChannel2::FillBandwidthEstimationStats(
VideoMediaInfo* video_media_info) {
// TODO(pbos): Implement.
BandwidthEstimationInfo bwe_info;
webrtc::Call::Stats stats = call_->GetStats();
bwe_info.available_send_bandwidth = stats.send_bandwidth_bps;
bwe_info.available_recv_bandwidth = stats.recv_bandwidth_bps;
bwe_info.bucket_delay = stats.pacer_delay_ms;
// Get send stream bitrate stats.
rtc::CritScope stream_lock(&stream_crit_);
for (std::map<uint32, WebRtcVideoSendStream*>::iterator stream =
send_streams_.begin();
stream != send_streams_.end();
++stream) {
stream->second->FillBandwidthEstimationInfo(&bwe_info);
}
video_media_info->bw_estimations.push_back(bwe_info);
}
bool WebRtcVideoChannel2::SetCapturer(uint32 ssrc, VideoCapturer* capturer) {
@ -1842,12 +1856,12 @@ WebRtcVideoChannel2::WebRtcVideoSendStream::GetVideoSenderInfo() {
info.framerate_input = stats.input_frame_rate;
info.framerate_sent = stats.encode_frame_rate;
for (std::map<uint32_t, webrtc::StreamStats>::iterator it =
for (std::map<uint32_t, webrtc::SsrcStats>::iterator it =
stats.substreams.begin();
it != stats.substreams.end();
++it) {
// TODO(pbos): Wire up additional stats, such as padding bytes.
webrtc::StreamStats stream_stats = it->second;
webrtc::SsrcStats stream_stats = it->second;
info.bytes_sent += stream_stats.rtp_stats.bytes +
stream_stats.rtp_stats.header_bytes +
stream_stats.rtp_stats.padding_bytes;
@ -1857,7 +1871,7 @@ WebRtcVideoChannel2::WebRtcVideoSendStream::GetVideoSenderInfo() {
if (!stats.substreams.empty()) {
// TODO(pbos): Report fraction lost per SSRC.
webrtc::StreamStats first_stream_stats = stats.substreams.begin()->second;
webrtc::SsrcStats first_stream_stats = stats.substreams.begin()->second;
info.fraction_lost =
static_cast<float>(first_stream_stats.rtcp_stats.fraction_lost) /
(1 << 8);
@ -1884,6 +1898,23 @@ WebRtcVideoChannel2::WebRtcVideoSendStream::GetVideoSenderInfo() {
return info;
}
void WebRtcVideoChannel2::WebRtcVideoSendStream::FillBandwidthEstimationInfo(
BandwidthEstimationInfo* bwe_info) {
rtc::CritScope cs(&lock_);
if (stream_ == NULL) {
return;
}
webrtc::VideoSendStream::Stats stats = stream_->GetStats();
for (std::map<uint32_t, webrtc::SsrcStats>::iterator it =
stats.substreams.begin();
it != stats.substreams.end();
++it) {
bwe_info->transmit_bitrate += it->second.total_bitrate_bps;
bwe_info->retransmit_bitrate += it->second.retransmit_bitrate_bps;
}
bwe_info->actual_enc_bitrate = stats.media_bitrate_bps;
}
void WebRtcVideoChannel2::WebRtcVideoSendStream::OnCpuResolutionRequest(
CoordinatedVideoAdapter::AdaptRequest adapt_request) {
rtc::CritScope cs(&lock_);

View File

@ -315,6 +315,7 @@ class WebRtcVideoChannel2 : public rtc::MessageHandler,
void Stop();
VideoSenderInfo GetVideoSenderInfo();
void FillBandwidthEstimationInfo(BandwidthEstimationInfo* bwe_info);
void OnCpuResolutionRequest(
CoordinatedVideoAdapter::AdaptRequest adapt_request);

View File

@ -294,12 +294,9 @@ webrtc::PacketReceiver* FakeCall::Receiver() {
return NULL;
}
uint32_t FakeCall::SendBitrateEstimate() {
return 0;
}
uint32_t FakeCall::ReceiveBitrateEstimate() {
return 0;
webrtc::Call::Stats FakeCall::GetStats() const {
webrtc::Call::Stats stats;
return stats;
}
void FakeCall::SignalNetworkState(webrtc::Call::NetworkState state) {

View File

@ -127,8 +127,7 @@ class FakeCall : public webrtc::Call {
webrtc::VideoReceiveStream* receive_stream) OVERRIDE;
virtual webrtc::PacketReceiver* Receiver() OVERRIDE;
virtual uint32_t SendBitrateEstimate() OVERRIDE;
virtual uint32_t ReceiveBitrateEstimate() OVERRIDE;
virtual webrtc::Call::Stats GetStats() const OVERRIDE;
virtual void SignalNetworkState(webrtc::Call::NetworkState state) OVERRIDE;

View File

@ -88,6 +88,14 @@ class Call {
int stream_start_bitrate_bps;
};
struct Stats {
Stats() : send_bandwidth_bps(0), recv_bandwidth_bps(0), pacer_delay_ms(0) {}
int send_bandwidth_bps;
int recv_bandwidth_bps;
int pacer_delay_ms;
};
static Call* Create(const Call::Config& config);
static Call* Create(const Call::Config& config,
@ -109,13 +117,9 @@ class Call {
// Call instance exists.
virtual PacketReceiver* Receiver() = 0;
// Returns the estimated total send bandwidth. Note: this can differ from the
// actual encoded bitrate.
virtual uint32_t SendBitrateEstimate() = 0;
// Returns the total estimated receive bandwidth for the call. Note: this can
// differ from the actual receive bitrate.
virtual uint32_t ReceiveBitrateEstimate() = 0;
// Returns the call statistics, such as estimated send and receive bandwidth,
// pacing delay, etc.
virtual Stats GetStats() const = 0;
virtual void SignalNetworkState(NetworkState state) = 0;

View File

@ -271,7 +271,9 @@ class BitrateStatisticsObserver {
public:
virtual ~BitrateStatisticsObserver() {}
virtual void Notify(const BitrateStatistics& stats, uint32_t ssrc) = 0;
virtual void Notify(const BitrateStatistics& total_stats,
const BitrateStatistics& retransmit_stats,
uint32_t ssrc) = 0;
};
// Callback, used to notify an observer whenever frame counts have been updated

View File

@ -33,16 +33,19 @@ struct RtpStatistics {
int extended_max_sequence_number;
};
struct StreamStats {
StreamStats()
struct SsrcStats {
SsrcStats()
: key_frames(0),
delta_frames(0),
bitrate_bps(0),
total_bitrate_bps(0),
retransmit_bitrate_bps(0),
avg_delay_ms(0),
max_delay_ms(0) {}
uint32_t key_frames;
uint32_t delta_frames;
int32_t bitrate_bps;
// TODO(holmer): Move bitrate_bps out to the webrtc::Call layer.
int total_bitrate_bps;
int retransmit_bitrate_bps;
int avg_delay_ms;
int max_delay_ms;
StreamDataCounters rtp_stats;

View File

@ -40,6 +40,57 @@ const char* FrameTypeToString(const FrameType frame_type) {
} // namespace
class BitrateAggregator {
public:
explicit BitrateAggregator(BitrateStatisticsObserver* bitrate_callback)
: callback_(bitrate_callback),
total_bitrate_observer_(*this),
retransmit_bitrate_observer_(*this),
ssrc_(0) {}
void OnStatsUpdated() const {
if (callback_)
callback_->Notify(total_bitrate_observer_.statistics(),
retransmit_bitrate_observer_.statistics(),
ssrc_);
}
Bitrate::Observer* total_bitrate_observer() {
return &total_bitrate_observer_;
}
Bitrate::Observer* retransmit_bitrate_observer() {
return &retransmit_bitrate_observer_;
}
void set_ssrc(uint32_t ssrc) { ssrc_ = ssrc; }
private:
// We assume that these observers are called on the same thread, which is
// true for RtpSender as they are called on the Process thread.
class BitrateObserver : public Bitrate::Observer {
public:
explicit BitrateObserver(const BitrateAggregator& aggregator)
: aggregator_(aggregator) {}
// Implements Bitrate::Observer.
virtual void BitrateUpdated(const BitrateStatistics& stats) OVERRIDE {
statistics_ = stats;
aggregator_.OnStatsUpdated();
}
BitrateStatistics statistics() const { return statistics_; }
private:
BitrateStatistics statistics_;
const BitrateAggregator& aggregator_;
};
BitrateStatisticsObserver* const callback_;
BitrateObserver total_bitrate_observer_;
BitrateObserver retransmit_bitrate_observer_;
uint32_t ssrc_;
};
RTPSender::RTPSender(const int32_t id,
const bool audio,
Clock* clock,
@ -54,7 +105,8 @@ RTPSender::RTPSender(const int32_t id,
// TickTime.
clock_delta_ms_(clock_->TimeInMilliseconds() -
TickTime::MillisecondTimestamp()),
bitrate_sent_(clock, this),
bitrates_(new BitrateAggregator(bitrate_callback)),
total_bitrate_sent_(clock, bitrates_->total_bitrate_observer()),
id_(id),
audio_configured_(audio),
audio_(NULL),
@ -74,12 +126,11 @@ RTPSender::RTPSender(const int32_t id,
// NACK.
nack_byte_count_times_(),
nack_byte_count_(),
nack_bitrate_(clock, NULL),
nack_bitrate_(clock, bitrates_->retransmit_bitrate_observer()),
packet_history_(clock),
// Statistics
statistics_crit_(CriticalSectionWrapper::CreateCriticalSection()),
rtp_stats_callback_(NULL),
bitrate_callback_(bitrate_callback),
frame_count_observer_(frame_count_observer),
send_side_delay_observer_(send_side_delay_observer),
// RTP variables
@ -108,6 +159,7 @@ RTPSender::RTPSender(const int32_t id,
srand(static_cast<uint32_t>(clock_->TimeInMilliseconds()));
ssrc_ = ssrc_db_.CreateSSRC(); // Can't be 0.
ssrc_rtx_ = ssrc_db_.CreateSSRC(); // Can't be 0.
bitrates_->set_ssrc(ssrc_);
// Random start, 16 bits. Can't be 0.
sequence_number_rtx_ = static_cast<uint16_t>(rand() + 1) & 0x7FFF;
sequence_number_ = static_cast<uint16_t>(rand() + 1) & 0x7FFF;
@ -149,7 +201,7 @@ uint32_t RTPSender::GetTargetBitrate() {
}
uint16_t RTPSender::ActualSendBitrateKbit() const {
return (uint16_t)(bitrate_sent_.BitrateNow() / 1000);
return (uint16_t)(total_bitrate_sent_.BitrateNow() / 1000);
}
uint32_t RTPSender::VideoBitrateSent() const {
@ -864,7 +916,7 @@ void RTPSender::UpdateRtpStats(const uint8_t* buffer,
counters = &rtp_stats_;
}
bitrate_sent_.Update(size);
total_bitrate_sent_.Update(size);
++counters->packets;
if (IsFecPacket(buffer, header)) {
++counters->fec_packets;
@ -997,7 +1049,7 @@ void RTPSender::UpdateDelayStatistics(int64_t capture_time_ms, int64_t now_ms) {
void RTPSender::ProcessBitrate() {
CriticalSectionScoped cs(send_critsect_);
bitrate_sent_.Process();
total_bitrate_sent_.Process();
nack_bitrate_.Process();
if (audio_configured_) {
return;
@ -1420,6 +1472,7 @@ void RTPSender::SetSendingStatus(bool enabled) {
// Generate a new SSRC.
ssrc_db_.ReturnSSRC(ssrc_);
ssrc_ = ssrc_db_.CreateSSRC(); // Can't be 0.
bitrates_->set_ssrc(ssrc_);
}
// Don't initialize seq number if SSRC passed externally.
if (!sequence_number_forced_ && !ssrc_forced_) {
@ -1470,6 +1523,7 @@ uint32_t RTPSender::GenerateNewSSRC() {
return 0;
}
ssrc_ = ssrc_db_.CreateSSRC(); // Can't be 0.
bitrates_->set_ssrc(ssrc_);
return ssrc_;
}
@ -1484,6 +1538,7 @@ void RTPSender::SetSSRC(uint32_t ssrc) {
ssrc_db_.ReturnSSRC(ssrc_);
ssrc_db_.RegisterSSRC(ssrc);
ssrc_ = ssrc;
bitrates_->set_ssrc(ssrc_);
if (!sequence_number_forced_) {
sequence_number_ =
rand() / (RAND_MAX / MAX_INIT_RTP_SEQ_NUMBER); // NOLINT
@ -1681,17 +1736,8 @@ StreamDataCountersCallback* RTPSender::GetRtpStatisticsCallback() const {
return rtp_stats_callback_;
}
uint32_t RTPSender::BitrateSent() const { return bitrate_sent_.BitrateLast(); }
void RTPSender::BitrateUpdated(const BitrateStatistics& stats) {
uint32_t ssrc;
{
CriticalSectionScoped ssrc_lock(send_critsect_);
ssrc = ssrc_;
}
if (bitrate_callback_) {
bitrate_callback_->Notify(stats, ssrc);
}
uint32_t RTPSender::BitrateSent() const {
return total_bitrate_sent_.BitrateLast();
}
void RTPSender::SetRtpState(const RtpState& rtp_state) {

View File

@ -31,6 +31,7 @@
namespace webrtc {
class BitrateAggregator;
class CriticalSectionWrapper;
class RTPSenderAudio;
class RTPSenderVideo;
@ -65,7 +66,7 @@ class RTPSenderInterface {
PacedSender::Priority priority) = 0;
};
class RTPSender : public RTPSenderInterface, public Bitrate::Observer {
class RTPSender : public RTPSenderInterface {
public:
RTPSender(const int32_t id, const bool audio, Clock *clock,
Transport *transport, RtpAudioFeedback *audio_feedback,
@ -276,8 +277,6 @@ class RTPSender : public RTPSenderInterface, public Bitrate::Observer {
uint32_t BitrateSent() const;
virtual void BitrateUpdated(const BitrateStatistics& stats) OVERRIDE;
void SetRtpState(const RtpState& rtp_state);
RtpState GetRtpState() const;
void SetRtxRtpState(const RtpState& rtp_state);
@ -337,7 +336,9 @@ class RTPSender : public RTPSenderInterface, public Bitrate::Observer {
Clock* clock_;
int64_t clock_delta_ms_;
Bitrate bitrate_sent_;
scoped_ptr<BitrateAggregator> bitrates_;
Bitrate total_bitrate_sent_;
int32_t id_;
const bool audio_configured_;
@ -375,7 +376,6 @@ class RTPSender : public RTPSenderInterface, public Bitrate::Observer {
StreamDataCounters rtp_stats_ GUARDED_BY(statistics_crit_);
StreamDataCounters rtx_rtp_stats_ GUARDED_BY(statistics_crit_);
StreamDataCountersCallback* rtp_stats_callback_ GUARDED_BY(statistics_crit_);
BitrateStatisticsObserver* const bitrate_callback_;
FrameCountObserver* const frame_count_observer_;
SendSideDelayObserver* const send_side_delay_observer_;

View File

@ -855,20 +855,22 @@ TEST_F(RtpSenderTest, FrameCountCallbacks) {
TEST_F(RtpSenderTest, BitrateCallbacks) {
class TestCallback : public BitrateStatisticsObserver {
public:
TestCallback()
: BitrateStatisticsObserver(), num_calls_(0), ssrc_(0), bitrate_() {}
TestCallback() : BitrateStatisticsObserver(), num_calls_(0), ssrc_(0) {}
virtual ~TestCallback() {}
virtual void Notify(const BitrateStatistics& stats,
virtual void Notify(const BitrateStatistics& total_stats,
const BitrateStatistics& retransmit_stats,
uint32_t ssrc) OVERRIDE {
++num_calls_;
ssrc_ = ssrc;
bitrate_ = stats;
total_stats_ = total_stats;
retransmit_stats_ = retransmit_stats;
}
uint32_t num_calls_;
uint32_t ssrc_;
BitrateStatistics bitrate_;
BitrateStatistics total_stats_;
BitrateStatistics retransmit_stats_;
} callback;
rtp_sender_.reset(new RTPSender(0, false, &fake_clock_, &transport_, NULL,
&mock_paced_sender_, &callback, NULL, NULL));
@ -909,13 +911,15 @@ TEST_F(RtpSenderTest, BitrateCallbacks) {
const uint32_t expected_packet_rate = 1000 / kPacketInterval;
EXPECT_EQ(1U, callback.num_calls_);
// We get one call for every stats updated, thus two calls since both the
// stream stats and the retransmit stats are updated once.
EXPECT_EQ(2u, 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);
callback.total_stats_.timestamp_ms);
EXPECT_EQ(expected_packet_rate, callback.total_stats_.packet_rate);
EXPECT_EQ((kPacketOverhead + sizeof(payload)) * 8 * expected_packet_rate,
callback.bitrate_.bitrate_bps);
callback.total_stats_.bitrate_bps);
rtp_sender_.reset();
}

View File

@ -542,7 +542,7 @@ void MediaOptimization::UpdateSentBitrate(int64_t now_ms) {
now_ms - encoded_frame_samples_.front().time_complete_ms);
if (denom >= 1.0f) {
avg_sent_bit_rate_bps_ =
static_cast<uint32_t>(framesize_sum * 8 * 1000 / denom + 0.5f);
static_cast<uint32_t>(framesize_sum * 8.0f * 1000.0f / denom + 0.5f);
} else {
avg_sent_bit_rate_bps_ = framesize_sum * 8;
}

View File

@ -51,7 +51,8 @@ int32_t FakeEncoder::Encode(
assert(config_.maxFramerate > 0);
int time_since_last_encode_ms = 1000 / config_.maxFramerate;
int64_t time_now_ms = clock_->TimeInMilliseconds();
if (last_encode_time_ms_ > 0) {
const bool first_encode = last_encode_time_ms_ == 0;
if (!first_encode) {
// For all frames but the first we can estimate the display time by looking
// at the display time of the previous frame.
time_since_last_encode_ms = time_now_ms - last_encode_time_ms_;
@ -80,6 +81,12 @@ int32_t FakeEncoder::Encode(
int stream_bits = (bits_available > max_stream_bits) ? max_stream_bits :
bits_available;
int stream_bytes = (stream_bits + 7) / 8;
if (first_encode) {
// The first frame is a key frame and should be larger.
// TODO(holmer): The FakeEncoder should store the bits_available between
// encodes so that it can compensate for oversized frames.
stream_bytes *= 10;
}
if (static_cast<size_t>(stream_bytes) > sizeof(encoded_buffer_))
stream_bytes = sizeof(encoded_buffer_);
@ -96,7 +103,6 @@ int32_t FakeEncoder::Encode(
assert(callback_ != NULL);
if (callback_->Encoded(encoded, &specifics, NULL) != 0)
return -1;
bits_available -= encoded._length * 8;
}
return 0;

View File

@ -114,8 +114,7 @@ class Call : public webrtc::Call, public PacketReceiver {
virtual void DestroyVideoReceiveStream(
webrtc::VideoReceiveStream* receive_stream) OVERRIDE;
virtual uint32_t SendBitrateEstimate() OVERRIDE;
virtual uint32_t ReceiveBitrateEstimate() OVERRIDE;
virtual Stats GetStats() const OVERRIDE;
virtual DeliveryStatus DeliverPacket(const uint8_t* packet,
size_t length) OVERRIDE;
@ -321,14 +320,26 @@ void Call::DestroyVideoReceiveStream(
delete receive_stream_impl;
}
uint32_t Call::SendBitrateEstimate() {
// TODO(pbos): Return send-bitrate estimate
return 0;
}
uint32_t Call::ReceiveBitrateEstimate() {
// TODO(pbos): Return receive-bitrate estimate
return 0;
Call::Stats Call::GetStats() const {
Stats stats;
// Ignoring return values.
uint32_t send_bandwidth = 0;
rtp_rtcp_->GetEstimatedSendBandwidth(base_channel_id_, &send_bandwidth);
stats.send_bandwidth_bps = send_bandwidth;
uint32_t recv_bandwidth = 0;
rtp_rtcp_->GetEstimatedReceiveBandwidth(base_channel_id_, &recv_bandwidth);
stats.recv_bandwidth_bps = recv_bandwidth;
{
ReadLockScoped read_lock(*send_crit_);
for (std::map<uint32_t, VideoSendStream*>::const_iterator it =
send_ssrcs_.begin();
it != send_ssrcs_.end();
++it) {
stats.pacer_delay_ms =
std::max(it->second->GetPacerQueuingDelayMs(), stats.pacer_delay_ms);
}
}
return stats;
}
void Call::SignalNetworkState(NetworkState state) {

View File

@ -502,7 +502,8 @@ void CallPerfTest::TestMinTransmitBitrate(bool pad_to_min_bitrate) {
VideoSendStream::Stats stats = send_stream_->GetStats();
if (stats.substreams.size() > 0) {
assert(stats.substreams.size() == 1);
int bitrate_kbps = stats.substreams.begin()->second.bitrate_bps / 1000;
int bitrate_kbps =
stats.substreams.begin()->second.total_bitrate_bps / 1000;
if (bitrate_kbps > 0) {
test::PrintResult(
"bitrate_stats_",

View File

@ -1202,6 +1202,53 @@ TEST_F(EndToEndTest, ReceiveStreamSendsRemb) {
RunBaseTest(&test);
}
TEST_F(EndToEndTest, VerifyBandwidthStats) {
class RtcpObserver : public test::EndToEndTest, public PacketReceiver {
public:
RtcpObserver()
: EndToEndTest(kDefaultTimeoutMs),
sender_call_(NULL),
receiver_call_(NULL),
has_seen_pacer_delay_(false) {}
virtual DeliveryStatus DeliverPacket(const uint8_t* packet,
size_t length) OVERRIDE {
Call::Stats sender_stats = sender_call_->GetStats();
Call::Stats receiver_stats = receiver_call_->GetStats();
if (!has_seen_pacer_delay_)
has_seen_pacer_delay_ = sender_stats.pacer_delay_ms > 0;
if (sender_stats.send_bandwidth_bps > 0 &&
receiver_stats.recv_bandwidth_bps > 0 && has_seen_pacer_delay_)
observation_complete_->Set();
return receiver_call_->Receiver()->DeliverPacket(packet, length);
}
virtual void OnCallsCreated(Call* sender_call,
Call* receiver_call) OVERRIDE {
sender_call_ = sender_call;
receiver_call_ = receiver_call;
}
virtual void PerformTest() OVERRIDE {
EXPECT_EQ(kEventSignaled, Wait()) << "Timed out while waiting for "
"non-zero bandwidth stats.";
}
virtual void SetReceivers(
PacketReceiver* send_transport_receiver,
PacketReceiver* receive_transport_receiver) OVERRIDE {
test::RtpRtcpObserver::SetReceivers(this, receive_transport_receiver);
}
private:
Call* sender_call_;
Call* receiver_call_;
bool has_seen_pacer_delay_;
} test;
RunBaseTest(&test);
}
void EndToEndTest::TestXrReceiverReferenceTimeReport(bool enable_rrtr) {
static const int kNumRtcpReportPacketsToObserve = 5;
class RtcpXrObserver : public test::EndToEndTest {
@ -1434,7 +1481,7 @@ TEST_F(EndToEndTest, GetStats) {
// Make sure all fields have been populated.
receive_stats_filled_["IncomingRate"] |=
stats.network_frame_rate != 0 || stats.bitrate_bps != 0;
stats.network_frame_rate != 0 || stats.total_bitrate_bps != 0;
receive_stats_filled_["FrameCallback"] |= stats.decode_frame_rate != 0;
@ -1465,7 +1512,7 @@ TEST_F(EndToEndTest, GetStats) {
send_stats_filled_["NumStreams"] |=
stats.substreams.size() == expected_send_ssrcs_.size();
for (std::map<uint32_t, StreamStats>::const_iterator it =
for (std::map<uint32_t, SsrcStats>::const_iterator it =
stats.substreams.begin();
it != stats.substreams.end();
++it) {
@ -1475,7 +1522,7 @@ TEST_F(EndToEndTest, GetStats) {
send_stats_filled_[CompoundKey("IncomingRate", it->first)] |=
stats.input_frame_rate != 0;
const StreamStats& stream_stats = it->second;
const SsrcStats& stream_stats = it->second;
send_stats_filled_[CompoundKey("StatisticsUpdated", it->first)] |=
stream_stats.rtcp_stats.cumulative_lost != 0 ||
@ -1490,7 +1537,7 @@ TEST_F(EndToEndTest, GetStats) {
send_stats_filled_[CompoundKey("BitrateStatisticsObserver",
it->first)] |=
stream_stats.bitrate_bps != 0;
stream_stats.total_bitrate_bps != 0;
send_stats_filled_[CompoundKey("FrameCountObserver", it->first)] |=
stream_stats.delta_frames != 0 || stream_stats.key_frames != 0;

View File

@ -58,10 +58,10 @@ std::string ReceiveStatisticsProxy::GetCName() const {
void ReceiveStatisticsProxy::IncomingRate(const int video_channel,
const unsigned int framerate,
const unsigned int bitrate) {
const unsigned int bitrate_bps) {
CriticalSectionScoped lock(crit_.get());
stats_.network_frame_rate = framerate;
stats_.bitrate_bps = bitrate;
stats_.total_bitrate_bps = bitrate_bps;
}
void ReceiveStatisticsProxy::StatisticsUpdated(

View File

@ -52,7 +52,7 @@ class ReceiveStatisticsProxy : public ViEDecoderObserver,
const VideoCodec& video_codec) OVERRIDE {}
virtual void IncomingRate(const int video_channel,
const unsigned int framerate,
const unsigned int bitrate) OVERRIDE;
const unsigned int bitrate_bps) OVERRIDE;
virtual void DecoderTiming(int decode_ms,
int max_decode_ms,
int current_delay_ms,

View File

@ -29,6 +29,7 @@ void SendStatisticsProxy::OutgoingRate(const int video_channel,
const unsigned int bitrate) {
CriticalSectionScoped lock(crit_.get());
stats_.encode_frame_rate = framerate;
stats_.media_bitrate_bps = bitrate;
}
void SendStatisticsProxy::SuspendChange(int video_channel, bool is_suspended) {
@ -47,8 +48,8 @@ VideoSendStream::Stats SendStatisticsProxy::GetStats() const {
return stats_;
}
StreamStats* SendStatisticsProxy::GetStatsEntry(uint32_t ssrc) {
std::map<uint32_t, StreamStats>::iterator it = stats_.substreams.find(ssrc);
SsrcStats* SendStatisticsProxy::GetStatsEntry(uint32_t ssrc) {
std::map<uint32_t, SsrcStats>::iterator it = stats_.substreams.find(ssrc);
if (it != stats_.substreams.end())
return &it->second;
@ -66,7 +67,7 @@ StreamStats* SendStatisticsProxy::GetStatsEntry(uint32_t ssrc) {
void SendStatisticsProxy::StatisticsUpdated(const RtcpStatistics& statistics,
uint32_t ssrc) {
CriticalSectionScoped lock(crit_.get());
StreamStats* stats = GetStatsEntry(ssrc);
SsrcStats* stats = GetStatsEntry(ssrc);
if (stats == NULL)
return;
@ -77,28 +78,30 @@ void SendStatisticsProxy::DataCountersUpdated(
const StreamDataCounters& counters,
uint32_t ssrc) {
CriticalSectionScoped lock(crit_.get());
StreamStats* stats = GetStatsEntry(ssrc);
SsrcStats* stats = GetStatsEntry(ssrc);
if (stats == NULL)
return;
stats->rtp_stats = counters;
}
void SendStatisticsProxy::Notify(const BitrateStatistics& bitrate,
void SendStatisticsProxy::Notify(const BitrateStatistics& total_stats,
const BitrateStatistics& retransmit_stats,
uint32_t ssrc) {
CriticalSectionScoped lock(crit_.get());
StreamStats* stats = GetStatsEntry(ssrc);
SsrcStats* stats = GetStatsEntry(ssrc);
if (stats == NULL)
return;
stats->bitrate_bps = bitrate.bitrate_bps;
stats->total_bitrate_bps = total_stats.bitrate_bps;
stats->retransmit_bitrate_bps = retransmit_stats.bitrate_bps;
}
void SendStatisticsProxy::FrameCountUpdated(FrameType frame_type,
uint32_t frame_count,
const unsigned int ssrc) {
CriticalSectionScoped lock(crit_.get());
StreamStats* stats = GetStatsEntry(ssrc);
SsrcStats* stats = GetStatsEntry(ssrc);
if (stats == NULL)
return;
@ -120,7 +123,7 @@ void SendStatisticsProxy::SendSideDelayUpdated(int avg_delay_ms,
int max_delay_ms,
uint32_t ssrc) {
CriticalSectionScoped lock(crit_.get());
StreamStats* stats = GetStatsEntry(ssrc);
SsrcStats* stats = GetStatsEntry(ssrc);
if (stats == NULL)
return;
stats->avg_delay_ms = avg_delay_ms;

View File

@ -46,7 +46,9 @@ class SendStatisticsProxy : public RtcpStatisticsCallback,
uint32_t ssrc) OVERRIDE;
// From BitrateStatisticsObserver.
virtual void Notify(const BitrateStatistics& stats, uint32_t ssrc) OVERRIDE;
virtual void Notify(const BitrateStatistics& total_stats,
const BitrateStatistics& retransmit_stats,
uint32_t ssrc) OVERRIDE;
// From FrameCountObserver.
virtual void FrameCountUpdated(FrameType frame_type,
@ -75,7 +77,7 @@ class SendStatisticsProxy : public RtcpStatisticsCallback,
uint32_t ssrc) OVERRIDE;
private:
StreamStats* GetStatsEntry(uint32_t ssrc) EXCLUSIVE_LOCKS_REQUIRED(crit_);
SsrcStats* GetStatsEntry(uint32_t ssrc) EXCLUSIVE_LOCKS_REQUIRED(crit_);
const VideoSendStream::Config config_;
scoped_ptr<CriticalSectionWrapper> crit_;

View File

@ -44,22 +44,23 @@ class SendStatisticsProxyTest : public ::testing::Test {
void ExpectEqual(VideoSendStream::Stats one, VideoSendStream::Stats other) {
EXPECT_EQ(one.input_frame_rate, other.input_frame_rate);
EXPECT_EQ(one.encode_frame_rate, other.encode_frame_rate);
EXPECT_EQ(one.media_bitrate_bps, other.media_bitrate_bps);
EXPECT_EQ(one.suspended, other.suspended);
EXPECT_EQ(one.substreams.size(), other.substreams.size());
for (std::map<uint32_t, StreamStats>::const_iterator it =
for (std::map<uint32_t, SsrcStats>::const_iterator it =
one.substreams.begin();
it != one.substreams.end();
++it) {
std::map<uint32_t, StreamStats>::const_iterator corresponding_it =
std::map<uint32_t, SsrcStats>::const_iterator corresponding_it =
other.substreams.find(it->first);
ASSERT_TRUE(corresponding_it != other.substreams.end());
const StreamStats& a = it->second;
const StreamStats& b = corresponding_it->second;
const SsrcStats& a = it->second;
const SsrcStats& b = corresponding_it->second;
EXPECT_EQ(a.key_frames, b.key_frames);
EXPECT_EQ(a.delta_frames, b.delta_frames);
EXPECT_EQ(a.bitrate_bps, b.bitrate_bps);
EXPECT_EQ(a.total_bitrate_bps, b.total_bitrate_bps);
EXPECT_EQ(a.avg_delay_ms, b.avg_delay_ms);
EXPECT_EQ(a.max_delay_ms, b.max_delay_ms);
@ -84,7 +85,7 @@ class SendStatisticsProxyTest : public ::testing::Test {
int avg_delay_ms_;
int max_delay_ms_;
VideoSendStream::Stats expected_;
typedef std::map<uint32_t, StreamStats>::const_iterator StreamIterator;
typedef std::map<uint32_t, SsrcStats>::const_iterator StreamIterator;
};
TEST_F(SendStatisticsProxyTest, RtcpStatistics) {
@ -93,7 +94,7 @@ TEST_F(SendStatisticsProxyTest, RtcpStatistics) {
it != config_.rtp.ssrcs.end();
++it) {
const uint32_t ssrc = *it;
StreamStats& ssrc_stats = expected_.substreams[ssrc];
SsrcStats& ssrc_stats = expected_.substreams[ssrc];
// Add statistics with some arbitrary, but unique, numbers.
uint32_t offset = ssrc * sizeof(RtcpStatistics);
@ -107,7 +108,7 @@ TEST_F(SendStatisticsProxyTest, RtcpStatistics) {
it != config_.rtp.rtx.ssrcs.end();
++it) {
const uint32_t ssrc = *it;
StreamStats& ssrc_stats = expected_.substreams[ssrc];
SsrcStats& ssrc_stats = expected_.substreams[ssrc];
// Add statistics with some arbitrary, but unique, numbers.
uint32_t offset = ssrc * sizeof(RtcpStatistics);
@ -121,17 +122,25 @@ TEST_F(SendStatisticsProxyTest, RtcpStatistics) {
ExpectEqual(expected_, stats);
}
TEST_F(SendStatisticsProxyTest, FrameRates) {
TEST_F(SendStatisticsProxyTest, CaptureFramerate) {
const int capture_fps = 31;
const int encode_fps = 29;
ViECaptureObserver* capture_observer = statistics_proxy_.get();
capture_observer->CapturedFrameRate(0, capture_fps);
ViEEncoderObserver* encoder_observer = statistics_proxy_.get();
encoder_observer->OutgoingRate(0, encode_fps, 0);
VideoSendStream::Stats stats = statistics_proxy_->GetStats();
EXPECT_EQ(capture_fps, stats.input_frame_rate);
}
TEST_F(SendStatisticsProxyTest, EncodedBitrateAndFramerate) {
const int media_bitrate_bps = 500;
const int encode_fps = 29;
ViEEncoderObserver* encoder_observer = statistics_proxy_.get();
encoder_observer->OutgoingRate(0, encode_fps, media_bitrate_bps);
VideoSendStream::Stats stats = statistics_proxy_->GetStats();
EXPECT_EQ(media_bitrate_bps, stats.media_bitrate_bps);
EXPECT_EQ(encode_fps, stats.encode_frame_rate);
}
@ -156,8 +165,8 @@ TEST_F(SendStatisticsProxyTest, FrameCounts) {
++it) {
const uint32_t ssrc = *it;
// Add statistics with some arbitrary, but unique, numbers.
StreamStats& stats = expected_.substreams[ssrc];
uint32_t offset = ssrc * sizeof(StreamStats);
SsrcStats& stats = expected_.substreams[ssrc];
uint32_t offset = ssrc * sizeof(SsrcStats);
stats.key_frames = offset;
stats.delta_frames = offset + 1;
observer->FrameCountUpdated(kVideoFrameKey, stats.key_frames, ssrc);
@ -168,8 +177,8 @@ TEST_F(SendStatisticsProxyTest, FrameCounts) {
++it) {
const uint32_t ssrc = *it;
// Add statistics with some arbitrary, but unique, numbers.
StreamStats& stats = expected_.substreams[ssrc];
uint32_t offset = ssrc * sizeof(StreamStats);
SsrcStats& stats = expected_.substreams[ssrc];
uint32_t offset = ssrc * sizeof(SsrcStats);
stats.key_frames = offset;
stats.delta_frames = offset + 1;
observer->FrameCountUpdated(kVideoFrameKey, stats.key_frames, ssrc);
@ -223,21 +232,27 @@ TEST_F(SendStatisticsProxyTest, Bitrate) {
it != config_.rtp.ssrcs.end();
++it) {
const uint32_t ssrc = *it;
BitrateStatistics bitrate;
BitrateStatistics total;
BitrateStatistics retransmit;
// Use ssrc as bitrate_bps to get a unique value for each stream.
bitrate.bitrate_bps = ssrc;
observer->Notify(bitrate, ssrc);
expected_.substreams[ssrc].bitrate_bps = ssrc;
total.bitrate_bps = ssrc;
retransmit.bitrate_bps = ssrc + 1;
observer->Notify(total, retransmit, ssrc);
expected_.substreams[ssrc].total_bitrate_bps = total.bitrate_bps;
expected_.substreams[ssrc].retransmit_bitrate_bps = retransmit.bitrate_bps;
}
for (std::vector<uint32_t>::const_iterator it = config_.rtp.rtx.ssrcs.begin();
it != config_.rtp.rtx.ssrcs.end();
++it) {
const uint32_t ssrc = *it;
BitrateStatistics bitrate;
BitrateStatistics total;
BitrateStatistics retransmit;
// Use ssrc as bitrate_bps to get a unique value for each stream.
bitrate.bitrate_bps = ssrc;
observer->Notify(bitrate, ssrc);
expected_.substreams[ssrc].bitrate_bps = ssrc;
total.bitrate_bps = ssrc;
retransmit.bitrate_bps = ssrc + 1;
observer->Notify(total, retransmit, ssrc);
expected_.substreams[ssrc].total_bitrate_bps = total.bitrate_bps;
expected_.substreams[ssrc].retransmit_bitrate_bps = retransmit.bitrate_bps;
}
VideoSendStream::Stats stats = statistics_proxy_->GetStats();
@ -292,9 +307,10 @@ TEST_F(SendStatisticsProxyTest, NoSubstreams) {
rtp_callback->DataCountersUpdated(rtp_stats, exluded_ssrc);
// From BitrateStatisticsObserver.
BitrateStatistics bitrate;
BitrateStatistics total;
BitrateStatistics retransmit;
BitrateStatisticsObserver* bitrate_observer = statistics_proxy_.get();
bitrate_observer->Notify(bitrate, exluded_ssrc);
bitrate_observer->Notify(total, retransmit, exluded_ssrc);
// From FrameCountObserver.
FrameCountObserver* fps_observer = statistics_proxy_.get();

View File

@ -492,5 +492,12 @@ void VideoSendStream::SignalNetworkState(Call::NetworkState state) {
rtp_rtcp_->SetRTCPStatus(channel_, kRtcpNone);
}
int VideoSendStream::GetPacerQueuingDelayMs() const {
int pacer_delay_ms = 0;
if (rtp_rtcp_->GetPacerQueuingDelayMs(channel_, &pacer_delay_ms) != 0) {
return 0;
}
return pacer_delay_ms;
}
} // namespace internal
} // namespace webrtc

View File

@ -74,6 +74,8 @@ class VideoSendStream : public webrtc::VideoSendStream,
void SignalNetworkState(Call::NetworkState state);
int GetPacerQueuingDelayMs() const;
private:
void ConfigureSsrcs();
TransportAdapter transport_adapter_;

View File

@ -962,8 +962,8 @@ TEST_F(VideoSendStreamTest, ProducesStats) {
config_.rtp.ssrcs.begin(), config_.rtp.ssrcs.end(), ssrc));
// Check for data populated by various sources. RTCP excluded as this
// data is received from remote side. Tested in call tests instead.
const StreamStats& entry = stats.substreams[ssrc];
if (entry.key_frames > 0u && entry.bitrate_bps > 0 &&
const SsrcStats& entry = stats.substreams[ssrc];
if (entry.key_frames > 0u && entry.total_bitrate_bps > 0 &&
entry.rtp_stats.packets > 0u && entry.avg_delay_ms > 0 &&
entry.max_delay_ms > 0) {
return true;
@ -1045,20 +1045,20 @@ TEST_F(VideoSendStreamTest, MinTransmitBitrateRespectsRemb) {
VideoSendStream::Stats stats = stream_->GetStats();
if (!stats.substreams.empty()) {
EXPECT_EQ(1u, stats.substreams.size());
int bitrate_bps = stats.substreams.begin()->second.bitrate_bps;
test::PrintResult(
"bitrate_stats_",
"min_transmit_bitrate_low_remb",
"bitrate_bps",
static_cast<size_t>(bitrate_bps),
"bps",
false);
if (bitrate_bps > kHighBitrateBps) {
int total_bitrate_bps =
stats.substreams.begin()->second.total_bitrate_bps;
test::PrintResult("bitrate_stats_",
"min_transmit_bitrate_low_remb",
"bitrate_bps",
static_cast<size_t>(total_bitrate_bps),
"bps",
false);
if (total_bitrate_bps > kHighBitrateBps) {
rtp_rtcp_->SetREMBData(kRembBitrateBps, 1, &header.ssrc);
rtp_rtcp_->Process();
bitrate_capped_ = true;
} else if (bitrate_capped_ &&
bitrate_bps < kRembRespectedBitrateBps) {
total_bitrate_bps < kRembRespectedBitrateBps) {
observation_complete_->Set();
}
}

View File

@ -415,10 +415,12 @@ class ViEChannel
class RegisterableBitrateStatisticsObserver:
public RegisterableCallback<BitrateStatisticsObserver> {
virtual void Notify(const BitrateStatistics& stats, uint32_t ssrc) {
virtual void Notify(const BitrateStatistics& total_stats,
const BitrateStatistics& retransmit_stats,
uint32_t ssrc) {
CriticalSectionScoped cs(critsect_.get());
if (callback_)
callback_->Notify(stats, ssrc);
callback_->Notify(total_stats, retransmit_stats, ssrc);
}
}
send_bitrate_observer_;

View File

@ -63,7 +63,7 @@ class VideoReceiveStream {
int expected_delay_ms;
};
struct Stats : public StreamStats {
struct Stats : public SsrcStats {
Stats()
: network_frame_rate(0),
decode_frame_rate(0),

View File

@ -41,11 +41,13 @@ class VideoSendStream {
Stats()
: input_frame_rate(0),
encode_frame_rate(0),
media_bitrate_bps(0),
suspended(false) {}
int input_frame_rate;
int encode_frame_rate;
int media_bitrate_bps;
bool suspended;
std::map<uint32_t, StreamStats> substreams;
std::map<uint32_t, SsrcStats> substreams;
};
struct Config {