Allow to negotiate absolute capture time rtp header extension.

Bug: webrtc:10739
Change-Id: I239d67a8c02bcc4175b142174b254e876bdd8d6d
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/169920
Commit-Queue: Minyue Li <minyue@webrtc.org>
Reviewed-by: Danil Chapovalov <danilchap@webrtc.org>
Reviewed-by: Henrik Boström <hbos@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#30746}
diff --git a/pc/media_session.cc b/pc/media_session.cc
index 05c421e..110258d 100644
--- a/pc/media_session.cc
+++ b/pc/media_session.cc
@@ -1075,11 +1075,15 @@
 
   bool frame_descriptor_in_local = false;
   bool dependency_descriptor_in_local = false;
+  bool abs_capture_time_in_local = false;
+
   for (const webrtc::RtpExtension& ours : local_extensions) {
     if (ours.uri == webrtc::RtpExtension::kGenericFrameDescriptorUri00)
       frame_descriptor_in_local = true;
     else if (ours.uri == webrtc::RtpExtension::kDependencyDescriptorUri)
       dependency_descriptor_in_local = true;
+    else if (ours.uri == webrtc::RtpExtension::kAbsoluteCaptureTimeUri)
+      abs_capture_time_in_local = true;
     webrtc::RtpExtension theirs;
     if (FindByUriWithEncryptionPreference(
             offered_extensions, ours.uri,
@@ -1119,6 +1123,15 @@
           enable_encrypted_rtp_header_extensions, &theirs)) {
     negotiated_extensions->push_back(theirs);
   }
+
+  // Absolute capture time support. If the extension is not present locally, but
+  // is in the offer, we add it to the list.
+  if (!abs_capture_time_in_local &&
+      FindByUriWithEncryptionPreference(
+          offered_extensions, webrtc::RtpExtension::kAbsoluteCaptureTimeUri,
+          enable_encrypted_rtp_header_extensions, &theirs)) {
+    negotiated_extensions->push_back(theirs);
+  }
 }
 
 static void StripCNCodecs(AudioCodecs* audio_codecs) {
diff --git a/pc/media_session_unittest.cc b/pc/media_session_unittest.cc
index b217051..41e2767 100644
--- a/pc/media_session_unittest.cc
+++ b/pc/media_session_unittest.cc
@@ -1757,6 +1757,81 @@
 }
 
 TEST_F(MediaSessionDescriptionFactoryTest,
+       NegotiateAbsoluteCaptureTimeWhenUnexposedLocally) {
+  MediaSessionOptions opts;
+  AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
+
+  const cricket::RtpHeaderExtensions offered_extensions = {
+      RtpExtension(RtpExtension::kAbsoluteCaptureTimeUri, 7)};
+  const cricket::RtpHeaderExtensions local_extensions = {
+      RtpExtension(RtpExtension::kTransportSequenceNumberUri, 5)};
+  f1_.set_video_rtp_header_extensions(offered_extensions);
+  f1_.set_audio_rtp_header_extensions(offered_extensions);
+  f2_.set_video_rtp_header_extensions(local_extensions);
+  f2_.set_audio_rtp_header_extensions(local_extensions);
+
+  std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
+  std::unique_ptr<SessionDescription> answer =
+      f2_.CreateAnswer(offer.get(), opts, nullptr);
+  EXPECT_THAT(
+      GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
+      ElementsAreArray(offered_extensions));
+  EXPECT_THAT(
+      GetFirstAudioContentDescription(answer.get())->rtp_header_extensions(),
+      ElementsAreArray(offered_extensions));
+}
+
+TEST_F(MediaSessionDescriptionFactoryTest,
+       NegotiateAbsoluteCaptureTimeWhenExposedLocally) {
+  MediaSessionOptions opts;
+  AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
+
+  const cricket::RtpHeaderExtensions offered_extensions = {
+      RtpExtension(RtpExtension::kAbsoluteCaptureTimeUri, 7)};
+  const cricket::RtpHeaderExtensions local_extensions = {
+      RtpExtension(RtpExtension::kAbsoluteCaptureTimeUri, 5)};
+  f1_.set_video_rtp_header_extensions(offered_extensions);
+  f1_.set_audio_rtp_header_extensions(offered_extensions);
+  f2_.set_video_rtp_header_extensions(local_extensions);
+  f2_.set_audio_rtp_header_extensions(local_extensions);
+
+  std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
+  std::unique_ptr<SessionDescription> answer =
+      f2_.CreateAnswer(offer.get(), opts, nullptr);
+  EXPECT_THAT(
+      GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
+      ElementsAreArray(offered_extensions));
+  EXPECT_THAT(
+      GetFirstAudioContentDescription(answer.get())->rtp_header_extensions(),
+      ElementsAreArray(offered_extensions));
+}
+
+TEST_F(MediaSessionDescriptionFactoryTest,
+       DoNotNegotiateAbsoluteCaptureTimeWhenNotOffered) {
+  MediaSessionOptions opts;
+  AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);
+
+  const cricket::RtpHeaderExtensions offered_extensions = {
+      RtpExtension(RtpExtension::kTransportSequenceNumberUri, 7)};
+  const cricket::RtpHeaderExtensions local_extensions = {
+      RtpExtension(RtpExtension::kAbsoluteCaptureTimeUri, 5)};
+  f1_.set_video_rtp_header_extensions(offered_extensions);
+  f1_.set_audio_rtp_header_extensions(offered_extensions);
+  f2_.set_video_rtp_header_extensions(local_extensions);
+  f2_.set_audio_rtp_header_extensions(local_extensions);
+
+  std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
+  std::unique_ptr<SessionDescription> answer =
+      f2_.CreateAnswer(offer.get(), opts, nullptr);
+  EXPECT_THAT(
+      GetFirstVideoContentDescription(answer.get())->rtp_header_extensions(),
+      IsEmpty());
+  EXPECT_THAT(
+      GetFirstAudioContentDescription(answer.get())->rtp_header_extensions(),
+      IsEmpty());
+}
+
+TEST_F(MediaSessionDescriptionFactoryTest,
        TestOfferAnswerWithEncryptedRtpExtensionsBoth) {
   MediaSessionOptions opts;
   AddAudioVideoSections(RtpTransceiverDirection::kRecvOnly, &opts);