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:
parent
a22a628356
commit
0bae1fab4a
@ -1202,7 +1202,21 @@ void WebRtcVideoChannel2::FillReceiverStats(VideoMediaInfo* video_media_info) {
|
|||||||
|
|
||||||
void WebRtcVideoChannel2::FillBandwidthEstimationStats(
|
void WebRtcVideoChannel2::FillBandwidthEstimationStats(
|
||||||
VideoMediaInfo* video_media_info) {
|
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) {
|
bool WebRtcVideoChannel2::SetCapturer(uint32 ssrc, VideoCapturer* capturer) {
|
||||||
@ -1842,12 +1856,12 @@ WebRtcVideoChannel2::WebRtcVideoSendStream::GetVideoSenderInfo() {
|
|||||||
info.framerate_input = stats.input_frame_rate;
|
info.framerate_input = stats.input_frame_rate;
|
||||||
info.framerate_sent = stats.encode_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();
|
stats.substreams.begin();
|
||||||
it != stats.substreams.end();
|
it != stats.substreams.end();
|
||||||
++it) {
|
++it) {
|
||||||
// TODO(pbos): Wire up additional stats, such as padding bytes.
|
// 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 +
|
info.bytes_sent += stream_stats.rtp_stats.bytes +
|
||||||
stream_stats.rtp_stats.header_bytes +
|
stream_stats.rtp_stats.header_bytes +
|
||||||
stream_stats.rtp_stats.padding_bytes;
|
stream_stats.rtp_stats.padding_bytes;
|
||||||
@ -1857,7 +1871,7 @@ WebRtcVideoChannel2::WebRtcVideoSendStream::GetVideoSenderInfo() {
|
|||||||
|
|
||||||
if (!stats.substreams.empty()) {
|
if (!stats.substreams.empty()) {
|
||||||
// TODO(pbos): Report fraction lost per SSRC.
|
// 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 =
|
info.fraction_lost =
|
||||||
static_cast<float>(first_stream_stats.rtcp_stats.fraction_lost) /
|
static_cast<float>(first_stream_stats.rtcp_stats.fraction_lost) /
|
||||||
(1 << 8);
|
(1 << 8);
|
||||||
@ -1884,6 +1898,23 @@ WebRtcVideoChannel2::WebRtcVideoSendStream::GetVideoSenderInfo() {
|
|||||||
return info;
|
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(
|
void WebRtcVideoChannel2::WebRtcVideoSendStream::OnCpuResolutionRequest(
|
||||||
CoordinatedVideoAdapter::AdaptRequest adapt_request) {
|
CoordinatedVideoAdapter::AdaptRequest adapt_request) {
|
||||||
rtc::CritScope cs(&lock_);
|
rtc::CritScope cs(&lock_);
|
||||||
|
@ -315,6 +315,7 @@ class WebRtcVideoChannel2 : public rtc::MessageHandler,
|
|||||||
void Stop();
|
void Stop();
|
||||||
|
|
||||||
VideoSenderInfo GetVideoSenderInfo();
|
VideoSenderInfo GetVideoSenderInfo();
|
||||||
|
void FillBandwidthEstimationInfo(BandwidthEstimationInfo* bwe_info);
|
||||||
|
|
||||||
void OnCpuResolutionRequest(
|
void OnCpuResolutionRequest(
|
||||||
CoordinatedVideoAdapter::AdaptRequest adapt_request);
|
CoordinatedVideoAdapter::AdaptRequest adapt_request);
|
||||||
|
@ -294,12 +294,9 @@ webrtc::PacketReceiver* FakeCall::Receiver() {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t FakeCall::SendBitrateEstimate() {
|
webrtc::Call::Stats FakeCall::GetStats() const {
|
||||||
return 0;
|
webrtc::Call::Stats stats;
|
||||||
}
|
return stats;
|
||||||
|
|
||||||
uint32_t FakeCall::ReceiveBitrateEstimate() {
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FakeCall::SignalNetworkState(webrtc::Call::NetworkState state) {
|
void FakeCall::SignalNetworkState(webrtc::Call::NetworkState state) {
|
||||||
|
@ -127,8 +127,7 @@ class FakeCall : public webrtc::Call {
|
|||||||
webrtc::VideoReceiveStream* receive_stream) OVERRIDE;
|
webrtc::VideoReceiveStream* receive_stream) OVERRIDE;
|
||||||
virtual webrtc::PacketReceiver* Receiver() OVERRIDE;
|
virtual webrtc::PacketReceiver* Receiver() OVERRIDE;
|
||||||
|
|
||||||
virtual uint32_t SendBitrateEstimate() OVERRIDE;
|
virtual webrtc::Call::Stats GetStats() const OVERRIDE;
|
||||||
virtual uint32_t ReceiveBitrateEstimate() OVERRIDE;
|
|
||||||
|
|
||||||
virtual void SignalNetworkState(webrtc::Call::NetworkState state) OVERRIDE;
|
virtual void SignalNetworkState(webrtc::Call::NetworkState state) OVERRIDE;
|
||||||
|
|
||||||
|
@ -88,6 +88,14 @@ class Call {
|
|||||||
int stream_start_bitrate_bps;
|
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);
|
||||||
|
|
||||||
static Call* Create(const Call::Config& config,
|
static Call* Create(const Call::Config& config,
|
||||||
@ -109,13 +117,9 @@ class Call {
|
|||||||
// Call instance exists.
|
// Call instance exists.
|
||||||
virtual PacketReceiver* Receiver() = 0;
|
virtual PacketReceiver* Receiver() = 0;
|
||||||
|
|
||||||
// Returns the estimated total send bandwidth. Note: this can differ from the
|
// Returns the call statistics, such as estimated send and receive bandwidth,
|
||||||
// actual encoded bitrate.
|
// pacing delay, etc.
|
||||||
virtual uint32_t SendBitrateEstimate() = 0;
|
virtual Stats GetStats() const = 0;
|
||||||
|
|
||||||
// Returns the total estimated receive bandwidth for the call. Note: this can
|
|
||||||
// differ from the actual receive bitrate.
|
|
||||||
virtual uint32_t ReceiveBitrateEstimate() = 0;
|
|
||||||
|
|
||||||
virtual void SignalNetworkState(NetworkState state) = 0;
|
virtual void SignalNetworkState(NetworkState state) = 0;
|
||||||
|
|
||||||
|
@ -271,7 +271,9 @@ class BitrateStatisticsObserver {
|
|||||||
public:
|
public:
|
||||||
virtual ~BitrateStatisticsObserver() {}
|
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
|
// Callback, used to notify an observer whenever frame counts have been updated
|
||||||
|
@ -33,16 +33,19 @@ struct RtpStatistics {
|
|||||||
int extended_max_sequence_number;
|
int extended_max_sequence_number;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct StreamStats {
|
struct SsrcStats {
|
||||||
StreamStats()
|
SsrcStats()
|
||||||
: key_frames(0),
|
: key_frames(0),
|
||||||
delta_frames(0),
|
delta_frames(0),
|
||||||
bitrate_bps(0),
|
total_bitrate_bps(0),
|
||||||
|
retransmit_bitrate_bps(0),
|
||||||
avg_delay_ms(0),
|
avg_delay_ms(0),
|
||||||
max_delay_ms(0) {}
|
max_delay_ms(0) {}
|
||||||
uint32_t key_frames;
|
uint32_t key_frames;
|
||||||
uint32_t delta_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 avg_delay_ms;
|
||||||
int max_delay_ms;
|
int max_delay_ms;
|
||||||
StreamDataCounters rtp_stats;
|
StreamDataCounters rtp_stats;
|
||||||
|
@ -40,6 +40,57 @@ const char* FrameTypeToString(const FrameType frame_type) {
|
|||||||
|
|
||||||
} // namespace
|
} // 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,
|
RTPSender::RTPSender(const int32_t id,
|
||||||
const bool audio,
|
const bool audio,
|
||||||
Clock* clock,
|
Clock* clock,
|
||||||
@ -54,7 +105,8 @@ RTPSender::RTPSender(const int32_t id,
|
|||||||
// TickTime.
|
// TickTime.
|
||||||
clock_delta_ms_(clock_->TimeInMilliseconds() -
|
clock_delta_ms_(clock_->TimeInMilliseconds() -
|
||||||
TickTime::MillisecondTimestamp()),
|
TickTime::MillisecondTimestamp()),
|
||||||
bitrate_sent_(clock, this),
|
bitrates_(new BitrateAggregator(bitrate_callback)),
|
||||||
|
total_bitrate_sent_(clock, bitrates_->total_bitrate_observer()),
|
||||||
id_(id),
|
id_(id),
|
||||||
audio_configured_(audio),
|
audio_configured_(audio),
|
||||||
audio_(NULL),
|
audio_(NULL),
|
||||||
@ -74,12 +126,11 @@ RTPSender::RTPSender(const int32_t id,
|
|||||||
// NACK.
|
// NACK.
|
||||||
nack_byte_count_times_(),
|
nack_byte_count_times_(),
|
||||||
nack_byte_count_(),
|
nack_byte_count_(),
|
||||||
nack_bitrate_(clock, NULL),
|
nack_bitrate_(clock, bitrates_->retransmit_bitrate_observer()),
|
||||||
packet_history_(clock),
|
packet_history_(clock),
|
||||||
// Statistics
|
// Statistics
|
||||||
statistics_crit_(CriticalSectionWrapper::CreateCriticalSection()),
|
statistics_crit_(CriticalSectionWrapper::CreateCriticalSection()),
|
||||||
rtp_stats_callback_(NULL),
|
rtp_stats_callback_(NULL),
|
||||||
bitrate_callback_(bitrate_callback),
|
|
||||||
frame_count_observer_(frame_count_observer),
|
frame_count_observer_(frame_count_observer),
|
||||||
send_side_delay_observer_(send_side_delay_observer),
|
send_side_delay_observer_(send_side_delay_observer),
|
||||||
// RTP variables
|
// RTP variables
|
||||||
@ -108,6 +159,7 @@ RTPSender::RTPSender(const int32_t id,
|
|||||||
srand(static_cast<uint32_t>(clock_->TimeInMilliseconds()));
|
srand(static_cast<uint32_t>(clock_->TimeInMilliseconds()));
|
||||||
ssrc_ = ssrc_db_.CreateSSRC(); // Can't be 0.
|
ssrc_ = ssrc_db_.CreateSSRC(); // Can't be 0.
|
||||||
ssrc_rtx_ = 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.
|
// Random start, 16 bits. Can't be 0.
|
||||||
sequence_number_rtx_ = static_cast<uint16_t>(rand() + 1) & 0x7FFF;
|
sequence_number_rtx_ = static_cast<uint16_t>(rand() + 1) & 0x7FFF;
|
||||||
sequence_number_ = 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 {
|
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 {
|
uint32_t RTPSender::VideoBitrateSent() const {
|
||||||
@ -864,7 +916,7 @@ void RTPSender::UpdateRtpStats(const uint8_t* buffer,
|
|||||||
counters = &rtp_stats_;
|
counters = &rtp_stats_;
|
||||||
}
|
}
|
||||||
|
|
||||||
bitrate_sent_.Update(size);
|
total_bitrate_sent_.Update(size);
|
||||||
++counters->packets;
|
++counters->packets;
|
||||||
if (IsFecPacket(buffer, header)) {
|
if (IsFecPacket(buffer, header)) {
|
||||||
++counters->fec_packets;
|
++counters->fec_packets;
|
||||||
@ -997,7 +1049,7 @@ void RTPSender::UpdateDelayStatistics(int64_t capture_time_ms, int64_t now_ms) {
|
|||||||
|
|
||||||
void RTPSender::ProcessBitrate() {
|
void RTPSender::ProcessBitrate() {
|
||||||
CriticalSectionScoped cs(send_critsect_);
|
CriticalSectionScoped cs(send_critsect_);
|
||||||
bitrate_sent_.Process();
|
total_bitrate_sent_.Process();
|
||||||
nack_bitrate_.Process();
|
nack_bitrate_.Process();
|
||||||
if (audio_configured_) {
|
if (audio_configured_) {
|
||||||
return;
|
return;
|
||||||
@ -1420,6 +1472,7 @@ void RTPSender::SetSendingStatus(bool enabled) {
|
|||||||
// Generate a new SSRC.
|
// Generate a new SSRC.
|
||||||
ssrc_db_.ReturnSSRC(ssrc_);
|
ssrc_db_.ReturnSSRC(ssrc_);
|
||||||
ssrc_ = ssrc_db_.CreateSSRC(); // Can't be 0.
|
ssrc_ = ssrc_db_.CreateSSRC(); // Can't be 0.
|
||||||
|
bitrates_->set_ssrc(ssrc_);
|
||||||
}
|
}
|
||||||
// Don't initialize seq number if SSRC passed externally.
|
// Don't initialize seq number if SSRC passed externally.
|
||||||
if (!sequence_number_forced_ && !ssrc_forced_) {
|
if (!sequence_number_forced_ && !ssrc_forced_) {
|
||||||
@ -1470,6 +1523,7 @@ uint32_t RTPSender::GenerateNewSSRC() {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
ssrc_ = ssrc_db_.CreateSSRC(); // Can't be 0.
|
ssrc_ = ssrc_db_.CreateSSRC(); // Can't be 0.
|
||||||
|
bitrates_->set_ssrc(ssrc_);
|
||||||
return ssrc_;
|
return ssrc_;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1484,6 +1538,7 @@ void RTPSender::SetSSRC(uint32_t ssrc) {
|
|||||||
ssrc_db_.ReturnSSRC(ssrc_);
|
ssrc_db_.ReturnSSRC(ssrc_);
|
||||||
ssrc_db_.RegisterSSRC(ssrc);
|
ssrc_db_.RegisterSSRC(ssrc);
|
||||||
ssrc_ = ssrc;
|
ssrc_ = ssrc;
|
||||||
|
bitrates_->set_ssrc(ssrc_);
|
||||||
if (!sequence_number_forced_) {
|
if (!sequence_number_forced_) {
|
||||||
sequence_number_ =
|
sequence_number_ =
|
||||||
rand() / (RAND_MAX / MAX_INIT_RTP_SEQ_NUMBER); // NOLINT
|
rand() / (RAND_MAX / MAX_INIT_RTP_SEQ_NUMBER); // NOLINT
|
||||||
@ -1681,17 +1736,8 @@ StreamDataCountersCallback* RTPSender::GetRtpStatisticsCallback() const {
|
|||||||
return rtp_stats_callback_;
|
return rtp_stats_callback_;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t RTPSender::BitrateSent() const { return bitrate_sent_.BitrateLast(); }
|
uint32_t RTPSender::BitrateSent() const {
|
||||||
|
return total_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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RTPSender::SetRtpState(const RtpState& rtp_state) {
|
void RTPSender::SetRtpState(const RtpState& rtp_state) {
|
||||||
|
@ -31,6 +31,7 @@
|
|||||||
|
|
||||||
namespace webrtc {
|
namespace webrtc {
|
||||||
|
|
||||||
|
class BitrateAggregator;
|
||||||
class CriticalSectionWrapper;
|
class CriticalSectionWrapper;
|
||||||
class RTPSenderAudio;
|
class RTPSenderAudio;
|
||||||
class RTPSenderVideo;
|
class RTPSenderVideo;
|
||||||
@ -65,7 +66,7 @@ class RTPSenderInterface {
|
|||||||
PacedSender::Priority priority) = 0;
|
PacedSender::Priority priority) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class RTPSender : public RTPSenderInterface, public Bitrate::Observer {
|
class RTPSender : public RTPSenderInterface {
|
||||||
public:
|
public:
|
||||||
RTPSender(const int32_t id, const bool audio, Clock *clock,
|
RTPSender(const int32_t id, const bool audio, Clock *clock,
|
||||||
Transport *transport, RtpAudioFeedback *audio_feedback,
|
Transport *transport, RtpAudioFeedback *audio_feedback,
|
||||||
@ -276,8 +277,6 @@ class RTPSender : public RTPSenderInterface, public Bitrate::Observer {
|
|||||||
|
|
||||||
uint32_t BitrateSent() const;
|
uint32_t BitrateSent() const;
|
||||||
|
|
||||||
virtual void BitrateUpdated(const BitrateStatistics& stats) OVERRIDE;
|
|
||||||
|
|
||||||
void SetRtpState(const RtpState& rtp_state);
|
void SetRtpState(const RtpState& rtp_state);
|
||||||
RtpState GetRtpState() const;
|
RtpState GetRtpState() const;
|
||||||
void SetRtxRtpState(const RtpState& rtp_state);
|
void SetRtxRtpState(const RtpState& rtp_state);
|
||||||
@ -337,7 +336,9 @@ class RTPSender : public RTPSenderInterface, public Bitrate::Observer {
|
|||||||
|
|
||||||
Clock* clock_;
|
Clock* clock_;
|
||||||
int64_t clock_delta_ms_;
|
int64_t clock_delta_ms_;
|
||||||
Bitrate bitrate_sent_;
|
|
||||||
|
scoped_ptr<BitrateAggregator> bitrates_;
|
||||||
|
Bitrate total_bitrate_sent_;
|
||||||
|
|
||||||
int32_t id_;
|
int32_t id_;
|
||||||
const bool audio_configured_;
|
const bool audio_configured_;
|
||||||
@ -375,7 +376,6 @@ class RTPSender : public RTPSenderInterface, public Bitrate::Observer {
|
|||||||
StreamDataCounters rtp_stats_ GUARDED_BY(statistics_crit_);
|
StreamDataCounters rtp_stats_ GUARDED_BY(statistics_crit_);
|
||||||
StreamDataCounters rtx_rtp_stats_ GUARDED_BY(statistics_crit_);
|
StreamDataCounters rtx_rtp_stats_ GUARDED_BY(statistics_crit_);
|
||||||
StreamDataCountersCallback* rtp_stats_callback_ GUARDED_BY(statistics_crit_);
|
StreamDataCountersCallback* rtp_stats_callback_ GUARDED_BY(statistics_crit_);
|
||||||
BitrateStatisticsObserver* const bitrate_callback_;
|
|
||||||
FrameCountObserver* const frame_count_observer_;
|
FrameCountObserver* const frame_count_observer_;
|
||||||
SendSideDelayObserver* const send_side_delay_observer_;
|
SendSideDelayObserver* const send_side_delay_observer_;
|
||||||
|
|
||||||
|
@ -855,20 +855,22 @@ TEST_F(RtpSenderTest, FrameCountCallbacks) {
|
|||||||
TEST_F(RtpSenderTest, BitrateCallbacks) {
|
TEST_F(RtpSenderTest, BitrateCallbacks) {
|
||||||
class TestCallback : public BitrateStatisticsObserver {
|
class TestCallback : public BitrateStatisticsObserver {
|
||||||
public:
|
public:
|
||||||
TestCallback()
|
TestCallback() : BitrateStatisticsObserver(), num_calls_(0), ssrc_(0) {}
|
||||||
: BitrateStatisticsObserver(), num_calls_(0), ssrc_(0), bitrate_() {}
|
|
||||||
virtual ~TestCallback() {}
|
virtual ~TestCallback() {}
|
||||||
|
|
||||||
virtual void Notify(const BitrateStatistics& stats,
|
virtual void Notify(const BitrateStatistics& total_stats,
|
||||||
|
const BitrateStatistics& retransmit_stats,
|
||||||
uint32_t ssrc) OVERRIDE {
|
uint32_t ssrc) OVERRIDE {
|
||||||
++num_calls_;
|
++num_calls_;
|
||||||
ssrc_ = ssrc;
|
ssrc_ = ssrc;
|
||||||
bitrate_ = stats;
|
total_stats_ = total_stats;
|
||||||
|
retransmit_stats_ = retransmit_stats;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t num_calls_;
|
uint32_t num_calls_;
|
||||||
uint32_t ssrc_;
|
uint32_t ssrc_;
|
||||||
BitrateStatistics bitrate_;
|
BitrateStatistics total_stats_;
|
||||||
|
BitrateStatistics retransmit_stats_;
|
||||||
} callback;
|
} callback;
|
||||||
rtp_sender_.reset(new RTPSender(0, false, &fake_clock_, &transport_, NULL,
|
rtp_sender_.reset(new RTPSender(0, false, &fake_clock_, &transport_, NULL,
|
||||||
&mock_paced_sender_, &callback, NULL, NULL));
|
&mock_paced_sender_, &callback, NULL, NULL));
|
||||||
@ -909,13 +911,15 @@ TEST_F(RtpSenderTest, BitrateCallbacks) {
|
|||||||
|
|
||||||
const uint32_t expected_packet_rate = 1000 / kPacketInterval;
|
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(ssrc, callback.ssrc_);
|
||||||
EXPECT_EQ(start_time + (kNumPackets * kPacketInterval),
|
EXPECT_EQ(start_time + (kNumPackets * kPacketInterval),
|
||||||
callback.bitrate_.timestamp_ms);
|
callback.total_stats_.timestamp_ms);
|
||||||
EXPECT_EQ(expected_packet_rate, callback.bitrate_.packet_rate);
|
EXPECT_EQ(expected_packet_rate, callback.total_stats_.packet_rate);
|
||||||
EXPECT_EQ((kPacketOverhead + sizeof(payload)) * 8 * expected_packet_rate,
|
EXPECT_EQ((kPacketOverhead + sizeof(payload)) * 8 * expected_packet_rate,
|
||||||
callback.bitrate_.bitrate_bps);
|
callback.total_stats_.bitrate_bps);
|
||||||
|
|
||||||
rtp_sender_.reset();
|
rtp_sender_.reset();
|
||||||
}
|
}
|
||||||
|
@ -542,7 +542,7 @@ void MediaOptimization::UpdateSentBitrate(int64_t now_ms) {
|
|||||||
now_ms - encoded_frame_samples_.front().time_complete_ms);
|
now_ms - encoded_frame_samples_.front().time_complete_ms);
|
||||||
if (denom >= 1.0f) {
|
if (denom >= 1.0f) {
|
||||||
avg_sent_bit_rate_bps_ =
|
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 {
|
} else {
|
||||||
avg_sent_bit_rate_bps_ = framesize_sum * 8;
|
avg_sent_bit_rate_bps_ = framesize_sum * 8;
|
||||||
}
|
}
|
||||||
|
@ -51,7 +51,8 @@ int32_t FakeEncoder::Encode(
|
|||||||
assert(config_.maxFramerate > 0);
|
assert(config_.maxFramerate > 0);
|
||||||
int time_since_last_encode_ms = 1000 / config_.maxFramerate;
|
int time_since_last_encode_ms = 1000 / config_.maxFramerate;
|
||||||
int64_t time_now_ms = clock_->TimeInMilliseconds();
|
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
|
// For all frames but the first we can estimate the display time by looking
|
||||||
// at the display time of the previous frame.
|
// at the display time of the previous frame.
|
||||||
time_since_last_encode_ms = time_now_ms - last_encode_time_ms_;
|
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 :
|
int stream_bits = (bits_available > max_stream_bits) ? max_stream_bits :
|
||||||
bits_available;
|
bits_available;
|
||||||
int stream_bytes = (stream_bits + 7) / 8;
|
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_))
|
if (static_cast<size_t>(stream_bytes) > sizeof(encoded_buffer_))
|
||||||
stream_bytes = sizeof(encoded_buffer_);
|
stream_bytes = sizeof(encoded_buffer_);
|
||||||
|
|
||||||
@ -96,7 +103,6 @@ int32_t FakeEncoder::Encode(
|
|||||||
assert(callback_ != NULL);
|
assert(callback_ != NULL);
|
||||||
if (callback_->Encoded(encoded, &specifics, NULL) != 0)
|
if (callback_->Encoded(encoded, &specifics, NULL) != 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
bits_available -= encoded._length * 8;
|
bits_available -= encoded._length * 8;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -114,8 +114,7 @@ class Call : public webrtc::Call, public PacketReceiver {
|
|||||||
virtual void DestroyVideoReceiveStream(
|
virtual void DestroyVideoReceiveStream(
|
||||||
webrtc::VideoReceiveStream* receive_stream) OVERRIDE;
|
webrtc::VideoReceiveStream* receive_stream) OVERRIDE;
|
||||||
|
|
||||||
virtual uint32_t SendBitrateEstimate() OVERRIDE;
|
virtual Stats GetStats() const OVERRIDE;
|
||||||
virtual uint32_t ReceiveBitrateEstimate() OVERRIDE;
|
|
||||||
|
|
||||||
virtual DeliveryStatus DeliverPacket(const uint8_t* packet,
|
virtual DeliveryStatus DeliverPacket(const uint8_t* packet,
|
||||||
size_t length) OVERRIDE;
|
size_t length) OVERRIDE;
|
||||||
@ -321,14 +320,26 @@ void Call::DestroyVideoReceiveStream(
|
|||||||
delete receive_stream_impl;
|
delete receive_stream_impl;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t Call::SendBitrateEstimate() {
|
Call::Stats Call::GetStats() const {
|
||||||
// TODO(pbos): Return send-bitrate estimate
|
Stats stats;
|
||||||
return 0;
|
// 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);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
uint32_t Call::ReceiveBitrateEstimate() {
|
return stats;
|
||||||
// TODO(pbos): Return receive-bitrate estimate
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Call::SignalNetworkState(NetworkState state) {
|
void Call::SignalNetworkState(NetworkState state) {
|
||||||
|
@ -502,7 +502,8 @@ void CallPerfTest::TestMinTransmitBitrate(bool pad_to_min_bitrate) {
|
|||||||
VideoSendStream::Stats stats = send_stream_->GetStats();
|
VideoSendStream::Stats stats = send_stream_->GetStats();
|
||||||
if (stats.substreams.size() > 0) {
|
if (stats.substreams.size() > 0) {
|
||||||
assert(stats.substreams.size() == 1);
|
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) {
|
if (bitrate_kbps > 0) {
|
||||||
test::PrintResult(
|
test::PrintResult(
|
||||||
"bitrate_stats_",
|
"bitrate_stats_",
|
||||||
|
@ -1202,6 +1202,53 @@ TEST_F(EndToEndTest, ReceiveStreamSendsRemb) {
|
|||||||
RunBaseTest(&test);
|
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) {
|
void EndToEndTest::TestXrReceiverReferenceTimeReport(bool enable_rrtr) {
|
||||||
static const int kNumRtcpReportPacketsToObserve = 5;
|
static const int kNumRtcpReportPacketsToObserve = 5;
|
||||||
class RtcpXrObserver : public test::EndToEndTest {
|
class RtcpXrObserver : public test::EndToEndTest {
|
||||||
@ -1434,7 +1481,7 @@ TEST_F(EndToEndTest, GetStats) {
|
|||||||
// Make sure all fields have been populated.
|
// Make sure all fields have been populated.
|
||||||
|
|
||||||
receive_stats_filled_["IncomingRate"] |=
|
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;
|
receive_stats_filled_["FrameCallback"] |= stats.decode_frame_rate != 0;
|
||||||
|
|
||||||
@ -1465,7 +1512,7 @@ TEST_F(EndToEndTest, GetStats) {
|
|||||||
send_stats_filled_["NumStreams"] |=
|
send_stats_filled_["NumStreams"] |=
|
||||||
stats.substreams.size() == expected_send_ssrcs_.size();
|
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();
|
stats.substreams.begin();
|
||||||
it != stats.substreams.end();
|
it != stats.substreams.end();
|
||||||
++it) {
|
++it) {
|
||||||
@ -1475,7 +1522,7 @@ TEST_F(EndToEndTest, GetStats) {
|
|||||||
send_stats_filled_[CompoundKey("IncomingRate", it->first)] |=
|
send_stats_filled_[CompoundKey("IncomingRate", it->first)] |=
|
||||||
stats.input_frame_rate != 0;
|
stats.input_frame_rate != 0;
|
||||||
|
|
||||||
const StreamStats& stream_stats = it->second;
|
const SsrcStats& stream_stats = it->second;
|
||||||
|
|
||||||
send_stats_filled_[CompoundKey("StatisticsUpdated", it->first)] |=
|
send_stats_filled_[CompoundKey("StatisticsUpdated", it->first)] |=
|
||||||
stream_stats.rtcp_stats.cumulative_lost != 0 ||
|
stream_stats.rtcp_stats.cumulative_lost != 0 ||
|
||||||
@ -1490,7 +1537,7 @@ TEST_F(EndToEndTest, GetStats) {
|
|||||||
|
|
||||||
send_stats_filled_[CompoundKey("BitrateStatisticsObserver",
|
send_stats_filled_[CompoundKey("BitrateStatisticsObserver",
|
||||||
it->first)] |=
|
it->first)] |=
|
||||||
stream_stats.bitrate_bps != 0;
|
stream_stats.total_bitrate_bps != 0;
|
||||||
|
|
||||||
send_stats_filled_[CompoundKey("FrameCountObserver", it->first)] |=
|
send_stats_filled_[CompoundKey("FrameCountObserver", it->first)] |=
|
||||||
stream_stats.delta_frames != 0 || stream_stats.key_frames != 0;
|
stream_stats.delta_frames != 0 || stream_stats.key_frames != 0;
|
||||||
|
@ -58,10 +58,10 @@ std::string ReceiveStatisticsProxy::GetCName() const {
|
|||||||
|
|
||||||
void ReceiveStatisticsProxy::IncomingRate(const int video_channel,
|
void ReceiveStatisticsProxy::IncomingRate(const int video_channel,
|
||||||
const unsigned int framerate,
|
const unsigned int framerate,
|
||||||
const unsigned int bitrate) {
|
const unsigned int bitrate_bps) {
|
||||||
CriticalSectionScoped lock(crit_.get());
|
CriticalSectionScoped lock(crit_.get());
|
||||||
stats_.network_frame_rate = framerate;
|
stats_.network_frame_rate = framerate;
|
||||||
stats_.bitrate_bps = bitrate;
|
stats_.total_bitrate_bps = bitrate_bps;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReceiveStatisticsProxy::StatisticsUpdated(
|
void ReceiveStatisticsProxy::StatisticsUpdated(
|
||||||
|
@ -52,7 +52,7 @@ class ReceiveStatisticsProxy : public ViEDecoderObserver,
|
|||||||
const VideoCodec& video_codec) OVERRIDE {}
|
const VideoCodec& video_codec) OVERRIDE {}
|
||||||
virtual void IncomingRate(const int video_channel,
|
virtual void IncomingRate(const int video_channel,
|
||||||
const unsigned int framerate,
|
const unsigned int framerate,
|
||||||
const unsigned int bitrate) OVERRIDE;
|
const unsigned int bitrate_bps) OVERRIDE;
|
||||||
virtual void DecoderTiming(int decode_ms,
|
virtual void DecoderTiming(int decode_ms,
|
||||||
int max_decode_ms,
|
int max_decode_ms,
|
||||||
int current_delay_ms,
|
int current_delay_ms,
|
||||||
|
@ -29,6 +29,7 @@ void SendStatisticsProxy::OutgoingRate(const int video_channel,
|
|||||||
const unsigned int bitrate) {
|
const unsigned int bitrate) {
|
||||||
CriticalSectionScoped lock(crit_.get());
|
CriticalSectionScoped lock(crit_.get());
|
||||||
stats_.encode_frame_rate = framerate;
|
stats_.encode_frame_rate = framerate;
|
||||||
|
stats_.media_bitrate_bps = bitrate;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SendStatisticsProxy::SuspendChange(int video_channel, bool is_suspended) {
|
void SendStatisticsProxy::SuspendChange(int video_channel, bool is_suspended) {
|
||||||
@ -47,8 +48,8 @@ VideoSendStream::Stats SendStatisticsProxy::GetStats() const {
|
|||||||
return stats_;
|
return stats_;
|
||||||
}
|
}
|
||||||
|
|
||||||
StreamStats* SendStatisticsProxy::GetStatsEntry(uint32_t ssrc) {
|
SsrcStats* SendStatisticsProxy::GetStatsEntry(uint32_t ssrc) {
|
||||||
std::map<uint32_t, StreamStats>::iterator it = stats_.substreams.find(ssrc);
|
std::map<uint32_t, SsrcStats>::iterator it = stats_.substreams.find(ssrc);
|
||||||
if (it != stats_.substreams.end())
|
if (it != stats_.substreams.end())
|
||||||
return &it->second;
|
return &it->second;
|
||||||
|
|
||||||
@ -66,7 +67,7 @@ StreamStats* SendStatisticsProxy::GetStatsEntry(uint32_t ssrc) {
|
|||||||
void SendStatisticsProxy::StatisticsUpdated(const RtcpStatistics& statistics,
|
void SendStatisticsProxy::StatisticsUpdated(const RtcpStatistics& statistics,
|
||||||
uint32_t ssrc) {
|
uint32_t ssrc) {
|
||||||
CriticalSectionScoped lock(crit_.get());
|
CriticalSectionScoped lock(crit_.get());
|
||||||
StreamStats* stats = GetStatsEntry(ssrc);
|
SsrcStats* stats = GetStatsEntry(ssrc);
|
||||||
if (stats == NULL)
|
if (stats == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -77,28 +78,30 @@ void SendStatisticsProxy::DataCountersUpdated(
|
|||||||
const StreamDataCounters& counters,
|
const StreamDataCounters& counters,
|
||||||
uint32_t ssrc) {
|
uint32_t ssrc) {
|
||||||
CriticalSectionScoped lock(crit_.get());
|
CriticalSectionScoped lock(crit_.get());
|
||||||
StreamStats* stats = GetStatsEntry(ssrc);
|
SsrcStats* stats = GetStatsEntry(ssrc);
|
||||||
if (stats == NULL)
|
if (stats == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
stats->rtp_stats = counters;
|
stats->rtp_stats = counters;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SendStatisticsProxy::Notify(const BitrateStatistics& bitrate,
|
void SendStatisticsProxy::Notify(const BitrateStatistics& total_stats,
|
||||||
|
const BitrateStatistics& retransmit_stats,
|
||||||
uint32_t ssrc) {
|
uint32_t ssrc) {
|
||||||
CriticalSectionScoped lock(crit_.get());
|
CriticalSectionScoped lock(crit_.get());
|
||||||
StreamStats* stats = GetStatsEntry(ssrc);
|
SsrcStats* stats = GetStatsEntry(ssrc);
|
||||||
if (stats == NULL)
|
if (stats == NULL)
|
||||||
return;
|
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,
|
void SendStatisticsProxy::FrameCountUpdated(FrameType frame_type,
|
||||||
uint32_t frame_count,
|
uint32_t frame_count,
|
||||||
const unsigned int ssrc) {
|
const unsigned int ssrc) {
|
||||||
CriticalSectionScoped lock(crit_.get());
|
CriticalSectionScoped lock(crit_.get());
|
||||||
StreamStats* stats = GetStatsEntry(ssrc);
|
SsrcStats* stats = GetStatsEntry(ssrc);
|
||||||
if (stats == NULL)
|
if (stats == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -120,7 +123,7 @@ void SendStatisticsProxy::SendSideDelayUpdated(int avg_delay_ms,
|
|||||||
int max_delay_ms,
|
int max_delay_ms,
|
||||||
uint32_t ssrc) {
|
uint32_t ssrc) {
|
||||||
CriticalSectionScoped lock(crit_.get());
|
CriticalSectionScoped lock(crit_.get());
|
||||||
StreamStats* stats = GetStatsEntry(ssrc);
|
SsrcStats* stats = GetStatsEntry(ssrc);
|
||||||
if (stats == NULL)
|
if (stats == NULL)
|
||||||
return;
|
return;
|
||||||
stats->avg_delay_ms = avg_delay_ms;
|
stats->avg_delay_ms = avg_delay_ms;
|
||||||
|
@ -46,7 +46,9 @@ class SendStatisticsProxy : public RtcpStatisticsCallback,
|
|||||||
uint32_t ssrc) OVERRIDE;
|
uint32_t ssrc) OVERRIDE;
|
||||||
|
|
||||||
// From BitrateStatisticsObserver.
|
// 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.
|
// From FrameCountObserver.
|
||||||
virtual void FrameCountUpdated(FrameType frame_type,
|
virtual void FrameCountUpdated(FrameType frame_type,
|
||||||
@ -75,7 +77,7 @@ class SendStatisticsProxy : public RtcpStatisticsCallback,
|
|||||||
uint32_t ssrc) OVERRIDE;
|
uint32_t ssrc) OVERRIDE;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
StreamStats* GetStatsEntry(uint32_t ssrc) EXCLUSIVE_LOCKS_REQUIRED(crit_);
|
SsrcStats* GetStatsEntry(uint32_t ssrc) EXCLUSIVE_LOCKS_REQUIRED(crit_);
|
||||||
|
|
||||||
const VideoSendStream::Config config_;
|
const VideoSendStream::Config config_;
|
||||||
scoped_ptr<CriticalSectionWrapper> crit_;
|
scoped_ptr<CriticalSectionWrapper> crit_;
|
||||||
|
@ -44,22 +44,23 @@ class SendStatisticsProxyTest : public ::testing::Test {
|
|||||||
void ExpectEqual(VideoSendStream::Stats one, VideoSendStream::Stats other) {
|
void ExpectEqual(VideoSendStream::Stats one, VideoSendStream::Stats other) {
|
||||||
EXPECT_EQ(one.input_frame_rate, other.input_frame_rate);
|
EXPECT_EQ(one.input_frame_rate, other.input_frame_rate);
|
||||||
EXPECT_EQ(one.encode_frame_rate, other.encode_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.suspended, other.suspended);
|
||||||
|
|
||||||
EXPECT_EQ(one.substreams.size(), other.substreams.size());
|
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();
|
one.substreams.begin();
|
||||||
it != one.substreams.end();
|
it != one.substreams.end();
|
||||||
++it) {
|
++it) {
|
||||||
std::map<uint32_t, StreamStats>::const_iterator corresponding_it =
|
std::map<uint32_t, SsrcStats>::const_iterator corresponding_it =
|
||||||
other.substreams.find(it->first);
|
other.substreams.find(it->first);
|
||||||
ASSERT_TRUE(corresponding_it != other.substreams.end());
|
ASSERT_TRUE(corresponding_it != other.substreams.end());
|
||||||
const StreamStats& a = it->second;
|
const SsrcStats& a = it->second;
|
||||||
const StreamStats& b = corresponding_it->second;
|
const SsrcStats& b = corresponding_it->second;
|
||||||
|
|
||||||
EXPECT_EQ(a.key_frames, b.key_frames);
|
EXPECT_EQ(a.key_frames, b.key_frames);
|
||||||
EXPECT_EQ(a.delta_frames, b.delta_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.avg_delay_ms, b.avg_delay_ms);
|
||||||
EXPECT_EQ(a.max_delay_ms, b.max_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 avg_delay_ms_;
|
||||||
int max_delay_ms_;
|
int max_delay_ms_;
|
||||||
VideoSendStream::Stats expected_;
|
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) {
|
TEST_F(SendStatisticsProxyTest, RtcpStatistics) {
|
||||||
@ -93,7 +94,7 @@ TEST_F(SendStatisticsProxyTest, RtcpStatistics) {
|
|||||||
it != config_.rtp.ssrcs.end();
|
it != config_.rtp.ssrcs.end();
|
||||||
++it) {
|
++it) {
|
||||||
const uint32_t ssrc = *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.
|
// Add statistics with some arbitrary, but unique, numbers.
|
||||||
uint32_t offset = ssrc * sizeof(RtcpStatistics);
|
uint32_t offset = ssrc * sizeof(RtcpStatistics);
|
||||||
@ -107,7 +108,7 @@ TEST_F(SendStatisticsProxyTest, RtcpStatistics) {
|
|||||||
it != config_.rtp.rtx.ssrcs.end();
|
it != config_.rtp.rtx.ssrcs.end();
|
||||||
++it) {
|
++it) {
|
||||||
const uint32_t ssrc = *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.
|
// Add statistics with some arbitrary, but unique, numbers.
|
||||||
uint32_t offset = ssrc * sizeof(RtcpStatistics);
|
uint32_t offset = ssrc * sizeof(RtcpStatistics);
|
||||||
@ -121,17 +122,25 @@ TEST_F(SendStatisticsProxyTest, RtcpStatistics) {
|
|||||||
ExpectEqual(expected_, stats);
|
ExpectEqual(expected_, stats);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(SendStatisticsProxyTest, FrameRates) {
|
TEST_F(SendStatisticsProxyTest, CaptureFramerate) {
|
||||||
const int capture_fps = 31;
|
const int capture_fps = 31;
|
||||||
const int encode_fps = 29;
|
|
||||||
|
|
||||||
ViECaptureObserver* capture_observer = statistics_proxy_.get();
|
ViECaptureObserver* capture_observer = statistics_proxy_.get();
|
||||||
capture_observer->CapturedFrameRate(0, capture_fps);
|
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();
|
VideoSendStream::Stats stats = statistics_proxy_->GetStats();
|
||||||
EXPECT_EQ(capture_fps, stats.input_frame_rate);
|
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);
|
EXPECT_EQ(encode_fps, stats.encode_frame_rate);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -156,8 +165,8 @@ TEST_F(SendStatisticsProxyTest, FrameCounts) {
|
|||||||
++it) {
|
++it) {
|
||||||
const uint32_t ssrc = *it;
|
const uint32_t ssrc = *it;
|
||||||
// Add statistics with some arbitrary, but unique, numbers.
|
// Add statistics with some arbitrary, but unique, numbers.
|
||||||
StreamStats& stats = expected_.substreams[ssrc];
|
SsrcStats& stats = expected_.substreams[ssrc];
|
||||||
uint32_t offset = ssrc * sizeof(StreamStats);
|
uint32_t offset = ssrc * sizeof(SsrcStats);
|
||||||
stats.key_frames = offset;
|
stats.key_frames = offset;
|
||||||
stats.delta_frames = offset + 1;
|
stats.delta_frames = offset + 1;
|
||||||
observer->FrameCountUpdated(kVideoFrameKey, stats.key_frames, ssrc);
|
observer->FrameCountUpdated(kVideoFrameKey, stats.key_frames, ssrc);
|
||||||
@ -168,8 +177,8 @@ TEST_F(SendStatisticsProxyTest, FrameCounts) {
|
|||||||
++it) {
|
++it) {
|
||||||
const uint32_t ssrc = *it;
|
const uint32_t ssrc = *it;
|
||||||
// Add statistics with some arbitrary, but unique, numbers.
|
// Add statistics with some arbitrary, but unique, numbers.
|
||||||
StreamStats& stats = expected_.substreams[ssrc];
|
SsrcStats& stats = expected_.substreams[ssrc];
|
||||||
uint32_t offset = ssrc * sizeof(StreamStats);
|
uint32_t offset = ssrc * sizeof(SsrcStats);
|
||||||
stats.key_frames = offset;
|
stats.key_frames = offset;
|
||||||
stats.delta_frames = offset + 1;
|
stats.delta_frames = offset + 1;
|
||||||
observer->FrameCountUpdated(kVideoFrameKey, stats.key_frames, ssrc);
|
observer->FrameCountUpdated(kVideoFrameKey, stats.key_frames, ssrc);
|
||||||
@ -223,21 +232,27 @@ TEST_F(SendStatisticsProxyTest, Bitrate) {
|
|||||||
it != config_.rtp.ssrcs.end();
|
it != config_.rtp.ssrcs.end();
|
||||||
++it) {
|
++it) {
|
||||||
const uint32_t ssrc = *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.
|
// Use ssrc as bitrate_bps to get a unique value for each stream.
|
||||||
bitrate.bitrate_bps = ssrc;
|
total.bitrate_bps = ssrc;
|
||||||
observer->Notify(bitrate, ssrc);
|
retransmit.bitrate_bps = ssrc + 1;
|
||||||
expected_.substreams[ssrc].bitrate_bps = ssrc;
|
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();
|
for (std::vector<uint32_t>::const_iterator it = config_.rtp.rtx.ssrcs.begin();
|
||||||
it != config_.rtp.rtx.ssrcs.end();
|
it != config_.rtp.rtx.ssrcs.end();
|
||||||
++it) {
|
++it) {
|
||||||
const uint32_t ssrc = *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.
|
// Use ssrc as bitrate_bps to get a unique value for each stream.
|
||||||
bitrate.bitrate_bps = ssrc;
|
total.bitrate_bps = ssrc;
|
||||||
observer->Notify(bitrate, ssrc);
|
retransmit.bitrate_bps = ssrc + 1;
|
||||||
expected_.substreams[ssrc].bitrate_bps = ssrc;
|
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();
|
VideoSendStream::Stats stats = statistics_proxy_->GetStats();
|
||||||
@ -292,9 +307,10 @@ TEST_F(SendStatisticsProxyTest, NoSubstreams) {
|
|||||||
rtp_callback->DataCountersUpdated(rtp_stats, exluded_ssrc);
|
rtp_callback->DataCountersUpdated(rtp_stats, exluded_ssrc);
|
||||||
|
|
||||||
// From BitrateStatisticsObserver.
|
// From BitrateStatisticsObserver.
|
||||||
BitrateStatistics bitrate;
|
BitrateStatistics total;
|
||||||
|
BitrateStatistics retransmit;
|
||||||
BitrateStatisticsObserver* bitrate_observer = statistics_proxy_.get();
|
BitrateStatisticsObserver* bitrate_observer = statistics_proxy_.get();
|
||||||
bitrate_observer->Notify(bitrate, exluded_ssrc);
|
bitrate_observer->Notify(total, retransmit, exluded_ssrc);
|
||||||
|
|
||||||
// From FrameCountObserver.
|
// From FrameCountObserver.
|
||||||
FrameCountObserver* fps_observer = statistics_proxy_.get();
|
FrameCountObserver* fps_observer = statistics_proxy_.get();
|
||||||
|
@ -492,5 +492,12 @@ void VideoSendStream::SignalNetworkState(Call::NetworkState state) {
|
|||||||
rtp_rtcp_->SetRTCPStatus(channel_, kRtcpNone);
|
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 internal
|
||||||
} // namespace webrtc
|
} // namespace webrtc
|
||||||
|
@ -74,6 +74,8 @@ class VideoSendStream : public webrtc::VideoSendStream,
|
|||||||
|
|
||||||
void SignalNetworkState(Call::NetworkState state);
|
void SignalNetworkState(Call::NetworkState state);
|
||||||
|
|
||||||
|
int GetPacerQueuingDelayMs() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void ConfigureSsrcs();
|
void ConfigureSsrcs();
|
||||||
TransportAdapter transport_adapter_;
|
TransportAdapter transport_adapter_;
|
||||||
|
@ -962,8 +962,8 @@ TEST_F(VideoSendStreamTest, ProducesStats) {
|
|||||||
config_.rtp.ssrcs.begin(), config_.rtp.ssrcs.end(), ssrc));
|
config_.rtp.ssrcs.begin(), config_.rtp.ssrcs.end(), ssrc));
|
||||||
// Check for data populated by various sources. RTCP excluded as this
|
// Check for data populated by various sources. RTCP excluded as this
|
||||||
// data is received from remote side. Tested in call tests instead.
|
// data is received from remote side. Tested in call tests instead.
|
||||||
const StreamStats& entry = stats.substreams[ssrc];
|
const SsrcStats& entry = stats.substreams[ssrc];
|
||||||
if (entry.key_frames > 0u && entry.bitrate_bps > 0 &&
|
if (entry.key_frames > 0u && entry.total_bitrate_bps > 0 &&
|
||||||
entry.rtp_stats.packets > 0u && entry.avg_delay_ms > 0 &&
|
entry.rtp_stats.packets > 0u && entry.avg_delay_ms > 0 &&
|
||||||
entry.max_delay_ms > 0) {
|
entry.max_delay_ms > 0) {
|
||||||
return true;
|
return true;
|
||||||
@ -1045,20 +1045,20 @@ TEST_F(VideoSendStreamTest, MinTransmitBitrateRespectsRemb) {
|
|||||||
VideoSendStream::Stats stats = stream_->GetStats();
|
VideoSendStream::Stats stats = stream_->GetStats();
|
||||||
if (!stats.substreams.empty()) {
|
if (!stats.substreams.empty()) {
|
||||||
EXPECT_EQ(1u, stats.substreams.size());
|
EXPECT_EQ(1u, stats.substreams.size());
|
||||||
int bitrate_bps = stats.substreams.begin()->second.bitrate_bps;
|
int total_bitrate_bps =
|
||||||
test::PrintResult(
|
stats.substreams.begin()->second.total_bitrate_bps;
|
||||||
"bitrate_stats_",
|
test::PrintResult("bitrate_stats_",
|
||||||
"min_transmit_bitrate_low_remb",
|
"min_transmit_bitrate_low_remb",
|
||||||
"bitrate_bps",
|
"bitrate_bps",
|
||||||
static_cast<size_t>(bitrate_bps),
|
static_cast<size_t>(total_bitrate_bps),
|
||||||
"bps",
|
"bps",
|
||||||
false);
|
false);
|
||||||
if (bitrate_bps > kHighBitrateBps) {
|
if (total_bitrate_bps > kHighBitrateBps) {
|
||||||
rtp_rtcp_->SetREMBData(kRembBitrateBps, 1, &header.ssrc);
|
rtp_rtcp_->SetREMBData(kRembBitrateBps, 1, &header.ssrc);
|
||||||
rtp_rtcp_->Process();
|
rtp_rtcp_->Process();
|
||||||
bitrate_capped_ = true;
|
bitrate_capped_ = true;
|
||||||
} else if (bitrate_capped_ &&
|
} else if (bitrate_capped_ &&
|
||||||
bitrate_bps < kRembRespectedBitrateBps) {
|
total_bitrate_bps < kRembRespectedBitrateBps) {
|
||||||
observation_complete_->Set();
|
observation_complete_->Set();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -415,10 +415,12 @@ class ViEChannel
|
|||||||
|
|
||||||
class RegisterableBitrateStatisticsObserver:
|
class RegisterableBitrateStatisticsObserver:
|
||||||
public RegisterableCallback<BitrateStatisticsObserver> {
|
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());
|
CriticalSectionScoped cs(critsect_.get());
|
||||||
if (callback_)
|
if (callback_)
|
||||||
callback_->Notify(stats, ssrc);
|
callback_->Notify(total_stats, retransmit_stats, ssrc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
send_bitrate_observer_;
|
send_bitrate_observer_;
|
||||||
|
@ -63,7 +63,7 @@ class VideoReceiveStream {
|
|||||||
int expected_delay_ms;
|
int expected_delay_ms;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Stats : public StreamStats {
|
struct Stats : public SsrcStats {
|
||||||
Stats()
|
Stats()
|
||||||
: network_frame_rate(0),
|
: network_frame_rate(0),
|
||||||
decode_frame_rate(0),
|
decode_frame_rate(0),
|
||||||
|
@ -41,11 +41,13 @@ class VideoSendStream {
|
|||||||
Stats()
|
Stats()
|
||||||
: input_frame_rate(0),
|
: input_frame_rate(0),
|
||||||
encode_frame_rate(0),
|
encode_frame_rate(0),
|
||||||
|
media_bitrate_bps(0),
|
||||||
suspended(false) {}
|
suspended(false) {}
|
||||||
int input_frame_rate;
|
int input_frame_rate;
|
||||||
int encode_frame_rate;
|
int encode_frame_rate;
|
||||||
|
int media_bitrate_bps;
|
||||||
bool suspended;
|
bool suspended;
|
||||||
std::map<uint32_t, StreamStats> substreams;
|
std::map<uint32_t, SsrcStats> substreams;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Config {
|
struct Config {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user