Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(132)

Side by Side Diff: media/remoting/remoting_renderer_controller.cc

Issue 2457563002: Media Remoting: Add remoting control logic for encrypted contents. (Closed)
Patch Set: Addressed xhwang's comments. Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 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/remoting/remoting_renderer_controller.h"
6
7 #include "base/bind.h"
8 #include "base/logging.h"
9 #include "base/threading/thread_checker.h"
10 #include "media/remoting/remoting_cdm_context.h"
11
12 namespace media {
13
14 RemotingRendererController::RemotingRendererController(
15 scoped_refptr<RemotingSourceImpl> remoting_source)
16 : remoting_source_(remoting_source), weak_factory_(this) {
17 remoting_source_->AddClient(this);
18 }
19
20 RemotingRendererController::~RemotingRendererController() {
21 DCHECK(thread_checker_.CalledOnValidThread());
22 remoting_source_->RemoveClient(this);
23 }
24
25 void RemotingRendererController::OnStarted(bool success) {
26 DCHECK(thread_checker_.CalledOnValidThread());
27
28 if (success) {
29 VLOG(1) << "Remoting started successively.";
30 if (remote_rendering_started_) {
31 DCHECK(!switch_renderer_cb_.is_null());
32 switch_renderer_cb_.Run();
33 } else {
34 remoting_source_->StopRemoting(this);
35 }
36 } else {
37 VLOG(1) << "Failed to start remoting.";
38 remote_rendering_started_ = false;
39 }
40 }
41
42 void RemotingRendererController::OnSessionStateChanged() {
43 DCHECK(thread_checker_.CalledOnValidThread());
44
45 VLOG(1) << "OnSessionStateChanged: " << remoting_source_->state();
46 UpdateAndMaybeSwitch();
47 }
48
49 void RemotingRendererController::OnEnteredFullscreen() {
50 DCHECK(thread_checker_.CalledOnValidThread());
51
52 is_fullscreen_ = true;
53 UpdateAndMaybeSwitch();
54 }
55
56 void RemotingRendererController::OnExitedFullscreen() {
57 DCHECK(thread_checker_.CalledOnValidThread());
58
59 is_fullscreen_ = false;
60 UpdateAndMaybeSwitch();
61 }
62
63 void RemotingRendererController::OnSetCdm(CdmContext* cdm_context) {
64 DCHECK(thread_checker_.CalledOnValidThread());
65
66 auto* cdm = RemotingCdmContext::From(cdm_context);
xhwang 2016/11/02 06:47:05 s/cdm/remoting_cdm_context, strictly speaking it's
xjz 2016/11/02 17:38:11 Done.
67 if (!cdm)
68 return;
69
70 remoting_source_->RemoveClient(this);
71 remoting_source_ = cdm->GetRemotingSource();
72 remoting_source_->AddClient(this); // Calls OnSessionStateChanged().
73 UpdateAndMaybeSwitch();
74 }
75
76 void RemotingRendererController::SetSwitchRendererCallback(
77 const base::Closure& cb) {
78 DCHECK(thread_checker_.CalledOnValidThread());
79 DCHECK(!cb.is_null());
80
81 switch_renderer_cb_ = cb;
82 UpdateAndMaybeSwitch();
83 }
84
85 base::WeakPtr<remoting::RpcBroker> RemotingRendererController::GetRpcBroker()
86 const {
87 DCHECK(thread_checker_.CalledOnValidThread());
88
89 return remoting_source_->GetRpcBroker();
90 }
91
92 void RemotingRendererController::StartDataPipe(
93 std::unique_ptr<mojo::DataPipe> audio_data_pipe,
94 std::unique_ptr<mojo::DataPipe> video_data_pipe,
95 const RemotingSourceImpl::DataPipeStartCallback& done_callback) {
96 DCHECK(thread_checker_.CalledOnValidThread());
97
98 remoting_source_->StartDataPipe(std::move(audio_data_pipe),
99 std::move(video_data_pipe), done_callback);
100 }
101
102 void RemotingRendererController::OnMetadataChanged(
103 const PipelineMetadata& metadata) {
104 DCHECK(thread_checker_.CalledOnValidThread());
105
106 has_video_ =
107 metadata.has_video && metadata.video_decoder_config.IsValidConfig();
108 has_audio_ =
109 metadata.has_audio && metadata.audio_decoder_config.IsValidConfig();
110
111 is_encrypted_ = false;
112 if (has_video_) {
113 video_decoder_config_ = metadata.video_decoder_config;
114 is_encrypted_ |= video_decoder_config_.is_encrypted();
115 }
116 if (has_audio_) {
117 audio_decoder_config_ = metadata.audio_decoder_config;
118 is_encrypted_ |= audio_decoder_config_.is_encrypted();
119 }
120 UpdateAndMaybeSwitch();
121 }
122
123 bool RemotingRendererController::IsVideoCodecSupported() {
124 DCHECK(thread_checker_.CalledOnValidThread());
125 DCHECK(has_video_);
126
127 switch (video_decoder_config_.codec()) {
128 case VideoCodec::kCodecH264:
129 case VideoCodec::kCodecVP8:
130 return true;
131 default:
132 VLOG(2) << "Remoting does not support video codec: "
133 << video_decoder_config_.codec();
134 return false;
135 }
136 }
137
138 bool RemotingRendererController::IsAudioCodecSupported() {
139 DCHECK(thread_checker_.CalledOnValidThread());
140 DCHECK(has_audio_);
141
142 switch (audio_decoder_config_.codec()) {
143 case AudioCodec::kCodecAAC:
144 case AudioCodec::kCodecMP3:
145 case AudioCodec::kCodecPCM:
146 case AudioCodec::kCodecVorbis:
147 case AudioCodec::kCodecFLAC:
148 case AudioCodec::kCodecAMR_NB:
149 case AudioCodec::kCodecAMR_WB:
150 case AudioCodec::kCodecPCM_MULAW:
151 case AudioCodec::kCodecGSM_MS:
152 case AudioCodec::kCodecPCM_S16BE:
153 case AudioCodec::kCodecPCM_S24BE:
154 case AudioCodec::kCodecOpus:
155 case AudioCodec::kCodecEAC3:
156 case AudioCodec::kCodecPCM_ALAW:
157 case AudioCodec::kCodecALAC:
158 case AudioCodec::kCodecAC3:
159 return true;
160 default:
161 VLOG(2) << "Remoting does not support audio codec: "
162 << audio_decoder_config_.codec();
163 return false;
164 }
165 }
166
167 bool RemotingRendererController::ShouldBeRemoting() {
168 DCHECK(thread_checker_.CalledOnValidThread());
169
170 if (switch_renderer_cb_.is_null())
171 return false; // No way to switch to a RemotingRenderImpl.
172
173 const RemotingSessionState state = remoting_source_->state();
174 if (is_encrypted_) {
175 // Due to technical limitations when playing encrypted content, once a
176 // remoting session has been started, always return true here to indicate
177 // that the RemotingRendererImpl should be used. In the stopped states,
178 // RemotingRendererImpl will display an interstitial to notify the user that
179 // local rendering cannot be resumed.
180 return state == RemotingSessionState::SESSION_STARTED ||
181 state == RemotingSessionState::SESSION_STOPPING ||
182 state == RemotingSessionState::SESSION_PERMANENTLY_STOPPED;
183 }
184
185 switch (state) {
186 case SESSION_UNAVAILABLE:
187 return false; // Cannot remote media without a remote sink.
188 case SESSION_CAN_START:
189 case SESSION_STARTING:
190 case SESSION_STARTED:
191 break; // Media remoting is possible, assuming other requirments are met.
192 case SESSION_STOPPING:
193 case SESSION_PERMANENTLY_STOPPED:
194 return false; // Use local rendering after stopping remoting.
195 }
196 if ((!has_audio_ && !has_video_) ||
197 (has_video_ && !IsVideoCodecSupported()) ||
198 (has_audio_ && !IsAudioCodecSupported()))
199 return false;
200
201 // Normally, entering fullscreen is the signal that starts remote rendering.
202 // However, current technical limitations require encrypted content be remoted
203 // without waiting for a user signal.
204 return is_fullscreen_;
205 }
206
207 void RemotingRendererController::UpdateAndMaybeSwitch() {
208 DCHECK(thread_checker_.CalledOnValidThread());
209
210 bool should_be_remoting = ShouldBeRemoting();
211
212 if (remote_rendering_started_ == should_be_remoting)
213 return;
214
215 // Switch between local renderer and remoting renderer.
216 remote_rendering_started_ = should_be_remoting;
217
218 if (remote_rendering_started_) {
219 DCHECK(!switch_renderer_cb_.is_null());
220 if (remoting_source_->state() ==
221 RemotingSessionState::SESSION_PERMANENTLY_STOPPED) {
222 switch_renderer_cb_.Run();
223 return;
224 }
225 // |switch_renderer_cb_.Run()| will be called after remoting is started
226 // successfully.
227 remoting_source_->StartRemoting(this);
228 } else {
229 // For encrypted content, it's only valid to switch to remoting renderer,
230 // and never back to the local renderer. The RemotingCdmController will
231 // force-stop the session when remoting has ended; so no need to call
232 // StopRemoting() from here.
233 DCHECK(!is_encrypted_);
234 switch_renderer_cb_.Run();
235 remoting_source_->StopRemoting(this);
236 }
237 }
238
239 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698