/* * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/audio_coding/neteq/tools/neteq_stats_getter.h" #include #include #include #include "rtc_base/checks.h" #include "rtc_base/strings/string_builder.h" #include "rtc_base/time_utils.h" namespace webrtc { namespace test { std::string NetEqStatsGetter::ConcealmentEvent::ToString() const { char ss_buf[256]; rtc::SimpleStringBuilder ss(ss_buf); ss << "ConcealmentEvent duration_ms:" << duration_ms << " event_number:" << concealment_event_number << " time_from_previous_event_end_ms:" << time_from_previous_event_end_ms; return ss.str(); } NetEqStatsGetter::NetEqStatsGetter( std::unique_ptr delay_analyzer) : delay_analyzer_(std::move(delay_analyzer)) {} void NetEqStatsGetter::BeforeGetAudio(NetEq* neteq) { if (delay_analyzer_) { delay_analyzer_->BeforeGetAudio(neteq); } } void NetEqStatsGetter::AfterGetAudio(int64_t time_now_ms, const AudioFrame& audio_frame, bool muted, NetEq* neteq) { // TODO(minyue): Get stats should better not be called as a call back after // get audio. It is called independently from get audio in practice. const auto lifetime_stat = neteq->GetLifetimeStatistics(); if (last_stats_query_time_ms_ == 0 || rtc::TimeDiff(time_now_ms, last_stats_query_time_ms_) >= stats_query_interval_ms_) { NetEqNetworkStatistics stats; RTC_CHECK_EQ(neteq->NetworkStatistics(&stats), 0); stats_.push_back(std::make_pair(time_now_ms, stats)); lifetime_stats_.push_back(std::make_pair(time_now_ms, lifetime_stat)); last_stats_query_time_ms_ = time_now_ms; } const auto voice_concealed_samples = lifetime_stat.concealed_samples - lifetime_stat.silent_concealed_samples; if (current_concealment_event_ != lifetime_stat.concealment_events && voice_concealed_samples_until_last_event_ < voice_concealed_samples) { if (last_event_end_time_ms_ > 0) { // Do not account for the first event to avoid start of the call // skewing. ConcealmentEvent concealment_event; uint64_t last_event_voice_concealed_samples = voice_concealed_samples - voice_concealed_samples_until_last_event_; RTC_CHECK_GT(last_event_voice_concealed_samples, 0); concealment_event.duration_ms = last_event_voice_concealed_samples / (audio_frame.sample_rate_hz_ / 1000); concealment_event.concealment_event_number = current_concealment_event_; concealment_event.time_from_previous_event_end_ms = time_now_ms - last_event_end_time_ms_; concealment_events_.emplace_back(concealment_event); voice_concealed_samples_until_last_event_ = voice_concealed_samples; } last_event_end_time_ms_ = time_now_ms; voice_concealed_samples_until_last_event_ = voice_concealed_samples; current_concealment_event_ = lifetime_stat.concealment_events; } if (delay_analyzer_) { delay_analyzer_->AfterGetAudio(time_now_ms, audio_frame, muted, neteq); } } double NetEqStatsGetter::AverageSpeechExpandRate() const { double sum_speech_expand = std::accumulate( stats_.begin(), stats_.end(), double{0.0}, [](double a, std::pair b) { return a + static_cast(b.second.speech_expand_rate); }); return sum_speech_expand / 16384.0 / stats_.size(); } NetEqStatsGetter::Stats NetEqStatsGetter::AverageStats() const { Stats sum_stats = std::accumulate( stats_.begin(), stats_.end(), Stats(), [](Stats a, std::pair bb) { const auto& b = bb.second; a.current_buffer_size_ms += b.current_buffer_size_ms; a.preferred_buffer_size_ms += b.preferred_buffer_size_ms; a.jitter_peaks_found += b.jitter_peaks_found; a.packet_loss_rate += b.packet_loss_rate / 16384.0; a.expand_rate += b.expand_rate / 16384.0; a.speech_expand_rate += b.speech_expand_rate / 16384.0; a.preemptive_rate += b.preemptive_rate / 16384.0; a.accelerate_rate += b.accelerate_rate / 16384.0; a.secondary_decoded_rate += b.secondary_decoded_rate / 16384.0; a.secondary_discarded_rate += b.secondary_discarded_rate / 16384.0; a.added_zero_samples += b.added_zero_samples; a.mean_waiting_time_ms += b.mean_waiting_time_ms; a.median_waiting_time_ms += b.median_waiting_time_ms; a.min_waiting_time_ms = std::min( a.min_waiting_time_ms, static_cast(b.min_waiting_time_ms)); a.max_waiting_time_ms = std::max( a.max_waiting_time_ms, static_cast(b.max_waiting_time_ms)); return a; }); sum_stats.current_buffer_size_ms /= stats_.size(); sum_stats.preferred_buffer_size_ms /= stats_.size(); sum_stats.jitter_peaks_found /= stats_.size(); sum_stats.packet_loss_rate /= stats_.size(); sum_stats.expand_rate /= stats_.size(); sum_stats.speech_expand_rate /= stats_.size(); sum_stats.preemptive_rate /= stats_.size(); sum_stats.accelerate_rate /= stats_.size(); sum_stats.secondary_decoded_rate /= stats_.size(); sum_stats.secondary_discarded_rate /= stats_.size(); sum_stats.added_zero_samples /= stats_.size(); sum_stats.mean_waiting_time_ms /= stats_.size(); sum_stats.median_waiting_time_ms /= stats_.size(); return sum_stats; } } // namespace test } // namespace webrtc