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 using RenderFrameHostId = std::pair<int, int>; | |
34 | |
35 namespace { | |
36 | |
37 // Returns the unique identifier for the supplied RenderViewHost. | |
38 RenderFrameHostId GetRenderFrameHostId(RenderFrameHost* render_view_host) { | |
39 int render_process_id = render_view_host->GetProcess()->GetID(); | |
40 int render_frame_id = render_view_host->GetRoutingID(); | |
41 return RenderFrameHostId(render_process_id, render_frame_id); | |
42 } | |
43 | |
44 std::string GetDisplayNameForFrame(RenderFrameHostId render_frame_host_id) { | |
45 RenderFrameHost* render_view_host = RenderFrameHost::FromID( | |
46 render_frame_host_id.first, render_frame_host_id.second); | |
47 std::string host = render_view_host->GetLastCommittedURL().host(); | |
48 if (StartsWithASCII(host, "www.", false)) | |
49 host = host.substr(4); | |
50 return host; | |
51 } | |
52 | |
53 } // namespace | |
54 | |
55 // Used by PresentationServiceDelegateImpl to manage | |
56 // listeners and default presentation info in a render frame. | |
57 // Its lifetime: | |
58 // * PresentationFrameManager AddDelegateObserver | |
59 // * Reset 0+ times. | |
60 // * PresentationFrameManager.RemoveDelegateObserver. | |
61 class PresentationFrame { | |
62 public: | |
63 using DelegateObserver = content::PresentationServiceDelegate::Observer; | |
64 | |
65 PresentationFrame(content::WebContents* web_contents, MediaRouter* router); | |
66 ~PresentationFrame(); | |
67 | |
68 // Mirror corresponding APIs in PresentationServiceDelegateImpl. | |
mark a. foltz
2015/06/01 19:18:12
Why doesn't this implement content::PresentationSe
haibinlu
2015/06/01 21:44:58
PresentationFrame/Manager do not implement StartSe
mark a. foltz
2015/06/02 00:18:39
Acknowledged.
| |
69 bool SetScreenAvailabilityListener( | |
70 content::PresentationScreenAvailabilityListener* listener); | |
71 bool RemoveScreenAvailabilityListener( | |
72 content::PresentationScreenAvailabilityListener* listener); | |
73 bool HasScreenAvailabilityListenerForTest( | |
74 const MediaSourceId& source_id) const; | |
75 void SetDefaultPresentationInfo(const std::string& default_presentation_url, | |
76 const std::string& default_presentation_id); | |
77 std::string GetDefaultPresentationId() const; | |
78 void Reset(); | |
79 | |
80 void OnDefaultPresentationStarted( | |
81 const content::PresentationSessionInfo& session) const; | |
82 void OnPresentationServiceDelegateDestroyed() const; | |
83 | |
84 void set_delegate_observer(DelegateObserver* observer) { | |
85 delegate_observer_ = observer; | |
86 } | |
87 | |
88 private: | |
89 MediaSource GetMediaSourceFromListener( | |
90 content::PresentationScreenAvailabilityListener* listener) const; | |
91 | |
92 scoped_ptr<content::PresentationSessionInfo> default_presentation_info_; | |
93 scoped_ptr<PresentationMediaSinksObserver> sink_observer_; | |
mark a. foltz
2015/06/01 19:18:12
nit: sinks_observer_
haibinlu
2015/06/01 21:44:58
Done.
| |
94 | |
95 // References to the owning WebContents, and the corresponding MediaRouter. | |
96 const content::WebContents* web_contents_; | |
97 MediaRouter* router_; | |
98 | |
99 DelegateObserver* delegate_observer_; | |
100 }; | |
101 | |
102 PresentationFrame::PresentationFrame(content::WebContents* web_contents, | |
103 MediaRouter* router) | |
104 : web_contents_(web_contents), | |
105 router_(router), | |
106 delegate_observer_(nullptr) { | |
107 DCHECK(web_contents_); | |
108 DCHECK(router_); | |
109 } | |
110 | |
111 PresentationFrame::~PresentationFrame() { | |
112 } | |
113 | |
114 void PresentationFrame::OnPresentationServiceDelegateDestroyed() const { | |
115 if (delegate_observer_) | |
116 delegate_observer_->OnDelegateDestroyed(); | |
117 } | |
118 | |
119 void PresentationFrame::OnDefaultPresentationStarted( | |
120 const content::PresentationSessionInfo& session) const { | |
121 if (delegate_observer_) | |
122 delegate_observer_->OnDefaultPresentationStarted(session); | |
123 } | |
124 | |
125 bool PresentationFrame::SetScreenAvailabilityListener( | |
126 content::PresentationScreenAvailabilityListener* listener) { | |
127 if (sink_observer_ && sink_observer_->listener() == listener) { | |
128 return false; | |
129 } | |
130 MediaSource source(GetMediaSourceFromListener(listener)); | |
131 sink_observer_.reset( | |
132 new PresentationMediaSinksObserver(router_, listener, source)); | |
133 return true; | |
134 } | |
135 | |
136 bool PresentationFrame::RemoveScreenAvailabilityListener( | |
137 content::PresentationScreenAvailabilityListener* listener) { | |
138 if (sink_observer_ && sink_observer_->listener() == listener) { | |
139 sink_observer_.reset(); | |
140 return true; | |
141 } | |
142 return false; | |
143 } | |
144 | |
145 bool PresentationFrame::HasScreenAvailabilityListenerForTest( | |
146 const MediaSourceId& source_id) const { | |
147 return sink_observer_ && sink_observer_->source().id() == source_id; | |
148 } | |
149 | |
150 void PresentationFrame::Reset() { | |
151 sink_observer_.reset(); | |
152 default_presentation_info_.reset(); | |
153 } | |
154 | |
155 void PresentationFrame::SetDefaultPresentationInfo( | |
156 const std::string& default_presentation_url, | |
157 const std::string& default_presentation_id) { | |
158 if (default_presentation_url.empty() && default_presentation_id.empty()) { | |
159 default_presentation_info_.reset(); | |
160 } else { | |
161 default_presentation_info_.reset(new content::PresentationSessionInfo( | |
162 default_presentation_url, default_presentation_id)); | |
163 } | |
164 } | |
165 | |
166 std::string PresentationFrame::GetDefaultPresentationId() const { | |
167 if (default_presentation_info_) | |
168 return default_presentation_info_->presentation_id; | |
mark a. foltz
2015/06/01 19:18:12
return default_presentation_info_ ? default_presen
haibinlu
2015/06/01 21:44:58
wez@ prefers "if() return a; return b;" style. I a
mark a. foltz
2015/06/02 00:18:39
Ok, we have different preferences on that front.
| |
169 return ""; | |
170 } | |
171 | |
172 MediaSource PresentationFrame::GetMediaSourceFromListener( | |
173 content::PresentationScreenAvailabilityListener* listener) const { | |
174 // If the default presentation URL is empty then fall back to tab mirroring. | |
175 std::string presentation_url(listener->GetPresentationUrl()); | |
176 if (presentation_url.empty()) | |
mark a. foltz
2015/06/01 19:18:12
Ditto
haibinlu
2015/06/01 21:44:58
wez@ prefers "if() return a; return b;" style. I a
| |
177 return MediaSourceForTab(SessionTabHelper::IdForTab(web_contents_)); | |
178 return MediaSourceForPresentationUrl(presentation_url); | |
179 } | |
180 | |
181 // Used by PresentationServiceDelegateImpl to manage PresentationFrames. | |
182 class PresentationFrameManager { | |
183 public: | |
184 using DelegateObserver = content::PresentationServiceDelegate::Observer; | |
mark a. foltz
2015/06/01 19:18:13
Repeated definition. Move to file level?
haibinlu
2015/06/01 21:44:58
Done.
| |
185 | |
186 PresentationFrameManager(content::WebContents* web_contents, | |
187 MediaRouter* router); | |
188 ~PresentationFrameManager(); | |
189 | |
190 // Mirror corresponding APIs in PresentationServiceDelegateImpl. | |
191 bool SetScreenAvailabilityListener( | |
192 const RenderFrameHostId& render_frame_host_id, | |
193 content::PresentationScreenAvailabilityListener* listener); | |
194 bool RemoveScreenAvailabilityListener( | |
195 const RenderFrameHostId& render_frame_host_id, | |
196 content::PresentationScreenAvailabilityListener* listener); | |
197 void SetDefaultPresentationInfo(const RenderFrameHostId& render_frame_host_id, | |
198 const std::string& default_presentation_url, | |
199 const std::string& default_presentation_id); | |
200 void AddDelegateObserver(const RenderFrameHostId& render_frame_host_id, | |
201 DelegateObserver* observer); | |
202 void RemoveDelegateObserver(const RenderFrameHostId& render_frame_host_id); | |
203 void Reset(const RenderFrameHostId& render_frame_host_id); | |
204 bool HasScreenAvailabilityListenerForTest( | |
205 const RenderFrameHostId& render_frame_host_id, | |
206 const MediaSourceId& source_id) const; | |
207 void SetMediaRouterForTest(MediaRouter* router); | |
208 | |
209 // Returns default presentation ID, or empty string if no default | |
210 // presentation ID is set in the frame. | |
211 std::string GetDefaultPresentationId( | |
212 const RenderFrameHostId& render_frame_host_id) const; | |
213 | |
214 void OnDefaultPresentationStarted( | |
215 const RenderFrameHostId& render_frame_host_id, | |
216 const content::PresentationSessionInfo& session) const; | |
217 | |
218 private: | |
219 PresentationFrame* GetOrAddFrame( | |
220 const RenderFrameHostId& render_frame_host_id); | |
221 | |
222 // Maps a frame identifier to a PresentationFrame object for frames | |
223 // that are using presentation API. | |
224 base::ScopedPtrHashMap<RenderFrameHostId, scoped_ptr<PresentationFrame>> | |
225 presentation_frames_; | |
226 | |
227 // References to the owning WebContents, and the corresponding MediaRouter. | |
228 MediaRouter* router_; | |
229 content::WebContents* web_contents_; | |
230 }; | |
231 | |
232 PresentationFrameManager::PresentationFrameManager( | |
233 content::WebContents* web_contents, | |
234 MediaRouter* router) | |
235 : router_(router), web_contents_(web_contents) { | |
236 DCHECK(web_contents_); | |
237 } | |
238 | |
239 PresentationFrameManager::~PresentationFrameManager() { | |
240 for (auto& frame : presentation_frames_) | |
241 frame.second->OnPresentationServiceDelegateDestroyed(); | |
242 } | |
243 | |
244 void PresentationFrameManager::OnDefaultPresentationStarted( | |
245 const RenderFrameHostId& render_frame_host_id, | |
246 const content::PresentationSessionInfo& session) const { | |
247 auto presentation_frame = presentation_frames_.get(render_frame_host_id); | |
248 if (presentation_frame) | |
249 presentation_frame->OnDefaultPresentationStarted(session); | |
250 } | |
251 | |
252 bool PresentationFrameManager::SetScreenAvailabilityListener( | |
253 const RenderFrameHostId& render_frame_host_id, | |
254 content::PresentationScreenAvailabilityListener* listener) { | |
255 DCHECK(listener); | |
256 auto presentation_frame = GetOrAddFrame(render_frame_host_id); | |
mark a. foltz
2015/06/01 19:18:12
GetOrAddPresentationFrame? (We aren't creating a D
haibinlu
2015/06/01 21:44:58
Done.
| |
257 return presentation_frame->SetScreenAvailabilityListener(listener); | |
258 } | |
259 | |
260 bool PresentationFrameManager::RemoveScreenAvailabilityListener( | |
261 const RenderFrameHostId& render_frame_host_id, | |
262 content::PresentationScreenAvailabilityListener* listener) { | |
263 DCHECK(listener); | |
264 auto presentation_frame = presentation_frames_.get(render_frame_host_id); | |
265 return presentation_frame && | |
266 presentation_frame->RemoveScreenAvailabilityListener(listener); | |
267 } | |
268 | |
269 bool PresentationFrameManager::HasScreenAvailabilityListenerForTest( | |
270 const RenderFrameHostId& render_frame_host_id, | |
271 const MediaSourceId& source_id) const { | |
272 auto presentation_frame = presentation_frames_.get(render_frame_host_id); | |
273 return presentation_frame && | |
274 presentation_frame->HasScreenAvailabilityListenerForTest(source_id); | |
275 } | |
276 | |
277 void PresentationFrameManager::SetDefaultPresentationInfo( | |
278 const RenderFrameHostId& render_frame_host_id, | |
279 const std::string& default_presentation_url, | |
280 const std::string& default_presentation_id) { | |
281 auto presentation_frame = GetOrAddFrame(render_frame_host_id); | |
282 presentation_frame->SetDefaultPresentationInfo(default_presentation_url, | |
283 default_presentation_id); | |
284 } | |
285 | |
286 std::string PresentationFrameManager::GetDefaultPresentationId( | |
287 const RenderFrameHostId& render_frame_host_id) const { | |
288 auto presentation_frame = presentation_frames_.get(render_frame_host_id); | |
289 if (presentation_frame) | |
290 return presentation_frame->GetDefaultPresentationId(); | |
291 return ""; | |
292 } | |
293 | |
294 void PresentationFrameManager::AddDelegateObserver( | |
295 const RenderFrameHostId& render_frame_host_id, | |
296 content::PresentationServiceDelegate::Observer* observer) { | |
297 auto presentation_frame = GetOrAddFrame(render_frame_host_id); | |
298 presentation_frame->set_delegate_observer(observer); | |
299 } | |
300 | |
301 void PresentationFrameManager::RemoveDelegateObserver( | |
302 const RenderFrameHostId& render_frame_host_id) { | |
303 auto presentation_frame = presentation_frames_.get(render_frame_host_id); | |
304 if (presentation_frame) { | |
305 presentation_frame->set_delegate_observer(nullptr); | |
306 presentation_frames_.erase(render_frame_host_id); | |
307 } | |
308 } | |
309 | |
310 void PresentationFrameManager::Reset( | |
311 const RenderFrameHostId& render_frame_host_id) { | |
312 auto presentation_frame = presentation_frames_.get(render_frame_host_id); | |
313 if (presentation_frame) | |
314 presentation_frame->Reset(); | |
315 } | |
316 | |
317 PresentationFrame* PresentationFrameManager::GetOrAddFrame( | |
318 const RenderFrameHostId& render_frame_host_id) { | |
319 if (!presentation_frames_.contains(render_frame_host_id)) { | |
320 presentation_frames_.add( | |
321 render_frame_host_id, | |
322 scoped_ptr<PresentationFrame>( | |
323 new PresentationFrame(web_contents_, router_))); | |
324 } | |
325 return presentation_frames_.get(render_frame_host_id); | |
326 } | |
327 | |
328 void PresentationFrameManager::SetMediaRouterForTest(MediaRouter* router) { | |
329 router_ = router; | |
330 } | |
331 | |
332 // TODO(haibinlu): Get router from MediaRouterMojoImplFactory once it lands. | |
333 // BUG=464205 | |
mark a. foltz
2015/06/01 19:18:12
https://codereview.chromium.org/1143603004/ has la
haibinlu
2015/06/01 21:44:58
Done.
| |
334 PresentationServiceDelegateImpl::PresentationServiceDelegateImpl( | |
335 content::WebContents* web_contents) | |
336 : frame_manager_(new PresentationFrameManager(web_contents, nullptr)), | |
337 web_contents_(web_contents), | |
338 router_(nullptr), | |
339 weak_factory_(this) { | |
340 } | |
341 | |
342 PresentationServiceDelegateImpl::~PresentationServiceDelegateImpl() { | |
343 } | |
344 | |
345 void PresentationServiceDelegateImpl::AddObserver( | |
346 int render_process_id, | |
347 int render_frame_id, | |
348 content::PresentationServiceDelegate::Observer* observer) { | |
349 DCHECK(observer); | |
350 frame_manager_->AddDelegateObserver( | |
351 RenderFrameHostId(render_process_id, render_frame_id), observer); | |
352 } | |
353 | |
354 void PresentationServiceDelegateImpl::RemoveObserver(int render_process_id, | |
355 int render_frame_id) { | |
356 frame_manager_->RemoveDelegateObserver( | |
357 RenderFrameHostId(render_process_id, render_frame_id)); | |
358 } | |
359 | |
360 bool PresentationServiceDelegateImpl::AddScreenAvailabilityListener( | |
361 int render_process_id, | |
362 int render_frame_id, | |
363 content::PresentationScreenAvailabilityListener* listener) { | |
364 DCHECK(listener); | |
365 return frame_manager_->SetScreenAvailabilityListener( | |
366 RenderFrameHostId(render_process_id, render_frame_id), listener); | |
367 } | |
368 | |
369 void PresentationServiceDelegateImpl::RemoveScreenAvailabilityListener( | |
370 int render_process_id, | |
371 int render_frame_id, | |
372 content::PresentationScreenAvailabilityListener* listener) { | |
373 DCHECK(listener); | |
374 frame_manager_->RemoveScreenAvailabilityListener( | |
375 RenderFrameHostId(render_process_id, render_frame_id), listener); | |
376 } | |
377 | |
378 void PresentationServiceDelegateImpl::Reset(int render_process_id, | |
379 int render_frame_id) { | |
380 RenderFrameHostId render_frame_host_id(render_process_id, render_frame_id); | |
381 frame_manager_->Reset(render_frame_host_id); | |
382 if (IsMainFrame(render_process_id, render_frame_id)) | |
383 UpdateDefaultMediaSourceAndNotifyObservers(MediaSource(), std::string()); | |
384 } | |
385 | |
386 void PresentationServiceDelegateImpl::SetDefaultPresentationUrl( | |
387 int render_process_id, | |
388 int render_frame_id, | |
389 const std::string& default_presentation_url, | |
390 const std::string& default_presentation_id) { | |
391 RenderFrameHostId render_frame_host_id(render_process_id, render_frame_id); | |
392 frame_manager_->SetDefaultPresentationInfo( | |
393 render_frame_host_id, default_presentation_url, default_presentation_id); | |
394 if (IsMainFrame(render_process_id, render_frame_id)) { | |
395 // This is the main frame, which means tab-level default presentation | |
396 // might have been updated. | |
397 MediaSource default_source; | |
398 if (!default_presentation_url.empty()) | |
399 default_source = MediaSourceForPresentationUrl(default_presentation_url); | |
400 std::string default_frame_display_name( | |
401 GetDisplayNameForFrame(render_frame_host_id)); | |
402 UpdateDefaultMediaSourceAndNotifyObservers(default_source, | |
403 default_frame_display_name); | |
404 } | |
405 } | |
406 | |
407 bool PresentationServiceDelegateImpl::IsMainFrame(int render_process_id, | |
408 int render_frame_id) const { | |
409 RenderFrameHost* main_frame = web_contents_->GetMainFrame(); | |
410 return main_frame && | |
411 GetRenderFrameHostId(main_frame) == | |
412 RenderFrameHostId(render_process_id, render_frame_id); | |
413 } | |
414 | |
415 void PresentationServiceDelegateImpl:: | |
416 UpdateDefaultMediaSourceAndNotifyObservers( | |
417 const MediaSource& default_source, | |
418 const std::string& default_frame_display_name) { | |
419 if (!default_source.Equals(default_source_) || | |
420 default_frame_display_name != default_frame_display_name_) { | |
421 default_source_ = default_source; | |
422 default_frame_display_name_ = default_frame_display_name; | |
423 FOR_EACH_OBSERVER(DefaultMediaSourceObserver, | |
424 default_media_source_observers_, | |
425 OnDefaultMediaSourceChanged(default_source_, | |
426 default_frame_display_name_)); | |
427 } | |
428 } | |
429 | |
430 void PresentationServiceDelegateImpl::StartSession( | |
431 int render_process_id, | |
432 int render_frame_id, | |
433 const std::string& presentation_url, | |
434 const std::string& presentation_id, | |
435 const PresentationSessionSuccessCallback& success_cb, | |
436 const PresentationSessionErrorCallback& error_cb) { | |
437 // BUG=464205 | |
438 NOTIMPLEMENTED(); | |
439 } | |
440 | |
441 void PresentationServiceDelegateImpl::JoinSession( | |
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 // BUG=464205 | |
449 NOTIMPLEMENTED(); | |
450 } | |
451 | |
452 void PresentationServiceDelegateImpl::ListenForSessionMessages( | |
453 int render_process_id, | |
454 int render_frame_id, | |
455 const PresentationSessionMessageCallback& message_cb) { | |
456 // BUG=464205 | |
457 NOTIMPLEMENTED(); | |
458 } | |
459 | |
460 void PresentationServiceDelegateImpl::SendMessage( | |
461 int render_process_id, | |
462 int render_frame_id, | |
463 scoped_ptr<content::PresentationSessionMessage> message_request, | |
464 const SendMessageCallback& send_message_cb) { | |
465 // BUG=464205 | |
466 NOTIMPLEMENTED(); | |
467 } | |
468 | |
469 void PresentationServiceDelegateImpl::OnRouteCreated(const MediaRoute& route) { | |
470 const MediaSource& source = route.media_source(); | |
471 DCHECK(!source.Empty()); | |
472 if (!default_source_.Equals(source)) | |
473 return; | |
474 RenderFrameHost* main_frame = web_contents_->GetMainFrame(); | |
475 if (!main_frame) | |
476 return; | |
477 RenderFrameHostId render_frame_host_id(GetRenderFrameHostId(main_frame)); | |
478 // TODO(imcheng): Pass in valid default presentation ID once it is | |
479 // available from MediaRoute URN. BUG=493365 | |
480 frame_manager_->OnDefaultPresentationStarted( | |
481 render_frame_host_id, | |
482 content::PresentationSessionInfo(PresentationUrlFromMediaSource(source), | |
483 std::string())); | |
484 } | |
485 | |
486 void PresentationServiceDelegateImpl::AddDefaultMediaSourceObserver( | |
487 DefaultMediaSourceObserver* observer) { | |
488 default_media_source_observers_.AddObserver(observer); | |
489 } | |
490 | |
491 void PresentationServiceDelegateImpl::RemoveDefaultMediaSourceObserver( | |
492 DefaultMediaSourceObserver* observer) { | |
493 default_media_source_observers_.RemoveObserver(observer); | |
494 } | |
495 | |
496 void PresentationServiceDelegateImpl::SetMediaRouterForTest( | |
497 MediaRouter* router) { | |
498 router_ = router; | |
499 frame_manager_->SetMediaRouterForTest(router); | |
500 } | |
501 | |
502 base::WeakPtr<PresentationServiceDelegateImpl> | |
503 PresentationServiceDelegateImpl::GetWeakPtr() { | |
504 return weak_factory_.GetWeakPtr(); | |
505 } | |
506 | |
507 bool PresentationServiceDelegateImpl::HasScreenAvailabilityListenerForTest( | |
508 int render_process_id, | |
509 int render_frame_id, | |
510 const MediaSourceId& source_id) const { | |
511 RenderFrameHostId render_frame_host_id(render_process_id, render_frame_id); | |
512 return frame_manager_->HasScreenAvailabilityListenerForTest( | |
513 render_frame_host_id, source_id); | |
514 } | |
515 | |
516 } // namespace media_router | |
OLD | NEW |