Add RTP timestamp to contributing sources

RTP timestamp was recently added to contributing sources in the WebRTC
specification. This CL implements that change in WebRTC.

Bug: webrtc:10650
Change-Id: Ic0ccfbea7049a5b66063fa6cf60d01d5bd713132
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/137515
Reviewed-by: Fredrik Solenberg <solenberg@webrtc.org>
Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org>
Reviewed-by: Danil Chapovalov <danilchap@webrtc.org>
Commit-Queue: Johannes Kron <kron@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#28020}
diff --git a/api/rtp_receiver_interface.cc b/api/rtp_receiver_interface.cc
index 52f72df..efa7f1b 100644
--- a/api/rtp_receiver_interface.cc
+++ b/api/rtp_receiver_interface.cc
@@ -14,10 +14,22 @@
 
 RtpSource::RtpSource(int64_t timestamp_ms,
                      uint32_t source_id,
+                     RtpSourceType source_type,
+                     absl::optional<uint8_t> audio_level,
+                     uint32_t rtp_timestamp)
+    : timestamp_ms_(timestamp_ms),
+      source_id_(source_id),
+      source_type_(source_type),
+      audio_level_(audio_level),
+      rtp_timestamp_(rtp_timestamp) {}
+
+RtpSource::RtpSource(int64_t timestamp_ms,
+                     uint32_t source_id,
                      RtpSourceType source_type)
     : timestamp_ms_(timestamp_ms),
       source_id_(source_id),
-      source_type_(source_type) {}
+      source_type_(source_type),
+      rtp_timestamp_(0) {}
 
 RtpSource::RtpSource(int64_t timestamp_ms,
                      uint32_t source_id,
@@ -26,7 +38,8 @@
     : timestamp_ms_(timestamp_ms),
       source_id_(source_id),
       source_type_(source_type),
-      audio_level_(audio_level) {}
+      audio_level_(audio_level),
+      rtp_timestamp_(0) {}
 
 RtpSource::RtpSource(const RtpSource&) = default;
 RtpSource& RtpSource::operator=(const RtpSource&) = default;
diff --git a/api/rtp_receiver_interface.h b/api/rtp_receiver_interface.h
index 3934215c..f79bf8f 100644
--- a/api/rtp_receiver_interface.h
+++ b/api/rtp_receiver_interface.h
@@ -24,6 +24,7 @@
 #include "api/proxy.h"
 #include "api/rtp_parameters.h"
 #include "api/scoped_refptr.h"
+#include "rtc_base/deprecation.h"
 #include "rtc_base/ref_count.h"
 
 namespace webrtc {
@@ -36,13 +37,23 @@
 class RtpSource {
  public:
   RtpSource() = delete;
-  RtpSource(int64_t timestamp_ms,
-            uint32_t source_id,
-            RtpSourceType source_type);
+
   RtpSource(int64_t timestamp_ms,
             uint32_t source_id,
             RtpSourceType source_type,
-            uint8_t audio_level);
+            absl::optional<uint8_t> audio_level,
+            uint32_t rtp_timestamp);
+
+  // DEPRECATED: Will be removed after 2019-07-31.
+  RTC_DEPRECATED RtpSource(int64_t timestamp_ms,
+                           uint32_t source_id,
+                           RtpSourceType source_type);
+  // DEPRECATED: Will be removed after 2019-07-31.
+  RTC_DEPRECATED RtpSource(int64_t timestamp_ms,
+                           uint32_t source_id,
+                           RtpSourceType source_type,
+                           uint8_t audio_level);
+
   RtpSource(const RtpSource&);
   RtpSource& operator=(const RtpSource&);
   ~RtpSource();
@@ -64,9 +75,12 @@
     audio_level_ = level;
   }
 
+  uint32_t rtp_timestamp() const { return rtp_timestamp_; }
+
   bool operator==(const RtpSource& o) const {
     return timestamp_ms_ == o.timestamp_ms() && source_id_ == o.source_id() &&
-           source_type_ == o.source_type() && audio_level_ == o.audio_level_;
+           source_type_ == o.source_type() && audio_level_ == o.audio_level_ &&
+           rtp_timestamp_ == o.rtp_timestamp();
   }
 
  private:
@@ -74,6 +88,7 @@
   uint32_t source_id_;
   RtpSourceType source_type_;
   absl::optional<uint8_t> audio_level_;
+  uint32_t rtp_timestamp_;
 };
 
 class RtpReceiverObserverInterface {
diff --git a/audio/channel_receive.cc b/audio/channel_receive.cc
index 85a029d..5f59275 100644
--- a/audio/channel_receive.cc
+++ b/audio/channel_receive.cc
@@ -564,9 +564,10 @@
     sources = contributing_sources_.GetSources(now_ms);
     if (last_received_rtp_system_time_ms_ >=
         now_ms - ContributingSources::kHistoryMs) {
+      RTC_DCHECK(last_received_rtp_timestamp_.has_value());
       sources.emplace_back(*last_received_rtp_system_time_ms_, remote_ssrc_,
-                           RtpSourceType::SSRC);
-      sources.back().set_audio_level(last_received_rtp_audio_level_);
+                           RtpSourceType::SSRC, last_received_rtp_audio_level_,
+                           *last_received_rtp_timestamp_);
     }
   }
   return sources;
@@ -599,7 +600,8 @@
     std::vector<uint32_t> csrcs = packet.Csrcs();
     contributing_sources_.Update(
         now_ms, csrcs,
-        has_audio_level ? absl::optional<uint8_t>(audio_level) : absl::nullopt);
+        has_audio_level ? absl::optional<uint8_t>(audio_level) : absl::nullopt,
+        packet.Timestamp());
   }
 
   // Store playout timestamp for the received RTP packet
diff --git a/modules/rtp_rtcp/source/contributing_sources.cc b/modules/rtp_rtcp/source/contributing_sources.cc
index 64dc443..88274ff 100644
--- a/modules/rtp_rtcp/source/contributing_sources.cc
+++ b/modules/rtp_rtcp/source/contributing_sources.cc
@@ -26,8 +26,9 @@
 
 void ContributingSources::Update(int64_t now_ms,
                                  rtc::ArrayView<const uint32_t> csrcs,
-                                 absl::optional<uint8_t> audio_level) {
-  Entry entry = { now_ms, audio_level };
+                                 absl::optional<uint8_t> audio_level,
+                                 uint32_t rtp_timestamp) {
+  Entry entry = {now_ms, audio_level, rtp_timestamp};
   for (uint32_t csrc : csrcs) {
     active_csrcs_[csrc] = entry;
   }
@@ -47,14 +48,9 @@
   std::vector<RtpSource> sources;
   for (auto& record : active_csrcs_) {
     if (record.second.last_seen_ms >= now_ms - kHistoryMs) {
-      if (record.second.audio_level.has_value()) {
-        sources.emplace_back(record.second.last_seen_ms, record.first,
-                             RtpSourceType::CSRC,
-                             *record.second.audio_level);
-      } else {
-        sources.emplace_back(record.second.last_seen_ms, record.first,
-                             RtpSourceType::CSRC);
-      }
+      sources.emplace_back(record.second.last_seen_ms, record.first,
+                           RtpSourceType::CSRC, record.second.audio_level,
+                           record.second.rtp_timestamp);
     }
   }
 
@@ -76,7 +72,10 @@
 
 ContributingSources::Entry::Entry() = default;
 ContributingSources::Entry::Entry(int64_t timestamp_ms,
-                                  absl::optional<uint8_t> audio_level_arg)
-    : last_seen_ms(timestamp_ms), audio_level(audio_level_arg) {}
+                                  absl::optional<uint8_t> audio_level_arg,
+                                  uint32_t rtp_timestamp)
+    : last_seen_ms(timestamp_ms),
+      audio_level(audio_level_arg),
+      rtp_timestamp(rtp_timestamp) {}
 
 }  // namespace webrtc
diff --git a/modules/rtp_rtcp/source/contributing_sources.h b/modules/rtp_rtcp/source/contributing_sources.h
index 81bf725..67e8967 100644
--- a/modules/rtp_rtcp/source/contributing_sources.h
+++ b/modules/rtp_rtcp/source/contributing_sources.h
@@ -32,8 +32,10 @@
   ContributingSources();
   ~ContributingSources();
 
-  void Update(int64_t now_ms, rtc::ArrayView<const uint32_t> csrcs,
-              absl::optional<uint8_t> audio_level);
+  void Update(int64_t now_ms,
+              rtc::ArrayView<const uint32_t> csrcs,
+              absl::optional<uint8_t> audio_level,
+              uint32_t rtp_timestamp);
 
   // Returns contributing sources seen the last 10 s.
   std::vector<RtpSource> GetSources(int64_t now_ms) const;
@@ -41,10 +43,13 @@
  private:
   struct Entry {
     Entry();
-    Entry(int64_t timestamp_ms, absl::optional<uint8_t> audio_level);
+    Entry(int64_t timestamp_ms,
+          absl::optional<uint8_t> audio_level,
+          uint32_t rtp_timestamp);
 
     int64_t last_seen_ms;
     absl::optional<uint8_t> audio_level;
+    uint32_t rtp_timestamp;
   };
 
   void DeleteOldEntries(int64_t now_ms);
diff --git a/modules/rtp_rtcp/source/contributing_sources_unittest.cc b/modules/rtp_rtcp/source/contributing_sources_unittest.cc
index 38d25ce..acf8a90 100644
--- a/modules/rtp_rtcp/source/contributing_sources_unittest.cc
+++ b/modules/rtp_rtcp/source/contributing_sources_unittest.cc
@@ -23,6 +23,9 @@
 constexpr uint32_t kCsrc1 = 111;
 constexpr uint32_t kCsrc2 = 222;
 constexpr uint32_t kCsrc3 = 333;
+constexpr uint32_t kRtpTimestamp1 = 314;
+constexpr uint32_t kRtpTimestamp2 = 315;
+constexpr uint32_t kRtpTimestamp3 = 316;
 
 }  // namespace
 
@@ -30,11 +33,13 @@
   ContributingSources csrcs;
   constexpr uint32_t kCsrcs[] = {kCsrc1, kCsrc2};
   constexpr int64_t kTime1 = 10;
-  csrcs.Update(kTime1, kCsrcs, absl::nullopt);
+  csrcs.Update(kTime1, kCsrcs, absl::nullopt, kRtpTimestamp1);
   EXPECT_THAT(
       csrcs.GetSources(kTime1),
-      UnorderedElementsAre(RtpSource(kTime1, kCsrc1, RtpSourceType::CSRC),
-                           RtpSource(kTime1, kCsrc2, RtpSourceType::CSRC)));
+      UnorderedElementsAre(RtpSource(kTime1, kCsrc1, RtpSourceType::CSRC,
+                                     absl::nullopt, kRtpTimestamp1),
+                           RtpSource(kTime1, kCsrc2, RtpSourceType::CSRC,
+                                     absl::nullopt, kRtpTimestamp1)));
 }
 
 TEST(ContributingSourcesTest, UpdateSources) {
@@ -45,17 +50,22 @@
   constexpr uint32_t kCsrcs2[] = {kCsrc2, kCsrc3};
   constexpr int64_t kTime1 = 10;
   constexpr int64_t kTime2 = kTime1 + 5 * rtc::kNumMillisecsPerSec;
-  csrcs.Update(kTime1, kCsrcs1, absl::nullopt);
+  csrcs.Update(kTime1, kCsrcs1, absl::nullopt, kRtpTimestamp1);
   EXPECT_THAT(
       csrcs.GetSources(kTime1),
-      UnorderedElementsAre(RtpSource(kTime1, kCsrc1, RtpSourceType::CSRC),
-                           RtpSource(kTime1, kCsrc2, RtpSourceType::CSRC)));
-  csrcs.Update(kTime2, kCsrcs2, absl::nullopt);
+      UnorderedElementsAre(RtpSource(kTime1, kCsrc1, RtpSourceType::CSRC,
+                                     absl::nullopt, kRtpTimestamp1),
+                           RtpSource(kTime1, kCsrc2, RtpSourceType::CSRC,
+                                     absl::nullopt, kRtpTimestamp1)));
+  csrcs.Update(kTime2, kCsrcs2, absl::nullopt, kRtpTimestamp2);
   EXPECT_THAT(
       csrcs.GetSources(kTime2),
-      UnorderedElementsAre(RtpSource(kTime1, kCsrc1, RtpSourceType::CSRC),
-                           RtpSource(kTime2, kCsrc2, RtpSourceType::CSRC),
-                           RtpSource(kTime2, kCsrc3, RtpSourceType::CSRC)));
+      UnorderedElementsAre(RtpSource(kTime1, kCsrc1, RtpSourceType::CSRC,
+                                     absl::nullopt, kRtpTimestamp1),
+                           RtpSource(kTime2, kCsrc2, RtpSourceType::CSRC,
+                                     absl::nullopt, kRtpTimestamp2),
+                           RtpSource(kTime2, kCsrc3, RtpSourceType::CSRC,
+                                     absl::nullopt, kRtpTimestamp2)));
 }
 
 TEST(ContributingSourcesTest, ReturnRecentOnly) {
@@ -65,16 +75,20 @@
   constexpr int64_t kTime1 = 10;
   constexpr int64_t kTime2 = kTime1 + 5 * rtc::kNumMillisecsPerSec;
   constexpr int64_t kTime3 = kTime1 + 12 * rtc::kNumMillisecsPerSec;
-  csrcs.Update(kTime1, kCsrcs1, absl::nullopt);
+  csrcs.Update(kTime1, kCsrcs1, absl::nullopt, kRtpTimestamp1);
   EXPECT_THAT(
       csrcs.GetSources(kTime1),
-      UnorderedElementsAre(RtpSource(kTime1, kCsrc1, RtpSourceType::CSRC),
-                           RtpSource(kTime1, kCsrc2, RtpSourceType::CSRC)));
-  csrcs.Update(kTime2, kCsrcs2, absl::nullopt);
+      UnorderedElementsAre(RtpSource(kTime1, kCsrc1, RtpSourceType::CSRC,
+                                     absl::nullopt, kRtpTimestamp1),
+                           RtpSource(kTime1, kCsrc2, RtpSourceType::CSRC,
+                                     absl::nullopt, kRtpTimestamp1)));
+  csrcs.Update(kTime2, kCsrcs2, absl::nullopt, kRtpTimestamp2);
   EXPECT_THAT(
       csrcs.GetSources(kTime3),
-      UnorderedElementsAre(RtpSource(kTime2, kCsrc2, RtpSourceType::CSRC),
-                           RtpSource(kTime2, kCsrc3, RtpSourceType::CSRC)));
+      UnorderedElementsAre(RtpSource(kTime2, kCsrc2, RtpSourceType::CSRC,
+                                     absl::nullopt, kRtpTimestamp2),
+                           RtpSource(kTime2, kCsrc3, RtpSourceType::CSRC,
+                                     absl::nullopt, kRtpTimestamp2)));
 }
 
 TEST(ContributingSourcesTest, PurgeOldSources) {
@@ -84,46 +98,58 @@
   constexpr int64_t kTime1 = 10;
   constexpr int64_t kTime2 = kTime1 + 10 * rtc::kNumMillisecsPerSec;
   constexpr int64_t kTime3 = kTime1 + 20 * rtc::kNumMillisecsPerSec;
-  csrcs.Update(kTime1, kCsrcs1, absl::nullopt);
+  csrcs.Update(kTime1, kCsrcs1, absl::nullopt, kRtpTimestamp1);
   EXPECT_THAT(
       csrcs.GetSources(kTime2),
-      UnorderedElementsAre(RtpSource(kTime1, kCsrc1, RtpSourceType::CSRC),
-                           RtpSource(kTime1, kCsrc2, RtpSourceType::CSRC)));
-  csrcs.Update(kTime2, kCsrcs2, absl::nullopt);
+      UnorderedElementsAre(RtpSource(kTime1, kCsrc1, RtpSourceType::CSRC,
+                                     absl::nullopt, kRtpTimestamp1),
+                           RtpSource(kTime1, kCsrc2, RtpSourceType::CSRC,
+                                     absl::nullopt, kRtpTimestamp1)));
+  csrcs.Update(kTime2, kCsrcs2, absl::nullopt, kRtpTimestamp2);
   EXPECT_THAT(
       csrcs.GetSources(kTime2),
-      UnorderedElementsAre(RtpSource(kTime1, kCsrc1, RtpSourceType::CSRC),
-                           RtpSource(kTime2, kCsrc2, RtpSourceType::CSRC),
-                           RtpSource(kTime2, kCsrc3, RtpSourceType::CSRC)));
-  csrcs.Update(kTime3, kCsrcs2, absl::nullopt);
+      UnorderedElementsAre(RtpSource(kTime1, kCsrc1, RtpSourceType::CSRC,
+                                     absl::nullopt, kRtpTimestamp1),
+                           RtpSource(kTime2, kCsrc2, RtpSourceType::CSRC,
+                                     absl::nullopt, kRtpTimestamp2),
+                           RtpSource(kTime2, kCsrc3, RtpSourceType::CSRC,
+                                     absl::nullopt, kRtpTimestamp2)));
+  csrcs.Update(kTime3, kCsrcs2, absl::nullopt, kRtpTimestamp3);
   EXPECT_THAT(
       csrcs.GetSources(kTime3),
-      UnorderedElementsAre(RtpSource(kTime3, kCsrc2, RtpSourceType::CSRC),
-                           RtpSource(kTime3, kCsrc3, RtpSourceType::CSRC)));
+      UnorderedElementsAre(RtpSource(kTime3, kCsrc2, RtpSourceType::CSRC,
+                                     absl::nullopt, kRtpTimestamp3),
+                           RtpSource(kTime3, kCsrc3, RtpSourceType::CSRC,
+                                     absl::nullopt, kRtpTimestamp3)));
   // Query at an earlier time; check that old sources really have been purged
   // and don't reappear.
   EXPECT_THAT(
       csrcs.GetSources(kTime2),
-      UnorderedElementsAre(RtpSource(kTime3, kCsrc2, RtpSourceType::CSRC),
-                           RtpSource(kTime3, kCsrc3, RtpSourceType::CSRC)));
+      UnorderedElementsAre(RtpSource(kTime3, kCsrc2, RtpSourceType::CSRC,
+                                     absl::nullopt, kRtpTimestamp3),
+                           RtpSource(kTime3, kCsrc3, RtpSourceType::CSRC,
+                                     absl::nullopt, kRtpTimestamp3)));
 }
 
 TEST(ContributingSourcesTest, AudioLevel) {
   ContributingSources csrcs;
   constexpr uint32_t kCsrcs[] = {kCsrc1, kCsrc2};
   constexpr int64_t kTime1 = 10;
-  csrcs.Update(kTime1, kCsrcs, 47);
+  csrcs.Update(kTime1, kCsrcs, 47, kRtpTimestamp1);
   EXPECT_THAT(
       csrcs.GetSources(kTime1),
-      UnorderedElementsAre(RtpSource(kTime1, kCsrc1, RtpSourceType::CSRC, 47),
-                           RtpSource(kTime1, kCsrc2, RtpSourceType::CSRC, 47)));
+      UnorderedElementsAre(
+          RtpSource(kTime1, kCsrc1, RtpSourceType::CSRC, 47, kRtpTimestamp1),
+          RtpSource(kTime1, kCsrc2, RtpSourceType::CSRC, 47, kRtpTimestamp1)));
 
   constexpr uint32_t kCsrcsSubset[] = {kCsrc1};
-  csrcs.Update(kTime1 + 1, kCsrcsSubset, absl::nullopt);
+  csrcs.Update(kTime1 + 1, kCsrcsSubset, absl::nullopt, kRtpTimestamp2);
   EXPECT_THAT(
       csrcs.GetSources(kTime1 + 1),
-      UnorderedElementsAre(RtpSource(kTime1 + 1, kCsrc1, RtpSourceType::CSRC),
-                           RtpSource(kTime1, kCsrc2, RtpSourceType::CSRC, 47)));
+      UnorderedElementsAre(
+          RtpSource(kTime1 + 1, kCsrc1, RtpSourceType::CSRC, absl::nullopt,
+                    kRtpTimestamp2),
+          RtpSource(kTime1, kCsrc2, RtpSourceType::CSRC, 47, kRtpTimestamp1)));
 }
 
 }  // namespace webrtc
diff --git a/video/rtp_video_stream_receiver.cc b/video/rtp_video_stream_receiver.cc
index 305b8bd..edced5d 100644
--- a/video/rtp_video_stream_receiver.cc
+++ b/video/rtp_video_stream_receiver.cc
@@ -326,7 +326,8 @@
 
       std::vector<uint32_t> csrcs = packet.Csrcs();
       contributing_sources_.Update(now_ms, csrcs,
-                                   /* audio level */ absl::nullopt);
+                                   /* audio level */ absl::nullopt,
+                                   packet.Timestamp());
     }
     // Periodically log the RTP header of incoming packets.
     if (now_ms - last_packet_log_ms_ > kPacketLogIntervalMs) {
@@ -781,8 +782,11 @@
     sources = contributing_sources_.GetSources(now_ms);
     if (last_received_rtp_system_time_ms_ >=
         now_ms - ContributingSources::kHistoryMs) {
+      RTC_DCHECK(last_received_rtp_timestamp_.has_value());
       sources.emplace_back(*last_received_rtp_system_time_ms_,
-                           config_.rtp.remote_ssrc, RtpSourceType::SSRC);
+                           config_.rtp.remote_ssrc, RtpSourceType::SSRC,
+                           /* audio_level */ absl::nullopt,
+                           *last_received_rtp_timestamp_);
     }
   }
   return sources;