diff --git a/modules/rtp_rtcp/BUILD.gn b/modules/rtp_rtcp/BUILD.gn index f7ce1ab936..4b195f2198 100644 --- a/modules/rtp_rtcp/BUILD.gn +++ b/modules/rtp_rtcp/BUILD.gn @@ -502,6 +502,7 @@ if (rtc_include_tests) { "../..:webrtc_common", "../../api:array_view", "../../api:libjingle_peerconnection_api", + "../../api:mock_frame_encryptor", "../../api:rtp_headers", "../../api:rtp_packet_info", "../../api:rtp_parameters", diff --git a/modules/rtp_rtcp/source/rtp_sender_video.cc b/modules/rtp_rtcp/source/rtp_sender_video.cc index 78ece7ffef..efc674c695 100644 --- a/modules/rtp_rtcp/source/rtp_sender_video.cc +++ b/modules/rtp_rtcp/source/rtp_sender_video.cc @@ -28,6 +28,7 @@ #include "modules/rtp_rtcp/source/absolute_capture_time_sender.h" #include "modules/rtp_rtcp/source/byte_io.h" #include "modules/rtp_rtcp/source/rtp_dependency_descriptor_extension.h" +#include "modules/rtp_rtcp/source/rtp_descriptor_authentication.h" #include "modules/rtp_rtcp/source/rtp_format.h" #include "modules/rtp_rtcp/source/rtp_generic_frame_descriptor_extension.h" #include "modules/rtp_rtcp/source/rtp_header_extensions.h" @@ -613,23 +614,24 @@ bool RTPSenderVideo::SendVideo( limits.last_packet_reduction_len = last_packet->headers_size() - middle_packet->headers_size(); - rtc::ArrayView generic_descriptor_raw_00 = - first_packet->GetRawExtension(); - rtc::ArrayView generic_descriptor_raw_01 = - first_packet->GetRawExtension(); + bool has_generic_descriptor_00 = + first_packet->HasExtension(); + bool has_generic_descriptor_01 = + first_packet->HasExtension(); + bool has_dependency_descriptor = + first_packet->HasExtension(); - if (!generic_descriptor_raw_00.empty() && - !generic_descriptor_raw_01.empty()) { + if (has_generic_descriptor_00 && has_generic_descriptor_01) { RTC_LOG(LS_WARNING) << "Two versions of GFD extension used."; return false; } - // Minimiazation of the vp8 descriptor may erase temporal_id, so save it. + // Minimization of the vp8 descriptor may erase temporal_id, so save it. const uint8_t temporal_id = GetTemporalId(video_header); - rtc::ArrayView generic_descriptor_raw = - !generic_descriptor_raw_01.empty() ? generic_descriptor_raw_01 - : generic_descriptor_raw_00; - if (!generic_descriptor_raw.empty()) { + bool has_generic_descriptor = has_generic_descriptor_00 || + has_generic_descriptor_01 || + has_dependency_descriptor; + if (has_generic_descriptor) { MinimizeDescriptor(&video_header); } @@ -645,7 +647,7 @@ bool RTPSenderVideo::SendVideo( // TODO(benwright@webrtc.org) - Allocate enough to always encrypt inline. rtc::Buffer encrypted_video_payload; if (frame_encryptor_ != nullptr) { - if (generic_descriptor_raw.empty()) { + if (!has_generic_descriptor) { return false; } @@ -657,9 +659,9 @@ bool RTPSenderVideo::SendVideo( size_t bytes_written = 0; // Enable header authentication if the field trial isn't disabled. - rtc::ArrayView additional_data; + std::vector additional_data; if (generic_descriptor_auth_experiment_) { - additional_data = generic_descriptor_raw; + additional_data = RtpDescriptorAuthentication(video_header); } if (frame_encryptor_->Encrypt( diff --git a/modules/rtp_rtcp/source/rtp_sender_video_unittest.cc b/modules/rtp_rtcp/source/rtp_sender_video_unittest.cc index af235afe2a..b185f0a26b 100644 --- a/modules/rtp_rtcp/source/rtp_sender_video_unittest.cc +++ b/modules/rtp_rtcp/source/rtp_sender_video_unittest.cc @@ -15,6 +15,7 @@ #include #include +#include "api/test/mock_frame_encryptor.h" #include "api/transport/rtp/dependency_descriptor.h" #include "api/video/video_codec_constants.h" #include "api/video/video_timing.h" @@ -39,16 +40,22 @@ namespace webrtc { namespace { +using ::testing::_; using ::testing::ElementsAre; +using ::testing::ElementsAreArray; using ::testing::IsEmpty; +using ::testing::NiceMock; +using ::testing::Return; +using ::testing::ReturnArg; using ::testing::SizeIs; +using ::testing::WithArgs; enum : int { // The first valid value is 1. kAbsoluteSendTimeExtensionId = 1, kFrameMarkingExtensionId, kGenericDescriptorId00, kGenericDescriptorId01, - kGenericDescriptorId02, + kDependencyDescriptorId, kTransmissionTimeOffsetExtensionId, kTransportSequenceNumberExtensionId, kVideoRotationExtensionId, @@ -83,7 +90,7 @@ class LoopbackTransportTest : public webrtc::Transport { receivers_extensions_.Register( kGenericDescriptorId01); receivers_extensions_.Register( - kGenericDescriptorId02); + kDependencyDescriptorId); receivers_extensions_.Register( kFrameMarkingExtensionId); receivers_extensions_.Register( @@ -537,7 +544,7 @@ TEST_P(RtpSenderVideoTest, SendsDependencyDescriptorWhenVideoStructureIsSet) { const int64_t kFrameId = 100000; uint8_t kFrame[100]; rtp_module_->RegisterRtpHeaderExtension( - RtpDependencyDescriptorExtension::kUri, kGenericDescriptorId02); + RtpDependencyDescriptorExtension::kUri, kDependencyDescriptorId); FrameDependencyStructure video_structure; video_structure.num_decode_targets = 2; video_structure.templates = { @@ -606,7 +613,7 @@ TEST_P(RtpSenderVideoTest, const int64_t kFrameId = 100000; uint8_t kFrame[100]; rtp_module_->RegisterRtpHeaderExtension( - RtpDependencyDescriptorExtension::kUri, kGenericDescriptorId02); + RtpDependencyDescriptorExtension::kUri, kDependencyDescriptorId); FrameDependencyStructure video_structure1; video_structure1.num_decode_targets = 2; video_structure1.templates = { @@ -675,6 +682,50 @@ TEST_P(RtpSenderVideoTest, descriptor_key2.attached_structure.get(), &descriptor_delta)); } +TEST_P(RtpSenderVideoTest, + AuthenticateVideoHeaderWhenDependencyDescriptorExtensionIsUsed) { + static constexpr size_t kFrameSize = 100; + uint8_t kFrame[kFrameSize] = {1, 2, 3, 4}; + + rtp_module_->RegisterRtpHeaderExtension( + RtpDependencyDescriptorExtension::kUri, kDependencyDescriptorId); + rtc::scoped_refptr encryptor( + new rtc::RefCountedObject>); + ON_CALL(*encryptor, GetMaxCiphertextByteSize).WillByDefault(ReturnArg<1>()); + ON_CALL(*encryptor, Encrypt) + .WillByDefault(WithArgs<3, 5>( + [](rtc::ArrayView frame, size_t* bytes_written) { + *bytes_written = frame.size(); + return 0; + })); + RTPSenderVideo::Config config; + config.clock = &fake_clock_; + config.rtp_sender = rtp_module_->RtpSender(); + config.field_trials = &field_trials_; + config.frame_encryptor = encryptor; + RTPSenderVideo rtp_sender_video(config); + + FrameDependencyStructure video_structure; + video_structure.num_decode_targets = 1; + video_structure.templates = {GenericFrameInfo::Builder().Dtis("S").Build()}; + rtp_sender_video.SetVideoStructure(&video_structure); + + // Send key frame. + RTPVideoHeader hdr; + hdr.frame_type = VideoFrameType::kVideoFrameKey; + hdr.generic.emplace().decode_target_indications = + video_structure.templates[0].decode_target_indications; + + EXPECT_CALL(*encryptor, + Encrypt(_, _, Not(IsEmpty()), ElementsAreArray(kFrame), _, _)); + rtp_sender_video.SendVideo(kPayload, kType, kTimestamp, 0, kFrame, nullptr, + hdr, kDefaultExpectedRetransmissionTimeMs); + // Double check packet with the dependency descriptor is sent. + ASSERT_EQ(transport_.packets_sent(), 1); + EXPECT_TRUE(transport_.last_sent_packet() + .HasExtension()); +} + void RtpSenderVideoTest::PopulateGenericFrameDescriptor(int version) { const absl::string_view ext_uri = (version == 0) ? RtpGenericFrameDescriptorExtension00::kUri