Modify NetEqQualityTest

- Take input sample rate as parameter - provides resampling when needed.
- Add support for wav output.

BUG=2692
R=minyue@webrtc.org

Review URL: https://webrtc-codereview.appspot.com/49699004

Cr-Commit-Position: refs/heads/master@{#9158}
This commit is contained in:
Henrik Lundin 2015-05-08 10:33:57 +02:00
parent cb05b72eb2
commit 83b5c053b9
8 changed files with 130 additions and 105 deletions

View File

@ -81,7 +81,7 @@ class NetEq {
background_noise_mode(kBgnOff), background_noise_mode(kBgnOff),
playout_mode(kPlayoutOn) {} playout_mode(kPlayoutOn) {}
int sample_rate_hz; // Initial vale. Will change with input data. int sample_rate_hz; // Initial value. Will change with input data.
bool enable_audio_classifier; bool enable_audio_classifier;
int max_packets_in_buffer; int max_packets_in_buffer;
int max_delay_ms; int max_delay_ms;

View File

@ -10,7 +10,6 @@
#include "webrtc/modules/audio_coding/codecs/isac/fix/interface/isacfix.h" #include "webrtc/modules/audio_coding/codecs/isac/fix/interface/isacfix.h"
#include "webrtc/modules/audio_coding/neteq/tools/neteq_quality_test.h" #include "webrtc/modules/audio_coding/neteq/tools/neteq_quality_test.h"
#include "webrtc/test/testsupport/fileutils.h"
using google::RegisterFlagValidator; using google::RegisterFlagValidator;
using google::ParseCommandLineFlags; using google::ParseCommandLineFlags;
@ -19,47 +18,12 @@ using testing::InitGoogleTest;
namespace webrtc { namespace webrtc {
namespace test { namespace test {
namespace {
static const int kIsacBlockDurationMs = 30; static const int kIsacBlockDurationMs = 30;
static const int kIsacInputSamplingKhz = 16; static const int kIsacInputSamplingKhz = 16;
static const int kIsacOutputSamplingKhz = 16; static const int kIsacOutputSamplingKhz = 16;
// Define switch for input file name. // Define switch for bit rate.
static bool ValidateInFilename(const char* flagname, const string& value) {
FILE* fid = fopen(value.c_str(), "rb");
if (fid != NULL) {
fclose(fid);
return true;
}
printf("Invalid input filename.");
return false;
}
DEFINE_string(in_filename,
ResourcePath("audio_coding/speech_mono_16kHz", "pcm"),
"Filename for input audio (should be 16 kHz sampled mono).");
static const bool in_filename_dummy =
RegisterFlagValidator(&FLAGS_in_filename, &ValidateInFilename);
// Define switch for output file name.
static bool ValidateOutFilename(const char* flagname, const string& value) {
FILE* fid = fopen(value.c_str(), "wb");
if (fid != NULL) {
fclose(fid);
return true;
}
printf("Invalid output filename.");
return false;
}
DEFINE_string(out_filename, OutputPath() + "neteq4_isac_quality_test.pcm",
"Name of output audio file.");
static const bool out_filename_dummy =
RegisterFlagValidator(&FLAGS_out_filename, &ValidateOutFilename);
// Define switch for bir rate.
static bool ValidateBitRate(const char* flagname, int32_t value) { static bool ValidateBitRate(const char* flagname, int32_t value) {
if (value >= 10 && value <= 32) if (value >= 10 && value <= 32)
return true; return true;
@ -85,6 +49,8 @@ DEFINE_int32(runtime_ms, 10000, "Simulated runtime (milliseconds).");
static const bool runtime_dummy = static const bool runtime_dummy =
RegisterFlagValidator(&FLAGS_runtime_ms, &ValidateRuntime); RegisterFlagValidator(&FLAGS_runtime_ms, &ValidateRuntime);
} // namespace
class NetEqIsacQualityTest : public NetEqQualityTest { class NetEqIsacQualityTest : public NetEqQualityTest {
protected: protected:
NetEqIsacQualityTest(); NetEqIsacQualityTest();
@ -98,12 +64,11 @@ class NetEqIsacQualityTest : public NetEqQualityTest {
}; };
NetEqIsacQualityTest::NetEqIsacQualityTest() NetEqIsacQualityTest::NetEqIsacQualityTest()
: NetEqQualityTest(kIsacBlockDurationMs, kIsacInputSamplingKhz, : NetEqQualityTest(kIsacBlockDurationMs,
kIsacInputSamplingKhz,
kIsacOutputSamplingKhz, kIsacOutputSamplingKhz,
kDecoderISAC, kDecoderISAC,
1, 1),
FLAGS_in_filename,
FLAGS_out_filename),
isac_encoder_(NULL), isac_encoder_(NULL),
bit_rate_kbps_(FLAGS_bit_rate_kbps) { bit_rate_kbps_(FLAGS_bit_rate_kbps) {
} }

View File

@ -11,7 +11,6 @@
#include "webrtc/modules/audio_coding/codecs/opus/interface/opus_interface.h" #include "webrtc/modules/audio_coding/codecs/opus/interface/opus_interface.h"
#include "webrtc/modules/audio_coding/codecs/opus/opus_inst.h" #include "webrtc/modules/audio_coding/codecs/opus/opus_inst.h"
#include "webrtc/modules/audio_coding/neteq/tools/neteq_quality_test.h" #include "webrtc/modules/audio_coding/neteq/tools/neteq_quality_test.h"
#include "webrtc/test/testsupport/fileutils.h"
using google::RegisterFlagValidator; using google::RegisterFlagValidator;
using google::ParseCommandLineFlags; using google::ParseCommandLineFlags;
@ -20,44 +19,25 @@ using testing::InitGoogleTest;
namespace webrtc { namespace webrtc {
namespace test { namespace test {
namespace {
static const int kOpusBlockDurationMs = 20; static const int kOpusBlockDurationMs = 20;
static const int kOpusSamplingKhz = 48; static const int kOpusSamplingKhz = 48;
// Define switch for input file name. // Define switch for sample rate.
static bool ValidateInFilename(const char* flagname, const string& value) { static bool ValidateSampleRate(const char* flagname, int32_t value) {
FILE* fid = fopen(value.c_str(), "rb"); if (value == 8000 || value == 16000 || value == 32000 || value == 48000)
if (fid != NULL) {
fclose(fid);
return true; return true;
} printf("Invalid sample rate should be 8000, 16000, 32000 or 48000 Hz.");
printf("Invalid input filename.");
return false; return false;
} }
DEFINE_string(in_filename, DEFINE_int32(input_sample_rate,
ResourcePath("audio_coding/speech_mono_32_48kHz", "pcm"), kOpusSamplingKhz * 1000,
"Filename for input audio (should be 48 kHz sampled raw data)."); "Sample rate of input file.");
static const bool in_filename_dummy = static const bool sample_rate_dummy =
RegisterFlagValidator(&FLAGS_in_filename, &ValidateInFilename); RegisterFlagValidator(&FLAGS_input_sample_rate, &ValidateSampleRate);
// Define switch for output file name.
static bool ValidateOutFilename(const char* flagname, const string& value) {
FILE* fid = fopen(value.c_str(), "wb");
if (fid != NULL) {
fclose(fid);
return true;
}
printf("Invalid output filename.");
return false;
}
DEFINE_string(out_filename, OutputPath() + "neteq_opus_quality_test.pcm",
"Name of output audio file.");
static const bool out_filename_dummy =
RegisterFlagValidator(&FLAGS_out_filename, &ValidateOutFilename);
// Define switch for channels. // Define switch for channels.
static bool ValidateChannels(const char* flagname, int32_t value) { static bool ValidateChannels(const char* flagname, int32_t value) {
@ -125,6 +105,8 @@ DEFINE_int32(sub_packets, 1, "Number of sub packets to repacketize.");
static const bool sub_packets_dummy = static const bool sub_packets_dummy =
RegisterFlagValidator(&FLAGS_sub_packets, &ValidateSubPackets); RegisterFlagValidator(&FLAGS_sub_packets, &ValidateSubPackets);
} // namepsace
class NetEqOpusQualityTest : public NetEqQualityTest { class NetEqOpusQualityTest : public NetEqQualityTest {
protected: protected:
NetEqOpusQualityTest(); NetEqOpusQualityTest();
@ -149,9 +131,7 @@ NetEqOpusQualityTest::NetEqOpusQualityTest()
kOpusSamplingKhz, kOpusSamplingKhz,
kOpusSamplingKhz, kOpusSamplingKhz,
(FLAGS_channels == 1) ? kDecoderOpus : kDecoderOpus_2ch, (FLAGS_channels == 1) ? kDecoderOpus : kDecoderOpus_2ch,
FLAGS_channels, FLAGS_channels),
FLAGS_in_filename,
FLAGS_out_filename),
opus_encoder_(NULL), opus_encoder_(NULL),
repacketizer_(NULL), repacketizer_(NULL),
sub_block_size_samples_(kOpusBlockDurationMs * kOpusSamplingKhz), sub_block_size_samples_(kOpusBlockDurationMs * kOpusSamplingKhz),

View File

@ -32,7 +32,7 @@ class InputAudioFile {
// if the read was successful, otherwise false. If the file end is reached, // if the read was successful, otherwise false. If the file end is reached,
// the file is rewound and reading continues from the beginning. // the file is rewound and reading continues from the beginning.
// The output |destination| must have the capacity to hold |samples| elements. // The output |destination| must have the capacity to hold |samples| elements.
bool Read(size_t samples, int16_t* destination); virtual bool Read(size_t samples, int16_t* destination);
// Creates a multi-channel signal from a mono signal. Each sample is repeated // Creates a multi-channel signal from a mono signal. Each sample is repeated
// |channels| times to create an interleaved multi-channel signal where all // |channels| times to create an interleaved multi-channel signal where all

View File

@ -10,7 +10,14 @@
#include <math.h> #include <math.h>
#include <stdio.h> #include <stdio.h>
#include "webrtc/base/checks.h"
#include "webrtc/modules/audio_coding/neteq/tools/neteq_quality_test.h" #include "webrtc/modules/audio_coding/neteq/tools/neteq_quality_test.h"
#include "webrtc/modules/audio_coding/neteq/tools/output_audio_file.h"
#include "webrtc/modules/audio_coding/neteq/tools/output_wav_file.h"
#include "webrtc/modules/audio_coding/neteq/tools/resample_input_audio_file.h"
#include "webrtc/test/testsupport/fileutils.h"
using std::string;
namespace webrtc { namespace webrtc {
namespace test { namespace test {
@ -20,6 +27,61 @@ const int kOutputSizeMs = 10;
const int kInitSeed = 0x12345678; const int kInitSeed = 0x12345678;
const int kPacketLossTimeUnitMs = 10; const int kPacketLossTimeUnitMs = 10;
// Common validator for file names.
static bool ValidateFilename(const string& value, bool write) {
FILE* fid = write ? fopen(value.c_str(), "wb") : fopen(value.c_str(), "rb");
if (fid == nullptr)
return false;
fclose(fid);
return true;
}
// Define switch for input file name.
static bool ValidateInFilename(const char* flagname, const string& value) {
if (!ValidateFilename(value, false)) {
printf("Invalid input filename.");
return false;
}
return true;
}
DEFINE_string(
in_filename,
ResourcePath("audio_coding/speech_mono_16kHz", "pcm"),
"Filename for input audio (specify sample rate with --input_sample_rate).");
static const bool in_filename_dummy =
RegisterFlagValidator(&FLAGS_in_filename, &ValidateInFilename);
// Define switch for sample rate.
static bool ValidateSampleRate(const char* flagname, int32_t value) {
if (value == 8000 || value == 16000 || value == 32000 || value == 48000)
return true;
printf("Invalid sample rate should be 8000, 16000, 32000 or 48000 Hz.");
return false;
}
DEFINE_int32(input_sample_rate, 16000, "Sample rate of input file in Hz.");
static const bool sample_rate_dummy =
RegisterFlagValidator(&FLAGS_input_sample_rate, &ValidateSampleRate);
// Define switch for output file name.
static bool ValidateOutFilename(const char* flagname, const string& value) {
if (!ValidateFilename(value, true)) {
printf("Invalid output filename.");
return false;
}
return true;
}
DEFINE_string(out_filename,
OutputPath() + "neteq_quality_test_out.pcm",
"Name of output audio file.");
static const bool out_filename_dummy =
RegisterFlagValidator(&FLAGS_out_filename, &ValidateOutFilename);
// Define switch for packet loss rate. // Define switch for packet loss rate.
static bool ValidatePacketLossRate(const char* /* flag_name */, int32_t value) { static bool ValidatePacketLossRate(const char* /* flag_name */, int32_t value) {
if (value >= 0 && value <= 100) if (value >= 0 && value <= 100)
@ -120,9 +182,7 @@ NetEqQualityTest::NetEqQualityTest(int block_duration_ms,
int in_sampling_khz, int in_sampling_khz,
int out_sampling_khz, int out_sampling_khz,
enum NetEqDecoder decoder_type, enum NetEqDecoder decoder_type,
int channels, int channels)
std::string in_filename,
std::string out_filename)
: decoded_time_ms_(0), : decoded_time_ms_(0),
decodable_time_ms_(0), decodable_time_ms_(0),
drift_factor_(FLAGS_drift_factor), drift_factor_(FLAGS_drift_factor),
@ -132,19 +192,32 @@ NetEqQualityTest::NetEqQualityTest(int block_duration_ms,
out_sampling_khz_(out_sampling_khz), out_sampling_khz_(out_sampling_khz),
decoder_type_(decoder_type), decoder_type_(decoder_type),
channels_(channels), channels_(channels),
in_filename_(in_filename),
out_filename_(out_filename),
log_filename_(out_filename + ".log"),
in_size_samples_(in_sampling_khz_ * block_duration_ms_), in_size_samples_(in_sampling_khz_ * block_duration_ms_),
out_size_samples_(out_sampling_khz_ * kOutputSizeMs), out_size_samples_(out_sampling_khz_ * kOutputSizeMs),
payload_size_bytes_(0), payload_size_bytes_(0),
max_payload_bytes_(0), max_payload_bytes_(0),
in_file_(new InputAudioFile(in_filename_)), in_file_(new ResampleInputAudioFile(FLAGS_in_filename,
out_file_(NULL), FLAGS_input_sample_rate,
in_sampling_khz * 1000)),
log_file_(NULL), log_file_(NULL),
rtp_generator_(new RtpGenerator(in_sampling_khz_, 0, 0, rtp_generator_(
decodable_time_ms_)), new RtpGenerator(in_sampling_khz_, 0, 0, decodable_time_ms_)),
total_payload_size_bytes_(0) { total_payload_size_bytes_(0) {
const std::string out_filename = FLAGS_out_filename;
const std::string log_filename = out_filename + ".log";
log_file_ = fopen(log_filename.c_str(), "wt");
CHECK(log_file_);
if (out_filename.size() >= 4 &&
out_filename.substr(out_filename.size() - 4) == ".wav") {
// Open a wav file.
output_.reset(
new webrtc::test::OutputWavFile(out_filename, 1000 * out_sampling_khz));
} else {
// Open a pcm file.
output_.reset(new webrtc::test::OutputAudioFile(out_filename));
}
NetEq::Config config; NetEq::Config config;
config.sample_rate_hz = out_sampling_khz_ * 1000; config.sample_rate_hz = out_sampling_khz_ * 1000;
neteq_.reset(NetEq::Create(config)); neteq_.reset(NetEq::Create(config));
@ -189,9 +262,6 @@ bool GilbertElliotLoss::Lost() {
} }
void NetEqQualityTest::SetUp() { void NetEqQualityTest::SetUp() {
out_file_ = fopen(out_filename_.c_str(), "wb");
log_file_ = fopen(log_filename_.c_str(), "wt");
ASSERT_TRUE(out_file_ != NULL);
ASSERT_EQ(0, neteq_->RegisterPayloadType(decoder_type_, kPayloadType)); ASSERT_EQ(0, neteq_->RegisterPayloadType(decoder_type_, kPayloadType));
rtp_generator_->set_drift_factor(drift_factor_); rtp_generator_->set_drift_factor(drift_factor_);
@ -245,10 +315,6 @@ void NetEqQualityTest::SetUp() {
srand(kInitSeed); srand(kInitSeed);
} }
void NetEqQualityTest::TearDown() {
fclose(out_file_);
}
bool NetEqQualityTest::PacketLost() { bool NetEqQualityTest::PacketLost() {
int cycles = block_duration_ms_ / kPacketLossTimeUnitMs; int cycles = block_duration_ms_ / kPacketLossTimeUnitMs;
@ -297,7 +363,7 @@ int NetEqQualityTest::DecodeBlock() {
} else { } else {
assert(channels == channels_); assert(channels == channels_);
assert(samples == kOutputSizeMs * out_sampling_khz_); assert(samples == kOutputSizeMs * out_sampling_khz_);
fwrite(&out_data_[0], sizeof(int16_t), samples * channels, out_file_); CHECK(output_->WriteArray(out_data_.get(), samples * channels));
return samples; return samples;
} }
} }

View File

@ -12,10 +12,10 @@
#define WEBRTC_MODULES_AUDIO_CODING_NETEQ_TOOLS_NETEQ_QUALITY_TEST_H_ #define WEBRTC_MODULES_AUDIO_CODING_NETEQ_TOOLS_NETEQ_QUALITY_TEST_H_
#include <gflags/gflags.h> #include <gflags/gflags.h>
#include <string>
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
#include "webrtc/base/scoped_ptr.h" #include "webrtc/base/scoped_ptr.h"
#include "webrtc/modules/audio_coding/neteq/interface/neteq.h" #include "webrtc/modules/audio_coding/neteq/interface/neteq.h"
#include "webrtc/modules/audio_coding/neteq/tools/audio_sink.h"
#include "webrtc/modules/audio_coding/neteq/tools/input_audio_file.h" #include "webrtc/modules/audio_coding/neteq/tools/input_audio_file.h"
#include "webrtc/modules/audio_coding/neteq/tools/rtp_generator.h" #include "webrtc/modules/audio_coding/neteq/tools/rtp_generator.h"
#include "webrtc/typedefs.h" #include "webrtc/typedefs.h"
@ -66,11 +66,8 @@ class NetEqQualityTest : public ::testing::Test {
int in_sampling_khz, int in_sampling_khz,
int out_sampling_khz, int out_sampling_khz,
enum NetEqDecoder decoder_type, enum NetEqDecoder decoder_type,
int channels, int channels);
std::string in_filename,
std::string out_filename);
void SetUp() override; void SetUp() override;
void TearDown() override;
// EncodeBlock(...) does the following: // EncodeBlock(...) does the following:
// 1. encodes a block of audio, saved in |in_data| and has a length of // 1. encodes a block of audio, saved in |in_data| and has a length of
@ -108,9 +105,6 @@ class NetEqQualityTest : public ::testing::Test {
const int out_sampling_khz_; const int out_sampling_khz_;
const enum NetEqDecoder decoder_type_; const enum NetEqDecoder decoder_type_;
const int channels_; const int channels_;
const std::string in_filename_;
const std::string out_filename_;
const std::string log_filename_;
// Number of samples per channel in a frame. // Number of samples per channel in a frame.
const int in_size_samples_; const int in_size_samples_;
@ -122,7 +116,7 @@ class NetEqQualityTest : public ::testing::Test {
int max_payload_bytes_; int max_payload_bytes_;
rtc::scoped_ptr<InputAudioFile> in_file_; rtc::scoped_ptr<InputAudioFile> in_file_;
FILE* out_file_; rtc::scoped_ptr<AudioSink> output_;
FILE* log_file_; FILE* log_file_;
rtc::scoped_ptr<RtpGenerator> rtp_generator_; rtc::scoped_ptr<RtpGenerator> rtp_generator_;

View File

@ -37,5 +37,14 @@ bool ResampleInputAudioFile::Read(size_t samples,
return true; return true;
} }
bool ResampleInputAudioFile::Read(size_t samples, int16_t* destination) {
CHECK_GT(output_rate_hz_, 0) << "Output rate not set.";
return Read(samples, output_rate_hz_, destination);
}
void ResampleInputAudioFile::set_output_rate_hz(int rate_hz) {
output_rate_hz_ = rate_hz;
}
} // namespace test } // namespace test
} // namespace webrtc } // namespace webrtc

View File

@ -25,12 +25,23 @@ namespace test {
class ResampleInputAudioFile : public InputAudioFile { class ResampleInputAudioFile : public InputAudioFile {
public: public:
ResampleInputAudioFile(const std::string file_name, int file_rate_hz) ResampleInputAudioFile(const std::string file_name, int file_rate_hz)
: InputAudioFile(file_name), file_rate_hz_(file_rate_hz) {} : InputAudioFile(file_name),
file_rate_hz_(file_rate_hz),
output_rate_hz_(-1) {}
ResampleInputAudioFile(const std::string file_name,
int file_rate_hz,
int output_rate_hz)
: InputAudioFile(file_name),
file_rate_hz_(file_rate_hz),
output_rate_hz_(output_rate_hz) {}
bool Read(size_t samples, int output_rate_hz, int16_t* destination); bool Read(size_t samples, int output_rate_hz, int16_t* destination);
bool Read(size_t samples, int16_t* destination) override;
void set_output_rate_hz(int rate_hz);
private: private:
const int file_rate_hz_; const int file_rate_hz_;
int output_rate_hz_;
Resampler resampler_; Resampler resampler_;
DISALLOW_COPY_AND_ASSIGN(ResampleInputAudioFile); DISALLOW_COPY_AND_ASSIGN(ResampleInputAudioFile);
}; };