Add new decoding statistics for muted output

This change adds a new statistic for logging how many calls to
NetEq::GetAudio resulted in a "muted output". A muted output happens
if the packet stream has been dead for some time (and the last decoded
packet was not comfort noise).

BUG=webrtc:5606
BUG=b/31256483

Review-Url: https://codereview.webrtc.org/2341293002
Cr-Commit-Position: refs/heads/master@{#14302}
This commit is contained in:
henrik.lundin 2016-09-20 01:47:12 -07:00 committed by Commit bot
parent 1b1863a11a
commit 63489787a0
16 changed files with 46 additions and 14 deletions

View File

@ -57,6 +57,7 @@ class AudioReceiveStream {
int32_t decoding_plc = 0;
int32_t decoding_cng = 0;
int32_t decoding_plc_cng = 0;
int32_t decoding_muted_output = 0;
int64_t capture_start_ntp_time_ms = 0;
};

View File

@ -143,6 +143,8 @@ void ExtractStats(const cricket::VoiceReceiverInfo& info, StatsReport* report) {
{ StatsReport::kStatsValueNameDecodingCTN, info.decoding_calls_to_neteq },
{ StatsReport::kStatsValueNameDecodingCTSG,
info.decoding_calls_to_silence_generator },
{ StatsReport::kStatsValueNameDecodingMutedOutput,
info.decoding_muted_output },
{ StatsReport::kStatsValueNameDecodingNormal, info.decoding_normal },
{ StatsReport::kStatsValueNameDecodingPLC, info.decoding_plc },
{ StatsReport::kStatsValueNameDecodingPLCCNG, info.decoding_plc_cng },

View File

@ -348,8 +348,11 @@ void VerifyVoiceReceiverInfoReport(
EXPECT_TRUE(GetValue(
report, StatsReport::kStatsValueNameDecodingPLCCNG, &value_in_report));
EXPECT_EQ(rtc::ToString<int>(info.decoding_plc_cng), value_in_report);
EXPECT_TRUE(GetValue(
report, StatsReport::kStatsValueNameCodecName, &value_in_report));
EXPECT_TRUE(GetValue(report, StatsReport::kStatsValueNameDecodingMutedOutput,
&value_in_report));
EXPECT_EQ(rtc::ToString<int>(info.decoding_muted_output), value_in_report);
EXPECT_TRUE(GetValue(report, StatsReport::kStatsValueNameCodecName,
&value_in_report));
}

View File

@ -456,6 +456,8 @@ const char* StatsReport::Value::display_name() const {
return "googDecodingCTSG";
case kStatsValueNameDecodingCTN:
return "googDecodingCTN";
case kStatsValueNameDecodingMutedOutput:
return "googDecodingMuted";
case kStatsValueNameDecodingNormal:
return "googDecodingNormal";
case kStatsValueNameDecodingPLC:

View File

@ -148,6 +148,7 @@ class StatsReport {
kStatsValueNameDecodingCNG,
kStatsValueNameDecodingCTN,
kStatsValueNameDecodingCTSG,
kStatsValueNameDecodingMutedOutput,
kStatsValueNameDecodingNormal,
kStatsValueNameDecodingPLC,
kStatsValueNameDecodingPLCCNG,

View File

@ -211,6 +211,7 @@ webrtc::AudioReceiveStream::Stats AudioReceiveStream::GetStats() const {
stats.decoding_plc = ds.decoded_plc;
stats.decoding_cng = ds.decoded_cng;
stats.decoding_plc_cng = ds.decoded_plc_cng;
stats.decoding_muted_output = ds.decoded_muted_output;
return stats;
}

View File

@ -43,6 +43,7 @@ AudioDecodingCallStats MakeAudioDecodeStatsForTest() {
audio_decode_stats.decoded_plc = 123;
audio_decode_stats.decoded_cng = 456;
audio_decode_stats.decoded_plc_cng = 789;
audio_decode_stats.decoded_muted_output = 987;
return audio_decode_stats;
}
@ -356,6 +357,8 @@ TEST(AudioReceiveStreamTest, GetStats) {
EXPECT_EQ(kAudioDecodeStats.decoded_plc, stats.decoding_plc);
EXPECT_EQ(kAudioDecodeStats.decoded_cng, stats.decoding_cng);
EXPECT_EQ(kAudioDecodeStats.decoded_plc_cng, stats.decoding_plc_cng);
EXPECT_EQ(kAudioDecodeStats.decoded_muted_output,
stats.decoding_muted_output);
EXPECT_EQ(kCallStats.capture_start_ntp_time_ms_,
stats.capture_start_ntp_time_ms);
}

View File

@ -385,7 +385,8 @@ struct AudioDecodingCallStats {
decoded_normal(0),
decoded_plc(0),
decoded_cng(0),
decoded_plc_cng(0) {}
decoded_plc_cng(0),
decoded_muted_output(0) {}
int calls_to_silence_generator; // Number of calls where silence generated,
// and NetEq was disengaged from decoding.
@ -394,6 +395,7 @@ struct AudioDecodingCallStats {
int decoded_plc; // Number of calls resulted in PLC.
int decoded_cng; // Number of calls where comfort noise generated due to DTX.
int decoded_plc_cng; // Number of calls resulted where PLC faded to CNG.
int decoded_muted_output; // Number of calls returning a muted state output.
};
// Type of Noise Suppression.

View File

@ -620,6 +620,7 @@ struct VoiceReceiverInfo : public MediaReceiverInfo {
decoding_plc(0),
decoding_cng(0),
decoding_plc_cng(0),
decoding_muted_output(0),
capture_start_ntp_time_ms(-1) {}
int ext_seqnum;
@ -644,6 +645,7 @@ struct VoiceReceiverInfo : public MediaReceiverInfo {
int decoding_plc;
int decoding_cng;
int decoding_plc_cng;
int decoding_muted_output;
// Estimated capture start time in NTP time in ms.
int64_t capture_start_ntp_time_ms;
};

View File

@ -2611,6 +2611,7 @@ bool WebRtcVoiceMediaChannel::GetStats(VoiceMediaInfo* info) {
rinfo.decoding_plc = stats.decoding_plc;
rinfo.decoding_cng = stats.decoding_cng;
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;
info->receivers.push_back(rinfo);
}

View File

@ -450,7 +450,8 @@ class WebRtcVoiceEngineTestFake : public testing::Test {
stats.decoding_plc = 1234;
stats.decoding_cng = 5678;
stats.decoding_plc_cng = 9012;
stats.capture_start_ntp_time_ms = 3456;
stats.decoding_muted_output = 3456;
stats.capture_start_ntp_time_ms = 7890;
return stats;
}
void SetAudioReceiveStreamStats() {
@ -485,6 +486,7 @@ class WebRtcVoiceEngineTestFake : public testing::Test {
EXPECT_EQ(info.decoding_plc, stats.decoding_plc);
EXPECT_EQ(info.decoding_cng, stats.decoding_cng);
EXPECT_EQ(info.decoding_plc_cng, stats.decoding_plc_cng);
EXPECT_EQ(info.decoding_muted_output, stats.decoding_muted_output);
EXPECT_EQ(info.capture_start_ntp_time_ms, stats.capture_start_ntp_time_ms);
}

View File

@ -135,6 +135,7 @@ int AcmReceiver::InsertPacket(const WebRtcRTPHeader& rtp_header,
int AcmReceiver::GetAudio(int desired_freq_hz,
AudioFrame* audio_frame,
bool* muted) {
RTC_DCHECK(muted);
// Accessing members, take the lock.
rtc::CritScope lock(&crit_sect_);
@ -191,7 +192,7 @@ int AcmReceiver::GetAudio(int desired_freq_hz,
sizeof(int16_t) * audio_frame->samples_per_channel_ *
audio_frame->num_channels_);
call_stats_.DecodedByNetEq(audio_frame->speech_type_);
call_stats_.DecodedByNetEq(audio_frame->speech_type_, *muted);
return 0;
}

View File

@ -253,6 +253,7 @@ TEST_F(AudioCodingModuleTestOldApi, MAYBE_InitializedToZero) {
EXPECT_EQ(0, stats.decoded_cng);
EXPECT_EQ(0, stats.decoded_plc);
EXPECT_EQ(0, stats.decoded_plc_cng);
EXPECT_EQ(0, stats.decoded_muted_output);
}
// Insert some packets and pull audio. Check statistics are valid. Then,
@ -278,6 +279,7 @@ TEST_F(AudioCodingModuleTestOldApi, MAYBE_NetEqCalls) {
EXPECT_EQ(0, stats.decoded_cng);
EXPECT_EQ(0, stats.decoded_plc);
EXPECT_EQ(0, stats.decoded_plc_cng);
EXPECT_EQ(0, stats.decoded_muted_output);
const int kNumPlc = 3;
const int kNumPlcCng = 5;
@ -293,6 +295,8 @@ TEST_F(AudioCodingModuleTestOldApi, MAYBE_NetEqCalls) {
EXPECT_EQ(0, stats.decoded_cng);
EXPECT_EQ(kNumPlc, stats.decoded_plc);
EXPECT_EQ(kNumPlcCng, stats.decoded_plc_cng);
EXPECT_EQ(0, stats.decoded_muted_output);
// TODO(henrik.lundin) Add a test with muted state enabled.
}
TEST_F(AudioCodingModuleTestOldApi, VerifyOutputFrame) {

View File

@ -10,14 +10,18 @@
#include "webrtc/modules/audio_coding/acm2/call_statistics.h"
#include <assert.h>
#include "webrtc/base/checks.h"
namespace webrtc {
namespace acm2 {
void CallStatistics::DecodedByNetEq(AudioFrame::SpeechType speech_type) {
void CallStatistics::DecodedByNetEq(AudioFrame::SpeechType speech_type,
bool muted) {
++decoding_stat_.calls_to_neteq;
if (muted) {
++decoding_stat_.decoded_muted_output;
}
switch (speech_type) {
case AudioFrame::kNormalSpeech: {
++decoding_stat_.decoded_normal;
@ -37,7 +41,7 @@ void CallStatistics::DecodedByNetEq(AudioFrame::SpeechType speech_type) {
}
case AudioFrame::kUndefined: {
// If the audio is decoded by NetEq, |kUndefined| is not an option.
assert(false);
RTC_NOTREACHED();
}
}
}

View File

@ -37,8 +37,9 @@ class CallStatistics {
~CallStatistics() {}
// Call this method to indicate that NetEq engaged in decoding. |speech_type|
// is the audio-type according to NetEq.
void DecodedByNetEq(AudioFrame::SpeechType speech_type);
// is the audio-type according to NetEq, and |muted| indicates if the decoded
// frame was produced in muted state.
void DecodedByNetEq(AudioFrame::SpeechType speech_type, bool muted);
// Call this method to indicate that a decoding call resulted in generating
// silence, i.e. call to NetEq is bypassed and the output audio is zero.

View File

@ -26,6 +26,7 @@ TEST(CallStatisticsTest, InitializedZero) {
EXPECT_EQ(0, stats.decoded_cng);
EXPECT_EQ(0, stats.decoded_plc);
EXPECT_EQ(0, stats.decoded_plc_cng);
EXPECT_EQ(0, stats.decoded_muted_output);
}
TEST(CallStatisticsTest, AllCalls) {
@ -33,10 +34,10 @@ TEST(CallStatisticsTest, AllCalls) {
AudioDecodingCallStats stats;
call_stats.DecodedBySilenceGenerator();
call_stats.DecodedByNetEq(AudioFrame::kNormalSpeech);
call_stats.DecodedByNetEq(AudioFrame::kPLC);
call_stats.DecodedByNetEq(AudioFrame::kPLCCNG);
call_stats.DecodedByNetEq(AudioFrame::kCNG);
call_stats.DecodedByNetEq(AudioFrame::kNormalSpeech, false);
call_stats.DecodedByNetEq(AudioFrame::kPLC, false);
call_stats.DecodedByNetEq(AudioFrame::kPLCCNG, true); // Let this be muted.
call_stats.DecodedByNetEq(AudioFrame::kCNG, false);
stats = call_stats.GetDecodingStatistics();
EXPECT_EQ(4, stats.calls_to_neteq);
@ -45,6 +46,7 @@ TEST(CallStatisticsTest, AllCalls) {
EXPECT_EQ(1, stats.decoded_cng);
EXPECT_EQ(1, stats.decoded_plc);
EXPECT_EQ(1, stats.decoded_plc_cng);
EXPECT_EQ(1, stats.decoded_muted_output);
}
} // namespace acm2