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

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

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

Powered by Google App Engine
This is Rietveld 408576698