Add RtpPacketInfo to hold information about a received RtpPacket.

This change adds classes so that we later can plumb information about received packets to each audio and video frame. It's not wired up to do anything yet.

Bug: webrtc:10668
Change-Id: I962df493a76692f668314f78d6792d7636c5a31b
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/138203
Commit-Queue: Chen Xing <chxg@google.com>
Reviewed-by: Minyue Li <minyue@webrtc.org>
Reviewed-by: Karl Wiberg <kwiberg@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#28138}
diff --git a/api/BUILD.gn b/api/BUILD.gn
index 4bf0a3b..2617a19 100644
--- a/api/BUILD.gn
+++ b/api/BUILD.gn
@@ -78,6 +78,24 @@
   ]
 }
 
+rtc_source_set("rtp_packet_info") {
+  visibility = [ "*" ]
+  sources = [
+    "rtp_packet_info.cc",
+    "rtp_packet_info.h",
+    "rtp_packet_infos.h",
+  ]
+  deps = [
+    ":array_view",
+    ":refcountedbase",
+    ":rtp_headers",
+    ":scoped_refptr",
+    "..:webrtc_common",
+    "../rtc_base:rtc_base_approved",
+    "//third_party/abseil-cpp/absl/types:optional",
+  ]
+}
+
 rtc_static_library("libjingle_peerconnection_api") {
   visibility = [ "*" ]
   cflags = []
@@ -148,6 +166,7 @@
     ":libjingle_logging_api",
     ":network_state_predictor_api",
     ":rtc_stats_api",
+    ":rtp_packet_info",
     ":scoped_refptr",
     "audio:audio_mixer_api",
     "audio_codecs:audio_codecs_api",
@@ -811,6 +830,8 @@
       "function_view_unittest.cc",
       "rtc_error_unittest.cc",
       "rtc_event_log_output_file_unittest.cc",
+      "rtp_packet_info_unittest.cc",
+      "rtp_packet_infos_unittest.cc",
       "rtp_parameters_unittest.cc",
       "test/loopback_media_transport_unittest.cc",
     ]
@@ -821,6 +842,7 @@
       ":libjingle_peerconnection_api",
       ":loopback_media_transport",
       ":rtc_event_log_output_file",
+      ":rtp_packet_info",
       "../rtc_base:checks",
       "../rtc_base:gunit_helpers",
       "../rtc_base:rtc_base_approved",
diff --git a/api/rtp_headers.h b/api/rtp_headers.h
index 44972ec..a7ae5cd 100644
--- a/api/rtp_headers.h
+++ b/api/rtp_headers.h
@@ -51,7 +51,7 @@
   absl::optional<FeedbackRequest> feedback_request;
 
   // Audio Level includes both level in dBov and voiced/unvoiced bit. See:
-  // https://datatracker.ietf.org/doc/draft-lennox-avt-rtp-audio-level-exthdr/
+  // https://tools.ietf.org/html/rfc6464#section-3
   bool hasAudioLevel;
   bool voiceActivity;
   uint8_t audioLevel;
diff --git a/api/rtp_packet_info.cc b/api/rtp_packet_info.cc
new file mode 100644
index 0000000..a61b173
--- /dev/null
+++ b/api/rtp_packet_info.cc
@@ -0,0 +1,58 @@
+/*
+ *  Copyright (c) 2019 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 "api/rtp_packet_info.h"
+
+#include <algorithm>
+#include <utility>
+
+namespace webrtc {
+
+RtpPacketInfo::RtpPacketInfo()
+    : ssrc_(0), sequence_number_(0), rtp_timestamp_(0), receive_time_ms_(-1) {}
+
+RtpPacketInfo::RtpPacketInfo(uint32_t ssrc,
+                             std::vector<uint32_t> csrcs,
+                             uint16_t sequence_number,
+                             uint32_t rtp_timestamp,
+                             absl::optional<uint8_t> audio_level,
+                             int64_t receive_time_ms)
+    : ssrc_(ssrc),
+      csrcs_(std::move(csrcs)),
+      sequence_number_(sequence_number),
+      rtp_timestamp_(rtp_timestamp),
+      audio_level_(audio_level),
+      receive_time_ms_(receive_time_ms) {}
+
+RtpPacketInfo::RtpPacketInfo(const RTPHeader& rtp_header,
+                             int64_t receive_time_ms)
+    : ssrc_(rtp_header.ssrc),
+      sequence_number_(rtp_header.sequenceNumber),
+      rtp_timestamp_(rtp_header.timestamp),
+      receive_time_ms_(receive_time_ms) {
+  const auto& extension = rtp_header.extension;
+  const auto csrcs_count = std::min<size_t>(rtp_header.numCSRCs, kRtpCsrcSize);
+
+  csrcs_.assign(&rtp_header.arrOfCSRCs[0], &rtp_header.arrOfCSRCs[csrcs_count]);
+
+  if (extension.hasAudioLevel) {
+    audio_level_ = extension.audioLevel;
+  }
+}
+
+bool operator==(const RtpPacketInfo& lhs, const RtpPacketInfo& rhs) {
+  return (lhs.ssrc() == rhs.ssrc()) && (lhs.csrcs() == rhs.csrcs()) &&
+         (lhs.sequence_number() == rhs.sequence_number()) &&
+         (lhs.rtp_timestamp() == rhs.rtp_timestamp()) &&
+         (lhs.audio_level() == rhs.audio_level()) &&
+         (lhs.receive_time_ms() == rhs.receive_time_ms());
+}
+
+}  // namespace webrtc
diff --git a/api/rtp_packet_info.h b/api/rtp_packet_info.h
new file mode 100644
index 0000000..7809067
--- /dev/null
+++ b/api/rtp_packet_info.h
@@ -0,0 +1,84 @@
+/*
+ *  Copyright (c) 2019 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 API_RTP_PACKET_INFO_H_
+#define API_RTP_PACKET_INFO_H_
+
+#include <cstdint>
+#include <utility>
+#include <vector>
+
+#include "absl/types/optional.h"
+#include "api/rtp_headers.h"
+
+namespace webrtc {
+
+// Structure to hold information about a received |RtpPacket|.
+class RtpPacketInfo {
+ public:
+  RtpPacketInfo();
+
+  RtpPacketInfo(uint32_t ssrc,
+                std::vector<uint32_t> csrcs,
+                uint16_t sequence_number,
+                uint32_t rtp_timestamp,
+                absl::optional<uint8_t> audio_level,
+                int64_t receive_time_ms);
+
+  RtpPacketInfo(const RTPHeader& rtp_header, int64_t receive_time_ms);
+
+  RtpPacketInfo(const RtpPacketInfo& other) = default;
+  RtpPacketInfo(RtpPacketInfo&& other) = default;
+  RtpPacketInfo& operator=(const RtpPacketInfo& other) = default;
+  RtpPacketInfo& operator=(RtpPacketInfo&& other) = default;
+
+  uint32_t ssrc() const { return ssrc_; }
+  void set_ssrc(uint32_t value) { ssrc_ = value; }
+
+  const std::vector<uint32_t>& csrcs() const { return csrcs_; }
+  void set_csrcs(std::vector<uint32_t> value) { csrcs_ = std::move(value); }
+
+  uint16_t sequence_number() const { return sequence_number_; }
+  void set_sequence_number(uint16_t value) { sequence_number_ = value; }
+
+  uint32_t rtp_timestamp() const { return rtp_timestamp_; }
+  void set_rtp_timestamp(uint32_t value) { rtp_timestamp_ = value; }
+
+  absl::optional<uint8_t> audio_level() const { return audio_level_; }
+  void set_audio_level(absl::optional<uint8_t> value) { audio_level_ = value; }
+
+  int64_t receive_time_ms() const { return receive_time_ms_; }
+  void set_receive_time_ms(int64_t value) { receive_time_ms_ = value; }
+
+ private:
+  // Fields from the RTP header:
+  // https://tools.ietf.org/html/rfc3550#section-5.1
+  uint32_t ssrc_;
+  std::vector<uint32_t> csrcs_;
+  uint16_t sequence_number_;
+  uint32_t rtp_timestamp_;
+
+  // Fields from the Audio Level header extension:
+  // https://tools.ietf.org/html/rfc6464#section-3
+  absl::optional<uint8_t> audio_level_;
+
+  // Local |webrtc::Clock|-based timestamp of when the packet was received.
+  int64_t receive_time_ms_;
+};
+
+bool operator==(const RtpPacketInfo& lhs, const RtpPacketInfo& rhs);
+
+inline bool operator!=(const RtpPacketInfo& lhs, const RtpPacketInfo& rhs) {
+  return !(lhs == rhs);
+}
+
+}  // namespace webrtc
+
+#endif  // API_RTP_PACKET_INFO_H_
diff --git a/api/rtp_packet_info_unittest.cc b/api/rtp_packet_info_unittest.cc
new file mode 100644
index 0000000..b9ad1ce
--- /dev/null
+++ b/api/rtp_packet_info_unittest.cc
@@ -0,0 +1,180 @@
+/*
+ *  Copyright (c) 2019 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 "api/rtp_packet_infos.h"
+
+#include "test/gmock.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+
+TEST(RtpPacketInfoTest, Ssrc) {
+  const uint32_t value = 4038189233;
+
+  RtpPacketInfo lhs;
+  RtpPacketInfo rhs;
+
+  EXPECT_TRUE(lhs == rhs);
+  EXPECT_FALSE(lhs != rhs);
+
+  rhs.set_ssrc(value);
+  EXPECT_EQ(rhs.ssrc(), value);
+
+  EXPECT_FALSE(lhs == rhs);
+  EXPECT_TRUE(lhs != rhs);
+
+  lhs = rhs;
+
+  EXPECT_TRUE(lhs == rhs);
+  EXPECT_FALSE(lhs != rhs);
+
+  rhs = RtpPacketInfo();
+  EXPECT_NE(rhs.ssrc(), value);
+
+  rhs = RtpPacketInfo(value, {}, {}, {}, {}, {});
+  EXPECT_EQ(rhs.ssrc(), value);
+}
+
+TEST(RtpPacketInfoTest, Csrcs) {
+  const std::vector<uint32_t> value = {4038189233, 3016333617, 1207992985};
+
+  RtpPacketInfo lhs;
+  RtpPacketInfo rhs;
+
+  EXPECT_TRUE(lhs == rhs);
+  EXPECT_FALSE(lhs != rhs);
+
+  rhs.set_csrcs(value);
+  EXPECT_EQ(rhs.csrcs(), value);
+
+  EXPECT_FALSE(lhs == rhs);
+  EXPECT_TRUE(lhs != rhs);
+
+  lhs = rhs;
+
+  EXPECT_TRUE(lhs == rhs);
+  EXPECT_FALSE(lhs != rhs);
+
+  rhs = RtpPacketInfo();
+  EXPECT_NE(rhs.csrcs(), value);
+
+  rhs = RtpPacketInfo({}, value, {}, {}, {}, {});
+  EXPECT_EQ(rhs.csrcs(), value);
+}
+
+TEST(RtpPacketInfoTest, SequenceNumber) {
+  const uint16_t value = 20238;
+
+  RtpPacketInfo lhs;
+  RtpPacketInfo rhs;
+
+  EXPECT_TRUE(lhs == rhs);
+  EXPECT_FALSE(lhs != rhs);
+
+  rhs.set_sequence_number(value);
+  EXPECT_EQ(rhs.sequence_number(), value);
+
+  EXPECT_FALSE(lhs == rhs);
+  EXPECT_TRUE(lhs != rhs);
+
+  lhs = rhs;
+
+  EXPECT_TRUE(lhs == rhs);
+  EXPECT_FALSE(lhs != rhs);
+
+  rhs = RtpPacketInfo();
+  EXPECT_NE(rhs.sequence_number(), value);
+
+  rhs = RtpPacketInfo({}, {}, value, {}, {}, {});
+  EXPECT_EQ(rhs.sequence_number(), value);
+}
+
+TEST(RtpPacketInfoTest, RtpTimestamp) {
+  const uint32_t value = 4038189233;
+
+  RtpPacketInfo lhs;
+  RtpPacketInfo rhs;
+
+  EXPECT_TRUE(lhs == rhs);
+  EXPECT_FALSE(lhs != rhs);
+
+  rhs.set_rtp_timestamp(value);
+  EXPECT_EQ(rhs.rtp_timestamp(), value);
+
+  EXPECT_FALSE(lhs == rhs);
+  EXPECT_TRUE(lhs != rhs);
+
+  lhs = rhs;
+
+  EXPECT_TRUE(lhs == rhs);
+  EXPECT_FALSE(lhs != rhs);
+
+  rhs = RtpPacketInfo();
+  EXPECT_NE(rhs.rtp_timestamp(), value);
+
+  rhs = RtpPacketInfo({}, {}, {}, value, {}, {});
+  EXPECT_EQ(rhs.rtp_timestamp(), value);
+}
+
+TEST(RtpPacketInfoTest, AudioLevel) {
+  const absl::optional<uint8_t> value = 31;
+
+  RtpPacketInfo lhs;
+  RtpPacketInfo rhs;
+
+  EXPECT_TRUE(lhs == rhs);
+  EXPECT_FALSE(lhs != rhs);
+
+  rhs.set_audio_level(value);
+  EXPECT_EQ(rhs.audio_level(), value);
+
+  EXPECT_FALSE(lhs == rhs);
+  EXPECT_TRUE(lhs != rhs);
+
+  lhs = rhs;
+
+  EXPECT_TRUE(lhs == rhs);
+  EXPECT_FALSE(lhs != rhs);
+
+  rhs = RtpPacketInfo();
+  EXPECT_NE(rhs.audio_level(), value);
+
+  rhs = RtpPacketInfo({}, {}, {}, {}, value, {});
+  EXPECT_EQ(rhs.audio_level(), value);
+}
+
+TEST(RtpPacketInfoTest, ReceiveTimeMs) {
+  const int64_t value = 8868963877546349045LL;
+
+  RtpPacketInfo lhs;
+  RtpPacketInfo rhs;
+
+  EXPECT_TRUE(lhs == rhs);
+  EXPECT_FALSE(lhs != rhs);
+
+  rhs.set_receive_time_ms(value);
+  EXPECT_EQ(rhs.receive_time_ms(), value);
+
+  EXPECT_FALSE(lhs == rhs);
+  EXPECT_TRUE(lhs != rhs);
+
+  lhs = rhs;
+
+  EXPECT_TRUE(lhs == rhs);
+  EXPECT_FALSE(lhs != rhs);
+
+  rhs = RtpPacketInfo();
+  EXPECT_NE(rhs.receive_time_ms(), value);
+
+  rhs = RtpPacketInfo({}, {}, {}, {}, {}, value);
+  EXPECT_EQ(rhs.receive_time_ms(), value);
+}
+
+}  // namespace webrtc
diff --git a/api/rtp_packet_infos.h b/api/rtp_packet_infos.h
new file mode 100644
index 0000000..a19163f
--- /dev/null
+++ b/api/rtp_packet_infos.h
@@ -0,0 +1,109 @@
+/*
+ *  Copyright (c) 2019 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 API_RTP_PACKET_INFOS_H_
+#define API_RTP_PACKET_INFOS_H_
+
+#include <cstdint>
+#include <vector>
+
+#include "api/ref_counted_base.h"
+#include "api/rtp_packet_info.h"
+#include "api/scoped_refptr.h"
+
+namespace webrtc {
+
+// Semi-immutable structure to hold information about packets used to assemble
+// an audio or video frame. Uses internal reference counting to make it very
+// cheap to copy.
+//
+// We should ideally just use |std::vector<RtpPacketInfo>| and have it
+// |std::move()|-ed as the per-packet information is transferred from one object
+// to another. But moving the info, instead of copying it, is not easily done
+// for the current video code.
+class RtpPacketInfos {
+ public:
+  using vector_type = std::vector<RtpPacketInfo>;
+
+  using value_type = vector_type::value_type;
+  using size_type = vector_type::size_type;
+  using difference_type = vector_type::difference_type;
+  using const_reference = vector_type::const_reference;
+  using const_pointer = vector_type::const_pointer;
+  using const_iterator = vector_type::const_iterator;
+  using const_reverse_iterator = vector_type::const_reverse_iterator;
+
+  using reference = const_reference;
+  using pointer = const_pointer;
+  using iterator = const_iterator;
+  using reverse_iterator = const_reverse_iterator;
+
+  RtpPacketInfos() {}
+  explicit RtpPacketInfos(vector_type entries) : data_(Data::Create(entries)) {}
+
+  RtpPacketInfos(const RtpPacketInfos& other) = default;
+  RtpPacketInfos(RtpPacketInfos&& other) = default;
+  RtpPacketInfos& operator=(const RtpPacketInfos& other) = default;
+  RtpPacketInfos& operator=(RtpPacketInfos&& other) = default;
+
+  const_reference operator[](size_type pos) const { return entries()[pos]; }
+
+  const_reference at(size_type pos) const { return entries().at(pos); }
+  const_reference front() const { return entries().front(); }
+  const_reference back() const { return entries().back(); }
+
+  const_iterator begin() const { return entries().begin(); }
+  const_iterator end() const { return entries().end(); }
+  const_reverse_iterator rbegin() const { return entries().rbegin(); }
+  const_reverse_iterator rend() const { return entries().rend(); }
+
+  const_iterator cbegin() const { return entries().cbegin(); }
+  const_iterator cend() const { return entries().cend(); }
+  const_reverse_iterator crbegin() const { return entries().crbegin(); }
+  const_reverse_iterator crend() const { return entries().crend(); }
+
+  bool empty() const { return entries().empty(); }
+  size_type size() const { return entries().size(); }
+
+ private:
+  class Data : public rtc::RefCountedBase {
+   public:
+    static rtc::scoped_refptr<Data> Create(vector_type entries) {
+      return new Data(entries);
+    }
+
+    const vector_type& entries() const { return entries_; }
+
+   private:
+    explicit Data(vector_type entries) : entries_(entries) {}
+    ~Data() override {}
+
+    const vector_type entries_;
+  };
+
+  static const vector_type& empty_entries() {
+    static const vector_type& value = *new vector_type();
+    return value;
+  }
+
+  const vector_type& entries() const {
+    if (data_ != nullptr) {
+      return data_->entries();
+    } else {
+      return empty_entries();
+    }
+  }
+
+  rtc::scoped_refptr<Data> data_;
+};
+
+}  // namespace webrtc
+
+#endif  // API_RTP_PACKET_INFOS_H_
diff --git a/api/rtp_packet_infos_unittest.cc b/api/rtp_packet_infos_unittest.cc
new file mode 100644
index 0000000..0e1b89a
--- /dev/null
+++ b/api/rtp_packet_infos_unittest.cc
@@ -0,0 +1,85 @@
+/*
+ *  Copyright (c) 2019 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 "api/rtp_packet_infos.h"
+
+#include "test/gmock.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+namespace {
+
+using ::testing::ElementsAre;
+using ::testing::SizeIs;
+
+template <typename Iterator>
+RtpPacketInfos::vector_type ToVector(Iterator begin, Iterator end) {
+  return RtpPacketInfos::vector_type(begin, end);
+}
+
+}  // namespace
+
+TEST(RtpPacketInfosTest, BasicFunctionality) {
+  RtpPacketInfo p0(123, {1, 2}, 42, 89, 5, 7);
+  RtpPacketInfo p1(456, {3, 4}, 37, 89, 4, 1);
+  RtpPacketInfo p2(789, {5, 6}, 91, 88, 1, 7);
+
+  RtpPacketInfos x({p0, p1, p2});
+
+  ASSERT_THAT(x, SizeIs(3));
+
+  EXPECT_EQ(x[0], p0);
+  EXPECT_EQ(x[1], p1);
+  EXPECT_EQ(x[2], p2);
+
+  EXPECT_EQ(x.front(), p0);
+  EXPECT_EQ(x.back(), p2);
+
+  EXPECT_THAT(ToVector(x.begin(), x.end()), ElementsAre(p0, p1, p2));
+  EXPECT_THAT(ToVector(x.rbegin(), x.rend()), ElementsAre(p2, p1, p0));
+
+  EXPECT_THAT(ToVector(x.cbegin(), x.cend()), ElementsAre(p0, p1, p2));
+  EXPECT_THAT(ToVector(x.crbegin(), x.crend()), ElementsAre(p2, p1, p0));
+
+  EXPECT_FALSE(x.empty());
+}
+
+TEST(RtpPacketInfosTest, CopyShareData) {
+  RtpPacketInfo p0(123, {1, 2}, 42, 89, 5, 7);
+  RtpPacketInfo p1(456, {3, 4}, 37, 89, 4, 1);
+  RtpPacketInfo p2(789, {5, 6}, 91, 88, 1, 7);
+
+  RtpPacketInfos lhs({p0, p1, p2});
+  RtpPacketInfos rhs = lhs;
+
+  ASSERT_THAT(lhs, SizeIs(3));
+  ASSERT_THAT(rhs, SizeIs(3));
+
+  for (size_t i = 0; i < lhs.size(); ++i) {
+    EXPECT_EQ(lhs[i], rhs[i]);
+  }
+
+  EXPECT_EQ(lhs.front(), rhs.front());
+  EXPECT_EQ(lhs.back(), rhs.back());
+
+  EXPECT_EQ(lhs.begin(), rhs.begin());
+  EXPECT_EQ(lhs.end(), rhs.end());
+  EXPECT_EQ(lhs.rbegin(), rhs.rbegin());
+  EXPECT_EQ(lhs.rend(), rhs.rend());
+
+  EXPECT_EQ(lhs.cbegin(), rhs.cbegin());
+  EXPECT_EQ(lhs.cend(), rhs.cend());
+  EXPECT_EQ(lhs.crbegin(), rhs.crbegin());
+  EXPECT_EQ(lhs.crend(), rhs.crend());
+
+  EXPECT_EQ(lhs.empty(), rhs.empty());
+}
+
+}  // namespace webrtc