blob: cb05deb92a06e3f4c9a2451fe5371fdd812b5baf [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"
Ali Tofigh714e3cb2022-07-20 12:53:07 +020016#include "absl/strings/string_view.h"
Karl Wiberg895ce822018-10-01 17:26:11 +020017#include "api/audio_codecs/audio_decoder_factory_template.h"
18#include "api/audio_codecs/audio_encoder_factory_template.h"
19#include "api/audio_codecs/ilbc/audio_decoder_ilbc.h"
20#include "api/audio_codecs/ilbc/audio_encoder_ilbc.h"
21#include "api/audio_codecs/isac/audio_decoder_isac_float.h"
22#include "api/audio_codecs/isac/audio_encoder_isac_float.h"
23#include "api/audio_codecs/opus/audio_decoder_opus.h"
24#include "api/audio_codecs/opus/audio_encoder_opus.h"
25#include "modules/audio_coding/codecs/cng/audio_encoder_cng.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020026#include "modules/audio_coding/test/PCMFile.h"
Jonas Olsson366a50c2018-09-06 13:41:30 +020027#include "rtc_base/strings/string_builder.h"
Fredrik Solenberg657b2962018-12-05 10:30:25 +010028#include "test/gtest.h"
Steve Anton10542f22019-01-11 09:11:00 -080029#include "test/testsupport/file_utils.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000030
tina.legrand@webrtc.org554ae1a2011-12-16 10:09:04 +000031namespace webrtc {
niklase@google.com470e71d2011-07-07 08:21:25 +000032
Niels Möller3bdc5e92020-03-10 09:28:33 +010033MonitoringAudioPacketizationCallback::MonitoringAudioPacketizationCallback(
34 AudioPacketizationCallback* next)
35 : next_(next) {
minyue@webrtc.org05617162015-03-03 12:02:30 +000036 ResetStatistics();
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +000037}
38
Niels Möller3bdc5e92020-03-10 09:28:33 +010039int32_t MonitoringAudioPacketizationCallback::SendData(
40 AudioFrameType frame_type,
41 uint8_t payload_type,
42 uint32_t timestamp,
43 const uint8_t* payload_data,
44 size_t payload_len_bytes,
45 int64_t absolute_capture_timestamp_ms) {
Niels Möllerc936cb62019-03-19 14:10:16 +010046 counter_[static_cast<int>(frame_type)]++;
Niels Möller3bdc5e92020-03-10 09:28:33 +010047 return next_->SendData(frame_type, payload_type, timestamp, payload_data,
48 payload_len_bytes, absolute_capture_timestamp_ms);
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +000049}
50
Niels Möller3bdc5e92020-03-10 09:28:33 +010051void MonitoringAudioPacketizationCallback::PrintStatistics() {
tina.legrand@webrtc.orgee92b662013-08-27 07:33:51 +000052 printf("\n");
Niels Möllerc936cb62019-03-19 14:10:16 +010053 printf("kEmptyFrame %u\n",
54 counter_[static_cast<int>(AudioFrameType::kEmptyFrame)]);
55 printf("kAudioFrameSpeech %u\n",
56 counter_[static_cast<int>(AudioFrameType::kAudioFrameSpeech)]);
57 printf("kAudioFrameCN %u\n",
58 counter_[static_cast<int>(AudioFrameType::kAudioFrameCN)]);
tina.legrand@webrtc.orgee92b662013-08-27 07:33:51 +000059 printf("\n\n");
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +000060}
61
Niels Möller3bdc5e92020-03-10 09:28:33 +010062void MonitoringAudioPacketizationCallback::ResetStatistics() {
minyue@webrtc.org05617162015-03-03 12:02:30 +000063 memset(counter_, 0, sizeof(counter_));
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +000064}
65
Niels Möller3bdc5e92020-03-10 09:28:33 +010066void MonitoringAudioPacketizationCallback::GetStatistics(uint32_t* counter) {
minyue@webrtc.org05617162015-03-03 12:02:30 +000067 memcpy(counter, counter_, sizeof(counter_));
68}
69
70TestVadDtx::TestVadDtx()
Karl Wiberg895ce822018-10-01 17:26:11 +020071 : encoder_factory_(CreateAudioEncoderFactory<AudioEncoderIlbc,
72 AudioEncoderIsacFloat,
73 AudioEncoderOpus>()),
74 decoder_factory_(CreateAudioDecoderFactory<AudioDecoderIlbc,
75 AudioDecoderIsacFloat,
76 AudioDecoderOpus>()),
77 acm_send_(AudioCodingModule::Create(
78 AudioCodingModule::Config(decoder_factory_))),
Karl Wiberg5817d3d2018-04-06 10:06:42 +020079 acm_receive_(AudioCodingModule::Create(
Karl Wiberg895ce822018-10-01 17:26:11 +020080 AudioCodingModule::Config(decoder_factory_))),
Niels Möller3bdc5e92020-03-10 09:28:33 +010081 channel_(std::make_unique<Channel>()),
82 packetization_callback_(
83 std::make_unique<MonitoringAudioPacketizationCallback>(
84 channel_.get())) {
85 EXPECT_EQ(
86 0, acm_send_->RegisterTransportCallback(packetization_callback_.get()));
minyue@webrtc.org05617162015-03-03 12:02:30 +000087 channel_->RegisterReceiverACM(acm_receive_.get());
minyue@webrtc.org05617162015-03-03 12:02:30 +000088}
89
Karl Wiberg895ce822018-10-01 17:26:11 +020090bool TestVadDtx::RegisterCodec(const SdpAudioFormat& codec_format,
91 absl::optional<Vad::Aggressiveness> vad_mode) {
92 constexpr int payload_type = 17, cn_payload_type = 117;
93 bool added_comfort_noise = false;
94
95 auto encoder = encoder_factory_->MakeAudioEncoder(payload_type, codec_format,
96 absl::nullopt);
97 if (vad_mode.has_value() &&
Niels Möller2edab4c2018-10-22 09:48:08 +020098 !absl::EqualsIgnoreCase(codec_format.name, "opus")) {
Karl Wiberg23659362018-11-01 11:13:44 +010099 AudioEncoderCngConfig config;
Karl Wiberg895ce822018-10-01 17:26:11 +0200100 config.speech_encoder = std::move(encoder);
101 config.num_channels = 1;
102 config.payload_type = cn_payload_type;
103 config.vad_mode = vad_mode.value();
Karl Wiberg23659362018-11-01 11:13:44 +0100104 encoder = CreateComfortNoiseEncoder(std::move(config));
Karl Wiberg895ce822018-10-01 17:26:11 +0200105 added_comfort_noise = true;
106 }
107 channel_->SetIsStereo(encoder->NumChannels() > 1);
108 acm_send_->SetEncoder(std::move(encoder));
109
Fredrik Solenberg657b2962018-12-05 10:30:25 +0100110 std::map<int, SdpAudioFormat> receive_codecs = {{payload_type, codec_format}};
111 acm_receive_->SetReceiveCodecs(receive_codecs);
112
Karl Wiberg895ce822018-10-01 17:26:11 +0200113 return added_comfort_noise;
minyue@webrtc.org05617162015-03-03 12:02:30 +0000114}
115
116// Encoding a file and see if the numbers that various packets occur follow
117// the expectation.
Ali Tofigh714e3cb2022-07-20 12:53:07 +0200118void TestVadDtx::Run(absl::string_view in_filename,
Yves Gerey665174f2018-06-19 15:03:05 +0200119 int frequency,
120 int channels,
Ali Tofigh714e3cb2022-07-20 12:53:07 +0200121 absl::string_view out_filename,
Yves Gerey665174f2018-06-19 15:03:05 +0200122 bool append,
minyue@webrtc.org05617162015-03-03 12:02:30 +0000123 const int* expects) {
Niels Möller3bdc5e92020-03-10 09:28:33 +0100124 packetization_callback_->ResetStatistics();
minyue@webrtc.org05617162015-03-03 12:02:30 +0000125
126 PCMFile in_file;
127 in_file.Open(in_filename, frequency, "rb");
128 in_file.ReadStereo(channels > 1);
Henrik Lundin4d682082015-12-10 16:24:39 +0100129 // Set test length to 1000 ms (100 blocks of 10 ms each).
130 in_file.SetNum10MsBlocksToRead(100);
131 // Fast-forward both files 500 ms (50 blocks). The first second of the file is
132 // silence, but we want to keep half of that to test silence periods.
133 in_file.FastForward(50);
minyue@webrtc.org05617162015-03-03 12:02:30 +0000134
135 PCMFile out_file;
136 if (append) {
137 out_file.Open(out_filename, kOutputFreqHz, "ab");
138 } else {
139 out_file.Open(out_filename, kOutputFreqHz, "wb");
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000140 }
minyue@webrtc.org05617162015-03-03 12:02:30 +0000141
142 uint16_t frame_size_samples = in_file.PayloadLength10Ms();
minyue@webrtc.org05617162015-03-03 12:02:30 +0000143 AudioFrame audio_frame;
144 while (!in_file.EndOfFile()) {
145 in_file.Read10MsData(audio_frame);
ossu63fb95a2016-07-06 09:34:22 -0700146 audio_frame.timestamp_ = time_stamp_;
147 time_stamp_ += frame_size_samples;
minyue@webrtc.org05617162015-03-03 12:02:30 +0000148 EXPECT_GE(acm_send_->Add10MsData(audio_frame), 0);
henrik.lundind4ccb002016-05-17 12:21:55 -0700149 bool muted;
150 acm_receive_->PlayoutData10Ms(kOutputFreqHz, &audio_frame, &muted);
151 ASSERT_FALSE(muted);
minyue@webrtc.org05617162015-03-03 12:02:30 +0000152 out_file.Write10MsData(audio_frame);
153 }
154
155 in_file.Close();
156 out_file.Close();
157
158#ifdef PRINT_STAT
Niels Möller3bdc5e92020-03-10 09:28:33 +0100159 packetization_callback_->PrintStatistics();
minyue@webrtc.org05617162015-03-03 12:02:30 +0000160#endif
161
Niels Möllerc936cb62019-03-19 14:10:16 +0100162 uint32_t stats[3];
Niels Möller3bdc5e92020-03-10 09:28:33 +0100163 packetization_callback_->GetStatistics(stats);
164 packetization_callback_->ResetStatistics();
minyue@webrtc.org05617162015-03-03 12:02:30 +0000165
henrik.lundin@webrtc.orge9217b42015-03-06 07:50:34 +0000166 for (const auto& st : stats) {
167 int i = &st - stats; // Calculate the current position in stats.
minyue@webrtc.org05617162015-03-03 12:02:30 +0000168 switch (expects[i]) {
169 case 0: {
Minyue Lic9408702020-11-03 23:22:26 +0100170 EXPECT_EQ(0u, st) << "stats[" << i << "] error.";
minyue@webrtc.org05617162015-03-03 12:02:30 +0000171 break;
172 }
173 case 1: {
Minyue Lic9408702020-11-03 23:22:26 +0100174 EXPECT_GT(st, 0u) << "stats[" << i << "] error.";
minyue@webrtc.org05617162015-03-03 12:02:30 +0000175 break;
176 }
177 }
178 }
179}
180
181// Following is the implementation of TestWebRtcVadDtx.
Karl Wiberg895ce822018-10-01 17:26:11 +0200182TestWebRtcVadDtx::TestWebRtcVadDtx() : output_file_num_(0) {}
minyue@webrtc.org05617162015-03-03 12:02:30 +0000183
184void TestWebRtcVadDtx::Perform() {
Karl Wiberg895ce822018-10-01 17:26:11 +0200185 RunTestCases({"ISAC", 16000, 1});
186 RunTestCases({"ISAC", 32000, 1});
187 RunTestCases({"ILBC", 8000, 1});
188 RunTestCases({"opus", 48000, 2});
minyue@webrtc.org05617162015-03-03 12:02:30 +0000189}
190
191// Test various configurations on VAD/DTX.
Karl Wiberg895ce822018-10-01 17:26:11 +0200192void TestWebRtcVadDtx::RunTestCases(const SdpAudioFormat& codec_format) {
193 Test(/*new_outfile=*/true,
Minyue Lic9408702020-11-03 23:22:26 +0100194 /*expect_dtx_enabled=*/RegisterCodec(codec_format, absl::nullopt));
minyue@webrtc.org05617162015-03-03 12:02:30 +0000195
Karl Wiberg895ce822018-10-01 17:26:11 +0200196 Test(/*new_outfile=*/false,
Minyue Lic9408702020-11-03 23:22:26 +0100197 /*expect_dtx_enabled=*/RegisterCodec(codec_format, Vad::kVadAggressive));
minyue@webrtc.org05617162015-03-03 12:02:30 +0000198
Karl Wiberg895ce822018-10-01 17:26:11 +0200199 Test(/*new_outfile=*/false,
Minyue Lic9408702020-11-03 23:22:26 +0100200 /*expect_dtx_enabled=*/RegisterCodec(codec_format, Vad::kVadLowBitrate));
minyue@webrtc.org05617162015-03-03 12:02:30 +0000201
Minyue Lic9408702020-11-03 23:22:26 +0100202 Test(/*new_outfile=*/false, /*expect_dtx_enabled=*/RegisterCodec(
203 codec_format, Vad::kVadVeryAggressive));
minyue@webrtc.org05617162015-03-03 12:02:30 +0000204
Karl Wiberg895ce822018-10-01 17:26:11 +0200205 Test(/*new_outfile=*/false,
Minyue Lic9408702020-11-03 23:22:26 +0100206 /*expect_dtx_enabled=*/RegisterCodec(codec_format, Vad::kVadNormal));
minyue@webrtc.org05617162015-03-03 12:02:30 +0000207}
208
209// Set the expectation and run the test.
Minyue Lic9408702020-11-03 23:22:26 +0100210void TestWebRtcVadDtx::Test(bool new_outfile, bool expect_dtx_enabled) {
211 int expects[] = {-1, 1, expect_dtx_enabled, 0, 0};
minyue@webrtc.org05617162015-03-03 12:02:30 +0000212 if (new_outfile) {
213 output_file_num_++;
214 }
Jonas Olsson366a50c2018-09-06 13:41:30 +0200215 rtc::StringBuilder out_filename;
Yves Gerey665174f2018-06-19 15:03:05 +0200216 out_filename << webrtc::test::OutputPath() << "testWebRtcVadDtx_outFile_"
217 << output_file_num_ << ".pcm";
218 Run(webrtc::test::ResourcePath("audio_coding/testfile32kHz", "pcm"), 32000, 1,
219 out_filename.str(), !new_outfile, expects);
minyue@webrtc.org05617162015-03-03 12:02:30 +0000220}
221
minyue@webrtc.org05617162015-03-03 12:02:30 +0000222// Following is the implementation of TestOpusDtx.
223void TestOpusDtx::Perform() {
Minyue Lic9408702020-11-03 23:22:26 +0100224 int expects[] = {0, 1, 0, 0, 0};
minyue@webrtc.org05617162015-03-03 12:02:30 +0000225
226 // Register Opus as send codec
Yves Gerey665174f2018-06-19 15:03:05 +0200227 std::string out_filename =
228 webrtc::test::OutputPath() + "testOpusDtx_outFile_mono.pcm";
Karl Wiberg895ce822018-10-01 17:26:11 +0200229 RegisterCodec({"opus", 48000, 2}, absl::nullopt);
Niels Möllerb90d38a2019-08-07 12:40:40 +0200230 acm_send_->ModifyEncoder([](std::unique_ptr<AudioEncoder>* encoder_ptr) {
231 (*encoder_ptr)->SetDtx(false);
232 });
minyue@webrtc.org05617162015-03-03 12:02:30 +0000233
Yves Gerey665174f2018-06-19 15:03:05 +0200234 Run(webrtc::test::ResourcePath("audio_coding/testfile32kHz", "pcm"), 32000, 1,
235 out_filename, false, expects);
minyue@webrtc.org05617162015-03-03 12:02:30 +0000236
Niels Möllerb90d38a2019-08-07 12:40:40 +0200237 acm_send_->ModifyEncoder([](std::unique_ptr<AudioEncoder>* encoder_ptr) {
238 (*encoder_ptr)->SetDtx(true);
239 });
Niels Möller8f7ce222019-03-21 15:43:58 +0100240 expects[static_cast<int>(AudioFrameType::kEmptyFrame)] = 1;
241 expects[static_cast<int>(AudioFrameType::kAudioFrameCN)] = 1;
Yves Gerey665174f2018-06-19 15:03:05 +0200242 Run(webrtc::test::ResourcePath("audio_coding/testfile32kHz", "pcm"), 32000, 1,
243 out_filename, true, expects);
minyue@webrtc.org05617162015-03-03 12:02:30 +0000244
245 // Register stereo Opus as send codec
246 out_filename = webrtc::test::OutputPath() + "testOpusDtx_outFile_stereo.pcm";
Karl Wiberg895ce822018-10-01 17:26:11 +0200247 RegisterCodec({"opus", 48000, 2, {{"stereo", "1"}}}, absl::nullopt);
Niels Möllerb90d38a2019-08-07 12:40:40 +0200248 acm_send_->ModifyEncoder([](std::unique_ptr<AudioEncoder>* encoder_ptr) {
249 (*encoder_ptr)->SetDtx(false);
250 });
Niels Möller8f7ce222019-03-21 15:43:58 +0100251 expects[static_cast<int>(AudioFrameType::kEmptyFrame)] = 0;
252 expects[static_cast<int>(AudioFrameType::kAudioFrameCN)] = 0;
Yves Gerey665174f2018-06-19 15:03:05 +0200253 Run(webrtc::test::ResourcePath("audio_coding/teststereo32kHz", "pcm"), 32000,
254 2, out_filename, false, expects);
minyue@webrtc.org05617162015-03-03 12:02:30 +0000255
Niels Möllerb90d38a2019-08-07 12:40:40 +0200256 acm_send_->ModifyEncoder([](std::unique_ptr<AudioEncoder>* encoder_ptr) {
257 (*encoder_ptr)->SetDtx(true);
Philipp Hanckefc4668d2020-07-16 17:22:03 +0200258 // The default bitrate will not generate frames recognized as CN on desktop
259 // since the frames will be encoded as CELT. Set a low target bitrate to get
260 // consistent behaviour across platforms.
261 (*encoder_ptr)->OnReceivedTargetAudioBitrate(24000);
Niels Möllerb90d38a2019-08-07 12:40:40 +0200262 });
minyue@webrtc.org05617162015-03-03 12:02:30 +0000263
Niels Möller8f7ce222019-03-21 15:43:58 +0100264 expects[static_cast<int>(AudioFrameType::kEmptyFrame)] = 1;
265 expects[static_cast<int>(AudioFrameType::kAudioFrameCN)] = 1;
Yves Gerey665174f2018-06-19 15:03:05 +0200266 Run(webrtc::test::ResourcePath("audio_coding/teststereo32kHz", "pcm"), 32000,
267 2, out_filename, true, expects);
tina.legrand@webrtc.orgd5726a12013-05-03 07:34:12 +0000268}
269
270} // namespace webrtc