webrtc/modules/audio_processing/aec3/frame_blocker_unittest.cc
Jonas Olsson 84df1c724e Make fewer copies when using StringBuilder.
Replace calls to .str() which copies with .Release which moves in cases where that's safe.

This CL was generated by this command:
git grep -l 'StringBuilder' |
xargs perl -i -0 -pe "s/(rtc::StringBuilder (\S+);.*?return )\\g2.str\(\)/\$1\$2.Release\(\)/sg"

Bug: webrtc:8982
Change-Id: If4dadbeb039df010aaaa9e58da81c1971a84fe8f
Reviewed-on: https://webrtc-review.googlesource.com/100307
Commit-Queue: Jonas Olsson <jonasolsson@webrtc.org>
Reviewed-by: Karl Wiberg <kwiberg@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#24790}
2018-09-24 09:39:19 +00:00

341 lines
13 KiB
C++

/*
* 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 "modules/audio_processing/aec3/frame_blocker.h"
#include <string>
#include <vector>
#include "modules/audio_processing/aec3/aec3_common.h"
#include "modules/audio_processing/aec3/block_framer.h"
#include "rtc_base/strings/string_builder.h"
#include "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) {
rtc::StringBuilder ss;
ss << "Sample rate: " << sample_rate_hz;
return ss.Release();
}
} // 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) {
rtc::StringBuilder 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