TestRedFec.cc (7736B)
1 /* 2 * Copyright (c) 2012 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 "modules/audio_coding/test/TestRedFec.h" 12 13 #include <cstddef> 14 #include <cstdint> 15 #include <map> 16 #include <memory> 17 #include <optional> 18 #include <string> 19 #include <utility> 20 21 #include "absl/strings/match.h" 22 #include "api/audio/audio_frame.h" 23 #include "api/audio_codecs/L16/audio_decoder_L16.h" 24 #include "api/audio_codecs/L16/audio_encoder_L16.h" 25 #include "api/audio_codecs/audio_decoder_factory_template.h" 26 #include "api/audio_codecs/audio_encoder.h" 27 #include "api/audio_codecs/audio_encoder_factory_template.h" 28 #include "api/audio_codecs/audio_format.h" 29 #include "api/audio_codecs/g711/audio_decoder_g711.h" 30 #include "api/audio_codecs/g711/audio_encoder_g711.h" 31 #include "api/audio_codecs/g722/audio_decoder_g722.h" 32 #include "api/audio_codecs/g722/audio_encoder_g722.h" 33 #include "api/audio_codecs/opus/audio_decoder_opus.h" 34 #include "api/audio_codecs/opus/audio_encoder_opus.h" 35 #include "api/environment/environment_factory.h" 36 #include "api/neteq/default_neteq_factory.h" 37 #include "api/neteq/neteq.h" 38 #include "common_audio/vad/include/vad.h" 39 #include "modules/audio_coding/codecs/cng/audio_encoder_cng.h" 40 #include "modules/audio_coding/codecs/red/audio_encoder_copy_red.h" 41 #include "modules/audio_coding/include/audio_coding_module.h" 42 #include "modules/audio_coding/test/Channel.h" 43 #include "rtc_base/strings/string_builder.h" 44 #include "test/create_test_field_trials.h" 45 #include "test/gtest.h" 46 #include "test/testsupport/file_utils.h" 47 48 namespace webrtc { 49 50 TestRedFec::TestRedFec() 51 : env_(CreateEnvironment(CreateTestFieldTrialsPtr())), 52 encoder_factory_(CreateAudioEncoderFactory<AudioEncoderG711, 53 AudioEncoderG722, 54 AudioEncoderL16, 55 AudioEncoderOpus>()), 56 decoder_factory_(CreateAudioDecoderFactory<AudioDecoderG711, 57 AudioDecoderG722, 58 AudioDecoderL16, 59 AudioDecoderOpus>()), 60 _acmA(AudioCodingModule::Create()), 61 _neteq(DefaultNetEqFactory().Create(env_, 62 NetEq::Config(), 63 decoder_factory_)), 64 _channelA2B(nullptr), 65 _testCntr(0) {} 66 67 TestRedFec::~TestRedFec() { 68 if (_channelA2B != nullptr) { 69 delete _channelA2B; 70 _channelA2B = nullptr; 71 } 72 } 73 74 void TestRedFec::Perform() { 75 const std::string file_name = 76 test::ResourcePath("audio_coding/testfile32kHz", "pcm"); 77 _inFileA.Open(file_name, 32000, "rb"); 78 79 // Create and connect the channel 80 _channelA2B = new Channel; 81 _acmA->RegisterTransportCallback(_channelA2B); 82 _channelA2B->RegisterReceiverNetEq(_neteq.get()); 83 84 RegisterSendCodec(_acmA, {"L16", 8000, 1}, Vad::kVadAggressive, true); 85 86 OpenOutFile(_testCntr); 87 Run(); 88 _outFileB.Close(); 89 90 // Switch to another 8 kHz codec; RED should remain switched on. 91 RegisterSendCodec(_acmA, {"PCMU", 8000, 1}, Vad::kVadAggressive, true); 92 OpenOutFile(_testCntr); 93 Run(); 94 _outFileB.Close(); 95 96 // TODO(bugs.webrtc.org/345525069): Either fix/enable or remove G722. 97 #if defined(__has_feature) && !__has_feature(undefined_behavior_sanitizer) 98 // Switch to a 16 kHz codec; RED should be switched off. 99 RegisterSendCodec(_acmA, {"G722", 8000, 1}, Vad::kVadAggressive, false); 100 101 OpenOutFile(_testCntr); 102 RegisterSendCodec(_acmA, {"G722", 8000, 1}, Vad::kVadAggressive, false); 103 Run(); 104 RegisterSendCodec(_acmA, {"G722", 8000, 1}, Vad::kVadAggressive, false); 105 Run(); 106 _outFileB.Close(); 107 108 _channelA2B->SetFECTestWithPacketLoss(true); 109 // Following tests are under packet losses. 110 111 // Switch to a 16 kHz codec; RED should be switched off. 112 RegisterSendCodec(_acmA, {"G722", 8000, 1}, Vad::kVadAggressive, false); 113 114 OpenOutFile(_testCntr); 115 Run(); 116 _outFileB.Close(); 117 #endif 118 119 RegisterSendCodec(_acmA, {"opus", 48000, 2}, std::nullopt, false); 120 121 // _channelA2B imposes 25% packet loss rate. 122 EXPECT_EQ(0, _acmA->SetPacketLossRate(25)); 123 124 _acmA->ModifyEncoder([&](std::unique_ptr<AudioEncoder>* enc) { 125 EXPECT_EQ(true, (*enc)->SetFec(true)); 126 }); 127 128 OpenOutFile(_testCntr); 129 Run(); 130 131 // Switch to L16 with RED. 132 RegisterSendCodec(_acmA, {"L16", 8000, 1}, std::nullopt, true); 133 Run(); 134 135 // Switch to Opus again. 136 RegisterSendCodec(_acmA, {"opus", 48000, 2}, std::nullopt, false); 137 _acmA->ModifyEncoder([&](std::unique_ptr<AudioEncoder>* enc) { 138 EXPECT_EQ(true, (*enc)->SetFec(false)); 139 }); 140 Run(); 141 142 _acmA->ModifyEncoder([&](std::unique_ptr<AudioEncoder>* enc) { 143 EXPECT_EQ(true, (*enc)->SetFec(true)); 144 }); 145 _outFileB.Close(); 146 } 147 148 void TestRedFec::RegisterSendCodec( 149 const std::unique_ptr<AudioCodingModule>& acm, 150 const SdpAudioFormat& codec_format, 151 std::optional<Vad::Aggressiveness> vad_mode, 152 bool use_red) { 153 constexpr int payload_type = 17, cn_payload_type = 27, red_payload_type = 37; 154 155 auto encoder = encoder_factory_->Create(env_, codec_format, 156 {.payload_type = payload_type}); 157 EXPECT_NE(encoder, nullptr); 158 std::map<int, SdpAudioFormat> receive_codecs = {{payload_type, codec_format}}; 159 if (!absl::EqualsIgnoreCase(codec_format.name, "opus")) { 160 if (vad_mode.has_value()) { 161 AudioEncoderCngConfig config; 162 config.speech_encoder = std::move(encoder); 163 config.num_channels = 1; 164 config.payload_type = cn_payload_type; 165 config.vad_mode = vad_mode.value(); 166 encoder = CreateComfortNoiseEncoder(std::move(config)); 167 receive_codecs.emplace(std::make_pair( 168 cn_payload_type, SdpAudioFormat("CN", codec_format.clockrate_hz, 1))); 169 } 170 if (use_red) { 171 AudioEncoderCopyRed::Config config; 172 config.payload_type = red_payload_type; 173 config.speech_encoder = std::move(encoder); 174 encoder = std::make_unique<AudioEncoderCopyRed>(std::move(config), 175 env_.field_trials()); 176 receive_codecs.emplace( 177 std::make_pair(red_payload_type, 178 SdpAudioFormat("red", codec_format.clockrate_hz, 1))); 179 } 180 } 181 acm->SetEncoder(std::move(encoder)); 182 _neteq->SetCodecs(receive_codecs); 183 } 184 185 void TestRedFec::Run() { 186 AudioFrame audioFrame; 187 int32_t outFreqHzB = _outFileB.SamplingFrequency(); 188 // Set test length to 500 ms (50 blocks of 10 ms each). 189 _inFileA.SetNum10MsBlocksToRead(50); 190 // Fast-forward 1 second (100 blocks) since the file starts with silence. 191 _inFileA.FastForward(100); 192 193 while (!_inFileA.EndOfFile()) { 194 EXPECT_GT(_inFileA.Read10MsData(audioFrame), 0); 195 EXPECT_GE(_acmA->Add10MsData(audioFrame), 0); 196 bool muted; 197 EXPECT_EQ(NetEq::kOK, _neteq->GetAudio(&audioFrame, &muted)); 198 EXPECT_TRUE(_resampler_helper.MaybeResample(outFreqHzB, &audioFrame)); 199 ASSERT_FALSE(muted); 200 _outFileB.Write10MsData(audioFrame.data(), audioFrame.samples_per_channel_); 201 } 202 _inFileA.Rewind(); 203 } 204 205 void TestRedFec::OpenOutFile(int16_t test_number) { 206 std::string file_name; 207 StringBuilder file_stream; 208 file_stream << test::OutputPath(); 209 file_stream << "TestRedFec_outFile_"; 210 file_stream << test_number << ".pcm"; 211 file_name = file_stream.str(); 212 _outFileB.Open(file_name, 16000, "wb"); 213 } 214 215 } // namespace webrtc