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/media_router_mojo_impl.h" | |
6 | |
7 #include "base/bind.h" | |
8 #include "base/guid.h" | |
9 #include "base/logging.h" | |
10 #include "base/observer_list.h" | |
11 #include "chrome/browser/media/router/media_router_mojo_impl_factory.h" | |
12 #include "chrome/browser/media/router/media_router_type_converters.h" | |
13 #include "chrome/browser/media/router/media_routes_observer.h" | |
14 #include "chrome/browser/media/router/media_sinks_observer.h" | |
15 #include "extensions/browser/process_manager.h" | |
16 | |
17 #define DVLOG_WITH_INSTANCE(level) \ | |
18 DVLOG(level) << "MR #" << instance_id_ << ": " | |
19 | |
20 #define DLOG_WITH_INSTANCE(level) DLOG(level) << "MR #" << instance_id_ << ": " | |
21 | |
22 namespace media_router { | |
23 namespace { | |
24 | |
25 // Converts the callback result of calling Mojo CreateRoute() into a local | |
26 // callback. | |
27 void CreateRouteFinished(const MediaSinkId& sink_id, | |
28 const MediaRouteResponseCallback& callback, | |
29 interfaces::MediaRoutePtr media_route, | |
30 const mojo::String& error_text) { | |
31 if (media_route.is_null()) { | |
32 // An error occurred. | |
33 DCHECK(!error_text.is_null()); | |
34 callback.Run(nullptr, !error_text.get().empty() ? error_text.get() | |
35 : "Unknown error."); | |
36 return; | |
37 } | |
38 callback.Run(make_scoped_ptr(new MediaRoute(media_route.To<MediaRoute>())), | |
xhwang
2015/05/28 06:53:21
You can have a converter converting interfaces::Me
imcheng (use chromium acct)
2015/05/28 20:46:35
Done.
| |
39 ""); | |
40 } | |
41 | |
42 // TODO(imcheng): We should handle failure in this case. One way is to invoke | |
43 // all pending requests with failure. (crbug.com/490787) | |
44 void EventPageWakeComplete(bool success) { | |
45 if (!success) | |
46 LOG(ERROR) << "An error encountered while waking the event page."; | |
47 } | |
48 | |
49 } // namespace | |
50 | |
51 MediaRouterMojoImpl::MediaRouterMojoImpl() | |
52 : event_page_tracker_(nullptr), instance_id_(base::GenerateGUID()) { | |
53 } | |
54 | |
55 MediaRouterMojoImpl::MediaRouterMojoImpl( | |
56 const std::string& mrpm_extension_id, | |
xhwang
2015/05/28 06:53:21
In the header file this is called mojo_media_route
imcheng (use chromium acct)
2015/05/28 20:46:35
Removed.
| |
57 extensions::EventPageTracker* event_page_tracker_for_test) | |
58 : MediaRouterMojoImpl() { | |
59 DCHECK(!mrpm_extension_id.empty()); | |
60 DCHECK(event_page_tracker_for_test); | |
61 | |
62 mojo_media_router_extension_id_ = mrpm_extension_id; | |
xhwang
2015/05/28 06:53:20
ditto about naming.
imcheng (use chromium acct)
2015/05/28 20:46:35
Acknowledged.
| |
63 event_page_tracker_ = event_page_tracker_for_test; | |
64 } | |
65 | |
66 MediaRouterMojoImpl::~MediaRouterMojoImpl() { | |
67 DCHECK(thread_checker_.CalledOnValidThread()); | |
68 } | |
69 | |
70 // static | |
71 void MediaRouterMojoImpl::BindToRequest( | |
72 const std::string& extension_id, | |
73 content::BrowserContext* context, | |
74 mojo::InterfaceRequest<interfaces::MediaRouterObserver> request) { | |
75 MediaRouterMojoImpl* impl = | |
76 MediaRouterMojoImplFactory::GetApiForBrowserContext(context); | |
77 DCHECK(impl); | |
78 | |
79 impl->BindToMojoRequest(request.Pass()); | |
80 impl->InitExtensionInfo(extension_id, context); | |
81 } | |
82 | |
83 void MediaRouterMojoImpl::BindToMojoRequest( | |
84 mojo::InterfaceRequest<interfaces::MediaRouterObserver> request) { | |
85 DCHECK(thread_checker_.CalledOnValidThread()); | |
86 | |
87 binding_.reset( | |
88 new mojo::Binding<interfaces::MediaRouterObserver>(this, request.Pass())); | |
89 binding_->set_error_handler(this); | |
90 } | |
91 | |
92 void MediaRouterMojoImpl::InitExtensionInfo(const std::string& extension_id, | |
93 content::BrowserContext* context) { | |
94 DCHECK(thread_checker_.CalledOnValidThread()); | |
95 DCHECK(context); | |
96 | |
97 mojo_media_router_extension_id_ = extension_id; | |
98 event_page_tracker_ = extensions::ProcessManager::Get(context); | |
99 } | |
100 | |
101 // TODO(imcheng): If this occurs while there are pending requests, we should | |
102 // probably invoke them with failure. (crbug.com/490787) | |
103 void MediaRouterMojoImpl::OnConnectionError() { | |
104 DCHECK(thread_checker_.CalledOnValidThread()); | |
105 | |
106 mojo_media_router_.reset(); | |
107 binding_.reset(); | |
108 } | |
xhwang
2015/05/28 06:53:21
OOC, will |this| get destructed upon connection er
imcheng (use chromium acct)
2015/05/28 20:46:35
|this| will not be destroyed upon connection error
| |
109 | |
110 void MediaRouterMojoImpl::ProvideMediaRouter( | |
111 interfaces::MediaRouterPtr media_router_ptr, | |
112 const interfaces::MediaRouterObserver::ProvideMediaRouterCallback& | |
113 callback) { | |
114 DCHECK(thread_checker_.CalledOnValidThread()); | |
115 | |
116 mojo_media_router_ = media_router_ptr.Pass(); | |
117 mojo_media_router_.set_error_handler(this); | |
118 callback.Run(instance_id_); | |
119 ExecutePendingRequests(); | |
120 } | |
121 | |
122 void MediaRouterMojoImpl::OnMessage(const mojo::String& route_id, | |
123 const mojo::String& message) { | |
124 // TODO(imcheng): Implement. (crbug.com/461815) | |
125 DCHECK(thread_checker_.CalledOnValidThread()); | |
126 NOTIMPLEMENTED(); | |
127 } | |
128 | |
129 void MediaRouterMojoImpl::OnIssue(const interfaces::IssuePtr issue) { | |
130 // TODO(imcheng): Implement. (crbug.com/461815) | |
131 DCHECK(thread_checker_.CalledOnValidThread()); | |
132 NOTIMPLEMENTED(); | |
133 } | |
134 | |
135 void MediaRouterMojoImpl::OnSinksReceived( | |
136 const mojo::String& media_source, | |
137 mojo::Array<interfaces::MediaSinkPtr> sinks) { | |
138 DCHECK(thread_checker_.CalledOnValidThread()); | |
139 | |
140 DVLOG_WITH_INSTANCE(1) << "OnSinksReceived"; | |
141 std::vector<MediaSink> sinks_converted; | |
142 sinks_converted.reserve(sinks.size()); | |
143 | |
144 for (size_t i = 0; i < sinks.size(); ++i) { | |
145 sinks_converted.push_back(sinks[i].To<MediaSink>()); | |
146 } | |
147 | |
148 auto it = sinks_observers_.find(media_source); | |
149 if (it == sinks_observers_.end()) { | |
150 DVLOG_WITH_INSTANCE(1) | |
151 << "Received sink list without any active observers: " << media_source; | |
152 } else { | |
153 FOR_EACH_OBSERVER(MediaSinksObserver, *it->second, | |
154 OnSinksReceived(sinks_converted)); | |
155 } | |
156 } | |
157 | |
158 void MediaRouterMojoImpl::OnRoutesUpdated( | |
159 mojo::Array<interfaces::MediaRoutePtr> routes) { | |
160 DCHECK(thread_checker_.CalledOnValidThread()); | |
161 | |
162 DVLOG_WITH_INSTANCE(1) << "OnRoutesUpdated"; | |
163 | |
164 std::vector<MediaRoute> routes_converted; | |
165 routes_converted.reserve(routes.size()); | |
166 | |
167 for (size_t i = 0; i < routes.size(); ++i) { | |
168 routes_converted.push_back(routes[i].To<MediaRoute>()); | |
169 } | |
170 | |
171 FOR_EACH_OBSERVER(MediaRoutesObserver, routes_observers_, | |
172 OnRoutesUpdated(routes_converted)); | |
173 } | |
174 | |
175 void MediaRouterMojoImpl::CreateRoute( | |
176 const MediaSourceId& source_id, | |
177 const MediaSinkId& sink_id, | |
178 const MediaRouteResponseCallback& callback) { | |
179 DCHECK(thread_checker_.CalledOnValidThread()); | |
180 | |
181 RunOrDefer(base::Bind(&MediaRouterMojoImpl::DoCreateRoute, | |
182 base::Unretained(this), source_id, sink_id, callback)); | |
183 } | |
184 | |
185 void MediaRouterMojoImpl::CloseRoute(const MediaRouteId& route_id) { | |
186 DCHECK(thread_checker_.CalledOnValidThread()); | |
187 | |
188 RunOrDefer(base::Bind(&MediaRouterMojoImpl::DoCloseRoute, | |
189 base::Unretained(this), route_id)); | |
190 } | |
191 | |
192 void MediaRouterMojoImpl::PostMessage(const MediaRouteId& route_id, | |
193 const std::string& message) { | |
194 DCHECK(thread_checker_.CalledOnValidThread()); | |
195 | |
196 RunOrDefer(base::Bind(&MediaRouterMojoImpl::DoPostMessage, | |
197 base::Unretained(this), route_id, message)); | |
198 } | |
199 | |
200 void MediaRouterMojoImpl::ClearIssue(const Issue::IssueId& issue_id) { | |
201 DCHECK(thread_checker_.CalledOnValidThread()); | |
202 | |
203 RunOrDefer(base::Bind(&MediaRouterMojoImpl::DoClearIssue, | |
204 base::Unretained(this), issue_id)); | |
205 } | |
206 | |
207 void MediaRouterMojoImpl::RegisterMediaSinksObserver( | |
208 MediaSinksObserver* observer) { | |
209 DCHECK(thread_checker_.CalledOnValidThread()); | |
210 | |
211 // Create an observer list for the media source and add |observer| | |
212 // to it. Fail if |observer| is already registered. | |
213 const std::string& source_id = observer->source().id(); | |
214 ObserverList<MediaSinksObserver>* observer_list = | |
215 sinks_observers_.get(source_id); | |
216 if (!observer_list) { | |
217 observer_list = new ObserverList<MediaSinksObserver>; | |
218 sinks_observers_.add(source_id, make_scoped_ptr(observer_list)); | |
219 } else { | |
220 DCHECK(!observer_list->HasObserver(observer)); | |
221 } | |
222 | |
223 // We need to call DoStartObservingMediaSinks every time an observer is | |
224 // added to ensure the observer will be notified with a fresh set of results. | |
225 // TODO(imcheng): Implement caching. (crbug.com/492451) | |
226 observer_list->AddObserver(observer); | |
227 RunOrDefer(base::Bind(&MediaRouterMojoImpl::DoStartObservingMediaSinks, | |
228 base::Unretained(this), source_id)); | |
229 } | |
230 | |
231 void MediaRouterMojoImpl::UnregisterMediaSinksObserver( | |
232 MediaSinksObserver* observer) { | |
233 DCHECK(thread_checker_.CalledOnValidThread()); | |
234 | |
235 const std::string& source_id = observer->source().id(); | |
236 auto* observer_list = sinks_observers_.get(source_id); | |
237 if (!observer_list || !observer_list->HasObserver(observer)) { | |
238 return; | |
239 } | |
240 | |
241 // If we are removing the final observer for the source, then stop | |
242 // observing sinks for it. | |
243 // might_have_observers() is reliable here on the assumption that this call | |
244 // is not inside the ObserverList iteration. | |
245 observer_list->RemoveObserver(observer); | |
246 if (!observer_list->might_have_observers()) { | |
247 RunOrDefer(base::Bind(&MediaRouterMojoImpl::DoStopObservingMediaSinks, | |
248 base::Unretained(this), source_id)); | |
249 sinks_observers_.erase(source_id); | |
250 } | |
251 } | |
252 | |
253 void MediaRouterMojoImpl::RegisterMediaRoutesObserver( | |
254 MediaRoutesObserver* observer) { | |
255 DCHECK(thread_checker_.CalledOnValidThread()); | |
256 DCHECK(!routes_observers_.HasObserver(observer)); | |
257 | |
258 RunOrDefer(base::Bind(&MediaRouterMojoImpl::DoStartObservingMediaRoutes, | |
259 base::Unretained(this))); | |
260 routes_observers_.AddObserver(observer); | |
261 } | |
262 | |
263 void MediaRouterMojoImpl::UnregisterMediaRoutesObserver( | |
264 MediaRoutesObserver* observer) { | |
265 if (!routes_observers_.HasObserver(observer)) | |
266 return; | |
267 | |
268 routes_observers_.RemoveObserver(observer); | |
269 if (!routes_observers_.might_have_observers()) { | |
270 RunOrDefer(base::Bind(&MediaRouterMojoImpl::DoStopObservingMediaRoutes, | |
271 base::Unretained(this))); | |
272 } | |
273 } | |
274 | |
275 void MediaRouterMojoImpl::AddIssuesObserver(IssuesObserver* observer) { | |
276 // TODO(imcheng): Implement. (crbug.com/461815) | |
277 NOTIMPLEMENTED(); | |
278 } | |
279 | |
280 void MediaRouterMojoImpl::RemoveIssuesObserver(IssuesObserver* observer) { | |
281 // TODO(imcheng): Implement. (crbug.com/461815) | |
282 NOTIMPLEMENTED(); | |
283 } | |
284 | |
285 void MediaRouterMojoImpl::DoCreateRoute( | |
286 const MediaSourceId& source_id, | |
287 const MediaSinkId& sink_id, | |
288 const MediaRouteResponseCallback& callback) { | |
289 DVLOG_WITH_INSTANCE(1) << "CreateRoute " << source_id << "=>" << sink_id; | |
290 mojo_media_router_->CreateRoute( | |
291 source_id, sink_id, base::Bind(&CreateRouteFinished, sink_id, callback)); | |
292 } | |
293 | |
294 void MediaRouterMojoImpl::DoCloseRoute(const MediaRouteId& route_id) { | |
295 DVLOG_WITH_INSTANCE(1) << "CloseRoute " << route_id; | |
296 mojo_media_router_->CloseRoute(route_id); | |
297 } | |
298 | |
299 void MediaRouterMojoImpl::DoPostMessage(const MediaRouteId& route_id, | |
300 const std::string& message) { | |
301 DVLOG_WITH_INSTANCE(1) << "PostMessage " << route_id; | |
302 mojo_media_router_->PostMessage(route_id, message); | |
303 } | |
304 | |
305 void MediaRouterMojoImpl::DoClearIssue(const Issue::IssueId& issue_id) { | |
306 DVLOG_WITH_INSTANCE(1) << "ClearIssue " << issue_id; | |
307 mojo_media_router_->ClearIssue(issue_id); | |
308 } | |
309 | |
310 void MediaRouterMojoImpl::DoStartObservingMediaSinks( | |
311 const std::string& source_id) { | |
312 DVLOG_WITH_INSTANCE(1) << "StartObservingMediaSinks: " << source_id; | |
313 mojo_media_router_->StartObservingMediaSinks(source_id); | |
314 } | |
315 | |
316 void MediaRouterMojoImpl::DoStopObservingMediaSinks( | |
317 const std::string& source_id) { | |
318 DVLOG_WITH_INSTANCE(1) << "StopObservingMediaSinks: " << source_id; | |
319 mojo_media_router_->StopObservingMediaSinks(source_id); | |
320 } | |
321 | |
322 void MediaRouterMojoImpl::DoStartObservingMediaRoutes() { | |
323 DVLOG_WITH_INSTANCE(1) << "StartObservingMediaRoutes"; | |
324 mojo_media_router_->StartObservingMediaRoutes(); | |
325 } | |
326 | |
327 void MediaRouterMojoImpl::DoStopObservingMediaRoutes() { | |
328 DVLOG_WITH_INSTANCE(1) << "StopObservingMediaRoutes"; | |
329 mojo_media_router_->StopObservingMediaRoutes(); | |
330 } | |
331 | |
332 void MediaRouterMojoImpl::EnqueueTask(const base::Closure& closure) { | |
333 pending_requests_.push_back(closure); | |
334 DVLOG_WITH_INSTANCE(2) << "EnqueueTask (queue-length=" | |
335 << pending_requests_.size() << ")"; | |
336 } | |
337 | |
338 void MediaRouterMojoImpl::RunOrDefer(const base::Closure& request) { | |
339 DCHECK(event_page_tracker_); | |
340 | |
341 if (event_page_tracker_->IsEventPageSuspended( | |
342 mojo_media_router_extension_id_)) { | |
343 DVLOG_WITH_INSTANCE(1) << "Waking event page."; | |
344 EnqueueTask(request); | |
345 if (!event_page_tracker_->WakeEventPage( | |
346 mojo_media_router_extension_id_, | |
347 base::Bind(&EventPageWakeComplete))) { | |
348 LOG(ERROR) << "An error encountered while waking the event page."; | |
349 } | |
350 mojo_media_router_.reset(); | |
351 } else if (!mojo_media_router_) { | |
352 DVLOG_WITH_INSTANCE(1) << "Extension is awake, awaiting MRPM connection."; | |
xhwang
2015/05/28 06:53:20
MRPM is not seen in this file; update the comment?
imcheng (use chromium acct)
2015/05/28 20:46:35
Done.
| |
353 EnqueueTask(request); | |
354 } else { | |
355 request.Run(); | |
356 } | |
357 } | |
358 | |
359 void MediaRouterMojoImpl::ExecutePendingRequests() { | |
360 DCHECK(thread_checker_.CalledOnValidThread()); | |
361 DCHECK(mojo_media_router_); | |
362 DCHECK(event_page_tracker_); | |
363 | |
364 if (event_page_tracker_->IsEventPageSuspended( | |
365 mojo_media_router_extension_id_)) { | |
366 DVLOG_WITH_INSTANCE(1) | |
367 << "ExecutePendingRequests was called while extension is suspended."; | |
368 return; | |
369 } | |
370 | |
371 for (const auto& next_request : pending_requests_) | |
372 next_request.Run(); | |
373 | |
374 pending_requests_.clear(); | |
375 } | |
376 | |
377 } // namespace media_router | |
OLD | NEW |