OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "chrome/browser/media/router/offscreen_presentation_manager.h" | |
6 | |
7 #include "content/public/browser/presentation_session_state_listener.h" | |
8 #include "content/public/browser/render_frame_host.h" | |
9 #include "content/public/browser/render_process_host.h" | |
10 #include "content/public/browser/web_contents.h" | |
11 | |
12 using content::PresentationSessionInfo; | |
13 using content::PresentationReceiverSessionAvailableCallback; | |
14 | |
15 namespace media_router { | |
16 | |
17 namespace { | |
18 | |
19 RenderFrameHostId GetMainFrameRenderFrameHostId( | |
20 content::WebContents* web_contents) { | |
21 content::RenderFrameHost* render_frame_host = web_contents->GetMainFrame(); | |
22 DCHECK(render_frame_host); | |
23 return RenderFrameHostId(render_frame_host->GetProcess()->GetID(), | |
24 render_frame_host->GetRoutingID()); | |
25 } | |
26 | |
27 } // namespace | |
28 | |
29 OffscreenPresenterContext::OffscreenPresenterContext( | |
30 content::WebContents* presenter_web_contents, | |
31 const std::string& presentation_id, | |
32 OffscreenPresentationManager* manager) | |
33 : presenter_web_contents_(presenter_web_contents), | |
34 presentation_id_(presentation_id), | |
35 manager_(manager) { | |
36 DCHECK(presenter_web_contents_); | |
37 DCHECK(manager_); | |
38 } | |
39 | |
40 OffscreenPresenterContext::~OffscreenPresenterContext() { | |
41 manager_->UnregisterPresenterTab(presenter_web_contents_); | |
42 } | |
43 | |
44 void OffscreenPresenterContext::GetPresentationReceiverSession( | |
45 const RenderFrameHostId& frame_id, | |
46 const content::PresentationReceiverSessionAvailableCallback& | |
47 success_callback, | |
48 const base::Callback<void(const std::string&)>& error_callback) { | |
49 if (!IsPresenterFrame(frame_id)) { | |
50 DVLOG(1) << "Not a presenter frame: " << frame_id.first << ", " | |
51 << frame_id.second; | |
52 error_callback.Run("Not a presenter frame"); | |
53 return; | |
54 } | |
55 | |
56 manager_->GetReceiverSession(frame_id, success_callback); | |
57 } | |
58 | |
59 std::vector<content::PresentationSessionInfo> | |
60 OffscreenPresenterContext::GetPresentationReceiverSessions( | |
61 const RenderFrameHostId& frame_id) const { | |
62 if (!IsPresenterFrame(frame_id)) { | |
63 DVLOG(1) << "Not a presenter frame: " << frame_id.first << ", " | |
64 << frame_id.second; | |
65 return std::vector<content::PresentationSessionInfo>(); | |
66 } | |
67 | |
68 return manager_->GetPresentationReceiverSessions(frame_id); | |
69 } | |
70 | |
71 bool OffscreenPresenterContext::IsPresenterFrame( | |
72 const RenderFrameHostId& frame_id) const { | |
73 return GetMainFrameRenderFrameHostId(presenter_web_contents_) == frame_id; | |
74 } | |
75 | |
76 void OffscreenPresenterContext::SendMessage( | |
77 const RenderFrameHostId& frame_id, | |
78 const content::PresentationSessionInfo& session, | |
79 scoped_ptr<content::PresentationSessionMessage> message, | |
80 const content::SendMessageCallback& callback) { | |
81 DCHECK_EQ(presentation_id_, session.presentation_id); | |
82 DCHECK(!session.IsController()); | |
83 DCHECK(IsPresenterFrame(frame_id)); | |
84 | |
85 manager_->SendMessage(session, message.Pass(), callback); | |
86 } | |
87 | |
88 void OffscreenPresenterContext::ListenForMessages( | |
89 const RenderFrameHostId& frame_id, | |
miu
2015/09/27 00:22:08
1. |frame_id| argument is not used, so can you rem
imcheng
2015/09/30 01:13:41
1. Removed. Also removed some other unused fields
| |
90 const content::PresentationSessionInfo& session, | |
91 const content::PresentationSessionMessageCallback& callback) { | |
92 DCHECK_EQ(presentation_id_, session.presentation_id); | |
93 DCHECK(!session.IsController()); | |
94 DCHECK(IsPresenterFrame(frame_id)); | |
95 | |
96 manager_->ListenForMessages(session, callback); | |
97 } | |
98 | |
99 void OffscreenPresenterContext::ListenForStateChanges( | |
100 const RenderFrameHostId& frame_id, | |
101 content::PresentationSessionStateListener* listener) { | |
102 DCHECK(listener); | |
103 DCHECK(IsPresenterFrame(frame_id)); | |
104 | |
105 const content::PresentationSessionInfo& session = listener->GetSessionInfo(); | |
miu
2015/09/27 00:22:08
These three lines need to be wrapped in a #ifndef
imcheng
2015/09/30 01:13:41
Removed
| |
106 DCHECK_EQ(presentation_id_, session.presentation_id); | |
107 DCHECK(!session.IsController()); | |
108 | |
109 manager_->ListenForStateChanges(listener); | |
110 } | |
111 | |
112 OffscreenController::OffscreenController( | |
113 const RenderFrameHostId& controller_frame_id, | |
114 const content::PresentationSessionInfo& session, | |
115 OffscreenPresentationManager* manager) | |
116 : controller_frame_id_(controller_frame_id), | |
117 session_(session), | |
118 manager_(manager) { | |
119 DCHECK(manager_); | |
120 DCHECK(session.IsController()); | |
121 } | |
122 | |
123 OffscreenController::~OffscreenController() { | |
124 manager_->UnregisterController(controller_frame_id_, | |
125 session_.presentation_id); | |
126 } | |
127 | |
128 void OffscreenController::SendMessage( | |
129 scoped_ptr<content::PresentationSessionMessage> message, | |
130 const content::SendMessageCallback& callback) { | |
131 manager_->SendMessage(session_, message.Pass(), callback); | |
132 } | |
133 | |
134 void OffscreenController::ListenForMessages( | |
135 const content::PresentationSessionMessageCallback& callback) { | |
136 manager_->ListenForMessages(session_, callback); | |
137 } | |
138 | |
139 void OffscreenController::ListenForStateChanges( | |
140 content::PresentationSessionStateListener* listener) { | |
141 DCHECK(listener); | |
142 DCHECK_EQ(session_.presentation_id, | |
143 listener->GetSessionInfo().presentation_id); | |
144 manager_->ListenForStateChanges(listener); | |
145 } | |
146 | |
147 OffscreenPresentationManager::~OffscreenPresentationManager() {} | |
148 | |
149 void OffscreenPresentationManager::RegisterPresenterTab( | |
150 const std::string& presentation_id, | |
151 content::WebContents* presenter_web_contents) { | |
152 DCHECK(presenter_web_contents); | |
153 RenderFrameHostId presenter_frame_id( | |
154 GetMainFrameRenderFrameHostId(presenter_web_contents)); | |
155 DCHECK(!ContainsKey(presenter_frames_, presenter_frame_id)); | |
156 presenter_frames_[presenter_frame_id] = presentation_id; | |
157 | |
158 auto* presentation_info = | |
159 GetOrCreateOffscreenPresentationInfo(presentation_id); | |
160 presentation_info->presenter_frame_id = presenter_frame_id; | |
161 // We wait until the controller side has registered before setting up the | |
162 // route. | |
163 } | |
164 | |
165 void OffscreenPresentationManager::UnregisterPresenterTab( | |
166 content::WebContents* presenter_web_contents) { | |
167 DCHECK(presenter_web_contents); | |
168 RenderFrameHostId presenter_frame_id( | |
169 GetMainFrameRenderFrameHostId(presenter_web_contents)); | |
170 | |
171 auto it = presenter_frames_.find(presenter_frame_id); | |
172 if (it == presenter_frames_.end()) | |
173 return; | |
174 | |
175 std::string presentation_id = it->second; | |
176 presenter_frames_.erase(it); | |
177 | |
178 auto* presentation_info = GetOffscreenPresentationInfo(presentation_id); | |
179 DCHECK(presentation_info); | |
180 DCHECK(presenter_frame_id == presentation_info->presenter_frame_id); | |
181 RemovePresenterAndNotifyStateChange(presentation_info); | |
182 if (presentation_info->IsEmpty()) | |
183 offscreen_presentation_infos_.erase(presentation_id); | |
184 } | |
185 | |
186 scoped_ptr<OffscreenPresenterContext> | |
187 OffscreenPresentationManager::GetOffscreenPresenterContext( | |
188 content::WebContents* presenter_web_contents) { | |
189 DCHECK(presenter_web_contents); | |
190 RenderFrameHostId presenter_frame_id( | |
191 GetMainFrameRenderFrameHostId(presenter_web_contents)); | |
192 auto it = presenter_frames_.find(presenter_frame_id); | |
193 if (it == presenter_frames_.end()) | |
194 return scoped_ptr<OffscreenPresenterContext>(); | |
195 | |
196 return make_scoped_ptr( | |
197 new OffscreenPresenterContext(presenter_web_contents, it->second, this)); | |
198 } | |
199 | |
200 scoped_ptr<OffscreenController> | |
201 OffscreenPresentationManager::RegisterController( | |
202 const content::PresentationSessionInfo& session, | |
203 const RenderFrameHostId& controller_frame_id) { | |
204 const std::string& presentation_id = session.presentation_id; | |
205 auto* presentation_info = | |
206 GetOrCreateOffscreenPresentationInfo(presentation_id); | |
207 | |
208 auto& route = presentation_info->route; | |
209 | |
210 // Check that this (presentation, controller) is not already registered. | |
211 DCHECK(!route.controller); | |
212 DCHECK(!route.presenter); | |
213 | |
214 route.controller.reset( | |
215 new OffscreenPresentationSessionInfo(controller_frame_id, session)); | |
216 content::PresentationSessionInfo presenter_session(std::string(), | |
217 presentation_id); | |
218 route.presenter.reset(new OffscreenPresentationSessionInfo( | |
219 controller_frame_id, presenter_session)); | |
220 | |
221 // Resolve pending getSession() request. | |
222 // Note: session objects for presenters do not contain presentation URLs. | |
223 if (!presentation_info->session_callback.is_null()) { | |
224 presentation_info->session_callback.Run(presenter_session); | |
225 presentation_info->session_callback.Reset(); | |
226 } | |
227 | |
228 return make_scoped_ptr( | |
229 new OffscreenController(controller_frame_id, session, this)); | |
230 } | |
231 | |
232 void OffscreenPresentationManager::GetReceiverSession( | |
233 const RenderFrameHostId& presenter_frame_id, | |
234 const PresentationReceiverSessionAvailableCallback& callback) { | |
235 DCHECK(!callback.is_null()); | |
236 DCHECK(ContainsKey(presenter_frames_, presenter_frame_id)); | |
237 | |
238 const std::string& presentation_id = presenter_frames_[presenter_frame_id]; | |
239 auto* presentation_info = GetOffscreenPresentationInfo(presentation_id); | |
240 DCHECK(presentation_info); | |
241 DCHECK(presenter_frame_id == presentation_info->presenter_frame_id); | |
242 | |
243 // Resolve with the first route. | |
244 const auto& route = presentation_info->route; | |
245 if (route.presenter) { | |
246 callback.Run(route.presenter->session); | |
247 return; | |
248 } else { | |
249 presentation_info->session_callback = callback; | |
250 } | |
251 } | |
252 | |
253 std::vector<content::PresentationSessionInfo> | |
254 OffscreenPresentationManager::GetPresentationReceiverSessions( | |
255 const RenderFrameHostId& presenter_frame_id) const { | |
256 DCHECK(ContainsKey(presenter_frames_, presenter_frame_id)); | |
257 | |
258 auto it = presenter_frames_.find(presenter_frame_id); | |
259 DCHECK(it != presenter_frames_.end()); | |
260 const std::string& presentation_id = it->second; | |
261 auto* presentation_info = GetOffscreenPresentationInfo(presentation_id); | |
262 DCHECK(presentation_info); | |
263 | |
264 std::vector<content::PresentationSessionInfo> sessions; | |
265 // TODO(imcheng): Support multiple controllers. | |
266 if (presentation_info->route.presenter) | |
267 sessions.push_back(presentation_info->route.presenter->session); | |
268 return sessions; | |
269 } | |
270 | |
271 void OffscreenPresentationManager::SendMessage( | |
272 const PresentationSessionInfo& session, | |
273 scoped_ptr<content::PresentationSessionMessage> message, | |
274 const content::SendMessageCallback& callback) { | |
275 const std::string& presentation_id = session.presentation_id; | |
276 auto* presentation_info = GetOffscreenPresentationInfo(presentation_id); | |
277 if (!presentation_info) { | |
278 LOG(ERROR) << "SendMessage: Unknown 1UA presentation " << presentation_id; | |
279 callback.Run(false); | |
280 return; | |
281 } | |
282 | |
283 auto& route = presentation_info->route; | |
284 // From presenter to controller. | |
285 if (!session.IsController()) { | |
286 auto* controller = route.controller.get(); | |
287 if (controller && !controller->message_callback.is_null()) { | |
288 ScopedVector<content::PresentationSessionMessage> messages; | |
289 messages.push_back(message.release()); | |
290 controller->message_callback.Run(messages.Pass(), true); | |
291 } | |
292 } else { | |
293 auto* presenter = route.presenter.get(); | |
294 // From controller to presenter. | |
295 if (presenter && !presenter->message_callback.is_null()) { | |
296 ScopedVector<content::PresentationSessionMessage> messages; | |
297 messages.push_back(message.release()); | |
298 presenter->message_callback.Run(messages.Pass(), true); | |
299 } | |
300 } | |
301 | |
302 callback.Run(true); | |
303 } | |
304 | |
305 void OffscreenPresentationManager::ListenForMessages( | |
306 const PresentationSessionInfo& session, | |
307 const content::PresentationSessionMessageCallback& callback) { | |
308 const std::string& presentation_id = session.presentation_id; | |
309 auto* presentation_info = GetOffscreenPresentationInfo(presentation_id); | |
310 if (!presentation_info) { | |
311 LOG(ERROR) << "ListenForMessages: Unknown 1UA presentation " | |
312 << presentation_id; | |
313 return; | |
314 } | |
315 | |
316 auto& route = presentation_info->route; | |
317 if (!session.IsController()) { | |
318 auto* presenter = route.presenter.get(); | |
319 if (!presenter) { | |
320 LOG(ERROR) << "ListenForMessages: presenter frame not found for " | |
321 << presentation_id; | |
322 return; | |
323 } | |
324 DVLOG_IF(2, !presenter->message_callback.is_null()) | |
325 << "Overwriting presenter frame message callback for " | |
326 << presentation_id; | |
327 presenter->message_callback = callback; | |
328 } else { | |
329 auto* controller = route.controller.get(); | |
330 if (!controller) { | |
331 LOG(ERROR) << "ListenForMessages: controller frame not found for " | |
332 << presentation_id; | |
333 return; | |
334 } | |
335 DVLOG_IF(2, !controller->message_callback.is_null()) | |
336 << "Overwriting controller frame message callback for " | |
337 << presentation_id; | |
338 controller->message_callback = callback; | |
339 } | |
340 } | |
341 | |
342 void OffscreenPresentationManager::ListenForStateChanges( | |
343 content::PresentationSessionStateListener* listener) { | |
344 DCHECK(listener); | |
345 | |
346 const content::PresentationSessionInfo& session = listener->GetSessionInfo(); | |
347 const std::string& presentation_id = session.presentation_id; | |
348 auto* presentation_info = GetOffscreenPresentationInfo(presentation_id); | |
349 if (!presentation_info) { | |
350 LOG(ERROR) << "ListenForMessages: Unknown 1UA presentation " | |
351 << presentation_id; | |
352 return; | |
353 } | |
354 | |
355 auto& route = presentation_info->route; | |
356 if (!session.IsController()) { | |
357 auto* presenter = route.presenter.get(); | |
358 if (!presenter) { | |
359 LOG(ERROR) << "ListenForMessages: presenter frame not found for " | |
360 << presentation_id; | |
361 return; | |
362 } | |
363 DVLOG_IF(2, presenter->state_change_listener) | |
364 << "Overwriting presenter frame state change listener for " | |
365 << presentation_id; | |
366 presenter->state_change_listener = listener; | |
367 } else { | |
368 auto* controller = route.controller.get(); | |
369 if (!controller) { | |
370 LOG(ERROR) << "ListenForMessages: controller frame not found for " | |
371 << presentation_id; | |
372 return; | |
373 } | |
374 DVLOG_IF(2, controller->state_change_listener) | |
375 << "Overwriting controller frame state change listener for " | |
376 << presentation_id; | |
377 controller->state_change_listener = listener; | |
378 } | |
379 } | |
380 | |
381 void OffscreenPresentationManager::UnregisterController( | |
382 const RenderFrameHostId& controller_frame_id, | |
383 const std::string& presentation_id) { | |
384 auto it = offscreen_presentation_infos_.find(presentation_id); | |
385 if (it == offscreen_presentation_infos_.end()) | |
386 return; | |
387 | |
388 auto* presentation_info = it->second; | |
389 RemoveControllerAndNotifyStateChange(presentation_info, controller_frame_id); | |
390 if (presentation_info->IsEmpty()) | |
391 offscreen_presentation_infos_.erase(it); | |
392 } | |
393 | |
394 OffscreenPresentationManager::OffscreenPresentationManager() {} | |
395 | |
396 void OffscreenPresentationManager::RemovePresenterAndNotifyStateChange( | |
397 OffscreenPresentationInfo* presentation_info) { | |
398 presentation_info->presenter_frame_id = RenderFrameHostId(); | |
399 presentation_info->session_callback.Reset(); | |
400 | |
401 auto& route = presentation_info->route; | |
402 if (route.presenter) { | |
403 route.presenter.reset(); | |
404 auto& controller = route.controller; | |
405 if (controller && controller->state_change_listener) { | |
406 controller->state_change_listener->OnSessionStateChanged( | |
407 content::PRESENTATION_SESSION_STATE_DISCONNECTED); | |
408 } | |
409 } | |
410 } | |
411 | |
412 void OffscreenPresentationManager::RemoveControllerAndNotifyStateChange( | |
413 OffscreenPresentationInfo* presentation_info, | |
414 const RenderFrameHostId& controller_frame_id) { | |
415 auto& route = presentation_info->route; | |
416 if (!route.controller || | |
417 route.controller->controller_frame_id != controller_frame_id) | |
418 return; | |
419 | |
420 route.controller.reset(); | |
421 | |
422 // Notify the corresponding presenter session object. | |
423 auto& presenter = route.presenter; | |
424 if (presenter && presenter->state_change_listener) { | |
425 presenter->state_change_listener->OnSessionStateChanged( | |
426 content::PRESENTATION_SESSION_STATE_DISCONNECTED); | |
427 } | |
428 } | |
429 | |
430 OffscreenPresentationManager::OffscreenPresentationInfo* | |
431 OffscreenPresentationManager::GetOrCreateOffscreenPresentationInfo( | |
432 const std::string& presentation_id) { | |
433 OffscreenPresentationInfo* info = nullptr; | |
434 auto presentation_info_it = | |
435 offscreen_presentation_infos_.find(presentation_id); | |
436 if (presentation_info_it == offscreen_presentation_infos_.end()) { | |
437 info = new OffscreenPresentationInfo; | |
438 offscreen_presentation_infos_.insert(presentation_id, | |
439 make_scoped_ptr(info)); | |
440 } else { | |
441 info = presentation_info_it->second; | |
442 } | |
443 DCHECK(info); | |
444 return info; | |
445 } | |
446 | |
447 OffscreenPresentationManager::OffscreenPresentationInfo* | |
448 OffscreenPresentationManager::GetOffscreenPresentationInfo( | |
449 const std::string& presentation_id) const { | |
450 OffscreenPresentationInfo* info = nullptr; | |
451 auto presentation_info_it = | |
452 offscreen_presentation_infos_.find(presentation_id); | |
453 return presentation_info_it == offscreen_presentation_infos_.end() | |
454 ? nullptr | |
455 : presentation_info_it->second; | |
456 } | |
457 | |
458 OffscreenPresentationManager::OffscreenPresentationSessionInfo:: | |
459 OffscreenPresentationSessionInfo( | |
460 const RenderFrameHostId& controller_frame_id, | |
461 const content::PresentationSessionInfo& session) | |
462 : controller_frame_id(controller_frame_id), | |
463 session(session), | |
464 state_change_listener(nullptr) {} | |
465 | |
466 OffscreenPresentationManager::OffscreenPresentationSessionInfo:: | |
467 ~OffscreenPresentationSessionInfo() {} | |
468 | |
469 OffscreenPresentationManager::OffscreenPresentationRoute:: | |
470 OffscreenPresentationRoute() {} | |
471 | |
472 OffscreenPresentationManager::OffscreenPresentationRoute:: | |
473 ~OffscreenPresentationRoute() {} | |
474 | |
475 OffscreenPresentationManager::OffscreenPresentationInfo:: | |
476 OffscreenPresentationInfo() {} | |
477 | |
478 OffscreenPresentationManager::OffscreenPresentationInfo:: | |
479 ~OffscreenPresentationInfo() {} | |
480 | |
481 bool OffscreenPresentationManager::OffscreenPresentationInfo::IsEmpty() const { | |
482 return !route.presenter && !route.controller; | |
483 } | |
484 | |
485 } // namespace media_router | |
OLD | NEW |