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

Side by Side Diff: chrome/browser/media/router/presentation_service_delegate_impl.cc

Issue 1132903002: [MediaRouter] Add implementation of PresentationServiceDelegate (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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 "chrome/browser/ui/webui/media_router/media_router_dialog_controller.h"
imcheng (use chromium acct) 2015/05/18 20:54:07 This isn't used yet. Please remove it and other un
haibinlu 2015/05/18 23:40:47 Done.
22 #include "content/public/browser/presentation_screen_availability_listener.h"
23 #include "content/public/browser/presentation_session.h"
24 #include "content/public/browser/render_frame_host.h"
25 #include "content/public/browser/render_process_host.h"
26
27 DEFINE_WEB_CONTENTS_USER_DATA_KEY(
28 media_router::PresentationServiceDelegateImpl);
29
30 using content::RenderFrameHost;
31
32 namespace {
imcheng (use chromium acct) 2015/05/18 20:54:07 You should be able to nest this anonymous namespac
haibinlu 2015/05/18 23:40:46 Done.
33
34 using RenderFrameHostId =
imcheng (use chromium acct) 2015/05/18 20:54:06 typedef not needed if moved into media_router name
haibinlu 2015/05/18 23:40:46 Done.
35 content::PresentationServiceDelegate::RenderFrameHostId;
36
37 // Helper function to extract ID for a RFH.
38 RenderFrameHostId GetRenderFrameHostId(RenderFrameHost* rfh) {
39 int render_process_id = rfh->GetProcess()->GetID();
40 int render_frame_id = rfh->GetRoutingID();
41 return RenderFrameHostId(render_process_id, render_frame_id);
42 }
43
44 // Gets the host name associated with the frame given by |rfh_id|.
45 std::string GetSourceHostForFrame(RenderFrameHostId rfh_id) {
46 RenderFrameHost* rfh = RenderFrameHost::FromID(rfh_id.first, rfh_id.second);
47 DCHECK(rfh);
48 std::string host = rfh->GetLastCommittedURL().host();
49 if (StartsWithASCII(host, "www.", false))
50 host = host.substr(4);
51 return host;
52 }
53
54 } // namespace
55
56 namespace media_router {
57
58 // Helper class for PresentationServiceDelegateImpl to manage
59 // listeners and default presentation info in a render frame.
60 class PresentationFrame {
61 public:
62 using DelegateObserver = content::PresentationServiceDelegate::Observer;
63
64 explicit PresentationFrame(content::WebContents* web_contents,
65 MediaRouter* router);
66 virtual ~PresentationFrame();
imcheng (use chromium acct) 2015/05/18 20:54:07 Doesn't need to be virtual.
haibinlu 2015/05/18 23:40:47 Done.
67
68 // Returns true if listener was added.
69 bool AddScreenAvailabilityListener(
70 content::PresentationScreenAvailabilityListener* listener);
71 // Returns true if listener was deleted.
72 bool RemoveScreenAvailabilityListener(
73 content::PresentationScreenAvailabilityListener* listener);
74 // Returns true if there is a listener for |source_id|.
75 bool HasScreenAvailabilityListenerFor(const MediaSourceId& source_id) const;
76 // Returns the number of screen-availability listeners.
77 int NumScreenAvailabilityListeners() const;
78
79 // Sets the default presentation URL and ID.
80 void SetDefaultPresentationInfo(const std::string& default_presentation_url,
81 const std::string& default_presentation_id);
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;
imcheng (use chromium acct) 2015/05/18 20:54:07 How about DCHECK(!delegate_observer_) before setti
haibinlu 2015/05/18 23:40:47 Done.
86 }
87 DelegateObserver* delegate_observer() const { return delegate_observer_; }
88
89 void Reset();
90
91 private:
92 MediaSource GetMediaSourceFromListener(
93 content::PresentationScreenAvailabilityListener* listener);
94
95 // Not owned by this class.
96 DelegateObserver* delegate_observer_;
imcheng (use chromium acct) 2015/05/18 20:54:07 Move this to after web_contents_
haibinlu 2015/05/18 23:40:47 Done.
97
98 scoped_ptr<content::PresentationSessionInfo> default_presentation_info_;
99 base::ScopedPtrHashMap<MediaSourceId, scoped_ptr<MediaSinksObserver>>
100 sink_observers_;
101
102 // Does not own these two objects.
103 MediaRouter* router_;
imcheng (use chromium acct) 2015/05/18 20:54:07 1. Can these be declared in the same order as ctor
haibinlu 2015/05/18 23:40:47 Done.
104 content::WebContents* web_contents_;
105 };
106
107 PresentationFrame::PresentationFrame(content::WebContents* web_contents,
108 MediaRouter* router)
109 : web_contents_(web_contents), router_(router), delegate_observer_(NULL) {
imcheng (use chromium acct) 2015/05/18 20:54:07 s/NULL/nullptr
haibinlu 2015/05/18 23:40:46 Done.
110 DCHECK(router_);
imcheng (use chromium acct) 2015/05/18 20:54:07 DCHECK(web_contents_) ?
haibinlu 2015/05/18 23:40:47 Done.
111 }
112
113 PresentationFrame::~PresentationFrame() {
114 DCHECK(sink_observers_.empty());
115 if (delegate_observer_) {
116 delegate_observer_->OnDelegateDestroyed();
117 }
118 }
119
120 bool PresentationFrame::AddScreenAvailabilityListener(
121 content::PresentationScreenAvailabilityListener* listener) {
122 MediaSource source(GetMediaSourceFromListener(listener));
123 if (sink_observers_.contains(source.id()))
imcheng (use chromium acct) 2015/05/18 20:54:06 A single add() will work: https://code.google.com/
haibinlu 2015/05/18 23:40:47 can not remove it. because "new PresentationMediaS
imcheng (use chromium acct) 2015/05/19 20:03:28 How about: add an empty scoped_ptr to the map, and
124 return false;
125
126 sink_observers_.add(source.id(),
127 make_scoped_ptr(new PresentationMediaSinksObserver(
128 router_, listener, source)));
129 return true;
130 }
131
132 bool PresentationFrame::RemoveScreenAvailabilityListener(
133 content::PresentationScreenAvailabilityListener* listener) {
134 MediaSource source(GetMediaSourceFromListener(listener));
135 return sink_observers_.erase(source.id()) == 1;
136 }
137
138 bool PresentationFrame::HasScreenAvailabilityListenerFor(
139 const MediaSourceId& source_id) const {
140 return sink_observers_.contains(source_id);
141 }
142
143 int PresentationFrame::NumScreenAvailabilityListeners() const {
144 return sink_observers_.size();
145 }
146
147 void PresentationFrame::Reset() {
148 sink_observers_.clear();
149 default_presentation_info_.reset();
150 }
151
152 void PresentationFrame::SetDefaultPresentationInfo(
153 const std::string& default_presentation_url,
154 const std::string& default_presentation_id) {
155 if (default_presentation_url.empty() && default_presentation_id.empty()) {
156 default_presentation_info_.reset();
157 } else {
158 default_presentation_info_.reset(new content::PresentationSessionInfo(
159 default_presentation_url, default_presentation_id));
160 }
161 }
162
163 std::string PresentationFrame::GetDefaultPresentationId() const {
164 return default_presentation_info_
165 ? default_presentation_info_->presentation_id
166 : "";
167 }
168
169 MediaSource PresentationFrame::GetMediaSourceFromListener(
170 content::PresentationScreenAvailabilityListener* listener) {
171 // If the default presentation URL is empty then fall back to 1-UA mode,
172 // i.e. offscreeen tab rendering.
173 std::string presentation_url(listener->GetPresentationUrl());
174 return presentation_url.empty()
175 ? ForTabMediaSource(SessionTabHelper::IdForTab(web_contents_))
176 : ForPresentationUrl(presentation_url);
177 }
178
179 // Helper class for PresentationServiceDelegateImpl to manage
180 // PresentationFrames.
181 class PresentationFrameMap {
182 public:
183 using RenderFrameHostId =
184 content::PresentationServiceDelegate::RenderFrameHostId;
185 using DelegateObserver = content::PresentationServiceDelegate::Observer;
186
187 explicit PresentationFrameMap(content::WebContents* web_contents,
188 MediaRouter* router);
189 virtual ~PresentationFrameMap();
imcheng (use chromium acct) 2015/05/18 20:54:07 Does not need to be virtual.
haibinlu 2015/05/18 23:40:47 Done.
190
191 // Returns true if listener was added.
192 bool AddScreenAvailabilityListener(
193 int render_process_id,
194 int render_frame_id,
195 content::PresentationScreenAvailabilityListener* listener);
196 // Returns true if listener was deleted.
imcheng (use chromium acct) 2015/05/18 20:54:07 Newline before comments, also s/deleted/removed
haibinlu 2015/05/18 23:40:47 Done.
197 bool RemoveScreenAvailabilityListener(
198 int render_process_id,
199 int render_frame_id,
200 content::PresentationScreenAvailabilityListener* listener);
201 // Returns true if there is a listener for |source_id| in the frame.
imcheng (use chromium acct) 2015/05/18 20:54:07 Newline before comments, same for below
haibinlu 2015/05/18 23:40:46 Done.
202 bool HasScreenAvailabilityListenerFor(RenderFrameHostId rfh_id,
203 const MediaSourceId& source_id) const;
204 // Returns the number of screen-availability listeners.
205 int NumScreenAvailabilityListeners() const;
206 // Returns the default presentation URL and ID for the frame.
207 void SetDefaultPresentationInfo(int render_process_id,
208 int render_frame_id,
209 const std::string& default_presentation_url,
210 const std::string& default_presentation_id);
211 // Returns empty string if no default presentation ID is set in the frame.
212 std::string GetDefaultPresentationId(RenderFrameHostId rfh_id) const;
213
214 void SetDelegateObserver(int render_process_id,
215 int render_frame_id,
216 DelegateObserver* observer);
217 DelegateObserver* GetDelegateObserver(RenderFrameHostId rfh_id) const;
218
219 void Reset(int render_process_id, int render_frame_id);
imcheng (use chromium acct) 2015/05/18 20:54:08 RenderFrameHostId rfh_id
haibinlu 2015/05/18 23:40:46 Done.
220
221 void SetMediaRouterForTest(MediaRouter* router);
222
223 private:
224 PresentationFrame* GetOrAddFrame(RenderFrameHostId rfh_id);
225
226 // Maps a frame identifier to a PresentationFrame object for frames
227 // that are using presentation API.
228 base::ScopedPtrHashMap<RenderFrameHostId, scoped_ptr<PresentationFrame>>
229 presentation_frames_;
imcheng (use chromium acct) 2015/05/18 20:54:07 It looks like we may have a potential memory leak
haibinlu 2015/05/18 23:40:46 As discussed, use removeObserver to remove the ent
230
231 // Does not own these two objects.
232 MediaRouter* router_;
233 content::WebContents* web_contents_;
234 };
235
236 PresentationFrameMap::PresentationFrameMap(content::WebContents* web_contents,
237 MediaRouter* router)
238 : web_contents_(web_contents), router_(router) {
imcheng (use chromium acct) 2015/05/18 20:54:07 DCHECKs?
haibinlu 2015/05/18 23:40:46 Done.
239 }
240
241 PresentationFrameMap::~PresentationFrameMap() {
242 }
243
244 bool PresentationFrameMap::AddScreenAvailabilityListener(
245 int render_process_id,
246 int render_frame_id,
247 content::PresentationScreenAvailabilityListener* listener) {
248 if (NumScreenAvailabilityListeners() >=
249 PresentationServiceDelegateImpl::kMaxNumSources) {
250 return false;
251 }
252
253 RenderFrameHostId rfh_id(render_process_id, render_frame_id);
254 auto presentation_frame = GetOrAddFrame(rfh_id);
255 return presentation_frame->AddScreenAvailabilityListener(listener);
256 }
257
258 bool PresentationFrameMap::RemoveScreenAvailabilityListener(
259 int render_process_id,
260 int render_frame_id,
261 content::PresentationScreenAvailabilityListener* listener) {
262 DCHECK(listener);
263
264 RenderFrameHostId rfh_id(render_process_id, render_frame_id);
265 auto presentation_frame = presentation_frames_.get(rfh_id);
266 return presentation_frame &&
267 presentation_frame->RemoveScreenAvailabilityListener(listener);
268 }
269
270 bool PresentationFrameMap::HasScreenAvailabilityListenerFor(
271 RenderFrameHostId rfh_id,
272 const MediaSourceId& source_id) const {
273 auto presentation_frame = presentation_frames_.get(rfh_id);
274 return presentation_frame &&
275 presentation_frame->HasScreenAvailabilityListenerFor(source_id);
276 }
277
278 int PresentationFrameMap::NumScreenAvailabilityListeners() const {
279 int count = 0;
280 for (const auto& pf : presentation_frames_) {
281 count += pf.second->NumScreenAvailabilityListeners();
282 }
283 return count;
284 }
285
286 void PresentationFrameMap::SetDefaultPresentationInfo(
287 int render_process_id,
288 int render_frame_id,
289 const std::string& default_presentation_url,
290 const std::string& default_presentation_id) {
291 RenderFrameHostId rfh_id(render_process_id, render_frame_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::SetDelegateObserver(
305 int render_process_id,
306 int render_frame_id,
307 content::PresentationServiceDelegate::Observer* observer) {
308 RenderFrameHostId rfh_id(render_process_id, render_frame_id);
309 auto presentation_frame = GetOrAddFrame(rfh_id);
310 presentation_frame->set_delegate_observer(observer);
311 }
312
313 PresentationFrameMap::DelegateObserver*
314 PresentationFrameMap::GetDelegateObserver(RenderFrameHostId rfh_id) const {
315 auto presentation_frame = presentation_frames_.get(rfh_id);
316 return presentation_frame ? presentation_frame->delegate_observer() : NULL;
317 }
318
319 void PresentationFrameMap::Reset(int render_process_id, int render_frame_id) {
320 RenderFrameHostId rfh_id(render_process_id, render_frame_id);
321 auto presentation_frame = presentation_frames_.get(rfh_id);
322 if (presentation_frame) {
imcheng (use chromium acct) 2015/05/18 20:54:06 braces not needed for a single line.
haibinlu 2015/05/18 23:40:47 Done.
323 presentation_frame->Reset();
324 }
325 }
326
327 PresentationFrame* PresentationFrameMap::GetOrAddFrame(
328 RenderFrameHostId rfh_id) {
329 auto presentation_frame = presentation_frames_.get(rfh_id);
imcheng (use chromium acct) 2015/05/18 20:54:06 redundant get.
haibinlu 2015/05/18 23:40:47 Done.
330 if (!presentation_frames_.contains(rfh_id)) {
imcheng (use chromium acct) 2015/05/18 20:54:07 For this use case it looks like a single add() is
haibinlu 2015/05/18 23:40:47 But it'd create a new PresentationFrameObject and
imcheng (use chromium acct) 2015/05/19 20:03:29 same comment as above.
331 presentation_frames_.add(
332 rfh_id, scoped_ptr<PresentationFrame>(
333 new PresentationFrame(web_contents_, router_)));
334 }
335 return presentation_frames_.get(rfh_id);
336 }
337
338 void PresentationFrameMap::SetMediaRouterForTest(MediaRouter* router) {
339 router_ = router;
340 }
341
342 // TODO(haibinlu): Get router from MediaRouterMojoImplFactory once it lands.
343 PresentationServiceDelegateImpl::PresentationServiceDelegateImpl(
344 content::WebContents* web_contents)
345 : web_contents_(web_contents),
346 router_(NULL),
imcheng (use chromium acct) 2015/05/18 20:54:07 s/NULL/nullptr, same for below
haibinlu 2015/05/18 23:40:47 Done.
347 frame_map_(new PresentationFrameMap(web_contents, NULL)),
348 weak_factory_(this) {
349 // DCHECK(router_);
350 }
351
352 PresentationServiceDelegateImpl::~PresentationServiceDelegateImpl() {
353 }
354
355 void PresentationServiceDelegateImpl::AddObserver(
356 int render_process_id,
357 int render_frame_id,
358 content::PresentationServiceDelegate::Observer* observer) {
359 DCHECK(observer);
360 frame_map_->SetDelegateObserver(render_process_id, render_frame_id, observer);
361 }
362
363 void PresentationServiceDelegateImpl::RemoveObserver(int render_process_id,
364 int render_frame_id) {
365 frame_map_->SetDelegateObserver(render_process_id, render_frame_id, NULL);
imcheng (use chromium acct) 2015/05/18 20:54:06 nullptr
haibinlu 2015/05/18 23:40:47 Done.
366 }
367
368 bool PresentationServiceDelegateImpl::AddScreenAvailabilityListener(
369 int render_process_id,
370 int render_frame_id,
371 content::PresentationScreenAvailabilityListener* listener) {
372 DCHECK(listener);
373 return frame_map_->AddScreenAvailabilityListener(render_process_id,
374 render_frame_id, listener);
375 }
376
377 void PresentationServiceDelegateImpl::RemoveScreenAvailabilityListener(
378 int render_process_id,
379 int render_frame_id,
380 content::PresentationScreenAvailabilityListener* listener) {
381 DCHECK(listener);
382 frame_map_->RemoveScreenAvailabilityListener(render_process_id,
383 render_frame_id, listener);
384 }
385
386 void PresentationServiceDelegateImpl::Reset(int render_process_id,
387 int render_frame_id) {
388 frame_map_->Reset(render_process_id, render_frame_id);
389 RenderFrameHostId rfh_id(render_process_id, render_frame_id);
390 if (IsMainFrame(rfh_id))
391 UpdateDefaultMediaSourceAndNotifyObservers(MediaSource(), std::string());
392 }
393
394 void PresentationServiceDelegateImpl::SetDefaultPresentationUrl(
395 int render_process_id,
396 int render_frame_id,
397 const std::string& default_presentation_url,
398 const std::string& default_presentation_id) {
399 frame_map_->SetDefaultPresentationInfo(render_process_id, render_frame_id,
400 default_presentation_url,
401 default_presentation_id);
402
403 RenderFrameHostId rfh_id(render_process_id, render_frame_id);
404 if (IsMainFrame(rfh_id)) {
405 // This is the main frame, that means tab-level default presentation
406 // might have been updated.
407 MediaSource new_default_source;
408 if (!default_presentation_url.empty())
409 new_default_source = ForPresentationUrl(default_presentation_url);
410 std::string new_default_source_host(GetSourceHostForFrame(rfh_id));
411 UpdateDefaultMediaSourceAndNotifyObservers(new_default_source,
412 new_default_source_host);
413 }
414 }
415
416 bool PresentationServiceDelegateImpl::IsMainFrame(
417 RenderFrameHostId rfh_id) const {
418 RenderFrameHost* main_frame = web_contents_->GetMainFrame();
419 return main_frame && GetRenderFrameHostId(main_frame) == rfh_id;
420 }
421
422 void PresentationServiceDelegateImpl::
423 UpdateDefaultMediaSourceAndNotifyObservers(
424 const MediaSource& new_default_source,
425 const std::string& new_default_source_host) {
426 if (!new_default_source.Equals(default_source_) ||
427 new_default_source_host != default_source_host_) {
428 default_source_ = new_default_source;
429 default_source_host_ = new_default_source_host;
430 FOR_EACH_OBSERVER(
431 DefaultMediaSourceObserver, default_media_source_observers_,
432 OnDefaultMediaSourceChanged(default_source_, default_source_host_));
433 }
434 }
435
436 void PresentationServiceDelegateImpl::StartSession(
437 int render_process_id,
438 int render_frame_id,
439 const std::string& presentation_url,
440 const std::string& presentation_id,
441 const PresentationSessionSuccessCallback& success_cb,
442 const PresentationSessionErrorCallback& error_cb) {
443 NOTIMPLEMENTED();
444 }
445
446 void PresentationServiceDelegateImpl::JoinSession(
447 int render_process_id,
448 int render_frame_id,
449 const std::string& presentation_url,
450 const std::string& presentation_id,
451 const PresentationSessionSuccessCallback& success_cb,
452 const PresentationSessionErrorCallback& error_cb) {
453 NOTIMPLEMENTED();
454 }
455
456 void PresentationServiceDelegateImpl::ListenForSessionMessages(
457 int render_process_id,
458 int render_frame_id,
459 const PresentationSessionMessageCallback& message_cb) {
460 NOTIMPLEMENTED();
461 }
462
463 void PresentationServiceDelegateImpl::SendMessage(
464 int render_process_id,
465 int render_frame_id,
466 scoped_ptr<content::PresentationSessionMessage> message_request,
467 const SendMessageCallback& send_message_cb) {
468 NOTIMPLEMENTED();
469 }
470
471 void PresentationServiceDelegateImpl::OnRouteCreated(const MediaRoute& route) {
472 const MediaSource& source = route.media_source();
473 DCHECK(!source.Empty());
474 if (default_source_.Equals(source)) {
475 RenderFrameHost* main_frame = web_contents_->GetMainFrame();
imcheng (use chromium acct) 2015/05/18 20:54:07 Thinking about this some more, I think this is not
haibinlu 2015/05/18 23:40:46 I am not sure this is the right behavior either. A
imcheng (use chromium acct) 2015/05/19 20:03:29 Per offline chat. This is correct behavior (at lea
476 if (main_frame) {
477 RenderFrameHostId rfh_id(GetRenderFrameHostId(main_frame));
478 auto observer = frame_map_->GetDelegateObserver(rfh_id);
479 if (observer) {
480 // TODO(imcheng): Pass in valid default presentation ID once it is
481 // available from MediaRoute URN.
482 observer->OnDefaultPresentationStarted(content::PresentationSessionInfo(
483 GetPresentationUrl(source), std::string()));
484 }
485 }
486 }
487 }
488
489 MediaSource PresentationServiceDelegateImpl::GetDefaultMediaSource() const {
490 return default_source_;
491 }
492
493 void PresentationServiceDelegateImpl::AddDefaultMediaSourceObserver(
494 DefaultMediaSourceObserver* observer) {
495 default_media_source_observers_.AddObserver(observer);
496 }
497
498 void PresentationServiceDelegateImpl::RemoveDefaultMediaSourceObserver(
499 DefaultMediaSourceObserver* observer) {
500 default_media_source_observers_.RemoveObserver(observer);
501 }
502
503 void PresentationServiceDelegateImpl::SetMediaRouterForTest(
504 MediaRouter* router) {
505 router_ = router;
506 frame_map_->SetMediaRouterForTest(router);
507 }
508
509 base::WeakPtr<PresentationServiceDelegateImpl>
510 PresentationServiceDelegateImpl::GetWeakPtr() {
511 return weak_factory_.GetWeakPtr();
512 }
513
514 bool PresentationServiceDelegateImpl::HasScreenAvailabilityListenerFor(
imcheng (use chromium acct) 2015/05/18 20:54:06 is this used?
haibinlu 2015/05/18 23:40:47 Used in test, which was accessing private member d
imcheng (use chromium acct) 2015/05/19 20:03:29 Can we use friend class and FRIEND_TEST_ALL_PREFIX
515 RenderFrameHostId rfh_id,
516 const MediaSourceId& source_id) const {
517 return frame_map_->HasScreenAvailabilityListenerFor(rfh_id, source_id);
518 }
519
520 } // namespace media_router
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698