2011-07-07 08:21:25 +00:00
|
|
|
/*
|
2012-05-02 23:56:37 +00:00
|
|
|
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
2011-07-07 08:21:25 +00:00
|
|
|
*
|
|
|
|
|
* Use of this source code is governed by a BSD-style license
|
|
|
|
|
* that can be found in the LICENSE file in the root of the source
|
|
|
|
|
* tree. An additional intellectual property rights grant can be found
|
|
|
|
|
* in the file PATENTS. All contributing project authors may
|
|
|
|
|
* be found in the AUTHORS file in the root of the source tree.
|
|
|
|
|
*/
|
|
|
|
|
|
2017-09-15 06:47:31 +02:00
|
|
|
#include "modules/audio_coding/test/TestVADDTX.h"
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2015-03-03 12:02:30 +00:00
|
|
|
#include <string>
|
2011-12-21 13:34:18 +00:00
|
|
|
|
2018-10-22 09:48:08 +02:00
|
|
|
#include "absl/strings/match.h"
|
2022-07-20 12:53:07 +02:00
|
|
|
#include "absl/strings/string_view.h"
|
2018-10-01 17:26:11 +02:00
|
|
|
#include "api/audio_codecs/audio_decoder_factory_template.h"
|
|
|
|
|
#include "api/audio_codecs/audio_encoder_factory_template.h"
|
|
|
|
|
#include "api/audio_codecs/opus/audio_decoder_opus.h"
|
|
|
|
|
#include "api/audio_codecs/opus/audio_encoder_opus.h"
|
2024-06-18 11:20:40 +02:00
|
|
|
#include "api/environment/environment_factory.h"
|
2024-09-27 07:18:06 +00:00
|
|
|
#include "api/neteq/default_neteq_factory.h"
|
2018-10-01 17:26:11 +02:00
|
|
|
#include "modules/audio_coding/codecs/cng/audio_encoder_cng.h"
|
2017-09-15 06:47:31 +02:00
|
|
|
#include "modules/audio_coding/test/PCMFile.h"
|
2018-09-06 13:41:30 +02:00
|
|
|
#include "rtc_base/strings/string_builder.h"
|
2018-12-05 10:30:25 +01:00
|
|
|
#include "test/gtest.h"
|
2019-01-11 09:11:00 -08:00
|
|
|
#include "test/testsupport/file_utils.h"
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2011-12-16 10:09:04 +00:00
|
|
|
namespace webrtc {
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2020-03-10 09:28:33 +01:00
|
|
|
MonitoringAudioPacketizationCallback::MonitoringAudioPacketizationCallback(
|
|
|
|
|
AudioPacketizationCallback* next)
|
|
|
|
|
: next_(next) {
|
2015-03-03 12:02:30 +00:00
|
|
|
ResetStatistics();
|
|
|
|
|
}
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2020-03-10 09:28:33 +01:00
|
|
|
int32_t MonitoringAudioPacketizationCallback::SendData(
|
|
|
|
|
AudioFrameType frame_type,
|
|
|
|
|
uint8_t payload_type,
|
|
|
|
|
uint32_t timestamp,
|
|
|
|
|
const uint8_t* payload_data,
|
|
|
|
|
size_t payload_len_bytes,
|
|
|
|
|
int64_t absolute_capture_timestamp_ms) {
|
2019-03-19 14:10:16 +01:00
|
|
|
counter_[static_cast<int>(frame_type)]++;
|
2020-03-10 09:28:33 +01:00
|
|
|
return next_->SendData(frame_type, payload_type, timestamp, payload_data,
|
|
|
|
|
payload_len_bytes, absolute_capture_timestamp_ms);
|
2015-03-03 12:02:30 +00:00
|
|
|
}
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2020-03-10 09:28:33 +01:00
|
|
|
void MonitoringAudioPacketizationCallback::PrintStatistics() {
|
2015-03-03 12:02:30 +00:00
|
|
|
printf("\n");
|
2019-03-19 14:10:16 +01:00
|
|
|
printf("kEmptyFrame %u\n",
|
|
|
|
|
counter_[static_cast<int>(AudioFrameType::kEmptyFrame)]);
|
|
|
|
|
printf("kAudioFrameSpeech %u\n",
|
|
|
|
|
counter_[static_cast<int>(AudioFrameType::kAudioFrameSpeech)]);
|
|
|
|
|
printf("kAudioFrameCN %u\n",
|
|
|
|
|
counter_[static_cast<int>(AudioFrameType::kAudioFrameCN)]);
|
2015-03-03 12:02:30 +00:00
|
|
|
printf("\n\n");
|
|
|
|
|
}
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2020-03-10 09:28:33 +01:00
|
|
|
void MonitoringAudioPacketizationCallback::ResetStatistics() {
|
2015-03-03 12:02:30 +00:00
|
|
|
memset(counter_, 0, sizeof(counter_));
|
|
|
|
|
}
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2020-03-10 09:28:33 +01:00
|
|
|
void MonitoringAudioPacketizationCallback::GetStatistics(uint32_t* counter) {
|
2015-03-03 12:02:30 +00:00
|
|
|
memcpy(counter, counter_, sizeof(counter_));
|
|
|
|
|
}
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2015-03-03 12:02:30 +00:00
|
|
|
TestVadDtx::TestVadDtx()
|
2024-06-18 11:20:40 +02:00
|
|
|
: env_(CreateEnvironment()),
|
2024-10-09 14:35:43 +02:00
|
|
|
encoder_factory_(CreateAudioEncoderFactory<AudioEncoderOpus>()),
|
|
|
|
|
decoder_factory_(CreateAudioDecoderFactory<AudioDecoderOpus>()),
|
2023-02-01 12:07:10 +00:00
|
|
|
acm_send_(AudioCodingModule::Create()),
|
2024-09-13 13:46:56 +00:00
|
|
|
neteq_(DefaultNetEqFactory().Create(env_,
|
|
|
|
|
NetEq::Config(),
|
|
|
|
|
decoder_factory_)),
|
2020-03-10 09:28:33 +01:00
|
|
|
channel_(std::make_unique<Channel>()),
|
|
|
|
|
packetization_callback_(
|
|
|
|
|
std::make_unique<MonitoringAudioPacketizationCallback>(
|
|
|
|
|
channel_.get())) {
|
|
|
|
|
EXPECT_EQ(
|
|
|
|
|
0, acm_send_->RegisterTransportCallback(packetization_callback_.get()));
|
2024-09-13 13:46:56 +00:00
|
|
|
channel_->RegisterReceiverNetEq(neteq_.get());
|
2015-03-03 12:02:30 +00:00
|
|
|
}
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2018-10-01 17:26:11 +02:00
|
|
|
bool TestVadDtx::RegisterCodec(const SdpAudioFormat& codec_format,
|
2024-08-29 13:00:40 +00:00
|
|
|
std::optional<Vad::Aggressiveness> vad_mode) {
|
2018-10-01 17:26:11 +02:00
|
|
|
constexpr int payload_type = 17, cn_payload_type = 117;
|
|
|
|
|
bool added_comfort_noise = false;
|
|
|
|
|
|
2024-06-18 11:20:40 +02:00
|
|
|
auto encoder = encoder_factory_->Create(env_, codec_format,
|
|
|
|
|
{.payload_type = payload_type});
|
2018-10-01 17:26:11 +02:00
|
|
|
if (vad_mode.has_value() &&
|
2018-10-22 09:48:08 +02:00
|
|
|
!absl::EqualsIgnoreCase(codec_format.name, "opus")) {
|
2018-11-01 11:13:44 +01:00
|
|
|
AudioEncoderCngConfig config;
|
2018-10-01 17:26:11 +02:00
|
|
|
config.speech_encoder = std::move(encoder);
|
|
|
|
|
config.num_channels = 1;
|
|
|
|
|
config.payload_type = cn_payload_type;
|
|
|
|
|
config.vad_mode = vad_mode.value();
|
2018-11-01 11:13:44 +01:00
|
|
|
encoder = CreateComfortNoiseEncoder(std::move(config));
|
2018-10-01 17:26:11 +02:00
|
|
|
added_comfort_noise = true;
|
|
|
|
|
}
|
|
|
|
|
channel_->SetIsStereo(encoder->NumChannels() > 1);
|
|
|
|
|
acm_send_->SetEncoder(std::move(encoder));
|
|
|
|
|
|
2018-12-05 10:30:25 +01:00
|
|
|
std::map<int, SdpAudioFormat> receive_codecs = {{payload_type, codec_format}};
|
2024-09-13 13:46:56 +00:00
|
|
|
neteq_->SetCodecs(receive_codecs);
|
2018-12-05 10:30:25 +01:00
|
|
|
|
2018-10-01 17:26:11 +02:00
|
|
|
return added_comfort_noise;
|
2015-03-03 12:02:30 +00:00
|
|
|
}
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2015-03-03 12:02:30 +00:00
|
|
|
// Encoding a file and see if the numbers that various packets occur follow
|
|
|
|
|
// the expectation.
|
2022-07-20 12:53:07 +02:00
|
|
|
void TestVadDtx::Run(absl::string_view in_filename,
|
2018-06-19 15:03:05 +02:00
|
|
|
int frequency,
|
|
|
|
|
int channels,
|
2022-07-20 12:53:07 +02:00
|
|
|
absl::string_view out_filename,
|
2018-06-19 15:03:05 +02:00
|
|
|
bool append,
|
2015-03-03 12:02:30 +00:00
|
|
|
const int* expects) {
|
2020-03-10 09:28:33 +01:00
|
|
|
packetization_callback_->ResetStatistics();
|
2015-03-03 12:02:30 +00:00
|
|
|
|
|
|
|
|
PCMFile in_file;
|
|
|
|
|
in_file.Open(in_filename, frequency, "rb");
|
|
|
|
|
in_file.ReadStereo(channels > 1);
|
2015-12-10 16:24:39 +01:00
|
|
|
// Set test length to 1000 ms (100 blocks of 10 ms each).
|
|
|
|
|
in_file.SetNum10MsBlocksToRead(100);
|
|
|
|
|
// Fast-forward both files 500 ms (50 blocks). The first second of the file is
|
|
|
|
|
// silence, but we want to keep half of that to test silence periods.
|
|
|
|
|
in_file.FastForward(50);
|
2015-03-03 12:02:30 +00:00
|
|
|
|
|
|
|
|
PCMFile out_file;
|
|
|
|
|
if (append) {
|
|
|
|
|
out_file.Open(out_filename, kOutputFreqHz, "ab");
|
|
|
|
|
} else {
|
|
|
|
|
out_file.Open(out_filename, kOutputFreqHz, "wb");
|
|
|
|
|
}
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2015-03-03 12:02:30 +00:00
|
|
|
uint16_t frame_size_samples = in_file.PayloadLength10Ms();
|
|
|
|
|
AudioFrame audio_frame;
|
|
|
|
|
while (!in_file.EndOfFile()) {
|
|
|
|
|
in_file.Read10MsData(audio_frame);
|
2016-07-06 09:34:22 -07:00
|
|
|
audio_frame.timestamp_ = time_stamp_;
|
|
|
|
|
time_stamp_ += frame_size_samples;
|
2015-03-03 12:02:30 +00:00
|
|
|
EXPECT_GE(acm_send_->Add10MsData(audio_frame), 0);
|
2016-05-17 12:21:55 -07:00
|
|
|
bool muted;
|
2024-09-13 13:46:56 +00:00
|
|
|
neteq_->GetAudio(&audio_frame, &muted);
|
|
|
|
|
resampler_helper_.MaybeResample(kOutputFreqHz, &audio_frame);
|
2016-05-17 12:21:55 -07:00
|
|
|
ASSERT_FALSE(muted);
|
2015-03-03 12:02:30 +00:00
|
|
|
out_file.Write10MsData(audio_frame);
|
|
|
|
|
}
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2015-03-03 12:02:30 +00:00
|
|
|
in_file.Close();
|
|
|
|
|
out_file.Close();
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2015-03-03 12:02:30 +00:00
|
|
|
#ifdef PRINT_STAT
|
2020-03-10 09:28:33 +01:00
|
|
|
packetization_callback_->PrintStatistics();
|
2011-07-07 08:21:25 +00:00
|
|
|
#endif
|
|
|
|
|
|
2019-03-19 14:10:16 +01:00
|
|
|
uint32_t stats[3];
|
2020-03-10 09:28:33 +01:00
|
|
|
packetization_callback_->GetStatistics(stats);
|
|
|
|
|
packetization_callback_->ResetStatistics();
|
2015-03-03 12:02:30 +00:00
|
|
|
|
2015-03-06 07:50:34 +00:00
|
|
|
for (const auto& st : stats) {
|
|
|
|
|
int i = &st - stats; // Calculate the current position in stats.
|
2015-03-03 12:02:30 +00:00
|
|
|
switch (expects[i]) {
|
|
|
|
|
case 0: {
|
2020-11-03 23:22:26 +01:00
|
|
|
EXPECT_EQ(0u, st) << "stats[" << i << "] error.";
|
2015-03-03 12:02:30 +00:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case 1: {
|
2020-11-03 23:22:26 +01:00
|
|
|
EXPECT_GT(st, 0u) << "stats[" << i << "] error.";
|
2015-03-03 12:02:30 +00:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2015-03-03 12:02:30 +00:00
|
|
|
// Following is the implementation of TestWebRtcVadDtx.
|
2018-10-01 17:26:11 +02:00
|
|
|
TestWebRtcVadDtx::TestWebRtcVadDtx() : output_file_num_(0) {}
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2015-03-03 12:02:30 +00:00
|
|
|
void TestWebRtcVadDtx::Perform() {
|
2018-10-01 17:26:11 +02:00
|
|
|
RunTestCases({"opus", 48000, 2});
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2015-03-03 12:02:30 +00:00
|
|
|
// Test various configurations on VAD/DTX.
|
2018-10-01 17:26:11 +02:00
|
|
|
void TestWebRtcVadDtx::RunTestCases(const SdpAudioFormat& codec_format) {
|
|
|
|
|
Test(/*new_outfile=*/true,
|
2024-08-29 13:00:40 +00:00
|
|
|
/*expect_dtx_enabled=*/RegisterCodec(codec_format, std::nullopt));
|
2018-10-01 17:26:11 +02:00
|
|
|
|
|
|
|
|
Test(/*new_outfile=*/false,
|
2020-11-03 23:22:26 +01:00
|
|
|
/*expect_dtx_enabled=*/RegisterCodec(codec_format, Vad::kVadAggressive));
|
2018-10-01 17:26:11 +02:00
|
|
|
|
|
|
|
|
Test(/*new_outfile=*/false,
|
2020-11-03 23:22:26 +01:00
|
|
|
/*expect_dtx_enabled=*/RegisterCodec(codec_format, Vad::kVadLowBitrate));
|
2018-10-01 17:26:11 +02:00
|
|
|
|
2020-11-03 23:22:26 +01:00
|
|
|
Test(/*new_outfile=*/false, /*expect_dtx_enabled=*/RegisterCodec(
|
|
|
|
|
codec_format, Vad::kVadVeryAggressive));
|
2018-10-01 17:26:11 +02:00
|
|
|
|
|
|
|
|
Test(/*new_outfile=*/false,
|
2020-11-03 23:22:26 +01:00
|
|
|
/*expect_dtx_enabled=*/RegisterCodec(codec_format, Vad::kVadNormal));
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
2013-05-03 07:34:12 +00:00
|
|
|
|
2015-03-03 12:02:30 +00:00
|
|
|
// Set the expectation and run the test.
|
2020-11-03 23:22:26 +01:00
|
|
|
void TestWebRtcVadDtx::Test(bool new_outfile, bool expect_dtx_enabled) {
|
|
|
|
|
int expects[] = {-1, 1, expect_dtx_enabled, 0, 0};
|
2015-03-03 12:02:30 +00:00
|
|
|
if (new_outfile) {
|
|
|
|
|
output_file_num_++;
|
2013-05-03 07:34:12 +00:00
|
|
|
}
|
2025-02-19 10:06:32 +00:00
|
|
|
StringBuilder out_filename;
|
2018-06-19 15:03:05 +02:00
|
|
|
out_filename << webrtc::test::OutputPath() << "testWebRtcVadDtx_outFile_"
|
|
|
|
|
<< output_file_num_ << ".pcm";
|
|
|
|
|
Run(webrtc::test::ResourcePath("audio_coding/testfile32kHz", "pcm"), 32000, 1,
|
|
|
|
|
out_filename.str(), !new_outfile, expects);
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2015-03-03 12:02:30 +00:00
|
|
|
// Following is the implementation of TestOpusDtx.
|
|
|
|
|
void TestOpusDtx::Perform() {
|
2020-11-03 23:22:26 +01:00
|
|
|
int expects[] = {0, 1, 0, 0, 0};
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2015-03-03 12:02:30 +00:00
|
|
|
// Register Opus as send codec
|
2018-06-19 15:03:05 +02:00
|
|
|
std::string out_filename =
|
|
|
|
|
webrtc::test::OutputPath() + "testOpusDtx_outFile_mono.pcm";
|
2024-08-29 13:00:40 +00:00
|
|
|
RegisterCodec({"opus", 48000, 2}, std::nullopt);
|
2019-08-07 12:40:40 +02:00
|
|
|
acm_send_->ModifyEncoder([](std::unique_ptr<AudioEncoder>* encoder_ptr) {
|
|
|
|
|
(*encoder_ptr)->SetDtx(false);
|
|
|
|
|
});
|
2015-03-03 12:02:30 +00:00
|
|
|
|
2018-06-19 15:03:05 +02:00
|
|
|
Run(webrtc::test::ResourcePath("audio_coding/testfile32kHz", "pcm"), 32000, 1,
|
|
|
|
|
out_filename, false, expects);
|
2015-03-03 12:02:30 +00:00
|
|
|
|
2019-08-07 12:40:40 +02:00
|
|
|
acm_send_->ModifyEncoder([](std::unique_ptr<AudioEncoder>* encoder_ptr) {
|
|
|
|
|
(*encoder_ptr)->SetDtx(true);
|
|
|
|
|
});
|
2019-03-21 15:43:58 +01:00
|
|
|
expects[static_cast<int>(AudioFrameType::kEmptyFrame)] = 1;
|
|
|
|
|
expects[static_cast<int>(AudioFrameType::kAudioFrameCN)] = 1;
|
2018-06-19 15:03:05 +02:00
|
|
|
Run(webrtc::test::ResourcePath("audio_coding/testfile32kHz", "pcm"), 32000, 1,
|
|
|
|
|
out_filename, true, expects);
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
2011-12-16 10:09:04 +00:00
|
|
|
|
2013-05-03 07:34:12 +00:00
|
|
|
} // namespace webrtc
|