Piping audio interruption metrics to API layer
Bug: webrtc:10549 Change-Id: Ie6abe5819c5b73dc5f5f89bdc375bad77f44ce97 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/134303 Reviewed-by: Karl Wiberg <kwiberg@webrtc.org> Reviewed-by: Ivo Creusen <ivoc@webrtc.org> Commit-Queue: Henrik Lundin <henrik.lundin@webrtc.org> Cr-Commit-Position: refs/heads/master@{#27788}
This commit is contained in:

committed by
Commit Bot

parent
c35b6e675a
commit
299c4e6846
@ -565,6 +565,8 @@ const char* StatsReport::Value::display_name() const {
|
|||||||
return "googInitiator";
|
return "googInitiator";
|
||||||
case kStatsValueNameInterframeDelayMaxMs:
|
case kStatsValueNameInterframeDelayMaxMs:
|
||||||
return "googInterframeDelayMax";
|
return "googInterframeDelayMax";
|
||||||
|
case kStatsValueNameInterruptionCount:
|
||||||
|
return "googInterruptionCount";
|
||||||
case kStatsValueNameIssuerId:
|
case kStatsValueNameIssuerId:
|
||||||
return "googIssuerId";
|
return "googIssuerId";
|
||||||
case kStatsValueNameJitterReceived:
|
case kStatsValueNameJitterReceived:
|
||||||
@ -647,6 +649,8 @@ const char* StatsReport::Value::display_name() const {
|
|||||||
return "googTrackId";
|
return "googTrackId";
|
||||||
case kStatsValueNameTimingFrameInfo:
|
case kStatsValueNameTimingFrameInfo:
|
||||||
return "googTimingFrameInfo";
|
return "googTimingFrameInfo";
|
||||||
|
case kStatsValueNameTotalInterruptionDurationMs:
|
||||||
|
return "googTotalInterruptionDurationMs";
|
||||||
case kStatsValueNameTypingNoiseState:
|
case kStatsValueNameTypingNoiseState:
|
||||||
return "googTypingNoiseState";
|
return "googTypingNoiseState";
|
||||||
case kStatsValueNameWritable:
|
case kStatsValueNameWritable:
|
||||||
|
@ -192,6 +192,7 @@ class StatsReport {
|
|||||||
kStatsValueNameHugeFramesSent,
|
kStatsValueNameHugeFramesSent,
|
||||||
kStatsValueNameInitiator,
|
kStatsValueNameInitiator,
|
||||||
kStatsValueNameInterframeDelayMaxMs, // Max over last 10 seconds.
|
kStatsValueNameInterframeDelayMaxMs, // Max over last 10 seconds.
|
||||||
|
kStatsValueNameInterruptionCount,
|
||||||
kStatsValueNameIssuerId,
|
kStatsValueNameIssuerId,
|
||||||
kStatsValueNameJitterBufferMs,
|
kStatsValueNameJitterBufferMs,
|
||||||
kStatsValueNameJitterReceived,
|
kStatsValueNameJitterReceived,
|
||||||
@ -232,6 +233,7 @@ class StatsReport {
|
|||||||
kStatsValueNameTargetDelayMs,
|
kStatsValueNameTargetDelayMs,
|
||||||
kStatsValueNameTargetEncBitrate,
|
kStatsValueNameTargetEncBitrate,
|
||||||
kStatsValueNameTimingFrameInfo, // Result of |TimingFrameInfo::ToString|
|
kStatsValueNameTimingFrameInfo, // Result of |TimingFrameInfo::ToString|
|
||||||
|
kStatsValueNameTotalInterruptionDurationMs,
|
||||||
kStatsValueNameTrackId,
|
kStatsValueNameTrackId,
|
||||||
kStatsValueNameTransmitBitrate,
|
kStatsValueNameTransmitBitrate,
|
||||||
kStatsValueNameTransportType,
|
kStatsValueNameTransportType,
|
||||||
|
@ -226,6 +226,8 @@ webrtc::AudioReceiveStream::Stats AudioReceiveStream::GetStats() const {
|
|||||||
stats.relative_packet_arrival_delay_seconds =
|
stats.relative_packet_arrival_delay_seconds =
|
||||||
static_cast<double>(ns.relativePacketArrivalDelayMs) /
|
static_cast<double>(ns.relativePacketArrivalDelayMs) /
|
||||||
static_cast<double>(rtc::kNumMillisecsPerSec);
|
static_cast<double>(rtc::kNumMillisecsPerSec);
|
||||||
|
stats.interruption_count = ns.interruptionCount;
|
||||||
|
stats.total_interruption_duration_ms = ns.totalInterruptionDurationMs;
|
||||||
|
|
||||||
auto ds = channel_receive_->GetDecodingCallStatistics();
|
auto ds = channel_receive_->GetDecodingCallStatistics();
|
||||||
stats.decoding_calls_to_silence_generator = ds.calls_to_silence_generator;
|
stats.decoding_calls_to_silence_generator = ds.calls_to_silence_generator;
|
||||||
|
@ -79,6 +79,8 @@ class AudioReceiveStream {
|
|||||||
absl::optional<int64_t> last_packet_received_timestamp_ms;
|
absl::optional<int64_t> last_packet_received_timestamp_ms;
|
||||||
uint64_t jitter_buffer_flushes = 0;
|
uint64_t jitter_buffer_flushes = 0;
|
||||||
double relative_packet_arrival_delay_seconds = 0.0;
|
double relative_packet_arrival_delay_seconds = 0.0;
|
||||||
|
int32_t interruption_count = 0;
|
||||||
|
int32_t total_interruption_duration_ms = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Config {
|
struct Config {
|
||||||
|
@ -514,6 +514,10 @@ struct VoiceReceiverInfo : public MediaReceiverInfo {
|
|||||||
uint64_t delayed_packet_outage_samples = 0;
|
uint64_t delayed_packet_outage_samples = 0;
|
||||||
// Arrival delay of received audio packets.
|
// Arrival delay of received audio packets.
|
||||||
double relative_packet_arrival_delay_seconds = 0.0;
|
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 {
|
struct VideoSenderInfo : public MediaSenderInfo {
|
||||||
|
@ -2274,6 +2274,8 @@ bool WebRtcVoiceMediaChannel::GetStats(VoiceMediaInfo* info) {
|
|||||||
rinfo.jitter_buffer_flushes = stats.jitter_buffer_flushes;
|
rinfo.jitter_buffer_flushes = stats.jitter_buffer_flushes;
|
||||||
rinfo.relative_packet_arrival_delay_seconds =
|
rinfo.relative_packet_arrival_delay_seconds =
|
||||||
stats.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);
|
info->receivers.push_back(rinfo);
|
||||||
}
|
}
|
||||||
|
@ -259,6 +259,9 @@ void AcmReceiver::GetNetworkStatistics(NetworkStatistics* acm_stat) {
|
|||||||
neteq_lifetime_stat.delayed_packet_outage_samples;
|
neteq_lifetime_stat.delayed_packet_outage_samples;
|
||||||
acm_stat->relativePacketArrivalDelayMs =
|
acm_stat->relativePacketArrivalDelayMs =
|
||||||
neteq_lifetime_stat.relative_packet_arrival_delay_ms;
|
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 =
|
NetEqOperationsAndState neteq_operations_and_state =
|
||||||
neteq_->GetOperationsAndState();
|
neteq_->GetOperationsAndState();
|
||||||
|
@ -130,6 +130,10 @@ struct NetworkStatistics {
|
|||||||
uint64_t delayedPacketOutageSamples;
|
uint64_t delayedPacketOutageSamples;
|
||||||
// arrival delay of incoming packets
|
// arrival delay of incoming packets
|
||||||
uint64_t relativePacketArrivalDelayMs;
|
uint64_t relativePacketArrivalDelayMs;
|
||||||
|
// number of audio interruptions
|
||||||
|
int32_t interruptionCount;
|
||||||
|
// total duration of audio interruptions
|
||||||
|
int32_t totalInterruptionDurationMs;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace webrtc
|
} // namespace webrtc
|
||||||
|
@ -90,8 +90,8 @@ struct NetEqLifetimeStatistics {
|
|||||||
// An interruption is a loss-concealment event lasting at least 150 ms. The
|
// 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
|
// two stats below count the number os such events and the total duration of
|
||||||
// these events.
|
// these events.
|
||||||
uint64_t interruption_count = 0;
|
int32_t interruption_count = 0;
|
||||||
uint64_t total_interruption_duration_ms = 0;
|
int32_t total_interruption_duration_ms = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Metrics that describe the operations performed in NetEq, and the internal
|
// Metrics that describe the operations performed in NetEq, and the internal
|
||||||
|
@ -745,7 +745,7 @@ TEST_F(NetEqImplTest, NoAudioInterruptionLoggedBeforeFirstDecode) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto lifetime_stats = neteq_->GetLifetimeStatistics();
|
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
|
// This test verifies that NetEq can handle comfort noise and enters/quits codec
|
||||||
|
@ -135,31 +135,31 @@ TEST(StatisticsCalculator, InterruptionCounter) {
|
|||||||
stats.DecodedOutputPlayed();
|
stats.DecodedOutputPlayed();
|
||||||
stats.EndExpandEvent(fs_hz);
|
stats.EndExpandEvent(fs_hz);
|
||||||
auto lts = stats.GetLifetimeStatistics();
|
auto lts = stats.GetLifetimeStatistics();
|
||||||
EXPECT_EQ(0u, lts.interruption_count);
|
EXPECT_EQ(0, lts.interruption_count);
|
||||||
EXPECT_EQ(0u, lts.total_interruption_duration_ms);
|
EXPECT_EQ(0, lts.total_interruption_duration_ms);
|
||||||
|
|
||||||
// Add an event that is shorter than 150 ms. Should not be logged.
|
// Add an event that is shorter than 150 ms. Should not be logged.
|
||||||
stats.ExpandedVoiceSamples(10 * fs_khz, false); // 10 ms.
|
stats.ExpandedVoiceSamples(10 * fs_khz, false); // 10 ms.
|
||||||
stats.ExpandedNoiseSamples(139 * fs_khz, false); // 139 ms.
|
stats.ExpandedNoiseSamples(139 * fs_khz, false); // 139 ms.
|
||||||
stats.EndExpandEvent(fs_hz);
|
stats.EndExpandEvent(fs_hz);
|
||||||
lts = stats.GetLifetimeStatistics();
|
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.
|
// Add an event that is longer than 150 ms. Should be logged.
|
||||||
stats.ExpandedVoiceSamples(140 * fs_khz, false); // 140 ms.
|
stats.ExpandedVoiceSamples(140 * fs_khz, false); // 140 ms.
|
||||||
stats.ExpandedNoiseSamples(11 * fs_khz, false); // 11 ms.
|
stats.ExpandedNoiseSamples(11 * fs_khz, false); // 11 ms.
|
||||||
stats.EndExpandEvent(fs_hz);
|
stats.EndExpandEvent(fs_hz);
|
||||||
lts = stats.GetLifetimeStatistics();
|
lts = stats.GetLifetimeStatistics();
|
||||||
EXPECT_EQ(1u, lts.interruption_count);
|
EXPECT_EQ(1, lts.interruption_count);
|
||||||
EXPECT_EQ(151u, lts.total_interruption_duration_ms);
|
EXPECT_EQ(151, lts.total_interruption_duration_ms);
|
||||||
|
|
||||||
// Add one more long event.
|
// Add one more long event.
|
||||||
stats.ExpandedVoiceSamples(100 * fs_khz, false); // 100 ms.
|
stats.ExpandedVoiceSamples(100 * fs_khz, false); // 100 ms.
|
||||||
stats.ExpandedNoiseSamples(5000 * fs_khz, false); // 5000 ms.
|
stats.ExpandedNoiseSamples(5000 * fs_khz, false); // 5000 ms.
|
||||||
stats.EndExpandEvent(fs_hz);
|
stats.EndExpandEvent(fs_hz);
|
||||||
lts = stats.GetLifetimeStatistics();
|
lts = stats.GetLifetimeStatistics();
|
||||||
EXPECT_EQ(2u, lts.interruption_count);
|
EXPECT_EQ(2, lts.interruption_count);
|
||||||
EXPECT_EQ(5100u + 151u, lts.total_interruption_duration_ms);
|
EXPECT_EQ(5100 + 151, lts.total_interruption_duration_ms);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(StatisticsCalculator, InterruptionCounterDoNotLogBeforeDecoding) {
|
TEST(StatisticsCalculator, InterruptionCounterDoNotLogBeforeDecoding) {
|
||||||
@ -172,7 +172,7 @@ TEST(StatisticsCalculator, InterruptionCounterDoNotLogBeforeDecoding) {
|
|||||||
stats.ExpandedVoiceSamples(151 * fs_khz, false); // 151 ms.
|
stats.ExpandedVoiceSamples(151 * fs_khz, false); // 151 ms.
|
||||||
stats.EndExpandEvent(fs_hz);
|
stats.EndExpandEvent(fs_hz);
|
||||||
auto lts = stats.GetLifetimeStatistics();
|
auto lts = stats.GetLifetimeStatistics();
|
||||||
EXPECT_EQ(0u, lts.interruption_count);
|
EXPECT_EQ(0, lts.interruption_count);
|
||||||
|
|
||||||
// Call DecodedOutputPlayed(). Logging should happen after this.
|
// Call DecodedOutputPlayed(). Logging should happen after this.
|
||||||
stats.DecodedOutputPlayed();
|
stats.DecodedOutputPlayed();
|
||||||
@ -181,7 +181,7 @@ TEST(StatisticsCalculator, InterruptionCounterDoNotLogBeforeDecoding) {
|
|||||||
stats.ExpandedVoiceSamples(151 * fs_khz, false); // 151 ms.
|
stats.ExpandedVoiceSamples(151 * fs_khz, false); // 151 ms.
|
||||||
stats.EndExpandEvent(fs_hz);
|
stats.EndExpandEvent(fs_hz);
|
||||||
lts = stats.GetLifetimeStatistics();
|
lts = stats.GetLifetimeStatistics();
|
||||||
EXPECT_EQ(1u, lts.interruption_count);
|
EXPECT_EQ(1, lts.interruption_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace webrtc
|
} // namespace webrtc
|
||||||
|
@ -79,9 +79,8 @@ void NetEqStatsPlotter::SimulationEnded(int64_t simulation_time_ms) {
|
|||||||
const auto lifetime_stats_vector = stats_getter_->lifetime_stats();
|
const auto lifetime_stats_vector = stats_getter_->lifetime_stats();
|
||||||
if (!lifetime_stats_vector->empty()) {
|
if (!lifetime_stats_vector->empty()) {
|
||||||
auto lifetime_stats = lifetime_stats_vector->back().second;
|
auto lifetime_stats = lifetime_stats_vector->back().second;
|
||||||
printf(" num_interruptions: %" PRId64 "\n",
|
printf(" num_interruptions: %d\n", lifetime_stats.interruption_count);
|
||||||
lifetime_stats.interruption_count);
|
printf(" sum_interruption_length_ms: %d ms\n",
|
||||||
printf(" sum_interruption_length_ms: %" PRId64 " ms\n",
|
|
||||||
lifetime_stats.total_interruption_duration_ms);
|
lifetime_stats.total_interruption_duration_ms);
|
||||||
printf(" interruption ratio: %f%%\n",
|
printf(" interruption ratio: %f%%\n",
|
||||||
100.0 * lifetime_stats.total_interruption_duration_ms /
|
100.0 * lifetime_stats.total_interruption_duration_ms /
|
||||||
|
@ -165,6 +165,9 @@ void ExtractStats(const cricket::VoiceReceiverInfo& info, StatsReport* report) {
|
|||||||
{StatsReport::kStatsValueNamePacketsReceived, info.packets_rcvd},
|
{StatsReport::kStatsValueNamePacketsReceived, info.packets_rcvd},
|
||||||
{StatsReport::kStatsValueNamePreferredJitterBufferMs,
|
{StatsReport::kStatsValueNamePreferredJitterBufferMs,
|
||||||
info.jitter_buffer_preferred_ms},
|
info.jitter_buffer_preferred_ms},
|
||||||
|
{StatsReport::kStatsValueNameInterruptionCount, info.interruption_count},
|
||||||
|
{StatsReport::kStatsValueNameTotalInterruptionDurationMs,
|
||||||
|
info.total_interruption_duration_ms},
|
||||||
};
|
};
|
||||||
|
|
||||||
for (const auto& f : floats)
|
for (const auto& f : floats)
|
||||||
|
@ -383,6 +383,14 @@ void VerifyVoiceReceiverInfoReport(const StatsReport* report,
|
|||||||
EXPECT_EQ(rtc::ToString(info.decoding_muted_output), value_in_report);
|
EXPECT_EQ(rtc::ToString(info.decoding_muted_output), value_in_report);
|
||||||
EXPECT_TRUE(GetValue(report, StatsReport::kStatsValueNameCodecName,
|
EXPECT_TRUE(GetValue(report, StatsReport::kStatsValueNameCodecName,
|
||||||
&value_in_report));
|
&value_in_report));
|
||||||
|
EXPECT_TRUE(GetValue(report, StatsReport::kStatsValueNameInterruptionCount,
|
||||||
|
&value_in_report));
|
||||||
|
EXPECT_EQ(rtc::ToString(info.interruption_count), value_in_report);
|
||||||
|
EXPECT_TRUE(GetValue(report,
|
||||||
|
StatsReport::kStatsValueNameTotalInterruptionDurationMs,
|
||||||
|
&value_in_report));
|
||||||
|
EXPECT_EQ(rtc::ToString(info.total_interruption_duration_ms),
|
||||||
|
value_in_report);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VerifyVoiceSenderInfoReport(const StatsReport* report,
|
void VerifyVoiceSenderInfoReport(const StatsReport* report,
|
||||||
|
Reference in New Issue
Block a user