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