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:
alessiob 2017-04-10 00:53:53 -07:00 committed by Commit bot
parent 2042c16be0
commit 36e6a8f1bd
9 changed files with 115 additions and 120 deletions

View File

@ -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",

View File

@ -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

View File

@ -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;

View File

@ -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_;

View File

@ -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";

View File

@ -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

View File

@ -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_

View File

@ -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;

View File

@ -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