Add jitterBufferTargetDelay as RTCNonStandardStatsMember to new GetStats API

Bug: webrtc:11381
Change-Id: I7df3450e50da49d178e1e3a5d9f4970672d91aac
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/169120
Reviewed-by: Karl Wiberg <kwiberg@webrtc.org>
Reviewed-by: Henrik Boström <hbos@webrtc.org>
Reviewed-by: Ivo Creusen <ivoc@webrtc.org>
Commit-Queue: Artem Titov <titovartem@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#30758}
diff --git a/api/neteq/neteq.h b/api/neteq/neteq.h
index 67dbd50..d632e03 100644
--- a/api/neteq/neteq.h
+++ b/api/neteq/neteq.h
@@ -68,6 +68,7 @@
   uint64_t concealment_events = 0;
   uint64_t jitter_buffer_delay_ms = 0;
   uint64_t jitter_buffer_emitted_count = 0;
+  uint64_t jitter_buffer_target_delay_ms = 0;
   uint64_t inserted_samples_for_deceleration = 0;
   uint64_t removed_samples_for_acceleration = 0;
   uint64_t silent_concealed_samples = 0;
diff --git a/api/stats/rtcstats_objects.h b/api/stats/rtcstats_objects.h
index 197a810..e83c83d 100644
--- a/api/stats/rtcstats_objects.h
+++ b/api/stats/rtcstats_objects.h
@@ -327,6 +327,14 @@
   RTCNonStandardStatsMember<uint64_t> jitter_buffer_flushes;
   RTCNonStandardStatsMember<uint64_t> delayed_packet_outage_samples;
   RTCNonStandardStatsMember<double> relative_packet_arrival_delay;
+  // Non-standard metric showing target delay of jitter buffer.
+  // This value is increased by the target jitter buffer delay every time a
+  // sample is emitted by the jitter buffer. The added target is the target
+  // delay, in seconds, at the time that the sample was emitted from the jitter
+  // buffer. (https://github.com/w3c/webrtc-provisional-stats/pull/20)
+  // Currently it is implemented only for audio.
+  // TODO(titovartem) implement for video streams when will be requested.
+  RTCNonStandardStatsMember<double> jitter_buffer_target_delay;
   // TODO(henrik.lundin): Add description of the interruption metrics at
   // https://github.com/henbos/webrtc-provisional-stats/issues/17
   RTCNonStandardStatsMember<uint32_t> interruption_count;
diff --git a/audio/audio_receive_stream.cc b/audio/audio_receive_stream.cc
index 7c6adcd..ce1b344 100644
--- a/audio/audio_receive_stream.cc
+++ b/audio/audio_receive_stream.cc
@@ -222,6 +222,9 @@
       static_cast<double>(ns.jitterBufferDelayMs) /
       static_cast<double>(rtc::kNumMillisecsPerSec);
   stats.jitter_buffer_emitted_count = ns.jitterBufferEmittedCount;
+  stats.jitter_buffer_target_delay_seconds =
+      static_cast<double>(ns.jitterBufferTargetDelayMs) /
+      static_cast<double>(rtc::kNumMillisecsPerSec);
   stats.inserted_samples_for_deceleration = ns.insertedSamplesForDeceleration;
   stats.removed_samples_for_acceleration = ns.removedSamplesForAcceleration;
   stats.expand_rate = Q14ToFloat(ns.currentExpandRate);
diff --git a/audio/audio_receive_stream_unittest.cc b/audio/audio_receive_stream_unittest.cc
index b8eff0a..0b2cae5 100644
--- a/audio/audio_receive_stream_unittest.cc
+++ b/audio/audio_receive_stream_unittest.cc
@@ -69,9 +69,9 @@
     123,
     {"codec_name_recv", 96000, 0}};
 const NetworkStatistics kNetworkStats = {
-    123, 456, false, 789012, 3456, 123, 456, 789, 543, 432,
-    321, 123, 101,   0,      {},   789, 12,  345, 678, 901,
-    0,   -1,  -1,    -1,     -1,   0,   0,   0,   0};
+    123, 456, false, 789012, 3456, 123, 456, 789, 543, 123,
+    432, 321, 123,   101,    0,    {},  789, 12,  345, 678,
+    901, 0,   -1,    -1,     -1,   -1,  0,   0,   0,   0};
 const AudioDecodingCallStats kAudioDecodeStats = MakeAudioDecodeStatsForTest();
 
 struct ConfigHelper {
@@ -294,6 +294,9 @@
             stats.jitter_buffer_delay_seconds);
   EXPECT_EQ(kNetworkStats.jitterBufferEmittedCount,
             stats.jitter_buffer_emitted_count);
+  EXPECT_EQ(static_cast<double>(kNetworkStats.jitterBufferTargetDelayMs) /
+                static_cast<double>(rtc::kNumMillisecsPerSec),
+            stats.jitter_buffer_target_delay_seconds);
   EXPECT_EQ(Q14ToFloat(kNetworkStats.currentExpandRate), stats.expand_rate);
   EXPECT_EQ(Q14ToFloat(kNetworkStats.currentSpeechExpandRate),
             stats.speech_expand_rate);
diff --git a/call/audio_receive_stream.h b/call/audio_receive_stream.h
index 090fb82..4a50cdb 100644
--- a/call/audio_receive_stream.h
+++ b/call/audio_receive_stream.h
@@ -58,6 +58,7 @@
     uint64_t concealment_events = 0;
     double jitter_buffer_delay_seconds = 0.0;
     uint64_t jitter_buffer_emitted_count = 0;
+    double jitter_buffer_target_delay_seconds = 0.0;
     uint64_t inserted_samples_for_deceleration = 0;
     uint64_t removed_samples_for_acceleration = 0;
     // Stats below DO NOT correspond directly to anything in the WebRTC stats
diff --git a/media/base/media_channel.h b/media/base/media_channel.h
index a62c618..7ca6002 100644
--- a/media/base/media_channel.h
+++ b/media/base/media_channel.h
@@ -512,6 +512,7 @@
   uint64_t concealment_events = 0;
   double jitter_buffer_delay_seconds = 0.0;
   uint64_t jitter_buffer_emitted_count = 0;
+  double jitter_buffer_target_delay_seconds = 0.0;
   uint64_t inserted_samples_for_deceleration = 0;
   uint64_t removed_samples_for_acceleration = 0;
   uint64_t fec_packets_received = 0;
diff --git a/media/engine/webrtc_voice_engine.cc b/media/engine/webrtc_voice_engine.cc
index 7da9abd..45b46bf 100644
--- a/media/engine/webrtc_voice_engine.cc
+++ b/media/engine/webrtc_voice_engine.cc
@@ -2230,6 +2230,8 @@
     rinfo.concealment_events = stats.concealment_events;
     rinfo.jitter_buffer_delay_seconds = stats.jitter_buffer_delay_seconds;
     rinfo.jitter_buffer_emitted_count = stats.jitter_buffer_emitted_count;
+    rinfo.jitter_buffer_target_delay_seconds =
+        stats.jitter_buffer_target_delay_seconds;
     rinfo.inserted_samples_for_deceleration =
         stats.inserted_samples_for_deceleration;
     rinfo.removed_samples_for_acceleration =
diff --git a/modules/audio_coding/acm2/acm_receiver.cc b/modules/audio_coding/acm2/acm_receiver.cc
index 9cecb98..29eff19 100644
--- a/modules/audio_coding/acm2/acm_receiver.cc
+++ b/modules/audio_coding/acm2/acm_receiver.cc
@@ -272,6 +272,8 @@
       neteq_lifetime_stat.silent_concealed_samples;
   acm_stat->concealmentEvents = neteq_lifetime_stat.concealment_events;
   acm_stat->jitterBufferDelayMs = neteq_lifetime_stat.jitter_buffer_delay_ms;
+  acm_stat->jitterBufferTargetDelayMs =
+      neteq_lifetime_stat.jitter_buffer_target_delay_ms;
   acm_stat->jitterBufferEmittedCount =
       neteq_lifetime_stat.jitter_buffer_emitted_count;
   acm_stat->delayedPacketOutageSamples =
diff --git a/modules/audio_coding/include/audio_coding_module_typedefs.h b/modules/audio_coding/include/audio_coding_module_typedefs.h
index 2f40acd..a5d4b24 100644
--- a/modules/audio_coding/include/audio_coding_module_typedefs.h
+++ b/modules/audio_coding/include/audio_coding_module_typedefs.h
@@ -90,6 +90,8 @@
   uint64_t concealmentEvents;
   uint64_t jitterBufferDelayMs;
   uint64_t jitterBufferEmittedCount;
+  // Non standard stats propagated to spec complaint GetStats API.
+  uint64_t jitterBufferTargetDelayMs;
   uint64_t insertedSamplesForDeceleration;
   uint64_t removedSamplesForAcceleration;
   uint64_t fecPacketsReceived;
diff --git a/modules/audio_coding/neteq/neteq_impl.cc b/modules/audio_coding/neteq/neteq_impl.cc
index 265043a..0b7510d 100644
--- a/modules/audio_coding/neteq/neteq_impl.cc
+++ b/modules/audio_coding/neteq/neteq_impl.cc
@@ -1987,7 +1987,9 @@
     }
     extracted_samples = packet->timestamp - first_timestamp + packet_duration;
 
-    stats_->JitterBufferDelay(packet_duration, waiting_time_ms);
+    RTC_DCHECK(controller_);
+    stats_->JitterBufferDelay(packet_duration, waiting_time_ms,
+                              controller_->TargetLevelMs());
 
     packet_list->push_back(std::move(*packet));  // Store packet in list.
     packet = absl::nullopt;  // Ensure it's never used after the move.
diff --git a/modules/audio_coding/neteq/neteq_unittest.cc b/modules/audio_coding/neteq/neteq_unittest.cc
index 701a3c5..d78e2c6 100644
--- a/modules/audio_coding/neteq/neteq_unittest.cc
+++ b/modules/audio_coding/neteq/neteq_unittest.cc
@@ -986,6 +986,7 @@
   int packets_sent = 0;
   int packets_received = 0;
   int expected_delay = 0;
+  int expected_target_delay = 0;
   uint64_t expected_emitted_count = 0;
   while (packets_received < kNumPackets) {
     // Insert packet.
@@ -1010,6 +1011,7 @@
       // number of samples that are sent for play out.
       int current_delay_ms = packets_delay * kPacketLenMs;
       expected_delay += current_delay_ms * kSamples;
+      expected_target_delay += neteq_->TargetDelayMs() * kSamples;
       expected_emitted_count += kSamples;
     }
   }
@@ -1021,8 +1023,11 @@
 
   // Check jitter buffer delay.
   NetEqLifetimeStatistics stats = neteq_->GetLifetimeStatistics();
-  EXPECT_EQ(expected_delay, static_cast<int>(stats.jitter_buffer_delay_ms));
+  EXPECT_EQ(expected_delay,
+            rtc::checked_cast<int>(stats.jitter_buffer_delay_ms));
   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));
 }
 
 TEST_F(NetEqDecodingTestFaxMode, TestJitterBufferDelayWithoutLoss) {
@@ -1043,6 +1048,7 @@
   rtp_info.markerBit = 0;
   const uint8_t payload[kPayloadBytes] = {0};
 
+  int expected_target_delay = neteq_->TargetDelayMs() * kSamples;
   neteq_->InsertPacket(rtp_info, payload);
 
   bool muted;
@@ -1055,6 +1061,7 @@
   rtp_info.timestamp += kSamples;
   neteq_->InsertPacket(rtp_info, payload);
 
+  expected_target_delay += neteq_->TargetDelayMs() * 2 * kSamples;
   // We have two packets in the buffer and kAccelerate operation will
   // extract 20 ms of data.
   neteq_->GetAudio(&out_frame_, &muted, NetEq::Operation::kAccelerate);
@@ -1063,6 +1070,8 @@
   NetEqLifetimeStatistics stats = neteq_->GetLifetimeStatistics();
   EXPECT_EQ(10 * kSamples * 3, stats.jitter_buffer_delay_ms);
   EXPECT_EQ(kSamples * 3, stats.jitter_buffer_emitted_count);
+  EXPECT_EQ(expected_target_delay,
+            rtc::checked_cast<int>(stats.jitter_buffer_target_delay_ms));
 }
 
 namespace test {
diff --git a/modules/audio_coding/neteq/statistics_calculator.cc b/modules/audio_coding/neteq/statistics_calculator.cc
index 081ec33..fa2925c 100644
--- a/modules/audio_coding/neteq/statistics_calculator.cc
+++ b/modules/audio_coding/neteq/statistics_calculator.cc
@@ -275,8 +275,11 @@
 }
 
 void StatisticsCalculator::JitterBufferDelay(size_t num_samples,
-                                             uint64_t waiting_time_ms) {
+                                             uint64_t waiting_time_ms,
+                                             uint64_t target_delay_ms) {
   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_emitted_count += num_samples;
 }
 
diff --git a/modules/audio_coding/neteq/statistics_calculator.h b/modules/audio_coding/neteq/statistics_calculator.h
index 38e463c..333f4a7 100644
--- a/modules/audio_coding/neteq/statistics_calculator.h
+++ b/modules/audio_coding/neteq/statistics_calculator.h
@@ -83,7 +83,9 @@
   void IncreaseCounter(size_t num_samples, int fs_hz);
 
   // Update jitter buffer delay counter.
-  void JitterBufferDelay(size_t num_samples, uint64_t waiting_time_ms);
+  void JitterBufferDelay(size_t num_samples,
+                         uint64_t waiting_time_ms,
+                         uint64_t target_delay_ms);
 
   // Stores new packet waiting time in waiting time statistics.
   void StoreWaitingTime(int waiting_time_ms);
diff --git a/pc/rtc_stats_collector.cc b/pc/rtc_stats_collector.cc
index 5b34f1c..29c7d09 100644
--- a/pc/rtc_stats_collector.cc
+++ b/pc/rtc_stats_collector.cc
@@ -648,6 +648,8 @@
       voice_receiver_info.delayed_packet_outage_samples;
   audio_track_stats->relative_packet_arrival_delay =
       voice_receiver_info.relative_packet_arrival_delay_seconds;
+  audio_track_stats->jitter_buffer_target_delay =
+      voice_receiver_info.jitter_buffer_target_delay_seconds;
   audio_track_stats->interruption_count =
       voice_receiver_info.interruption_count >= 0
           ? voice_receiver_info.interruption_count
diff --git a/pc/rtc_stats_collector_unittest.cc b/pc/rtc_stats_collector_unittest.cc
index f886e14..12f6059 100644
--- a/pc/rtc_stats_collector_unittest.cc
+++ b/pc/rtc_stats_collector_unittest.cc
@@ -1547,6 +1547,7 @@
   voice_receiver_info.silent_concealed_samples = 765;
   voice_receiver_info.jitter_buffer_delay_seconds = 3456;
   voice_receiver_info.jitter_buffer_emitted_count = 13;
+  voice_receiver_info.jitter_buffer_target_delay_seconds = 7.894;
   voice_receiver_info.jitter_buffer_flushes = 7;
   voice_receiver_info.delayed_packet_outage_samples = 15;
   voice_receiver_info.relative_packet_arrival_delay_seconds = 16;
@@ -1591,6 +1592,7 @@
   expected_remote_audio_track.silent_concealed_samples = 765;
   expected_remote_audio_track.jitter_buffer_delay = 3456;
   expected_remote_audio_track.jitter_buffer_emitted_count = 13;
+  expected_remote_audio_track.jitter_buffer_target_delay = 7.894;
   expected_remote_audio_track.jitter_buffer_flushes = 7;
   expected_remote_audio_track.delayed_packet_outage_samples = 15;
   expected_remote_audio_track.relative_packet_arrival_delay = 16;
diff --git a/pc/rtc_stats_integrationtest.cc b/pc/rtc_stats_integrationtest.cc
index 93a46ef..fa7d56a 100644
--- a/pc/rtc_stats_integrationtest.cc
+++ b/pc/rtc_stats_integrationtest.cc
@@ -650,6 +650,8 @@
       verifier.TestMemberIsUndefined(media_stream_track.interruption_count);
       verifier.TestMemberIsUndefined(
           media_stream_track.total_interruption_duration);
+      verifier.TestMemberIsUndefined(
+          media_stream_track.jitter_buffer_target_delay);
     } else {
       RTC_DCHECK_EQ(*media_stream_track.kind, RTCMediaStreamTrackKind::kAudio);
       // The type of the referenced media source depends on kind.
@@ -660,6 +662,8 @@
             media_stream_track.jitter_buffer_delay);
         verifier.TestMemberIsNonNegative<uint64_t>(
             media_stream_track.jitter_buffer_emitted_count);
+        verifier.TestMemberIsNonNegative<double>(
+            media_stream_track.jitter_buffer_target_delay);
         verifier.TestMemberIsPositive<double>(media_stream_track.audio_level);
         verifier.TestMemberIsPositive<double>(
             media_stream_track.total_audio_energy);
@@ -694,6 +698,8 @@
         verifier.TestMemberIsUndefined(media_stream_track.jitter_buffer_delay);
         verifier.TestMemberIsUndefined(
             media_stream_track.jitter_buffer_emitted_count);
+        verifier.TestMemberIsUndefined(
+            media_stream_track.jitter_buffer_target_delay);
         verifier.TestMemberIsUndefined(media_stream_track.audio_level);
         verifier.TestMemberIsUndefined(media_stream_track.total_audio_energy);
         verifier.TestMemberIsUndefined(
diff --git a/stats/rtcstats_objects.cc b/stats/rtcstats_objects.cc
index 77cbc09..d99c9e7 100644
--- a/stats/rtcstats_objects.cc
+++ b/stats/rtcstats_objects.cc
@@ -395,6 +395,7 @@
                      &jitter_buffer_flushes,
                      &delayed_packet_outage_samples,
                      &relative_packet_arrival_delay,
+                     &jitter_buffer_target_delay,
                      &interruption_count,
                      &total_interruption_duration,
                      &freeze_count,
@@ -454,6 +455,7 @@
       relative_packet_arrival_delay(
           "relativePacketArrivalDelay",
           {NonStandardGroupId::kRtcStatsRelativePacketArrivalDelay}),
+      jitter_buffer_target_delay("jitterBufferTargetDelay"),
       interruption_count("interruptionCount"),
       total_interruption_duration("totalInterruptionDuration"),
       freeze_count("freezeCount"),
@@ -503,6 +505,7 @@
       jitter_buffer_flushes(other.jitter_buffer_flushes),
       delayed_packet_outage_samples(other.delayed_packet_outage_samples),
       relative_packet_arrival_delay(other.relative_packet_arrival_delay),
+      jitter_buffer_target_delay(other.jitter_buffer_target_delay),
       interruption_count(other.interruption_count),
       total_interruption_duration(other.total_interruption_duration),
       freeze_count(other.freeze_count),