Add estimatedPlayoutTimestamp to RTCInboundRTPStreamStats.

https://w3c.github.io/webrtc-stats/#dom-rtcinboundrtpstreamstats-estimatedplayouttimestamp

Partial implementation: currently only populated when a/v sync is enabled.

Bug: webrtc:7065
Change-Id: I8595cc848d080d7c3bef152462a9becf0e5a2196
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/155621
Commit-Queue: Åsa Persson <asapersson@webrtc.org>
Reviewed-by: Oskar Sundbom <ossu@webrtc.org>
Reviewed-by: Henrik Boström <hbos@webrtc.org>
Reviewed-by: Niels Moller <nisse@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#29581}
diff --git a/audio/audio_receive_stream.cc b/audio/audio_receive_stream.cc
index 190693c..c6291c7 100644
--- a/audio/audio_receive_stream.cc
+++ b/audio/audio_receive_stream.cc
@@ -206,6 +206,9 @@
   stats.audio_level = channel_receive_->GetSpeechOutputLevelFullRange();
   stats.total_output_energy = channel_receive_->GetTotalOutputEnergy();
   stats.total_output_duration = channel_receive_->GetTotalOutputDuration();
+  stats.estimated_playout_ntp_timestamp_ms =
+      channel_receive_->GetCurrentEstimatedPlayoutNtpTimestampMs(
+          rtc::TimeMillis());
 
   // Get jitter buffer and total delay (alg + jitter + playout) stats.
   auto ns = channel_receive_->GetNetworkStatistics();
@@ -310,9 +313,18 @@
   return info;
 }
 
-uint32_t AudioReceiveStream::GetPlayoutTimestamp() const {
+bool AudioReceiveStream::GetPlayoutRtpTimestamp(uint32_t* rtp_timestamp,
+                                                int64_t* time_ms) const {
   // Called on video capture thread.
-  return channel_receive_->GetPlayoutTimestamp();
+  return channel_receive_->GetPlayoutRtpTimestamp(rtp_timestamp, time_ms);
+}
+
+void AudioReceiveStream::SetEstimatedPlayoutNtpTimestampMs(
+    int64_t ntp_timestamp_ms,
+    int64_t time_ms) {
+  // Called on video capture thread.
+  channel_receive_->SetEstimatedPlayoutNtpTimestampMs(ntp_timestamp_ms,
+                                                      time_ms);
 }
 
 void AudioReceiveStream::SetMinimumPlayoutDelay(int delay_ms) {
diff --git a/audio/audio_receive_stream.h b/audio/audio_receive_stream.h
index 86301a3..26bcf63 100644
--- a/audio/audio_receive_stream.h
+++ b/audio/audio_receive_stream.h
@@ -87,7 +87,10 @@
   // Syncable
   int id() const override;
   absl::optional<Syncable::Info> GetInfo() const override;
-  uint32_t GetPlayoutTimestamp() const override;
+  bool GetPlayoutRtpTimestamp(uint32_t* rtp_timestamp,
+                              int64_t* time_ms) const override;
+  void SetEstimatedPlayoutNtpTimestampMs(int64_t ntp_timestamp_ms,
+                                         int64_t time_ms) override;
   void SetMinimumPlayoutDelay(int delay_ms) override;
 
   void AssociateSendStream(AudioSendStream* send_stream);
diff --git a/audio/audio_receive_stream_unittest.cc b/audio/audio_receive_stream_unittest.cc
index ae6605c..473b387 100644
--- a/audio/audio_receive_stream_unittest.cc
+++ b/audio/audio_receive_stream_unittest.cc
@@ -62,6 +62,7 @@
 const unsigned int kSpeechOutputLevel = 99;
 const double kTotalOutputEnergy = 0.25;
 const double kTotalOutputDuration = 0.5;
+const int64_t kPlayoutNtpTimestampMs = 5678;
 
 const CallReceiveStatistics kCallStats = {678, 234, -12, 567, 78, 890, 123};
 const std::pair<int, SdpAudioFormat> kReceiveCodec = {
@@ -145,6 +146,8 @@
         .WillOnce(Return(kAudioDecodeStats));
     EXPECT_CALL(*channel_receive_, GetReceiveCodec())
         .WillOnce(Return(kReceiveCodec));
+    EXPECT_CALL(*channel_receive_, GetCurrentEstimatedPlayoutNtpTimestampMs(_))
+        .WillOnce(Return(kPlayoutNtpTimestampMs));
   }
 
  private:
@@ -315,6 +318,7 @@
             stats.decoding_muted_output);
   EXPECT_EQ(kCallStats.capture_start_ntp_time_ms_,
             stats.capture_start_ntp_time_ms);
+  EXPECT_EQ(kPlayoutNtpTimestampMs, stats.estimated_playout_ntp_timestamp_ms);
 }
 
 TEST(AudioReceiveStreamTest, SetGain) {
diff --git a/audio/channel_receive.cc b/audio/channel_receive.cc
index fa1463a..7fe41a1 100644
--- a/audio/channel_receive.cc
+++ b/audio/channel_receive.cc
@@ -141,7 +141,12 @@
   // Audio+Video Sync.
   uint32_t GetDelayEstimate() const override;
   void SetMinimumPlayoutDelay(int delayMs) override;
-  uint32_t GetPlayoutTimestamp() const override;
+  bool GetPlayoutRtpTimestamp(uint32_t* rtp_timestamp,
+                              int64_t* time_ms) const override;
+  void SetEstimatedPlayoutNtpTimestampMs(int64_t ntp_timestamp_ms,
+                                         int64_t time_ms) override;
+  absl::optional<int64_t> GetCurrentEstimatedPlayoutNtpTimestampMs(
+      int64_t now_ms) const override;
 
   // Audio quality.
   bool SetBaseMinimumPlayoutDelayMs(int delay_ms) override;
@@ -178,7 +183,7 @@
                      size_t packet_length,
                      const RTPHeader& header);
   int ResendPackets(const uint16_t* sequence_numbers, int length);
-  void UpdatePlayoutTimestamp(bool rtcp);
+  void UpdatePlayoutTimestamp(bool rtcp, int64_t now_ms);
 
   int GetRtpTimestampRateHz() const;
   int64_t GetRTT() const;
@@ -242,7 +247,13 @@
 
   rtc::CriticalSection video_sync_lock_;
   uint32_t playout_timestamp_rtp_ RTC_GUARDED_BY(video_sync_lock_);
+  absl::optional<int64_t> playout_timestamp_rtp_time_ms_
+      RTC_GUARDED_BY(video_sync_lock_);
   uint32_t playout_delay_ms_ RTC_GUARDED_BY(video_sync_lock_);
+  absl::optional<int64_t> playout_timestamp_ntp_
+      RTC_GUARDED_BY(video_sync_lock_);
+  absl::optional<int64_t> playout_timestamp_ntp_time_ms_
+      RTC_GUARDED_BY(video_sync_lock_);
 
   rtc::CriticalSection ts_stats_lock_;
 
@@ -573,7 +584,7 @@
   }
 
   // Store playout timestamp for the received RTP packet
-  UpdatePlayoutTimestamp(false);
+  UpdatePlayoutTimestamp(false, now_ms);
 
   const auto& it = payload_type_frequencies_.find(packet.PayloadType());
   if (it == payload_type_frequencies_.end())
@@ -638,7 +649,7 @@
 // May be called on either worker thread or network thread.
 void ChannelReceive::ReceivedRTCPPacket(const uint8_t* data, size_t length) {
   // Store playout timestamp for the received RTCP packet
-  UpdatePlayoutTimestamp(true);
+  UpdatePlayoutTimestamp(true, rtc::TimeMillis());
 
   // Deliver RTCP packet to RTP/RTCP module for parsing
   _rtpRtcpModule->IncomingRtcpPacket(data, length);
@@ -806,14 +817,38 @@
   }
 }
 
-uint32_t ChannelReceive::GetPlayoutTimestamp() const {
+bool ChannelReceive::GetPlayoutRtpTimestamp(uint32_t* rtp_timestamp,
+                                            int64_t* time_ms) const {
   RTC_DCHECK_RUNS_SERIALIZED(&video_capture_thread_race_checker_);
   {
     rtc::CritScope lock(&video_sync_lock_);
-    return playout_timestamp_rtp_;
+    if (!playout_timestamp_rtp_time_ms_)
+      return false;
+    *rtp_timestamp = playout_timestamp_rtp_;
+    *time_ms = playout_timestamp_rtp_time_ms_.value();
+    return true;
   }
 }
 
+void ChannelReceive::SetEstimatedPlayoutNtpTimestampMs(int64_t ntp_timestamp_ms,
+                                                       int64_t time_ms) {
+  RTC_DCHECK_RUNS_SERIALIZED(&video_capture_thread_race_checker_);
+  rtc::CritScope lock(&video_sync_lock_);
+  playout_timestamp_ntp_ = ntp_timestamp_ms;
+  playout_timestamp_ntp_time_ms_ = time_ms;
+}
+
+absl::optional<int64_t>
+ChannelReceive::GetCurrentEstimatedPlayoutNtpTimestampMs(int64_t now_ms) const {
+  RTC_DCHECK(worker_thread_checker_.IsCurrent());
+  rtc::CritScope lock(&video_sync_lock_);
+  if (!playout_timestamp_ntp_ || !playout_timestamp_ntp_time_ms_)
+    return absl::nullopt;
+
+  int64_t elapsed_ms = now_ms - *playout_timestamp_ntp_time_ms_;
+  return *playout_timestamp_ntp_ + elapsed_ms;
+}
+
 bool ChannelReceive::SetBaseMinimumPlayoutDelayMs(int delay_ms) {
   return acm_receiver_.SetBaseMinimumDelayMs(delay_ms);
 }
@@ -841,7 +876,7 @@
   return info;
 }
 
-void ChannelReceive::UpdatePlayoutTimestamp(bool rtcp) {
+void ChannelReceive::UpdatePlayoutTimestamp(bool rtcp, int64_t now_ms) {
   jitter_buffer_playout_timestamp_ = acm_receiver_.GetPlayoutTimestamp();
 
   if (!jitter_buffer_playout_timestamp_) {
@@ -868,6 +903,7 @@
     rtc::CritScope lock(&video_sync_lock_);
     if (!rtcp) {
       playout_timestamp_rtp_ = playout_timestamp;
+      playout_timestamp_rtp_time_ms_ = now_ms;
     }
     playout_delay_ms_ = delay_ms;
   }
diff --git a/audio/channel_receive.h b/audio/channel_receive.h
index 5f71ea3..fb79dc2 100644
--- a/audio/channel_receive.h
+++ b/audio/channel_receive.h
@@ -105,7 +105,12 @@
   // Audio+Video Sync.
   virtual uint32_t GetDelayEstimate() const = 0;
   virtual void SetMinimumPlayoutDelay(int delay_ms) = 0;
-  virtual uint32_t GetPlayoutTimestamp() const = 0;
+  virtual bool GetPlayoutRtpTimestamp(uint32_t* rtp_timestamp,
+                                      int64_t* time_ms) const = 0;
+  virtual void SetEstimatedPlayoutNtpTimestampMs(int64_t ntp_timestamp_ms,
+                                                 int64_t time_ms) = 0;
+  virtual absl::optional<int64_t> GetCurrentEstimatedPlayoutNtpTimestampMs(
+      int64_t now_ms) const = 0;
 
   // Audio quality.
   // Base minimum delay sets lower bound on minimum delay value which
diff --git a/audio/mock_voe_channel_proxy.h b/audio/mock_voe_channel_proxy.h
index e666bf2..d61bc89 100644
--- a/audio/mock_voe_channel_proxy.h
+++ b/audio/mock_voe_channel_proxy.h
@@ -49,7 +49,12 @@
   MOCK_CONST_METHOD0(PreferredSampleRate, int());
   MOCK_METHOD1(SetAssociatedSendChannel,
                void(const voe::ChannelSendInterface* send_channel));
-  MOCK_CONST_METHOD0(GetPlayoutTimestamp, uint32_t());
+  MOCK_CONST_METHOD2(GetPlayoutRtpTimestamp,
+                     bool(uint32_t* rtp_timestamp, int64_t* time_ms));
+  MOCK_METHOD2(SetEstimatedPlayoutNtpTimestampMs,
+               void(int64_t ntp_timestamp_ms, int64_t time_ms));
+  MOCK_CONST_METHOD1(GetCurrentEstimatedPlayoutNtpTimestampMs,
+                     absl::optional<int64_t>(int64_t now_ms));
   MOCK_CONST_METHOD0(GetSyncInfo, absl::optional<Syncable::Info>());
   MOCK_METHOD1(SetMinimumPlayoutDelay, void(int delay_ms));
   MOCK_METHOD1(SetBaseMinimumPlayoutDelayMs, bool(int delay_ms));