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