Computing and propagating the audio stats totalprocessingdelay.
Bug: webrtc:344347965 Change-Id: Id7dd74ef085338d14582dcc0db98508d365301e6 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/352680 Reviewed-by: Harald Alvestrand <hta@webrtc.org> Reviewed-by: Jakob Ivarsson <jakobi@webrtc.org> Commit-Queue: Jesus de Vicente Pena <devicentepena@webrtc.org> Cr-Commit-Position: refs/heads/main@{#42507}
This commit is contained in:
parent
418bcf2acb
commit
fc6df056b6
@ -94,6 +94,7 @@ struct NetEqLifetimeStatistics {
|
||||
int32_t total_interruption_duration_ms = 0;
|
||||
// Total number of comfort noise samples generated during DTX.
|
||||
uint64_t generated_noise_samples = 0;
|
||||
uint64_t total_processing_delay_us = 0;
|
||||
};
|
||||
|
||||
// Metrics that describe the operations performed in NetEq, and the internal
|
||||
|
||||
@ -321,6 +321,9 @@ webrtc::AudioReceiveStreamInterface::Stats AudioReceiveStreamImpl::GetStats(
|
||||
static_cast<double>(rtc::kNumMillisecsPerSec);
|
||||
stats.inserted_samples_for_deceleration = ns.insertedSamplesForDeceleration;
|
||||
stats.removed_samples_for_acceleration = ns.removedSamplesForAcceleration;
|
||||
stats.total_processing_delay_seconds =
|
||||
static_cast<double>(ns.totalProcessingDelayUs) /
|
||||
static_cast<double>(rtc::kNumMicrosecsPerSec);
|
||||
stats.expand_rate = Q14ToFloat(ns.currentExpandRate);
|
||||
stats.speech_expand_rate = Q14ToFloat(ns.currentSpeechExpandRate);
|
||||
stats.secondary_decoded_rate = Q14ToFloat(ns.currentSecondaryDecodedRate);
|
||||
|
||||
@ -82,6 +82,7 @@ const NetworkStatistics kNetworkStats = {
|
||||
/*removedSamplesForAcceleration=*/321,
|
||||
/*fecPacketsReceived=*/123,
|
||||
/*fecPacketsDiscarded=*/101,
|
||||
/*totalProcessingDelayMs=*/154,
|
||||
/*packetsDiscarded=*/989,
|
||||
/*currentExpandRate=*/789,
|
||||
/*currentSpeechExpandRate=*/12,
|
||||
@ -287,6 +288,9 @@ TEST(AudioReceiveStreamTest, GetStats) {
|
||||
stats.removed_samples_for_acceleration);
|
||||
EXPECT_EQ(kNetworkStats.fecPacketsReceived, stats.fec_packets_received);
|
||||
EXPECT_EQ(kNetworkStats.fecPacketsDiscarded, stats.fec_packets_discarded);
|
||||
EXPECT_EQ(static_cast<double>(kNetworkStats.totalProcessingDelayUs) /
|
||||
static_cast<double>(rtc::kNumMicrosecsPerSec),
|
||||
stats.total_processing_delay_seconds);
|
||||
EXPECT_EQ(kNetworkStats.packetsDiscarded, stats.packets_discarded);
|
||||
EXPECT_EQ(Q14ToFloat(kNetworkStats.currentExpandRate), stats.expand_rate);
|
||||
EXPECT_EQ(Q14ToFloat(kNetworkStats.currentSpeechExpandRate),
|
||||
|
||||
@ -62,6 +62,7 @@ class AudioReceiveStreamInterface : public MediaReceiveStreamInterface {
|
||||
double jitter_buffer_minimum_delay_seconds = 0.0;
|
||||
uint64_t inserted_samples_for_deceleration = 0;
|
||||
uint64_t removed_samples_for_acceleration = 0;
|
||||
double total_processing_delay_seconds = 0.0;
|
||||
// Stats below DO NOT correspond directly to anything in the WebRTC stats
|
||||
float expand_rate = 0.0f;
|
||||
float speech_expand_rate = 0.0f;
|
||||
|
||||
@ -476,6 +476,8 @@ struct MediaReceiverInfo {
|
||||
absl::optional<uint64_t> fec_packets_discarded;
|
||||
// https://w3c.github.io/webrtc-stats/#dom-rtcinboundrtpstreamstats-fecbytesreceived
|
||||
absl::optional<uint64_t> fec_bytes_received;
|
||||
// https://www.w3.org/TR/webrtc-stats/#dom-rtcinboundrtpstreamstats-totalprocessingdelay
|
||||
double total_processing_delay_seconds = 0.0;
|
||||
|
||||
// Remote outbound stats derived by the received RTCP sender reports.
|
||||
// https://w3c.github.io/webrtc-stats/#remoteoutboundrtpstats-dict*
|
||||
|
||||
@ -2652,7 +2652,7 @@ bool WebRtcVoiceReceiveChannel::GetStats(VoiceMediaReceiveInfo* info,
|
||||
rinfo.round_trip_time = stats.round_trip_time;
|
||||
rinfo.round_trip_time_measurements = stats.round_trip_time_measurements;
|
||||
rinfo.total_round_trip_time = stats.total_round_trip_time;
|
||||
|
||||
rinfo.total_processing_delay_seconds = stats.total_processing_delay_seconds;
|
||||
if (recv_nack_enabled_) {
|
||||
rinfo.nacks_sent = stats.nacks_sent;
|
||||
}
|
||||
|
||||
@ -717,6 +717,7 @@ class WebRtcVoiceEngineTestFake : public ::testing::TestWithParam<bool> {
|
||||
stats.concealment_events = 12;
|
||||
stats.jitter_buffer_delay_seconds = 34;
|
||||
stats.jitter_buffer_emitted_count = 77;
|
||||
stats.total_processing_delay_seconds = 0.123;
|
||||
stats.expand_rate = 5.67f;
|
||||
stats.speech_expand_rate = 8.90f;
|
||||
stats.secondary_decoded_rate = 1.23f;
|
||||
@ -765,6 +766,8 @@ class WebRtcVoiceEngineTestFake : public ::testing::TestWithParam<bool> {
|
||||
stats.jitter_buffer_delay_seconds);
|
||||
EXPECT_EQ(info.jitter_buffer_emitted_count,
|
||||
stats.jitter_buffer_emitted_count);
|
||||
EXPECT_EQ(info.total_processing_delay_seconds,
|
||||
stats.total_processing_delay_seconds);
|
||||
EXPECT_EQ(info.expand_rate, stats.expand_rate);
|
||||
EXPECT_EQ(info.speech_expand_rate, stats.speech_expand_rate);
|
||||
EXPECT_EQ(info.secondary_decoded_rate, stats.secondary_decoded_rate);
|
||||
|
||||
@ -303,6 +303,8 @@ void AcmReceiver::GetNetworkStatistics(
|
||||
neteq_lifetime_stat.removed_samples_for_acceleration;
|
||||
acm_stat->fecPacketsReceived = neteq_lifetime_stat.fec_packets_received;
|
||||
acm_stat->fecPacketsDiscarded = neteq_lifetime_stat.fec_packets_discarded;
|
||||
acm_stat->totalProcessingDelayUs =
|
||||
neteq_lifetime_stat.total_processing_delay_us;
|
||||
acm_stat->packetsDiscarded = neteq_lifetime_stat.packets_discarded;
|
||||
|
||||
NetEqOperationsAndState neteq_operations_and_state =
|
||||
|
||||
@ -94,6 +94,7 @@ struct NetworkStatistics {
|
||||
uint64_t removedSamplesForAcceleration;
|
||||
uint64_t fecPacketsReceived;
|
||||
uint64_t fecPacketsDiscarded;
|
||||
uint64_t totalProcessingDelayUs;
|
||||
// Stats below correspond to similarly-named fields in the WebRTC stats spec.
|
||||
// https://w3c.github.io/webrtc-stats/#dom-rtcreceivedrtpstreamstats
|
||||
uint64_t packetsDiscarded;
|
||||
|
||||
@ -1976,9 +1976,17 @@ int NetEqImpl::ExtractPackets(size_t required_samples,
|
||||
extracted_samples = packet->timestamp - first_timestamp + packet_duration;
|
||||
|
||||
RTC_DCHECK(controller_);
|
||||
stats_->JitterBufferDelay(packet_duration, waiting_time_ms,
|
||||
controller_->TargetLevelMs(),
|
||||
controller_->UnlimitedTargetLevelMs());
|
||||
TimeDelta processing_time = TimeDelta::Zero();
|
||||
|
||||
if (packet->packet_info.has_value() &&
|
||||
!packet->packet_info->receive_time().IsMinusInfinity()) {
|
||||
processing_time =
|
||||
clock_->CurrentTime() - packet->packet_info->receive_time();
|
||||
}
|
||||
|
||||
stats_->JitterBufferDelay(
|
||||
packet_duration, waiting_time_ms, controller_->TargetLevelMs(),
|
||||
controller_->UnlimitedTargetLevelMs(), processing_time.us());
|
||||
|
||||
// Check what packet is available next.
|
||||
next_packet = packet_buffer_->PeekNextPacket();
|
||||
|
||||
@ -909,6 +909,7 @@ void NetEqDecodingTestFaxMode::TestJitterBufferDelay(bool apply_packet_loss) {
|
||||
|
||||
// Get packet.
|
||||
if (packets_sent > kDelayInNumPackets) {
|
||||
clock_.AdvanceTime(TimeDelta::Millis(kPacketLenMs));
|
||||
neteq_->GetAudio(&out_frame_, &muted);
|
||||
packets_received++;
|
||||
|
||||
@ -928,6 +929,7 @@ void NetEqDecodingTestFaxMode::TestJitterBufferDelay(bool apply_packet_loss) {
|
||||
}
|
||||
|
||||
if (apply_packet_loss) {
|
||||
clock_.AdvanceTime(TimeDelta::Millis(kPacketLenMs));
|
||||
// Extra call to GetAudio to cause concealment.
|
||||
neteq_->GetAudio(&out_frame_, &muted);
|
||||
}
|
||||
@ -939,6 +941,11 @@ void NetEqDecodingTestFaxMode::TestJitterBufferDelay(bool apply_packet_loss) {
|
||||
EXPECT_EQ(expected_emitted_count, stats.jitter_buffer_emitted_count);
|
||||
EXPECT_EQ(expected_target_delay,
|
||||
rtc::checked_cast<int>(stats.jitter_buffer_target_delay_ms));
|
||||
// In this test, since the packets are inserted with a receive time equal to
|
||||
// the current clock time, the jitter buffer delay should match the total
|
||||
// processing delay.
|
||||
EXPECT_EQ(stats.jitter_buffer_delay_ms * 1000,
|
||||
stats.total_processing_delay_us);
|
||||
}
|
||||
|
||||
TEST_F(NetEqDecodingTestFaxMode, TestJitterBufferDelayWithoutLoss) {
|
||||
|
||||
@ -262,17 +262,19 @@ void StatisticsCalculator::IncreaseCounter(size_t num_samples, int fs_hz) {
|
||||
lifetime_stats_.total_samples_received += num_samples;
|
||||
}
|
||||
|
||||
void StatisticsCalculator::JitterBufferDelay(
|
||||
size_t num_samples,
|
||||
uint64_t waiting_time_ms,
|
||||
uint64_t target_delay_ms,
|
||||
uint64_t unlimited_target_delay_ms) {
|
||||
void StatisticsCalculator::JitterBufferDelay(size_t num_samples,
|
||||
uint64_t waiting_time_ms,
|
||||
uint64_t target_delay_ms,
|
||||
uint64_t unlimited_target_delay_ms,
|
||||
uint64_t processing_delay_us) {
|
||||
lifetime_stats_.jitter_buffer_delay_ms += waiting_time_ms * num_samples;
|
||||
lifetime_stats_.jitter_buffer_target_delay_ms +=
|
||||
target_delay_ms * num_samples;
|
||||
lifetime_stats_.jitter_buffer_minimum_delay_ms +=
|
||||
unlimited_target_delay_ms * num_samples;
|
||||
lifetime_stats_.jitter_buffer_emitted_count += num_samples;
|
||||
lifetime_stats_.total_processing_delay_us +=
|
||||
num_samples * processing_delay_us;
|
||||
}
|
||||
|
||||
void StatisticsCalculator::SecondaryDecodedSamples(int num_samples) {
|
||||
|
||||
@ -86,7 +86,8 @@ class StatisticsCalculator {
|
||||
void JitterBufferDelay(size_t num_samples,
|
||||
uint64_t waiting_time_ms,
|
||||
uint64_t target_delay_ms,
|
||||
uint64_t unlimited_target_delay_ms);
|
||||
uint64_t unlimited_target_delay_ms,
|
||||
uint64_t processing_delay_us);
|
||||
|
||||
// Stores new packet waiting time in waiting time statistics.
|
||||
void StoreWaitingTime(int waiting_time_ms);
|
||||
|
||||
@ -203,4 +203,33 @@ TEST(StatisticsCalculator, DiscardedPackets) {
|
||||
statistics_calculator.GetLifetimeStatistics().packets_discarded);
|
||||
}
|
||||
|
||||
TEST(StatisticsCalculator, JitterBufferDelay) {
|
||||
StatisticsCalculator stats;
|
||||
NetEqLifetimeStatistics lts;
|
||||
lts = stats.GetLifetimeStatistics();
|
||||
EXPECT_EQ(lts.total_processing_delay_us, 0ul);
|
||||
stats.JitterBufferDelay(/*num_samples=*/480,
|
||||
/*waiting_time_ms=*/90ul,
|
||||
/*target_delay_ms=*/80ul,
|
||||
/*unlimited_target_delay_ms=*/70,
|
||||
/*processing_delay_us=*/100 * 1000ul);
|
||||
lts = stats.GetLifetimeStatistics();
|
||||
EXPECT_EQ(lts.jitter_buffer_delay_ms / 480, 90ul);
|
||||
EXPECT_EQ(lts.jitter_buffer_target_delay_ms / 480, 80ul);
|
||||
EXPECT_EQ(lts.jitter_buffer_minimum_delay_ms / 480, 70ul);
|
||||
EXPECT_EQ(lts.total_processing_delay_us / 480, 100 * 1000ul);
|
||||
EXPECT_EQ(lts.jitter_buffer_emitted_count, 480ul);
|
||||
stats.JitterBufferDelay(/*num_samples=*/480,
|
||||
/*waiting_time_ms=*/90ul,
|
||||
/*target_delay_ms=*/80ul,
|
||||
/*unlimited_target_delay_ms=*/70,
|
||||
/*processing_delay_us=*/100 * 1000ul);
|
||||
lts = stats.GetLifetimeStatistics();
|
||||
EXPECT_EQ(lts.jitter_buffer_delay_ms / 960, 90ul);
|
||||
EXPECT_EQ(lts.jitter_buffer_target_delay_ms / 960, 80ul);
|
||||
EXPECT_EQ(lts.jitter_buffer_minimum_delay_ms / 960, 70ul);
|
||||
EXPECT_EQ(lts.total_processing_delay_us / 960, 100 * 1000ul);
|
||||
EXPECT_EQ(lts.jitter_buffer_emitted_count, 960ul);
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
@ -423,6 +423,8 @@ void SetInboundRTPStreamStatsFromMediaReceiverInfo(
|
||||
if (media_receiver_info.fec_bytes_received.has_value()) {
|
||||
inbound_stats->fec_bytes_received = *media_receiver_info.fec_bytes_received;
|
||||
}
|
||||
inbound_stats->total_processing_delay =
|
||||
media_receiver_info.total_processing_delay_seconds;
|
||||
}
|
||||
|
||||
std::unique_ptr<RTCInboundRtpStreamStats> CreateInboundAudioStreamStats(
|
||||
|
||||
@ -2201,6 +2201,7 @@ TEST_F(RTCStatsCollectorTest, CollectRTCInboundRtpStreamStats_Audio) {
|
||||
voice_media_info.receivers[0].interruption_count = 7788;
|
||||
voice_media_info.receivers[0].total_interruption_duration_ms = 778899;
|
||||
voice_media_info.receivers[0].last_packet_received = absl::nullopt;
|
||||
voice_media_info.receivers[0].total_processing_delay_seconds = 0.123;
|
||||
|
||||
RtpCodecParameters codec_parameters;
|
||||
codec_parameters.payload_type = 42;
|
||||
@ -2258,6 +2259,7 @@ TEST_F(RTCStatsCollectorTest, CollectRTCInboundRtpStreamStats_Audio) {
|
||||
expected_audio.relative_packet_arrival_delay = 16;
|
||||
expected_audio.interruption_count = 7788;
|
||||
expected_audio.total_interruption_duration = 778.899;
|
||||
expected_audio.total_processing_delay = 0.123;
|
||||
expected_audio.playout_id = "AP";
|
||||
|
||||
ASSERT_TRUE(report->Get(expected_audio.id()));
|
||||
|
||||
@ -608,6 +608,8 @@ class RTCStatsReportVerifier {
|
||||
inbound_stream.jitter_buffer_target_delay);
|
||||
verifier.TestAttributeIsNonNegative<double>(
|
||||
inbound_stream.jitter_buffer_minimum_delay);
|
||||
verifier.TestAttributeIsNonNegative<double>(
|
||||
inbound_stream.total_processing_delay);
|
||||
if (inbound_stream.kind.has_value() && *inbound_stream.kind == "video") {
|
||||
verifier.TestAttributeIsUndefined(inbound_stream.total_samples_received);
|
||||
verifier.TestAttributeIsUndefined(inbound_stream.concealed_samples);
|
||||
@ -681,8 +683,6 @@ class RTCStatsReportVerifier {
|
||||
inbound_stream.frames_dropped);
|
||||
verifier.TestAttributeIsNonNegative<double>(
|
||||
inbound_stream.total_decode_time);
|
||||
verifier.TestAttributeIsNonNegative<double>(
|
||||
inbound_stream.total_processing_delay);
|
||||
verifier.TestAttributeIsNonNegative<double>(
|
||||
inbound_stream.total_assembly_time);
|
||||
verifier.TestAttributeIsDefined(
|
||||
@ -717,7 +717,6 @@ class RTCStatsReportVerifier {
|
||||
verifier.TestAttributeIsUndefined(inbound_stream.key_frames_decoded);
|
||||
verifier.TestAttributeIsUndefined(inbound_stream.frames_dropped);
|
||||
verifier.TestAttributeIsUndefined(inbound_stream.total_decode_time);
|
||||
verifier.TestAttributeIsUndefined(inbound_stream.total_processing_delay);
|
||||
verifier.TestAttributeIsUndefined(inbound_stream.total_assembly_time);
|
||||
verifier.TestAttributeIsUndefined(
|
||||
inbound_stream.frames_assembled_from_multiple_packets);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user