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
diff --git a/webrtc/modules/audio_coding/neteq/neteq_tests.gypi b/webrtc/modules/audio_coding/neteq/neteq_tests.gypi
index 48cd9eb..2905232 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 19a34ec..f954b1b 100644
--- a/webrtc/modules/audio_coding/neteq/test/RTPcat.cc
+++ b/webrtc/modules/audio_coding/neteq/test/RTPcat.cc
@@ -10,13 +10,14 @@
 
 #include <stdio.h>
 
-#include <algorithm>
-#include <vector>
+#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 @@
     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<RtpFileWriter> 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<RtpFileReader> 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 19531ed..dcb5f0f 100644
--- a/webrtc/test/rtp_file_reader.cc
+++ b/webrtc/test/rtp_file_reader.cc
@@ -91,11 +91,11 @@
     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 @@
     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 @@
   }
 
  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 @@
     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 0000000..1b9bfdc
--- /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 <stdio.h>
+
+#include <string>
+
+#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<uint16_t>(packet->length + kPacketHeaderSize);
+    CHECK_GE(packet->original_length, packet->length);
+    uint16_t plen = static_cast<uint16_t>(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<uint8_t>((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<uint8_t>((in >> 8) & 0xFF);
+    if (fwrite(&tmp, sizeof(uint8_t), 1, file_) != 1)
+      return false;
+    // Write 8 LSBs.
+    tmp = static_cast<uint8_t>(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 0000000..453b2776
--- /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 <string>
+
+#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 0000000..7f390cc
--- /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 <string.h>
+
+#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<test::RtpFileReader> 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<size_t>(i), packet.length);
+      EXPECT_EQ(static_cast<size_t>(i), packet.original_length);
+      EXPECT_EQ(static_cast<uint32_t>(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<test::RtpFileWriter> 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 7aba2f5..d261fd2 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 cd07663..242b0cd 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