WavReaderAdaptor is a simple adaptor of the existing class WavReader from webrtc/common_audio/wav_file.h. The adaptor was mainly needed to use dependency injection and easily test the MultiEndCall class (see https://codereview.webrtc.org/2761853002/).
The unit test ConversationalSpeechTest.MultiEndCallWavReaderAdaptorSine uses CreateSineWavFile() and writes temporary wav files that are used for test (deleted only if the test passes). BUG=webrtc:7218 Review-Url: https://codereview.webrtc.org/2774423005 Cr-Commit-Position: refs/heads/master@{#17608}
This commit is contained in:
parent
2042c16be0
commit
36e6a8f1bd
@ -38,8 +38,6 @@ rtc_static_library("lib") {
|
||||
"timing.cc",
|
||||
"timing.h",
|
||||
"wavreader_abstract_factory.h",
|
||||
"wavreader_adaptor.cc",
|
||||
"wavreader_adaptor.h",
|
||||
"wavreader_factory.cc",
|
||||
"wavreader_factory.h",
|
||||
"wavreader_interface.h",
|
||||
@ -65,6 +63,7 @@ rtc_source_set("unittest") {
|
||||
":lib",
|
||||
"../../../../../webrtc:webrtc_common",
|
||||
"../../../../../webrtc/base:rtc_base_approved",
|
||||
"../../../../../webrtc/common_audio",
|
||||
"../../../../../webrtc/test:test_support",
|
||||
"//testing/gmock",
|
||||
"//testing/gtest",
|
||||
|
||||
@ -33,15 +33,22 @@
|
||||
// cases in which there are wrong offsets leading to self cross-talk (which is
|
||||
// rejected).
|
||||
|
||||
// MSVC++ requires this to be set before any other includes to get M_PI.
|
||||
#define _USE_MATH_DEFINES
|
||||
|
||||
#include <stdio.h>
|
||||
#include <cmath>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
|
||||
#include "webrtc/base/logging.h"
|
||||
#include "webrtc/base/pathutils.h"
|
||||
#include "webrtc/common_audio/wav_file.h"
|
||||
#include "webrtc/modules/audio_processing/test/conversational_speech/config.h"
|
||||
#include "webrtc/modules/audio_processing/test/conversational_speech/mock_wavreader_factory.h"
|
||||
#include "webrtc/modules/audio_processing/test/conversational_speech/multiend_call.h"
|
||||
#include "webrtc/modules/audio_processing/test/conversational_speech/timing.h"
|
||||
#include "webrtc/modules/audio_processing/test/conversational_speech/wavreader_factory.h"
|
||||
#include "webrtc/test/gmock.h"
|
||||
#include "webrtc/test/gtest.h"
|
||||
#include "webrtc/test/testsupport/fileutils.h"
|
||||
@ -55,7 +62,7 @@ using conversational_speech::SaveTiming;
|
||||
using conversational_speech::MockWavReaderFactory;
|
||||
using conversational_speech::MultiEndCall;
|
||||
using conversational_speech::Turn;
|
||||
using conversational_speech::WavReaderAbstractFactory;
|
||||
using conversational_speech::WavReaderFactory;
|
||||
|
||||
const char* const audiotracks_path = "/path/to/audiotracks";
|
||||
const char* const timing_filepath = "/path/to/timing_file.txt";
|
||||
@ -89,6 +96,23 @@ std::unique_ptr<MockWavReaderFactory> CreateMockWavReaderFactory() {
|
||||
kDefaultMockWavReaderFactoryParamsMap));
|
||||
}
|
||||
|
||||
void CreateSineWavFile(const std::string& filepath,
|
||||
const MockWavReaderFactory::Params& params,
|
||||
float frequency = 440.0f) {
|
||||
// Create samples.
|
||||
constexpr double two_pi = 2.0 * M_PI;
|
||||
std::vector<int16_t> samples(params.num_samples);
|
||||
for (std::size_t i = 0; i < params.num_samples; ++i) {
|
||||
// TODO(alessiob): the produced tone is not pure, improve.
|
||||
samples[i] = std::lround(32767.0f * std::sin(
|
||||
two_pi * i * frequency / params.sample_rate));
|
||||
}
|
||||
|
||||
// Write samples.
|
||||
WavWriter wav_writer(filepath, params.sample_rate, params.num_channels);
|
||||
wav_writer.WriteSamples(samples.data(), params.num_samples);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
using testing::_;
|
||||
@ -487,5 +511,34 @@ TEST_F(ConversationalSpeechTest, MultiEndCallSetupLongSequenceInvalid) {
|
||||
EXPECT_FALSE(multiend_call.valid());
|
||||
}
|
||||
|
||||
TEST_F(ConversationalSpeechTest, MultiEndCallWavReaderAdaptorSine) {
|
||||
// Parameters with which wav files are created.
|
||||
constexpr int duration_seconds = 5;
|
||||
const int sample_rates[] = {8000, 11025, 16000, 22050, 32000, 44100, 48000};
|
||||
|
||||
for (int sample_rate : sample_rates) {
|
||||
const rtc::Pathname temp_filename(
|
||||
OutputPath(), "TempSineWavFile_" + std::to_string(sample_rate)
|
||||
+ ".wav");
|
||||
|
||||
// Write wav file.
|
||||
const std::size_t num_samples = duration_seconds * sample_rate;
|
||||
MockWavReaderFactory::Params params = {sample_rate, 1u, num_samples};
|
||||
CreateSineWavFile(temp_filename.pathname(), params);
|
||||
LOG(LS_VERBOSE) << "wav file @" << sample_rate << " Hz created ("
|
||||
<< num_samples << " samples)";
|
||||
|
||||
// Load wav file and check if params match.
|
||||
WavReaderFactory wav_reader_factory;
|
||||
auto wav_reader = wav_reader_factory.Create(temp_filename.pathname());
|
||||
EXPECT_EQ(sample_rate, wav_reader->SampleRate());
|
||||
EXPECT_EQ(1u, wav_reader->NumChannels());
|
||||
EXPECT_EQ(num_samples, wav_reader->NumSamples());
|
||||
|
||||
// Clean up.
|
||||
remove(temp_filename.pathname().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace test
|
||||
} // namespace webrtc
|
||||
|
||||
@ -20,9 +20,9 @@ MockWavReader::MockWavReader(
|
||||
int sample_rate, size_t num_channels, size_t num_samples)
|
||||
: sample_rate_(sample_rate), num_channels_(num_channels),
|
||||
num_samples_(num_samples) {
|
||||
ON_CALL(*this, sample_rate()).WillByDefault(Return(sample_rate_));
|
||||
ON_CALL(*this, num_channels()).WillByDefault(Return(num_channels_));
|
||||
ON_CALL(*this, num_samples()).WillByDefault(Return(num_samples_));
|
||||
ON_CALL(*this, SampleRate()).WillByDefault(Return(sample_rate_));
|
||||
ON_CALL(*this, NumChannels()).WillByDefault(Return(num_channels_));
|
||||
ON_CALL(*this, NumSamples()).WillByDefault(Return(num_samples_));
|
||||
}
|
||||
|
||||
MockWavReader::~MockWavReader() = default;
|
||||
|
||||
@ -14,6 +14,7 @@
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
|
||||
#include "webrtc/base/array_view.h"
|
||||
#include "webrtc/modules/audio_processing/test/conversational_speech/wavreader_interface.h"
|
||||
#include "webrtc/test/gmock.h"
|
||||
#include "webrtc/typedefs.h"
|
||||
@ -28,12 +29,12 @@ class MockWavReader : public WavReaderInterface {
|
||||
~MockWavReader();
|
||||
|
||||
// TODO(alessiob): use ON_CALL to return random samples.
|
||||
MOCK_METHOD2(ReadFloatSamples, size_t(size_t, float*));
|
||||
MOCK_METHOD2(ReadInt16Samples, size_t(size_t, int16_t*));
|
||||
MOCK_METHOD1(ReadFloatSamples, size_t(rtc::ArrayView<float>));
|
||||
MOCK_METHOD1(ReadInt16Samples, size_t(rtc::ArrayView<int16_t>));
|
||||
|
||||
MOCK_CONST_METHOD0(sample_rate, int());
|
||||
MOCK_CONST_METHOD0(num_channels, size_t());
|
||||
MOCK_CONST_METHOD0(num_samples, size_t());
|
||||
MOCK_CONST_METHOD0(SampleRate, int());
|
||||
MOCK_CONST_METHOD0(NumChannels, size_t());
|
||||
MOCK_CONST_METHOD0(NumSamples, size_t());
|
||||
|
||||
private:
|
||||
const int sample_rate_;
|
||||
|
||||
@ -120,9 +120,9 @@ bool MultiEndCall::CheckTiming() {
|
||||
|
||||
// Begin and end timestamps for the current turn.
|
||||
int offset_samples = millisecond_to_samples(
|
||||
turn.offset, it->second->sample_rate());
|
||||
size_t begin_timestamp = last_turn.end + offset_samples;
|
||||
size_t end_timestamp = begin_timestamp + it->second->num_samples();
|
||||
turn.offset, it->second->SampleRate());
|
||||
std::size_t begin_timestamp = last_turn.end + offset_samples;
|
||||
std::size_t end_timestamp = begin_timestamp + it->second->NumSamples();
|
||||
LOG(LS_INFO) << "turn #" << turn_index << " " << begin_timestamp
|
||||
<< "-" << end_timestamp << " ms";
|
||||
|
||||
|
||||
@ -1,58 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2017 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/test/conversational_speech/wavreader_adaptor.h"
|
||||
|
||||
#include "webrtc/base/checks.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace test {
|
||||
namespace conversational_speech {
|
||||
|
||||
WavReaderAdaptor::WavReaderAdaptor(const std::string& filepath) {
|
||||
// TODO(alessiob): implement.
|
||||
}
|
||||
|
||||
WavReaderAdaptor::~WavReaderAdaptor() {}
|
||||
|
||||
size_t WavReaderAdaptor::ReadFloatSamples(size_t num_samples, float* samples) {
|
||||
// TODO(alessiob): implement.
|
||||
FATAL();
|
||||
return 0u;
|
||||
}
|
||||
|
||||
size_t WavReaderAdaptor::ReadInt16Samples(
|
||||
size_t num_samples, int16_t* samples) {
|
||||
// TODO(alessiob): implement.
|
||||
FATAL();
|
||||
return 0u;
|
||||
}
|
||||
|
||||
int WavReaderAdaptor::sample_rate() const {
|
||||
// TODO(alessiob): implement.
|
||||
FATAL();
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t WavReaderAdaptor::num_channels() const {
|
||||
// TODO(alessiob): implement.
|
||||
FATAL();
|
||||
return 0u;
|
||||
}
|
||||
|
||||
size_t WavReaderAdaptor::num_samples() const {
|
||||
// TODO(alessiob): implement.
|
||||
FATAL();
|
||||
return 0u;
|
||||
}
|
||||
|
||||
} // namespace conversational_speech
|
||||
} // namespace test
|
||||
} // namespace webrtc
|
||||
@ -1,42 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2017 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.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_TEST_CONVERSATIONAL_SPEECH_WAVREADER_ADAPTOR_H_
|
||||
#define WEBRTC_MODULES_AUDIO_PROCESSING_TEST_CONVERSATIONAL_SPEECH_WAVREADER_ADAPTOR_H_
|
||||
|
||||
#include "webrtc/modules/audio_processing/test/conversational_speech/wavreader_interface.h"
|
||||
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
|
||||
#include "webrtc/typedefs.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace test {
|
||||
namespace conversational_speech {
|
||||
|
||||
class WavReaderAdaptor : public WavReaderInterface {
|
||||
public:
|
||||
explicit WavReaderAdaptor(const std::string& filepath);
|
||||
~WavReaderAdaptor() override;
|
||||
|
||||
size_t ReadFloatSamples(size_t num_samples, float* samples) override;
|
||||
size_t ReadInt16Samples(size_t num_samples, int16_t* samples) override;
|
||||
|
||||
int sample_rate() const override;
|
||||
size_t num_channels() const override;
|
||||
size_t num_samples() const override;
|
||||
};
|
||||
|
||||
} // namespace conversational_speech
|
||||
} // namespace test
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // WEBRTC_MODULES_AUDIO_PROCESSING_TEST_CONVERSATIONAL_SPEECH_WAVREADER_ADAPTOR_H_
|
||||
@ -10,10 +10,51 @@
|
||||
|
||||
#include "webrtc/modules/audio_processing/test/conversational_speech/wavreader_factory.h"
|
||||
|
||||
#include "webrtc/modules/audio_processing/test/conversational_speech/wavreader_adaptor.h"
|
||||
#include <cstddef>
|
||||
|
||||
#include "webrtc/base/array_view.h"
|
||||
#include "webrtc/base/checks.h"
|
||||
#include "webrtc/common_audio/wav_file.h"
|
||||
#include "webrtc/typedefs.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace test {
|
||||
namespace {
|
||||
|
||||
using conversational_speech::WavReaderInterface;
|
||||
|
||||
class WavReaderAdaptor final : public WavReaderInterface {
|
||||
public:
|
||||
explicit WavReaderAdaptor(const std::string& filepath)
|
||||
: wav_reader_(filepath) {}
|
||||
~WavReaderAdaptor() override = default;
|
||||
|
||||
size_t ReadFloatSamples(rtc::ArrayView<float> samples) override {
|
||||
return wav_reader_.ReadSamples(samples.size(), samples.begin());
|
||||
}
|
||||
|
||||
size_t ReadInt16Samples(rtc::ArrayView<int16_t> samples) override {
|
||||
return wav_reader_.ReadSamples(samples.size(), samples.begin());
|
||||
}
|
||||
|
||||
int SampleRate() const override {
|
||||
return wav_reader_.sample_rate();
|
||||
}
|
||||
|
||||
size_t NumChannels() const override {
|
||||
return wav_reader_.num_channels();
|
||||
}
|
||||
|
||||
size_t NumSamples() const override {
|
||||
return wav_reader_.num_samples();
|
||||
}
|
||||
|
||||
private:
|
||||
WavReader wav_reader_;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace conversational_speech {
|
||||
|
||||
WavReaderFactory::WavReaderFactory() = default;
|
||||
|
||||
@ -13,6 +13,7 @@
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "webrtc/base/array_view.h"
|
||||
#include "webrtc/typedefs.h"
|
||||
|
||||
namespace webrtc {
|
||||
@ -24,13 +25,13 @@ class WavReaderInterface {
|
||||
virtual ~WavReaderInterface() = default;
|
||||
|
||||
// Returns the number of samples read.
|
||||
virtual size_t ReadFloatSamples(size_t num_samples, float* samples) = 0;
|
||||
virtual size_t ReadInt16Samples(size_t num_samples, int16_t* samples) = 0;
|
||||
virtual size_t ReadFloatSamples(rtc::ArrayView<float> samples) = 0;
|
||||
virtual size_t ReadInt16Samples(rtc::ArrayView<int16_t> samples) = 0;
|
||||
|
||||
// Getters.
|
||||
virtual int sample_rate() const = 0;
|
||||
virtual size_t num_channels() const = 0;
|
||||
virtual size_t num_samples() const = 0;
|
||||
virtual int SampleRate() const = 0;
|
||||
virtual size_t NumChannels() const = 0;
|
||||
virtual size_t NumSamples() const = 0;
|
||||
};
|
||||
|
||||
} // namespace conversational_speech
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user