diff --git a/api/stats/rtcstats.h b/api/stats/rtcstats.h index f65df289e1..7fd0d84e0b 100644 --- a/api/stats/rtcstats.h +++ b/api/stats/rtcstats.h @@ -295,15 +295,6 @@ class RTC_EXPORT RTCStatsMember : public RTCStatsMemberInterface { is_defined_ = true; return value_; } - T& operator=(const RTCStatsMember& 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 @@ class RTCNonStandardStatsMember : public RTCStatsMember { : RTCStatsMember(std::move(other)) {} bool is_standardized() const override { return false; } + + T& operator=(const T& value) { return RTCStatsMember::operator=(value); } + T& operator=(const T&& value) { + return RTCStatsMember::operator=(std::move(value)); + } }; } // namespace webrtc diff --git a/api/stats/rtcstats_objects.h b/api/stats/rtcstats_objects.h index dc9da72ec9..8496f8caa2 100644 --- a/api/stats/rtcstats_objects.h +++ b/api/stats/rtcstats_objects.h @@ -308,6 +308,9 @@ class RTC_EXPORT RTCMediaStreamTrackStats final : public RTCStats { RTCStatsMember total_samples_duration; RTCStatsMember concealed_samples; RTCStatsMember concealment_events; + // Non-standard audio-only member + // TODO(kuddai): Add descriptoin to standard. crbug.com/webrtc/10042 + RTCNonStandardStatsMember 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 42507656ec..2da387713b 100644 --- a/audio/audio_receive_stream.cc +++ b/audio/audio_receive_stream.cc @@ -213,6 +213,7 @@ webrtc::AudioReceiveStream::Stats AudioReceiveStream::GetStats() const { 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 f792aa2f04..fe609de72d 100644 --- a/call/audio_receive_stream.h +++ b/call/audio_receive_stream.h @@ -71,6 +71,7 @@ class AudioReceiveStream { 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 3ab333ec7c..04e70c5122 100644 --- a/media/base/mediachannel.h +++ b/media/base/mediachannel.h @@ -476,6 +476,8 @@ struct VoiceReceiverInfo : public MediaReceiverInfo { 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 51f4582cf4..c6751bb59e 100644 --- a/media/engine/webrtcvoiceengine.cc +++ b/media/engine/webrtcvoiceengine.cc @@ -2242,6 +2242,8 @@ bool WebRtcVoiceMediaChannel::GetStats(VoiceMediaInfo* info) { 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 e3aa4ed3e2..d02e50d43d 100644 --- a/modules/audio_coding/acm2/acm_receiver.cc +++ b/modules/audio_coding/acm2/acm_receiver.cc @@ -345,6 +345,11 @@ void AcmReceiver::GetNetworkStatistics(NetworkStatistics* acm_stat) { 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 8946afd1a3..3c746de883 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 @@ struct NetworkStatistics { 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 f9375f7415..46687bab5f 100644 --- a/pc/rtcstats_integrationtest.cc +++ b/pc/rtcstats_integrationtest.cc @@ -604,11 +604,14 @@ class RTCStatsReportVerifier { media_stream_track.concealed_samples); verifier.TestMemberIsNonNegative( media_stream_track.concealment_events); + verifier.TestMemberIsNonNegative( + 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 871cff9726..33d4af1bec 100644 --- a/pc/rtcstatscollector.cc +++ b/pc/rtcstatscollector.cc @@ -454,6 +454,8 @@ ProduceMediaStreamTrackStatsFromVoiceReceiverInfo( 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 3fc0127b48..e16c7e302b 100644 --- a/pc/rtcstatscollector_unittest.cc +++ b/pc/rtcstatscollector_unittest.cc @@ -1426,6 +1426,7 @@ TEST_F(RTCStatsCollectorTest, 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 @@ TEST_F(RTCStatsCollectorTest, 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 dcc1180f16..669db14fc8 100644 --- a/stats/rtcstats_objects.cc +++ b/stats/rtcstats_objects.cc @@ -374,7 +374,8 @@ WEBRTC_RTCSTATS_IMPL(RTCMediaStreamTrackStats, RTCStats, "track", &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 @@ RTCMediaStreamTrackStats::RTCMediaStreamTrackStats(std::string&& id, 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 @@ RTCMediaStreamTrackStats::RTCMediaStreamTrackStats( 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() {}