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/presentation_service_delegate_impl.h" | |
6 | |
7 #include <string> | |
8 | |
9 #include "base/containers/scoped_ptr_hash_map.h" | |
10 #include "base/guid.h" | |
11 #include "base/strings/string_util.h" | |
12 #include "base/strings/stringprintf.h" | |
13 #include "chrome/browser/media/router/create_session_request.h" | |
14 #include "chrome/browser/media/router/media_route.h" | |
15 #include "chrome/browser/media/router/media_router.h" | |
16 #include "chrome/browser/media/router/media_sink.h" | |
17 #include "chrome/browser/media/router/media_source_helper.h" | |
18 #include "chrome/browser/media/router/presentation_helper.h" | |
19 #include "chrome/browser/media/router/presentation_media_sinks_observer.h" | |
20 #include "chrome/browser/sessions/session_tab_helper.h" | |
21 #include "content/public/browser/presentation_screen_availability_listener.h" | |
22 #include "content/public/browser/presentation_session.h" | |
23 #include "content/public/browser/render_frame_host.h" | |
24 #include "content/public/browser/render_process_host.h" | |
25 | |
26 DEFINE_WEB_CONTENTS_USER_DATA_KEY( | |
27 media_router::PresentationServiceDelegateImpl); | |
28 | |
29 using content::RenderFrameHost; | |
30 | |
31 namespace media_router { | |
32 | |
33 namespace { | |
34 | |
35 // Helper function to extract ID for a RFH. | |
36 RenderFrameHostId GetRenderFrameHostId(RenderFrameHost* rfh) { | |
37 int render_process_id = rfh->GetProcess()->GetID(); | |
38 int render_frame_id = rfh->GetRoutingID(); | |
39 return RenderFrameHostId(render_process_id, render_frame_id); | |
40 } | |
41 | |
42 // Gets the host name associated with the frame given by |rfh_id|. | |
43 std::string GetSourceHostForFrame(RenderFrameHostId rfh_id) { | |
44 RenderFrameHost* rfh = RenderFrameHost::FromID(rfh_id.first, rfh_id.second); | |
45 DCHECK(rfh); | |
46 std::string host = rfh->GetLastCommittedURL().host(); | |
47 if (StartsWithASCII(host, "www.", false)) | |
48 host = host.substr(4); | |
49 return host; | |
50 } | |
51 | |
52 } // namespace | |
53 | |
54 // Helper class for PresentationServiceDelegateImpl to manage | |
55 // listeners and default presentation info in a render frame. | |
56 class PresentationFrame final { | |
57 public: | |
58 using DelegateObserver = content::PresentationServiceDelegate::Observer; | |
59 | |
60 PresentationFrame(content::WebContents* web_contents, MediaRouter* router); | |
61 ~PresentationFrame(); | |
62 | |
63 // Returns true if listener was added. | |
64 bool AddScreenAvailabilityListener( | |
65 content::PresentationScreenAvailabilityListener* listener); | |
66 | |
67 // Returns true if listener was removed. | |
68 bool RemoveScreenAvailabilityListener( | |
69 content::PresentationScreenAvailabilityListener* listener); | |
70 | |
71 // Returns true if there is a listener for |source_id|. | |
72 bool HasScreenAvailabilityListenerForTest( | |
73 const MediaSourceId& source_id) const; | |
74 | |
75 // Returns the number of screen-availability listeners. | |
76 int NumScreenAvailabilityListeners() const; | |
77 | |
78 // Sets the default presentation URL and ID. | |
79 void SetDefaultPresentationInfo(const std::string& default_presentation_url, | |
80 const std::string& default_presentation_id); | |
81 | |
82 // Returns empty string if no default presentation ID is set. | |
83 std::string GetDefaultPresentationId() const; | |
84 void set_delegate_observer(DelegateObserver* observer) { | |
85 delegate_observer_ = observer; | |
86 } | |
87 DelegateObserver* delegate_observer() const { return delegate_observer_; } | |
88 | |
89 void Reset(); | |
90 void OnDelegateDestroyed(); | |
91 | |
92 private: | |
93 MediaSource GetMediaSourceFromListener( | |
94 content::PresentationScreenAvailabilityListener* listener); | |
95 | |
96 scoped_ptr<content::PresentationSessionInfo> default_presentation_info_; | |
97 base::ScopedPtrHashMap<MediaSourceId, scoped_ptr<MediaSinksObserver>> | |
98 sink_observers_; | |
99 | |
100 // Does not own these objects. | |
101 const content::WebContents* web_contents_; | |
102 MediaRouter* router_; | |
103 DelegateObserver* delegate_observer_; | |
104 }; | |
105 | |
106 PresentationFrame::PresentationFrame(content::WebContents* web_contents, | |
107 MediaRouter* router) | |
108 : web_contents_(web_contents), | |
109 router_(router), | |
110 delegate_observer_(nullptr) { | |
111 DCHECK(web_contents_); | |
112 DCHECK(router_); | |
113 } | |
114 | |
115 PresentationFrame::~PresentationFrame() { | |
116 DCHECK(sink_observers_.empty()); | |
117 } | |
118 | |
119 bool PresentationFrame::AddScreenAvailabilityListener( | |
120 content::PresentationScreenAvailabilityListener* listener) { | |
121 MediaSource source(GetMediaSourceFromListener(listener)); | |
122 if (sink_observers_.contains(source.id())) | |
123 return false; | |
124 | |
125 return sink_observers_.add(source.id(), | |
126 make_scoped_ptr(new PresentationMediaSinksObserver( | |
127 router_, listener, source))).second; | |
128 } | |
129 | |
130 bool PresentationFrame::RemoveScreenAvailabilityListener( | |
131 content::PresentationScreenAvailabilityListener* listener) { | |
132 MediaSource source(GetMediaSourceFromListener(listener)); | |
133 return sink_observers_.erase(source.id()) == 1; | |
134 } | |
135 | |
136 bool PresentationFrame::HasScreenAvailabilityListenerForTest( | |
137 const MediaSourceId& source_id) const { | |
138 return sink_observers_.contains(source_id); | |
139 } | |
140 | |
141 int PresentationFrame::NumScreenAvailabilityListeners() const { | |
142 return sink_observers_.size(); | |
143 } | |
144 | |
145 void PresentationFrame::Reset() { | |
146 sink_observers_.clear(); | |
147 default_presentation_info_.reset(); | |
148 } | |
149 | |
150 void PresentationFrame::OnDelegateDestroyed() { | |
151 if (delegate_observer_) { | |
152 delegate_observer_->OnDelegateDestroyed(); | |
153 } | |
154 } | |
155 | |
156 void PresentationFrame::SetDefaultPresentationInfo( | |
157 const std::string& default_presentation_url, | |
158 const std::string& default_presentation_id) { | |
159 if (default_presentation_url.empty() && default_presentation_id.empty()) { | |
160 default_presentation_info_.reset(); | |
161 } else { | |
162 default_presentation_info_.reset(new content::PresentationSessionInfo( | |
163 default_presentation_url, default_presentation_id)); | |
164 } | |
165 } | |
166 | |
167 std::string PresentationFrame::GetDefaultPresentationId() const { | |
168 return default_presentation_info_ | |
169 ? default_presentation_info_->presentation_id | |
170 : ""; | |
171 } | |
172 | |
173 MediaSource PresentationFrame::GetMediaSourceFromListener( | |
174 content::PresentationScreenAvailabilityListener* listener) { | |
175 // If the default presentation URL is empty then fall back to 1-UA mode, | |
176 // i.e. offscreeen tab rendering. | |
177 std::string presentation_url(listener->GetPresentationUrl()); | |
178 return presentation_url.empty() | |
179 ? ForTabMediaSource(SessionTabHelper::IdForTab(web_contents_)) | |
180 : ForPresentationUrl(presentation_url); | |
181 } | |
182 | |
183 // Helper class for PresentationServiceDelegateImpl to manage | |
184 // PresentationFrames. | |
185 class PresentationFrameMap final { | |
186 public: | |
187 using DelegateObserver = content::PresentationServiceDelegate::Observer; | |
188 | |
189 PresentationFrameMap(content::WebContents* web_contents, MediaRouter* router); | |
190 ~PresentationFrameMap(); | |
191 | |
192 // Returns true if listener was added. | |
193 bool AddScreenAvailabilityListener( | |
194 RenderFrameHostId rfh_id, | |
195 content::PresentationScreenAvailabilityListener* listener); | |
196 | |
197 // Returns true if listener was removed. | |
198 bool RemoveScreenAvailabilityListener( | |
199 RenderFrameHostId rfh_id, | |
200 content::PresentationScreenAvailabilityListener* listener); | |
201 | |
202 // Returns true if there is a listener for |source_id| in the frame. | |
203 bool HasScreenAvailabilityListenerForTest( | |
204 RenderFrameHostId rfh_id, | |
205 const MediaSourceId& source_id) const; | |
206 | |
207 // Returns the number of screen-availability listeners. | |
208 int NumScreenAvailabilityListeners() const; | |
209 | |
210 // Returns the default presentation URL and ID for the frame. | |
211 void SetDefaultPresentationInfo(RenderFrameHostId rfh_id, | |
212 const std::string& default_presentation_url, | |
213 const std::string& default_presentation_id); | |
214 | |
215 // Returns empty string if no default presentation ID is set in the frame. | |
216 std::string GetDefaultPresentationId(RenderFrameHostId rfh_id) const; | |
217 | |
218 void RegisterPresenationFrame(RenderFrameHostId rfh_id, | |
219 DelegateObserver* observer); | |
220 void UnregisterPresenationFrame(RenderFrameHostId rfh_id); | |
221 | |
222 DelegateObserver* GetDelegateObserver(RenderFrameHostId rfh_id) const; | |
223 | |
224 void Reset(RenderFrameHostId rfh_id); | |
225 void OnDelegateDestroyed(); | |
226 void SetMediaRouterForTest(MediaRouter* router); | |
227 | |
228 private: | |
229 PresentationFrame* GetOrAddFrame(RenderFrameHostId rfh_id); | |
230 | |
231 // Maps a frame identifier to a PresentationFrame object for frames | |
232 // that are using presentation API. | |
233 base::ScopedPtrHashMap<RenderFrameHostId, scoped_ptr<PresentationFrame>> | |
234 presentation_frames_; | |
235 | |
236 // Does not own these two objects. | |
237 MediaRouter* router_; | |
238 content::WebContents* web_contents_; | |
239 }; | |
240 | |
241 PresentationFrameMap::PresentationFrameMap(content::WebContents* web_contents, | |
242 MediaRouter* router) | |
243 : web_contents_(web_contents), router_(router) { | |
244 DCHECK(web_contents_); | |
245 } | |
246 | |
247 PresentationFrameMap::~PresentationFrameMap() { | |
248 } | |
249 | |
250 bool PresentationFrameMap::AddScreenAvailabilityListener( | |
251 RenderFrameHostId rfh_id, | |
252 content::PresentationScreenAvailabilityListener* listener) { | |
253 DCHECK(listener); | |
254 if (NumScreenAvailabilityListeners() >= | |
255 PresentationServiceDelegateImpl::kMaxNumSources) { | |
256 return false; | |
257 } | |
258 | |
259 auto presentation_frame = GetOrAddFrame(rfh_id); | |
260 return presentation_frame->AddScreenAvailabilityListener(listener); | |
261 } | |
262 | |
263 bool PresentationFrameMap::RemoveScreenAvailabilityListener( | |
264 RenderFrameHostId rfh_id, | |
265 content::PresentationScreenAvailabilityListener* listener) { | |
266 DCHECK(listener); | |
267 auto presentation_frame = presentation_frames_.get(rfh_id); | |
268 return presentation_frame && | |
269 presentation_frame->RemoveScreenAvailabilityListener(listener); | |
270 } | |
271 | |
272 bool PresentationFrameMap::HasScreenAvailabilityListenerForTest( | |
273 RenderFrameHostId rfh_id, | |
274 const MediaSourceId& source_id) const { | |
275 auto presentation_frame = presentation_frames_.get(rfh_id); | |
276 return presentation_frame && | |
277 presentation_frame->HasScreenAvailabilityListenerForTest(source_id); | |
278 } | |
279 | |
280 int PresentationFrameMap::NumScreenAvailabilityListeners() const { | |
281 int count = 0; | |
282 for (const auto& pf : presentation_frames_) { | |
283 count += pf.second->NumScreenAvailabilityListeners(); | |
284 } | |
285 return count; | |
286 } | |
287 | |
288 void PresentationFrameMap::SetDefaultPresentationInfo( | |
289 RenderFrameHostId rfh_id, | |
290 const std::string& default_presentation_url, | |
291 const std::string& default_presentation_id) { | |
292 auto presentation_frame = GetOrAddFrame(rfh_id); | |
293 presentation_frame->SetDefaultPresentationInfo(default_presentation_url, | |
294 default_presentation_id); | |
295 } | |
296 | |
297 std::string PresentationFrameMap::GetDefaultPresentationId( | |
298 RenderFrameHostId rfh_id) const { | |
299 auto presentation_frame = presentation_frames_.get(rfh_id); | |
300 return presentation_frame ? presentation_frame->GetDefaultPresentationId() | |
301 : ""; | |
302 } | |
303 | |
304 void PresentationFrameMap::RegisterPresenationFrame( | |
305 RenderFrameHostId rfh_id, | |
306 content::PresentationServiceDelegate::Observer* observer) { | |
307 auto presentation_frame = GetOrAddFrame(rfh_id); | |
308 presentation_frame->set_delegate_observer(observer); | |
309 } | |
310 | |
311 void PresentationFrameMap::UnregisterPresenationFrame( | |
312 RenderFrameHostId rfh_id) { | |
313 presentation_frames_.erase(rfh_id); | |
314 } | |
315 | |
316 PresentationFrameMap::DelegateObserver* | |
317 PresentationFrameMap::GetDelegateObserver(RenderFrameHostId rfh_id) const { | |
318 auto presentation_frame = presentation_frames_.get(rfh_id); | |
319 return presentation_frame ? presentation_frame->delegate_observer() : nullptr; | |
320 } | |
321 | |
322 void PresentationFrameMap::Reset(RenderFrameHostId rfh_id) { | |
323 auto presentation_frame = presentation_frames_.get(rfh_id); | |
324 if (presentation_frame) | |
325 presentation_frame->Reset(); | |
326 } | |
327 | |
328 void PresentationFrameMap::OnDelegateDestroyed() { | |
329 for (auto& kv : presentation_frames_) | |
330 kv.second->OnDelegateDestroyed(); | |
331 } | |
332 | |
333 PresentationFrame* PresentationFrameMap::GetOrAddFrame( | |
334 RenderFrameHostId rfh_id) { | |
335 if (!presentation_frames_.contains(rfh_id)) { | |
336 presentation_frames_.add( | |
337 rfh_id, scoped_ptr<PresentationFrame>( | |
338 new PresentationFrame(web_contents_, router_))); | |
339 } | |
340 return presentation_frames_.get(rfh_id); | |
341 } | |
342 | |
343 void PresentationFrameMap::SetMediaRouterForTest(MediaRouter* router) { | |
344 router_ = router; | |
345 } | |
346 | |
347 // TODO(haibinlu): Get router from MediaRouterMojoImplFactory once it lands. | |
348 PresentationServiceDelegateImpl::PresentationServiceDelegateImpl( | |
349 content::WebContents* web_contents) | |
350 : web_contents_(web_contents), | |
351 router_(NULL), | |
352 frame_map_(new PresentationFrameMap(web_contents, nullptr)), | |
353 weak_factory_(this) { | |
354 } | |
355 | |
356 PresentationServiceDelegateImpl::~PresentationServiceDelegateImpl() { | |
357 frame_map_->OnDelegateDestroyed(); | |
358 } | |
359 | |
360 void PresentationServiceDelegateImpl::AddObserver( | |
361 int render_process_id, | |
362 int render_frame_id, | |
363 content::PresentationServiceDelegate::Observer* observer) { | |
364 DCHECK(observer); | |
365 RenderFrameHostId rfh_id(render_process_id, render_frame_id); | |
366 frame_map_->RegisterPresenationFrame(rfh_id, observer); | |
imcheng (use chromium acct)
2015/05/19 22:00:46
nit: rfh_id can be inlined
haibinlu
2015/05/19 22:20:52
Done.
| |
367 } | |
368 | |
369 void PresentationServiceDelegateImpl::RemoveObserver(int render_process_id, | |
370 int render_frame_id) { | |
371 RenderFrameHostId rfh_id(render_process_id, render_frame_id); | |
372 frame_map_->UnregisterPresenationFrame(rfh_id); | |
imcheng (use chromium acct)
2015/05/19 22:00:46
ditto
haibinlu
2015/05/19 22:20:53
Done.
| |
373 } | |
374 | |
375 bool PresentationServiceDelegateImpl::AddScreenAvailabilityListener( | |
376 int render_process_id, | |
377 int render_frame_id, | |
378 content::PresentationScreenAvailabilityListener* listener) { | |
379 DCHECK(listener); | |
380 RenderFrameHostId rfh_id(render_process_id, render_frame_id); | |
381 return frame_map_->AddScreenAvailabilityListener(rfh_id, listener); | |
imcheng (use chromium acct)
2015/05/19 22:00:46
ditto
haibinlu
2015/05/19 22:20:53
Done.
| |
382 } | |
383 | |
384 void PresentationServiceDelegateImpl::RemoveScreenAvailabilityListener( | |
385 int render_process_id, | |
386 int render_frame_id, | |
387 content::PresentationScreenAvailabilityListener* listener) { | |
388 DCHECK(listener); | |
389 RenderFrameHostId rfh_id(render_process_id, render_frame_id); | |
390 frame_map_->RemoveScreenAvailabilityListener(rfh_id, listener); | |
imcheng (use chromium acct)
2015/05/19 22:00:46
ditto
haibinlu
2015/05/19 22:20:53
Done.
| |
391 } | |
392 | |
393 void PresentationServiceDelegateImpl::Reset(int render_process_id, | |
394 int render_frame_id) { | |
395 RenderFrameHostId rfh_id(render_process_id, render_frame_id); | |
396 frame_map_->Reset(rfh_id); | |
397 if (IsMainFrame(rfh_id)) | |
398 UpdateDefaultMediaSourceAndNotifyObservers(MediaSource(), std::string()); | |
399 } | |
400 | |
401 void PresentationServiceDelegateImpl::SetDefaultPresentationUrl( | |
402 int render_process_id, | |
403 int render_frame_id, | |
404 const std::string& default_presentation_url, | |
405 const std::string& default_presentation_id) { | |
406 RenderFrameHostId rfh_id(render_process_id, render_frame_id); | |
407 frame_map_->SetDefaultPresentationInfo(rfh_id, default_presentation_url, | |
408 default_presentation_id); | |
409 if (IsMainFrame(rfh_id)) { | |
410 // This is the main frame, that means tab-level default presentation | |
411 // might have been updated. | |
412 MediaSource new_default_source; | |
413 if (!default_presentation_url.empty()) | |
414 new_default_source = ForPresentationUrl(default_presentation_url); | |
415 std::string new_default_source_host(GetSourceHostForFrame(rfh_id)); | |
416 UpdateDefaultMediaSourceAndNotifyObservers(new_default_source, | |
417 new_default_source_host); | |
418 } | |
419 } | |
420 | |
421 bool PresentationServiceDelegateImpl::IsMainFrame( | |
422 RenderFrameHostId rfh_id) const { | |
423 RenderFrameHost* main_frame = web_contents_->GetMainFrame(); | |
424 return main_frame && GetRenderFrameHostId(main_frame) == rfh_id; | |
425 } | |
426 | |
427 void PresentationServiceDelegateImpl:: | |
428 UpdateDefaultMediaSourceAndNotifyObservers( | |
429 const MediaSource& new_default_source, | |
430 const std::string& new_default_source_host) { | |
431 if (!new_default_source.Equals(default_source_) || | |
432 new_default_source_host != default_source_host_) { | |
433 default_source_ = new_default_source; | |
434 default_source_host_ = new_default_source_host; | |
435 FOR_EACH_OBSERVER( | |
436 DefaultMediaSourceObserver, default_media_source_observers_, | |
437 OnDefaultMediaSourceChanged(default_source_, default_source_host_)); | |
438 } | |
439 } | |
440 | |
441 void PresentationServiceDelegateImpl::StartSession( | |
442 int render_process_id, | |
443 int render_frame_id, | |
444 const std::string& presentation_url, | |
445 const std::string& presentation_id, | |
446 const PresentationSessionSuccessCallback& success_cb, | |
447 const PresentationSessionErrorCallback& error_cb) { | |
448 NOTIMPLEMENTED(); | |
449 } | |
450 | |
451 void PresentationServiceDelegateImpl::JoinSession( | |
452 int render_process_id, | |
453 int render_frame_id, | |
454 const std::string& presentation_url, | |
455 const std::string& presentation_id, | |
456 const PresentationSessionSuccessCallback& success_cb, | |
457 const PresentationSessionErrorCallback& error_cb) { | |
458 NOTIMPLEMENTED(); | |
459 } | |
460 | |
461 void PresentationServiceDelegateImpl::ListenForSessionMessages( | |
462 int render_process_id, | |
463 int render_frame_id, | |
464 const PresentationSessionMessageCallback& message_cb) { | |
465 NOTIMPLEMENTED(); | |
466 } | |
467 | |
468 void PresentationServiceDelegateImpl::SendMessage( | |
469 int render_process_id, | |
470 int render_frame_id, | |
471 scoped_ptr<content::PresentationSessionMessage> message_request, | |
472 const SendMessageCallback& send_message_cb) { | |
473 NOTIMPLEMENTED(); | |
474 } | |
475 | |
476 void PresentationServiceDelegateImpl::OnRouteCreated(const MediaRoute& route) { | |
477 const MediaSource& source = route.media_source(); | |
478 DCHECK(!source.Empty()); | |
479 if (default_source_.Equals(source)) { | |
480 RenderFrameHost* main_frame = web_contents_->GetMainFrame(); | |
481 if (main_frame) { | |
482 RenderFrameHostId rfh_id(GetRenderFrameHostId(main_frame)); | |
483 auto observer = frame_map_->GetDelegateObserver(rfh_id); | |
484 if (observer) { | |
485 // TODO(imcheng): Pass in valid default presentation ID once it is | |
486 // available from MediaRoute URN. | |
487 observer->OnDefaultPresentationStarted(content::PresentationSessionInfo( | |
488 GetPresentationUrl(source), std::string())); | |
489 } | |
490 } | |
491 } | |
492 } | |
493 | |
494 void PresentationServiceDelegateImpl::AddDefaultMediaSourceObserver( | |
495 DefaultMediaSourceObserver* observer) { | |
496 default_media_source_observers_.AddObserver(observer); | |
497 } | |
498 | |
499 void PresentationServiceDelegateImpl::RemoveDefaultMediaSourceObserver( | |
500 DefaultMediaSourceObserver* observer) { | |
501 default_media_source_observers_.RemoveObserver(observer); | |
502 } | |
503 | |
504 void PresentationServiceDelegateImpl::SetMediaRouterForTest( | |
505 MediaRouter* router) { | |
506 router_ = router; | |
507 frame_map_->SetMediaRouterForTest(router); | |
508 } | |
509 | |
510 base::WeakPtr<PresentationServiceDelegateImpl> | |
511 PresentationServiceDelegateImpl::GetWeakPtr() { | |
512 return weak_factory_.GetWeakPtr(); | |
513 } | |
514 | |
515 bool PresentationServiceDelegateImpl::HasScreenAvailabilityListenerForTest( | |
516 RenderFrameHostId rfh_id, | |
517 const MediaSourceId& source_id) const { | |
518 return frame_map_->HasScreenAvailabilityListenerForTest(rfh_id, source_id); | |
519 } | |
520 | |
521 } // namespace media_router | |
OLD | NEW |