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

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

Issue 2631993002: Media Remoting: UMAs to track session events and measurements. (Closed)
Patch Set: Fixes per 1st round comments from xjz and holte. Created 3 years, 11 months 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
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/remoting_renderer_controller.h" 5 #include "media/remoting/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 "media/remoting/remoting_cdm_context.h" 11 #include "media/remoting/remoting_cdm_context.h"
11 12
12 namespace media { 13 namespace media {
13 14
14 RemotingRendererController::RemotingRendererController( 15 RemotingRendererController::RemotingRendererController(
15 scoped_refptr<RemotingSourceImpl> remoting_source) 16 scoped_refptr<RemotingSourceImpl> remoting_source)
16 : remoting_source_(remoting_source), weak_factory_(this) { 17 : remoting_source_(remoting_source), weak_factory_(this) {
17 remoting_source_->AddClient(this); 18 remoting_source_->AddClient(this);
18 } 19 }
19 20
20 RemotingRendererController::~RemotingRendererController() { 21 RemotingRendererController::~RemotingRendererController() {
21 DCHECK(thread_checker_.CalledOnValidThread()); 22 DCHECK(thread_checker_.CalledOnValidThread());
23 metrics_recorder_.WillStopSession(remoting::MEDIA_ELEMENT_DESTROYED);
22 remoting_source_->RemoveClient(this); 24 remoting_source_->RemoveClient(this);
23 } 25 }
24 26
25 void RemotingRendererController::OnStarted(bool success) { 27 void RemotingRendererController::OnStarted(bool success) {
26 DCHECK(thread_checker_.CalledOnValidThread()); 28 DCHECK(thread_checker_.CalledOnValidThread());
27 29
28 if (success) { 30 if (success) {
29 VLOG(1) << "Remoting started successively."; 31 VLOG(1) << "Remoting started successively.";
30 if (remote_rendering_started_) { 32 if (remote_rendering_started_) {
33 metrics_recorder_.DidStartSession();
31 DCHECK(!switch_renderer_cb_.is_null()); 34 DCHECK(!switch_renderer_cb_.is_null());
32 switch_renderer_cb_.Run(); 35 switch_renderer_cb_.Run();
33 } else { 36 } else {
34 remoting_source_->StopRemoting(this); 37 remoting_source_->StopRemoting(this);
35 } 38 }
36 } else { 39 } else {
37 VLOG(1) << "Failed to start remoting."; 40 VLOG(1) << "Failed to start remoting.";
38 remote_rendering_started_ = false; 41 remote_rendering_started_ = false;
42 metrics_recorder_.WillStopSession(remoting::START_RACE);
39 } 43 }
40 } 44 }
41 45
42 void RemotingRendererController::OnSessionStateChanged() { 46 void RemotingRendererController::OnSessionStateChanged() {
43 DCHECK(thread_checker_.CalledOnValidThread()); 47 DCHECK(thread_checker_.CalledOnValidThread());
48 UpdateFromSessionState(remoting::SINK_AVAILABLE, remoting::ROUTE_TERMINATED);
49 }
44 50
45 VLOG(1) << "OnSessionStateChanged: " << remoting_source_->state(); 51 void RemotingRendererController::UpdateFromSessionState(
52 remoting::StartTrigger start_trigger,
53 remoting::StopTrigger stop_trigger) {
54 VLOG(1) << "UpdateFromSessionState: " << remoting_source_->state();
46 if (!sink_available_changed_cb_.is_null()) 55 if (!sink_available_changed_cb_.is_null())
47 sink_available_changed_cb_.Run(IsRemoteSinkAvailable()); 56 sink_available_changed_cb_.Run(IsRemoteSinkAvailable());
48 57
49 UpdateInterstitial(base::nullopt); 58 UpdateInterstitial(base::nullopt);
50 UpdateAndMaybeSwitch(); 59 UpdateAndMaybeSwitch(start_trigger, stop_trigger);
51 } 60 }
52 61
53 bool RemotingRendererController::IsRemoteSinkAvailable() { 62 bool RemotingRendererController::IsRemoteSinkAvailable() {
54 DCHECK(thread_checker_.CalledOnValidThread()); 63 DCHECK(thread_checker_.CalledOnValidThread());
55 64
56 switch (remoting_source_->state()) { 65 switch (remoting_source_->state()) {
57 case SESSION_CAN_START: 66 case SESSION_CAN_START:
58 case SESSION_STARTING: 67 case SESSION_STARTING:
59 case SESSION_STARTED: 68 case SESSION_STARTED:
60 return true; 69 return true;
61 case SESSION_UNAVAILABLE: 70 case SESSION_UNAVAILABLE:
62 case SESSION_STOPPING: 71 case SESSION_STOPPING:
63 case SESSION_PERMANENTLY_STOPPED: 72 case SESSION_PERMANENTLY_STOPPED:
64 return false; 73 return false;
65 } 74 }
66 75
67 return false; // To suppress compile warning. 76 return false; // To suppress compile warning.
68 } 77 }
69 78
70 void RemotingRendererController::OnEnteredFullscreen() { 79 void RemotingRendererController::OnEnteredFullscreen() {
71 DCHECK(thread_checker_.CalledOnValidThread()); 80 DCHECK(thread_checker_.CalledOnValidThread());
72 81
73 is_fullscreen_ = true; 82 is_fullscreen_ = true;
74 UpdateAndMaybeSwitch(); 83 // See notes in OnBecameDominantVisibleContent() for why this is forced:
84 is_dominant_content_ = true;
85 UpdateAndMaybeSwitch(remoting::ENTERED_FULLSCREEN,
86 remoting::UNKNOWN_STOP_TRIGGER);
75 } 87 }
76 88
77 void RemotingRendererController::OnExitedFullscreen() { 89 void RemotingRendererController::OnExitedFullscreen() {
78 DCHECK(thread_checker_.CalledOnValidThread()); 90 DCHECK(thread_checker_.CalledOnValidThread());
79 91
80 is_fullscreen_ = false; 92 is_fullscreen_ = false;
81 UpdateAndMaybeSwitch(); 93 // See notes in OnBecameDominantVisibleContent() for why this is forced:
94 is_dominant_content_ = false;
95 UpdateAndMaybeSwitch(remoting::UNKNOWN_START_TRIGGER,
96 remoting::EXITED_FULLSCREEN);
82 } 97 }
83 98
84 void RemotingRendererController::OnBecameDominantVisibleContent( 99 void RemotingRendererController::OnBecameDominantVisibleContent(
85 bool is_dominant) { 100 bool is_dominant) {
86 DCHECK(thread_checker_.CalledOnValidThread()); 101 DCHECK(thread_checker_.CalledOnValidThread());
102
103 // Two scenarios where "dominance" status mixes with fullscreen transitions:
104 //
105 // 1. Just before/after entering fullscreen, the element will, of course,
106 // become the dominant on-screen content via automatic page layout.
107 // 2. Just before/after exiting fullscreen, the element may or may not
108 // shrink in size enough to become non-dominant. However, exiting
109 // fullscreen was caused by a user action that explicitly indicates a
110 // desire to exit remoting, so even if the element is still dominant,
111 // remoting should be shut down.
112 //
113 // Thus, to achieve the desired behaviors, |is_dominant_content_| is force-set
114 // in OnEnteredFullscreen() and OnExitedFullscreen(), and changes to it here
115 // are ignored while in fullscreen.
116 if (is_fullscreen_)
117 return;
118
87 is_dominant_content_ = is_dominant; 119 is_dominant_content_ = is_dominant;
88 UpdateAndMaybeSwitch(); 120 UpdateAndMaybeSwitch(remoting::BECAME_DOMINANT_CONTENT,
121 remoting::BECAME_AUXILIARY_CONTENT);
89 } 122 }
90 123
91 void RemotingRendererController::OnSetCdm(CdmContext* cdm_context) { 124 void RemotingRendererController::OnSetCdm(CdmContext* cdm_context) {
92 DCHECK(thread_checker_.CalledOnValidThread()); 125 DCHECK(thread_checker_.CalledOnValidThread());
93 126
94 auto* remoting_cdm_context = RemotingCdmContext::From(cdm_context); 127 auto* remoting_cdm_context = RemotingCdmContext::From(cdm_context);
95 if (!remoting_cdm_context) 128 if (!remoting_cdm_context)
96 return; 129 return;
97 130
98 remoting_source_->RemoveClient(this); 131 remoting_source_->RemoveClient(this);
99 remoting_source_ = remoting_cdm_context->GetRemotingSource(); 132 remoting_source_ = remoting_cdm_context->GetRemotingSource();
100 remoting_source_->AddClient(this); // Calls OnSessionStateChanged(). 133 remoting_source_->AddClient(this);
101 UpdateAndMaybeSwitch(); 134 UpdateFromSessionState(remoting::CDM_READY, remoting::DECRYPTION_ERROR);
102 } 135 }
103 136
104 void RemotingRendererController::OnRemotePlaybackDisabled(bool disabled) { 137 void RemotingRendererController::OnRemotePlaybackDisabled(bool disabled) {
105 DCHECK(thread_checker_.CalledOnValidThread()); 138 DCHECK(thread_checker_.CalledOnValidThread());
106 139
107 is_remote_playback_disabled_ = disabled; 140 is_remote_playback_disabled_ = disabled;
108 UpdateAndMaybeSwitch(); 141 metrics_recorder_.OnRemotePlaybackDisabled(disabled);
142 UpdateAndMaybeSwitch(remoting::ENABLED_BY_PAGE, remoting::DISABLED_BY_PAGE);
109 } 143 }
110 144
111 void RemotingRendererController::OnSetPoster(const GURL& poster_url) { 145 void RemotingRendererController::OnSetPoster(const GURL& poster_url) {
112 DCHECK(thread_checker_.CalledOnValidThread()); 146 DCHECK(thread_checker_.CalledOnValidThread());
113 147
114 if (poster_url != poster_url_) { 148 if (poster_url != poster_url_) {
115 poster_url_ = poster_url; 149 poster_url_ = poster_url;
116 if (poster_url_.is_empty()) 150 if (poster_url_.is_empty())
117 UpdateInterstitial(SkBitmap()); 151 UpdateInterstitial(SkBitmap());
118 else 152 else
119 DownloadPosterImage(); 153 DownloadPosterImage();
120 } 154 }
121 } 155 }
122 156
123 void RemotingRendererController::SetSwitchRendererCallback( 157 void RemotingRendererController::SetSwitchRendererCallback(
124 const base::Closure& cb) { 158 const base::Closure& cb) {
125 DCHECK(thread_checker_.CalledOnValidThread()); 159 DCHECK(thread_checker_.CalledOnValidThread());
126 DCHECK(!cb.is_null()); 160 DCHECK(!cb.is_null());
127 161
128 switch_renderer_cb_ = cb; 162 switch_renderer_cb_ = cb;
129 UpdateAndMaybeSwitch(); 163 // Note: Not calling UpdateAndMaybeSwitch() here since this method should be
164 // called during the initialization phase of this RemotingRendererController;
165 // and definitely before a whole lot of other things that are needed to
166 // trigger a switch.
xjz 2017/01/17 21:52:04 nit: Now this comment can be deleted.
miu 2017/01/17 22:46:31 Notice that I re-worded the comment since the last
130 } 167 }
131 168
132 void RemotingRendererController::SetRemoteSinkAvailableChangedCallback( 169 void RemotingRendererController::SetRemoteSinkAvailableChangedCallback(
133 const base::Callback<void(bool)>& cb) { 170 const base::Callback<void(bool)>& cb) {
134 DCHECK(thread_checker_.CalledOnValidThread()); 171 DCHECK(thread_checker_.CalledOnValidThread());
135 172
136 sink_available_changed_cb_ = cb; 173 sink_available_changed_cb_ = cb;
137 if (!sink_available_changed_cb_.is_null()) 174 if (!sink_available_changed_cb_.is_null())
138 sink_available_changed_cb_.Run(IsRemoteSinkAvailable()); 175 sink_available_changed_cb_.Run(IsRemoteSinkAvailable());
139 } 176 }
(...skipping 13 matching lines...) Expand all
153 190
154 remoting_source_->StartDataPipe(std::move(audio_data_pipe), 191 remoting_source_->StartDataPipe(std::move(audio_data_pipe),
155 std::move(video_data_pipe), done_callback); 192 std::move(video_data_pipe), done_callback);
156 } 193 }
157 194
158 void RemotingRendererController::OnMetadataChanged( 195 void RemotingRendererController::OnMetadataChanged(
159 const PipelineMetadata& metadata) { 196 const PipelineMetadata& metadata) {
160 DCHECK(thread_checker_.CalledOnValidThread()); 197 DCHECK(thread_checker_.CalledOnValidThread());
161 198
162 const gfx::Size old_size = pipeline_metadata_.natural_size; 199 const gfx::Size old_size = pipeline_metadata_.natural_size;
200 const bool was_audio_codec_supported = has_audio() && IsAudioCodecSupported();
201 const bool was_video_codec_supported = has_video() && IsVideoCodecSupported();
163 pipeline_metadata_ = metadata; 202 pipeline_metadata_ = metadata;
203 const bool is_audio_codec_supported = has_audio() && IsAudioCodecSupported();
204 const bool is_video_codec_supported = has_video() && IsVideoCodecSupported();
205 metrics_recorder_.OnPipelineMetadataChanged(metadata);
164 206
165 is_encrypted_ = false; 207 is_encrypted_ = false;
166 if (has_video()) 208 if (has_video())
167 is_encrypted_ |= metadata.video_decoder_config.is_encrypted(); 209 is_encrypted_ |= metadata.video_decoder_config.is_encrypted();
168 if (has_audio()) 210 if (has_audio())
169 is_encrypted_ |= metadata.audio_decoder_config.is_encrypted(); 211 is_encrypted_ |= metadata.audio_decoder_config.is_encrypted();
170 212
171 if (pipeline_metadata_.natural_size != old_size) 213 if (pipeline_metadata_.natural_size != old_size)
172 UpdateInterstitial(base::nullopt); 214 UpdateInterstitial(base::nullopt);
173 215
174 UpdateAndMaybeSwitch(); 216 remoting::StartTrigger start_trigger = remoting::UNKNOWN_START_TRIGGER;
217 if (!was_audio_codec_supported && is_audio_codec_supported)
218 start_trigger = remoting::SUPPORTED_AUDIO_CODEC;
219 if (!was_video_codec_supported && is_video_codec_supported) {
220 start_trigger = start_trigger == remoting::SUPPORTED_AUDIO_CODEC
221 ? remoting::SUPPORTED_AUDIO_AND_VIDEO_CODECS
222 : remoting::SUPPORTED_VIDEO_CODEC;
223 }
224 remoting::StopTrigger stop_trigger = remoting::UNKNOWN_STOP_TRIGGER;
225 if (was_audio_codec_supported && !is_audio_codec_supported)
226 stop_trigger = remoting::UNSUPPORTED_AUDIO_CODEC;
227 if (was_video_codec_supported && !is_video_codec_supported) {
228 stop_trigger = stop_trigger == remoting::UNSUPPORTED_AUDIO_CODEC
229 ? remoting::UNSUPPORTED_AUDIO_AND_VIDEO_CODECS
230 : remoting::UNSUPPORTED_VIDEO_CODEC;
231 }
232 UpdateAndMaybeSwitch(start_trigger, stop_trigger);
175 } 233 }
176 234
177 bool RemotingRendererController::IsVideoCodecSupported() { 235 bool RemotingRendererController::IsVideoCodecSupported() {
178 DCHECK(thread_checker_.CalledOnValidThread()); 236 DCHECK(thread_checker_.CalledOnValidThread());
179 DCHECK(has_video()); 237 DCHECK(has_video());
180 238
181 switch (pipeline_metadata_.video_decoder_config.codec()) { 239 switch (pipeline_metadata_.video_decoder_config.codec()) {
182 case VideoCodec::kCodecH264: 240 case VideoCodec::kCodecH264:
183 case VideoCodec::kCodecVP8: 241 case VideoCodec::kCodecVP8:
184 return true; 242 return true;
(...skipping 30 matching lines...) Expand all
215 VLOG(2) << "Remoting does not support audio codec: " 273 VLOG(2) << "Remoting does not support audio codec: "
216 << pipeline_metadata_.audio_decoder_config.codec(); 274 << pipeline_metadata_.audio_decoder_config.codec();
217 return false; 275 return false;
218 } 276 }
219 } 277 }
220 278
221 void RemotingRendererController::OnPlaying() { 279 void RemotingRendererController::OnPlaying() {
222 DCHECK(thread_checker_.CalledOnValidThread()); 280 DCHECK(thread_checker_.CalledOnValidThread());
223 281
224 is_paused_ = false; 282 is_paused_ = false;
225 UpdateAndMaybeSwitch(); 283 UpdateAndMaybeSwitch(remoting::PLAY_COMMAND, remoting::UNKNOWN_STOP_TRIGGER);
226 } 284 }
227 285
228 void RemotingRendererController::OnPaused() { 286 void RemotingRendererController::OnPaused() {
229 DCHECK(thread_checker_.CalledOnValidThread()); 287 DCHECK(thread_checker_.CalledOnValidThread());
230 288
231 is_paused_ = true; 289 is_paused_ = true;
232 } 290 }
233 291
234 bool RemotingRendererController::ShouldBeRemoting() { 292 bool RemotingRendererController::ShouldBeRemoting() {
235 DCHECK(thread_checker_.CalledOnValidThread()); 293 DCHECK(thread_checker_.CalledOnValidThread());
236 294
237 if (switch_renderer_cb_.is_null()) { 295 if (switch_renderer_cb_.is_null()) {
238 DCHECK(!remote_rendering_started_); 296 DCHECK(!remote_rendering_started_);
239 return false; // No way to switch to a RemotingRenderImpl. 297 return false; // No way to switch to a RemotingRenderImpl.
240 } 298 }
241 299
242 const RemotingSessionState state = remoting_source_->state(); 300 const RemotingSessionState state = remoting_source_->state();
243 if (is_encrypted_) { 301 if (is_encrypted_) {
244 // Due to technical limitations when playing encrypted content, once a 302 // Due to technical limitations when playing encrypted content, once a
245 // remoting session has been started, always return true here to indicate 303 // remoting session has been started, always return true here to indicate
246 // that the RemotingRendererImpl should be used. In the stopped states, 304 // that the RemotingRendererImpl should be used. In the stopped states,
247 // RemotingRendererImpl will display an interstitial to notify the user that 305 // RemotingRendererImpl will display an interstitial to notify the user that
248 // local rendering cannot be resumed. 306 // local rendering cannot be resumed.
249 return state == RemotingSessionState::SESSION_STARTED || 307 return state == RemotingSessionState::SESSION_STARTED ||
250 state == RemotingSessionState::SESSION_STOPPING || 308 state == RemotingSessionState::SESSION_STOPPING ||
251 state == RemotingSessionState::SESSION_PERMANENTLY_STOPPED; 309 state == RemotingSessionState::SESSION_PERMANENTLY_STOPPED;
252 } 310 }
253 311
254 if (irregular_playback_detected_) 312 if (encountered_renderer_fatal_error_)
255 return false; 313 return false;
256 314
257 switch (state) { 315 switch (state) {
258 case SESSION_UNAVAILABLE: 316 case SESSION_UNAVAILABLE:
259 return false; // Cannot remote media without a remote sink. 317 return false; // Cannot remote media without a remote sink.
260 case SESSION_CAN_START: 318 case SESSION_CAN_START:
261 case SESSION_STARTING: 319 case SESSION_STARTING:
262 case SESSION_STARTED: 320 case SESSION_STARTED:
263 break; // Media remoting is possible, assuming other requirments are met. 321 break; // Media remoting is possible, assuming other requirments are met.
264 case SESSION_STOPPING: 322 case SESSION_STOPPING:
(...skipping 17 matching lines...) Expand all
282 340
283 if (is_remote_playback_disabled_) 341 if (is_remote_playback_disabled_)
284 return false; 342 return false;
285 343
286 // Normally, entering fullscreen or being the dominant visible content is the 344 // Normally, entering fullscreen or being the dominant visible content is the
287 // signal that starts remote rendering. However, current technical limitations 345 // signal that starts remote rendering. However, current technical limitations
288 // require encrypted content be remoted without waiting for a user signal. 346 // require encrypted content be remoted without waiting for a user signal.
289 return is_fullscreen_ || is_dominant_content_; 347 return is_fullscreen_ || is_dominant_content_;
290 } 348 }
291 349
292 void RemotingRendererController::UpdateAndMaybeSwitch() { 350 void RemotingRendererController::UpdateAndMaybeSwitch(
351 remoting::StartTrigger start_trigger,
352 remoting::StopTrigger stop_trigger) {
293 DCHECK(thread_checker_.CalledOnValidThread()); 353 DCHECK(thread_checker_.CalledOnValidThread());
294 354
295 bool should_be_remoting = ShouldBeRemoting(); 355 bool should_be_remoting = ShouldBeRemoting();
296 356
297 if (remote_rendering_started_ == should_be_remoting) 357 if (remote_rendering_started_ == should_be_remoting)
298 return; 358 return;
299 359
300 // Only switch to remoting when media is playing. Since the renderer is 360 // Only switch to remoting when media is playing. Since the renderer is
301 // created when video starts loading/playing, receiver will display a black 361 // created when video starts loading/playing, receiver will display a black
302 // screen before video starts playing if switching to remoting when paused. 362 // screen before video starts playing if switching to remoting when paused.
303 // Keep mirroring the video in this case is good for the user experience. 363 // Thus, the user experience is improved by not starting remoting until
364 // playback resumes.
304 if (should_be_remoting && is_paused_) 365 if (should_be_remoting && is_paused_)
305 return; 366 return;
306 367
307 // Switch between local renderer and remoting renderer. 368 // Switch between local renderer and remoting renderer.
308 remote_rendering_started_ = should_be_remoting; 369 remote_rendering_started_ = should_be_remoting;
309 370
310 if (remote_rendering_started_) { 371 if (remote_rendering_started_) {
311 DCHECK(!switch_renderer_cb_.is_null()); 372 DCHECK(!switch_renderer_cb_.is_null());
312 if (remoting_source_->state() == 373 if (remoting_source_->state() ==
313 RemotingSessionState::SESSION_PERMANENTLY_STOPPED) { 374 RemotingSessionState::SESSION_PERMANENTLY_STOPPED) {
314 switch_renderer_cb_.Run(); 375 switch_renderer_cb_.Run();
315 return; 376 return;
316 } 377 }
378 DCHECK_NE(start_trigger, remoting::UNKNOWN_START_TRIGGER);
379 metrics_recorder_.WillStartSession(start_trigger);
317 // |switch_renderer_cb_.Run()| will be called after remoting is started 380 // |switch_renderer_cb_.Run()| will be called after remoting is started
318 // successfully. 381 // successfully.
319 remoting_source_->StartRemoting(this); 382 remoting_source_->StartRemoting(this);
320 } else { 383 } else {
321 // For encrypted content, it's only valid to switch to remoting renderer, 384 // For encrypted content, it's only valid to switch to remoting renderer,
322 // and never back to the local renderer. The RemotingCdmController will 385 // and never back to the local renderer. The RemotingCdmController will
323 // force-stop the session when remoting has ended; so no need to call 386 // force-stop the session when remoting has ended; so no need to call
324 // StopRemoting() from here. 387 // StopRemoting() from here.
325 DCHECK(!is_encrypted_); 388 DCHECK(!is_encrypted_);
389 DCHECK_NE(stop_trigger, remoting::UNKNOWN_STOP_TRIGGER);
390 metrics_recorder_.WillStopSession(stop_trigger);
326 switch_renderer_cb_.Run(); 391 switch_renderer_cb_.Run();
327 remoting_source_->StopRemoting(this); 392 remoting_source_->StopRemoting(this);
328 } 393 }
329 } 394 }
330 395
331 void RemotingRendererController::SetShowInterstitialCallback( 396 void RemotingRendererController::SetShowInterstitialCallback(
332 const ShowInterstitialCallback& cb) { 397 const ShowInterstitialCallback& cb) {
333 DCHECK(thread_checker_.CalledOnValidThread()); 398 DCHECK(thread_checker_.CalledOnValidThread());
334 show_interstitial_cb_ = cb; 399 show_interstitial_cb_ = cb;
335 UpdateInterstitial(SkBitmap()); 400 UpdateInterstitial(SkBitmap());
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
369 } 434 }
370 435
371 show_interstitial_cb_.Run(image, pipeline_metadata_.natural_size, type); 436 show_interstitial_cb_.Run(image, pipeline_metadata_.natural_size, type);
372 } 437 }
373 438
374 void RemotingRendererController::DownloadPosterImage() { 439 void RemotingRendererController::DownloadPosterImage() {
375 if (download_poster_cb_.is_null() || show_interstitial_cb_.is_null()) 440 if (download_poster_cb_.is_null() || show_interstitial_cb_.is_null())
376 return; 441 return;
377 DCHECK(!poster_url_.is_empty()); 442 DCHECK(!poster_url_.is_empty());
378 443
444 const base::TimeTicks download_start_time = base::TimeTicks::Now();
379 download_poster_cb_.Run( 445 download_poster_cb_.Run(
380 poster_url_, 446 poster_url_,
381 base::Bind(&RemotingRendererController::OnPosterImageDownloaded, 447 base::Bind(&RemotingRendererController::OnPosterImageDownloaded,
382 weak_factory_.GetWeakPtr(), poster_url_)); 448 weak_factory_.GetWeakPtr(), poster_url_, download_start_time));
383 } 449 }
384 450
385 void RemotingRendererController::OnPosterImageDownloaded( 451 void RemotingRendererController::OnPosterImageDownloaded(
386 const GURL& download_url, 452 const GURL& download_url,
453 base::TimeTicks download_start_time,
387 const SkBitmap& image) { 454 const SkBitmap& image) {
388 DCHECK(thread_checker_.CalledOnValidThread()); 455 DCHECK(thread_checker_.CalledOnValidThread());
389 456
457 metrics_recorder_.OnPosterImageDownloaded(
458 base::TimeTicks::Now() - download_start_time, !image.drawsNothing());
390 if (download_url != poster_url_) 459 if (download_url != poster_url_)
391 return; // The poster image URL has changed during the download. 460 return; // The poster image URL has changed during the download.
392 UpdateInterstitial(image); 461 UpdateInterstitial(image);
393 } 462 }
394 463
395 void RemotingRendererController::OnIrregularPlaybackDetected() { 464 void RemotingRendererController::OnRendererFatalError(
465 remoting::StopTrigger stop_trigger) {
396 DCHECK(thread_checker_.CalledOnValidThread()); 466 DCHECK(thread_checker_.CalledOnValidThread());
397 467
398 if (irregular_playback_detected_) 468 // Do not act on errors caused by things like Mojo pipes being closed during
469 // shutdown.
470 if (!remote_rendering_started_)
399 return; 471 return;
400 irregular_playback_detected_ = true; 472
401 UpdateAndMaybeSwitch(); 473 encountered_renderer_fatal_error_ = true;
474 UpdateAndMaybeSwitch(remoting::UNKNOWN_START_TRIGGER, stop_trigger);
402 } 475 }
403 476
404 } // namespace media 477 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698