1 // Copyright 2018 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "media/renderers/decrypting_renderer.h"
7 #include "base/functional/bind.h"
8 #include "base/functional/callback_helpers.h"
9 #include "base/task/sequenced_task_runner.h"
10 #include "media/base/cdm_context.h"
11 #include "media/base/demuxer_stream.h"
12 #include "media/base/media_log.h"
13 #include "media/base/media_resource.h"
14 #include "media/base/renderer_client.h"
15 #include "media/filters/decrypting_demuxer_stream.h"
16 #include "media/filters/decrypting_media_resource.h"
20 DecryptingRenderer::DecryptingRenderer(
21 std::unique_ptr<Renderer> renderer,
23 const scoped_refptr<base::SequencedTaskRunner> media_task_runner)
24 : renderer_(std::move(renderer)),
25 media_log_(media_log),
26 media_task_runner_(media_task_runner),
28 media_resource_(nullptr),
29 decrypting_media_resource_(nullptr) {
33 DecryptingRenderer::~DecryptingRenderer() {}
35 // The behavior of Initialize():
37 // Streams CdmContext Action
38 // ---------------------------------------------------------------------
39 // Clear nullptr InitializeRenderer()
40 // Clear AesDecryptor CreateAndInitializeDecryptingMediaResource()
41 // Clear Other InitializeRenderer()
42 // Encrypted nullptr Wait
43 // Encrypted AesDecryptor CreateAndInitializeDecryptingMediaResource()
44 // Encrypted Other InitializeRenderer()
45 void DecryptingRenderer::Initialize(MediaResource* media_resource,
46 RendererClient* client,
47 PipelineStatusCallback init_cb) {
48 DCHECK(media_task_runner_->RunsTasksInCurrentSequence());
49 DCHECK(media_resource);
52 // Using |this| with a MediaResource::Type::URL will result in a crash.
53 DCHECK_EQ(media_resource->GetType(), MediaResource::Type::kStream);
55 media_resource_ = media_resource;
57 init_cb_ = std::move(init_cb);
59 bool has_encrypted_stream = HasEncryptedStream();
61 // If we do not have a valid |cdm_context_| and there are encrypted streams we
63 if (!cdm_context_ && has_encrypted_stream) {
64 waiting_for_cdm_ = true;
68 if (cdm_context_ && cdm_context_->GetDecryptor() &&
69 cdm_context_->GetDecryptor()->CanAlwaysDecrypt()) {
70 CreateAndInitializeDecryptingMediaResource();
74 InitializeRenderer(true);
77 void DecryptingRenderer::SetCdm(CdmContext* cdm_context,
78 CdmAttachedCB cdm_attached_cb) {
79 DCHECK(media_task_runner_->RunsTasksInCurrentSequence());
82 DVLOG(1) << "Switching CDM not supported.";
83 std::move(cdm_attached_cb).Run(false);
87 cdm_context_ = cdm_context;
89 // If we are using an AesDecryptor all decryption will be handled by the
90 // DecryptingMediaResource instead of the renderer implementation.
91 if (cdm_context_->GetDecryptor() &&
92 cdm_context_->GetDecryptor()->CanAlwaysDecrypt()) {
93 // If Initialize() was invoked prior to this function then
94 // |waiting_for_cdm_| will be true (if we reached this branch). In this
95 // scenario we want to initialize the DecryptingMediaResource here.
97 CreateAndInitializeDecryptingMediaResource();
98 std::move(cdm_attached_cb).Run(true);
102 renderer_->SetCdm(cdm_context_, std::move(cdm_attached_cb));
104 // We only want to initialize the renderer if we were waiting for the
105 // CdmContext, otherwise it will already have been initialized.
106 if (waiting_for_cdm_)
107 InitializeRenderer(true);
110 void DecryptingRenderer::SetLatencyHint(
111 absl::optional<base::TimeDelta> latency_hint) {
112 renderer_->SetLatencyHint(latency_hint);
115 void DecryptingRenderer::SetPreservesPitch(bool preserves_pitch) {
116 renderer_->SetPreservesPitch(preserves_pitch);
119 void DecryptingRenderer::SetWasPlayedWithUserActivation(
120 bool was_played_with_user_activation) {
121 renderer_->SetWasPlayedWithUserActivation(was_played_with_user_activation);
124 void DecryptingRenderer::Flush(base::OnceClosure flush_cb) {
125 renderer_->Flush(std::move(flush_cb));
128 void DecryptingRenderer::StartPlayingFrom(base::TimeDelta time) {
129 renderer_->StartPlayingFrom(time);
132 void DecryptingRenderer::SetPlaybackRate(double playback_rate) {
133 renderer_->SetPlaybackRate(playback_rate);
136 void DecryptingRenderer::SetVolume(float volume) {
137 renderer_->SetVolume(volume);
140 base::TimeDelta DecryptingRenderer::GetMediaTime() {
141 return renderer_->GetMediaTime();
144 void DecryptingRenderer::OnSelectedVideoTracksChanged(
145 const std::vector<DemuxerStream*>& enabled_tracks,
146 base::OnceClosure change_completed_cb) {
147 renderer_->OnSelectedVideoTracksChanged(enabled_tracks,
148 std::move(change_completed_cb));
151 void DecryptingRenderer::OnEnabledAudioTracksChanged(
152 const std::vector<DemuxerStream*>& enabled_tracks,
153 base::OnceClosure change_completed_cb) {
154 renderer_->OnEnabledAudioTracksChanged(enabled_tracks,
155 std::move(change_completed_cb));
158 RendererType DecryptingRenderer::GetRendererType() {
159 // DecryptingRenderer is a thin wrapping layer; return the underlying type.
160 return renderer_->GetRendererType();
163 void DecryptingRenderer::CreateAndInitializeDecryptingMediaResource() {
164 DCHECK(media_task_runner_->RunsTasksInCurrentSequence());
167 decrypting_media_resource_ = std::make_unique<DecryptingMediaResource>(
168 media_resource_, cdm_context_, media_log_, media_task_runner_);
169 decrypting_media_resource_->Initialize(
170 base::BindOnce(&DecryptingRenderer::InitializeRenderer,
171 weak_factory_.GetWeakPtr()),
172 base::BindRepeating(&DecryptingRenderer::OnWaiting,
173 weak_factory_.GetWeakPtr()));
176 void DecryptingRenderer::InitializeRenderer(bool success) {
177 DCHECK(media_task_runner_->RunsTasksInCurrentSequence());
180 std::move(init_cb_).Run(PIPELINE_ERROR_INITIALIZATION_FAILED);
184 // |decrypting_media_resource_| when |cdm_context_| is null and there are no
185 // encrypted streams.
186 MediaResource* const maybe_decrypting_media_resource =
187 decrypting_media_resource_ ? decrypting_media_resource_.get()
188 : media_resource_.get();
189 renderer_->Initialize(maybe_decrypting_media_resource, client_,
190 std::move(init_cb_));
193 bool DecryptingRenderer::HasEncryptedStream() {
194 DCHECK(media_task_runner_->RunsTasksInCurrentSequence());
196 for (auto* stream : media_resource_->GetAllStreams()) {
197 if ((stream->type() == DemuxerStream::AUDIO &&
198 stream->audio_decoder_config().is_encrypted()) ||
199 (stream->type() == DemuxerStream::VIDEO &&
200 stream->video_decoder_config().is_encrypted())) {
208 bool DecryptingRenderer::HasDecryptingMediaResourceForTesting() const {
209 return decrypting_media_resource_ != nullptr;
212 void DecryptingRenderer::OnWaiting(WaitingReason reason) {
213 DCHECK(media_task_runner_->RunsTasksInCurrentSequence());
214 client_->OnWaiting(reason);