blob: f8acf48508c7255c865bab7d16bedff601686412 [file] [log] [blame]
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +00001/*
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
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "modules/audio_coding/test/TestRedFec.h"
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +000012
Mirko Bonadei317a1f02019-09-17 17:06:18 +020013#include <memory>
Fredrik Solenberg657b2962018-12-05 10:30:25 +010014#include <utility>
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +000015
Fredrik Solenberg657b2962018-12-05 10:30:25 +010016#include "absl/strings/match.h"
Karl Wibergc2c4d042018-10-04 12:38:03 +020017#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"
Karl Wibergc2c4d042018-10-04 12:38:03 +020025#include "api/audio_codecs/opus/audio_decoder_opus.h"
26#include "api/audio_codecs/opus/audio_encoder_opus.h"
Karl Wibergc2c4d042018-10-04 12:38:03 +020027#include "modules/audio_coding/codecs/cng/audio_encoder_cng.h"
28#include "modules/audio_coding/codecs/red/audio_encoder_copy_red.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020029#include "modules/audio_coding/include/audio_coding_module_typedefs.h"
Jonas Olsson366a50c2018-09-06 13:41:30 +020030#include "rtc_base/strings/string_builder.h"
Fredrik Solenberg657b2962018-12-05 10:30:25 +010031#include "test/gtest.h"
Steve Anton10542f22019-01-11 09:11:00 -080032#include "test/testsupport/file_utils.h"
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +000033
34namespace webrtc {
35
36TestRedFec::TestRedFec()
Karl Wibergc2c4d042018-10-04 12:38:03 +020037 : encoder_factory_(CreateAudioEncoderFactory<AudioEncoderG711,
38 AudioEncoderG722,
Karl Wibergc2c4d042018-10-04 12:38:03 +020039 AudioEncoderL16,
40 AudioEncoderOpus>()),
41 decoder_factory_(CreateAudioDecoderFactory<AudioDecoderG711,
42 AudioDecoderG722,
Karl Wibergc2c4d042018-10-04 12:38:03 +020043 AudioDecoderL16,
44 AudioDecoderOpus>()),
Henrik Lundin84f75692023-02-01 12:07:10 +000045 _acmA(AudioCodingModule::Create()),
46 _acm_receiver(std::make_unique<acm2::AcmReceiver>(
47 acm2::AcmReceiver::Config(decoder_factory_))),
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +000048 _channelA2B(NULL),
Karl Wiberg5817d3d2018-04-06 10:06:42 +020049 _testCntr(0) {}
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +000050
51TestRedFec::~TestRedFec() {
52 if (_channelA2B != NULL) {
53 delete _channelA2B;
54 _channelA2B = NULL;
55 }
56}
57
58void TestRedFec::Perform() {
Jonas Olssona4d87372019-07-05 19:08:33 +020059 const std::string file_name =
60 webrtc::test::ResourcePath("audio_coding/testfile32kHz", "pcm");
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +000061 _inFileA.Open(file_name, 32000, "rb");
62
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +000063 // Create and connect the channel
64 _channelA2B = new Channel;
65 _acmA->RegisterTransportCallback(_channelA2B);
Henrik Lundin84f75692023-02-01 12:07:10 +000066 _channelA2B->RegisterReceiverACM(_acm_receiver.get());
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +000067
Karl Wibergc2c4d042018-10-04 12:38:03 +020068 RegisterSendCodec(_acmA, {"L16", 8000, 1}, Vad::kVadAggressive, true);
minyue@webrtc.org41d2bef2015-03-23 12:57:45 +000069
70 OpenOutFile(_testCntr);
71 Run();
72 _outFileB.Close();
73
Karl Wibergc2c4d042018-10-04 12:38:03 +020074 // Switch to another 8 kHz codec; RED should remain switched on.
75 RegisterSendCodec(_acmA, {"PCMU", 8000, 1}, Vad::kVadAggressive, true);
minyue@webrtc.org41d2bef2015-03-23 12:57:45 +000076 OpenOutFile(_testCntr);
77 Run();
78 _outFileB.Close();
79
Karl Wibergc2c4d042018-10-04 12:38:03 +020080 // Switch to a 16 kHz codec; RED should be switched off.
81 RegisterSendCodec(_acmA, {"G722", 8000, 1}, Vad::kVadAggressive, false);
minyue@webrtc.org41d2bef2015-03-23 12:57:45 +000082
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +000083 OpenOutFile(_testCntr);
Karl Wibergc2c4d042018-10-04 12:38:03 +020084 RegisterSendCodec(_acmA, {"G722", 8000, 1}, Vad::kVadAggressive, false);
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +000085 Run();
Karl Wibergc2c4d042018-10-04 12:38:03 +020086 RegisterSendCodec(_acmA, {"G722", 8000, 1}, Vad::kVadAggressive, false);
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +000087 Run();
88 _outFileB.Close();
89
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +000090 _channelA2B->SetFECTestWithPacketLoss(true);
minyue@webrtc.org41d2bef2015-03-23 12:57:45 +000091 // Following tests are under packet losses.
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +000092
Karl Wibergc2c4d042018-10-04 12:38:03 +020093 // Switch to a 16 kHz codec; RED should be switched off.
94 RegisterSendCodec(_acmA, {"G722", 8000, 1}, Vad::kVadAggressive, false);
95
96 OpenOutFile(_testCntr);
97 Run();
98 _outFileB.Close();
minyue@webrtc.org41d2bef2015-03-23 12:57:45 +000099
Karl Wibergc2c4d042018-10-04 12:38:03 +0200100 RegisterSendCodec(_acmA, {"opus", 48000, 2}, absl::nullopt, false);
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +0000101
102 // _channelA2B imposes 25% packet loss rate.
103 EXPECT_EQ(0, _acmA->SetPacketLossRate(25));
104
Karl Wibergc2c4d042018-10-04 12:38:03 +0200105 _acmA->ModifyEncoder([&](std::unique_ptr<AudioEncoder>* enc) {
106 EXPECT_EQ(true, (*enc)->SetFec(true));
107 });
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +0000108
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +0000109 OpenOutFile(_testCntr);
110 Run();
111
minyue@webrtc.org41d2bef2015-03-23 12:57:45 +0000112 // Switch to L16 with RED.
Karl Wibergc2c4d042018-10-04 12:38:03 +0200113 RegisterSendCodec(_acmA, {"L16", 8000, 1}, absl::nullopt, true);
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +0000114 Run();
115
116 // Switch to Opus again.
Karl Wibergc2c4d042018-10-04 12:38:03 +0200117 RegisterSendCodec(_acmA, {"opus", 48000, 2}, absl::nullopt, false);
118 _acmA->ModifyEncoder([&](std::unique_ptr<AudioEncoder>* enc) {
119 EXPECT_EQ(true, (*enc)->SetFec(false));
120 });
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +0000121 Run();
122
Karl Wibergc2c4d042018-10-04 12:38:03 +0200123 _acmA->ModifyEncoder([&](std::unique_ptr<AudioEncoder>* enc) {
124 EXPECT_EQ(true, (*enc)->SetFec(true));
125 });
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +0000126 _outFileB.Close();
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +0000127}
128
Karl Wibergc2c4d042018-10-04 12:38:03 +0200129void TestRedFec::RegisterSendCodec(
130 const std::unique_ptr<AudioCodingModule>& acm,
131 const SdpAudioFormat& codec_format,
132 absl::optional<Vad::Aggressiveness> vad_mode,
133 bool use_red) {
134 constexpr int payload_type = 17, cn_payload_type = 27, red_payload_type = 37;
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +0000135
Karl Wibergc2c4d042018-10-04 12:38:03 +0200136 auto encoder = encoder_factory_->MakeAudioEncoder(payload_type, codec_format,
137 absl::nullopt);
138 EXPECT_NE(encoder, nullptr);
Fredrik Solenberg657b2962018-12-05 10:30:25 +0100139 std::map<int, SdpAudioFormat> receive_codecs = {{payload_type, codec_format}};
Niels Möller2edab4c2018-10-22 09:48:08 +0200140 if (!absl::EqualsIgnoreCase(codec_format.name, "opus")) {
Karl Wibergc2c4d042018-10-04 12:38:03 +0200141 if (vad_mode.has_value()) {
Karl Wiberg23659362018-11-01 11:13:44 +0100142 AudioEncoderCngConfig config;
Karl Wibergc2c4d042018-10-04 12:38:03 +0200143 config.speech_encoder = std::move(encoder);
144 config.num_channels = 1;
145 config.payload_type = cn_payload_type;
146 config.vad_mode = vad_mode.value();
Karl Wiberg23659362018-11-01 11:13:44 +0100147 encoder = CreateComfortNoiseEncoder(std::move(config));
Jonas Olssona4d87372019-07-05 19:08:33 +0200148 receive_codecs.emplace(std::make_pair(
149 cn_payload_type, SdpAudioFormat("CN", codec_format.clockrate_hz, 1)));
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +0000150 }
Karl Wibergc2c4d042018-10-04 12:38:03 +0200151 if (use_red) {
152 AudioEncoderCopyRed::Config config;
153 config.payload_type = red_payload_type;
154 config.speech_encoder = std::move(encoder);
Jonas Orelanda943e732022-03-16 13:50:58 +0100155 encoder = std::make_unique<AudioEncoderCopyRed>(std::move(config),
156 field_trials_);
Fredrik Solenberg657b2962018-12-05 10:30:25 +0100157 receive_codecs.emplace(
158 std::make_pair(red_payload_type,
159 SdpAudioFormat("red", codec_format.clockrate_hz, 1)));
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +0000160 }
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +0000161 }
Karl Wibergc2c4d042018-10-04 12:38:03 +0200162 acm->SetEncoder(std::move(encoder));
Henrik Lundin84f75692023-02-01 12:07:10 +0000163 _acm_receiver->SetCodecs(receive_codecs);
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +0000164}
165
166void TestRedFec::Run() {
167 AudioFrame audioFrame;
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +0000168 int32_t outFreqHzB = _outFileB.SamplingFrequency();
Henrik Lundin4d682082015-12-10 16:24:39 +0100169 // Set test length to 500 ms (50 blocks of 10 ms each).
170 _inFileA.SetNum10MsBlocksToRead(50);
171 // Fast-forward 1 second (100 blocks) since the file starts with silence.
172 _inFileA.FastForward(100);
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +0000173
174 while (!_inFileA.EndOfFile()) {
175 EXPECT_GT(_inFileA.Read10MsData(audioFrame), 0);
henrik.lundin@webrtc.orgf56c1622015-03-02 12:29:30 +0000176 EXPECT_GE(_acmA->Add10MsData(audioFrame), 0);
henrik.lundind4ccb002016-05-17 12:21:55 -0700177 bool muted;
Henrik Lundin84f75692023-02-01 12:07:10 +0000178 EXPECT_EQ(0, _acm_receiver->GetAudio(outFreqHzB, &audioFrame, &muted));
henrik.lundind4ccb002016-05-17 12:21:55 -0700179 ASSERT_FALSE(muted);
yujo36b1a5f2017-06-12 12:45:32 -0700180 _outFileB.Write10MsData(audioFrame.data(), audioFrame.samples_per_channel_);
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +0000181 }
182 _inFileA.Rewind();
183}
184
185void TestRedFec::OpenOutFile(int16_t test_number) {
186 std::string file_name;
Jonas Olsson366a50c2018-09-06 13:41:30 +0200187 rtc::StringBuilder file_stream;
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +0000188 file_stream << webrtc::test::OutputPath();
189 file_stream << "TestRedFec_outFile_";
190 file_stream << test_number << ".pcm";
191 file_name = file_stream.str();
192 _outFileB.Open(file_name, 16000, "wb");
193}
194
195} // namespace webrtc