From 83317146ba236fd535f7fdbc4f849ca0913b088c Mon Sep 17 00:00:00 2001 From: "henrik.lundin@webrtc.org" Date: Mon, 1 Dec 2014 11:25:04 +0000 Subject: [PATCH] Adding a new test helper RtpFileWriter and use it in RTPcat This new helper class writes RTP packets to file in rtpdump format. A unit test is also included. The new test class is used while re-writing the test tool RTPcat. BUG=2692 R=pbos@webrtc.org Review URL: https://webrtc-codereview.appspot.com/28099004 git-svn-id: http://webrtc.googlecode.com/svn/trunk@7768 4adac7df-926f-26a2-2b94-8c16560cd09d --- .../audio_coding/neteq/neteq_tests.gypi | 2 +- .../modules/audio_coding/neteq/test/RTPcat.cc | 65 +++-------- webrtc/test/rtp_file_reader.cc | 20 ++-- webrtc/test/rtp_file_writer.cc | 109 ++++++++++++++++++ webrtc/test/rtp_file_writer.h | 33 ++++++ webrtc/test/rtp_file_writer_unittest.cc | 75 ++++++++++++ webrtc/test/test.gyp | 2 + webrtc/test/webrtc_test_common.gyp | 1 + 8 files changed, 248 insertions(+), 59 deletions(-) create mode 100644 webrtc/test/rtp_file_writer.cc create mode 100644 webrtc/test/rtp_file_writer.h create mode 100644 webrtc/test/rtp_file_writer_unittest.cc diff --git a/webrtc/modules/audio_coding/neteq/neteq_tests.gypi b/webrtc/modules/audio_coding/neteq/neteq_tests.gypi index 48cd9ebef..2905232e1 100644 --- a/webrtc/modules/audio_coding/neteq/neteq_tests.gypi +++ b/webrtc/modules/audio_coding/neteq/neteq_tests.gypi @@ -122,8 +122,8 @@ 'target_name': 'RTPcat', 'type': 'executable', 'dependencies': [ - 'neteq_test_tools', '<(DEPTH)/testing/gtest.gyp:gtest', + '<(webrtc_root)/test/test.gyp:rtp_test_utils', ], 'sources': [ 'test/RTPcat.cc', diff --git a/webrtc/modules/audio_coding/neteq/test/RTPcat.cc b/webrtc/modules/audio_coding/neteq/test/RTPcat.cc index 19a34ec2e..f954b1bfb 100644 --- a/webrtc/modules/audio_coding/neteq/test/RTPcat.cc +++ b/webrtc/modules/audio_coding/neteq/test/RTPcat.cc @@ -10,13 +10,14 @@ #include -#include -#include +#include "webrtc/base/checks.h" +#include "webrtc/system_wrappers/interface/scoped_ptr.h" +#include "webrtc/test/rtp_file_reader.h" +#include "webrtc/test/rtp_file_writer.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "webrtc/modules/audio_coding/neteq/test/NETEQTEST_RTPpacket.h" - -#define FIRSTLINELEN 40 +using webrtc::scoped_ptr; +using webrtc::test::RtpFileReader; +using webrtc::test::RtpFileWriter; int main(int argc, char* argv[]) { if (argc < 3) { @@ -24,52 +25,20 @@ int main(int argc, char* argv[]) { exit(1); } - FILE* in_file = fopen(argv[1], "rb"); - if (!in_file) { - printf("Cannot open input file %s\n", argv[1]); - return -1; - } - - FILE* out_file = fopen(argv[argc - 1], "wb"); // Last parameter is out file. - if (!out_file) { - printf("Cannot open output file %s\n", argv[argc - 1]); - return -1; - } - printf("Output RTP file: %s\n\n", argv[argc - 1]); - - // Read file header and write directly to output file. - char firstline[FIRSTLINELEN]; - const unsigned int kRtpDumpHeaderSize = 4 + 4 + 4 + 2 + 2; - EXPECT_TRUE(fgets(firstline, FIRSTLINELEN, in_file) != NULL); - EXPECT_GT(fputs(firstline, out_file), 0); - EXPECT_EQ(kRtpDumpHeaderSize, fread(firstline, 1, kRtpDumpHeaderSize, - in_file)); - EXPECT_EQ(kRtpDumpHeaderSize, fwrite(firstline, 1, kRtpDumpHeaderSize, - out_file)); - - // Close input file and re-open it later (easier to write the loop below). - fclose(in_file); + scoped_ptr output( + RtpFileWriter::Create(RtpFileWriter::kRtpDump, argv[argc - 1])); + CHECK(output.get() != NULL) << "Cannot open output file."; + printf("Output RTP file: %s\n", argv[argc - 1]); for (int i = 1; i < argc - 1; i++) { - in_file = fopen(argv[i], "rb"); - if (!in_file) { - printf("Cannot open input file %s\n", argv[i]); - return -1; - } + scoped_ptr input( + RtpFileReader::Create(RtpFileReader::kRtpDump, argv[i])); + CHECK(input.get() != NULL) << "Cannot open input file " << argv[i]; printf("Input RTP file: %s\n", argv[i]); - NETEQTEST_RTPpacket::skipFileHeader(in_file); - NETEQTEST_RTPpacket packet; - int pack_len = packet.readFromFile(in_file); - if (pack_len < 0) { - exit(1); - } - while (pack_len >= 0) { - packet.writeToFile(out_file); - pack_len = packet.readFromFile(in_file); - } - fclose(in_file); + webrtc::test::RtpPacket packet; + while (input->NextPacket(&packet)) + CHECK(output->WritePacket(&packet)); } - fclose(out_file); return 0; } diff --git a/webrtc/test/rtp_file_reader.cc b/webrtc/test/rtp_file_reader.cc index 19531ed48..dcb5f0fed 100644 --- a/webrtc/test/rtp_file_reader.cc +++ b/webrtc/test/rtp_file_reader.cc @@ -91,11 +91,11 @@ class RtpDumpReader : public RtpFileReaderImpl { uint32_t source; uint16_t port; uint16_t padding; - TRY(Read(&start_sec)); - TRY(Read(&start_usec)); - TRY(Read(&source)); - TRY(Read(&port)); - TRY(Read(&padding)); + TRY(ReadUint32(&start_sec)); + TRY(ReadUint32(&start_usec)); + TRY(ReadUint32(&source)); + TRY(ReadUint16(&port)); + TRY(ReadUint16(&padding)); return true; } @@ -107,9 +107,9 @@ class RtpDumpReader : public RtpFileReaderImpl { uint16_t len; uint16_t plen; uint32_t offset; - TRY(Read(&len)); - TRY(Read(&plen)); - TRY(Read(&offset)); + TRY(ReadUint16(&len)); + TRY(ReadUint16(&plen)); + TRY(ReadUint32(&offset)); // Use 'len' here because a 'plen' of 0 specifies rtcp. len -= kPacketHeaderSize; @@ -130,7 +130,7 @@ class RtpDumpReader : public RtpFileReaderImpl { } private: - bool Read(uint32_t* out) { + bool ReadUint32(uint32_t* out) { *out = 0; for (size_t i = 0; i < 4; ++i) { *out <<= 8; @@ -142,7 +142,7 @@ class RtpDumpReader : public RtpFileReaderImpl { return true; } - bool Read(uint16_t* out) { + bool ReadUint16(uint16_t* out) { *out = 0; for (size_t i = 0; i < 2; ++i) { *out <<= 8; diff --git a/webrtc/test/rtp_file_writer.cc b/webrtc/test/rtp_file_writer.cc new file mode 100644 index 000000000..1b9bfdc2a --- /dev/null +++ b/webrtc/test/rtp_file_writer.cc @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2014 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/test/rtp_file_writer.h" + +#include + +#include + +#include "webrtc/base/checks.h" +#include "webrtc/base/constructormagic.h" + +namespace webrtc { +namespace test { + +static const uint16_t kPacketHeaderSize = 8; +static const char kFirstLine[] = "#!rtpplay1.0 0.0.0.0/0\n"; + +// Write RTP packets to file in rtpdump format, as documented at: +// http://www.cs.columbia.edu/irt/software/rtptools/ +class RtpDumpWriter : public RtpFileWriter { + public: + explicit RtpDumpWriter(FILE* file) : file_(file) { + CHECK(file_ != NULL); + Init(); + } + virtual ~RtpDumpWriter() { + if (file_ != NULL) { + fclose(file_); + file_ = NULL; + } + } + + virtual bool WritePacket(const RtpPacket* packet) OVERRIDE { + uint16_t len = static_cast(packet->length + kPacketHeaderSize); + CHECK_GE(packet->original_length, packet->length); + uint16_t plen = static_cast(packet->original_length); + uint32_t offset = packet->time_ms; + CHECK(WriteUint16(len)); + CHECK(WriteUint16(plen)); + CHECK(WriteUint32(offset)); + return fwrite(packet->data, sizeof(uint8_t), packet->length, file_) == + packet->length; + } + + private: + bool Init() { + fprintf(file_, "%s", kFirstLine); + + CHECK(WriteUint32(0)); + CHECK(WriteUint32(0)); + CHECK(WriteUint32(0)); + CHECK(WriteUint16(0)); + CHECK(WriteUint16(0)); + + return true; + } + + bool WriteUint32(uint32_t in) { + // Loop through shifts = {24, 16, 8, 0}. + for (int shifts = 24; shifts >= 0; shifts -= 8) { + uint8_t tmp = static_cast((in >> shifts) & 0xFF); + if (fwrite(&tmp, sizeof(uint8_t), 1, file_) != 1) + return false; + } + return true; + } + + bool WriteUint16(uint16_t in) { + // Write 8 MSBs. + uint8_t tmp = static_cast((in >> 8) & 0xFF); + if (fwrite(&tmp, sizeof(uint8_t), 1, file_) != 1) + return false; + // Write 8 LSBs. + tmp = static_cast(in & 0xFF); + if (fwrite(&tmp, sizeof(uint8_t), 1, file_) != 1) + return false; + return true; + } + + FILE* file_; + + DISALLOW_COPY_AND_ASSIGN(RtpDumpWriter); +}; + +RtpFileWriter* RtpFileWriter::Create(FileFormat format, + const std::string& filename) { + FILE* file = fopen(filename.c_str(), "wb"); + if (file == NULL) { + printf("ERROR: Can't open file: %s\n", filename.c_str()); + return NULL; + } + switch (format) { + case kRtpDump: + return new RtpDumpWriter(file); + } + fclose(file); + return NULL; +} + +} // namespace test +} // namespace webrtc diff --git a/webrtc/test/rtp_file_writer.h b/webrtc/test/rtp_file_writer.h new file mode 100644 index 000000000..453b27762 --- /dev/null +++ b/webrtc/test/rtp_file_writer.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2014 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_TEST_RTP_FILE_WRITER_H_ +#define WEBRTC_TEST_RTP_FILE_WRITER_H_ + +#include + +#include "webrtc/common_types.h" +#include "webrtc/test/rtp_file_reader.h" + +namespace webrtc { +namespace test { +class RtpFileWriter { + public: + enum FileFormat { + kRtpDump, + }; + + virtual ~RtpFileWriter() {} + static RtpFileWriter* Create(FileFormat format, const std::string& filename); + + virtual bool WritePacket(const RtpPacket* packet) = 0; +}; +} // namespace test +} // namespace webrtc +#endif // WEBRTC_TEST_RTP_FILE_WRITER_H_ diff --git a/webrtc/test/rtp_file_writer_unittest.cc b/webrtc/test/rtp_file_writer_unittest.cc new file mode 100644 index 000000000..7f390cc81 --- /dev/null +++ b/webrtc/test/rtp_file_writer_unittest.cc @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2014 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 + +#include "testing/gtest/include/gtest/gtest.h" +#include "webrtc/system_wrappers/interface/scoped_ptr.h" +#include "webrtc/test/rtp_file_reader.h" +#include "webrtc/test/rtp_file_writer.h" +#include "webrtc/test/testsupport/fileutils.h" + +namespace webrtc { + +class RtpFileWriterTest : public ::testing::Test { + public: + void Init(const std::string& filename) { + filename_ = test::OutputPath() + filename; + rtp_writer_.reset( + test::RtpFileWriter::Create(test::RtpFileWriter::kRtpDump, filename_)); + } + + void WriteRtpPackets(int num_packets) { + ASSERT_TRUE(rtp_writer_.get() != NULL); + test::RtpPacket packet; + for (int i = 1; i <= num_packets; ++i) { + packet.length = i; + packet.original_length = i; + packet.time_ms = i; + memset(packet.data, i, packet.length); + EXPECT_TRUE(rtp_writer_->WritePacket(&packet)); + } + } + + void CloseOutputFile() { rtp_writer_.reset(); } + + void VerifyFileContents(int expected_packets) { + ASSERT_TRUE(rtp_writer_.get() == NULL) + << "Must call CloseOutputFile before VerifyFileContents"; + scoped_ptr rtp_reader( + test::RtpFileReader::Create(test::RtpFileReader::kRtpDump, filename_)); + ASSERT_TRUE(rtp_reader.get() != NULL); + test::RtpPacket packet; + int i = 0; + while (rtp_reader->NextPacket(&packet)) { + ++i; + EXPECT_EQ(static_cast(i), packet.length); + EXPECT_EQ(static_cast(i), packet.original_length); + EXPECT_EQ(static_cast(i), packet.time_ms); + for (int j = 0; j < i; ++j) { + EXPECT_EQ(i, packet.data[j]); + } + } + EXPECT_EQ(expected_packets, i); + } + + private: + scoped_ptr rtp_writer_; + std::string filename_; +}; + +TEST_F(RtpFileWriterTest, WriteToRtpDump) { + Init("test_rtp_file_writer.rtp"); + WriteRtpPackets(10); + CloseOutputFile(); + VerifyFileContents(10); +} + +} // namespace webrtc diff --git a/webrtc/test/test.gyp b/webrtc/test/test.gyp index 7aba2f573..d261fd237 100644 --- a/webrtc/test/test.gyp +++ b/webrtc/test/test.gyp @@ -60,6 +60,8 @@ 'rtcp_packet_parser.h', 'rtp_file_reader.cc', 'rtp_file_reader.h', + 'rtp_file_writer.cc', + 'rtp_file_writer.h', ], 'dependencies': [ '<(webrtc_root)/modules/modules.gyp:rtp_rtcp', diff --git a/webrtc/test/webrtc_test_common.gyp b/webrtc/test/webrtc_test_common.gyp index cd076639c..242b0cdea 100644 --- a/webrtc/test/webrtc_test_common.gyp +++ b/webrtc/test/webrtc_test_common.gyp @@ -157,6 +157,7 @@ 'sources': [ 'fake_network_pipe_unittest.cc', 'rtp_file_reader_unittest.cc', + 'rtp_file_writer_unittest.cc', ], }, ], #targets