Expose jitter buffer flushes metric in new getStats api.

Origin trial experiment proposal (new statistic part):
https://docs.google.com/document/d/1stYIZhEmDZ7NJF9gjjsM66eLFJUdc-14a3QutrFbIwI/edit?ts=5bf5535c#

Bug: chromium:907113
Change-Id: I1d005291f9b47665f70c26148dbdcbb55564bef8
Reviewed-on: https://webrtc-review.googlesource.com/c/111505
Reviewed-by: Karl Wiberg <kwiberg@webrtc.org>
Reviewed-by: Jonas Olsson <jonasolsson@webrtc.org>
Reviewed-by: Henrik Boström <hbos@webrtc.org>
Commit-Queue: Ruslan Burakov <kuddai@google.com>
Cr-Commit-Position: refs/heads/master@{#25768}
diff --git a/api/stats/rtcstats.h b/api/stats/rtcstats.h
index f65df28..7fd0d84 100644
--- a/api/stats/rtcstats.h
+++ b/api/stats/rtcstats.h
@@ -295,15 +295,6 @@
     is_defined_ = true;
     return value_;
   }
-  T& operator=(const RTCStatsMember<T>& other) {
-    RTC_DCHECK(other.is_defined_);
-    // Shouldn't be attempting to assign an RTCNonStandardStatsMember to an
-    // RTCStatsMember or vice versa.
-    RTC_DCHECK(is_standardized() == other.is_standardized());
-    value_ = other.value_;
-    is_defined_ = true;
-    return value_;
-  }
 
   // Value getters.
   T& operator*() {
@@ -348,6 +339,11 @@
       : RTCStatsMember<T>(std::move(other)) {}
 
   bool is_standardized() const override { return false; }
+
+  T& operator=(const T& value) { return RTCStatsMember<T>::operator=(value); }
+  T& operator=(const T&& value) {
+    return RTCStatsMember<T>::operator=(std::move(value));
+  }
 };
 }  // namespace webrtc
 
diff --git a/api/stats/rtcstats_objects.h b/api/stats/rtcstats_objects.h
index dc9da72..8496f8c 100644
--- a/api/stats/rtcstats_objects.h
+++ b/api/stats/rtcstats_objects.h
@@ -308,6 +308,9 @@
   RTCStatsMember<double> total_samples_duration;
   RTCStatsMember<uint64_t> concealed_samples;
   RTCStatsMember<uint64_t> concealment_events;
+  // Non-standard audio-only member
+  // TODO(kuddai): Add descriptoin to standard. crbug.com/webrtc/10042
+  RTCNonStandardStatsMember<uint64_t> jitter_buffer_flushes;
 };
 
 // https://w3c.github.io/webrtc-stats/#pcstats-dict*
diff --git a/audio/audio_receive_stream.cc b/audio/audio_receive_stream.cc
index 4250765..2da3877 100644
--- a/audio/audio_receive_stream.cc
+++ b/audio/audio_receive_stream.cc
@@ -213,6 +213,7 @@
   stats.secondary_discarded_rate = Q14ToFloat(ns.currentSecondaryDiscardedRate);
   stats.accelerate_rate = Q14ToFloat(ns.currentAccelerateRate);
   stats.preemptive_expand_rate = Q14ToFloat(ns.currentPreemptiveRate);
+  stats.jitter_buffer_flushes = ns.packetBufferFlushes;
 
   auto ds = channel_receive_->GetDecodingCallStatistics();
   stats.decoding_calls_to_silence_generator = ds.calls_to_silence_generator;
diff --git a/call/audio_receive_stream.h b/call/audio_receive_stream.h
index f792aa2..fe609de 100644
--- a/call/audio_receive_stream.h
+++ b/call/audio_receive_stream.h
@@ -71,6 +71,7 @@
     int32_t decoding_plc_cng = 0;
     int32_t decoding_muted_output = 0;
     int64_t capture_start_ntp_time_ms = 0;
+    uint64_t jitter_buffer_flushes = 0;
   };
 
   struct Config {
diff --git a/media/base/mediachannel.h b/media/base/mediachannel.h
index 3ab333e..04e70c5 100644
--- a/media/base/mediachannel.h
+++ b/media/base/mediachannel.h
@@ -476,6 +476,8 @@
   int decoding_muted_output = 0;
   // Estimated capture start time in NTP time in ms.
   int64_t capture_start_ntp_time_ms = -1;
+  // Count of the number of buffer flushes.
+  uint64_t jitter_buffer_flushes = 0;
 };
 
 struct VideoSenderInfo : public MediaSenderInfo {
diff --git a/media/engine/webrtcvoiceengine.cc b/media/engine/webrtcvoiceengine.cc
index 51f4582..c6751bb 100644
--- a/media/engine/webrtcvoiceengine.cc
+++ b/media/engine/webrtcvoiceengine.cc
@@ -2242,6 +2242,8 @@
     rinfo.decoding_plc_cng = stats.decoding_plc_cng;
     rinfo.decoding_muted_output = stats.decoding_muted_output;
     rinfo.capture_start_ntp_time_ms = stats.capture_start_ntp_time_ms;
+    rinfo.jitter_buffer_flushes = stats.jitter_buffer_flushes;
+
     info->receivers.push_back(rinfo);
   }
 
diff --git a/modules/audio_coding/acm2/acm_receiver.cc b/modules/audio_coding/acm2/acm_receiver.cc
index e3aa4ed..d02e50d 100644
--- a/modules/audio_coding/acm2/acm_receiver.cc
+++ b/modules/audio_coding/acm2/acm_receiver.cc
@@ -345,6 +345,11 @@
   acm_stat->concealedSamples = neteq_lifetime_stat.concealed_samples;
   acm_stat->concealmentEvents = neteq_lifetime_stat.concealment_events;
   acm_stat->jitterBufferDelayMs = neteq_lifetime_stat.jitter_buffer_delay_ms;
+
+  NetEqOperationsAndState neteq_operations_and_state =
+      neteq_->GetOperationsAndState();
+  acm_stat->packetBufferFlushes =
+      neteq_operations_and_state.packet_buffer_flushes;
 }
 
 int AcmReceiver::DecoderByPayloadType(uint8_t payload_type,
diff --git a/modules/audio_coding/include/audio_coding_module_typedefs.h b/modules/audio_coding/include/audio_coding_module_typedefs.h
index 8946afd..3c746de 100644
--- a/modules/audio_coding/include/audio_coding_module_typedefs.h
+++ b/modules/audio_coding/include/audio_coding_module_typedefs.h
@@ -117,6 +117,8 @@
   int maxWaitingTimeMs;
   // added samples in off mode due to packet loss
   size_t addedSamples;
+  // count of the number of buffer flushes
+  uint64_t packetBufferFlushes;
 };
 
 }  // namespace webrtc
diff --git a/pc/rtcstats_integrationtest.cc b/pc/rtcstats_integrationtest.cc
index f9375f7..46687ba 100644
--- a/pc/rtcstats_integrationtest.cc
+++ b/pc/rtcstats_integrationtest.cc
@@ -604,11 +604,14 @@
           media_stream_track.concealed_samples);
       verifier.TestMemberIsNonNegative<uint64_t>(
           media_stream_track.concealment_events);
+      verifier.TestMemberIsNonNegative<uint64_t>(
+          media_stream_track.jitter_buffer_flushes);
     } else {
       verifier.TestMemberIsUndefined(media_stream_track.jitter_buffer_delay);
       verifier.TestMemberIsUndefined(media_stream_track.total_samples_received);
       verifier.TestMemberIsUndefined(media_stream_track.concealed_samples);
       verifier.TestMemberIsUndefined(media_stream_track.concealment_events);
+      verifier.TestMemberIsUndefined(media_stream_track.jitter_buffer_flushes);
     }
     return verifier.ExpectAllMembersSuccessfullyTested();
   }
diff --git a/pc/rtcstatscollector.cc b/pc/rtcstatscollector.cc
index 871cff9..33d4af1 100644
--- a/pc/rtcstatscollector.cc
+++ b/pc/rtcstatscollector.cc
@@ -454,6 +454,8 @@
   audio_track_stats->concealed_samples = voice_receiver_info.concealed_samples;
   audio_track_stats->concealment_events =
       voice_receiver_info.concealment_events;
+  audio_track_stats->jitter_buffer_flushes =
+      voice_receiver_info.jitter_buffer_flushes;
   return audio_track_stats;
 }
 
diff --git a/pc/rtcstatscollector_unittest.cc b/pc/rtcstatscollector_unittest.cc
index 3fc0127..e16c7e3 100644
--- a/pc/rtcstatscollector_unittest.cc
+++ b/pc/rtcstatscollector_unittest.cc
@@ -1426,6 +1426,7 @@
   voice_receiver_info.concealed_samples = 123;
   voice_receiver_info.concealment_events = 12;
   voice_receiver_info.jitter_buffer_delay_seconds = 3456;
+  voice_receiver_info.jitter_buffer_flushes = 7;
 
   stats_->CreateMockRtpSendersReceiversAndChannels(
       {}, {std::make_pair(remote_audio_track.get(), voice_receiver_info)}, {},
@@ -1459,6 +1460,7 @@
   expected_remote_audio_track.concealed_samples = 123;
   expected_remote_audio_track.concealment_events = 12;
   expected_remote_audio_track.jitter_buffer_delay = 3456;
+  expected_remote_audio_track.jitter_buffer_flushes = 7;
   ASSERT_TRUE(report->Get(expected_remote_audio_track.id()));
   EXPECT_EQ(expected_remote_audio_track,
             report->Get(expected_remote_audio_track.id())
diff --git a/stats/rtcstats_objects.cc b/stats/rtcstats_objects.cc
index dcc1180..669db14 100644
--- a/stats/rtcstats_objects.cc
+++ b/stats/rtcstats_objects.cc
@@ -374,7 +374,8 @@
                      &total_samples_received,
                      &total_samples_duration,
                      &concealed_samples,
-                     &concealment_events);
+                     &concealment_events,
+                     &jitter_buffer_flushes);
 // clang-format on
 
 RTCMediaStreamTrackStats::RTCMediaStreamTrackStats(const std::string& id,
@@ -410,7 +411,8 @@
       total_samples_received("totalSamplesReceived"),
       total_samples_duration("totalSamplesDuration"),
       concealed_samples("concealedSamples"),
-      concealment_events("concealmentEvents") {
+      concealment_events("concealmentEvents"),
+      jitter_buffer_flushes("jitterBufferFlushes") {
   RTC_DCHECK(kind == RTCMediaStreamTrackKind::kAudio ||
              kind == RTCMediaStreamTrackKind::kVideo);
 }
@@ -442,7 +444,8 @@
       total_samples_received(other.total_samples_received),
       total_samples_duration(other.total_samples_duration),
       concealed_samples(other.concealed_samples),
-      concealment_events(other.concealment_events) {}
+      concealment_events(other.concealment_events),
+      jitter_buffer_flushes(other.jitter_buffer_flushes) {}
 
 RTCMediaStreamTrackStats::~RTCMediaStreamTrackStats() {}