diff --git a/talk/media/base/mediachannel.h b/talk/media/base/mediachannel.h index ce8aaac4c..19cb9a38d 100644 --- a/talk/media/base/mediachannel.h +++ b/talk/media/base/mediachannel.h @@ -779,6 +779,8 @@ struct VoiceReceiverInfo : public MediaReceiverInfo { delay_estimate_ms(0), audio_level(0), expand_rate(0), + speech_expand_rate(0), + secondary_decoded_rate(0), decoding_calls_to_silence_generator(0), decoding_calls_to_neteq(0), decoding_normal(0), @@ -794,8 +796,12 @@ struct VoiceReceiverInfo : public MediaReceiverInfo { int jitter_buffer_preferred_ms; int delay_estimate_ms; int audio_level; - // fraction of synthesized speech inserted through pre-emptive expansion + // fraction of synthesized audio inserted through expansion. float expand_rate; + // fraction of synthesized speech inserted through expansion. + float speech_expand_rate; + // fraction of data out of secondary decoding, including FEC and RED. + float secondary_decoded_rate; int decoding_calls_to_silence_generator; int decoding_calls_to_neteq; int decoding_normal; diff --git a/talk/media/webrtc/fakewebrtcvoiceengine.h b/talk/media/webrtc/fakewebrtcvoiceengine.h index 566da3c5e..65807fc36 100644 --- a/talk/media/webrtc/fakewebrtcvoiceengine.h +++ b/talk/media/webrtc/fakewebrtcvoiceengine.h @@ -65,6 +65,25 @@ static const int kOpusBandwidthWb = 8000; static const int kOpusBandwidthSwb = 12000; static const int kOpusBandwidthFb = 20000; +static const webrtc::NetworkStatistics kNetStats = { + 1, // uint16_t currentBufferSize; + 2, // uint16_t preferredBufferSize; + true, // bool jitterPeaksFound; + 1234, // uint16_t currentPacketLossRate; + 567, // uint16_t currentDiscardRate; + 8901, // uint16_t currentExpandRate; + 234, // uint16_t currentSpeechExpandRate; + 5678, // uint16_t currentPreemptiveRate; + 9012, // uint16_t currentAccelerateRate; + 3456, // uint16_t currentSecondaryDecodedRate; + 7890, // int32_t clockDriftPPM; + 54, // meanWaitingTimeMs; + 32, // int medianWaitingTimeMs; + 1, // int minWaitingTimeMs; + 98, // int maxWaitingTimeMs; + 7654, // int addedSamples; +}; // These random but non-trivial numbers are used for testing. + // Verify the header extension ID, if enabled, is within the bounds specified in // [RFC5285]: 1-14 inclusive. #define WEBRTC_CHECK_HEADER_EXTENSION_ID(enable, id) \ @@ -823,7 +842,13 @@ class FakeWebRtcVoiceEngine virtual bool BuiltInAECIsAvailable() const { return false; } // webrtc::VoENetEqStats - WEBRTC_STUB(GetNetworkStatistics, (int, webrtc::NetworkStatistics&)); + WEBRTC_FUNC(GetNetworkStatistics, (int channel, + webrtc::NetworkStatistics& ns)) { + WEBRTC_CHECK_CHANNEL(channel); + memcpy(&ns, &kNetStats, sizeof(webrtc::NetworkStatistics)); + return 0; + } + WEBRTC_FUNC_CONST(GetDecodingCallStatistics, (int channel, webrtc::AudioDecodingCallStats*)) { WEBRTC_CHECK_CHANNEL(channel); diff --git a/talk/media/webrtc/webrtcvoiceengine.cc b/talk/media/webrtc/webrtcvoiceengine.cc index dab2b511f..a6fc3073a 100644 --- a/talk/media/webrtc/webrtcvoiceengine.cc +++ b/talk/media/webrtc/webrtcvoiceengine.cc @@ -3413,6 +3413,10 @@ bool WebRtcVoiceMediaChannel::GetStats(VoiceMediaInfo* info) { rinfo.jitter_buffer_preferred_ms = ns.preferredBufferSize; rinfo.expand_rate = static_cast(ns.currentExpandRate) / (1 << 14); + rinfo.speech_expand_rate = + static_cast(ns.currentSpeechExpandRate) / (1 << 14); + rinfo.secondary_decoded_rate = + static_cast(ns.currentSecondaryDecodedRate) / (1 << 14); } webrtc::AudioDecodingCallStats ds; diff --git a/talk/media/webrtc/webrtcvoiceengine_unittest.cc b/talk/media/webrtc/webrtcvoiceengine_unittest.cc index 5faec6c06..749ff9cb3 100644 --- a/talk/media/webrtc/webrtcvoiceengine_unittest.cc +++ b/talk/media/webrtc/webrtcvoiceengine_unittest.cc @@ -1992,6 +1992,12 @@ TEST_F(WebRtcVoiceEngineTestFake, GetStatsWithMultipleSendStreams) { EXPECT_EQ(cricket::kIntStatValue, info.receivers[0].packets_lost); EXPECT_EQ(cricket::kIntStatValue, info.receivers[0].ext_seqnum); EXPECT_EQ(kPcmuCodec.name, info.receivers[0].codec_name); + EXPECT_EQ(static_cast(cricket::kNetStats.currentExpandRate) / + (1 << 14), info.receivers[0].expand_rate); + EXPECT_EQ(static_cast(cricket::kNetStats.currentSpeechExpandRate) / + (1 << 14), info.receivers[0].speech_expand_rate); + EXPECT_EQ(static_cast(cricket::kNetStats.currentSecondaryDecodedRate) / + (1 << 14), info.receivers[0].secondary_decoded_rate); } // Test that we can add and remove receive streams, and do proper send/playout. @@ -2319,6 +2325,12 @@ TEST_F(WebRtcVoiceEngineTestFake, GetStats) { EXPECT_EQ(cricket::kIntStatValue, info.receivers[0].packets_lost); EXPECT_EQ(cricket::kIntStatValue, info.receivers[0].ext_seqnum); EXPECT_EQ(kPcmuCodec.name, info.receivers[0].codec_name); + EXPECT_EQ(static_cast(cricket::kNetStats.currentExpandRate) / + (1 << 14), info.receivers[0].expand_rate); + EXPECT_EQ(static_cast(cricket::kNetStats.currentSpeechExpandRate) / + (1 << 14), info.receivers[0].speech_expand_rate); + EXPECT_EQ(static_cast(cricket::kNetStats.currentSecondaryDecodedRate) / + (1 << 14), info.receivers[0].secondary_decoded_rate); // TODO(sriniv): Add testing for more receiver fields. } diff --git a/webrtc/common_types.h b/webrtc/common_types.h index 17f50fa67..ec7f1ed26 100644 --- a/webrtc/common_types.h +++ b/webrtc/common_types.h @@ -346,14 +346,19 @@ struct NetworkStatistics // NETEQ statistics uint16_t currentPacketLossRate; // Late loss rate; fraction between 0 and 1, scaled to Q14. uint16_t currentDiscardRate; - // fraction (of original stream) of synthesized speech inserted through + // fraction (of original stream) of synthesized audio inserted through // expansion (in Q14) uint16_t currentExpandRate; + // fraction (of original stream) of synthesized speech inserted through + // expansion (in Q14) + uint16_t currentSpeechExpandRate; // fraction of synthesized speech inserted through pre-emptive expansion // (in Q14) uint16_t currentPreemptiveRate; // fraction of data removed through acceleration (in Q14) uint16_t currentAccelerateRate; + // fraction of data coming from secondary decoding (in Q14) + uint16_t currentSecondaryDecodedRate; // clock-drift in parts-per-million (negative or positive) int32_t clockDriftPPM; // average packet waiting time in the jitter buffer (ms) diff --git a/webrtc/modules/audio_coding/main/acm2/acm_receiver.cc b/webrtc/modules/audio_coding/main/acm2/acm_receiver.cc index 5466c18ef..5d78625de 100644 --- a/webrtc/modules/audio_coding/main/acm2/acm_receiver.cc +++ b/webrtc/modules/audio_coding/main/acm2/acm_receiver.cc @@ -639,7 +639,7 @@ int AcmReceiver::LastAudioCodec(CodecInst* codec) const { return 0; } -void AcmReceiver::NetworkStatistics(ACMNetworkStatistics* acm_stat) { +void AcmReceiver::GetNetworkStatistics(NetworkStatistics* acm_stat) { NetEqNetworkStatistics neteq_stat; // NetEq function always returns zero, so we don't check the return value. neteq_->NetworkStatistics(&neteq_stat); @@ -650,8 +650,10 @@ void AcmReceiver::NetworkStatistics(ACMNetworkStatistics* acm_stat) { acm_stat->currentPacketLossRate = neteq_stat.packet_loss_rate; acm_stat->currentDiscardRate = neteq_stat.packet_discard_rate; acm_stat->currentExpandRate = neteq_stat.expand_rate; + acm_stat->currentSpeechExpandRate = neteq_stat.speech_expand_rate; acm_stat->currentPreemptiveRate = neteq_stat.preemptive_rate; acm_stat->currentAccelerateRate = neteq_stat.accelerate_rate; + acm_stat->currentSecondaryDecodedRate = neteq_stat.secondary_decoded_rate; acm_stat->clockDriftPPM = neteq_stat.clockdrift_ppm; acm_stat->addedSamples = neteq_stat.added_zero_samples; diff --git a/webrtc/modules/audio_coding/main/acm2/acm_receiver.h b/webrtc/modules/audio_coding/main/acm2/acm_receiver.h index f6ce463e1..f3ef16f73 100644 --- a/webrtc/modules/audio_coding/main/acm2/acm_receiver.h +++ b/webrtc/modules/audio_coding/main/acm2/acm_receiver.h @@ -191,7 +191,7 @@ class AcmReceiver { // Output: // - statistics : The current network statistics. // - void NetworkStatistics(ACMNetworkStatistics* statistics); + void GetNetworkStatistics(NetworkStatistics* statistics); // // Enable post-decoding VAD. diff --git a/webrtc/modules/audio_coding/main/acm2/audio_coding_module_impl.cc b/webrtc/modules/audio_coding/main/acm2/audio_coding_module_impl.cc index fc1191a45..b38360f4f 100644 --- a/webrtc/modules/audio_coding/main/acm2/audio_coding_module_impl.cc +++ b/webrtc/modules/audio_coding/main/acm2/audio_coding_module_impl.cc @@ -1451,8 +1451,8 @@ int AudioCodingModuleImpl::PlayoutData10Ms(int desired_freq_hz, // TODO(turajs) change the return value to void. Also change the corresponding // NetEq function. -int AudioCodingModuleImpl::NetworkStatistics(ACMNetworkStatistics* statistics) { - receiver_.NetworkStatistics(statistics); +int AudioCodingModuleImpl::GetNetworkStatistics(NetworkStatistics* statistics) { + receiver_.GetNetworkStatistics(statistics); return 0; } @@ -1841,8 +1841,8 @@ bool AudioCodingImpl::Get10MsAudio(AudioFrame* audio_frame) { return acm_old_->PlayoutData10Ms(playout_frequency_hz_, audio_frame) == 0; } -bool AudioCodingImpl::NetworkStatistics( - ACMNetworkStatistics* network_statistics) { +bool AudioCodingImpl::GetNetworkStatistics( + NetworkStatistics* network_statistics) { FATAL() << "Not implemented yet."; return false; } diff --git a/webrtc/modules/audio_coding/main/acm2/audio_coding_module_impl.h b/webrtc/modules/audio_coding/main/acm2/audio_coding_module_impl.h index 12d4bdf65..72e1e75ed 100644 --- a/webrtc/modules/audio_coding/main/acm2/audio_coding_module_impl.h +++ b/webrtc/modules/audio_coding/main/acm2/audio_coding_module_impl.h @@ -198,7 +198,7 @@ class AudioCodingModuleImpl : public AudioCodingModule { // Statistics // - virtual int NetworkStatistics(ACMNetworkStatistics* statistics) OVERRIDE; + virtual int GetNetworkStatistics(NetworkStatistics* statistics) OVERRIDE; // GET RED payload for iSAC. The method id called when 'this' ACM is // the default ACM. @@ -418,8 +418,8 @@ class AudioCodingImpl : public AudioCoding { virtual bool Get10MsAudio(AudioFrame* audio_frame) OVERRIDE; - virtual bool NetworkStatistics( - ACMNetworkStatistics* network_statistics) OVERRIDE; + virtual bool GetNetworkStatistics( + NetworkStatistics* network_statistics) OVERRIDE; virtual bool EnableNack(size_t max_nack_list_size) OVERRIDE; diff --git a/webrtc/modules/audio_coding/main/interface/audio_coding_module.h b/webrtc/modules/audio_coding/main/interface/audio_coding_module.h index 7de0a1207..a039802d0 100644 --- a/webrtc/modules/audio_coding/main/interface/audio_coding_module.h +++ b/webrtc/modules/audio_coding/main/interface/audio_coding_module.h @@ -909,7 +909,7 @@ class AudioCodingModule: public Module { // /////////////////////////////////////////////////////////////////////////// - // int32_t NetworkStatistics() + // int32_t GetNetworkStatistics() // Get network statistics. Note that the internal statistics of NetEq are // reset by this call. // @@ -920,8 +920,8 @@ class AudioCodingModule: public Module { // -1 if failed to set the network statistics, // 0 if statistics are set successfully. // - virtual int32_t NetworkStatistics( - ACMNetworkStatistics* network_statistics) = 0; + virtual int32_t GetNetworkStatistics( + NetworkStatistics* network_statistics) = 0; // // Set an initial delay for playout. @@ -1107,7 +1107,7 @@ class AudioCoding { // Returns the network statistics. Note that the internal statistics of NetEq // are reset by this call. Returns true if successful, false otherwise. - virtual bool NetworkStatistics(ACMNetworkStatistics* network_statistics) = 0; + virtual bool GetNetworkStatistics(NetworkStatistics* network_statistics) = 0; // Enables NACK and sets the maximum size of the NACK list. If NACK is already // enabled then the maximum NACK list size is modified accordingly. Returns diff --git a/webrtc/modules/audio_coding/main/interface/audio_coding_module_typedefs.h b/webrtc/modules/audio_coding/main/interface/audio_coding_module_typedefs.h index dce5352a7..ee7a2f134 100644 --- a/webrtc/modules/audio_coding/main/interface/audio_coding_module_typedefs.h +++ b/webrtc/modules/audio_coding/main/interface/audio_coding_module_typedefs.h @@ -144,48 +144,6 @@ enum ACMAMRPackingFormat { AMRFileStorage = 2 }; - -/////////////////////////////////////////////////////////////////////////// -// -// Struct containing network statistics -// -// -currentBufferSize : current jitter buffer size in ms -// -preferredBufferSize : preferred (optimal) buffer size in ms -// -jitterPeaksFound : indicate if peaky-jitter mode is engaged, that is, -// if severe but sparse network delays have occurred. -// -currentPacketLossRate : loss rate (network + late) (in Q14) -// -currentDiscardRate : late loss rate (in Q14) -// -currentExpandRate : fraction (of original stream) of synthesized -// speech inserted through expansion (in Q14) -// -currentPreemptiveRate : fraction of synthesized speech inserted through -// pre-emptive expansion (in Q14) -// -currentAccelerateRate : fraction of data removed through acceleration -// (in Q14) -// -clockDriftPPM : clock-drift between sender and receiver in parts- -// per-million. Positive means that receiver sample -// rate is higher than sender sample rate. -// -meanWaitingTimeMs : average packet waiting time in the buffer -// -medianWaitingTimeMs : median packet waiting time in the buffer -// -minWaitingTimeMs : min packet waiting time in the buffer -// -maxWaitingTimeMs : max packet waiting time in the buffer -// -addedSamples : samples inserted because of packet loss in off mode -typedef struct { - uint16_t currentBufferSize; - uint16_t preferredBufferSize; - bool jitterPeaksFound; - uint16_t currentPacketLossRate; - uint16_t currentDiscardRate; - uint16_t currentExpandRate; - uint16_t currentPreemptiveRate; - uint16_t currentAccelerateRate; - int32_t clockDriftPPM; - int meanWaitingTimeMs; - int medianWaitingTimeMs; - int minWaitingTimeMs; - int maxWaitingTimeMs; - int addedSamples; -} ACMNetworkStatistics; - /////////////////////////////////////////////////////////////////////////// // // Enumeration of background noise mode a mapping from NetEQ interface. diff --git a/webrtc/modules/audio_coding/main/test/APITest.cc b/webrtc/modules/audio_coding/main/test/APITest.cc index b6e471458..6893587d5 100644 --- a/webrtc/modules/audio_coding/main/test/APITest.cc +++ b/webrtc/modules/audio_coding/main/test/APITest.cc @@ -785,8 +785,8 @@ void APITest::TestDelay(char side) { *myMinDelay = (rand() % 1000) + 1; - ACMNetworkStatistics networkStat; - CHECK_ERROR_MT(myACM->NetworkStatistics(&networkStat)); + NetworkStatistics networkStat; + CHECK_ERROR_MT(myACM->GetNetworkStatistics(&networkStat)); if (!_randomTest) { fprintf(stdout, "\n\nJitter Statistics at Side %c\n", side); @@ -803,10 +803,14 @@ void APITest::TestDelay(char side) { networkStat.currentDiscardRate); fprintf(stdout, "expand rate............. %d\n", networkStat.currentExpandRate); + fprintf(stdout, "speech expand rate...... %d\n", + networkStat.currentSpeechExpandRate); fprintf(stdout, "Preemptive rate......... %d\n", networkStat.currentPreemptiveRate); fprintf(stdout, "Accelerate rate......... %d\n", networkStat.currentAccelerateRate); + fprintf(stdout, "Secondary decoded rate.. %d\n", + networkStat.currentSecondaryDecodedRate); fprintf(stdout, "Clock-drift............. %d\n", networkStat.clockDriftPPM); fprintf(stdout, "Mean waiting time....... %d\n", networkStat.meanWaitingTimeMs); diff --git a/webrtc/modules/audio_coding/main/test/delay_test.cc b/webrtc/modules/audio_coding/main/test/delay_test.cc index 2e7547212..dbebe38eb 100644 --- a/webrtc/modules/audio_coding/main/test/delay_test.cc +++ b/webrtc/modules/audio_coding/main/test/delay_test.cc @@ -196,8 +196,8 @@ class DelayTest { // Print delay information every 16 frame if ((num_frames & 0x3F) == 0x3F) { - ACMNetworkStatistics statistics; - acm_b_->NetworkStatistics(&statistics); + NetworkStatistics statistics; + acm_b_->GetNetworkStatistics(&statistics); fprintf(stdout, "delay: min=%3d max=%3d mean=%3d median=%3d" " ts-based average = %6.3f, " "curr buff-lev = %4u opt buff-lev = %4u \n", diff --git a/webrtc/modules/audio_coding/main/test/insert_packet_with_timing.cc b/webrtc/modules/audio_coding/main/test/insert_packet_with_timing.cc index 0173ac1d1..64dc608bf 100644 --- a/webrtc/modules/audio_coding/main/test/insert_packet_with_timing.cc +++ b/webrtc/modules/audio_coding/main/test/insert_packet_with_timing.cc @@ -219,8 +219,8 @@ class InsertPacketWithTiming { // Jitter buffer delay. void Delay(int* optimal_delay, int* current_delay) { - ACMNetworkStatistics statistics; - receive_acm_->NetworkStatistics(&statistics); + NetworkStatistics statistics; + receive_acm_->GetNetworkStatistics(&statistics); *optimal_delay = statistics.preferredBufferSize; *current_delay = statistics.currentBufferSize; } diff --git a/webrtc/modules/audio_coding/main/test/target_delay_unittest.cc b/webrtc/modules/audio_coding/main/test/target_delay_unittest.cc index a90249907..629e1b5bb 100644 --- a/webrtc/modules/audio_coding/main/test/target_delay_unittest.cc +++ b/webrtc/modules/audio_coding/main/test/target_delay_unittest.cc @@ -185,8 +185,8 @@ class TargetDelayTest : public ::testing::Test { } int GetCurrentOptimalDelayMs() { - ACMNetworkStatistics stats; - acm_->NetworkStatistics(&stats); + NetworkStatistics stats; + acm_->GetNetworkStatistics(&stats); return stats.preferredBufferSize; } diff --git a/webrtc/voice_engine/channel.cc b/webrtc/voice_engine/channel.cc index bb8fcb10e..cc3bb1b01 100644 --- a/webrtc/voice_engine/channel.cc +++ b/webrtc/voice_engine/channel.cc @@ -3686,12 +3686,7 @@ Channel::GetNetworkStatistics(NetworkStatistics& stats) { WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId), "Channel::GetNetworkStatistics()"); - ACMNetworkStatistics acm_stats; - int return_value = audio_coding_->NetworkStatistics(&acm_stats); - if (return_value >= 0) { - memcpy(&stats, &acm_stats, sizeof(NetworkStatistics)); - } - return return_value; + return audio_coding_->GetNetworkStatistics(&stats); } void Channel::GetDecodingCallStatistics(AudioDecodingCallStats* stats) const { diff --git a/webrtc/voice_engine/test/auto_test/standard/neteq_stats_test.cc b/webrtc/voice_engine/test/auto_test/standard/neteq_stats_test.cc index c9a913510..f3be6355b 100644 --- a/webrtc/voice_engine/test/auto_test/standard/neteq_stats_test.cc +++ b/webrtc/voice_engine/test/auto_test/standard/neteq_stats_test.cc @@ -23,31 +23,35 @@ TEST_F(NetEQStatsTest, ManualPrintStatisticsAfterRunningAWhile) { TEST_LOG("Inspect these statistics and ensure they make sense.\n"); - TEST_LOG(" currentAccelerateRate = %hu \n", + TEST_LOG(" currentAccelerateRate = %hu \n", network_statistics.currentAccelerateRate); - TEST_LOG(" currentBufferSize = %hu \n", + TEST_LOG(" currentBufferSize = %hu \n", network_statistics.currentBufferSize); - TEST_LOG(" currentDiscardRate = %hu \n", + TEST_LOG(" currentSecondaryDecodedRate = %hu \n", + network_statistics.currentSecondaryDecodedRate); + TEST_LOG(" currentDiscardRate = %hu \n", network_statistics.currentDiscardRate); - TEST_LOG(" currentExpandRate = %hu \n", + TEST_LOG(" currentExpandRate = %hu \n", network_statistics.currentExpandRate); - TEST_LOG(" currentPacketLossRate = %hu \n", + TEST_LOG(" currentPacketLossRate = %hu \n", network_statistics.currentPacketLossRate); - TEST_LOG(" currentPreemptiveRate = %hu \n", + TEST_LOG(" currentPreemptiveRate = %hu \n", network_statistics.currentPreemptiveRate); - TEST_LOG(" preferredBufferSize = %hu \n", + TEST_LOG(" currentSpeechExpandRate = %hu \n", + network_statistics.currentSpeechExpandRate); + TEST_LOG(" preferredBufferSize = %hu \n", network_statistics.preferredBufferSize); - TEST_LOG(" jitterPeaksFound = %i \n", + TEST_LOG(" jitterPeaksFound = %i \n", network_statistics.jitterPeaksFound); - TEST_LOG(" clockDriftPPM = %i \n", + TEST_LOG(" clockDriftPPM = %i \n", network_statistics.clockDriftPPM); - TEST_LOG(" meanWaitingTimeMs = %i \n", + TEST_LOG(" meanWaitingTimeMs = %i \n", network_statistics.meanWaitingTimeMs); - TEST_LOG(" medianWaitingTimeMs = %i \n", + TEST_LOG(" medianWaitingTimeMs = %i \n", network_statistics.medianWaitingTimeMs); - TEST_LOG(" minWaitingTimeMs = %i \n", + TEST_LOG(" minWaitingTimeMs = %i \n", network_statistics.minWaitingTimeMs); - TEST_LOG(" maxWaitingTimeMs = %i \n", + TEST_LOG(" maxWaitingTimeMs = %i \n", network_statistics.maxWaitingTimeMs); // This is only set to a non-zero value in off-mode.