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

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

Powered by Google App Engine
This is Rietveld 408576698