| // Copyright 2018 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "media/renderers/decrypting_renderer.h" |
| |
| #include "base/bind.h" |
| #include "base/callback_helpers.h" |
| #include "base/single_thread_task_runner.h" |
| #include "base/test/gmock_callback_support.h" |
| #include "base/test/mock_callback.h" |
| #include "base/test/task_environment.h" |
| #include "media/base/demuxer_stream.h" |
| #include "media/base/media_util.h" |
| #include "media/base/mock_filters.h" |
| #include "media/base/test_helpers.h" |
| #include "media/filters/decrypting_media_resource.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| |
| using ::base::test::RunCallback; |
| using ::base::test::RunOnceCallback; |
| using ::testing::_; |
| using ::testing::AnyNumber; |
| using ::testing::Invoke; |
| using ::testing::Return; |
| using ::testing::ReturnPointee; |
| using ::testing::StrictMock; |
| |
| namespace media { |
| |
| class CdmContext; |
| class DemuxerStream; |
| class MediaLog; |
| |
| class DecryptingRendererTest : public testing::Test { |
| public: |
| DecryptingRendererTest() { |
| auto renderer = std::make_unique<StrictMock<MockRenderer>>(); |
| renderer_ = renderer.get(); |
| decrypting_renderer_ = std::make_unique<DecryptingRenderer>( |
| std::move(renderer), &null_media_log_, |
| task_environment_.GetMainThreadTaskRunner()); |
| |
| EXPECT_CALL(cdm_context_, RegisterEventCB(_)).Times(AnyNumber()); |
| EXPECT_CALL(cdm_context_, GetDecryptor()) |
| .WillRepeatedly(Return(&decryptor_)); |
| EXPECT_CALL(decryptor_, CanAlwaysDecrypt()) |
| .WillRepeatedly(ReturnPointee(&use_aes_decryptor_)); |
| EXPECT_CALL(decryptor_, CancelDecrypt(_)).Times(AnyNumber()); |
| EXPECT_CALL(media_resource_, GetAllStreams()) |
| .WillRepeatedly(Invoke(this, &DecryptingRendererTest::GetAllStreams)); |
| EXPECT_CALL(media_resource_, GetType()) |
| .WillRepeatedly(Return(MediaResource::STREAM)); |
| } |
| |
| ~DecryptingRendererTest() override { |
| // Ensure that the DecryptingRenderer is destructed before other objects |
| // that it internally references but does not own. |
| decrypting_renderer_.reset(); |
| } |
| |
| void AddStream(DemuxerStream::Type type, bool encrypted) { |
| streams_.push_back(CreateMockDemuxerStream(type, encrypted)); |
| } |
| |
| void UseAesDecryptor(bool use_aes_decryptor) { |
| use_aes_decryptor_ = use_aes_decryptor; |
| } |
| |
| std::vector<DemuxerStream*> GetAllStreams() { |
| std::vector<DemuxerStream*> streams; |
| |
| for (auto& stream : streams_) { |
| streams.push_back(stream.get()); |
| } |
| |
| return streams; |
| } |
| |
| protected: |
| // Invoking InitializeRenderer(false) will cause the initialization of the |
| // DecryptingRenderer to halt and an error will be propagated to the media |
| // pipeline. |
| void InitializeDecryptingRendererWithFalse() { |
| decrypting_renderer_->InitializeRenderer(false); |
| } |
| |
| bool use_aes_decryptor_ = false; |
| base::test::TaskEnvironment task_environment_; |
| base::MockCallback<Renderer::CdmAttachedCB> set_cdm_cb_; |
| base::MockOnceCallback<void(PipelineStatus)> renderer_init_cb_; |
| NullMediaLog null_media_log_; |
| StrictMock<MockCdmContext> cdm_context_; |
| StrictMock<MockDecryptor> decryptor_; |
| StrictMock<MockMediaResource> media_resource_; |
| StrictMock<MockRendererClient> renderer_client_; |
| StrictMock<MockRenderer>* renderer_; |
| std::unique_ptr<DecryptingRenderer> decrypting_renderer_; |
| std::vector<std::unique_ptr<StrictMock<MockDemuxerStream>>> streams_; |
| }; |
| |
| TEST_F(DecryptingRendererTest, ClearStreams_NoCdm) { |
| AddStream(DemuxerStream::AUDIO, /* encrypted = */ false); |
| AddStream(DemuxerStream::VIDEO, /* encrypted = */ false); |
| |
| EXPECT_CALL(*renderer_, OnInitialize(_, _, _)) |
| .WillOnce(RunOnceCallback<2>(PIPELINE_OK)); |
| EXPECT_CALL(renderer_init_cb_, Run(PIPELINE_OK)); |
| |
| decrypting_renderer_->Initialize(&media_resource_, &renderer_client_, |
| renderer_init_cb_.Get()); |
| task_environment_.RunUntilIdle(); |
| |
| EXPECT_FALSE(decrypting_renderer_->HasDecryptingMediaResourceForTesting()); |
| } |
| |
| TEST_F(DecryptingRendererTest, ClearStreams_AesDecryptor) { |
| AddStream(DemuxerStream::AUDIO, /* encrypted = */ false); |
| AddStream(DemuxerStream::VIDEO, /* encrypted = */ false); |
| UseAesDecryptor(true); |
| |
| EXPECT_CALL(*renderer_, OnInitialize(_, _, _)) |
| .WillOnce(RunOnceCallback<2>(PIPELINE_OK)); |
| EXPECT_CALL(set_cdm_cb_, Run(true)); |
| EXPECT_CALL(renderer_init_cb_, Run(PIPELINE_OK)); |
| |
| decrypting_renderer_->SetCdm(&cdm_context_, set_cdm_cb_.Get()); |
| decrypting_renderer_->Initialize(&media_resource_, &renderer_client_, |
| renderer_init_cb_.Get()); |
| task_environment_.RunUntilIdle(); |
| |
| EXPECT_TRUE(decrypting_renderer_->HasDecryptingMediaResourceForTesting()); |
| } |
| |
| TEST_F(DecryptingRendererTest, ClearStreams_OtherCdm) { |
| AddStream(DemuxerStream::AUDIO, /* encrypted = */ false); |
| AddStream(DemuxerStream::VIDEO, /* encrypted = */ false); |
| |
| EXPECT_CALL(*renderer_, OnInitialize(_, _, _)) |
| .WillOnce(RunOnceCallback<2>(PIPELINE_OK)); |
| EXPECT_CALL(*renderer_, OnSetCdm(_, _)).WillOnce(RunOnceCallback<1>(true)); |
| EXPECT_CALL(renderer_init_cb_, Run(PIPELINE_OK)); |
| EXPECT_CALL(set_cdm_cb_, Run(true)); |
| |
| decrypting_renderer_->Initialize(&media_resource_, &renderer_client_, |
| renderer_init_cb_.Get()); |
| decrypting_renderer_->SetCdm(&cdm_context_, set_cdm_cb_.Get()); |
| task_environment_.RunUntilIdle(); |
| |
| EXPECT_FALSE(decrypting_renderer_->HasDecryptingMediaResourceForTesting()); |
| } |
| |
| TEST_F(DecryptingRendererTest, EncryptedStreams_NoCdm) { |
| AddStream(DemuxerStream::AUDIO, /* encrypted = */ true); |
| AddStream(DemuxerStream::VIDEO, /* encrypted = */ true); |
| |
| decrypting_renderer_->Initialize(&media_resource_, &renderer_client_, |
| renderer_init_cb_.Get()); |
| task_environment_.RunUntilIdle(); |
| |
| EXPECT_FALSE(decrypting_renderer_->HasDecryptingMediaResourceForTesting()); |
| } |
| |
| TEST_F(DecryptingRendererTest, EncryptedStreams_AesDecryptor) { |
| AddStream(DemuxerStream::AUDIO, /* encrypted = */ true); |
| AddStream(DemuxerStream::VIDEO, /* encrypted = */ true); |
| UseAesDecryptor(true); |
| |
| EXPECT_CALL(*renderer_, OnInitialize(_, _, _)) |
| .WillOnce(RunOnceCallback<2>(PIPELINE_OK)); |
| EXPECT_CALL(renderer_init_cb_, Run(PIPELINE_OK)); |
| EXPECT_CALL(set_cdm_cb_, Run(true)); |
| |
| decrypting_renderer_->Initialize(&media_resource_, &renderer_client_, |
| renderer_init_cb_.Get()); |
| decrypting_renderer_->SetCdm(&cdm_context_, set_cdm_cb_.Get()); |
| task_environment_.RunUntilIdle(); |
| |
| EXPECT_TRUE(decrypting_renderer_->HasDecryptingMediaResourceForTesting()); |
| } |
| |
| TEST_F(DecryptingRendererTest, EncryptedStreams_OtherCdm) { |
| AddStream(DemuxerStream::AUDIO, /* encrypted = */ true); |
| AddStream(DemuxerStream::VIDEO, /* encrypted = */ true); |
| |
| EXPECT_CALL(*renderer_, OnInitialize(_, _, _)) |
| .WillOnce(RunOnceCallback<2>(PIPELINE_OK)); |
| EXPECT_CALL(*renderer_, OnSetCdm(_, _)).WillOnce(RunOnceCallback<1>(true)); |
| EXPECT_CALL(renderer_init_cb_, Run(PIPELINE_OK)); |
| EXPECT_CALL(set_cdm_cb_, Run(true)); |
| |
| decrypting_renderer_->Initialize(&media_resource_, &renderer_client_, |
| renderer_init_cb_.Get()); |
| decrypting_renderer_->SetCdm(&cdm_context_, set_cdm_cb_.Get()); |
| task_environment_.RunUntilIdle(); |
| |
| EXPECT_FALSE(decrypting_renderer_->HasDecryptingMediaResourceForTesting()); |
| } |
| |
| TEST_F(DecryptingRendererTest, EncryptedStreams_AesDecryptor_CdmSetBeforeInit) { |
| AddStream(DemuxerStream::AUDIO, /* encrypted = */ true); |
| AddStream(DemuxerStream::VIDEO, /* encrypted = */ true); |
| UseAesDecryptor(true); |
| |
| EXPECT_CALL(*renderer_, OnInitialize(_, _, _)) |
| .WillOnce(RunOnceCallback<2>(PIPELINE_OK)); |
| EXPECT_CALL(renderer_init_cb_, Run(PIPELINE_OK)); |
| EXPECT_CALL(set_cdm_cb_, Run(true)); |
| |
| decrypting_renderer_->SetCdm(&cdm_context_, set_cdm_cb_.Get()); |
| decrypting_renderer_->Initialize(&media_resource_, &renderer_client_, |
| renderer_init_cb_.Get()); |
| task_environment_.RunUntilIdle(); |
| |
| EXPECT_TRUE(decrypting_renderer_->HasDecryptingMediaResourceForTesting()); |
| } |
| |
| TEST_F(DecryptingRendererTest, EncryptedStreams_OtherCdm_CdmSetBeforeInit) { |
| AddStream(DemuxerStream::AUDIO, /* encrypted = */ true); |
| AddStream(DemuxerStream::VIDEO, /* encrypted = */ true); |
| |
| EXPECT_CALL(*renderer_, OnInitialize(_, _, _)) |
| .WillOnce(RunOnceCallback<2>(PIPELINE_OK)); |
| EXPECT_CALL(*renderer_, OnSetCdm(_, _)).WillOnce(RunOnceCallback<1>(true)); |
| EXPECT_CALL(renderer_init_cb_, Run(PIPELINE_OK)); |
| EXPECT_CALL(set_cdm_cb_, Run(true)); |
| |
| decrypting_renderer_->SetCdm(&cdm_context_, set_cdm_cb_.Get()); |
| decrypting_renderer_->Initialize(&media_resource_, &renderer_client_, |
| renderer_init_cb_.Get()); |
| task_environment_.RunUntilIdle(); |
| |
| EXPECT_FALSE(decrypting_renderer_->HasDecryptingMediaResourceForTesting()); |
| } |
| |
| TEST_F(DecryptingRendererTest, EncryptedAndClearStream_OtherCdm) { |
| AddStream(DemuxerStream::AUDIO, /* encrypted = */ false); |
| AddStream(DemuxerStream::VIDEO, /* encrypted = */ true); |
| |
| EXPECT_CALL(*renderer_, OnInitialize(_, _, _)) |
| .WillOnce(RunOnceCallback<2>(PIPELINE_OK)); |
| EXPECT_CALL(*renderer_, OnSetCdm(_, _)).WillOnce(RunOnceCallback<1>(true)); |
| EXPECT_CALL(renderer_init_cb_, Run(PIPELINE_OK)); |
| EXPECT_CALL(set_cdm_cb_, Run(true)); |
| |
| decrypting_renderer_->Initialize(&media_resource_, &renderer_client_, |
| renderer_init_cb_.Get()); |
| decrypting_renderer_->SetCdm(&cdm_context_, set_cdm_cb_.Get()); |
| task_environment_.RunUntilIdle(); |
| |
| EXPECT_FALSE(decrypting_renderer_->HasDecryptingMediaResourceForTesting()); |
| } |
| |
| TEST_F(DecryptingRendererTest, DecryptingMediaResourceInitFails) { |
| AddStream(DemuxerStream::AUDIO, /* encrypted = */ false); |
| AddStream(DemuxerStream::VIDEO, /* encrypted = */ true); |
| UseAesDecryptor(true); |
| |
| EXPECT_CALL(renderer_init_cb_, Run(PIPELINE_ERROR_INITIALIZATION_FAILED)); |
| |
| decrypting_renderer_->Initialize(&media_resource_, &renderer_client_, |
| renderer_init_cb_.Get()); |
| task_environment_.RunUntilIdle(); |
| |
| // Cause a PIPELINE_ERROR_INITIALIZATION_FAILED error to be passed as a |
| // parameter to the initialization callback. |
| InitializeDecryptingRendererWithFalse(); |
| } |
| |
| } // namespace media |