1 /* 2 * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 #include "testing/gmock/include/gmock/gmock.h" 12 #include "webrtc/base/scoped_ptr.h" 13 #include "webrtc/modules/audio_coding/neteq/tools/neteq_external_decoder_test.h" 14 #include "webrtc/modules/audio_coding/neteq/tools/rtp_generator.h" 15 16 namespace webrtc { 17 namespace test { 18 19 using ::testing::_; 20 using ::testing::SetArgPointee; 21 using ::testing::Return; 22 23 class MockAudioDecoder final : public AudioDecoder { 24 public: 25 static const int kPacketDuration = 960; // 48 kHz * 20 ms 26 27 explicit MockAudioDecoder(size_t num_channels) 28 : num_channels_(num_channels), fec_enabled_(false) { 29 } 30 ~MockAudioDecoder() override { Die(); } 31 MOCK_METHOD0(Die, void()); 32 33 MOCK_METHOD0(Reset, void()); 34 35 int PacketDuration(const uint8_t* encoded, 36 size_t encoded_len) const override { 37 return kPacketDuration; 38 } 39 40 int PacketDurationRedundant(const uint8_t* encoded, 41 size_t encoded_len) const override { 42 return kPacketDuration; 43 } 44 45 bool PacketHasFec(const uint8_t* encoded, size_t encoded_len) const override { 46 return fec_enabled_; 47 } 48 49 size_t Channels() const override { return num_channels_; } 50 51 void set_fec_enabled(bool enable_fec) { fec_enabled_ = enable_fec; } 52 53 bool fec_enabled() const { return fec_enabled_; } 54 55 protected: 56 // Override the following methods such that no actual payload is needed. 57 int DecodeInternal(const uint8_t* encoded, 58 size_t encoded_len, 59 int /*sample_rate_hz*/, 60 int16_t* decoded, 61 SpeechType* speech_type) override { 62 *speech_type = kSpeech; 63 memset(decoded, 0, sizeof(int16_t) * kPacketDuration * Channels()); 64 return kPacketDuration * Channels(); 65 } 66 67 int DecodeRedundantInternal(const uint8_t* encoded, 68 size_t encoded_len, 69 int sample_rate_hz, 70 int16_t* decoded, 71 SpeechType* speech_type) override { 72 return DecodeInternal(encoded, encoded_len, sample_rate_hz, decoded, 73 speech_type); 74 } 75 76 private: 77 const size_t num_channels_; 78 bool fec_enabled_; 79 }; 80 81 class NetEqNetworkStatsTest : public NetEqExternalDecoderTest { 82 public: 83 static const int kPayloadSizeByte = 30; 84 static const int kFrameSizeMs = 20; 85 static const int kMaxOutputSize = 960; // 10 ms * 48 kHz * 2 channels. 86 87 enum logic { 88 IGNORE, 89 EQUAL, 90 SMALLER_THAN, 91 LARGER_THAN, 92 }; 93 94 struct NetEqNetworkStatsCheck { 95 logic current_buffer_size_ms; 96 logic preferred_buffer_size_ms; 97 logic jitter_peaks_found; 98 logic packet_loss_rate; 99 logic packet_discard_rate; 100 logic expand_rate; 101 logic speech_expand_rate; 102 logic preemptive_rate; 103 logic accelerate_rate; 104 logic secondary_decoded_rate; 105 logic clockdrift_ppm; 106 logic added_zero_samples; 107 NetEqNetworkStatistics stats_ref; 108 }; 109 110 NetEqNetworkStatsTest(NetEqDecoder codec, 111 MockAudioDecoder* decoder) 112 : NetEqExternalDecoderTest(codec, decoder), 113 external_decoder_(decoder), 114 samples_per_ms_(CodecSampleRateHz(codec) / 1000), 115 frame_size_samples_(kFrameSizeMs * samples_per_ms_), 116 rtp_generator_(new test::RtpGenerator(samples_per_ms_)), 117 last_lost_time_(0), 118 packet_loss_interval_(0xffffffff) { 119 Init(); 120 } 121 122 bool Lost(uint32_t send_time) { 123 if (send_time - last_lost_time_ >= packet_loss_interval_) { 124 last_lost_time_ = send_time; 125 return true; 126 } 127 return false; 128 } 129 130 void SetPacketLossRate(double loss_rate) { 131 packet_loss_interval_ = (loss_rate >= 1e-3 ? 132 static_cast<double>(kFrameSizeMs) / loss_rate : 0xffffffff); 133 } 134 135 // |stats_ref| 136 // expects.x = -1, do not care 137 // expects.x = 0, 'x' in current stats should equal 'x' in |stats_ref| 138 // expects.x = 1, 'x' in current stats should < 'x' in |stats_ref| 139 // expects.x = 2, 'x' in current stats should > 'x' in |stats_ref| 140 void CheckNetworkStatistics(NetEqNetworkStatsCheck expects) { 141 NetEqNetworkStatistics stats; 142 neteq()->NetworkStatistics(&stats); 143 144 #define CHECK_NETEQ_NETWORK_STATS(x)\ 145 switch (expects.x) {\ 146 case EQUAL:\ 147 EXPECT_EQ(stats.x, expects.stats_ref.x);\ 148 break;\ 149 case SMALLER_THAN:\ 150 EXPECT_LT(stats.x, expects.stats_ref.x);\ 151 break;\ 152 case LARGER_THAN:\ 153 EXPECT_GT(stats.x, expects.stats_ref.x);\ 154 break;\ 155 default:\ 156 break;\ 157 } 158 159 CHECK_NETEQ_NETWORK_STATS(current_buffer_size_ms); 160 CHECK_NETEQ_NETWORK_STATS(preferred_buffer_size_ms); 161 CHECK_NETEQ_NETWORK_STATS(jitter_peaks_found); 162 CHECK_NETEQ_NETWORK_STATS(packet_loss_rate); 163 CHECK_NETEQ_NETWORK_STATS(packet_discard_rate); 164 CHECK_NETEQ_NETWORK_STATS(expand_rate); 165 CHECK_NETEQ_NETWORK_STATS(speech_expand_rate); 166 CHECK_NETEQ_NETWORK_STATS(preemptive_rate); 167 CHECK_NETEQ_NETWORK_STATS(accelerate_rate); 168 CHECK_NETEQ_NETWORK_STATS(secondary_decoded_rate); 169 CHECK_NETEQ_NETWORK_STATS(clockdrift_ppm); 170 CHECK_NETEQ_NETWORK_STATS(added_zero_samples); 171 172 #undef CHECK_NETEQ_NETWORK_STATS 173 174 // Compare with CurrentDelay, which should be identical. 175 EXPECT_EQ(stats.current_buffer_size_ms, neteq()->CurrentDelayMs()); 176 } 177 178 void RunTest(int num_loops, NetEqNetworkStatsCheck expects) { 179 NetEqOutputType output_type; 180 uint32_t time_now; 181 uint32_t next_send_time; 182 183 // Initiate |last_lost_time_|. 184 time_now = next_send_time = last_lost_time_ = 185 rtp_generator_->GetRtpHeader(kPayloadType, frame_size_samples_, 186 &rtp_header_); 187 for (int k = 0; k < num_loops; ++k) { 188 // Delay by one frame such that the FEC can come in. 189 while (time_now + kFrameSizeMs >= next_send_time) { 190 next_send_time = rtp_generator_->GetRtpHeader(kPayloadType, 191 frame_size_samples_, 192 &rtp_header_); 193 if (!Lost(next_send_time)) { 194 InsertPacket(rtp_header_, payload_, next_send_time); 195 } 196 } 197 GetOutputAudio(kMaxOutputSize, output_, &output_type); 198 time_now += kOutputLengthMs; 199 } 200 CheckNetworkStatistics(expects); 201 neteq()->FlushBuffers(); 202 } 203 204 void DecodeFecTest() { 205 external_decoder_->set_fec_enabled(false); 206 NetEqNetworkStatsCheck expects = { 207 IGNORE, // current_buffer_size_ms 208 IGNORE, // preferred_buffer_size_ms 209 IGNORE, // jitter_peaks_found 210 EQUAL, // packet_loss_rate 211 EQUAL, // packet_discard_rate 212 EQUAL, // expand_rate 213 EQUAL, // voice_expand_rate 214 IGNORE, // preemptive_rate 215 EQUAL, // accelerate_rate 216 EQUAL, // decoded_fec_rate 217 IGNORE, // clockdrift_ppm 218 EQUAL, // added_zero_samples 219 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} 220 }; 221 RunTest(50, expects); 222 223 // Next we introduce packet losses. 224 SetPacketLossRate(0.1); 225 expects.stats_ref.packet_loss_rate = 1337; 226 expects.stats_ref.expand_rate = expects.stats_ref.speech_expand_rate = 1065; 227 RunTest(50, expects); 228 229 // Next we enable FEC. 230 external_decoder_->set_fec_enabled(true); 231 // If FEC fills in the lost packets, no packet loss will be counted. 232 expects.stats_ref.packet_loss_rate = 0; 233 expects.stats_ref.expand_rate = expects.stats_ref.speech_expand_rate = 0; 234 expects.stats_ref.secondary_decoded_rate = 2006; 235 RunTest(50, expects); 236 } 237 238 void NoiseExpansionTest() { 239 NetEqNetworkStatsCheck expects = { 240 IGNORE, // current_buffer_size_ms 241 IGNORE, // preferred_buffer_size_ms 242 IGNORE, // jitter_peaks_found 243 EQUAL, // packet_loss_rate 244 EQUAL, // packet_discard_rate 245 EQUAL, // expand_rate 246 EQUAL, // speech_expand_rate 247 IGNORE, // preemptive_rate 248 EQUAL, // accelerate_rate 249 EQUAL, // decoded_fec_rate 250 IGNORE, // clockdrift_ppm 251 EQUAL, // added_zero_samples 252 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} 253 }; 254 RunTest(50, expects); 255 256 SetPacketLossRate(1); 257 expects.stats_ref.expand_rate = 16384; 258 expects.stats_ref.speech_expand_rate = 5324; 259 RunTest(10, expects); // Lost 10 * 20ms in a row. 260 } 261 262 private: 263 MockAudioDecoder* external_decoder_; 264 const int samples_per_ms_; 265 const size_t frame_size_samples_; 266 rtc::scoped_ptr<test::RtpGenerator> rtp_generator_; 267 WebRtcRTPHeader rtp_header_; 268 uint32_t last_lost_time_; 269 uint32_t packet_loss_interval_; 270 uint8_t payload_[kPayloadSizeByte]; 271 int16_t output_[kMaxOutputSize]; 272 }; 273 274 TEST(NetEqNetworkStatsTest, DecodeFec) { 275 MockAudioDecoder decoder(1); 276 NetEqNetworkStatsTest test(NetEqDecoder::kDecoderOpus, &decoder); 277 test.DecodeFecTest(); 278 EXPECT_CALL(decoder, Die()).Times(1); 279 } 280 281 TEST(NetEqNetworkStatsTest, StereoDecodeFec) { 282 MockAudioDecoder decoder(2); 283 NetEqNetworkStatsTest test(NetEqDecoder::kDecoderOpus, &decoder); 284 test.DecodeFecTest(); 285 EXPECT_CALL(decoder, Die()).Times(1); 286 } 287 288 TEST(NetEqNetworkStatsTest, NoiseExpansionTest) { 289 MockAudioDecoder decoder(1); 290 NetEqNetworkStatsTest test(NetEqDecoder::kDecoderOpus, &decoder); 291 test.NoiseExpansionTest(); 292 EXPECT_CALL(decoder, Die()).Times(1); 293 } 294 295 } // namespace test 296 } // namespace webrtc 297 298 299 300 301