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

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

Issue 1143603004: [Media Router] Add Media Router Mojo impl code. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Addressed nits 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/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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698