blob: 254c7d420484f1424bcada81991268ef10dc403f [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
andrew@webrtc.org63a50982012-05-02 23:56:37 +00002 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
niklase@google.com470e71d2011-07-07 08:21:25 +00003 *
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/TestVADDTX.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000012
minyue@webrtc.org05617162015-03-03 12:02:30 +000013#include <string>
kjellander@webrtc.org5490c712011-12-21 13:34:18 +000014
Niels Möller2edab4c2018-10-22 09:48:08 +020015#include "absl/strings/match.h"
Karl Wiberg895ce822018-10-01 17:26:11 +020016#include "api/audio_codecs/audio_decoder_factory_template.h"
17#include "api/audio_codecs/audio_encoder_factory_template.h"
18#include "api/audio_codecs/ilbc/audio_decoder_ilbc.h"
19#include "api/audio_codecs/ilbc/audio_encoder_ilbc.h"
20#include "api/audio_codecs/isac/audio_decoder_isac_float.h"
21#include "api/audio_codecs/isac/audio_encoder_isac_float.h"
22#include "api/audio_codecs/opus/audio_decoder_opus.h"
23#include "api/audio_codecs/opus/audio_encoder_opus.h"
24#include "modules/audio_coding/codecs/cng/audio_encoder_cng.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020025#include "modules/audio_coding/test/PCMFile.h"
Jonas Olsson366a50c2018-09-06 13:41:30 +020026#include "rtc_base/strings/string_builder.h"
Fredrik Solenberg657b2962018-12-05 10:30:25 +010027#include "test/gtest.h"
Steve Anton10542f22019-01-11 09:11:00 -080028#include "test/testsupport/file_utils.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000029
tina.legrand@webrtc.org554ae1a2011-12-16 10:09:04 +000030namespace webrtc {
niklase@google.com470e71d2011-07-07 08:21:25 +000031
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +000032ActivityMonitor::ActivityMonitor() {
minyue@webrtc.org05617162015-03-03 12:02:30 +000033 ResetStatistics();
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +000034}
35
Niels Möller87e2d782019-03-07 10:18:23 +010036int32_t ActivityMonitor::InFrameType(AudioFrameType frame_type) {
Niels Möllerc936cb62019-03-19 14:10:16 +010037 counter_[static_cast<int>(frame_type)]++;
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +000038 return 0;
39}
40
tina.legrand@webrtc.orgee92b662013-08-27 07:33:51 +000041void ActivityMonitor::PrintStatistics() {
42 printf("\n");
Niels Möllerc936cb62019-03-19 14:10:16 +010043 printf("kEmptyFrame %u\n",
44 counter_[static_cast<int>(AudioFrameType::kEmptyFrame)]);
45 printf("kAudioFrameSpeech %u\n",
46 counter_[static_cast<int>(AudioFrameType::kAudioFrameSpeech)]);
47 printf("kAudioFrameCN %u\n",
48 counter_[static_cast<int>(AudioFrameType::kAudioFrameCN)]);
tina.legrand@webrtc.orgee92b662013-08-27 07:33:51 +000049 printf("\n\n");
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +000050}
51
52void ActivityMonitor::ResetStatistics() {
minyue@webrtc.org05617162015-03-03 12:02:30 +000053 memset(counter_, 0, sizeof(counter_));
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +000054}
55
minyue@webrtc.org05617162015-03-03 12:02:30 +000056void ActivityMonitor::GetStatistics(uint32_t* counter) {
57 memcpy(counter, counter_, sizeof(counter_));
58}
59
60TestVadDtx::TestVadDtx()
Karl Wiberg895ce822018-10-01 17:26:11 +020061 : encoder_factory_(CreateAudioEncoderFactory<AudioEncoderIlbc,
62 AudioEncoderIsacFloat,
63 AudioEncoderOpus>()),
64 decoder_factory_(CreateAudioDecoderFactory<AudioDecoderIlbc,
65 AudioDecoderIsacFloat,
66 AudioDecoderOpus>()),
67 acm_send_(AudioCodingModule::Create(
68 AudioCodingModule::Config(decoder_factory_))),
Karl Wiberg5817d3d2018-04-06 10:06:42 +020069 acm_receive_(AudioCodingModule::Create(
Karl Wiberg895ce822018-10-01 17:26:11 +020070 AudioCodingModule::Config(decoder_factory_))),
minyue@webrtc.org05617162015-03-03 12:02:30 +000071 channel_(new Channel),
72 monitor_(new ActivityMonitor) {
73 EXPECT_EQ(0, acm_send_->RegisterTransportCallback(channel_.get()));
74 channel_->RegisterReceiverACM(acm_receive_.get());
75 EXPECT_EQ(0, acm_send_->RegisterVADCallback(monitor_.get()));
minyue@webrtc.org05617162015-03-03 12:02:30 +000076}
77
Karl Wiberg895ce822018-10-01 17:26:11 +020078bool TestVadDtx::RegisterCodec(const SdpAudioFormat& codec_format,
79 absl::optional<Vad::Aggressiveness> vad_mode) {
80 constexpr int payload_type = 17, cn_payload_type = 117;
81 bool added_comfort_noise = false;
82
83 auto encoder = encoder_factory_->MakeAudioEncoder(payload_type, codec_format,
84 absl::nullopt);
85 if (vad_mode.has_value() &&
Niels Möller2edab4c2018-10-22 09:48:08 +020086 !absl::EqualsIgnoreCase(codec_format.name, "opus")) {
Karl Wiberg23659362018-11-01 11:13:44 +010087 AudioEncoderCngConfig config;
Karl Wiberg895ce822018-10-01 17:26:11 +020088 config.speech_encoder = std::move(encoder);
89 config.num_channels = 1;
90 config.payload_type = cn_payload_type;
91 config.vad_mode = vad_mode.value();
Karl Wiberg23659362018-11-01 11:13:44 +010092 encoder = CreateComfortNoiseEncoder(std::move(config));
Karl Wiberg895ce822018-10-01 17:26:11 +020093 added_comfort_noise = true;
94 }
95 channel_->SetIsStereo(encoder->NumChannels() > 1);
96 acm_send_->SetEncoder(std::move(encoder));
97
Fredrik Solenberg657b2962018-12-05 10:30:25 +010098 std::map<int, SdpAudioFormat> receive_codecs = {{payload_type, codec_format}};
99 acm_receive_->SetReceiveCodecs(receive_codecs);
100
Karl Wiberg895ce822018-10-01 17:26:11 +0200101 return added_comfort_noise;
minyue@webrtc.org05617162015-03-03 12:02:30 +0000102}
103
104// Encoding a file and see if the numbers that various packets occur follow
105// the expectation.
Yves Gerey665174f2018-06-19 15:03:05 +0200106void TestVadDtx::Run(std::string in_filename,
107 int frequency,
108 int channels,
109 std::string out_filename,
110 bool append,
minyue@webrtc.org05617162015-03-03 12:02:30 +0000111 const int* expects) {
112 monitor_->ResetStatistics();
113
114 PCMFile in_file;
115 in_file.Open(in_filename, frequency, "rb");
116 in_file.ReadStereo(channels > 1);
Henrik Lundin4d682082015-12-10 16:24:39 +0100117 // Set test length to 1000 ms (100 blocks of 10 ms each).
118 in_file.SetNum10MsBlocksToRead(100);
119 // Fast-forward both files 500 ms (50 blocks). The first second of the file is
120 // silence, but we want to keep half of that to test silence periods.
121 in_file.FastForward(50);
minyue@webrtc.org05617162015-03-03 12:02:30 +0000122
123 PCMFile out_file;
124 if (append) {
125 out_file.Open(out_filename, kOutputFreqHz, "ab");
126 } else {
127 out_file.Open(out_filename, kOutputFreqHz, "wb");
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000128 }
minyue@webrtc.org05617162015-03-03 12:02:30 +0000129
130 uint16_t frame_size_samples = in_file.PayloadLength10Ms();
minyue@webrtc.org05617162015-03-03 12:02:30 +0000131 AudioFrame audio_frame;
132 while (!in_file.EndOfFile()) {
133 in_file.Read10MsData(audio_frame);
ossu63fb95a2016-07-06 09:34:22 -0700134 audio_frame.timestamp_ = time_stamp_;
135 time_stamp_ += frame_size_samples;
minyue@webrtc.org05617162015-03-03 12:02:30 +0000136 EXPECT_GE(acm_send_->Add10MsData(audio_frame), 0);
henrik.lundind4ccb002016-05-17 12:21:55 -0700137 bool muted;
138 acm_receive_->PlayoutData10Ms(kOutputFreqHz, &audio_frame, &muted);
139 ASSERT_FALSE(muted);
minyue@webrtc.org05617162015-03-03 12:02:30 +0000140 out_file.Write10MsData(audio_frame);
141 }
142
143 in_file.Close();
144 out_file.Close();
145
146#ifdef PRINT_STAT
147 monitor_->PrintStatistics();
148#endif
149
Niels Möllerc936cb62019-03-19 14:10:16 +0100150 uint32_t stats[3];
minyue@webrtc.org05617162015-03-03 12:02:30 +0000151 monitor_->GetStatistics(stats);
152 monitor_->ResetStatistics();
153
henrik.lundin@webrtc.orge9217b42015-03-06 07:50:34 +0000154 for (const auto& st : stats) {
155 int i = &st - stats; // Calculate the current position in stats.
minyue@webrtc.org05617162015-03-03 12:02:30 +0000156 switch (expects[i]) {
157 case 0: {
henrik.lundin@webrtc.orge9217b42015-03-06 07:50:34 +0000158 EXPECT_EQ(0u, st) << "stats[" << i << "] error.";
minyue@webrtc.org05617162015-03-03 12:02:30 +0000159 break;
160 }
161 case 1: {
henrik.lundin@webrtc.orge9217b42015-03-06 07:50:34 +0000162 EXPECT_GT(st, 0u) << "stats[" << i << "] error.";
minyue@webrtc.org05617162015-03-03 12:02:30 +0000163 break;
164 }
165 }
166 }
167}
168
169// Following is the implementation of TestWebRtcVadDtx.
Karl Wiberg895ce822018-10-01 17:26:11 +0200170TestWebRtcVadDtx::TestWebRtcVadDtx() : output_file_num_(0) {}
minyue@webrtc.org05617162015-03-03 12:02:30 +0000171
172void TestWebRtcVadDtx::Perform() {
Karl Wiberg895ce822018-10-01 17:26:11 +0200173 RunTestCases({"ISAC", 16000, 1});
174 RunTestCases({"ISAC", 32000, 1});
175 RunTestCases({"ILBC", 8000, 1});
176 RunTestCases({"opus", 48000, 2});
minyue@webrtc.org05617162015-03-03 12:02:30 +0000177}
178
179// Test various configurations on VAD/DTX.
Karl Wiberg895ce822018-10-01 17:26:11 +0200180void TestWebRtcVadDtx::RunTestCases(const SdpAudioFormat& codec_format) {
181 Test(/*new_outfile=*/true,
182 /*expect_dtx_enabled=*/RegisterCodec(codec_format, absl::nullopt));
minyue@webrtc.org05617162015-03-03 12:02:30 +0000183
Karl Wiberg895ce822018-10-01 17:26:11 +0200184 Test(/*new_outfile=*/false,
185 /*expect_dtx_enabled=*/RegisterCodec(codec_format, Vad::kVadAggressive));
minyue@webrtc.org05617162015-03-03 12:02:30 +0000186
Karl Wiberg895ce822018-10-01 17:26:11 +0200187 Test(/*new_outfile=*/false,
188 /*expect_dtx_enabled=*/RegisterCodec(codec_format, Vad::kVadLowBitrate));
minyue@webrtc.org05617162015-03-03 12:02:30 +0000189
Karl Wiberg895ce822018-10-01 17:26:11 +0200190 Test(/*new_outfile=*/false, /*expect_dtx_enabled=*/RegisterCodec(
191 codec_format, Vad::kVadVeryAggressive));
minyue@webrtc.org05617162015-03-03 12:02:30 +0000192
Karl Wiberg895ce822018-10-01 17:26:11 +0200193 Test(/*new_outfile=*/false,
194 /*expect_dtx_enabled=*/RegisterCodec(codec_format, Vad::kVadNormal));
minyue@webrtc.org05617162015-03-03 12:02:30 +0000195}
196
197// Set the expectation and run the test.
Karl Wiberg895ce822018-10-01 17:26:11 +0200198void TestWebRtcVadDtx::Test(bool new_outfile, bool expect_dtx_enabled) {
199 int expects[] = {-1, 1, expect_dtx_enabled, 0, 0};
minyue@webrtc.org05617162015-03-03 12:02:30 +0000200 if (new_outfile) {
201 output_file_num_++;
202 }
Jonas Olsson366a50c2018-09-06 13:41:30 +0200203 rtc::StringBuilder out_filename;
Yves Gerey665174f2018-06-19 15:03:05 +0200204 out_filename << webrtc::test::OutputPath() << "testWebRtcVadDtx_outFile_"
205 << output_file_num_ << ".pcm";
206 Run(webrtc::test::ResourcePath("audio_coding/testfile32kHz", "pcm"), 32000, 1,
207 out_filename.str(), !new_outfile, expects);
minyue@webrtc.org05617162015-03-03 12:02:30 +0000208}
209
minyue@webrtc.org05617162015-03-03 12:02:30 +0000210// Following is the implementation of TestOpusDtx.
211void TestOpusDtx::Perform() {
kwiberg44307632015-12-16 06:24:05 -0800212 // If we set other codec than Opus, DTX cannot be switched on.
Karl Wiberg895ce822018-10-01 17:26:11 +0200213 RegisterCodec({"ISAC", 16000, 1}, absl::nullopt);
Minyue Li092041c2015-05-11 12:19:35 +0200214 EXPECT_EQ(-1, acm_send_->EnableOpusDtx());
kwiberg44307632015-12-16 06:24:05 -0800215 EXPECT_EQ(0, acm_send_->DisableOpusDtx());
minyue@webrtc.orge16bfde2015-03-12 15:28:41 +0000216
henrik.lundin@webrtc.orge9217b42015-03-06 07:50:34 +0000217 int expects[] = {0, 1, 0, 0, 0};
minyue@webrtc.org05617162015-03-03 12:02:30 +0000218
219 // Register Opus as send codec
Yves Gerey665174f2018-06-19 15:03:05 +0200220 std::string out_filename =
221 webrtc::test::OutputPath() + "testOpusDtx_outFile_mono.pcm";
Karl Wiberg895ce822018-10-01 17:26:11 +0200222 RegisterCodec({"opus", 48000, 2}, absl::nullopt);
minyue@webrtc.org05617162015-03-03 12:02:30 +0000223 EXPECT_EQ(0, acm_send_->DisableOpusDtx());
224
Yves Gerey665174f2018-06-19 15:03:05 +0200225 Run(webrtc::test::ResourcePath("audio_coding/testfile32kHz", "pcm"), 32000, 1,
226 out_filename, false, expects);
minyue@webrtc.org05617162015-03-03 12:02:30 +0000227
Minyue Li092041c2015-05-11 12:19:35 +0200228 EXPECT_EQ(0, acm_send_->EnableOpusDtx());
Niels Möller8f7ce222019-03-21 15:43:58 +0100229 expects[static_cast<int>(AudioFrameType::kEmptyFrame)] = 1;
230 expects[static_cast<int>(AudioFrameType::kAudioFrameCN)] = 1;
Yves Gerey665174f2018-06-19 15:03:05 +0200231 Run(webrtc::test::ResourcePath("audio_coding/testfile32kHz", "pcm"), 32000, 1,
232 out_filename, true, expects);
minyue@webrtc.org05617162015-03-03 12:02:30 +0000233
234 // Register stereo Opus as send codec
235 out_filename = webrtc::test::OutputPath() + "testOpusDtx_outFile_stereo.pcm";
Karl Wiberg895ce822018-10-01 17:26:11 +0200236 RegisterCodec({"opus", 48000, 2, {{"stereo", "1"}}}, absl::nullopt);
minyue@webrtc.org05617162015-03-03 12:02:30 +0000237 EXPECT_EQ(0, acm_send_->DisableOpusDtx());
Niels Möller8f7ce222019-03-21 15:43:58 +0100238 expects[static_cast<int>(AudioFrameType::kEmptyFrame)] = 0;
239 expects[static_cast<int>(AudioFrameType::kAudioFrameCN)] = 0;
Yves Gerey665174f2018-06-19 15:03:05 +0200240 Run(webrtc::test::ResourcePath("audio_coding/teststereo32kHz", "pcm"), 32000,
241 2, out_filename, false, expects);
minyue@webrtc.org05617162015-03-03 12:02:30 +0000242
Minyue Li092041c2015-05-11 12:19:35 +0200243 EXPECT_EQ(0, acm_send_->EnableOpusDtx());
minyue@webrtc.org05617162015-03-03 12:02:30 +0000244
Niels Möller8f7ce222019-03-21 15:43:58 +0100245 expects[static_cast<int>(AudioFrameType::kEmptyFrame)] = 1;
246 expects[static_cast<int>(AudioFrameType::kAudioFrameCN)] = 1;
Yves Gerey665174f2018-06-19 15:03:05 +0200247 Run(webrtc::test::ResourcePath("audio_coding/teststereo32kHz", "pcm"), 32000,
248 2, out_filename, true, expects);
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000249}
250
251} // namespace webrtc