diff --git a/pc/media_session.cc b/pc/media_session.cc index 05c421ed51..110258d2b3 100644 --- a/pc/media_session.cc +++ b/pc/media_session.cc @@ -1075,11 +1075,15 @@ static void NegotiateRtpHeaderExtensions( 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 @@ static void NegotiateRtpHeaderExtensions( 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 b217051054..41e2767601 100644 --- a/pc/media_session_unittest.cc +++ b/pc/media_session_unittest.cc @@ -1756,6 +1756,81 @@ TEST_F(MediaSessionDescriptionFactoryTest, ElementsAre(offer_dd)); } +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 offer = f1_.CreateOffer(opts, nullptr); + std::unique_ptr 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 offer = f1_.CreateOffer(opts, nullptr); + std::unique_ptr 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 offer = f1_.CreateOffer(opts, nullptr); + std::unique_ptr 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;