webrtc_m130/modules/audio_processing/aec3/frame_blocker_unittest.cc

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

342 lines
13 KiB
C++
Raw Normal View History

Reland of Added first layer of the echo canceller 3 functionality. Reason for reland: Added disabling of the BlockProcessor DEATH tests due to false alarms on the trybots. These errors cannot be reproduced locally and they occur only in the DEATH test code, which means that the memory leaks do not occur under normal conditions. Original issue's description: > Reason for revert: > Memcheck buildbot detected memory leaks in the death tests. The code looks fine > to me, but please investigate what causes the error and reland. > > Original issue's description: > > Added first layer of the echo canceller 3 functionality. > > > > This CL adds the first layer of the echo canceller 3. > > All of the code is as it should, apart from > > block_processor.* which only contains placeholder > > functionality. (Upcoming CLs will add proper > > functionality into those files.) > > > > > > > > BUG=webrtc:6018 > > > > Review-Url: https://codereview.webrtc.org/2584493002 > > Cr-Commit-Position: refs/heads/master@{#15861} > > Committed: > https://chromium.googlesource.com/external/webrtc/+/38fd1758e90bcdc7690a552e7ef0ec0d143d2f30 > > TBR=ivoc@webrtc.org,aleloi@webrtc.org,henrik.lundin@webrtc.org,peah@webrtc.org > # Skipping CQ checks because original CL landed less than 1 days ago. > NOPRESUBMIT=true > NOTREECHECKS=true > NOTRY=true > BUG=webrtc:6018 BUG=webrtc:6018 TBR=ivoc@webrtc.org,aleloi@webrtc.org,henrik.lundin@webrtc.org Review-Url: https://codereview.webrtc.org/2608233002 Cr-Commit-Position: refs/heads/master@{#15884}
2017-01-03 04:20:34 -08:00
/*
* Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
*
* 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.
*/
#include "webrtc/modules/audio_processing/aec3/frame_blocker.h"
#include <sstream>
#include <string>
#include <vector>
#include "webrtc/modules/audio_processing/aec3/aec3_common.h"
Reland of Added first layer of the echo canceller 3 functionality. Reason for reland: Added disabling of the BlockProcessor DEATH tests due to false alarms on the trybots. These errors cannot be reproduced locally and they occur only in the DEATH test code, which means that the memory leaks do not occur under normal conditions. Original issue's description: > Reason for revert: > Memcheck buildbot detected memory leaks in the death tests. The code looks fine > to me, but please investigate what causes the error and reland. > > Original issue's description: > > Added first layer of the echo canceller 3 functionality. > > > > This CL adds the first layer of the echo canceller 3. > > All of the code is as it should, apart from > > block_processor.* which only contains placeholder > > functionality. (Upcoming CLs will add proper > > functionality into those files.) > > > > > > > > BUG=webrtc:6018 > > > > Review-Url: https://codereview.webrtc.org/2584493002 > > Cr-Commit-Position: refs/heads/master@{#15861} > > Committed: > https://chromium.googlesource.com/external/webrtc/+/38fd1758e90bcdc7690a552e7ef0ec0d143d2f30 > > TBR=ivoc@webrtc.org,aleloi@webrtc.org,henrik.lundin@webrtc.org,peah@webrtc.org > # Skipping CQ checks because original CL landed less than 1 days ago. > NOPRESUBMIT=true > NOTREECHECKS=true > NOTRY=true > BUG=webrtc:6018 BUG=webrtc:6018 TBR=ivoc@webrtc.org,aleloi@webrtc.org,henrik.lundin@webrtc.org Review-Url: https://codereview.webrtc.org/2608233002 Cr-Commit-Position: refs/heads/master@{#15884}
2017-01-03 04:20:34 -08:00
#include "webrtc/modules/audio_processing/aec3/block_framer.h"
#include "webrtc/test/gtest.h"
namespace webrtc {
namespace {
float ComputeSampleValue(size_t chunk_counter,
size_t chunk_size,
size_t band,
size_t sample_index,
int offset) {
float value =
static_cast<int>(chunk_counter * chunk_size + sample_index) + offset;
return value > 0 ? 5000 * band + value : 0;
}
void FillSubFrame(size_t sub_frame_counter,
int offset,
std::vector<std::vector<float>>* sub_frame) {
for (size_t k = 0; k < sub_frame->size(); ++k) {
for (size_t i = 0; i < (*sub_frame)[0].size(); ++i) {
(*sub_frame)[k][i] =
ComputeSampleValue(sub_frame_counter, kSubFrameLength, k, i, offset);
}
}
}
void FillSubFrameView(size_t sub_frame_counter,
int offset,
std::vector<std::vector<float>>* sub_frame,
std::vector<rtc::ArrayView<float>>* sub_frame_view) {
FillSubFrame(sub_frame_counter, offset, sub_frame);
for (size_t k = 0; k < sub_frame_view->size(); ++k) {
(*sub_frame_view)[k] =
rtc::ArrayView<float>(&(*sub_frame)[k][0], (*sub_frame)[k].size());
}
}
bool VerifySubFrame(size_t sub_frame_counter,
int offset,
const std::vector<rtc::ArrayView<float>>& sub_frame_view) {
std::vector<std::vector<float>> reference_sub_frame(
sub_frame_view.size(), std::vector<float>(sub_frame_view[0].size(), 0.f));
FillSubFrame(sub_frame_counter, offset, &reference_sub_frame);
for (size_t k = 0; k < sub_frame_view.size(); ++k) {
for (size_t i = 0; i < sub_frame_view[k].size(); ++i) {
if (reference_sub_frame[k][i] != sub_frame_view[k][i]) {
return false;
}
}
}
return true;
}
bool VerifyBlock(size_t block_counter,
int offset,
const std::vector<std::vector<float>>& block) {
for (size_t k = 0; k < block.size(); ++k) {
for (size_t i = 0; i < block[k].size(); ++i) {
const float reference_value =
ComputeSampleValue(block_counter, kBlockSize, k, i, offset);
if (reference_value != block[k][i]) {
return false;
}
}
}
return true;
}
// Verifies that the FrameBlocker properly forms blocks out of the frames.
void RunBlockerTest(int sample_rate_hz) {
constexpr size_t kNumSubFramesToProcess = 20;
const size_t num_bands = NumBandsForRate(sample_rate_hz);
std::vector<std::vector<float>> block(num_bands,
std::vector<float>(kBlockSize, 0.f));
std::vector<std::vector<float>> input_sub_frame(
num_bands, std::vector<float>(kSubFrameLength, 0.f));
std::vector<rtc::ArrayView<float>> input_sub_frame_view(num_bands);
FrameBlocker blocker(num_bands);
size_t block_counter = 0;
for (size_t sub_frame_index = 0; sub_frame_index < kNumSubFramesToProcess;
++sub_frame_index) {
FillSubFrameView(sub_frame_index, 0, &input_sub_frame,
&input_sub_frame_view);
blocker.InsertSubFrameAndExtractBlock(input_sub_frame_view, &block);
VerifyBlock(block_counter++, 0, block);
if ((sub_frame_index + 1) % 4 == 0) {
EXPECT_TRUE(blocker.IsBlockAvailable());
} else {
EXPECT_FALSE(blocker.IsBlockAvailable());
}
if (blocker.IsBlockAvailable()) {
blocker.ExtractBlock(&block);
VerifyBlock(block_counter++, 0, block);
}
}
}
// Verifies that the FrameBlocker and BlockFramer work well together and produce
// the expected output.
void RunBlockerAndFramerTest(int sample_rate_hz) {
const size_t kNumSubFramesToProcess = 20;
const size_t num_bands = NumBandsForRate(sample_rate_hz);
std::vector<std::vector<float>> block(num_bands,
std::vector<float>(kBlockSize, 0.f));
std::vector<std::vector<float>> input_sub_frame(
num_bands, std::vector<float>(kSubFrameLength, 0.f));
std::vector<std::vector<float>> output_sub_frame(
num_bands, std::vector<float>(kSubFrameLength, 0.f));
std::vector<rtc::ArrayView<float>> output_sub_frame_view(num_bands);
std::vector<rtc::ArrayView<float>> input_sub_frame_view(num_bands);
FrameBlocker blocker(num_bands);
BlockFramer framer(num_bands);
for (size_t sub_frame_index = 0; sub_frame_index < kNumSubFramesToProcess;
++sub_frame_index) {
FillSubFrameView(sub_frame_index, 0, &input_sub_frame,
&input_sub_frame_view);
FillSubFrameView(sub_frame_index, 0, &output_sub_frame,
&output_sub_frame_view);
blocker.InsertSubFrameAndExtractBlock(input_sub_frame_view, &block);
framer.InsertBlockAndExtractSubFrame(block, &output_sub_frame_view);
if ((sub_frame_index + 1) % 4 == 0) {
EXPECT_TRUE(blocker.IsBlockAvailable());
} else {
EXPECT_FALSE(blocker.IsBlockAvailable());
}
if (blocker.IsBlockAvailable()) {
blocker.ExtractBlock(&block);
framer.InsertBlock(block);
}
EXPECT_TRUE(VerifySubFrame(sub_frame_index, -64, output_sub_frame_view));
}
}
#if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
// Verifies that the FrameBlocker crashes if the InsertSubFrameAndExtractBlock
// method is called for inputs with the wrong number of bands or band lengths.
void RunWronglySizedInsertAndExtractParametersTest(int sample_rate_hz,
size_t num_block_bands,
size_t block_length,
size_t num_sub_frame_bands,
size_t sub_frame_length) {
const size_t correct_num_bands = NumBandsForRate(sample_rate_hz);
std::vector<std::vector<float>> block(num_block_bands,
std::vector<float>(block_length, 0.f));
std::vector<std::vector<float>> input_sub_frame(
num_sub_frame_bands, std::vector<float>(sub_frame_length, 0.f));
std::vector<rtc::ArrayView<float>> input_sub_frame_view(
input_sub_frame.size());
FillSubFrameView(0, 0, &input_sub_frame, &input_sub_frame_view);
FrameBlocker blocker(correct_num_bands);
EXPECT_DEATH(
blocker.InsertSubFrameAndExtractBlock(input_sub_frame_view, &block), "");
}
// Verifies that the FrameBlocker crashes if the ExtractBlock method is called
// for inputs with the wrong number of bands or band lengths.
void RunWronglySizedExtractParameterTest(int sample_rate_hz,
size_t num_block_bands,
size_t block_length) {
const size_t correct_num_bands = NumBandsForRate(sample_rate_hz);
std::vector<std::vector<float>> correct_block(
correct_num_bands, std::vector<float>(kBlockSize, 0.f));
std::vector<std::vector<float>> wrong_block(
num_block_bands, std::vector<float>(block_length, 0.f));
std::vector<std::vector<float>> input_sub_frame(
correct_num_bands, std::vector<float>(kSubFrameLength, 0.f));
std::vector<rtc::ArrayView<float>> input_sub_frame_view(
input_sub_frame.size());
FillSubFrameView(0, 0, &input_sub_frame, &input_sub_frame_view);
FrameBlocker blocker(correct_num_bands);
blocker.InsertSubFrameAndExtractBlock(input_sub_frame_view, &correct_block);
blocker.InsertSubFrameAndExtractBlock(input_sub_frame_view, &correct_block);
blocker.InsertSubFrameAndExtractBlock(input_sub_frame_view, &correct_block);
blocker.InsertSubFrameAndExtractBlock(input_sub_frame_view, &correct_block);
EXPECT_DEATH(blocker.ExtractBlock(&wrong_block), "");
}
// Verifies that the FrameBlocker crashes if the ExtractBlock method is called
// after a wrong number of previous InsertSubFrameAndExtractBlock method calls
// have been made.
void RunWrongExtractOrderTest(int sample_rate_hz,
size_t num_preceeding_api_calls) {
const size_t correct_num_bands = NumBandsForRate(sample_rate_hz);
std::vector<std::vector<float>> block(correct_num_bands,
std::vector<float>(kBlockSize, 0.f));
std::vector<std::vector<float>> input_sub_frame(
correct_num_bands, std::vector<float>(kSubFrameLength, 0.f));
std::vector<rtc::ArrayView<float>> input_sub_frame_view(
input_sub_frame.size());
FillSubFrameView(0, 0, &input_sub_frame, &input_sub_frame_view);
FrameBlocker blocker(correct_num_bands);
for (size_t k = 0; k < num_preceeding_api_calls; ++k) {
blocker.InsertSubFrameAndExtractBlock(input_sub_frame_view, &block);
}
EXPECT_DEATH(blocker.ExtractBlock(&block), "");
}
#endif
std::string ProduceDebugText(int sample_rate_hz) {
std::ostringstream ss;
ss << "Sample rate: " << sample_rate_hz;
return ss.str();
}
} // namespace
#if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
TEST(FrameBlocker, WrongNumberOfBandsInBlockForInsertSubFrameAndExtractBlock) {
for (auto rate : {8000, 16000, 32000, 48000}) {
SCOPED_TRACE(ProduceDebugText(rate));
const size_t correct_num_bands = NumBandsForRate(rate);
const size_t wrong_num_bands = (correct_num_bands % 3) + 1;
RunWronglySizedInsertAndExtractParametersTest(
rate, wrong_num_bands, kBlockSize, correct_num_bands, kSubFrameLength);
}
}
TEST(FrameBlocker,
WrongNumberOfBandsInSubFrameForInsertSubFrameAndExtractBlock) {
for (auto rate : {8000, 16000, 32000, 48000}) {
SCOPED_TRACE(ProduceDebugText(rate));
const size_t correct_num_bands = NumBandsForRate(rate);
const size_t wrong_num_bands = (correct_num_bands % 3) + 1;
RunWronglySizedInsertAndExtractParametersTest(
rate, correct_num_bands, kBlockSize, wrong_num_bands, kSubFrameLength);
}
}
TEST(FrameBlocker,
WrongNumberOfSamplesInBlockForInsertSubFrameAndExtractBlock) {
for (auto rate : {8000, 16000, 32000, 48000}) {
SCOPED_TRACE(ProduceDebugText(rate));
const size_t correct_num_bands = NumBandsForRate(rate);
RunWronglySizedInsertAndExtractParametersTest(
rate, correct_num_bands, kBlockSize - 1, correct_num_bands,
kSubFrameLength);
}
}
TEST(FrameBlocker,
WrongNumberOfSamplesInSubFrameForInsertSubFrameAndExtractBlock) {
for (auto rate : {8000, 16000, 32000, 48000}) {
SCOPED_TRACE(ProduceDebugText(rate));
const size_t correct_num_bands = NumBandsForRate(rate);
RunWronglySizedInsertAndExtractParametersTest(rate, correct_num_bands,
kBlockSize, correct_num_bands,
kSubFrameLength - 1);
}
}
TEST(FrameBlocker, WrongNumberOfBandsInBlockForExtractBlock) {
for (auto rate : {8000, 16000, 32000, 48000}) {
SCOPED_TRACE(ProduceDebugText(rate));
const size_t correct_num_bands = NumBandsForRate(rate);
const size_t wrong_num_bands = (correct_num_bands % 3) + 1;
RunWronglySizedExtractParameterTest(rate, wrong_num_bands, kBlockSize);
}
}
TEST(FrameBlocker, WrongNumberOfSamplesInBlockForExtractBlock) {
for (auto rate : {8000, 16000, 32000, 48000}) {
SCOPED_TRACE(ProduceDebugText(rate));
const size_t correct_num_bands = NumBandsForRate(rate);
RunWronglySizedExtractParameterTest(rate, correct_num_bands,
kBlockSize - 1);
}
}
TEST(FrameBlocker, WrongNumberOfPreceedingApiCallsForExtractBlock) {
for (auto rate : {8000, 16000, 32000, 48000}) {
for (size_t num_calls = 0; num_calls < 4; ++num_calls) {
std::ostringstream ss;
ss << "Sample rate: " << rate;
ss << ", Num preceeding InsertSubFrameAndExtractBlock calls: "
<< num_calls;
SCOPED_TRACE(ss.str());
RunWrongExtractOrderTest(rate, num_calls);
}
}
}
// Verifiers that the verification for null sub_frame pointer works.
TEST(FrameBlocker, NullBlockParameter) {
std::vector<std::vector<float>> sub_frame(
1, std::vector<float>(kSubFrameLength, 0.f));
std::vector<rtc::ArrayView<float>> sub_frame_view(sub_frame.size());
FillSubFrameView(0, 0, &sub_frame, &sub_frame_view);
EXPECT_DEATH(
FrameBlocker(1).InsertSubFrameAndExtractBlock(sub_frame_view, nullptr),
"");
}
#endif
TEST(FrameBlocker, BlockBitexactness) {
for (auto rate : {8000, 16000, 32000, 48000}) {
SCOPED_TRACE(ProduceDebugText(rate));
RunBlockerTest(rate);
}
}
TEST(FrameBlocker, BlockerAndFramer) {
for (auto rate : {8000, 16000, 32000, 48000}) {
SCOPED_TRACE(ProduceDebugText(rate));
RunBlockerAndFramerTest(rate);
}
}
} // namespace webrtc