Reland "Piping audio interruption metrics to API layer"

The metrics are now added as RTCNonStandardStatsMember objects in
RTCMediaStreamTrackStats. Unit tests are updated.

This is a reland of https://webrtc-review.googlesource.com/c/src/+/134303,
with fixes.

TBR=kwiberg@webrtc.org

Bug: webrtc:10549
Change-Id: I29dcc6fbfc69156715664e71acfa054c1b2d9038
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/134500
Commit-Queue: Henrik Lundin <henrik.lundin@webrtc.org>
Reviewed-by: Henrik Boström <hbos@webrtc.org>
Reviewed-by: Ivo Creusen <ivoc@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#27806}
This commit is contained in:
Henrik Lundin 2019-04-29 17:00:46 +02:00 committed by Commit Bot
parent 7cca042dd4
commit 44125faba5
15 changed files with 59 additions and 15 deletions

View File

@ -321,6 +321,10 @@ class RTC_EXPORT RTCMediaStreamTrackStats final : public RTCStats {
RTCNonStandardStatsMember<uint64_t> jitter_buffer_flushes;
RTCNonStandardStatsMember<uint64_t> delayed_packet_outage_samples;
RTCNonStandardStatsMember<double> relative_packet_arrival_delay;
// TODO(henrik.lundin): Add description of the interruption metrics at
// https://github.com/henbos/webrtc-provisional-stats/issues/17
RTCNonStandardStatsMember<uint32_t> interruption_count;
RTCNonStandardStatsMember<double> total_interruption_duration;
// Non-standard video-only members.
// https://henbos.github.io/webrtc-provisional-stats/#RTCVideoReceiverStats-dict*
RTCNonStandardStatsMember<uint32_t> freeze_count;

View File

@ -226,6 +226,8 @@ webrtc::AudioReceiveStream::Stats AudioReceiveStream::GetStats() const {
stats.relative_packet_arrival_delay_seconds =
static_cast<double>(ns.relativePacketArrivalDelayMs) /
static_cast<double>(rtc::kNumMillisecsPerSec);
stats.interruption_count = ns.interruptionCount;
stats.total_interruption_duration_ms = ns.totalInterruptionDurationMs;
auto ds = channel_receive_->GetDecodingCallStatistics();
stats.decoding_calls_to_silence_generator = ds.calls_to_silence_generator;

View File

@ -79,6 +79,8 @@ class AudioReceiveStream {
absl::optional<int64_t> last_packet_received_timestamp_ms;
uint64_t jitter_buffer_flushes = 0;
double relative_packet_arrival_delay_seconds = 0.0;
int32_t interruption_count = 0;
int32_t total_interruption_duration_ms = 0;
};
struct Config {

View File

@ -514,6 +514,10 @@ struct VoiceReceiverInfo : public MediaReceiverInfo {
uint64_t delayed_packet_outage_samples = 0;
// Arrival delay of received audio packets.
double relative_packet_arrival_delay_seconds = 0.0;
// Count and total duration of audio interruptions (loss-concealement periods
// longer than 150 ms).
int32_t interruption_count = 0;
int32_t total_interruption_duration_ms = 0;
};
struct VideoSenderInfo : public MediaSenderInfo {

View File

@ -2264,6 +2264,8 @@ bool WebRtcVoiceMediaChannel::GetStats(VoiceMediaInfo* info) {
rinfo.jitter_buffer_flushes = stats.jitter_buffer_flushes;
rinfo.relative_packet_arrival_delay_seconds =
stats.relative_packet_arrival_delay_seconds;
rinfo.interruption_count = stats.interruption_count;
rinfo.total_interruption_duration_ms = stats.total_interruption_duration_ms;
info->receivers.push_back(rinfo);
}

View File

@ -259,6 +259,9 @@ void AcmReceiver::GetNetworkStatistics(NetworkStatistics* acm_stat) {
neteq_lifetime_stat.delayed_packet_outage_samples;
acm_stat->relativePacketArrivalDelayMs =
neteq_lifetime_stat.relative_packet_arrival_delay_ms;
acm_stat->interruptionCount = neteq_lifetime_stat.interruption_count;
acm_stat->totalInterruptionDurationMs =
neteq_lifetime_stat.total_interruption_duration_ms;
NetEqOperationsAndState neteq_operations_and_state =
neteq_->GetOperationsAndState();

View File

@ -130,6 +130,10 @@ struct NetworkStatistics {
uint64_t delayedPacketOutageSamples;
// arrival delay of incoming packets
uint64_t relativePacketArrivalDelayMs;
// number of audio interruptions
int32_t interruptionCount;
// total duration of audio interruptions
int32_t totalInterruptionDurationMs;
};
} // namespace webrtc

View File

@ -90,8 +90,8 @@ struct NetEqLifetimeStatistics {
// An interruption is a loss-concealment event lasting at least 150 ms. The
// two stats below count the number os such events and the total duration of
// these events.
uint64_t interruption_count = 0;
uint64_t total_interruption_duration_ms = 0;
int32_t interruption_count = 0;
int32_t total_interruption_duration_ms = 0;
};
// Metrics that describe the operations performed in NetEq, and the internal

View File

@ -745,7 +745,7 @@ TEST_F(NetEqImplTest, NoAudioInterruptionLoggedBeforeFirstDecode) {
}
auto lifetime_stats = neteq_->GetLifetimeStatistics();
EXPECT_EQ(0u, lifetime_stats.interruption_count);
EXPECT_EQ(0, lifetime_stats.interruption_count);
}
// This test verifies that NetEq can handle comfort noise and enters/quits codec

View File

@ -135,31 +135,31 @@ TEST(StatisticsCalculator, InterruptionCounter) {
stats.DecodedOutputPlayed();
stats.EndExpandEvent(fs_hz);
auto lts = stats.GetLifetimeStatistics();
EXPECT_EQ(0u, lts.interruption_count);
EXPECT_EQ(0u, lts.total_interruption_duration_ms);
EXPECT_EQ(0, lts.interruption_count);
EXPECT_EQ(0, lts.total_interruption_duration_ms);
// Add an event that is shorter than 150 ms. Should not be logged.
stats.ExpandedVoiceSamples(10 * fs_khz, false); // 10 ms.
stats.ExpandedNoiseSamples(139 * fs_khz, false); // 139 ms.
stats.EndExpandEvent(fs_hz);
lts = stats.GetLifetimeStatistics();
EXPECT_EQ(0u, lts.interruption_count);
EXPECT_EQ(0, lts.interruption_count);
// Add an event that is longer than 150 ms. Should be logged.
stats.ExpandedVoiceSamples(140 * fs_khz, false); // 140 ms.
stats.ExpandedNoiseSamples(11 * fs_khz, false); // 11 ms.
stats.EndExpandEvent(fs_hz);
lts = stats.GetLifetimeStatistics();
EXPECT_EQ(1u, lts.interruption_count);
EXPECT_EQ(151u, lts.total_interruption_duration_ms);
EXPECT_EQ(1, lts.interruption_count);
EXPECT_EQ(151, lts.total_interruption_duration_ms);
// Add one more long event.
stats.ExpandedVoiceSamples(100 * fs_khz, false); // 100 ms.
stats.ExpandedNoiseSamples(5000 * fs_khz, false); // 5000 ms.
stats.EndExpandEvent(fs_hz);
lts = stats.GetLifetimeStatistics();
EXPECT_EQ(2u, lts.interruption_count);
EXPECT_EQ(5100u + 151u, lts.total_interruption_duration_ms);
EXPECT_EQ(2, lts.interruption_count);
EXPECT_EQ(5100 + 151, lts.total_interruption_duration_ms);
}
TEST(StatisticsCalculator, InterruptionCounterDoNotLogBeforeDecoding) {
@ -172,7 +172,7 @@ TEST(StatisticsCalculator, InterruptionCounterDoNotLogBeforeDecoding) {
stats.ExpandedVoiceSamples(151 * fs_khz, false); // 151 ms.
stats.EndExpandEvent(fs_hz);
auto lts = stats.GetLifetimeStatistics();
EXPECT_EQ(0u, lts.interruption_count);
EXPECT_EQ(0, lts.interruption_count);
// Call DecodedOutputPlayed(). Logging should happen after this.
stats.DecodedOutputPlayed();
@ -181,7 +181,7 @@ TEST(StatisticsCalculator, InterruptionCounterDoNotLogBeforeDecoding) {
stats.ExpandedVoiceSamples(151 * fs_khz, false); // 151 ms.
stats.EndExpandEvent(fs_hz);
lts = stats.GetLifetimeStatistics();
EXPECT_EQ(1u, lts.interruption_count);
EXPECT_EQ(1, lts.interruption_count);
}
} // namespace webrtc

View File

@ -79,9 +79,8 @@ void NetEqStatsPlotter::SimulationEnded(int64_t simulation_time_ms) {
const auto lifetime_stats_vector = stats_getter_->lifetime_stats();
if (!lifetime_stats_vector->empty()) {
auto lifetime_stats = lifetime_stats_vector->back().second;
printf(" num_interruptions: %" PRId64 "\n",
lifetime_stats.interruption_count);
printf(" sum_interruption_length_ms: %" PRId64 " ms\n",
printf(" num_interruptions: %d\n", lifetime_stats.interruption_count);
printf(" sum_interruption_length_ms: %d ms\n",
lifetime_stats.total_interruption_duration_ms);
printf(" interruption ratio: %f%%\n",
100.0 * lifetime_stats.total_interruption_duration_ms /

View File

@ -490,6 +490,13 @@ ProduceMediaStreamTrackStatsFromVoiceReceiverInfo(
voice_receiver_info.delayed_packet_outage_samples;
audio_track_stats->relative_packet_arrival_delay =
voice_receiver_info.relative_packet_arrival_delay_seconds;
audio_track_stats->interruption_count =
voice_receiver_info.interruption_count >= 0
? voice_receiver_info.interruption_count
: 0;
audio_track_stats->total_interruption_duration =
static_cast<double>(voice_receiver_info.total_interruption_duration_ms) /
rtc::kNumMillisecsPerSec;
return audio_track_stats;
}

View File

@ -1429,6 +1429,8 @@ TEST_F(RTCStatsCollectorTest,
voice_receiver_info.jitter_buffer_flushes = 7;
voice_receiver_info.delayed_packet_outage_samples = 15;
voice_receiver_info.relative_packet_arrival_delay_seconds = 16;
voice_receiver_info.interruption_count = 7788;
voice_receiver_info.total_interruption_duration_ms = 778899;
stats_->CreateMockRtpSendersReceiversAndChannels(
{}, {std::make_pair(remote_audio_track.get(), voice_receiver_info)}, {},
@ -1466,6 +1468,8 @@ TEST_F(RTCStatsCollectorTest,
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;
expected_remote_audio_track.interruption_count = 7788;
expected_remote_audio_track.total_interruption_duration = 778.899;
ASSERT_TRUE(report->Get(expected_remote_audio_track.id()));
EXPECT_EQ(expected_remote_audio_track,
report->Get(expected_remote_audio_track.id())

View File

@ -654,6 +654,10 @@ class RTCStatsReportVerifier {
media_stream_track.delayed_packet_outage_samples);
verifier.TestMemberIsNonNegative<double>(
media_stream_track.relative_packet_arrival_delay);
verifier.TestMemberIsNonNegative<uint32_t>(
media_stream_track.interruption_count);
verifier.TestMemberIsNonNegative<double>(
media_stream_track.total_interruption_duration);
} else {
verifier.TestMemberIsUndefined(media_stream_track.jitter_buffer_delay);
verifier.TestMemberIsUndefined(
@ -666,6 +670,9 @@ class RTCStatsReportVerifier {
media_stream_track.delayed_packet_outage_samples);
verifier.TestMemberIsUndefined(
media_stream_track.relative_packet_arrival_delay);
verifier.TestMemberIsUndefined(media_stream_track.interruption_count);
verifier.TestMemberIsUndefined(
media_stream_track.total_interruption_duration);
}
return verifier.ExpectAllMembersSuccessfullyTested();
}

View File

@ -389,6 +389,8 @@ WEBRTC_RTCSTATS_IMPL(RTCMediaStreamTrackStats, RTCStats, "track",
&jitter_buffer_flushes,
&delayed_packet_outage_samples,
&relative_packet_arrival_delay,
&interruption_count,
&total_interruption_duration,
&freeze_count,
&pause_count,
&total_freezes_duration,
@ -442,6 +444,8 @@ RTCMediaStreamTrackStats::RTCMediaStreamTrackStats(std::string&& id,
relative_packet_arrival_delay(
"relativePacketArrivalDelay",
{NonStandardGroupId::kRtcStatsRelativePacketArrivalDelay}),
interruption_count("interruptionCount"),
total_interruption_duration("totalInterruptionDuration"),
freeze_count("freezeCount"),
pause_count("pauseCount"),
total_freezes_duration("totalFreezesDuration"),
@ -484,6 +488,8 @@ RTCMediaStreamTrackStats::RTCMediaStreamTrackStats(
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),
interruption_count(other.interruption_count),
total_interruption_duration(other.total_interruption_duration),
freeze_count(other.freeze_count),
pause_count(other.pause_count),
total_freezes_duration(other.total_freezes_duration),