Start counting NetEq stats after first packet is decoded.

A slight behavior change is that we only increment total samples received when GetAudio is successful.

Bug: webrtc:370424996
Change-Id: I8607418c179ca3bc22963b98792a9e8b9af2d451
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/364220
Commit-Queue: Jakob Ivarsson‎ <jakobi@webrtc.org>
Reviewed-by: Henrik Lundin <henrik.lundin@webrtc.org>
Reviewed-by: Jakob Ivarsson‎ <jakobi@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#43139}
This commit is contained in:
Jakob Ivarsson 2024-10-02 09:25:29 +00:00 committed by WebRTC LUCI CQ
parent 57ec58b82d
commit 09c043a4bb
5 changed files with 91 additions and 8 deletions

View File

@ -201,6 +201,7 @@ int NetEqImpl::GetAudio(AudioFrame* audio_frame,
if (GetAudioInternal(audio_frame, action_override) != 0) {
return kFail;
}
stats_->IncreaseCounter(output_size_samples_, fs_hz_);
RTC_DCHECK_EQ(
audio_frame->sample_rate_hz_,
rtc::dchecked_cast<int>(audio_frame->samples_per_channel_ * 100));
@ -733,7 +734,6 @@ int NetEqImpl::GetAudioInternal(AudioFrame* audio_frame,
bool play_dtmf;
last_decoded_packet_infos_.clear();
tick_timer_->Increment();
stats_->IncreaseCounter(output_size_samples_, fs_hz_);
// Check for muted state.
if (enable_muted_state_ && expand_->Muted() && packet_buffer_->Empty()) {

View File

@ -384,6 +384,35 @@ TEST_F(NetEqImplTest, InsertPacket) {
/*receive_time=*/clock_.CurrentTime());
}
TEST_F(NetEqImplTest, CountStatsAfterFirstDecodedPacket) {
UseNoMocks();
CreateInstance();
const uint8_t kPayloadType = 17; // Just an arbitrary number.
EXPECT_TRUE(neteq_->RegisterPayloadType(kPayloadType,
SdpAudioFormat("l16", 8000, 1)));
const size_t kPayloadLengthSamples = 80;
const size_t kPayloadLengthBytes = 2 * kPayloadLengthSamples; // PCM 16-bit.
uint8_t payload[kPayloadLengthBytes] = {0};
RTPHeader rtp_header;
rtp_header.payloadType = kPayloadType;
rtp_header.sequenceNumber = 0x1234;
rtp_header.timestamp = 0x12345678;
rtp_header.ssrc = 0x87654321;
AudioFrame frame;
// Get audio a couple of times to make sure that samples received remains
// zero.
for (int i = 0; i < 3; ++i) {
neteq_->GetAudio(&frame);
EXPECT_EQ(neteq_->GetLifetimeStatistics().concealed_samples, 0u);
EXPECT_EQ(neteq_->GetLifetimeStatistics().total_samples_received, 0u);
}
neteq_->InsertPacket(rtp_header, payload, clock_.CurrentTime());
neteq_->GetAudio(&frame);
EXPECT_EQ(neteq_->GetLifetimeStatistics().concealed_samples, 0u);
EXPECT_EQ(neteq_->GetLifetimeStatistics().total_samples_received,
kPayloadLengthSamples);
}
TEST_F(NetEqImplTest, InsertPacketsUntilBufferIsFull) {
UseNoMocks();
CreateInstance();

View File

@ -81,7 +81,7 @@ TEST_F(NetEqDecodingTest, MAYBE_TestOpusBitExactness) {
"cefd2de4adfa8f6a9b66a3639ad63c2f6779d0cd";
const std::string network_stats_checksum =
"5f2c8e3dff9cff55dd7a9f4167939de001566d95|"
"06f6b9a86aeae6317fd25a36edf9ed16f35e798f|"
"80ab17c17da030d4f2dfbf314ac44aacdadd7f0c";
DecodeAndCompare(input_rtp_file, output_checksum, network_stats_checksum,
@ -103,7 +103,7 @@ TEST_F(NetEqDecodingTest, MAYBE_TestOpusDtxBitExactness) {
"5d13affec87bf4cc8c7667f0cd0d25e1ad09c7c3";
const std::string network_stats_checksum =
"92b0fdcbf8bb9354d40140b7312f2fb76a078555";
"6af74a713749cc4343464718b6af54f1e5b06ad9";
DecodeAndCompare(input_rtp_file, output_checksum, network_stats_checksum,
absl::GetFlag(FLAGS_gen_ref));
@ -660,7 +660,7 @@ TEST_F(NetEqDecodingTestWithMutedState, MutedState) {
// NetEqNetworkStatistics::expand_rate tells the fraction of samples that were
// concealment samples, in Q14 (16384 = 100%) .The vast majority should be
// concealment samples in this test.
EXPECT_GT(stats.expand_rate, 14000);
EXPECT_GT(stats.expand_rate, 13000);
// And, it should be greater than the speech_expand_rate.
EXPECT_GT(stats.expand_rate, stats.speech_expand_rate);
}

View File

@ -155,6 +155,9 @@ void StatisticsCalculator::ResetMcu() {
void StatisticsCalculator::ExpandedVoiceSamples(size_t num_samples,
bool is_new_concealment_event) {
if (!decoded_output_played_) {
return;
}
expanded_speech_samples_ += num_samples;
ConcealedSamplesCorrection(rtc::dchecked_cast<int>(num_samples), true);
lifetime_stats_.concealment_events += is_new_concealment_event;
@ -162,18 +165,27 @@ void StatisticsCalculator::ExpandedVoiceSamples(size_t num_samples,
void StatisticsCalculator::ExpandedNoiseSamples(size_t num_samples,
bool is_new_concealment_event) {
if (!decoded_output_played_) {
return;
}
expanded_noise_samples_ += num_samples;
ConcealedSamplesCorrection(rtc::dchecked_cast<int>(num_samples), false);
lifetime_stats_.concealment_events += is_new_concealment_event;
}
void StatisticsCalculator::ExpandedVoiceSamplesCorrection(int num_samples) {
if (!decoded_output_played_) {
return;
}
expanded_speech_samples_ =
AddIntToSizeTWithLowerCap(num_samples, expanded_speech_samples_);
ConcealedSamplesCorrection(num_samples, true);
}
void StatisticsCalculator::ExpandedNoiseSamplesCorrection(int num_samples) {
if (!decoded_output_played_) {
return;
}
expanded_noise_samples_ =
AddIntToSizeTWithLowerCap(num_samples, expanded_noise_samples_);
ConcealedSamplesCorrection(num_samples, false);
@ -184,6 +196,9 @@ void StatisticsCalculator::DecodedOutputPlayed() {
}
void StatisticsCalculator::EndExpandEvent(int fs_hz) {
if (!decoded_output_played_) {
return;
}
RTC_DCHECK_GE(lifetime_stats_.concealed_samples,
concealed_samples_at_event_end_);
const int event_duration_ms =
@ -201,6 +216,9 @@ void StatisticsCalculator::EndExpandEvent(int fs_hz) {
void StatisticsCalculator::ConcealedSamplesCorrection(int num_samples,
bool is_voice) {
if (!decoded_output_played_) {
return;
}
if (num_samples < 0) {
// Store negative correction to subtract from future positive additions.
// See also the function comment in the header file.
@ -226,18 +244,27 @@ void StatisticsCalculator::ConcealedSamplesCorrection(int num_samples,
}
void StatisticsCalculator::PreemptiveExpandedSamples(size_t num_samples) {
if (!decoded_output_played_) {
return;
}
preemptive_samples_ += num_samples;
operations_and_state_.preemptive_samples += num_samples;
lifetime_stats_.inserted_samples_for_deceleration += num_samples;
}
void StatisticsCalculator::AcceleratedSamples(size_t num_samples) {
if (!decoded_output_played_) {
return;
}
accelerate_samples_ += num_samples;
operations_and_state_.accelerate_samples += num_samples;
lifetime_stats_.removed_samples_for_acceleration += num_samples;
}
void StatisticsCalculator::GeneratedNoiseSamples(size_t num_samples) {
if (!decoded_output_played_) {
return;
}
lifetime_stats_.generated_noise_samples += num_samples;
}
@ -255,6 +282,9 @@ void StatisticsCalculator::SecondaryPacketsReceived(size_t num_packets) {
}
void StatisticsCalculator::IncreaseCounter(size_t num_samples, int fs_hz) {
if (!decoded_output_played_) {
return;
}
const int time_step_ms =
rtc::CheckedDivExact(static_cast<int>(1000 * num_samples), fs_hz);
delayed_packet_outage_counter_.AdvanceClock(time_step_ms);
@ -268,9 +298,13 @@ void StatisticsCalculator::IncreaseCounter(size_t num_samples, int fs_hz) {
lifetime_stats_.total_samples_received += num_samples;
expand_uma_logger_.UpdateSampleCounter(lifetime_stats_.concealed_samples,
fs_hz);
speech_expand_uma_logger_.UpdateSampleCounter(
lifetime_stats_.concealed_samples -
lifetime_stats_.silent_concealed_samples,
uint64_t speech_concealed_samples = 0;
if (lifetime_stats_.concealed_samples >
lifetime_stats_.silent_concealed_samples) {
speech_concealed_samples = lifetime_stats_.concealed_samples -
lifetime_stats_.silent_concealed_samples;
}
speech_expand_uma_logger_.UpdateSampleCounter(speech_concealed_samples,
fs_hz);
}

View File

@ -17,6 +17,7 @@ namespace webrtc {
TEST(LifetimeStatistics, TotalSamplesReceived) {
TickTimer timer;
StatisticsCalculator stats(&timer);
stats.DecodedOutputPlayed();
for (int i = 0; i < 10; ++i) {
stats.IncreaseCounter(480, 48000); // 10 ms at 48 kHz.
}
@ -26,6 +27,7 @@ TEST(LifetimeStatistics, TotalSamplesReceived) {
TEST(LifetimeStatistics, SamplesConcealed) {
TickTimer timer;
StatisticsCalculator stats(&timer);
stats.DecodedOutputPlayed();
stats.ExpandedVoiceSamples(100, false);
stats.ExpandedNoiseSamples(17, false);
EXPECT_EQ(100u + 17u, stats.GetLifetimeStatistics().concealed_samples);
@ -38,6 +40,7 @@ TEST(LifetimeStatistics, SamplesConcealed) {
TEST(LifetimeStatistics, SamplesConcealedCorrection) {
TickTimer timer;
StatisticsCalculator stats(&timer);
stats.DecodedOutputPlayed();
stats.ExpandedVoiceSamples(100, false);
EXPECT_EQ(100u, stats.GetLifetimeStatistics().concealed_samples);
stats.ExpandedVoiceSamplesCorrection(-10);
@ -60,6 +63,7 @@ TEST(LifetimeStatistics, SamplesConcealedCorrection) {
TEST(LifetimeStatistics, NoUpdateOnTimeStretch) {
TickTimer timer;
StatisticsCalculator stats(&timer);
stats.DecodedOutputPlayed();
stats.ExpandedVoiceSamples(100, false);
stats.AcceleratedSamples(4711);
stats.PreemptiveExpandedSamples(17);
@ -70,6 +74,7 @@ TEST(LifetimeStatistics, NoUpdateOnTimeStretch) {
TEST(StatisticsCalculator, ExpandedSamplesCorrection) {
TickTimer timer;
StatisticsCalculator stats(&timer);
stats.DecodedOutputPlayed();
NetEqNetworkStatistics stats_output;
constexpr int kSampleRateHz = 48000;
constexpr int k10MsSamples = kSampleRateHz / 100;
@ -243,4 +248,19 @@ TEST(StatisticsCalculator, JitterBufferDelay) {
EXPECT_EQ(lts.jitter_buffer_emitted_count, 960ul);
}
TEST(StatisticsCalculator, CountStatsAfterFirstDecodedPacket) {
TickTimer timer;
StatisticsCalculator stats(&timer);
stats.IncreaseCounter(/*num_samples=*/480, /*fs_hz=*/48000);
stats.ExpandedVoiceSamples(/*num_samples=*/480,
/*is_new_concealment_event=*/true);
NetEqLifetimeStatistics lts = stats.GetLifetimeStatistics();
EXPECT_EQ(lts.total_samples_received, 0u);
EXPECT_EQ(lts.concealed_samples, 0u);
stats.DecodedOutputPlayed();
stats.IncreaseCounter(/*num_samples=*/480, /*fs_hz=*/48000);
lts = stats.GetLifetimeStatistics();
EXPECT_EQ(lts.total_samples_received, 480u);
}
} // namespace webrtc