diff --git a/api/stats/rtcstats_objects.h b/api/stats/rtcstats_objects.h index 8abf224e09..e07e5a0054 100644 --- a/api/stats/rtcstats_objects.h +++ b/api/stats/rtcstats_objects.h @@ -314,6 +314,7 @@ class RTC_EXPORT RTCMediaStreamTrackStats final : public RTCStats { // TODO(kuddai): Add description to standard. crbug.com/webrtc/10042 RTCNonStandardStatsMember jitter_buffer_flushes; RTCNonStandardStatsMember delayed_packet_outage_samples; + RTCNonStandardStatsMember relative_packet_arrival_delay; // Non-standard video-only members. // https://henbos.github.io/webrtc-provisional-stats/#RTCVideoReceiverStats-dict* RTCNonStandardStatsMember freeze_count; diff --git a/audio/audio_receive_stream.cc b/audio/audio_receive_stream.cc index 00991886d8..584f1f9abd 100644 --- a/audio/audio_receive_stream.cc +++ b/audio/audio_receive_stream.cc @@ -221,6 +221,9 @@ webrtc::AudioReceiveStream::Stats AudioReceiveStream::GetStats() const { stats.preemptive_expand_rate = Q14ToFloat(ns.currentPreemptiveRate); stats.jitter_buffer_flushes = ns.packetBufferFlushes; stats.delayed_packet_outage_samples = ns.delayedPacketOutageSamples; + stats.relative_packet_arrival_delay_seconds = + static_cast(ns.relativePacketArrivalDelayMs) / + static_cast(rtc::kNumMillisecsPerSec); 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 64934b469a..194e8ae365 100644 --- a/call/audio_receive_stream.h +++ b/call/audio_receive_stream.h @@ -74,6 +74,7 @@ class AudioReceiveStream { int32_t decoding_muted_output = 0; int64_t capture_start_ntp_time_ms = 0; uint64_t jitter_buffer_flushes = 0; + double relative_packet_arrival_delay_seconds = 0.0; }; struct Config { diff --git a/media/base/media_channel.h b/media/base/media_channel.h index 4106949605..bd703dc624 100644 --- a/media/base/media_channel.h +++ b/media/base/media_channel.h @@ -487,6 +487,8 @@ struct VoiceReceiverInfo : public MediaReceiverInfo { uint64_t jitter_buffer_flushes = 0; // Number of samples expanded due to delayed packets. uint64_t delayed_packet_outage_samples = 0; + // Arrival delay of received audio packets. + double relative_packet_arrival_delay_seconds = 0.0; }; struct VideoSenderInfo : public MediaSenderInfo { diff --git a/media/engine/webrtc_voice_engine.cc b/media/engine/webrtc_voice_engine.cc index 1f1b585cd7..fe1de34fe1 100644 --- a/media/engine/webrtc_voice_engine.cc +++ b/media/engine/webrtc_voice_engine.cc @@ -2278,6 +2278,8 @@ bool WebRtcVoiceMediaChannel::GetStats(VoiceMediaInfo* info) { 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; + rinfo.relative_packet_arrival_delay_seconds = + stats.relative_packet_arrival_delay_seconds; info->receivers.push_back(rinfo); } diff --git a/modules/audio_coding/acm2/acm_receiver.cc b/modules/audio_coding/acm2/acm_receiver.cc index d296a57658..da7d62101b 100644 --- a/modules/audio_coding/acm2/acm_receiver.cc +++ b/modules/audio_coding/acm2/acm_receiver.cc @@ -257,6 +257,8 @@ void AcmReceiver::GetNetworkStatistics(NetworkStatistics* acm_stat) { neteq_lifetime_stat.jitter_buffer_emitted_count; acm_stat->delayedPacketOutageSamples = neteq_lifetime_stat.delayed_packet_outage_samples; + acm_stat->relativePacketArrivalDelayMs = + neteq_lifetime_stat.relative_packet_arrival_delay_ms; 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 0db423b543..7aa7f8b45c 100644 --- a/modules/audio_coding/include/audio_coding_module_typedefs.h +++ b/modules/audio_coding/include/audio_coding_module_typedefs.h @@ -122,6 +122,8 @@ struct NetworkStatistics { uint64_t packetBufferFlushes; // number of samples expanded due to delayed packets uint64_t delayedPacketOutageSamples; + // arrival delay of incoming packets + uint64_t relativePacketArrivalDelayMs; }; } // namespace webrtc diff --git a/pc/rtc_stats_collector.cc b/pc/rtc_stats_collector.cc index f3a081b724..a604663506 100644 --- a/pc/rtc_stats_collector.cc +++ b/pc/rtc_stats_collector.cc @@ -460,6 +460,8 @@ ProduceMediaStreamTrackStatsFromVoiceReceiverInfo( voice_receiver_info.jitter_buffer_flushes; audio_track_stats->delayed_packet_outage_samples = voice_receiver_info.delayed_packet_outage_samples; + audio_track_stats->relative_packet_arrival_delay = + voice_receiver_info.relative_packet_arrival_delay_seconds; return audio_track_stats; } diff --git a/pc/rtc_stats_collector_unittest.cc b/pc/rtc_stats_collector_unittest.cc index 8c1ab02c08..64a5ec6a4b 100644 --- a/pc/rtc_stats_collector_unittest.cc +++ b/pc/rtc_stats_collector_unittest.cc @@ -1428,6 +1428,7 @@ TEST_F(RTCStatsCollectorTest, voice_receiver_info.jitter_buffer_emitted_count = 13; voice_receiver_info.jitter_buffer_flushes = 7; voice_receiver_info.delayed_packet_outage_samples = 15; + voice_receiver_info.relative_packet_arrival_delay_seconds = 16; stats_->CreateMockRtpSendersReceiversAndChannels( {}, {std::make_pair(remote_audio_track.get(), voice_receiver_info)}, {}, @@ -1464,6 +1465,7 @@ TEST_F(RTCStatsCollectorTest, expected_remote_audio_track.jitter_buffer_emitted_count = 13; 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; 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/pc/rtc_stats_integrationtest.cc b/pc/rtc_stats_integrationtest.cc index 7fddfffc07..5fd353c4c7 100644 --- a/pc/rtc_stats_integrationtest.cc +++ b/pc/rtc_stats_integrationtest.cc @@ -652,6 +652,8 @@ class RTCStatsReportVerifier { media_stream_track.jitter_buffer_flushes); verifier.TestMemberIsNonNegative( media_stream_track.delayed_packet_outage_samples); + verifier.TestMemberIsNonNegative( + media_stream_track.relative_packet_arrival_delay); } else { verifier.TestMemberIsUndefined(media_stream_track.jitter_buffer_delay); verifier.TestMemberIsUndefined( @@ -662,6 +664,8 @@ class RTCStatsReportVerifier { verifier.TestMemberIsUndefined(media_stream_track.jitter_buffer_flushes); verifier.TestMemberIsUndefined( media_stream_track.delayed_packet_outage_samples); + verifier.TestMemberIsUndefined( + media_stream_track.relative_packet_arrival_delay); } return verifier.ExpectAllMembersSuccessfullyTested(); } diff --git a/stats/rtcstats_objects.cc b/stats/rtcstats_objects.cc index 14764d702f..ccf2574a8e 100644 --- a/stats/rtcstats_objects.cc +++ b/stats/rtcstats_objects.cc @@ -382,6 +382,7 @@ WEBRTC_RTCSTATS_IMPL(RTCMediaStreamTrackStats, RTCStats, "track", &concealment_events, &jitter_buffer_flushes, &delayed_packet_outage_samples, + &relative_packet_arrival_delay, &freeze_count, &pause_count, &total_freezes_duration, @@ -427,6 +428,7 @@ RTCMediaStreamTrackStats::RTCMediaStreamTrackStats(std::string&& id, concealment_events("concealmentEvents"), jitter_buffer_flushes("jitterBufferFlushes"), delayed_packet_outage_samples("delayedPacketOutageSamples"), + relative_packet_arrival_delay("relativePacketArrivalDelay"), freeze_count("freezeCount"), pause_count("pauseCount"), total_freezes_duration("totalFreezesDuration"), @@ -468,6 +470,7 @@ RTCMediaStreamTrackStats::RTCMediaStreamTrackStats( concealment_events(other.concealment_events), 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), freeze_count(other.freeze_count), pause_count(other.pause_count), total_freezes_duration(other.total_freezes_duration),