neteq_decoder_plc_unittest.cc (12010B)
1 /* 2 * Copyright (c) 2018 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 // Test to verify correct operation when using the decoder-internal PLC. 12 13 #include <cstddef> 14 #include <cstdint> 15 #include <memory> 16 #include <optional> 17 #include <string> 18 #include <utility> 19 #include <vector> 20 21 #include "api/array_view.h" 22 #include "api/audio_codecs/audio_decoder.h" 23 #include "api/audio_codecs/audio_format.h" 24 #include "api/make_ref_counted.h" 25 #include "api/neteq/neteq.h" 26 #include "modules/audio_coding/codecs/pcm16b/audio_encoder_pcm16b.h" 27 #include "modules/audio_coding/neteq/tools/audio_checksum.h" 28 #include "modules/audio_coding/neteq/tools/encode_neteq_input.h" 29 #include "modules/audio_coding/neteq/tools/input_audio_file.h" 30 #include "modules/audio_coding/neteq/tools/neteq_input.h" 31 #include "modules/audio_coding/neteq/tools/neteq_test.h" 32 #include "modules/rtp_rtcp/source/rtp_packet_received.h" 33 #include "rtc_base/buffer.h" 34 #include "rtc_base/checks.h" 35 #include "rtc_base/numerics/safe_conversions.h" 36 #include "test/audio_decoder_proxy_factory.h" 37 #include "test/gtest.h" 38 #include "test/testsupport/file_utils.h" 39 40 namespace webrtc { 41 namespace test { 42 namespace { 43 44 constexpr int kSampleRateHz = 32000; 45 constexpr int kRunTimeMs = 10000; 46 47 // This class implements a fake decoder. The decoder will read audio from a file 48 // and present as output, both for regular decoding and for PLC. 49 class AudioDecoderPlc : public AudioDecoder { 50 public: 51 AudioDecoderPlc(std::unique_ptr<InputAudioFile> input, int sample_rate_hz) 52 : input_(std::move(input)), sample_rate_hz_(sample_rate_hz) {} 53 54 void Reset() override {} 55 int SampleRateHz() const override { return sample_rate_hz_; } 56 size_t Channels() const override { return 1; } 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 RTC_CHECK_GE(encoded_len / 2, 10 * sample_rate_hz_ / 1000); 63 RTC_CHECK_LE(encoded_len / 2, 2 * 10 * sample_rate_hz_ / 1000); 64 RTC_CHECK_EQ(sample_rate_hz, sample_rate_hz_); 65 RTC_CHECK(decoded); 66 RTC_CHECK(speech_type); 67 RTC_CHECK(input_->Read(encoded_len / 2, decoded)); 68 *speech_type = kSpeech; 69 last_was_plc_ = false; 70 return encoded_len / 2; 71 } 72 73 void GeneratePlc(size_t requested_samples_per_channel, 74 BufferT<int16_t>* concealment_audio) override { 75 // Instead of generating random data for GeneratePlc we use the same data as 76 // the input, so we can check that we produce the same result independently 77 // of the losses. 78 RTC_DCHECK_EQ(requested_samples_per_channel, 10 * sample_rate_hz_ / 1000); 79 80 // Must keep a local copy of this since DecodeInternal sets it to false. 81 const bool last_was_plc = last_was_plc_; 82 83 std::vector<int16_t> decoded(5760); 84 SpeechType speech_type; 85 int dec_len = DecodeInternal(nullptr, 2 * 10 * sample_rate_hz_ / 1000, 86 sample_rate_hz_, decoded.data(), &speech_type); 87 concealment_audio->AppendData(decoded.data(), dec_len); 88 concealed_samples_ += checked_cast<size_t>(dec_len); 89 90 if (!last_was_plc) { 91 ++concealment_events_; 92 } 93 last_was_plc_ = true; 94 } 95 96 size_t concealed_samples() { return concealed_samples_; } 97 size_t concealment_events() { return concealment_events_; } 98 99 private: 100 const std::unique_ptr<InputAudioFile> input_; 101 const int sample_rate_hz_; 102 size_t concealed_samples_ = 0; 103 size_t concealment_events_ = 0; 104 bool last_was_plc_ = false; 105 }; 106 107 // An input sample generator which generates only zero-samples. 108 class ZeroSampleGenerator : public EncodeNetEqInput::Generator { 109 public: 110 ArrayView<const int16_t> Generate(size_t num_samples) override { 111 vec.resize(num_samples, 0); 112 ArrayView<const int16_t> view(vec); 113 RTC_DCHECK_EQ(view.size(), num_samples); 114 return view; 115 } 116 117 private: 118 std::vector<int16_t> vec; 119 }; 120 121 // A NetEqInput which connects to another NetEqInput, but drops a number of 122 // consecutive packets on the way 123 class LossyInput : public NetEqInput { 124 public: 125 LossyInput(int loss_cadence, 126 int burst_length, 127 std::unique_ptr<NetEqInput> input) 128 : loss_cadence_(loss_cadence), 129 burst_length_(burst_length), 130 input_(std::move(input)) {} 131 132 std::optional<int64_t> NextPacketTime() const override { 133 return input_->NextPacketTime(); 134 } 135 136 std::optional<int64_t> NextOutputEventTime() const override { 137 return input_->NextOutputEventTime(); 138 } 139 140 std::optional<SetMinimumDelayInfo> NextSetMinimumDelayInfo() const override { 141 return input_->NextSetMinimumDelayInfo(); 142 } 143 144 std::unique_ptr<RtpPacketReceived> PopPacket() override { 145 if (loss_cadence_ != 0 && (++count_ % loss_cadence_) == 0) { 146 // Pop `burst_length_` packets to create the loss. 147 auto packet_to_return = input_->PopPacket(); 148 for (int i = 0; i < burst_length_; i++) { 149 input_->PopPacket(); 150 } 151 return packet_to_return; 152 } 153 return input_->PopPacket(); 154 } 155 156 void AdvanceOutputEvent() override { return input_->AdvanceOutputEvent(); } 157 158 void AdvanceSetMinimumDelay() override { 159 return input_->AdvanceSetMinimumDelay(); 160 } 161 162 bool ended() const override { return input_->ended(); } 163 164 const RtpPacketReceived* NextPacket() const override { 165 return input_->NextPacket(); 166 } 167 168 private: 169 const int loss_cadence_; 170 const int burst_length_; 171 int count_ = 0; 172 const std::unique_ptr<NetEqInput> input_; 173 }; 174 175 class AudioChecksumWithOutput : public AudioChecksum { 176 public: 177 explicit AudioChecksumWithOutput(std::string* output_str) 178 : output_str_(*output_str) {} 179 ~AudioChecksumWithOutput() override { output_str_ = Finish(); } 180 181 private: 182 std::string& output_str_; 183 }; 184 185 struct TestStatistics { 186 NetEqNetworkStatistics network; 187 NetEqLifetimeStatistics lifetime; 188 }; 189 190 TestStatistics RunTest(int loss_cadence, 191 int burst_length, 192 std::string* checksum) { 193 NetEq::Config config; 194 config.for_test_no_time_stretching = true; 195 196 // The input is mostly useless. It sends zero-samples to a PCM16b encoder, 197 // but the actual encoded samples will never be used by the decoder in the 198 // test. See below about the decoder. 199 auto generator = std::make_unique<ZeroSampleGenerator>(); 200 constexpr int kPayloadType = 100; 201 AudioEncoderPcm16B::Config encoder_config; 202 encoder_config.sample_rate_hz = kSampleRateHz; 203 encoder_config.payload_type = kPayloadType; 204 auto encoder = std::make_unique<AudioEncoderPcm16B>(encoder_config); 205 auto input = std::make_unique<EncodeNetEqInput>( 206 std::move(generator), std::move(encoder), kRunTimeMs); 207 // Wrap the input in a loss function. 208 auto lossy_input = std::make_unique<LossyInput>(loss_cadence, burst_length, 209 std::move(input)); 210 211 // Setting up decoders. 212 NetEqTest::DecoderMap decoders; 213 // Using a fake decoder which simply reads the output audio from a file. 214 auto input_file = std::make_unique<InputAudioFile>( 215 test::ResourcePath("audio_coding/testfile32kHz", "pcm")); 216 AudioDecoderPlc dec(std::move(input_file), kSampleRateHz); 217 // Masquerading as a PCM16b decoder. 218 decoders.emplace(kPayloadType, SdpAudioFormat("l16", 32000, 1)); 219 220 // Output is simply a checksum calculator. 221 auto output = std::make_unique<AudioChecksumWithOutput>(checksum); 222 223 // No callback objects. 224 NetEqTest::Callbacks callbacks; 225 226 NetEqTest neteq_test( 227 config, /*decoder_factory=*/ 228 make_ref_counted<test::AudioDecoderProxyFactory>(&dec), 229 /*codecs=*/decoders, /*text_log=*/nullptr, /*neteq_factory=*/nullptr, 230 /*input=*/std::move(lossy_input), std::move(output), callbacks); 231 EXPECT_LE(kRunTimeMs, neteq_test.Run()); 232 233 auto lifetime_stats = neteq_test.LifetimeStats(); 234 EXPECT_EQ(dec.concealed_samples(), lifetime_stats.concealed_samples); 235 EXPECT_EQ(dec.concealment_events(), lifetime_stats.concealment_events); 236 return {.network = neteq_test.SimulationStats(), 237 .lifetime = neteq_test.LifetimeStats()}; 238 } 239 } // namespace 240 241 // Check that some basic metrics are produced in the right direction. In 242 // particular, expand_rate should only increase if there are losses present. Our 243 // dummy decoder is designed such as the checksum should always be the same 244 // regardless of the losses given that calls are executed in the right order. 245 TEST(NetEqDecoderPlc, BasicMetrics) { 246 std::string checksum; 247 248 // Drop 1 packet every 10 packets. 249 auto stats = RunTest(10, 1, &checksum); 250 251 std::string checksum_no_loss; 252 auto stats_no_loss = RunTest(0, 0, &checksum_no_loss); 253 254 EXPECT_EQ(checksum, checksum_no_loss); 255 256 EXPECT_EQ(stats.network.preemptive_rate, 257 stats_no_loss.network.preemptive_rate); 258 EXPECT_EQ(stats.network.accelerate_rate, 259 stats_no_loss.network.accelerate_rate); 260 EXPECT_EQ(0, stats_no_loss.network.expand_rate); 261 EXPECT_GT(stats.network.expand_rate, 0); 262 } 263 264 // Checks that interruptions are not counted in small losses but they are 265 // correctly counted in long interruptions. 266 TEST(NetEqDecoderPlc, CountInterruptions) { 267 std::string checksum; 268 std::string checksum_2; 269 std::string checksum_3; 270 271 // Half of the packets lost but in short interruptions. 272 auto stats_no_interruptions = RunTest(1, 1, &checksum); 273 // One lost of 500 ms (250 packets). 274 auto stats_one_interruption = RunTest(200, 250, &checksum_2); 275 // Two losses of 250ms each (125 packets). 276 auto stats_two_interruptions = RunTest(125, 125, &checksum_3); 277 278 EXPECT_EQ(checksum, checksum_2); 279 EXPECT_EQ(checksum, checksum_3); 280 EXPECT_GT(stats_no_interruptions.network.expand_rate, 0); 281 EXPECT_EQ(stats_no_interruptions.lifetime.total_interruption_duration_ms, 0); 282 EXPECT_EQ(stats_no_interruptions.lifetime.interruption_count, 0); 283 284 EXPECT_GT(stats_one_interruption.network.expand_rate, 0); 285 EXPECT_EQ(stats_one_interruption.lifetime.total_interruption_duration_ms, 286 5000); 287 EXPECT_EQ(stats_one_interruption.lifetime.interruption_count, 1); 288 289 EXPECT_GT(stats_two_interruptions.network.expand_rate, 0); 290 EXPECT_EQ(stats_two_interruptions.lifetime.total_interruption_duration_ms, 291 5000); 292 EXPECT_EQ(stats_two_interruptions.lifetime.interruption_count, 2); 293 } 294 295 // Checks that small losses do not produce interruptions. 296 TEST(NetEqDecoderPlc, NoInterruptionsInSmallLosses) { 297 std::string checksum_1; 298 std::string checksum_4; 299 300 auto stats_1 = RunTest(300, 1, &checksum_1); 301 auto stats_4 = RunTest(300, 4, &checksum_4); 302 303 EXPECT_EQ(checksum_1, checksum_4); 304 305 EXPECT_EQ(stats_1.lifetime.interruption_count, 0); 306 EXPECT_EQ(stats_1.lifetime.total_interruption_duration_ms, 0); 307 EXPECT_EQ(stats_1.lifetime.concealed_samples, 640u); // 20ms of concealment. 308 EXPECT_EQ(stats_1.lifetime.concealment_events, 1u); // in just one event. 309 310 EXPECT_EQ(stats_4.lifetime.interruption_count, 0); 311 EXPECT_EQ(stats_4.lifetime.total_interruption_duration_ms, 0); 312 EXPECT_EQ(stats_4.lifetime.concealed_samples, 2560u); // 80ms of concealment. 313 EXPECT_EQ(stats_4.lifetime.concealment_events, 1u); // in just one event. 314 } 315 316 // Checks that interruptions of different sizes report correct duration. 317 TEST(NetEqDecoderPlc, InterruptionsReportCorrectSize) { 318 std::string checksum; 319 320 for (int burst_length = 5; burst_length < 10; burst_length++) { 321 auto stats = RunTest(300, burst_length, &checksum); 322 auto duration = stats.lifetime.total_interruption_duration_ms; 323 if (burst_length < 8) { 324 EXPECT_EQ(duration, 0); 325 } else { 326 EXPECT_EQ(duration, burst_length * 20); 327 } 328 } 329 } 330 331 } // namespace test 332 } // namespace webrtc