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_impl.h" | |
12 #include "chrome/browser/media/router/media_router_impl_factory.h" | |
13 #include "chrome/browser/media/router/media_router_mojo_impl_factory.h" | |
14 #include "chrome/browser/media/router/media_router_type_converters.h" | |
15 #include "chrome/browser/media/router/media_routes_observer.h" | |
16 #include "chrome/browser/media/router/media_sinks_observer.h" | |
17 #include "extensions/browser/process_manager.h" | |
18 | |
19 #define DVLOG_WITH_INSTANCE(level) \ | |
20 DVLOG(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() | |
mark a. foltz
2015/05/08 00:58:37
extra ()
Kevin M
2015/05/12 23:56:09
Done.
| |
35 : "Unknown error.")); | |
36 return; | |
37 } | |
38 callback.Run(make_scoped_ptr(new MediaRoute(media_route.To<MediaRoute>())), | |
39 ""); | |
40 } | |
41 | |
42 void EventPageWakeComplete(bool success) { | |
43 if (!success) | |
44 LOG(ERROR) << "An error encountered while waking the event page."; | |
45 } | |
46 | |
47 } // namespace | |
48 | |
49 MediaRouterMojoImpl::MediaRouterMojoImpl() | |
50 : event_page_tracker_(nullptr), instance_id_(base::GenerateGUID()) { | |
51 } | |
52 | |
53 MediaRouterMojoImpl::MediaRouterMojoImpl( | |
54 const std::string& mrpm_extension_id, | |
55 extensions::EventPageTracker* event_page_tracker_for_test) | |
56 : MediaRouterMojoImpl() { | |
57 DCHECK(!mrpm_extension_id.empty()); | |
58 DCHECK(event_page_tracker_for_test); | |
59 mrpm_extension_id_ = mrpm_extension_id; | |
60 event_page_tracker_ = event_page_tracker_for_test; | |
61 } | |
62 | |
63 MediaRouterMojoImpl::~MediaRouterMojoImpl() { | |
64 DCHECK(thread_checker_.CalledOnValidThread()); | |
65 } | |
66 | |
67 // static | |
68 void MediaRouterMojoImpl::BindToRequest( | |
69 const std::string& extension_id, | |
70 content::BrowserContext* context, | |
71 mojo::InterfaceRequest<interfaces::MediaRouterObserver> request) { | |
72 MediaRouterMojoImpl* impl = | |
73 MediaRouterMojoImplFactory::GetApiForBrowserContext(context); | |
74 DCHECK(impl); | |
75 impl->Bind(request.Pass()); | |
mark a. foltz
2015/05/08 00:58:37
What does this do?
Kevin M
2015/05/12 23:56:09
Binds the object "impl" to a Mojo interface reques
| |
76 impl->MonitorExtension(extension_id, context); | |
mark a. foltz
2015/05/08 00:58:37
What if extension_id is already being monitored or
Kevin M
2015/05/12 23:56:09
It is idempotent for a given extension ID and cont
| |
77 } | |
78 | |
79 void MediaRouterMojoImpl::Bind( | |
80 mojo::InterfaceRequest<interfaces::MediaRouterObserver> request) { | |
81 DCHECK(thread_checker_.CalledOnValidThread()); | |
82 binding_.reset( | |
83 new mojo::Binding<interfaces::MediaRouterObserver>(this, request.Pass())); | |
84 binding_->set_error_handler(this); | |
85 } | |
86 | |
87 void MediaRouterMojoImpl::OnConnectionError() { | |
88 DCHECK(thread_checker_.CalledOnValidThread()); | |
89 mrpm_.reset(); | |
90 binding_.reset(); | |
91 } | |
92 | |
93 void MediaRouterMojoImpl::ProvideMediaRouter( | |
94 interfaces::MediaRouterPtr mrpm, | |
95 const interfaces::MediaRouterObserver::ProvideMediaRouterCallback& | |
96 callback) { | |
97 DCHECK(thread_checker_.CalledOnValidThread()); | |
98 mrpm_ = mrpm.Pass(); | |
99 mrpm_.set_error_handler(this); | |
100 callback.Run(instance_id_); | |
101 ExecutePendingRequests(); | |
102 } | |
103 | |
104 void MediaRouterMojoImpl::OnMessage(const mojo::String& route_id, | |
105 const mojo::String& message) { | |
106 DCHECK(thread_checker_.CalledOnValidThread()); | |
107 NOTIMPLEMENTED(); | |
108 } | |
109 | |
110 void MediaRouterMojoImpl::OnIssue(const interfaces::IssuePtr issue) { | |
111 DCHECK(thread_checker_.CalledOnValidThread()); | |
112 NOTIMPLEMENTED(); | |
113 } | |
114 | |
115 void MediaRouterMojoImpl::OnSinksReceived( | |
116 const mojo::String& media_source, | |
117 mojo::Array<interfaces::MediaSinkPtr> sinks) { | |
118 DCHECK(thread_checker_.CalledOnValidThread()); | |
119 DVLOG_WITH_INSTANCE(1) << "OnSinksReceived"; | |
120 std::vector<MediaSink> sinks_converted; | |
121 sinks_converted.reserve(sinks.size()); | |
122 | |
123 for (size_t i = 0; i < sinks.size(); ++i) { | |
124 sinks_converted.push_back(sinks[i].To<MediaSink>()); | |
125 } | |
126 | |
127 auto it = sinks_observers_.find(media_source); | |
128 if (it == sinks_observers_.end()) { | |
129 DVLOG_WITH_INSTANCE(1) | |
130 << "Received sink list without any active observers: " << media_source; | |
131 } else { | |
132 FOR_EACH_OBSERVER(MediaSinksObserver, *it->second, | |
133 OnSinksReceived(sinks_converted)); | |
134 } | |
135 } | |
136 | |
137 void MediaRouterMojoImpl::OnRoutesUpdated( | |
138 mojo::Array<interfaces::MediaRoutePtr> routes) { | |
139 DCHECK(thread_checker_.CalledOnValidThread()); | |
140 DVLOG_WITH_INSTANCE(1) << "OnRoutesUpdated"; | |
141 | |
142 std::vector<MediaRoute> routes_converted; | |
143 routes_converted.reserve(routes.size()); | |
144 | |
145 for (size_t i = 0; i < routes.size(); ++i) { | |
146 routes_converted.push_back(routes[i].To<MediaRoute>()); | |
147 } | |
148 | |
149 FOR_EACH_OBSERVER(MediaRoutesObserver, routes_observers_, | |
150 OnRoutesUpdated(routes_converted)); | |
151 } | |
152 | |
153 // ---------------------------------------------------------------------------- | |
154 // MediaRouter methods. | |
155 | |
156 void MediaRouterMojoImpl::CreateRoute( | |
157 const MediaSourceId& source_id, | |
158 const MediaSinkId& sink_id, | |
159 const MediaRouteResponseCallback& callback) { | |
160 DCHECK(thread_checker_.CalledOnValidThread()); | |
161 RunOrDefer(base::Bind(&MediaRouterMojoImpl::DoCreateRoute, | |
162 base::Unretained(this), source_id, sink_id, callback)); | |
163 } | |
164 | |
165 void MediaRouterMojoImpl::CloseRoute(const MediaRouteId& route_id) { | |
166 DCHECK(thread_checker_.CalledOnValidThread()); | |
167 RunOrDefer(base::Bind(&MediaRouterMojoImpl::DoCloseRoute, | |
168 base::Unretained(this), route_id)); | |
169 } | |
170 | |
171 void MediaRouterMojoImpl::PostMessage(const MediaRouteId& route_id, | |
172 const std::string& message) { | |
173 DCHECK(thread_checker_.CalledOnValidThread()); | |
174 RunOrDefer(base::Bind(&MediaRouterMojoImpl::DoPostMessage, | |
175 base::Unretained(this), route_id, message)); | |
176 } | |
177 | |
178 void MediaRouterMojoImpl::ClearIssue(const Issue::IssueId& issue_id) { | |
179 DCHECK(thread_checker_.CalledOnValidThread()); | |
180 RunOrDefer(base::Bind(&MediaRouterMojoImpl::DoClearIssue, | |
181 base::Unretained(this), issue_id)); | |
182 } | |
183 | |
184 bool MediaRouterMojoImpl::RegisterMediaSinksObserver( | |
185 MediaSinksObserver* observer) { | |
186 DCHECK(thread_checker_.CalledOnValidThread()); | |
187 | |
188 // Lazily create an observer list for the media source and add |observer| | |
mark a. foltz
2015/05/08 00:58:37
This doesn't look lazy - you're newing one up at L
Kevin M
2015/05/12 23:56:09
Done.
| |
189 // to it. | |
190 const std::string& source_id = observer->source().id(); | |
191 linked_ptr<ObserverList<MediaSinksObserver>> observer_list = | |
192 sinks_observers_[source_id]; | |
193 if (!observer_list.get()) { | |
194 observer_list = make_linked_ptr(new ObserverList<MediaSinksObserver>); | |
195 sinks_observers_[source_id] = observer_list; | |
196 } else { | |
197 if (observer_list->HasObserver(observer)) { | |
198 DLOG(FATAL) << "Redundant RegisterMediaSinksObserver call detected."; | |
mark a. foltz
2015/05/08 00:58:38
Log instance id?
Kevin M
2015/05/12 23:56:09
Done.
| |
199 return true; | |
200 } | |
201 } | |
202 | |
203 // Turn on sink observation if this is the first time we've started observing | |
204 // sinks for the media source. | |
205 if (!observer_list->might_have_observers()) { | |
206 RunOrDefer(base::Bind(&MediaRouterMojoImpl::DoStartObservingMediaSinks, | |
207 base::Unretained(this), source_id)); | |
208 } | |
209 observer_list->AddObserver(observer); | |
210 | |
211 return true; | |
212 } | |
213 | |
214 void MediaRouterMojoImpl::UnregisterMediaSinksObserver( | |
215 MediaSinksObserver* observer) { | |
216 DCHECK(thread_checker_.CalledOnValidThread()); | |
217 | |
218 const std::string& source_id = observer->source().id(); | |
219 const auto observer_list_it = sinks_observers_.find(source_id); | |
220 if (observer_list_it == sinks_observers_.end() || | |
221 !observer_list_it->second->HasObserver(observer)) { | |
222 return; | |
223 } | |
224 observer_list_it->second->RemoveObserver(observer); | |
225 | |
226 // If we are removing the final observer for the source, then stop | |
227 // observing sinks for it. | |
228 if (!observer_list_it->second->might_have_observers()) { | |
229 RunOrDefer(base::Bind(&MediaRouterMojoImpl::DoStopObservingMediaSinks, | |
230 base::Unretained(this), source_id)); | |
231 sinks_observers_.erase(observer_list_it); | |
232 } | |
233 } | |
234 | |
235 bool MediaRouterMojoImpl::RegisterMediaRoutesObserver( | |
236 MediaRoutesObserver* observer) { | |
237 DCHECK(thread_checker_.CalledOnValidThread()); | |
238 if (routes_observers_.HasObserver(observer)) { | |
239 DLOG(FATAL) << "Redundant RegisterMediaRoutesObserver() call detected."; | |
240 return true; | |
241 } | |
242 | |
243 // TODO(kmarshall): add result caching and max limits. | |
244 if (!routes_observers_.might_have_observers()) { | |
245 RunOrDefer(base::Bind(&MediaRouterMojoImpl::DoStartObservingMediaRoutes, | |
246 base::Unretained(this))); | |
247 } | |
248 routes_observers_.AddObserver(observer); | |
249 return true; | |
250 } | |
251 | |
252 void MediaRouterMojoImpl::UnregisterMediaRoutesObserver( | |
253 MediaRoutesObserver* observer) { | |
254 if (!routes_observers_.HasObserver(observer)) { | |
255 return; | |
256 } | |
257 routes_observers_.RemoveObserver(observer); | |
258 if (!routes_observers_.might_have_observers()) { | |
259 RunOrDefer(base::Bind(&MediaRouterMojoImpl::DoStopObservingMediaRoutes, | |
260 base::Unretained(this))); | |
261 } | |
262 } | |
263 | |
264 void MediaRouterMojoImpl::AddIssuesObserver(IssuesObserver* observer) { | |
265 NOTIMPLEMENTED(); // TODO(kmarshall): To be landed in a separate CL. | |
mark a. foltz
2015/05/08 00:58:37
I think that's implied by NOTIMPLEMENTED() :)
Or
Kevin M
2015/05/12 23:56:09
Done.
| |
266 } | |
267 | |
268 void MediaRouterMojoImpl::RemoveIssuesObserver(IssuesObserver* observer) { | |
269 NOTIMPLEMENTED(); | |
270 } | |
271 | |
272 void MediaRouterMojoImpl::DoCreateRoute( | |
273 const MediaSourceId& source_id, | |
274 const MediaSinkId& sink_id, | |
275 const MediaRouteResponseCallback& callback) { | |
276 DCHECK(thread_checker_.CalledOnValidThread()); | |
277 DCHECK(mrpm_); | |
278 DVLOG_WITH_INSTANCE(1) << "CreateRoute " << source_id << "=>" << sink_id; | |
279 mrpm_->CreateRoute(source_id, sink_id, | |
280 base::Bind(&CreateRouteFinished, sink_id, callback)); | |
281 } | |
282 | |
283 void MediaRouterMojoImpl::DoCloseRoute(const MediaRouteId& route_id) { | |
284 DCHECK(thread_checker_.CalledOnValidThread()); | |
285 DCHECK(mrpm_); | |
286 DVLOG_WITH_INSTANCE(1) << "CloseRoute " << route_id; | |
287 mrpm_->CloseRoute(route_id); | |
288 } | |
289 | |
290 void MediaRouterMojoImpl::DoPostMessage(const MediaRouteId& route_id, | |
291 const std::string& message) { | |
292 DCHECK(thread_checker_.CalledOnValidThread()); | |
293 DCHECK(mrpm_); | |
294 DVLOG_WITH_INSTANCE(1) << "PostMessage " << route_id; | |
295 mrpm_->PostMessage(route_id, message); | |
296 } | |
297 | |
298 void MediaRouterMojoImpl::DoClearIssue(const Issue::IssueId& issue_id) { | |
299 DCHECK(thread_checker_.CalledOnValidThread()); | |
300 DCHECK(mrpm_); | |
301 DVLOG_WITH_INSTANCE(1) << "ClearIssue " << issue_id; | |
302 mrpm_->ClearIssue(issue_id); | |
303 } | |
304 | |
305 void MediaRouterMojoImpl::DoStartObservingMediaSinks( | |
306 const std::string& source_id) { | |
307 DCHECK(thread_checker_.CalledOnValidThread()); | |
308 DCHECK(mrpm_); | |
309 DVLOG_WITH_INSTANCE(1) << "StartObservingMediaSinks: " << source_id; | |
310 mrpm_->StartObservingMediaSinks(source_id); | |
311 } | |
312 | |
313 void MediaRouterMojoImpl::DoStopObservingMediaSinks( | |
314 const std::string& source_id) { | |
315 DCHECK(thread_checker_.CalledOnValidThread()); | |
316 DCHECK(mrpm_); | |
317 DVLOG_WITH_INSTANCE(1) << "StopObservingMediaSinks: " << source_id; | |
318 mrpm_->StopObservingMediaSinks(source_id); | |
319 } | |
320 | |
321 void MediaRouterMojoImpl::DoStartObservingMediaRoutes() { | |
322 DCHECK(thread_checker_.CalledOnValidThread()); | |
323 DCHECK(mrpm_); | |
324 DVLOG_WITH_INSTANCE(1) << "StartObservingMediaRoutes"; | |
325 mrpm_->StartObservingMediaRoutes(); | |
326 } | |
327 | |
328 void MediaRouterMojoImpl::DoStopObservingMediaRoutes() { | |
329 DCHECK(thread_checker_.CalledOnValidThread()); | |
330 DCHECK(mrpm_); | |
331 DVLOG_WITH_INSTANCE(1) << "StopObservingMediaRoutes"; | |
332 mrpm_->StopObservingMediaRoutes(); | |
333 } | |
334 | |
335 void MediaRouterMojoImpl::EnqueueTask(const base::Closure& closure) { | |
336 DVLOG_WITH_INSTANCE(2) << "EnqueueTask (size=" << pending_requests_.size() | |
337 << ")"; | |
338 pending_requests_.push_back(closure); | |
339 } | |
340 | |
341 void MediaRouterMojoImpl::MonitorExtension(const std::string& extension_id, | |
342 content::BrowserContext* context) { | |
343 DCHECK(thread_checker_.CalledOnValidThread()); | |
344 DCHECK(!extension_id.empty()); | |
345 DCHECK(context); | |
346 mrpm_extension_id_ = extension_id; | |
347 event_page_tracker_ = extensions::ProcessManager::Get(context); | |
348 } | |
349 | |
350 void MediaRouterMojoImpl::RunOrDefer(const base::Closure& request_cb) { | |
351 DCHECK(event_page_tracker_); | |
352 if (event_page_tracker_->IsEventPageSuspended(mrpm_extension_id_)) { | |
353 DVLOG_WITH_INSTANCE(1) << "Waking event page."; | |
354 pending_requests_.push_back(request_cb); | |
355 if (!event_page_tracker_->WakeEventPage( | |
356 mrpm_extension_id_, base::Bind(&EventPageWakeComplete))) { | |
357 LOG(ERROR) << "An error encountered while waking the event page."; | |
358 } | |
359 mrpm_.reset(); | |
360 } else if (!mrpm_) { | |
361 DVLOG_WITH_INSTANCE(1) << "Extension is awake, awaiting MRPM connection."; | |
362 pending_requests_.push_back(request_cb); | |
363 } else { | |
364 request_cb.Run(); | |
365 } | |
366 } | |
367 | |
368 void MediaRouterMojoImpl::ExecutePendingRequests() { | |
369 DCHECK(thread_checker_.CalledOnValidThread()); | |
370 DCHECK(mrpm_); | |
371 DCHECK(event_page_tracker_); | |
372 if (event_page_tracker_->IsEventPageSuspended(mrpm_extension_id_)) { | |
373 DVLOG_WITH_INSTANCE(1) | |
374 << "ExecutePendingRequests was called while extension is suspended."; | |
375 return; | |
376 } | |
377 | |
378 for (const auto& next_request : pending_requests_) { | |
379 next_request.Run(); | |
380 } | |
381 pending_requests_.clear(); | |
382 } | |
383 | |
384 } // namespace media_router | |
OLD | NEW |