1 /*
2 * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #include "video/buffered_frame_decryptor.h"
12
13 #include <map>
14 #include <memory>
15 #include <vector>
16
17 #include "api/test/mock_frame_decryptor.h"
18 #include "modules/video_coding/packet_buffer.h"
19 #include "system_wrappers/include/clock.h"
20 #include "test/gmock.h"
21 #include "test/gtest.h"
22 #include "test/scoped_key_value_config.h"
23
24 using ::testing::Return;
25
26 namespace webrtc {
27 namespace {
28
DecryptSuccess()29 FrameDecryptorInterface::Result DecryptSuccess() {
30 return FrameDecryptorInterface::Result(FrameDecryptorInterface::Status::kOk,
31 0);
32 }
33
DecryptFail()34 FrameDecryptorInterface::Result DecryptFail() {
35 return FrameDecryptorInterface::Result(
36 FrameDecryptorInterface::Status::kFailedToDecrypt, 0);
37 }
38
39 } // namespace
40
41 class BufferedFrameDecryptorTest : public ::testing::Test,
42 public OnDecryptedFrameCallback,
43 public OnDecryptionStatusChangeCallback {
44 public:
45 // Implements the OnDecryptedFrameCallbackInterface
OnDecryptedFrame(std::unique_ptr<RtpFrameObject> frame)46 void OnDecryptedFrame(std::unique_ptr<RtpFrameObject> frame) override {
47 decrypted_frame_call_count_++;
48 }
49
OnDecryptionStatusChange(FrameDecryptorInterface::Status status)50 void OnDecryptionStatusChange(FrameDecryptorInterface::Status status) {
51 ++decryption_status_change_count_;
52 }
53
54 // Returns a new fake RtpFrameObject it abstracts the difficult construction
55 // of the RtpFrameObject to simplify testing.
CreateRtpFrameObject(bool key_frame)56 std::unique_ptr<RtpFrameObject> CreateRtpFrameObject(bool key_frame) {
57 seq_num_++;
58 RTPVideoHeader rtp_video_header;
59 rtp_video_header.generic.emplace();
60
61 // clang-format off
62 return std::make_unique<RtpFrameObject>(
63 seq_num_,
64 seq_num_,
65 /*markerBit=*/true,
66 /*times_nacked=*/0,
67 /*first_packet_received_time=*/0,
68 /*last_packet_received_time=*/0,
69 /*rtp_timestamp=*/0,
70 /*ntp_time_ms=*/0,
71 VideoSendTiming(),
72 /*payload_type=*/0,
73 kVideoCodecGeneric,
74 kVideoRotation_0,
75 VideoContentType::UNSPECIFIED,
76 rtp_video_header,
77 /*color_space=*/absl::nullopt,
78 RtpPacketInfos(),
79 EncodedImageBuffer::Create(/*size=*/0));
80 // clang-format on
81 }
82
83 protected:
BufferedFrameDecryptorTest()84 BufferedFrameDecryptorTest() {
85 fake_packet_data_ = std::vector<uint8_t>(100);
86 decrypted_frame_call_count_ = 0;
87 decryption_status_change_count_ = 0;
88 seq_num_ = 0;
89 mock_frame_decryptor_ = rtc::make_ref_counted<MockFrameDecryptor>();
90 buffered_frame_decryptor_ =
91 std::make_unique<BufferedFrameDecryptor>(this, this, field_trials_);
92 buffered_frame_decryptor_->SetFrameDecryptor(mock_frame_decryptor_);
93 }
94
95 static const size_t kMaxStashedFrames;
96
97 test::ScopedKeyValueConfig field_trials_;
98 std::vector<uint8_t> fake_packet_data_;
99 rtc::scoped_refptr<MockFrameDecryptor> mock_frame_decryptor_;
100 std::unique_ptr<BufferedFrameDecryptor> buffered_frame_decryptor_;
101 size_t decrypted_frame_call_count_;
102 size_t decryption_status_change_count_ = 0;
103 uint16_t seq_num_;
104 };
105
106 const size_t BufferedFrameDecryptorTest::kMaxStashedFrames = 24;
107
108 // Callback should always be triggered on a successful decryption.
TEST_F(BufferedFrameDecryptorTest,CallbackCalledOnSuccessfulDecryption)109 TEST_F(BufferedFrameDecryptorTest, CallbackCalledOnSuccessfulDecryption) {
110 EXPECT_CALL(*mock_frame_decryptor_, Decrypt)
111 .Times(1)
112 .WillOnce(Return(DecryptSuccess()));
113 EXPECT_CALL(*mock_frame_decryptor_, GetMaxPlaintextByteSize)
114 .Times(1)
115 .WillOnce(Return(0));
116 buffered_frame_decryptor_->ManageEncryptedFrame(CreateRtpFrameObject(true));
117 EXPECT_EQ(decrypted_frame_call_count_, static_cast<size_t>(1));
118 EXPECT_EQ(decryption_status_change_count_, static_cast<size_t>(1));
119 }
120
121 // An initial fail to decrypt should not trigger the callback.
TEST_F(BufferedFrameDecryptorTest,CallbackNotCalledOnFailedDecryption)122 TEST_F(BufferedFrameDecryptorTest, CallbackNotCalledOnFailedDecryption) {
123 EXPECT_CALL(*mock_frame_decryptor_, Decrypt)
124 .Times(1)
125 .WillOnce(Return(DecryptFail()));
126 EXPECT_CALL(*mock_frame_decryptor_, GetMaxPlaintextByteSize)
127 .Times(1)
128 .WillOnce(Return(0));
129 buffered_frame_decryptor_->ManageEncryptedFrame(CreateRtpFrameObject(true));
130 EXPECT_EQ(decrypted_frame_call_count_, static_cast<size_t>(0));
131 EXPECT_EQ(decryption_status_change_count_, static_cast<size_t>(1));
132 }
133
134 // Initial failures should be stored and retried after the first successful
135 // decryption.
TEST_F(BufferedFrameDecryptorTest,DelayedCallbackOnBufferedFrames)136 TEST_F(BufferedFrameDecryptorTest, DelayedCallbackOnBufferedFrames) {
137 EXPECT_CALL(*mock_frame_decryptor_, Decrypt)
138 .Times(3)
139 .WillOnce(Return(DecryptFail()))
140 .WillOnce(Return(DecryptSuccess()))
141 .WillOnce(Return(DecryptSuccess()));
142 EXPECT_CALL(*mock_frame_decryptor_, GetMaxPlaintextByteSize)
143 .Times(3)
144 .WillRepeatedly(Return(0));
145
146 // The first decrypt will fail stashing the first frame.
147 buffered_frame_decryptor_->ManageEncryptedFrame(CreateRtpFrameObject(true));
148 EXPECT_EQ(decrypted_frame_call_count_, static_cast<size_t>(0));
149 EXPECT_EQ(decryption_status_change_count_, static_cast<size_t>(1));
150 // The second call will succeed playing back both frames.
151 buffered_frame_decryptor_->ManageEncryptedFrame(CreateRtpFrameObject(false));
152 EXPECT_EQ(decrypted_frame_call_count_, static_cast<size_t>(2));
153 EXPECT_EQ(decryption_status_change_count_, static_cast<size_t>(2));
154 }
155
156 // Subsequent failure to decrypts after the first successful decryption should
157 // fail to decryptk
TEST_F(BufferedFrameDecryptorTest,FTDDiscardedAfterFirstSuccess)158 TEST_F(BufferedFrameDecryptorTest, FTDDiscardedAfterFirstSuccess) {
159 EXPECT_CALL(*mock_frame_decryptor_, Decrypt)
160 .Times(4)
161 .WillOnce(Return(DecryptFail()))
162 .WillOnce(Return(DecryptSuccess()))
163 .WillOnce(Return(DecryptSuccess()))
164 .WillOnce(Return(DecryptFail()));
165 EXPECT_CALL(*mock_frame_decryptor_, GetMaxPlaintextByteSize)
166 .Times(4)
167 .WillRepeatedly(Return(0));
168
169 // The first decrypt will fail stashing the first frame.
170 buffered_frame_decryptor_->ManageEncryptedFrame(CreateRtpFrameObject(true));
171 EXPECT_EQ(decrypted_frame_call_count_, static_cast<size_t>(0));
172 EXPECT_EQ(decryption_status_change_count_, static_cast<size_t>(1));
173 // The second call will succeed playing back both frames.
174 buffered_frame_decryptor_->ManageEncryptedFrame(CreateRtpFrameObject(false));
175 EXPECT_EQ(decrypted_frame_call_count_, static_cast<size_t>(2));
176 EXPECT_EQ(decryption_status_change_count_, static_cast<size_t>(2));
177 // A new failure call will not result in an additional decrypted frame
178 // callback.
179 buffered_frame_decryptor_->ManageEncryptedFrame(CreateRtpFrameObject(true));
180 EXPECT_EQ(decrypted_frame_call_count_, static_cast<size_t>(2));
181 EXPECT_EQ(decryption_status_change_count_, static_cast<size_t>(3));
182 }
183
184 // Validate that the maximum number of stashed frames cannot be exceeded even if
185 // more than its maximum arrives before the first successful decryption.
TEST_F(BufferedFrameDecryptorTest,MaximumNumberOfFramesStored)186 TEST_F(BufferedFrameDecryptorTest, MaximumNumberOfFramesStored) {
187 const size_t failed_to_decrypt_count = kMaxStashedFrames * 2;
188 EXPECT_CALL(*mock_frame_decryptor_, Decrypt)
189 .Times(failed_to_decrypt_count)
190 .WillRepeatedly(Return(DecryptFail()));
191 EXPECT_CALL(*mock_frame_decryptor_, GetMaxPlaintextByteSize)
192 .WillRepeatedly(Return(0));
193
194 for (size_t i = 0; i < failed_to_decrypt_count; ++i) {
195 buffered_frame_decryptor_->ManageEncryptedFrame(CreateRtpFrameObject(true));
196 }
197 EXPECT_EQ(decrypted_frame_call_count_, static_cast<size_t>(0));
198 EXPECT_EQ(decryption_status_change_count_, static_cast<size_t>(1));
199
200 EXPECT_CALL(*mock_frame_decryptor_, Decrypt)
201 .Times(kMaxStashedFrames + 1)
202 .WillRepeatedly(Return(DecryptSuccess()));
203 buffered_frame_decryptor_->ManageEncryptedFrame(CreateRtpFrameObject(true));
204 EXPECT_EQ(decrypted_frame_call_count_, kMaxStashedFrames + 1);
205 EXPECT_EQ(decryption_status_change_count_, static_cast<size_t>(2));
206 }
207
208 // Verifies if a BufferedFrameDecryptor is attached but has no FrameDecryptor
209 // attached it will still store frames up to the frame max.
TEST_F(BufferedFrameDecryptorTest,FramesStoredIfDecryptorNull)210 TEST_F(BufferedFrameDecryptorTest, FramesStoredIfDecryptorNull) {
211 buffered_frame_decryptor_->SetFrameDecryptor(nullptr);
212 for (size_t i = 0; i < (2 * kMaxStashedFrames); ++i) {
213 buffered_frame_decryptor_->ManageEncryptedFrame(CreateRtpFrameObject(true));
214 }
215
216 EXPECT_CALL(*mock_frame_decryptor_, Decrypt)
217 .Times(kMaxStashedFrames + 1)
218 .WillRepeatedly(Return(DecryptSuccess()));
219 EXPECT_CALL(*mock_frame_decryptor_, GetMaxPlaintextByteSize)
220 .WillRepeatedly(Return(0));
221
222 // Attach the frame decryptor at a later point after frames have arrived.
223 buffered_frame_decryptor_->SetFrameDecryptor(mock_frame_decryptor_);
224
225 // Next frame should trigger kMaxStashedFrame decryptions.
226 buffered_frame_decryptor_->ManageEncryptedFrame(CreateRtpFrameObject(true));
227 EXPECT_EQ(decrypted_frame_call_count_, kMaxStashedFrames + 1);
228 }
229
230 } // namespace webrtc
231