Chromium Code Reviews| 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 |