OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "media/remoting/renderer_controller.h" | 5 #include "media/remoting/renderer_controller.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/logging.h" | 8 #include "base/logging.h" |
9 #include "base/threading/thread_checker.h" | 9 #include "base/threading/thread_checker.h" |
10 #include "base/time/time.h" | 10 #include "base/time/time.h" |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
48 DCHECK(thread_checker_.CalledOnValidThread()); | 48 DCHECK(thread_checker_.CalledOnValidThread()); |
49 UpdateFromSessionState(SINK_AVAILABLE, ROUTE_TERMINATED); | 49 UpdateFromSessionState(SINK_AVAILABLE, ROUTE_TERMINATED); |
50 } | 50 } |
51 | 51 |
52 void RendererController::UpdateFromSessionState(StartTrigger start_trigger, | 52 void RendererController::UpdateFromSessionState(StartTrigger start_trigger, |
53 StopTrigger stop_trigger) { | 53 StopTrigger stop_trigger) { |
54 VLOG(1) << "UpdateFromSessionState: " << session_->state(); | 54 VLOG(1) << "UpdateFromSessionState: " << session_->state(); |
55 if (client_) | 55 if (client_) |
56 client_->ActivateViewportIntersectionMonitoring(IsRemoteSinkAvailable()); | 56 client_->ActivateViewportIntersectionMonitoring(IsRemoteSinkAvailable()); |
57 | 57 |
58 UpdateInterstitial(base::nullopt); | |
59 UpdateAndMaybeSwitch(start_trigger, stop_trigger); | 58 UpdateAndMaybeSwitch(start_trigger, stop_trigger); |
60 } | 59 } |
61 | 60 |
62 bool RendererController::IsRemoteSinkAvailable() { | 61 bool RendererController::IsRemoteSinkAvailable() { |
63 DCHECK(thread_checker_.CalledOnValidThread()); | 62 DCHECK(thread_checker_.CalledOnValidThread()); |
64 | 63 |
65 switch (session_->state()) { | 64 switch (session_->state()) { |
66 case SharedSession::SESSION_CAN_START: | 65 case SharedSession::SESSION_CAN_START: |
67 case SharedSession::SESSION_STARTING: | 66 case SharedSession::SESSION_STARTING: |
68 case SharedSession::SESSION_STARTED: | 67 case SharedSession::SESSION_STARTED: |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
132 } | 131 } |
133 | 132 |
134 void RendererController::OnRemotePlaybackDisabled(bool disabled) { | 133 void RendererController::OnRemotePlaybackDisabled(bool disabled) { |
135 DCHECK(thread_checker_.CalledOnValidThread()); | 134 DCHECK(thread_checker_.CalledOnValidThread()); |
136 | 135 |
137 is_remote_playback_disabled_ = disabled; | 136 is_remote_playback_disabled_ = disabled; |
138 metrics_recorder_.OnRemotePlaybackDisabled(disabled); | 137 metrics_recorder_.OnRemotePlaybackDisabled(disabled); |
139 UpdateAndMaybeSwitch(ENABLED_BY_PAGE, DISABLED_BY_PAGE); | 138 UpdateAndMaybeSwitch(ENABLED_BY_PAGE, DISABLED_BY_PAGE); |
140 } | 139 } |
141 | 140 |
142 void RendererController::OnSetPoster(const GURL& poster_url) { | |
143 DCHECK(thread_checker_.CalledOnValidThread()); | |
144 | |
145 if (poster_url != poster_url_) { | |
146 poster_url_ = poster_url; | |
147 if (poster_url_.is_empty()) | |
148 UpdateInterstitial(SkBitmap()); | |
149 else | |
150 DownloadPosterImage(); | |
151 } | |
152 } | |
153 | |
154 base::WeakPtr<RpcBroker> RendererController::GetRpcBroker() const { | 141 base::WeakPtr<RpcBroker> RendererController::GetRpcBroker() const { |
155 DCHECK(thread_checker_.CalledOnValidThread()); | 142 DCHECK(thread_checker_.CalledOnValidThread()); |
156 | 143 |
157 return session_->rpc_broker()->GetWeakPtr(); | 144 return session_->rpc_broker()->GetWeakPtr(); |
158 } | 145 } |
159 | 146 |
160 void RendererController::StartDataPipe( | 147 void RendererController::StartDataPipe( |
161 std::unique_ptr<mojo::DataPipe> audio_data_pipe, | 148 std::unique_ptr<mojo::DataPipe> audio_data_pipe, |
162 std::unique_ptr<mojo::DataPipe> video_data_pipe, | 149 std::unique_ptr<mojo::DataPipe> video_data_pipe, |
163 const SharedSession::DataPipeStartCallback& done_callback) { | 150 const SharedSession::DataPipeStartCallback& done_callback) { |
164 DCHECK(thread_checker_.CalledOnValidThread()); | 151 DCHECK(thread_checker_.CalledOnValidThread()); |
165 | 152 |
166 session_->StartDataPipe(std::move(audio_data_pipe), | 153 session_->StartDataPipe(std::move(audio_data_pipe), |
167 std::move(video_data_pipe), done_callback); | 154 std::move(video_data_pipe), done_callback); |
168 } | 155 } |
169 | 156 |
170 void RendererController::OnMetadataChanged(const PipelineMetadata& metadata) { | 157 void RendererController::OnMetadataChanged(const PipelineMetadata& metadata) { |
171 DCHECK(thread_checker_.CalledOnValidThread()); | 158 DCHECK(thread_checker_.CalledOnValidThread()); |
172 | 159 |
173 const gfx::Size old_size = pipeline_metadata_.natural_size; | |
174 const bool was_audio_codec_supported = has_audio() && IsAudioCodecSupported(); | 160 const bool was_audio_codec_supported = has_audio() && IsAudioCodecSupported(); |
175 const bool was_video_codec_supported = has_video() && IsVideoCodecSupported(); | 161 const bool was_video_codec_supported = has_video() && IsVideoCodecSupported(); |
176 pipeline_metadata_ = metadata; | 162 pipeline_metadata_ = metadata; |
177 const bool is_audio_codec_supported = has_audio() && IsAudioCodecSupported(); | 163 const bool is_audio_codec_supported = has_audio() && IsAudioCodecSupported(); |
178 const bool is_video_codec_supported = has_video() && IsVideoCodecSupported(); | 164 const bool is_video_codec_supported = has_video() && IsVideoCodecSupported(); |
179 metrics_recorder_.OnPipelineMetadataChanged(metadata); | 165 metrics_recorder_.OnPipelineMetadataChanged(metadata); |
180 | 166 |
181 is_encrypted_ = false; | 167 is_encrypted_ = false; |
182 if (has_video()) | 168 if (has_video()) |
183 is_encrypted_ |= metadata.video_decoder_config.is_encrypted(); | 169 is_encrypted_ |= metadata.video_decoder_config.is_encrypted(); |
184 if (has_audio()) | 170 if (has_audio()) |
185 is_encrypted_ |= metadata.audio_decoder_config.is_encrypted(); | 171 is_encrypted_ |= metadata.audio_decoder_config.is_encrypted(); |
186 | 172 |
187 if (pipeline_metadata_.natural_size != old_size) | |
188 UpdateInterstitial(base::nullopt); | |
189 | |
190 StartTrigger start_trigger = UNKNOWN_START_TRIGGER; | 173 StartTrigger start_trigger = UNKNOWN_START_TRIGGER; |
191 if (!was_audio_codec_supported && is_audio_codec_supported) | 174 if (!was_audio_codec_supported && is_audio_codec_supported) |
192 start_trigger = SUPPORTED_AUDIO_CODEC; | 175 start_trigger = SUPPORTED_AUDIO_CODEC; |
193 if (!was_video_codec_supported && is_video_codec_supported) { | 176 if (!was_video_codec_supported && is_video_codec_supported) { |
194 start_trigger = start_trigger == SUPPORTED_AUDIO_CODEC | 177 start_trigger = start_trigger == SUPPORTED_AUDIO_CODEC |
195 ? SUPPORTED_AUDIO_AND_VIDEO_CODECS | 178 ? SUPPORTED_AUDIO_AND_VIDEO_CODECS |
196 : SUPPORTED_VIDEO_CODEC; | 179 : SUPPORTED_VIDEO_CODEC; |
197 } | 180 } |
198 StopTrigger stop_trigger = UNKNOWN_STOP_TRIGGER; | 181 StopTrigger stop_trigger = UNKNOWN_STOP_TRIGGER; |
199 if (was_audio_codec_supported && !is_audio_codec_supported) | 182 if (was_audio_codec_supported && !is_audio_codec_supported) |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
267 DCHECK(thread_checker_.CalledOnValidThread()); | 250 DCHECK(thread_checker_.CalledOnValidThread()); |
268 | 251 |
269 if (!client_) { | 252 if (!client_) { |
270 DCHECK(!remote_rendering_started_); | 253 DCHECK(!remote_rendering_started_); |
271 return false; // No way to switch to the remoting renderer. | 254 return false; // No way to switch to the remoting renderer. |
272 } | 255 } |
273 | 256 |
274 const SharedSession::SessionState state = session_->state(); | 257 const SharedSession::SessionState state = session_->state(); |
275 if (is_encrypted_) { | 258 if (is_encrypted_) { |
276 // Due to technical limitations when playing encrypted content, once a | 259 // Due to technical limitations when playing encrypted content, once a |
277 // remoting session has been started, always return true here to indicate | 260 // remoting session has been started, playback cannot be resumed locally |
278 // that the CourierRenderer should continue to be used. In the stopped | 261 // without reloading the page, so leave the CourierRenderer in-place to |
279 // states, CourierRenderer will display an interstitial to notify the user | 262 // avoid having the default renderer attempt and fail to play the content. |
280 // that local rendering cannot be resumed. | |
281 // | 263 // |
282 // TODO(miu): Revisit this once more of the encrypted-remoting impl is | 264 // TODO(miu): Revisit this once more of the encrypted-remoting impl is |
283 // in-place. For example, this will prevent metrics from recording session | 265 // in-place. For example, this will prevent metrics from recording session |
284 // stop reasons. | 266 // stop reasons. |
285 return state == SharedSession::SESSION_STARTED || | 267 return state == SharedSession::SESSION_STARTED || |
286 state == SharedSession::SESSION_STOPPING || | 268 state == SharedSession::SESSION_STOPPING || |
287 state == SharedSession::SESSION_PERMANENTLY_STOPPED; | 269 state == SharedSession::SESSION_PERMANENTLY_STOPPED; |
288 } | 270 } |
289 | 271 |
290 if (encountered_renderer_fatal_error_) | 272 if (encountered_renderer_fatal_error_) |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
357 // started successfully. | 339 // started successfully. |
358 session_->StartRemoting(this); | 340 session_->StartRemoting(this); |
359 } else { | 341 } else { |
360 // For encrypted content, it's only valid to switch to remoting renderer, | 342 // For encrypted content, it's only valid to switch to remoting renderer, |
361 // and never back to the local renderer. The RemotingCdmController will | 343 // and never back to the local renderer. The RemotingCdmController will |
362 // force-stop the session when remoting has ended; so no need to call | 344 // force-stop the session when remoting has ended; so no need to call |
363 // StopRemoting() from here. | 345 // StopRemoting() from here. |
364 DCHECK(!is_encrypted_); | 346 DCHECK(!is_encrypted_); |
365 DCHECK_NE(stop_trigger, UNKNOWN_STOP_TRIGGER); | 347 DCHECK_NE(stop_trigger, UNKNOWN_STOP_TRIGGER); |
366 metrics_recorder_.WillStopSession(stop_trigger); | 348 metrics_recorder_.WillStopSession(stop_trigger); |
367 // Update the interstitial one last time before switching back to the local | |
368 // Renderer. | |
369 UpdateInterstitial(base::nullopt); | |
370 client_->SwitchRenderer(false); | 349 client_->SwitchRenderer(false); |
371 session_->StopRemoting(this); | 350 session_->StopRemoting(this); |
372 } | 351 } |
373 } | 352 } |
374 | 353 |
375 void RendererController::SetShowInterstitialCallback( | |
376 const ShowInterstitialCallback& cb) { | |
377 DCHECK(thread_checker_.CalledOnValidThread()); | |
378 show_interstitial_cb_ = cb; | |
379 UpdateInterstitial(SkBitmap()); | |
380 if (!poster_url_.is_empty()) | |
381 DownloadPosterImage(); | |
382 } | |
383 | |
384 void RendererController::SetDownloadPosterCallback( | |
385 const DownloadPosterCallback& cb) { | |
386 DCHECK(thread_checker_.CalledOnValidThread()); | |
387 DCHECK(download_poster_cb_.is_null()); | |
388 download_poster_cb_ = cb; | |
389 if (!poster_url_.is_empty()) | |
390 DownloadPosterImage(); | |
391 } | |
392 | |
393 void RendererController::UpdateInterstitial( | |
394 const base::Optional<SkBitmap>& image) { | |
395 DCHECK(thread_checker_.CalledOnValidThread()); | |
396 if (show_interstitial_cb_.is_null()) | |
397 return; | |
398 | |
399 InterstitialType type = InterstitialType::BETWEEN_SESSIONS; | |
400 switch (remote_rendering_started_ ? session_->state() | |
401 : SharedSession::SESSION_STOPPING) { | |
402 case SharedSession::SESSION_STARTED: | |
403 type = InterstitialType::IN_SESSION; | |
404 break; | |
405 case SharedSession::SESSION_PERMANENTLY_STOPPED: | |
406 type = InterstitialType::ENCRYPTED_MEDIA_FATAL_ERROR; | |
407 break; | |
408 case SharedSession::SESSION_UNAVAILABLE: | |
409 case SharedSession::SESSION_CAN_START: | |
410 case SharedSession::SESSION_STARTING: | |
411 case SharedSession::SESSION_STOPPING: | |
412 break; | |
413 } | |
414 | |
415 bool needs_update = false; | |
416 if (image.has_value()) { | |
417 interstitial_background_ = image.value(); | |
418 needs_update = true; | |
419 } | |
420 if (interstitial_natural_size_ != pipeline_metadata_.natural_size) { | |
421 interstitial_natural_size_ = pipeline_metadata_.natural_size; | |
422 needs_update = true; | |
423 } | |
424 if (interstitial_type_ != type) { | |
425 interstitial_type_ = type; | |
426 needs_update = true; | |
427 } | |
428 if (!needs_update) | |
429 return; | |
430 | |
431 show_interstitial_cb_.Run(interstitial_background_, | |
432 interstitial_natural_size_, interstitial_type_); | |
433 } | |
434 | |
435 void RendererController::DownloadPosterImage() { | |
436 if (download_poster_cb_.is_null() || show_interstitial_cb_.is_null()) | |
437 return; | |
438 DCHECK(!poster_url_.is_empty()); | |
439 | |
440 const base::TimeTicks download_start_time = base::TimeTicks::Now(); | |
441 download_poster_cb_.Run( | |
442 poster_url_, | |
443 base::Bind(&RendererController::OnPosterImageDownloaded, | |
444 weak_factory_.GetWeakPtr(), poster_url_, download_start_time)); | |
445 } | |
446 | |
447 void RendererController::OnPosterImageDownloaded( | |
448 const GURL& download_url, | |
449 base::TimeTicks download_start_time, | |
450 const SkBitmap& image) { | |
451 DCHECK(thread_checker_.CalledOnValidThread()); | |
452 | |
453 metrics_recorder_.OnPosterImageDownloaded( | |
454 base::TimeTicks::Now() - download_start_time, !image.drawsNothing()); | |
455 if (download_url != poster_url_) | |
456 return; // The poster image URL has changed during the download. | |
457 UpdateInterstitial(image); | |
458 } | |
459 | |
460 void RendererController::OnRendererFatalError(StopTrigger stop_trigger) { | 354 void RendererController::OnRendererFatalError(StopTrigger stop_trigger) { |
461 DCHECK(thread_checker_.CalledOnValidThread()); | 355 DCHECK(thread_checker_.CalledOnValidThread()); |
462 | 356 |
463 // Do not act on errors caused by things like Mojo pipes being closed during | 357 // Do not act on errors caused by things like Mojo pipes being closed during |
464 // shutdown. | 358 // shutdown. |
465 if (!remote_rendering_started_) | 359 if (!remote_rendering_started_) |
466 return; | 360 return; |
467 | 361 |
468 encountered_renderer_fatal_error_ = true; | 362 encountered_renderer_fatal_error_ = true; |
469 UpdateAndMaybeSwitch(UNKNOWN_START_TRIGGER, stop_trigger); | 363 UpdateAndMaybeSwitch(UNKNOWN_START_TRIGGER, stop_trigger); |
470 } | 364 } |
471 | 365 |
472 void RendererController::SetClient(MediaObserverClient* client) { | 366 void RendererController::SetClient(MediaObserverClient* client) { |
473 DCHECK(thread_checker_.CalledOnValidThread()); | 367 DCHECK(thread_checker_.CalledOnValidThread()); |
474 DCHECK(client); | 368 DCHECK(client); |
475 DCHECK(!client_); | 369 DCHECK(!client_); |
476 | 370 |
477 client_ = client; | 371 client_ = client; |
478 client_->ActivateViewportIntersectionMonitoring(IsRemoteSinkAvailable()); | 372 client_->ActivateViewportIntersectionMonitoring(IsRemoteSinkAvailable()); |
479 } | 373 } |
480 | 374 |
481 } // namespace remoting | 375 } // namespace remoting |
482 } // namespace media | 376 } // namespace media |
OLD | NEW |