Fix standard GetStats to not modify NetEq state.
Add a get_and_clear_legacy_stats flag to AudioReceiveStream::GetStats, to distinguish calls from standard GetStats and legacy GetStats. Add const method NetEq::CurrentNetworkStatistics to get current values of stateless NetEq stats. Standard GetStats will then call this method instead of NetEq::NetworkStatistics. Bug: webrtc:11622 Change-Id: I3833a246a9e39b18c99657a738da22c6e2bd5f5e Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/183600 Commit-Queue: Niels Moller <nisse@webrtc.org> Reviewed-by: Henrik Boström <hbos@webrtc.org> Reviewed-by: Karl Wiberg <kwiberg@webrtc.org> Reviewed-by: Ivo Creusen <ivoc@webrtc.org> Cr-Commit-Position: refs/heads/master@{#32092}
This commit is contained in:
@ -244,26 +244,45 @@ absl::optional<std::pair<int, SdpAudioFormat>> AcmReceiver::LastDecoder()
|
||||
return std::make_pair(last_decoder_->payload_type, last_decoder_->sdp_format);
|
||||
}
|
||||
|
||||
void AcmReceiver::GetNetworkStatistics(NetworkStatistics* acm_stat) const {
|
||||
void AcmReceiver::GetNetworkStatistics(
|
||||
NetworkStatistics* acm_stat,
|
||||
bool get_and_clear_legacy_stats /* = true */) const {
|
||||
NetEqNetworkStatistics neteq_stat;
|
||||
// NetEq function always returns zero, so we don't check the return value.
|
||||
neteq_->NetworkStatistics(&neteq_stat);
|
||||
if (get_and_clear_legacy_stats) {
|
||||
// NetEq function always returns zero, so we don't check the return value.
|
||||
neteq_->NetworkStatistics(&neteq_stat);
|
||||
|
||||
acm_stat->currentPacketLossRate = neteq_stat.packet_loss_rate;
|
||||
acm_stat->currentExpandRate = neteq_stat.expand_rate;
|
||||
acm_stat->currentSpeechExpandRate = neteq_stat.speech_expand_rate;
|
||||
acm_stat->currentPreemptiveRate = neteq_stat.preemptive_rate;
|
||||
acm_stat->currentAccelerateRate = neteq_stat.accelerate_rate;
|
||||
acm_stat->currentSecondaryDecodedRate = neteq_stat.secondary_decoded_rate;
|
||||
acm_stat->currentSecondaryDiscardedRate =
|
||||
neteq_stat.secondary_discarded_rate;
|
||||
acm_stat->addedSamples = neteq_stat.added_zero_samples;
|
||||
acm_stat->meanWaitingTimeMs = neteq_stat.mean_waiting_time_ms;
|
||||
acm_stat->medianWaitingTimeMs = neteq_stat.median_waiting_time_ms;
|
||||
acm_stat->minWaitingTimeMs = neteq_stat.min_waiting_time_ms;
|
||||
acm_stat->maxWaitingTimeMs = neteq_stat.max_waiting_time_ms;
|
||||
} else {
|
||||
neteq_stat = neteq_->CurrentNetworkStatistics();
|
||||
acm_stat->currentPacketLossRate = 0;
|
||||
acm_stat->currentExpandRate = 0;
|
||||
acm_stat->currentSpeechExpandRate = 0;
|
||||
acm_stat->currentPreemptiveRate = 0;
|
||||
acm_stat->currentAccelerateRate = 0;
|
||||
acm_stat->currentSecondaryDecodedRate = 0;
|
||||
acm_stat->currentSecondaryDiscardedRate = 0;
|
||||
acm_stat->addedSamples = 0;
|
||||
acm_stat->meanWaitingTimeMs = -1;
|
||||
acm_stat->medianWaitingTimeMs = -1;
|
||||
acm_stat->minWaitingTimeMs = -1;
|
||||
acm_stat->maxWaitingTimeMs = 1;
|
||||
}
|
||||
acm_stat->currentBufferSize = neteq_stat.current_buffer_size_ms;
|
||||
acm_stat->preferredBufferSize = neteq_stat.preferred_buffer_size_ms;
|
||||
acm_stat->jitterPeaksFound = neteq_stat.jitter_peaks_found ? true : false;
|
||||
acm_stat->currentPacketLossRate = neteq_stat.packet_loss_rate;
|
||||
acm_stat->currentExpandRate = neteq_stat.expand_rate;
|
||||
acm_stat->currentSpeechExpandRate = neteq_stat.speech_expand_rate;
|
||||
acm_stat->currentPreemptiveRate = neteq_stat.preemptive_rate;
|
||||
acm_stat->currentAccelerateRate = neteq_stat.accelerate_rate;
|
||||
acm_stat->currentSecondaryDecodedRate = neteq_stat.secondary_decoded_rate;
|
||||
acm_stat->currentSecondaryDiscardedRate = neteq_stat.secondary_discarded_rate;
|
||||
acm_stat->addedSamples = neteq_stat.added_zero_samples;
|
||||
acm_stat->meanWaitingTimeMs = neteq_stat.mean_waiting_time_ms;
|
||||
acm_stat->medianWaitingTimeMs = neteq_stat.median_waiting_time_ms;
|
||||
acm_stat->minWaitingTimeMs = neteq_stat.min_waiting_time_ms;
|
||||
acm_stat->maxWaitingTimeMs = neteq_stat.max_waiting_time_ms;
|
||||
|
||||
NetEqLifetimeStatistics neteq_lifetime_stat = neteq_->GetLifetimeStatistics();
|
||||
acm_stat->totalSamplesReceived = neteq_lifetime_stat.total_samples_received;
|
||||
|
||||
@ -138,7 +138,8 @@ class AcmReceiver {
|
||||
// Output:
|
||||
// - statistics : The current network statistics.
|
||||
//
|
||||
void GetNetworkStatistics(NetworkStatistics* statistics) const;
|
||||
void GetNetworkStatistics(NetworkStatistics* statistics,
|
||||
bool get_and_clear_legacy_stats = true) const;
|
||||
|
||||
//
|
||||
// Flushes the NetEq packet and speech buffers.
|
||||
|
||||
@ -387,17 +387,9 @@ int NetEqImpl::FilteredCurrentDelayMs() const {
|
||||
int NetEqImpl::NetworkStatistics(NetEqNetworkStatistics* stats) {
|
||||
MutexLock lock(&mutex_);
|
||||
assert(decoder_database_.get());
|
||||
const size_t total_samples_in_buffers =
|
||||
packet_buffer_->NumSamplesInBuffer(decoder_frame_length_) +
|
||||
sync_buffer_->FutureLength();
|
||||
assert(controller_.get());
|
||||
stats->preferred_buffer_size_ms = controller_->TargetLevelMs();
|
||||
stats->jitter_peaks_found = controller_->PeakFound();
|
||||
stats_->GetNetworkStatistics(fs_hz_, total_samples_in_buffers,
|
||||
decoder_frame_length_, stats);
|
||||
*stats = CurrentNetworkStatisticsInternal();
|
||||
stats_->GetNetworkStatistics(decoder_frame_length_, stats);
|
||||
// Compensate for output delay chain.
|
||||
stats->current_buffer_size_ms += output_delay_chain_ms_;
|
||||
stats->preferred_buffer_size_ms += output_delay_chain_ms_;
|
||||
stats->mean_waiting_time_ms += output_delay_chain_ms_;
|
||||
stats->median_waiting_time_ms += output_delay_chain_ms_;
|
||||
stats->min_waiting_time_ms += output_delay_chain_ms_;
|
||||
@ -405,6 +397,31 @@ int NetEqImpl::NetworkStatistics(NetEqNetworkStatistics* stats) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
NetEqNetworkStatistics NetEqImpl::CurrentNetworkStatistics() const {
|
||||
MutexLock lock(&mutex_);
|
||||
return CurrentNetworkStatisticsInternal();
|
||||
}
|
||||
|
||||
NetEqNetworkStatistics NetEqImpl::CurrentNetworkStatisticsInternal() const {
|
||||
assert(decoder_database_.get());
|
||||
NetEqNetworkStatistics stats;
|
||||
const size_t total_samples_in_buffers =
|
||||
packet_buffer_->NumSamplesInBuffer(decoder_frame_length_) +
|
||||
sync_buffer_->FutureLength();
|
||||
|
||||
assert(controller_.get());
|
||||
stats.preferred_buffer_size_ms = controller_->TargetLevelMs();
|
||||
stats.jitter_peaks_found = controller_->PeakFound();
|
||||
RTC_DCHECK_GT(fs_hz_, 0);
|
||||
stats.current_buffer_size_ms =
|
||||
static_cast<uint16_t>(total_samples_in_buffers * 1000 / fs_hz_);
|
||||
|
||||
// Compensate for output delay chain.
|
||||
stats.current_buffer_size_ms += output_delay_chain_ms_;
|
||||
stats.preferred_buffer_size_ms += output_delay_chain_ms_;
|
||||
return stats;
|
||||
}
|
||||
|
||||
NetEqLifetimeStatistics NetEqImpl::GetLifetimeStatistics() const {
|
||||
MutexLock lock(&mutex_);
|
||||
return stats_->GetLifetimeStatistics();
|
||||
|
||||
@ -162,6 +162,8 @@ class NetEqImpl : public webrtc::NetEq {
|
||||
// after the call.
|
||||
int NetworkStatistics(NetEqNetworkStatistics* stats) override;
|
||||
|
||||
NetEqNetworkStatistics CurrentNetworkStatistics() const override;
|
||||
|
||||
NetEqLifetimeStatistics GetLifetimeStatistics() const override;
|
||||
|
||||
NetEqOperationsAndState GetOperationsAndState() const override;
|
||||
@ -330,6 +332,9 @@ class NetEqImpl : public webrtc::NetEq {
|
||||
virtual void UpdatePlcComponents(int fs_hz, size_t channels)
|
||||
RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
|
||||
|
||||
NetEqNetworkStatistics CurrentNetworkStatisticsInternal() const
|
||||
RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
|
||||
|
||||
Clock* const clock_;
|
||||
|
||||
mutable Mutex mutex_;
|
||||
|
||||
@ -312,16 +312,11 @@ void StatisticsCalculator::StoreWaitingTime(int waiting_time_ms) {
|
||||
operations_and_state_.last_waiting_time_ms = waiting_time_ms;
|
||||
}
|
||||
|
||||
void StatisticsCalculator::GetNetworkStatistics(int fs_hz,
|
||||
size_t num_samples_in_buffers,
|
||||
size_t samples_per_packet,
|
||||
void StatisticsCalculator::GetNetworkStatistics(size_t samples_per_packet,
|
||||
NetEqNetworkStatistics* stats) {
|
||||
RTC_DCHECK_GT(fs_hz, 0);
|
||||
RTC_DCHECK(stats);
|
||||
|
||||
stats->added_zero_samples = 0;
|
||||
stats->current_buffer_size_ms =
|
||||
static_cast<uint16_t>(num_samples_in_buffers * 1000 / fs_hz);
|
||||
|
||||
stats->packet_loss_rate =
|
||||
CalculateQ14Ratio(lost_timestamps_, timestamps_since_last_report_);
|
||||
|
||||
@ -104,15 +104,11 @@ class StatisticsCalculator {
|
||||
// period caused not by an actual packet loss, but by a delayed packet.
|
||||
virtual void LogDelayedPacketOutageEvent(int num_samples, int fs_hz);
|
||||
|
||||
// Returns the current network statistics in |stats|. The current sample rate
|
||||
// is |fs_hz|, the total number of samples in packet buffer and sync buffer
|
||||
// yet to play out is |num_samples_in_buffers|, and the number of samples per
|
||||
// packet is |samples_per_packet|. The method does not populate
|
||||
// Returns the current network statistics in |stats|. The number of samples
|
||||
// per packet is |samples_per_packet|. The method does not populate
|
||||
// |preferred_buffer_size_ms|, |jitter_peaks_found| or |clockdrift_ppm|; use
|
||||
// the PopulateDelayManagerStats method for those.
|
||||
void GetNetworkStatistics(int fs_hz,
|
||||
size_t num_samples_in_buffers,
|
||||
size_t samples_per_packet,
|
||||
void GetNetworkStatistics(size_t samples_per_packet,
|
||||
NetEqNetworkStatistics* stats);
|
||||
|
||||
// Returns a copy of this class's lifetime statistics. These statistics are
|
||||
|
||||
@ -70,14 +70,11 @@ TEST(StatisticsCalculator, ExpandedSamplesCorrection) {
|
||||
constexpr int k10MsSamples = kSampleRateHz / 100;
|
||||
constexpr int kPacketSizeMs = 20;
|
||||
constexpr size_t kSamplesPerPacket = kPacketSizeMs * kSampleRateHz / 1000;
|
||||
// Assume 2 packets in the buffer.
|
||||
constexpr size_t kNumSamplesInBuffer = 2 * kSamplesPerPacket;
|
||||
|
||||
// Advance time by 10 ms.
|
||||
stats.IncreaseCounter(k10MsSamples, kSampleRateHz);
|
||||
|
||||
stats.GetNetworkStatistics(kSampleRateHz, kNumSamplesInBuffer,
|
||||
kSamplesPerPacket, &stats_output);
|
||||
stats.GetNetworkStatistics(kSamplesPerPacket, &stats_output);
|
||||
|
||||
EXPECT_EQ(0u, stats_output.expand_rate);
|
||||
EXPECT_EQ(0u, stats_output.speech_expand_rate);
|
||||
@ -86,8 +83,7 @@ TEST(StatisticsCalculator, ExpandedSamplesCorrection) {
|
||||
stats.ExpandedVoiceSamplesCorrection(-100);
|
||||
stats.ExpandedNoiseSamplesCorrection(-100);
|
||||
stats.IncreaseCounter(k10MsSamples, kSampleRateHz);
|
||||
stats.GetNetworkStatistics(kSampleRateHz, kNumSamplesInBuffer,
|
||||
kSamplesPerPacket, &stats_output);
|
||||
stats.GetNetworkStatistics(kSamplesPerPacket, &stats_output);
|
||||
// Expect no change, since negative values are disallowed.
|
||||
EXPECT_EQ(0u, stats_output.expand_rate);
|
||||
EXPECT_EQ(0u, stats_output.speech_expand_rate);
|
||||
@ -96,8 +92,7 @@ TEST(StatisticsCalculator, ExpandedSamplesCorrection) {
|
||||
stats.ExpandedVoiceSamplesCorrection(50);
|
||||
stats.ExpandedNoiseSamplesCorrection(200);
|
||||
stats.IncreaseCounter(k10MsSamples, kSampleRateHz);
|
||||
stats.GetNetworkStatistics(kSampleRateHz, kNumSamplesInBuffer,
|
||||
kSamplesPerPacket, &stats_output);
|
||||
stats.GetNetworkStatistics(kSamplesPerPacket, &stats_output);
|
||||
// Calculate expected rates in Q14. Expand rate is noise + voice, while
|
||||
// speech expand rate is only voice.
|
||||
EXPECT_EQ(((50u + 200u) << 14) / k10MsSamples, stats_output.expand_rate);
|
||||
|
||||
Reference in New Issue
Block a user