Revert "[ACM] iSAC audio codec removed"
This reverts commit b46c4bf27ba5c417fcba7f200d80fa4634e7e1a1. Reason for revert: breaks a downstream project Original change's description: > [ACM] iSAC audio codec removed > > Note: this CL has to leave behind one part of iSAC, which is its VAD > currently used by AGC1 in APM. The target visibility has been > restricted and the VAD will be removed together with AGC1 when the > time comes. > > Tested: see https://chromium-review.googlesource.com/c/chromium/src/+/4013319 > > Bug: webrtc:14450 > Change-Id: I69cc518b16280eae62a1f1977cdbfa24c08cf5f9 > Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/282421 > Reviewed-by: Henrik Lundin <henrik.lundin@webrtc.org> > Reviewed-by: Sam Zackrisson <saza@webrtc.org> > Reviewed-by: Henrik Boström <hbos@webrtc.org> > Commit-Queue: Alessio Bazzica <alessiob@webrtc.org> > Cr-Commit-Position: refs/heads/main@{#38652} Bug: webrtc:14450 Change-Id: Ice138004e84e8c5f896684e8d01133d4b2a77bb7 No-Presubmit: true No-Tree-Checks: true No-Try: true Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/283800 Reviewed-by: Alessio Bazzica <alessiob@webrtc.org> Commit-Queue: Mirko Bonadei <mbonadei@webrtc.org> Auto-Submit: Alessio Bazzica <alessiob@webrtc.org> Reviewed-by: Mirko Bonadei <mbonadei@webrtc.org> Owners-Override: Mirko Bonadei <mbonadei@webrtc.org> Bot-Commit: rubber-stamper@appspot.gserviceaccount.com <rubber-stamper@appspot.gserviceaccount.com> Cr-Commit-Position: refs/heads/main@{#38655}
This commit is contained in:
committed by
WebRTC LUCI CQ
parent
cb2b133bf0
commit
fbeb76ab51
@ -30,6 +30,7 @@
|
||||
#include "modules/audio_coding/codecs/cng/audio_encoder_cng.h"
|
||||
#include "modules/audio_coding/codecs/g711/audio_decoder_pcm.h"
|
||||
#include "modules/audio_coding/codecs/g711/audio_encoder_pcm.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/include/audio_encoder_isac.h"
|
||||
#include "modules/audio_coding/include/audio_coding_module_typedefs.h"
|
||||
#include "modules/audio_coding/neteq/tools/audio_checksum.h"
|
||||
#include "modules/audio_coding/neteq/tools/audio_loop.h"
|
||||
@ -301,6 +302,44 @@ TEST_F(AudioCodingModuleTestOldApi, TransportCallbackIsInvokedForEachPacket) {
|
||||
EXPECT_EQ(AudioFrameType::kAudioFrameSpeech, packet_cb_.last_frame_type());
|
||||
}
|
||||
|
||||
#if defined(WEBRTC_CODEC_ISAC) || defined(WEBRTC_CODEC_ISACFX)
|
||||
// Verifies that the RTP timestamp series is not reset when the codec is
|
||||
// changed.
|
||||
TEST_F(AudioCodingModuleTestOldApi, TimestampSeriesContinuesWhenCodecChanges) {
|
||||
RegisterCodec(); // This registers the default codec.
|
||||
uint32_t expected_ts = input_frame_.timestamp_;
|
||||
int blocks_per_packet = pac_size_ / (kSampleRateHz / 100);
|
||||
// Encode 5 packets of the first codec type.
|
||||
const int kNumPackets1 = 5;
|
||||
for (int j = 0; j < kNumPackets1; ++j) {
|
||||
for (int i = 0; i < blocks_per_packet; ++i) {
|
||||
EXPECT_EQ(j, packet_cb_.num_calls());
|
||||
InsertAudio();
|
||||
}
|
||||
EXPECT_EQ(j + 1, packet_cb_.num_calls());
|
||||
EXPECT_EQ(expected_ts, packet_cb_.last_timestamp());
|
||||
expected_ts += pac_size_;
|
||||
}
|
||||
|
||||
// Change codec.
|
||||
audio_format_ = SdpAudioFormat("ISAC", kSampleRateHz, 1);
|
||||
pac_size_ = 480;
|
||||
RegisterCodec();
|
||||
blocks_per_packet = pac_size_ / (kSampleRateHz / 100);
|
||||
// Encode another 5 packets.
|
||||
const int kNumPackets2 = 5;
|
||||
for (int j = 0; j < kNumPackets2; ++j) {
|
||||
for (int i = 0; i < blocks_per_packet; ++i) {
|
||||
EXPECT_EQ(kNumPackets1 + j, packet_cb_.num_calls());
|
||||
InsertAudio();
|
||||
}
|
||||
EXPECT_EQ(kNumPackets1 + j + 1, packet_cb_.num_calls());
|
||||
EXPECT_EQ(expected_ts, packet_cb_.last_timestamp());
|
||||
expected_ts += pac_size_;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Introduce this class to set different expectations on the number of encoded
|
||||
// bytes. This class expects all encoded packets to be 9 bytes (matching one
|
||||
// CNG SID frame) or 0 bytes. This test depends on `input_frame_` containing
|
||||
@ -381,7 +420,8 @@ TEST_F(AudioCodingModuleTestWithComfortNoiseOldApi,
|
||||
DoTest(k10MsBlocksPerPacket, kCngPayloadType);
|
||||
}
|
||||
|
||||
// A multi-threaded test for ACM that uses the PCM16b 16 kHz codec.
|
||||
// A multi-threaded test for ACM. This base class is using the PCM16b 16 kHz
|
||||
// codec, while the derive class AcmIsacMtTest is using iSAC.
|
||||
class AudioCodingModuleMtTestOldApi : public AudioCodingModuleTestOldApi {
|
||||
protected:
|
||||
static const int kNumPackets = 500;
|
||||
@ -520,6 +560,272 @@ TEST_F(AudioCodingModuleMtTestOldApi, MAYBE_DoTest) {
|
||||
EXPECT_TRUE(RunTest());
|
||||
}
|
||||
|
||||
// This is a multi-threaded ACM test using iSAC. The test encodes audio
|
||||
// from a PCM file. The most recent encoded frame is used as input to the
|
||||
// receiving part. Depending on timing, it may happen that the same RTP packet
|
||||
// is inserted into the receiver multiple times, but this is a valid use-case,
|
||||
// and simplifies the test code a lot.
|
||||
class AcmIsacMtTestOldApi : public AudioCodingModuleMtTestOldApi {
|
||||
protected:
|
||||
static const int kNumPackets = 500;
|
||||
static const int kNumPullCalls = 500;
|
||||
|
||||
AcmIsacMtTestOldApi()
|
||||
: AudioCodingModuleMtTestOldApi(), last_packet_number_(0) {}
|
||||
|
||||
~AcmIsacMtTestOldApi() {}
|
||||
|
||||
void SetUp() override {
|
||||
AudioCodingModuleTestOldApi::SetUp();
|
||||
RegisterCodec(); // Must be called before the threads start below.
|
||||
|
||||
// Set up input audio source to read from specified file, loop after 5
|
||||
// seconds, and deliver blocks of 10 ms.
|
||||
const std::string input_file_name =
|
||||
webrtc::test::ResourcePath("audio_coding/speech_mono_16kHz", "pcm");
|
||||
audio_loop_.Init(input_file_name, 5 * kSampleRateHz, kNumSamples10ms);
|
||||
|
||||
// Generate one packet to have something to insert.
|
||||
int loop_counter = 0;
|
||||
while (packet_cb_.last_payload_len_bytes() == 0) {
|
||||
InsertAudio();
|
||||
ASSERT_LT(loop_counter++, 10);
|
||||
}
|
||||
// Set `last_packet_number_` to one less that `num_calls` so that the packet
|
||||
// will be fetched in the next InsertPacket() call.
|
||||
last_packet_number_ = packet_cb_.num_calls() - 1;
|
||||
|
||||
StartThreads();
|
||||
}
|
||||
|
||||
void RegisterCodec() override {
|
||||
static_assert(kSampleRateHz == 16000, "test designed for iSAC 16 kHz");
|
||||
audio_format_ = SdpAudioFormat("isac", kSampleRateHz, 1);
|
||||
pac_size_ = 480;
|
||||
|
||||
// Register iSAC codec in ACM, effectively unregistering the PCM16B codec
|
||||
// registered in AudioCodingModuleTestOldApi::SetUp();
|
||||
acm_->SetReceiveCodecs({{kPayloadType, *audio_format_}});
|
||||
acm_->SetEncoder(CreateBuiltinAudioEncoderFactory()->MakeAudioEncoder(
|
||||
kPayloadType, *audio_format_, absl::nullopt));
|
||||
}
|
||||
|
||||
void InsertPacket() override {
|
||||
int num_calls = packet_cb_.num_calls(); // Store locally for thread safety.
|
||||
if (num_calls > last_packet_number_) {
|
||||
// Get the new payload out from the callback handler.
|
||||
// Note that since we swap buffers here instead of directly inserting
|
||||
// a pointer to the data in `packet_cb_`, we avoid locking the callback
|
||||
// for the duration of the IncomingPacket() call.
|
||||
packet_cb_.SwapBuffers(&last_payload_vec_);
|
||||
ASSERT_GT(last_payload_vec_.size(), 0u);
|
||||
rtp_utility_->Forward(&rtp_header_);
|
||||
last_packet_number_ = num_calls;
|
||||
}
|
||||
ASSERT_GT(last_payload_vec_.size(), 0u);
|
||||
ASSERT_EQ(0, acm_->IncomingPacket(&last_payload_vec_[0],
|
||||
last_payload_vec_.size(), rtp_header_));
|
||||
}
|
||||
|
||||
void InsertAudio() override {
|
||||
// TODO(kwiberg): Use std::copy here. Might be complications because AFAICS
|
||||
// this call confuses the number of samples with the number of bytes, and
|
||||
// ends up copying only half of what it should.
|
||||
memcpy(input_frame_.mutable_data(), audio_loop_.GetNextBlock().data(),
|
||||
kNumSamples10ms);
|
||||
AudioCodingModuleTestOldApi::InsertAudio();
|
||||
}
|
||||
|
||||
// Override the verification function with no-op, since iSAC produces variable
|
||||
// payload sizes.
|
||||
void VerifyEncoding() override {}
|
||||
|
||||
// This method is the same as AudioCodingModuleMtTestOldApi::TestDone(), but
|
||||
// here it is using the constants defined in this class (i.e., shorter test
|
||||
// run).
|
||||
bool TestDone() override {
|
||||
if (packet_cb_.num_calls() > kNumPackets) {
|
||||
MutexLock lock(&mutex_);
|
||||
if (pull_audio_count_ > kNumPullCalls) {
|
||||
// Both conditions for completion are met. End the test.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int last_packet_number_;
|
||||
std::vector<uint8_t> last_payload_vec_;
|
||||
test::AudioLoop audio_loop_;
|
||||
};
|
||||
|
||||
#if defined(WEBRTC_IOS)
|
||||
#define MAYBE_DoTest DISABLED_DoTest
|
||||
#else
|
||||
#define MAYBE_DoTest DoTest
|
||||
#endif
|
||||
#if defined(WEBRTC_CODEC_ISAC) || defined(WEBRTC_CODEC_ISACFX)
|
||||
TEST_F(AcmIsacMtTestOldApi, MAYBE_DoTest) {
|
||||
EXPECT_TRUE(RunTest());
|
||||
}
|
||||
#endif
|
||||
|
||||
class AcmReRegisterIsacMtTestOldApi : public AudioCodingModuleTestOldApi {
|
||||
protected:
|
||||
static const int kRegisterAfterNumPackets = 5;
|
||||
static const int kNumPackets = 10;
|
||||
static const int kPacketSizeMs = 30;
|
||||
static const int kPacketSizeSamples = kPacketSizeMs * 16;
|
||||
|
||||
AcmReRegisterIsacMtTestOldApi()
|
||||
: AudioCodingModuleTestOldApi(),
|
||||
codec_registered_(false),
|
||||
receive_packet_count_(0),
|
||||
next_insert_packet_time_ms_(0),
|
||||
fake_clock_(new SimulatedClock(0)) {
|
||||
AudioEncoderIsacFloatImpl::Config config;
|
||||
config.payload_type = kPayloadType;
|
||||
isac_encoder_.reset(new AudioEncoderIsacFloatImpl(config));
|
||||
clock_ = fake_clock_.get();
|
||||
}
|
||||
|
||||
void SetUp() override {
|
||||
AudioCodingModuleTestOldApi::SetUp();
|
||||
// Set up input audio source to read from specified file, loop after 5
|
||||
// seconds, and deliver blocks of 10 ms.
|
||||
const std::string input_file_name =
|
||||
webrtc::test::ResourcePath("audio_coding/speech_mono_16kHz", "pcm");
|
||||
audio_loop_.Init(input_file_name, 5 * kSampleRateHz, kNumSamples10ms);
|
||||
RegisterCodec(); // Must be called before the threads start below.
|
||||
StartThreads();
|
||||
}
|
||||
|
||||
void RegisterCodec() override {
|
||||
// Register iSAC codec in ACM, effectively unregistering the PCM16B codec
|
||||
// registered in AudioCodingModuleTestOldApi::SetUp();
|
||||
// Only register the decoder for now. The encoder is registered later.
|
||||
static_assert(kSampleRateHz == 16000, "test designed for iSAC 16 kHz");
|
||||
acm_->SetReceiveCodecs({{kPayloadType, {"ISAC", kSampleRateHz, 1}}});
|
||||
}
|
||||
|
||||
void StartThreads() {
|
||||
quit_.store(false);
|
||||
const auto attributes =
|
||||
rtc::ThreadAttributes().SetPriority(rtc::ThreadPriority::kRealtime);
|
||||
receive_thread_ = rtc::PlatformThread::SpawnJoinable(
|
||||
[this] {
|
||||
while (!quit_.load() && CbReceiveImpl()) {
|
||||
}
|
||||
},
|
||||
"receive", attributes);
|
||||
codec_registration_thread_ = rtc::PlatformThread::SpawnJoinable(
|
||||
[this] {
|
||||
while (!quit_.load()) {
|
||||
CbCodecRegistrationImpl();
|
||||
}
|
||||
},
|
||||
"codec_registration", attributes);
|
||||
}
|
||||
|
||||
void TearDown() override {
|
||||
AudioCodingModuleTestOldApi::TearDown();
|
||||
quit_.store(true);
|
||||
receive_thread_.Finalize();
|
||||
codec_registration_thread_.Finalize();
|
||||
}
|
||||
|
||||
bool RunTest() { return test_complete_.Wait(TimeDelta::Minutes(10)); }
|
||||
|
||||
bool CbReceiveImpl() {
|
||||
SleepMs(1);
|
||||
rtc::Buffer encoded;
|
||||
AudioEncoder::EncodedInfo info;
|
||||
{
|
||||
MutexLock lock(&mutex_);
|
||||
if (clock_->TimeInMilliseconds() < next_insert_packet_time_ms_) {
|
||||
return true;
|
||||
}
|
||||
next_insert_packet_time_ms_ += kPacketSizeMs;
|
||||
++receive_packet_count_;
|
||||
|
||||
// Encode new frame.
|
||||
uint32_t input_timestamp = rtp_header_.timestamp;
|
||||
while (info.encoded_bytes == 0) {
|
||||
info = isac_encoder_->Encode(input_timestamp,
|
||||
audio_loop_.GetNextBlock(), &encoded);
|
||||
input_timestamp += 160; // 10 ms at 16 kHz.
|
||||
}
|
||||
EXPECT_EQ(rtp_header_.timestamp + kPacketSizeSamples, input_timestamp);
|
||||
EXPECT_EQ(rtp_header_.timestamp, info.encoded_timestamp);
|
||||
EXPECT_EQ(rtp_header_.payloadType, info.payload_type);
|
||||
}
|
||||
// Now we're not holding the crit sect when calling ACM.
|
||||
|
||||
// Insert into ACM.
|
||||
EXPECT_EQ(0, acm_->IncomingPacket(encoded.data(), info.encoded_bytes,
|
||||
rtp_header_));
|
||||
|
||||
// Pull audio.
|
||||
for (int i = 0; i < rtc::CheckedDivExact(kPacketSizeMs, 10); ++i) {
|
||||
AudioFrame audio_frame;
|
||||
bool muted;
|
||||
EXPECT_EQ(0, acm_->PlayoutData10Ms(-1 /* default output frequency */,
|
||||
&audio_frame, &muted));
|
||||
if (muted) {
|
||||
ADD_FAILURE();
|
||||
return false;
|
||||
}
|
||||
fake_clock_->AdvanceTimeMilliseconds(10);
|
||||
}
|
||||
rtp_utility_->Forward(&rtp_header_);
|
||||
return true;
|
||||
}
|
||||
|
||||
void CbCodecRegistrationImpl() {
|
||||
SleepMs(1);
|
||||
if (HasFatalFailure()) {
|
||||
// End the test early if a fatal failure (ASSERT_*) has occurred.
|
||||
test_complete_.Set();
|
||||
}
|
||||
MutexLock lock(&mutex_);
|
||||
if (!codec_registered_ &&
|
||||
receive_packet_count_ > kRegisterAfterNumPackets) {
|
||||
// Register the iSAC encoder.
|
||||
acm_->SetEncoder(CreateBuiltinAudioEncoderFactory()->MakeAudioEncoder(
|
||||
kPayloadType, *audio_format_, absl::nullopt));
|
||||
codec_registered_ = true;
|
||||
}
|
||||
if (codec_registered_ && receive_packet_count_ > kNumPackets) {
|
||||
test_complete_.Set();
|
||||
}
|
||||
}
|
||||
|
||||
rtc::PlatformThread receive_thread_;
|
||||
rtc::PlatformThread codec_registration_thread_;
|
||||
// Used to force worker threads to stop looping.
|
||||
std::atomic<bool> quit_;
|
||||
|
||||
rtc::Event test_complete_;
|
||||
Mutex mutex_;
|
||||
bool codec_registered_ RTC_GUARDED_BY(mutex_);
|
||||
int receive_packet_count_ RTC_GUARDED_BY(mutex_);
|
||||
int64_t next_insert_packet_time_ms_ RTC_GUARDED_BY(mutex_);
|
||||
std::unique_ptr<AudioEncoderIsacFloatImpl> isac_encoder_;
|
||||
std::unique_ptr<SimulatedClock> fake_clock_;
|
||||
test::AudioLoop audio_loop_;
|
||||
};
|
||||
|
||||
#if defined(WEBRTC_IOS)
|
||||
#define MAYBE_DoTest DISABLED_DoTest
|
||||
#else
|
||||
#define MAYBE_DoTest DoTest
|
||||
#endif
|
||||
#if defined(WEBRTC_CODEC_ISAC) || defined(WEBRTC_CODEC_ISACFX)
|
||||
TEST_F(AcmReRegisterIsacMtTestOldApi, MAYBE_DoTest) {
|
||||
EXPECT_TRUE(RunTest());
|
||||
}
|
||||
#endif
|
||||
|
||||
// Disabling all of these tests on iOS until file support has been added.
|
||||
// See https://code.google.com/p/webrtc/issues/detail?id=4752 for details.
|
||||
#if !defined(WEBRTC_IOS)
|
||||
@ -719,6 +1025,38 @@ class AcmSenderBitExactnessOldApi : public ::testing::Test,
|
||||
|
||||
class AcmSenderBitExactnessNewApi : public AcmSenderBitExactnessOldApi {};
|
||||
|
||||
// Run bit exactness tests only for release builds.
|
||||
#if (defined(WEBRTC_CODEC_ISAC) || defined(WEBRTC_CODEC_ISACFX)) && \
|
||||
defined(NDEBUG) && defined(WEBRTC_LINUX) && defined(WEBRTC_ARCH_X86_64)
|
||||
TEST_F(AcmSenderBitExactnessOldApi, IsacWb30ms) {
|
||||
ASSERT_NO_FATAL_FAILURE(SetUpTest("ISAC", 16000, 1, 103, 480, 480));
|
||||
Run(/*audio_checksum_ref=*/"37ecdabad1698a857cf811e6d1fa91df",
|
||||
/*payload_checksum_ref=*/"3c79f16f34218271f3dca4e2b1dfe1bb",
|
||||
/*expected_packets=*/33,
|
||||
/*expected_channels=*/test::AcmReceiveTestOldApi::kMonoOutput);
|
||||
}
|
||||
|
||||
TEST_F(AcmSenderBitExactnessOldApi, IsacWb60ms) {
|
||||
ASSERT_NO_FATAL_FAILURE(SetUpTest("ISAC", 16000, 1, 103, 960, 960));
|
||||
Run(/*audio_checksum_ref=*/"0e9078d23454901496a88362ba0740c3",
|
||||
/*payload_checksum_ref=*/"9e0a0ab743ad987b55b8e14802769c56",
|
||||
/*expected_packets=*/16,
|
||||
/*expected_channels=*/test::AcmReceiveTestOldApi::kMonoOutput);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Run bit exactness test only for release build.
|
||||
#if defined(WEBRTC_CODEC_ISAC) && defined(NDEBUG) && defined(WEBRTC_LINUX) && \
|
||||
defined(WEBRTC_ARCH_X86_64)
|
||||
TEST_F(AcmSenderBitExactnessOldApi, IsacSwb30ms) {
|
||||
ASSERT_NO_FATAL_FAILURE(SetUpTest("ISAC", 32000, 1, 104, 960, 960));
|
||||
Run(/*audio_checksum_ref=*/"f4cf577f28a0dcbac33358b757518e0c",
|
||||
/*payload_checksum_ref=*/"ce86106a93419aefb063097108ec94ab",
|
||||
/*expected_packets=*/33,
|
||||
/*expected_channels=*/test::AcmReceiveTestOldApi::kMonoOutput);
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST_F(AcmSenderBitExactnessOldApi, Pcm16_8000khz_10ms) {
|
||||
ASSERT_NO_FATAL_FAILURE(SetUpTest("L16", 8000, 1, 107, 80, 80));
|
||||
Run(/*audio_checksum_ref=*/"69118ed438ac76252d023e0463819471",
|
||||
|
||||
Reference in New Issue
Block a user