From 8d8ffdbccacb6664cfa5f8d781fb7c2a362a6c10 Mon Sep 17 00:00:00 2001 From: Ivo Creusen Date: Tue, 30 Apr 2019 09:45:21 +0200 Subject: [PATCH] Expose new audio stats on the API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Reviewed-by: Henrik Boström Commit-Queue: Ivo Creusen Cr-Commit-Position: refs/heads/master@{#27839} --- api/stats/rtcstats_objects.h | 5 +++++ audio/audio_receive_stream.cc | 5 +++++ audio/audio_receive_stream_unittest.cc | 5 +++-- call/audio_receive_stream.h | 5 +++++ media/base/media_channel.h | 5 +++++ media/engine/webrtc_voice_engine.cc | 7 +++++++ modules/audio_coding/acm2/acm_receiver.cc | 8 ++++++++ .../include/audio_coding_module_typedefs.h | 5 +++++ pc/rtc_stats_collector.cc | 12 +++++++++++- pc/rtc_stats_collector_unittest.cc | 10 ++++++++++ pc/rtc_stats_integrationtest.cc | 13 +++++++++++++ stats/rtcstats_objects.cc | 11 +++++++++++ 12 files changed, 88 insertions(+), 3 deletions(-) diff --git a/api/stats/rtcstats_objects.h b/api/stats/rtcstats_objects.h index 96c7a033e8..d614a869f2 100644 --- a/api/stats/rtcstats_objects.h +++ b/api/stats/rtcstats_objects.h @@ -315,7 +315,10 @@ class RTC_EXPORT RTCMediaStreamTrackStats final : public RTCStats { RTCStatsMember total_samples_received; RTCStatsMember total_samples_duration; RTCStatsMember concealed_samples; + RTCStatsMember silent_concealed_samples; RTCStatsMember concealment_events; + RTCStatsMember inserted_samples_for_deceleration; + RTCStatsMember removed_samples_for_acceleration; // Non-standard audio-only member // TODO(kuddai): Add description to standard. crbug.com/webrtc/10042 RTCNonStandardStatsMember jitter_buffer_flushes; @@ -399,6 +402,8 @@ class RTC_EXPORT RTCInboundRTPStreamStats final : public RTCRTPStreamStats { ~RTCInboundRTPStreamStats() override; RTCStatsMember packets_received; + RTCStatsMember fec_packets_received; + RTCStatsMember fec_packets_discarded; RTCStatsMember bytes_received; RTCStatsMember packets_lost; // Signed per RFC 3550 RTCStatsMember last_packet_received_timestamp; diff --git a/audio/audio_receive_stream.cc b/audio/audio_receive_stream.cc index 677ee207ee..b98c213d15 100644 --- a/audio/audio_receive_stream.cc +++ b/audio/audio_receive_stream.cc @@ -206,15 +206,20 @@ webrtc::AudioReceiveStream::Stats AudioReceiveStream::GetStats() const { // 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(ns.jitterBufferDelayMs) / static_cast(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 127f2ff60c..303e0e8225 100644 --- a/audio/audio_receive_stream_unittest.cc +++ b/audio/audio_receive_stream_unittest.cc @@ -67,8 +67,9 @@ const std::pair kReceiveCodec = { 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 9091afd5ce..35c6ef70e2 100644 --- a/call/audio_receive_stream.h +++ b/call/audio_receive_stream.h @@ -38,6 +38,8 @@ class AudioReceiveStream { 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 @@ class AudioReceiveStream { 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 69570e7e65..15721c5948 100644 --- a/media/base/media_channel.h +++ b/media/base/media_channel.h @@ -479,9 +479,14 @@ struct VoiceReceiverInfo : public MediaReceiverInfo { 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 3b85064dd8..a3b375a8df 100644 --- a/media/engine/webrtc_voice_engine.cc +++ b/media/engine/webrtc_voice_engine.cc @@ -2226,6 +2226,8 @@ bool WebRtcVoiceMediaChannel::GetStats(VoiceMediaInfo* info) { 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 @@ bool WebRtcVoiceMediaChannel::GetStats(VoiceMediaInfo* info) { 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 c10a71ca6b..3bce0c4063 100644 --- a/modules/audio_coding/acm2/acm_receiver.cc +++ b/modules/audio_coding/acm2/acm_receiver.cc @@ -251,6 +251,8 @@ void AcmReceiver::GetNetworkStatistics(NetworkStatistics* acm_stat) { 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 @@ void AcmReceiver::GetNetworkStatistics(NetworkStatistics* acm_stat) { 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 621c478dc1..d256fd1860 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 @@ struct NetworkStatistics { // 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 8849d8614c..0d1fbba25a 100644 --- a/pc/rtc_stats_collector.cc +++ b/pc/rtc_stats_collector.cc @@ -250,6 +250,10 @@ void SetInboundRTPStreamStatsFromVoiceReceiverInfo( *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 @@ ProduceMediaStreamTrackStatsFromVoiceReceiverInfo( 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 @@ ProduceMediaStreamTrackStatsFromVoiceReceiverInfo( 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::ProducePartialResultsOnSignalingThreadImpl( 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 0539379564..a6531d2ac8 100644 --- a/pc/rtc_stats_collector_unittest.cc +++ b/pc/rtc_stats_collector_unittest.cc @@ -1424,6 +1424,9 @@ TEST_F(RTCStatsCollectorTest, 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 @@ TEST_F(RTCStatsCollectorTest, 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 @@ TEST_F(RTCStatsCollectorTest, CollectRTCInboundRTPStreamStats_Audio) { 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 @@ TEST_F(RTCStatsCollectorTest, CollectRTCInboundRTPStreamStats_Audio) { 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 d576c6082a..a7515993a9 100644 --- a/pc/rtc_stats_integrationtest.cc +++ b/pc/rtc_stats_integrationtest.cc @@ -648,6 +648,12 @@ class RTCStatsReportVerifier { media_stream_track.concealed_samples); verifier.TestMemberIsNonNegative( media_stream_track.concealment_events); + verifier.TestMemberIsNonNegative( + media_stream_track.inserted_samples_for_deceleration); + verifier.TestMemberIsNonNegative( + media_stream_track.removed_samples_for_acceleration); + verifier.TestMemberIsNonNegative( + media_stream_track.silent_concealed_samples); verifier.TestMemberIsNonNegative( media_stream_track.jitter_buffer_flushes); verifier.TestMemberIsNonNegative( @@ -722,6 +728,13 @@ class RTCStatsReportVerifier { verifier.TestMemberIsUndefined(inbound_stream.qp_sum); } verifier.TestMemberIsNonNegative(inbound_stream.packets_received); + if (inbound_stream.media_type.is_defined() && + *inbound_stream.media_type == "audio") { + verifier.TestMemberIsNonNegative( + inbound_stream.fec_packets_received); + verifier.TestMemberIsNonNegative( + inbound_stream.fec_packets_discarded); + } verifier.TestMemberIsNonNegative(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 6c914e7768..2aa2cd2e28 100644 --- a/stats/rtcstats_objects.cc +++ b/stats/rtcstats_objects.cc @@ -433,7 +433,10 @@ RTCMediaStreamTrackStats::RTCMediaStreamTrackStats(std::string&& id, 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 @@ RTCMediaStreamTrackStats::RTCMediaStreamTrackStats( 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 @@ RTCInboundRTPStreamStats::RTCInboundRTPStreamStats(std::string&& id, 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 @@ RTCInboundRTPStreamStats::RTCInboundRTPStreamStats( 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),