1 // Copyright 2018 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "media/renderers/decrypting_renderer.h"
6 
7 #include "base/bind.h"
8 #include "base/bind_helpers.h"
9 #include "base/single_thread_task_runner.h"
10 #include "base/test/gmock_callback_support.h"
11 #include "base/test/mock_callback.h"
12 #include "base/test/task_environment.h"
13 #include "media/base/demuxer_stream.h"
14 #include "media/base/media_util.h"
15 #include "media/base/mock_filters.h"
16 #include "media/base/test_helpers.h"
17 #include "media/filters/decrypting_media_resource.h"
18 #include "testing/gmock/include/gmock/gmock.h"
19 
20 using ::base::test::RunCallback;
21 using ::base::test::RunOnceCallback;
22 using ::testing::_;
23 using ::testing::AnyNumber;
24 using ::testing::Invoke;
25 using ::testing::Return;
26 using ::testing::ReturnPointee;
27 using ::testing::StrictMock;
28 
29 namespace media {
30 
31 class CdmContext;
32 class DemuxerStream;
33 class MediaLog;
34 
35 class DecryptingRendererTest : public testing::Test {
36  public:
DecryptingRendererTest()37   DecryptingRendererTest() {
38     auto renderer = std::make_unique<StrictMock<MockRenderer>>();
39     renderer_ = renderer.get();
40     decrypting_renderer_ = std::make_unique<DecryptingRenderer>(
41         std::move(renderer), &null_media_log_,
42         task_environment_.GetMainThreadTaskRunner());
43 
44     EXPECT_CALL(cdm_context_, GetDecryptor())
45         .WillRepeatedly(Return(&decryptor_));
46     EXPECT_CALL(decryptor_, CanAlwaysDecrypt())
47         .WillRepeatedly(ReturnPointee(&use_aes_decryptor_));
48     EXPECT_CALL(decryptor_, CancelDecrypt(_)).Times(AnyNumber());
49     EXPECT_CALL(decryptor_, RegisterNewKeyCB(_, _)).Times(AnyNumber());
50     EXPECT_CALL(media_resource_, GetAllStreams())
51         .WillRepeatedly(Invoke(this, &DecryptingRendererTest::GetAllStreams));
52     EXPECT_CALL(media_resource_, GetType())
53         .WillRepeatedly(Return(MediaResource::STREAM));
54   }
55 
~DecryptingRendererTest()56   ~DecryptingRendererTest() override {
57     // Ensure that the DecryptingRenderer is destructed before other objects
58     // that it internally references but does not own.
59     decrypting_renderer_.reset();
60   }
61 
AddStream(DemuxerStream::Type type,bool encrypted)62   void AddStream(DemuxerStream::Type type, bool encrypted) {
63     streams_.push_back(CreateMockDemuxerStream(type, encrypted));
64   }
65 
UseAesDecryptor(bool use_aes_decryptor)66   void UseAesDecryptor(bool use_aes_decryptor) {
67     use_aes_decryptor_ = use_aes_decryptor;
68   }
69 
GetAllStreams()70   std::vector<DemuxerStream*> GetAllStreams() {
71     std::vector<DemuxerStream*> streams;
72 
73     for (auto& stream : streams_) {
74       streams.push_back(stream.get());
75     }
76 
77     return streams;
78   }
79 
80  protected:
81   // Invoking InitializeRenderer(false) will cause the initialization of the
82   // DecryptingRenderer to halt and an error will be propagated to the media
83   // pipeline.
InitializeDecryptingRendererWithFalse()84   void InitializeDecryptingRendererWithFalse() {
85     decrypting_renderer_->InitializeRenderer(false);
86   }
87 
88   bool use_aes_decryptor_ = false;
89   base::test::TaskEnvironment task_environment_;
90   base::MockCallback<CdmAttachedCB> set_cdm_cb_;
91   base::MockOnceCallback<void(PipelineStatus)> renderer_init_cb_;
92   NullMediaLog null_media_log_;
93   StrictMock<MockCdmContext> cdm_context_;
94   StrictMock<MockDecryptor> decryptor_;
95   StrictMock<MockMediaResource> media_resource_;
96   StrictMock<MockRendererClient> renderer_client_;
97   StrictMock<MockRenderer>* renderer_;
98   std::unique_ptr<DecryptingRenderer> decrypting_renderer_;
99   std::vector<std::unique_ptr<StrictMock<MockDemuxerStream>>> streams_;
100 };
101 
TEST_F(DecryptingRendererTest,ClearStreams_NoCdm)102 TEST_F(DecryptingRendererTest, ClearStreams_NoCdm) {
103   AddStream(DemuxerStream::AUDIO, /* encrypted = */ false);
104   AddStream(DemuxerStream::VIDEO, /* encrypted = */ false);
105 
106   EXPECT_CALL(*renderer_, OnInitialize(_, _, _))
107       .WillOnce(RunOnceCallback<2>(PIPELINE_OK));
108   EXPECT_CALL(renderer_init_cb_, Run(PIPELINE_OK));
109 
110   decrypting_renderer_->Initialize(&media_resource_, &renderer_client_,
111                                    renderer_init_cb_.Get());
112   task_environment_.RunUntilIdle();
113 
114   EXPECT_FALSE(decrypting_renderer_->HasDecryptingMediaResourceForTesting());
115 }
116 
TEST_F(DecryptingRendererTest,ClearStreams_AesDecryptor)117 TEST_F(DecryptingRendererTest, ClearStreams_AesDecryptor) {
118   AddStream(DemuxerStream::AUDIO, /* encrypted = */ false);
119   AddStream(DemuxerStream::VIDEO, /* encrypted = */ false);
120   UseAesDecryptor(true);
121 
122   EXPECT_CALL(*renderer_, OnInitialize(_, _, _))
123       .WillOnce(RunOnceCallback<2>(PIPELINE_OK));
124   EXPECT_CALL(set_cdm_cb_, Run(true));
125   EXPECT_CALL(renderer_init_cb_, Run(PIPELINE_OK));
126 
127   decrypting_renderer_->SetCdm(&cdm_context_, set_cdm_cb_.Get());
128   decrypting_renderer_->Initialize(&media_resource_, &renderer_client_,
129                                    renderer_init_cb_.Get());
130   task_environment_.RunUntilIdle();
131 
132   EXPECT_TRUE(decrypting_renderer_->HasDecryptingMediaResourceForTesting());
133 }
134 
TEST_F(DecryptingRendererTest,ClearStreams_OtherCdm)135 TEST_F(DecryptingRendererTest, ClearStreams_OtherCdm) {
136   AddStream(DemuxerStream::AUDIO, /* encrypted = */ false);
137   AddStream(DemuxerStream::VIDEO, /* encrypted = */ false);
138 
139   EXPECT_CALL(*renderer_, OnInitialize(_, _, _))
140       .WillOnce(RunOnceCallback<2>(PIPELINE_OK));
141   EXPECT_CALL(*renderer_, OnSetCdm(_, _)).WillOnce(RunOnceCallback<1>(true));
142   EXPECT_CALL(renderer_init_cb_, Run(PIPELINE_OK));
143   EXPECT_CALL(set_cdm_cb_, Run(true));
144 
145   decrypting_renderer_->Initialize(&media_resource_, &renderer_client_,
146                                    renderer_init_cb_.Get());
147   decrypting_renderer_->SetCdm(&cdm_context_, set_cdm_cb_.Get());
148   task_environment_.RunUntilIdle();
149 
150   EXPECT_FALSE(decrypting_renderer_->HasDecryptingMediaResourceForTesting());
151 }
152 
TEST_F(DecryptingRendererTest,EncryptedStreams_NoCdm)153 TEST_F(DecryptingRendererTest, EncryptedStreams_NoCdm) {
154   AddStream(DemuxerStream::AUDIO, /* encrypted = */ true);
155   AddStream(DemuxerStream::VIDEO, /* encrypted = */ true);
156 
157   decrypting_renderer_->Initialize(&media_resource_, &renderer_client_,
158                                    renderer_init_cb_.Get());
159   task_environment_.RunUntilIdle();
160 
161   EXPECT_FALSE(decrypting_renderer_->HasDecryptingMediaResourceForTesting());
162 }
163 
TEST_F(DecryptingRendererTest,EncryptedStreams_AesDecryptor)164 TEST_F(DecryptingRendererTest, EncryptedStreams_AesDecryptor) {
165   AddStream(DemuxerStream::AUDIO, /* encrypted = */ true);
166   AddStream(DemuxerStream::VIDEO, /* encrypted = */ true);
167   UseAesDecryptor(true);
168 
169   EXPECT_CALL(*renderer_, OnInitialize(_, _, _))
170       .WillOnce(RunOnceCallback<2>(PIPELINE_OK));
171   EXPECT_CALL(renderer_init_cb_, Run(PIPELINE_OK));
172   EXPECT_CALL(set_cdm_cb_, Run(true));
173 
174   decrypting_renderer_->Initialize(&media_resource_, &renderer_client_,
175                                    renderer_init_cb_.Get());
176   decrypting_renderer_->SetCdm(&cdm_context_, set_cdm_cb_.Get());
177   task_environment_.RunUntilIdle();
178 
179   EXPECT_TRUE(decrypting_renderer_->HasDecryptingMediaResourceForTesting());
180 }
181 
TEST_F(DecryptingRendererTest,EncryptedStreams_OtherCdm)182 TEST_F(DecryptingRendererTest, EncryptedStreams_OtherCdm) {
183   AddStream(DemuxerStream::AUDIO, /* encrypted = */ true);
184   AddStream(DemuxerStream::VIDEO, /* encrypted = */ true);
185 
186   EXPECT_CALL(*renderer_, OnInitialize(_, _, _))
187       .WillOnce(RunOnceCallback<2>(PIPELINE_OK));
188   EXPECT_CALL(*renderer_, OnSetCdm(_, _)).WillOnce(RunOnceCallback<1>(true));
189   EXPECT_CALL(renderer_init_cb_, Run(PIPELINE_OK));
190   EXPECT_CALL(set_cdm_cb_, Run(true));
191 
192   decrypting_renderer_->Initialize(&media_resource_, &renderer_client_,
193                                    renderer_init_cb_.Get());
194   decrypting_renderer_->SetCdm(&cdm_context_, set_cdm_cb_.Get());
195   task_environment_.RunUntilIdle();
196 
197   EXPECT_FALSE(decrypting_renderer_->HasDecryptingMediaResourceForTesting());
198 }
199 
TEST_F(DecryptingRendererTest,EncryptedStreams_AesDecryptor_CdmSetBeforeInit)200 TEST_F(DecryptingRendererTest, EncryptedStreams_AesDecryptor_CdmSetBeforeInit) {
201   AddStream(DemuxerStream::AUDIO, /* encrypted = */ true);
202   AddStream(DemuxerStream::VIDEO, /* encrypted = */ true);
203   UseAesDecryptor(true);
204 
205   EXPECT_CALL(*renderer_, OnInitialize(_, _, _))
206       .WillOnce(RunOnceCallback<2>(PIPELINE_OK));
207   EXPECT_CALL(renderer_init_cb_, Run(PIPELINE_OK));
208   EXPECT_CALL(set_cdm_cb_, Run(true));
209 
210   decrypting_renderer_->SetCdm(&cdm_context_, set_cdm_cb_.Get());
211   decrypting_renderer_->Initialize(&media_resource_, &renderer_client_,
212                                    renderer_init_cb_.Get());
213   task_environment_.RunUntilIdle();
214 
215   EXPECT_TRUE(decrypting_renderer_->HasDecryptingMediaResourceForTesting());
216 }
217 
TEST_F(DecryptingRendererTest,EncryptedStreams_OtherCdm_CdmSetBeforeInit)218 TEST_F(DecryptingRendererTest, EncryptedStreams_OtherCdm_CdmSetBeforeInit) {
219   AddStream(DemuxerStream::AUDIO, /* encrypted = */ true);
220   AddStream(DemuxerStream::VIDEO, /* encrypted = */ true);
221 
222   EXPECT_CALL(*renderer_, OnInitialize(_, _, _))
223       .WillOnce(RunOnceCallback<2>(PIPELINE_OK));
224   EXPECT_CALL(*renderer_, OnSetCdm(_, _)).WillOnce(RunOnceCallback<1>(true));
225   EXPECT_CALL(renderer_init_cb_, Run(PIPELINE_OK));
226   EXPECT_CALL(set_cdm_cb_, Run(true));
227 
228   decrypting_renderer_->SetCdm(&cdm_context_, set_cdm_cb_.Get());
229   decrypting_renderer_->Initialize(&media_resource_, &renderer_client_,
230                                    renderer_init_cb_.Get());
231   task_environment_.RunUntilIdle();
232 
233   EXPECT_FALSE(decrypting_renderer_->HasDecryptingMediaResourceForTesting());
234 }
235 
TEST_F(DecryptingRendererTest,EncryptedAndClearStream_OtherCdm)236 TEST_F(DecryptingRendererTest, EncryptedAndClearStream_OtherCdm) {
237   AddStream(DemuxerStream::AUDIO, /* encrypted = */ false);
238   AddStream(DemuxerStream::VIDEO, /* encrypted = */ true);
239 
240   EXPECT_CALL(*renderer_, OnInitialize(_, _, _))
241       .WillOnce(RunOnceCallback<2>(PIPELINE_OK));
242   EXPECT_CALL(*renderer_, OnSetCdm(_, _)).WillOnce(RunOnceCallback<1>(true));
243   EXPECT_CALL(renderer_init_cb_, Run(PIPELINE_OK));
244   EXPECT_CALL(set_cdm_cb_, Run(true));
245 
246   decrypting_renderer_->Initialize(&media_resource_, &renderer_client_,
247                                    renderer_init_cb_.Get());
248   decrypting_renderer_->SetCdm(&cdm_context_, set_cdm_cb_.Get());
249   task_environment_.RunUntilIdle();
250 
251   EXPECT_FALSE(decrypting_renderer_->HasDecryptingMediaResourceForTesting());
252 }
253 
TEST_F(DecryptingRendererTest,DecryptingMediaResourceInitFails)254 TEST_F(DecryptingRendererTest, DecryptingMediaResourceInitFails) {
255   AddStream(DemuxerStream::AUDIO, /* encrypted = */ false);
256   AddStream(DemuxerStream::VIDEO, /* encrypted = */ true);
257   UseAesDecryptor(true);
258 
259   EXPECT_CALL(renderer_init_cb_, Run(PIPELINE_ERROR_INITIALIZATION_FAILED));
260 
261   decrypting_renderer_->Initialize(&media_resource_, &renderer_client_,
262                                    renderer_init_cb_.Get());
263   task_environment_.RunUntilIdle();
264 
265   // Cause a PIPELINE_ERROR_INITIALIZATION_FAILED error to be passed as a
266   // parameter to the initialization callback.
267   InitializeDecryptingRendererWithFalse();
268 }
269 
270 }  // namespace media
271