1 /*
2 * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #include "modules/audio_coding/neteq/tools/neteq_stats_getter.h"
12
13 #include <algorithm>
14 #include <numeric>
15 #include <utility>
16
17 #include "rtc_base/checks.h"
18 #include "rtc_base/strings/string_builder.h"
19 #include "rtc_base/time_utils.h"
20
21 namespace webrtc {
22 namespace test {
23
ToString() const24 std::string NetEqStatsGetter::ConcealmentEvent::ToString() const {
25 char ss_buf[256];
26 rtc::SimpleStringBuilder ss(ss_buf);
27 ss << "ConcealmentEvent duration_ms:" << duration_ms
28 << " event_number:" << concealment_event_number
29 << " time_from_previous_event_end_ms:" << time_from_previous_event_end_ms;
30 return ss.str();
31 }
32
NetEqStatsGetter(std::unique_ptr<NetEqDelayAnalyzer> delay_analyzer)33 NetEqStatsGetter::NetEqStatsGetter(
34 std::unique_ptr<NetEqDelayAnalyzer> delay_analyzer)
35 : delay_analyzer_(std::move(delay_analyzer)) {}
36
BeforeGetAudio(NetEq * neteq)37 void NetEqStatsGetter::BeforeGetAudio(NetEq* neteq) {
38 if (delay_analyzer_) {
39 delay_analyzer_->BeforeGetAudio(neteq);
40 }
41 }
42
AfterGetAudio(int64_t time_now_ms,const AudioFrame & audio_frame,bool muted,NetEq * neteq)43 void NetEqStatsGetter::AfterGetAudio(int64_t time_now_ms,
44 const AudioFrame& audio_frame,
45 bool muted,
46 NetEq* neteq) {
47 // TODO(minyue): Get stats should better not be called as a call back after
48 // get audio. It is called independently from get audio in practice.
49 const auto lifetime_stat = neteq->GetLifetimeStatistics();
50 if (last_stats_query_time_ms_ == 0 ||
51 rtc::TimeDiff(time_now_ms, last_stats_query_time_ms_) >=
52 stats_query_interval_ms_) {
53 NetEqNetworkStatistics stats;
54 RTC_CHECK_EQ(neteq->NetworkStatistics(&stats), 0);
55 stats_.push_back(std::make_pair(time_now_ms, stats));
56 lifetime_stats_.push_back(std::make_pair(time_now_ms, lifetime_stat));
57 last_stats_query_time_ms_ = time_now_ms;
58 }
59
60 const auto voice_concealed_samples =
61 lifetime_stat.concealed_samples - lifetime_stat.silent_concealed_samples;
62 if (current_concealment_event_ != lifetime_stat.concealment_events &&
63 voice_concealed_samples_until_last_event_ < voice_concealed_samples) {
64 if (last_event_end_time_ms_ > 0) {
65 // Do not account for the first event to avoid start of the call
66 // skewing.
67 ConcealmentEvent concealment_event;
68 uint64_t last_event_voice_concealed_samples =
69 voice_concealed_samples - voice_concealed_samples_until_last_event_;
70 RTC_CHECK_GT(last_event_voice_concealed_samples, 0);
71 concealment_event.duration_ms = last_event_voice_concealed_samples /
72 (audio_frame.sample_rate_hz_ / 1000);
73 concealment_event.concealment_event_number = current_concealment_event_;
74 concealment_event.time_from_previous_event_end_ms =
75 time_now_ms - last_event_end_time_ms_;
76 concealment_events_.emplace_back(concealment_event);
77 voice_concealed_samples_until_last_event_ = voice_concealed_samples;
78 }
79 last_event_end_time_ms_ = time_now_ms;
80 voice_concealed_samples_until_last_event_ = voice_concealed_samples;
81 current_concealment_event_ = lifetime_stat.concealment_events;
82 }
83
84 if (delay_analyzer_) {
85 delay_analyzer_->AfterGetAudio(time_now_ms, audio_frame, muted, neteq);
86 }
87 }
88
AverageSpeechExpandRate() const89 double NetEqStatsGetter::AverageSpeechExpandRate() const {
90 double sum_speech_expand = std::accumulate(
91 stats_.begin(), stats_.end(), double{0.0},
92 [](double a, std::pair<int64_t, NetEqNetworkStatistics> b) {
93 return a + static_cast<double>(b.second.speech_expand_rate);
94 });
95 return sum_speech_expand / 16384.0 / stats_.size();
96 }
97
AverageStats() const98 NetEqStatsGetter::Stats NetEqStatsGetter::AverageStats() const {
99 Stats sum_stats = std::accumulate(
100 stats_.begin(), stats_.end(), Stats(),
101 [](Stats a, std::pair<int64_t, NetEqNetworkStatistics> bb) {
102 const auto& b = bb.second;
103 a.current_buffer_size_ms += b.current_buffer_size_ms;
104 a.preferred_buffer_size_ms += b.preferred_buffer_size_ms;
105 a.jitter_peaks_found += b.jitter_peaks_found;
106 a.packet_loss_rate += b.packet_loss_rate / 16384.0;
107 a.expand_rate += b.expand_rate / 16384.0;
108 a.speech_expand_rate += b.speech_expand_rate / 16384.0;
109 a.preemptive_rate += b.preemptive_rate / 16384.0;
110 a.accelerate_rate += b.accelerate_rate / 16384.0;
111 a.secondary_decoded_rate += b.secondary_decoded_rate / 16384.0;
112 a.secondary_discarded_rate += b.secondary_discarded_rate / 16384.0;
113 a.added_zero_samples += b.added_zero_samples;
114 a.mean_waiting_time_ms += b.mean_waiting_time_ms;
115 a.median_waiting_time_ms += b.median_waiting_time_ms;
116 a.min_waiting_time_ms = std::min(
117 a.min_waiting_time_ms, static_cast<double>(b.min_waiting_time_ms));
118 a.max_waiting_time_ms = std::max(
119 a.max_waiting_time_ms, static_cast<double>(b.max_waiting_time_ms));
120 return a;
121 });
122
123 sum_stats.current_buffer_size_ms /= stats_.size();
124 sum_stats.preferred_buffer_size_ms /= stats_.size();
125 sum_stats.jitter_peaks_found /= stats_.size();
126 sum_stats.packet_loss_rate /= stats_.size();
127 sum_stats.expand_rate /= stats_.size();
128 sum_stats.speech_expand_rate /= stats_.size();
129 sum_stats.preemptive_rate /= stats_.size();
130 sum_stats.accelerate_rate /= stats_.size();
131 sum_stats.secondary_decoded_rate /= stats_.size();
132 sum_stats.secondary_discarded_rate /= stats_.size();
133 sum_stats.added_zero_samples /= stats_.size();
134 sum_stats.mean_waiting_time_ms /= stats_.size();
135 sum_stats.median_waiting_time_ms /= stats_.size();
136
137 return sum_stats;
138 }
139
140 } // namespace test
141 } // namespace webrtc
142