Use absolute capture timestamp from the beginning of payload

This ensure the absolute capture timestamp from the first audio sample
encoded in the payload is used for the corresponding rtp header.

Bug: webrtc:42226041
Change-Id: Ib8f2e3a5df5c82c5806171bd5b36a26d92fbea72
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/349265
Commit-Queue: Lionel Koenig <lionelk@webrtc.org>
Reviewed-by: Jakob Ivarsson‎ <jakobi@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#42281}
diff --git a/modules/audio_coding/acm2/audio_coding_module.cc b/modules/audio_coding/acm2/audio_coding_module.cc
index 97a204a..3635701 100644
--- a/modules/audio_coding/acm2/audio_coding_module.cc
+++ b/modules/audio_coding/acm2/audio_coding_module.cc
@@ -152,6 +152,8 @@
   bool first_frame_ RTC_GUARDED_BY(acm_mutex_);
   uint32_t last_timestamp_ RTC_GUARDED_BY(acm_mutex_);
   uint32_t last_rtp_timestamp_ RTC_GUARDED_BY(acm_mutex_);
+  absl::optional<int64_t> absolute_capture_timestamp_ms_
+      RTC_GUARDED_BY(acm_mutex_);
 
   Mutex callback_mutex_;
   AudioPacketizationCallback* packetization_callback_
@@ -225,6 +227,10 @@
   last_rtp_timestamp_ = rtp_timestamp;
   first_frame_ = false;
 
+  if (!absolute_capture_timestamp_ms_.has_value()) {
+    absolute_capture_timestamp_ms_ = absolute_capture_timestamp_ms;
+  }
+
   // Clear the buffer before reuse - encoded data will get appended.
   encode_buffer_.Clear();
   encoded_info = encoder_stack_->Encode(
@@ -271,9 +277,10 @@
       packetization_callback_->SendData(
           frame_type, encoded_info.payload_type, encoded_info.encoded_timestamp,
           encode_buffer_.data(), encode_buffer_.size(),
-          absolute_capture_timestamp_ms.value_or(-1));
+          absolute_capture_timestamp_ms_.value_or(-1));
     }
   }
+  absolute_capture_timestamp_ms_ = absl::nullopt;
   previous_pltype_ = encoded_info.payload_type;
   return static_cast<int32_t>(encode_buffer_.size());
 }
diff --git a/modules/audio_coding/acm2/audio_coding_module_unittest.cc b/modules/audio_coding/acm2/audio_coding_module_unittest.cc
index 2d9ea91..498e5aa 100644
--- a/modules/audio_coding/acm2/audio_coding_module_unittest.cc
+++ b/modules/audio_coding/acm2/audio_coding_module_unittest.cc
@@ -506,6 +506,83 @@
   EXPECT_TRUE(RunTest());
 }
 
+class AudioPacketizationCallbackMock : public AudioPacketizationCallback {
+ public:
+  MOCK_METHOD(int32_t,
+              SendData,
+              (AudioFrameType frame_type,
+               uint8_t payload_type,
+               uint32_t timestamp,
+               const uint8_t* payload_data,
+               size_t payload_len_bytes,
+               int64_t absolute_capture_timestamp_ms),
+              (override));
+};
+
+class AcmAbsoluteCaptureTimestamp : public ::testing::Test {
+ public:
+  AcmAbsoluteCaptureTimestamp() : audio_frame_(kSampleRateHz, kNumChannels) {}
+
+ protected:
+  static constexpr int kPTimeMs = 20;
+  static constexpr int kSampleRateHz = 48000;
+  static constexpr int kFrameSize = kSampleRateHz / 100;
+  static constexpr int kNumChannels = 2;
+
+  void SetUp() {
+    rtc::scoped_refptr<AudioEncoderFactory> codec_factory =
+        CreateBuiltinAudioEncoderFactory();
+    acm_ = AudioCodingModule::Create();
+    std::unique_ptr<AudioEncoder> encoder = codec_factory->MakeAudioEncoder(
+        111, SdpAudioFormat("OPUS", kSampleRateHz, kNumChannels),
+        absl::nullopt);
+    encoder->SetDtx(true);
+    encoder->SetReceiverFrameLengthRange(kPTimeMs, kPTimeMs);
+    acm_->SetEncoder(std::move(encoder));
+    acm_->RegisterTransportCallback(&transport_);
+    for (size_t k = 0; k < audio_.size(); ++k) {
+      audio_[k] = 10 * k;
+    }
+  }
+
+  const AudioFrame& GetAudioWithAbsoluteCaptureTimestamp(
+      int64_t absolute_capture_timestamp_ms) {
+    audio_frame_.ResetWithoutMuting();
+    audio_frame_.UpdateFrame(timestamp_, audio_.data(), kFrameSize,
+                             kSampleRateHz,
+                             AudioFrame::SpeechType::kNormalSpeech,
+                             AudioFrame::VADActivity::kVadActive, kNumChannels);
+    audio_frame_.set_absolute_capture_timestamp_ms(
+        absolute_capture_timestamp_ms);
+    timestamp_ += kFrameSize;
+    return audio_frame_;
+  }
+
+  std::unique_ptr<AudioCodingModule> acm_;
+  AudioPacketizationCallbackMock transport_;
+  AudioFrame audio_frame_;
+  std::array<int16_t, kFrameSize * kNumChannels> audio_;
+  uint32_t timestamp_ = 9873546;
+};
+
+TEST_F(AcmAbsoluteCaptureTimestamp, HaveBeginningOfFrameCaptureTime) {
+  constexpr int64_t first_absolute_capture_timestamp_ms = 123456789;
+
+  int64_t absolute_capture_timestamp_ms = first_absolute_capture_timestamp_ms;
+  EXPECT_CALL(transport_,
+              SendData(_, _, _, _, _, first_absolute_capture_timestamp_ms))
+      .Times(1);
+  EXPECT_CALL(
+      transport_,
+      SendData(_, _, _, _, _, first_absolute_capture_timestamp_ms + kPTimeMs))
+      .Times(1);
+  for (int k = 0; k < 5; ++k) {
+    acm_->Add10MsData(
+        GetAudioWithAbsoluteCaptureTimestamp(absolute_capture_timestamp_ms));
+    absolute_capture_timestamp_ms += 10;
+  }
+}
+
 // Disabling all of these tests on iOS until file support has been added.
 // See https://code.google.com/p/webrtc/issues/detail?id=4752 for details.
 #if !defined(WEBRTC_IOS)