Expose new audio stats on the API

Several new audio stats were recently standardized and implemented in
WebRTC in https://webrtc-review.googlesource.com/c/src/+/133887. This CL
adds these to the GetStats API.

Bug: webrtc:10442, webrtc:10443, webrtc:10444
Change-Id: I0e898ac14777e82b1a9099b5e0a5584eb9cb5934
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/134213
Reviewed-by: Karl Wiberg <kwiberg@webrtc.org>
Reviewed-by: Henrik Boström <hbos@webrtc.org>
Commit-Queue: Ivo Creusen <ivoc@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#27839}
diff --git a/api/stats/rtcstats_objects.h b/api/stats/rtcstats_objects.h
index 96c7a03..d614a86 100644
--- a/api/stats/rtcstats_objects.h
+++ b/api/stats/rtcstats_objects.h
@@ -315,7 +315,10 @@
   RTCStatsMember<uint64_t> total_samples_received;
   RTCStatsMember<double> total_samples_duration;
   RTCStatsMember<uint64_t> concealed_samples;
+  RTCStatsMember<uint64_t> silent_concealed_samples;
   RTCStatsMember<uint64_t> concealment_events;
+  RTCStatsMember<uint64_t> inserted_samples_for_deceleration;
+  RTCStatsMember<uint64_t> removed_samples_for_acceleration;
   // Non-standard audio-only member
   // TODO(kuddai): Add description to standard. crbug.com/webrtc/10042
   RTCNonStandardStatsMember<uint64_t> jitter_buffer_flushes;
@@ -399,6 +402,8 @@
   ~RTCInboundRTPStreamStats() override;
 
   RTCStatsMember<uint32_t> packets_received;
+  RTCStatsMember<uint64_t> fec_packets_received;
+  RTCStatsMember<uint64_t> fec_packets_discarded;
   RTCStatsMember<uint64_t> bytes_received;
   RTCStatsMember<int32_t> packets_lost;  // Signed per RFC 3550
   RTCStatsMember<double> last_packet_received_timestamp;
diff --git a/audio/audio_receive_stream.cc b/audio/audio_receive_stream.cc
index 677ee20..b98c213 100644
--- a/audio/audio_receive_stream.cc
+++ b/audio/audio_receive_stream.cc
@@ -206,15 +206,20 @@
 
   // Get jitter buffer and total delay (alg + jitter + playout) stats.
   auto ns = channel_receive_->GetNetworkStatistics();
+  stats.fec_packets_received = ns.fecPacketsReceived;
+  stats.fec_packets_discarded = ns.fecPacketsDiscarded;
   stats.jitter_buffer_ms = ns.currentBufferSize;
   stats.jitter_buffer_preferred_ms = ns.preferredBufferSize;
   stats.total_samples_received = ns.totalSamplesReceived;
   stats.concealed_samples = ns.concealedSamples;
+  stats.silent_concealed_samples = ns.silentConcealedSamples;
   stats.concealment_events = ns.concealmentEvents;
   stats.jitter_buffer_delay_seconds =
       static_cast<double>(ns.jitterBufferDelayMs) /
       static_cast<double>(rtc::kNumMillisecsPerSec);
   stats.jitter_buffer_emitted_count = ns.jitterBufferEmittedCount;
+  stats.inserted_samples_for_deceleration = ns.insertedSamplesForDeceleration;
+  stats.removed_samples_for_acceleration = ns.removedSamplesForAcceleration;
   stats.expand_rate = Q14ToFloat(ns.currentExpandRate);
   stats.speech_expand_rate = Q14ToFloat(ns.currentSpeechExpandRate);
   stats.secondary_decoded_rate = Q14ToFloat(ns.currentSecondaryDecodedRate);
diff --git a/audio/audio_receive_stream_unittest.cc b/audio/audio_receive_stream_unittest.cc
index 127f2ff..303e0e8 100644
--- a/audio/audio_receive_stream_unittest.cc
+++ b/audio/audio_receive_stream_unittest.cc
@@ -67,8 +67,9 @@
     123,
     {"codec_name_recv", 96000, 0}};
 const NetworkStatistics kNetworkStats = {
-    123, 456, false, 789012, 3456, 123, 456, 789, 0,  {}, 789,
-    12,  345, 678,   901,    0,    -1,  -1,  -1,  -1, -1, 0};
+    123, 456, false, 789012, 3456, 123, 456, 789, 543, 432,
+    321, 123, 101,   0,      {},   789, 12,  345, 678, 901,
+    0,   -1,  -1,    -1,     -1,   -1,  0,   0,   0,   0};
 const AudioDecodingCallStats kAudioDecodeStats = MakeAudioDecodeStatsForTest();
 
 struct ConfigHelper {
diff --git a/call/audio_receive_stream.h b/call/audio_receive_stream.h
index 9091afd..35c6ef7 100644
--- a/call/audio_receive_stream.h
+++ b/call/audio_receive_stream.h
@@ -38,6 +38,8 @@
     uint32_t remote_ssrc = 0;
     int64_t bytes_rcvd = 0;
     uint32_t packets_rcvd = 0;
+    uint64_t fec_packets_received = 0;
+    uint64_t fec_packets_discarded = 0;
     uint32_t packets_lost = 0;
     float fraction_lost = 0.0f;
     std::string codec_name;
@@ -54,9 +56,12 @@
     uint64_t total_samples_received = 0;
     double total_output_duration = 0.0;
     uint64_t concealed_samples = 0;
+    uint64_t silent_concealed_samples = 0;
     uint64_t concealment_events = 0;
     double jitter_buffer_delay_seconds = 0.0;
     uint64_t jitter_buffer_emitted_count = 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
     float expand_rate = 0.0f;
     float speech_expand_rate = 0.0f;
diff --git a/media/base/media_channel.h b/media/base/media_channel.h
index 69570e7..15721c5 100644
--- a/media/base/media_channel.h
+++ b/media/base/media_channel.h
@@ -479,9 +479,14 @@
   uint64_t total_samples_received = 0;
   double total_output_duration = 0.0;
   uint64_t concealed_samples = 0;
+  uint64_t silent_concealed_samples = 0;
   uint64_t concealment_events = 0;
   double jitter_buffer_delay_seconds = 0.0;
   uint64_t jitter_buffer_emitted_count = 0;
+  uint64_t inserted_samples_for_deceleration = 0;
+  uint64_t removed_samples_for_acceleration = 0;
+  uint64_t fec_packets_received = 0;
+  uint64_t fec_packets_discarded = 0;
   // Stats below DO NOT correspond directly to anything in the WebRTC stats
   // fraction of synthesized audio inserted through expansion.
   float expand_rate = 0.0f;
diff --git a/media/engine/webrtc_voice_engine.cc b/media/engine/webrtc_voice_engine.cc
index 3b85064..a3b375a 100644
--- a/media/engine/webrtc_voice_engine.cc
+++ b/media/engine/webrtc_voice_engine.cc
@@ -2226,6 +2226,8 @@
     rinfo.add_ssrc(stats.remote_ssrc);
     rinfo.bytes_rcvd = stats.bytes_rcvd;
     rinfo.packets_rcvd = stats.packets_rcvd;
+    rinfo.fec_packets_received = stats.fec_packets_received;
+    rinfo.fec_packets_discarded = stats.fec_packets_discarded;
     rinfo.packets_lost = stats.packets_lost;
     rinfo.fraction_lost = stats.fraction_lost;
     rinfo.codec_name = stats.codec_name;
@@ -2240,9 +2242,14 @@
     rinfo.total_samples_received = stats.total_samples_received;
     rinfo.total_output_duration = stats.total_output_duration;
     rinfo.concealed_samples = stats.concealed_samples;
+    rinfo.silent_concealed_samples = stats.silent_concealed_samples;
     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.inserted_samples_for_deceleration =
+        stats.inserted_samples_for_deceleration;
+    rinfo.removed_samples_for_acceleration =
+        stats.removed_samples_for_acceleration;
     rinfo.expand_rate = stats.expand_rate;
     rinfo.speech_expand_rate = stats.speech_expand_rate;
     rinfo.secondary_decoded_rate = stats.secondary_decoded_rate;
diff --git a/modules/audio_coding/acm2/acm_receiver.cc b/modules/audio_coding/acm2/acm_receiver.cc
index c10a71c..3bce0c4 100644
--- a/modules/audio_coding/acm2/acm_receiver.cc
+++ b/modules/audio_coding/acm2/acm_receiver.cc
@@ -251,6 +251,8 @@
   NetEqLifetimeStatistics neteq_lifetime_stat = neteq_->GetLifetimeStatistics();
   acm_stat->totalSamplesReceived = neteq_lifetime_stat.total_samples_received;
   acm_stat->concealedSamples = neteq_lifetime_stat.concealed_samples;
+  acm_stat->silentConcealedSamples =
+      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->jitterBufferEmittedCount =
@@ -262,6 +264,12 @@
   acm_stat->interruptionCount = neteq_lifetime_stat.interruption_count;
   acm_stat->totalInterruptionDurationMs =
       neteq_lifetime_stat.total_interruption_duration_ms;
+  acm_stat->insertedSamplesForDeceleration =
+      neteq_lifetime_stat.inserted_samples_for_deceleration;
+  acm_stat->removedSamplesForAcceleration =
+      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;
 
   NetEqOperationsAndState neteq_operations_and_state =
       neteq_->GetOperationsAndState();
diff --git a/modules/audio_coding/include/audio_coding_module_typedefs.h b/modules/audio_coding/include/audio_coding_module_typedefs.h
index 621c478..d256fd1 100644
--- a/modules/audio_coding/include/audio_coding_module_typedefs.h
+++ b/modules/audio_coding/include/audio_coding_module_typedefs.h
@@ -84,9 +84,14 @@
   // https://w3c.github.io/webrtc-stats/#dom-rtcmediastreamtrackstats
   uint64_t totalSamplesReceived;
   uint64_t concealedSamples;
+  uint64_t silentConcealedSamples;
   uint64_t concealmentEvents;
   uint64_t jitterBufferDelayMs;
   uint64_t jitterBufferEmittedCount;
+  uint64_t insertedSamplesForDeceleration;
+  uint64_t removedSamplesForAcceleration;
+  uint64_t fecPacketsReceived;
+  uint64_t fecPacketsDiscarded;
   // Stats below DO NOT correspond directly to anything in the WebRTC stats
   // Loss rate (network + late); fraction between 0 and 1, scaled to Q14.
   uint16_t currentPacketLossRate;
diff --git a/pc/rtc_stats_collector.cc b/pc/rtc_stats_collector.cc
index 8849d86..0d1fbba 100644
--- a/pc/rtc_stats_collector.cc
+++ b/pc/rtc_stats_collector.cc
@@ -250,6 +250,10 @@
             *voice_receiver_info.last_packet_received_timestamp_ms) /
         rtc::kNumMillisecsPerSec;
   }
+  inbound_audio->fec_packets_received =
+      voice_receiver_info.fec_packets_received;
+  inbound_audio->fec_packets_discarded =
+      voice_receiver_info.fec_packets_discarded;
 }
 
 void SetInboundRTPStreamStatsFromVideoReceiverInfo(
@@ -475,6 +479,10 @@
       voice_receiver_info.jitter_buffer_delay_seconds;
   audio_track_stats->jitter_buffer_emitted_count =
       voice_receiver_info.jitter_buffer_emitted_count;
+  audio_track_stats->inserted_samples_for_deceleration =
+      voice_receiver_info.inserted_samples_for_deceleration;
+  audio_track_stats->removed_samples_for_acceleration =
+      voice_receiver_info.removed_samples_for_acceleration;
   audio_track_stats->total_audio_energy =
       voice_receiver_info.total_output_energy;
   audio_track_stats->total_samples_received =
@@ -482,6 +490,8 @@
   audio_track_stats->total_samples_duration =
       voice_receiver_info.total_output_duration;
   audio_track_stats->concealed_samples = voice_receiver_info.concealed_samples;
+  audio_track_stats->silent_concealed_samples =
+      voice_receiver_info.silent_concealed_samples;
   audio_track_stats->concealment_events =
       voice_receiver_info.concealment_events;
   audio_track_stats->jitter_buffer_flushes =
@@ -921,7 +931,7 @@
 void RTCStatsCollector::ProducePartialResultsOnNetworkThread(
     int64_t timestamp_us) {
   RTC_DCHECK(network_thread_->IsCurrent());
-  // Touching |network_report_| on this thread is safe by this method because
+  // Touching |network_report_| on this thread is safe by this method because
   // |network_report_event_| is reset before this method is invoked.
   network_report_ = RTCStatsReport::Create(timestamp_us);
 
diff --git a/pc/rtc_stats_collector_unittest.cc b/pc/rtc_stats_collector_unittest.cc
index 0539379..a6531d2 100644
--- a/pc/rtc_stats_collector_unittest.cc
+++ b/pc/rtc_stats_collector_unittest.cc
@@ -1424,6 +1424,9 @@
   voice_receiver_info.total_output_duration = 0.25;
   voice_receiver_info.concealed_samples = 123;
   voice_receiver_info.concealment_events = 12;
+  voice_receiver_info.inserted_samples_for_deceleration = 987;
+  voice_receiver_info.removed_samples_for_acceleration = 876;
+  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_flushes = 7;
@@ -1463,6 +1466,9 @@
   expected_remote_audio_track.total_samples_duration = 0.25;
   expected_remote_audio_track.concealed_samples = 123;
   expected_remote_audio_track.concealment_events = 12;
+  expected_remote_audio_track.inserted_samples_for_deceleration = 987;
+  expected_remote_audio_track.removed_samples_for_acceleration = 876;
+  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_flushes = 7;
@@ -1625,6 +1631,8 @@
   voice_media_info.receivers[0].local_stats[0].ssrc = 1;
   voice_media_info.receivers[0].packets_lost = -1;  // Signed per RFC3550
   voice_media_info.receivers[0].packets_rcvd = 2;
+  voice_media_info.receivers[0].fec_packets_discarded = 5566;
+  voice_media_info.receivers[0].fec_packets_received = 6677;
   voice_media_info.receivers[0].bytes_rcvd = 3;
   voice_media_info.receivers[0].codec_payload_type = 42;
   voice_media_info.receivers[0].jitter_ms = 4500;
@@ -1660,6 +1668,8 @@
   expected_audio.transport_id = "RTCTransport_TransportName_1";
   expected_audio.codec_id = "RTCCodec_AudioMid_Inbound_42";
   expected_audio.packets_received = 2;
+  expected_audio.fec_packets_discarded = 5566;
+  expected_audio.fec_packets_received = 6677;
   expected_audio.bytes_received = 3;
   expected_audio.packets_lost = -1;
   // |expected_audio.last_packet_received_timestamp| should be undefined.
diff --git a/pc/rtc_stats_integrationtest.cc b/pc/rtc_stats_integrationtest.cc
index d576c60..a751599 100644
--- a/pc/rtc_stats_integrationtest.cc
+++ b/pc/rtc_stats_integrationtest.cc
@@ -649,6 +649,12 @@
       verifier.TestMemberIsNonNegative<uint64_t>(
           media_stream_track.concealment_events);
       verifier.TestMemberIsNonNegative<uint64_t>(
+          media_stream_track.inserted_samples_for_deceleration);
+      verifier.TestMemberIsNonNegative<uint64_t>(
+          media_stream_track.removed_samples_for_acceleration);
+      verifier.TestMemberIsNonNegative<uint64_t>(
+          media_stream_track.silent_concealed_samples);
+      verifier.TestMemberIsNonNegative<uint64_t>(
           media_stream_track.jitter_buffer_flushes);
       verifier.TestMemberIsNonNegative<uint64_t>(
           media_stream_track.delayed_packet_outage_samples);
@@ -722,6 +728,13 @@
       verifier.TestMemberIsUndefined(inbound_stream.qp_sum);
     }
     verifier.TestMemberIsNonNegative<uint32_t>(inbound_stream.packets_received);
+    if (inbound_stream.media_type.is_defined() &&
+        *inbound_stream.media_type == "audio") {
+      verifier.TestMemberIsNonNegative<uint64_t>(
+          inbound_stream.fec_packets_received);
+      verifier.TestMemberIsNonNegative<uint64_t>(
+          inbound_stream.fec_packets_discarded);
+    }
     verifier.TestMemberIsNonNegative<uint64_t>(inbound_stream.bytes_received);
     // packets_lost is defined as signed, but this should never happen in
     // this test. See RFC 3550.
diff --git a/stats/rtcstats_objects.cc b/stats/rtcstats_objects.cc
index 6c914e7..2aa2cd2 100644
--- a/stats/rtcstats_objects.cc
+++ b/stats/rtcstats_objects.cc
@@ -433,7 +433,10 @@
       total_samples_received("totalSamplesReceived"),
       total_samples_duration("totalSamplesDuration"),
       concealed_samples("concealedSamples"),
+      silent_concealed_samples("silentConcealedSamples"),
       concealment_events("concealmentEvents"),
+      inserted_samples_for_deceleration("insertedSamplesForDeceleration"),
+      removed_samples_for_acceleration("removedSamplesForAcceleration"),
       jitter_buffer_flushes(
           "jitterBufferFlushes",
           {NonStandardGroupId::kRtcAudioJitterBufferMaxPackets}),
@@ -484,7 +487,11 @@
       total_samples_received(other.total_samples_received),
       total_samples_duration(other.total_samples_duration),
       concealed_samples(other.concealed_samples),
+      silent_concealed_samples(other.silent_concealed_samples),
       concealment_events(other.concealment_events),
+      inserted_samples_for_deceleration(
+          other.inserted_samples_for_deceleration),
+      removed_samples_for_acceleration(other.removed_samples_for_acceleration),
       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),
@@ -610,6 +617,8 @@
                                                    int64_t timestamp_us)
     : RTCRTPStreamStats(std::move(id), timestamp_us),
       packets_received("packetsReceived"),
+      fec_packets_received("fecPacketsReceived"),
+      fec_packets_discarded("fecPacketsDiscarded"),
       bytes_received("bytesReceived"),
       packets_lost("packetsLost"),
       last_packet_received_timestamp("lastPacketReceivedTimestamp"),
@@ -633,6 +642,8 @@
     const RTCInboundRTPStreamStats& other)
     : RTCRTPStreamStats(other),
       packets_received(other.packets_received),
+      fec_packets_received(other.fec_packets_received),
+      fec_packets_discarded(other.fec_packets_discarded),
       bytes_received(other.bytes_received),
       packets_lost(other.packets_lost),
       last_packet_received_timestamp(other.last_packet_received_timestamp),