Making NetEq bitexactness test independent on reference files.

NetEq bitexactness test depended on reference files which differs from platform to platform. This makes it very hard to update Neteq.

New method maintains the ability to save output into files. But it verifies the checksum only. With this, when bitexactness test fails, we can still check closely to the output file if need, but the test becomes much easier to modify.

BUG=

Review-Url: https://codereview.webrtc.org/1928923002
Cr-Commit-Position: refs/heads/master@{#12567}
This commit is contained in:
minyue
2016-04-29 11:05:14 -07:00
committed by Commit bot
parent 05e61edd8f
commit 4f90677527
15 changed files with 143 additions and 218 deletions

View File

@ -1 +0,0 @@
2cf380a05ee07080bd72471e8ec7777a39644ec9

View File

@ -1 +0,0 @@
2853ab577fe571adfc7b18f77bbe58f1253d2019

View File

@ -1 +0,0 @@
373f15261ef1dca3b61bd62d7f5e6dd085ae3eb8

View File

@ -1 +0,0 @@
dc2d9f584efb0111ebcd71a2c86f1fb09cd8c2bb

View File

@ -1 +0,0 @@
c23004d91ffbe5e7a1f24620fc89b58c0426040f

View File

@ -1 +0,0 @@
c23004d91ffbe5e7a1f24620fc89b58c0426040f

View File

@ -1 +0,0 @@
c23004d91ffbe5e7a1f24620fc89b58c0426040f

View File

@ -1 +0,0 @@
e37c797e3de6a64dda88c9ade7a013d022a2e1e0

View File

@ -1 +0,0 @@
b8880bf9fed2487efbddcb8d94b9937a29ae521d

View File

@ -1 +0,0 @@
f3f7b3d3e71d7e635240b5373b57df6a7e4ce9d4

View File

@ -1 +0,0 @@
f587883b7c371ee8d87dbf1b0f07525af7d959b8

View File

@ -1 +0,0 @@
a349bd71dba548029b05d1d2a6dc7caafab9a856

View File

@ -1 +0,0 @@
f587883b7c371ee8d87dbf1b0f07525af7d959b8

View File

@ -1 +0,0 @@
08266b198e7686b3cd9330813e0d2cd72fc8fdc2

View File

@ -22,6 +22,8 @@
#include "gflags/gflags.h" #include "gflags/gflags.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
#include "webrtc/base/sha1digest.h"
#include "webrtc/base/stringencode.h"
#include "webrtc/modules/audio_coding/neteq/tools/audio_loop.h" #include "webrtc/modules/audio_coding/neteq/tools/audio_loop.h"
#include "webrtc/modules/audio_coding/neteq/tools/rtp_file_source.h" #include "webrtc/modules/audio_coding/neteq/tools/rtp_file_source.h"
#include "webrtc/modules/audio_coding/codecs/pcm16b/pcm16b.h" #include "webrtc/modules/audio_coding/codecs/pcm16b/pcm16b.h"
@ -41,6 +43,23 @@ DEFINE_bool(gen_ref, false, "Generate reference files.");
namespace { namespace {
const std::string& PlatformChecksum(const std::string& checksum_general,
const std::string& checksum_android,
const std::string& checksum_win_32,
const std::string& checksum_win_64) {
#ifdef WEBRTC_ANDROID
return checksum_android;
#elif WEBRTC_WIN
#ifdef WEBRTC_ARCH_64_BITS
return checksum_win_64;
#else
return checksum_win_32;
#endif // WEBRTC_ARCH_64_BITS
#else
return checksum_general;
#endif // WEBRTC_WIN
}
bool IsAllZero(const int16_t* buf, size_t buf_length) { bool IsAllZero(const int16_t* buf, size_t buf_length) {
bool all_zero = true; bool all_zero = true;
for (size_t n = 0; n < buf_length && all_zero; ++n) for (size_t n = 0; n < buf_length && all_zero; ++n)
@ -85,186 +104,98 @@ void Convert(const webrtc::RtcpStatistics& stats_raw,
stats->set_jitter(stats_raw.jitter); stats->set_jitter(stats_raw.jitter);
} }
void WriteMessage(FILE* file, const std::string& message) { void AddMessage(FILE* file, rtc::MessageDigest* digest,
const std::string& message) {
int32_t size = message.length(); int32_t size = message.length();
ASSERT_EQ(1u, fwrite(&size, sizeof(size), 1, file)); if (file)
if (size <= 0) ASSERT_EQ(1u, fwrite(&size, sizeof(size), 1, file));
return; digest->Update(&size, sizeof(size));
ASSERT_EQ(static_cast<size_t>(size),
fwrite(message.data(), sizeof(char), size, file)); if (file)
ASSERT_EQ(static_cast<size_t>(size),
fwrite(message.data(), sizeof(char), size, file));
digest->Update(message.data(), sizeof(char) * size);
} }
void ReadMessage(FILE* file, std::string* message) {
int32_t size;
ASSERT_EQ(1u, fread(&size, sizeof(size), 1, file));
if (size <= 0)
return;
std::unique_ptr<char[]> buffer(new char[size]);
ASSERT_EQ(static_cast<size_t>(size),
fread(buffer.get(), sizeof(char), size, file));
message->assign(buffer.get(), size);
}
#endif // WEBRTC_NETEQ_UNITTEST_BITEXACT #endif // WEBRTC_NETEQ_UNITTEST_BITEXACT
} // namespace } // namespace
namespace webrtc { namespace webrtc {
class RefFiles { class ResultSink {
public: public:
RefFiles(const std::string& input_file, const std::string& output_file); explicit ResultSink(const std::string& output_file);
~RefFiles(); ~ResultSink();
template<class T> void ProcessReference(const T& test_results);
template<typename T, size_t n> void ProcessReference(
const T (&test_results)[n],
size_t length);
template<typename T, size_t n> void WriteToFile(
const T (&test_results)[n],
size_t length);
template<typename T, size_t n> void ReadFromFileAndCompare(
const T (&test_results)[n],
size_t length);
void WriteToFile(const NetEqNetworkStatistics& stats);
void ReadFromFileAndCompare(const NetEqNetworkStatistics& stats);
void WriteToFile(const RtcpStatistics& stats);
void ReadFromFileAndCompare(const RtcpStatistics& stats);
FILE* input_fp_; template<typename T, size_t n> void AddResult(
const T (&test_results)[n],
size_t length);
void AddResult(const NetEqNetworkStatistics& stats);
void AddResult(const RtcpStatistics& stats);
void VerifyChecksum(const std::string& ref_check_sum);
private:
FILE* output_fp_; FILE* output_fp_;
std::unique_ptr<rtc::MessageDigest> digest_;
}; };
RefFiles::RefFiles(const std::string &input_file, ResultSink::ResultSink(const std::string &output_file)
const std::string &output_file) : output_fp_(nullptr),
: input_fp_(NULL), digest_(new rtc::Sha1Digest()) {
output_fp_(NULL) {
if (!input_file.empty()) {
input_fp_ = fopen(input_file.c_str(), "rb");
EXPECT_TRUE(input_fp_ != NULL);
}
if (!output_file.empty()) { if (!output_file.empty()) {
output_fp_ = fopen(output_file.c_str(), "wb"); output_fp_ = fopen(output_file.c_str(), "wb");
EXPECT_TRUE(output_fp_ != NULL); EXPECT_TRUE(output_fp_ != NULL);
} }
} }
RefFiles::~RefFiles() { ResultSink::~ResultSink() {
if (input_fp_) { if (output_fp_)
EXPECT_EQ(EOF, fgetc(input_fp_)); // Make sure that we reached the end. fclose(output_fp_);
fclose(input_fp_);
}
if (output_fp_) fclose(output_fp_);
}
template<class T>
void RefFiles::ProcessReference(const T& test_results) {
WriteToFile(test_results);
ReadFromFileAndCompare(test_results);
} }
template<typename T, size_t n> template<typename T, size_t n>
void RefFiles::ProcessReference(const T (&test_results)[n], size_t length) { void ResultSink::AddResult(const T (&test_results)[n], size_t length) {
WriteToFile(test_results, length);
ReadFromFileAndCompare(test_results, length);
}
template<typename T, size_t n>
void RefFiles::WriteToFile(const T (&test_results)[n], size_t length) {
if (output_fp_) { if (output_fp_) {
ASSERT_EQ(length, fwrite(&test_results, sizeof(T), length, output_fp_)); ASSERT_EQ(length, fwrite(&test_results, sizeof(T), length, output_fp_));
} }
digest_->Update(&test_results, sizeof(T) * length);
} }
template<typename T, size_t n> void ResultSink::AddResult(const NetEqNetworkStatistics& stats_raw) {
void RefFiles::ReadFromFileAndCompare(const T (&test_results)[n],
size_t length) {
if (input_fp_) {
// Read from ref file.
T* ref = new T[length];
ASSERT_EQ(length, fread(ref, sizeof(T), length, input_fp_));
// Compare
ASSERT_EQ(0, memcmp(&test_results, ref, sizeof(T) * length));
delete [] ref;
}
}
void RefFiles::WriteToFile(const NetEqNetworkStatistics& stats_raw) {
#ifdef WEBRTC_NETEQ_UNITTEST_BITEXACT #ifdef WEBRTC_NETEQ_UNITTEST_BITEXACT
if (!output_fp_)
return;
neteq_unittest::NetEqNetworkStatistics stats; neteq_unittest::NetEqNetworkStatistics stats;
Convert(stats_raw, &stats); Convert(stats_raw, &stats);
std::string stats_string; std::string stats_string;
ASSERT_TRUE(stats.SerializeToString(&stats_string)); ASSERT_TRUE(stats.SerializeToString(&stats_string));
WriteMessage(output_fp_, stats_string); AddMessage(output_fp_, digest_.get(), stats_string);
#else #else
FAIL() << "Writing to reference file requires Proto Buffer."; FAIL() << "Writing to reference file requires Proto Buffer.";
#endif // WEBRTC_NETEQ_UNITTEST_BITEXACT #endif // WEBRTC_NETEQ_UNITTEST_BITEXACT
} }
void RefFiles::ReadFromFileAndCompare( void ResultSink::AddResult(const RtcpStatistics& stats_raw) {
const NetEqNetworkStatistics& stats) {
#ifdef WEBRTC_NETEQ_UNITTEST_BITEXACT #ifdef WEBRTC_NETEQ_UNITTEST_BITEXACT
if (!input_fp_)
return;
std::string stats_string;
ReadMessage(input_fp_, &stats_string);
neteq_unittest::NetEqNetworkStatistics ref_stats;
ASSERT_TRUE(ref_stats.ParseFromString(stats_string));
// Compare
ASSERT_EQ(stats.current_buffer_size_ms, ref_stats.current_buffer_size_ms());
ASSERT_EQ(stats.preferred_buffer_size_ms,
ref_stats.preferred_buffer_size_ms());
ASSERT_EQ(stats.jitter_peaks_found, ref_stats.jitter_peaks_found());
ASSERT_EQ(stats.packet_loss_rate, ref_stats.packet_loss_rate());
ASSERT_EQ(stats.packet_discard_rate, ref_stats.packet_discard_rate());
ASSERT_EQ(stats.expand_rate, ref_stats.expand_rate());
ASSERT_EQ(stats.preemptive_rate, ref_stats.preemptive_rate());
ASSERT_EQ(stats.accelerate_rate, ref_stats.accelerate_rate());
ASSERT_EQ(stats.clockdrift_ppm, ref_stats.clockdrift_ppm());
ASSERT_EQ(stats.added_zero_samples, ref_stats.added_zero_samples());
ASSERT_EQ(stats.secondary_decoded_rate, ref_stats.secondary_decoded_rate());
ASSERT_LE(stats.speech_expand_rate, ref_stats.expand_rate());
#else
FAIL() << "Reading from reference file requires Proto Buffer.";
#endif // WEBRTC_NETEQ_UNITTEST_BITEXACT
}
void RefFiles::WriteToFile(const RtcpStatistics& stats_raw) {
#ifdef WEBRTC_NETEQ_UNITTEST_BITEXACT
if (!output_fp_)
return;
neteq_unittest::RtcpStatistics stats; neteq_unittest::RtcpStatistics stats;
Convert(stats_raw, &stats); Convert(stats_raw, &stats);
std::string stats_string; std::string stats_string;
ASSERT_TRUE(stats.SerializeToString(&stats_string)); ASSERT_TRUE(stats.SerializeToString(&stats_string));
WriteMessage(output_fp_, stats_string); AddMessage(output_fp_, digest_.get(), stats_string);
#else #else
FAIL() << "Writing to reference file requires Proto Buffer."; FAIL() << "Writing to reference file requires Proto Buffer.";
#endif // WEBRTC_NETEQ_UNITTEST_BITEXACT #endif // WEBRTC_NETEQ_UNITTEST_BITEXACT
} }
void RefFiles::ReadFromFileAndCompare(const RtcpStatistics& stats) { void ResultSink::VerifyChecksum(const std::string& checksum) {
#ifdef WEBRTC_NETEQ_UNITTEST_BITEXACT std::vector<char> buffer;
if (!input_fp_) buffer.resize(digest_->Size());
return; digest_->Finish(&buffer[0], buffer.size());
std::string stats_string; const std::string result = rtc::hex_encode(&buffer[0], digest_->Size());
ReadMessage(input_fp_, &stats_string); EXPECT_EQ(checksum, result);
neteq_unittest::RtcpStatistics ref_stats;
ASSERT_TRUE(ref_stats.ParseFromString(stats_string));
// Compare
ASSERT_EQ(stats.fraction_lost, ref_stats.fraction_lost());
ASSERT_EQ(stats.cumulative_lost, ref_stats.cumulative_lost());
ASSERT_EQ(stats.extended_max_sequence_number,
ref_stats.extended_max_sequence_number());
ASSERT_EQ(stats.jitter, ref_stats.jitter());
#else
FAIL() << "Reading from reference file requires Proto Buffer.";
#endif // WEBRTC_NETEQ_UNITTEST_BITEXACT
} }
class NetEqDecodingTest : public ::testing::Test { class NetEqDecodingTest : public ::testing::Test {
@ -287,9 +218,10 @@ class NetEqDecodingTest : public ::testing::Test {
void Process(); void Process();
void DecodeAndCompare(const std::string& rtp_file, void DecodeAndCompare(const std::string& rtp_file,
const std::string& ref_file, const std::string& output_checksum,
const std::string& stat_ref_file, const std::string& network_stats_checksum,
const std::string& rtcp_ref_file); const std::string& rtcp_stats_checksum,
bool gen_ref);
static void PopulateRtpInfo(int frame_index, static void PopulateRtpInfo(int frame_index,
int timestamp, int timestamp,
@ -434,29 +366,25 @@ void NetEqDecodingTest::Process() {
sim_clock_ += kTimeStepMs; sim_clock_ += kTimeStepMs;
} }
void NetEqDecodingTest::DecodeAndCompare(const std::string& rtp_file, void NetEqDecodingTest::DecodeAndCompare(
const std::string& ref_file, const std::string& rtp_file,
const std::string& stat_ref_file, const std::string& output_checksum,
const std::string& rtcp_ref_file) { const std::string& network_stats_checksum,
const std::string& rtcp_stats_checksum,
bool gen_ref) {
OpenInputFile(rtp_file); OpenInputFile(rtp_file);
std::string ref_out_file = ""; std::string ref_out_file =
if (ref_file.empty()) { gen_ref ? webrtc::test::OutputPath() + "neteq_universal_ref.pcm" : "";
ref_out_file = webrtc::test::OutputPath() + "neteq_universal_ref.pcm"; ResultSink output(ref_out_file);
}
RefFiles ref_files(ref_file, ref_out_file);
std::string stat_out_file = ""; std::string stat_out_file =
if (stat_ref_file.empty()) { gen_ref ? webrtc::test::OutputPath() + "neteq_network_stats.dat" : "";
stat_out_file = webrtc::test::OutputPath() + "neteq_network_stats.dat"; ResultSink network_stats(stat_out_file);
}
RefFiles network_stat_files(stat_ref_file, stat_out_file);
std::string rtcp_out_file = ""; std::string rtcp_out_file =
if (rtcp_ref_file.empty()) { gen_ref ? webrtc::test::OutputPath() + "neteq_rtcp_stats.dat" : "";
rtcp_out_file = webrtc::test::OutputPath() + "neteq_rtcp_stats.dat"; ResultSink rtcp_stats(rtcp_out_file);
}
RefFiles rtcp_stat_files(rtcp_ref_file, rtcp_out_file);
packet_.reset(rtp_source_->NextPacket()); packet_.reset(rtp_source_->NextPacket());
int i = 0; int i = 0;
@ -465,25 +393,33 @@ void NetEqDecodingTest::DecodeAndCompare(const std::string& rtp_file,
ss << "Lap number " << i++ << " in DecodeAndCompare while loop"; ss << "Lap number " << i++ << " in DecodeAndCompare while loop";
SCOPED_TRACE(ss.str()); // Print out the parameter values on failure. SCOPED_TRACE(ss.str()); // Print out the parameter values on failure.
ASSERT_NO_FATAL_FAILURE(Process()); ASSERT_NO_FATAL_FAILURE(Process());
ASSERT_NO_FATAL_FAILURE(ref_files.ProcessReference( ASSERT_NO_FATAL_FAILURE(output.AddResult(
out_frame_.data_, out_frame_.samples_per_channel_)); out_frame_.data_, out_frame_.samples_per_channel_));
// Query the network statistics API once per second // Query the network statistics API once per second
if (sim_clock_ % 1000 == 0) { if (sim_clock_ % 1000 == 0) {
// Process NetworkStatistics. // Process NetworkStatistics.
NetEqNetworkStatistics network_stats; NetEqNetworkStatistics current_network_stats;
ASSERT_EQ(0, neteq_->NetworkStatistics(&network_stats)); ASSERT_EQ(0, neteq_->NetworkStatistics(&current_network_stats));
ASSERT_NO_FATAL_FAILURE( ASSERT_NO_FATAL_FAILURE(network_stats.AddResult(current_network_stats));
network_stat_files.ProcessReference(network_stats));
// Compare with CurrentDelay, which should be identical. // Compare with CurrentDelay, which should be identical.
EXPECT_EQ(network_stats.current_buffer_size_ms, neteq_->CurrentDelayMs()); EXPECT_EQ(current_network_stats.current_buffer_size_ms,
neteq_->CurrentDelayMs());
// Process RTCPstat. // Process RTCPstat.
RtcpStatistics rtcp_stats; RtcpStatistics current_rtcp_stats;
neteq_->GetRtcpStatistics(&rtcp_stats); neteq_->GetRtcpStatistics(&current_rtcp_stats);
ASSERT_NO_FATAL_FAILURE(rtcp_stat_files.ProcessReference(rtcp_stats)); ASSERT_NO_FATAL_FAILURE(rtcp_stats.AddResult(current_rtcp_stats));
} }
} }
SCOPED_TRACE("Check output audio.");
output.VerifyChecksum(output_checksum);
SCOPED_TRACE("Check network stats.");
network_stats.VerifyChecksum(network_stats_checksum);
SCOPED_TRACE("Check rtcp stats.");
rtcp_stats.VerifyChecksum(rtcp_stats_checksum);
} }
void NetEqDecodingTest::PopulateRtpInfo(int frame_index, void NetEqDecodingTest::PopulateRtpInfo(int frame_index,
@ -522,31 +458,30 @@ void NetEqDecodingTest::PopulateCng(int frame_index,
TEST_F(NetEqDecodingTest, MAYBE_TestBitExactness) { TEST_F(NetEqDecodingTest, MAYBE_TestBitExactness) {
const std::string input_rtp_file = const std::string input_rtp_file =
webrtc::test::ResourcePath("audio_coding/neteq_universal_new", "rtp"); webrtc::test::ResourcePath("audio_coding/neteq_universal_new", "rtp");
// Note that neteq4_universal_ref.pcm and neteq4_universal_ref_win_32.pcm
// are identical. The latter could have been removed, but if clients still
// have a copy of the file, the test will fail.
const std::string input_ref_file =
webrtc::test::ResourcePath("audio_coding/neteq4_universal_ref", "pcm");
#if defined(_MSC_VER) && (_MSC_VER >= 1700)
// For Visual Studio 2012 and later, we will have to use the generic reference
// file, rather than the windows-specific one.
const std::string network_stat_ref_file = webrtc::test::ProjectRootPath() +
"resources/audio_coding/neteq4_network_stats.dat";
#else
const std::string network_stat_ref_file =
webrtc::test::ResourcePath("audio_coding/neteq4_network_stats", "dat");
#endif
const std::string rtcp_stat_ref_file =
webrtc::test::ResourcePath("audio_coding/neteq4_rtcp_stats", "dat");
if (FLAGS_gen_ref) { const std::string output_checksum = PlatformChecksum(
DecodeAndCompare(input_rtp_file, "", "", ""); "f587883b7c371ee8d87dbf1b0f07525af7d959b8",
} else { "a349bd71dba548029b05d1d2a6dc7caafab9a856",
DecodeAndCompare(input_rtp_file, "f587883b7c371ee8d87dbf1b0f07525af7d959b8",
input_ref_file, "08266b198e7686b3cd9330813e0d2cd72fc8fdc2");
network_stat_ref_file,
rtcp_stat_ref_file); const std::string network_stats_checksum = PlatformChecksum(
} "2cf380a05ee07080bd72471e8ec7777a39644ec9",
"2853ab577fe571adfc7b18f77bbe58f1253d2019",
"2cf380a05ee07080bd72471e8ec7777a39644ec9",
"2cf380a05ee07080bd72471e8ec7777a39644ec9");
const std::string rtcp_stats_checksum = PlatformChecksum(
"b8880bf9fed2487efbddcb8d94b9937a29ae521d",
"f3f7b3d3e71d7e635240b5373b57df6a7e4ce9d4",
"b8880bf9fed2487efbddcb8d94b9937a29ae521d",
"b8880bf9fed2487efbddcb8d94b9937a29ae521d");
DecodeAndCompare(input_rtp_file,
output_checksum,
network_stats_checksum,
rtcp_stats_checksum,
FLAGS_gen_ref);
} }
// Disabled for UBSan: https://bugs.chromium.org/p/webrtc/issues/detail?id=5820 // Disabled for UBSan: https://bugs.chromium.org/p/webrtc/issues/detail?id=5820
@ -560,26 +495,30 @@ TEST_F(NetEqDecodingTest, MAYBE_TestBitExactness) {
TEST_F(NetEqDecodingTest, MAYBE_TestOpusBitExactness) { TEST_F(NetEqDecodingTest, MAYBE_TestOpusBitExactness) {
const std::string input_rtp_file = const std::string input_rtp_file =
webrtc::test::ResourcePath("audio_coding/neteq_opus", "rtp"); webrtc::test::ResourcePath("audio_coding/neteq_opus", "rtp");
const std::string input_ref_file =
// The pcm files were generated by using Opus v1.1.2 to decode the RTC
// file generated by Opus v1.1
webrtc::test::ResourcePath("audio_coding/neteq4_opus_ref", "pcm");
const std::string network_stat_ref_file =
// The network stats file was generated when using Opus v1.1.2 to decode
// the RTC file generated by Opus v1.1
webrtc::test::ResourcePath("audio_coding/neteq4_opus_network_stats",
"dat");
const std::string rtcp_stat_ref_file =
webrtc::test::ResourcePath("audio_coding/neteq4_opus_rtcp_stats", "dat");
if (FLAGS_gen_ref) { const std::string output_checksum = PlatformChecksum(
DecodeAndCompare(input_rtp_file, "", "", ""); "c23004d91ffbe5e7a1f24620fc89b58c0426040f",
} else { "c23004d91ffbe5e7a1f24620fc89b58c0426040f",
DecodeAndCompare(input_rtp_file, "c23004d91ffbe5e7a1f24620fc89b58c0426040f",
input_ref_file, "c23004d91ffbe5e7a1f24620fc89b58c0426040f");
network_stat_ref_file,
rtcp_stat_ref_file); const std::string network_stats_checksum = PlatformChecksum(
} "dc2d9f584efb0111ebcd71a2c86f1fb09cd8c2bb",
"dc2d9f584efb0111ebcd71a2c86f1fb09cd8c2bb",
"dc2d9f584efb0111ebcd71a2c86f1fb09cd8c2bb",
"dc2d9f584efb0111ebcd71a2c86f1fb09cd8c2bb");
const std::string rtcp_stats_checksum = PlatformChecksum(
"e37c797e3de6a64dda88c9ade7a013d022a2e1e0",
"e37c797e3de6a64dda88c9ade7a013d022a2e1e0",
"e37c797e3de6a64dda88c9ade7a013d022a2e1e0",
"e37c797e3de6a64dda88c9ade7a013d022a2e1e0");
DecodeAndCompare(input_rtp_file,
output_checksum,
network_stats_checksum,
rtcp_stats_checksum,
FLAGS_gen_ref);
} }
// Use fax mode to avoid time-scaling. This is to simplify the testing of // Use fax mode to avoid time-scaling. This is to simplify the testing of