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

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

Issue 1126923002: Add Media Router Mojo impl code. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Redundant forward decl removed. 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>())),
39 "");
40 }
41
42 void EventPageWakeComplete(bool success) {
43 if (!success)
44 LOG(ERROR) << "An error encountered while waking the event page.";
Wez 2015/05/20 23:37:48 Shouldn't we do fun stuff like dispatch errors for
imcheng (use chromium acct) 2015/05/21 19:28:50 Filed a tracking bug for handling failure.
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);
Wez 2015/05/20 23:37:48 nit: Suggest a blank line between pre-condition DC
imcheng (use chromium acct) 2015/05/21 19:28:50 Done.
59 mojo_media_router_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());
76 impl->MonitorExtension(extension_id, context);
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());
Wez 2015/05/20 23:37:48 What happens to pendign requests at this point?
imcheng (use chromium acct) 2015/05/21 19:28:50 There's an edge case here where this can happen be
89 mojo_media_router_.reset();
90 binding_.reset();
91 }
92
93 void MediaRouterMojoImpl::ProvideMediaRouter(
94 interfaces::MediaRouterPtr media_router_ptr,
95 const interfaces::MediaRouterObserver::ProvideMediaRouterCallback&
96 callback) {
97 DCHECK(thread_checker_.CalledOnValidThread());
98 mojo_media_router_ = media_router_ptr.Pass();
99 mojo_media_router_.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();
Wez 2015/05/20 23:37:47 is this something that will be implemented, ever?
imcheng (use chromium acct) 2015/05/21 19:28:51 Yes, this will be implemented eventually.
108 }
109
110 void MediaRouterMojoImpl::OnIssue(const interfaces::IssuePtr issue) {
111 DCHECK(thread_checker_.CalledOnValidThread());
112 NOTIMPLEMENTED();
Wez 2015/05/20 23:37:48 See above.
imcheng (use chromium acct) 2015/05/21 19:28:50 Ditto.
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.
Wez 2015/05/20 23:37:48 nit: Remove this comment? It doesn't really add an
imcheng (use chromium acct) 2015/05/21 19:28:50 Done.
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 // Create an observer list for the media source and add |observer|
189 // to it. Fail if |observer| is already registered.
190 const std::string& source_id = observer->source().id();
191 ObserverList<MediaSinksObserver>* observer_list =
192 sinks_observers_.get(source_id);
193 if (!observer_list) {
194 observer_list = new ObserverList<MediaSinksObserver>;
195 sinks_observers_.add(source_id, make_scoped_ptr(observer_list));
196 } else {
197 if (observer_list->HasObserver(observer)) {
198 DLOG_WITH_INSTANCE(FATAL)
199 << "Redundant RegisterMediaSinksObserver call detected.";
Wez 2015/05/20 23:37:48 s/Redundant/Duplicate Does this indicate a coding
imcheng (use chromium acct) 2015/05/21 19:28:50 How about a DCHECK? That is what we used to have i
200 return false;
201 }
202 }
203
204 RunOrDefer(base::Bind(&MediaRouterMojoImpl::DoStartObservingMediaSinks,
205 base::Unretained(this), source_id));
206 observer_list->AddObserver(observer);
Wez 2015/05/20 23:37:47 nit: In principle you should add the observer _bef
imcheng (use chromium acct) 2015/05/21 19:28:51 Good point. Swapped the order.
207
208 return true;
209 }
210
211 void MediaRouterMojoImpl::UnregisterMediaSinksObserver(
212 MediaSinksObserver* observer) {
213 DCHECK(thread_checker_.CalledOnValidThread());
214
215 const std::string& source_id = observer->source().id();
216 auto* observer_list = sinks_observers_.get(source_id);
217 if (!observer_list || !observer_list->HasObserver(observer)) {
218 return;
Wez 2015/05/20 23:37:47 Does reaching here indicate a coding error? If so
imcheng (use chromium acct) 2015/05/21 19:28:51 Done.
219 }
220 observer_list->RemoveObserver(observer);
221
222 // If we are removing the final observer for the source, then stop
223 // observing sinks for it.
Wez 2015/05/20 23:37:48 nit: Suggest clarifying here that might_have_obser
imcheng (use chromium acct) 2015/05/21 19:28:51 Done.
224 if (!observer_list->might_have_observers()) {
225 RunOrDefer(base::Bind(&MediaRouterMojoImpl::DoStopObservingMediaSinks,
226 base::Unretained(this), source_id));
227 sinks_observers_.erase(source_id);
228 }
229 }
230
231 bool MediaRouterMojoImpl::RegisterMediaRoutesObserver(
232 MediaRoutesObserver* observer) {
233 DCHECK(thread_checker_.CalledOnValidThread());
234 if (routes_observers_.HasObserver(observer)) {
235 DLOG(FATAL) << "Redundant RegisterMediaRoutesObserver() call detected.";
Wez 2015/05/20 23:37:48 See above re these never-reached error conditions.
imcheng (use chromium acct) 2015/05/21 19:28:50 Done.
236 return true;
Wez 2015/05/20 23:37:48 Why return true here?
imcheng (use chromium acct) 2015/05/21 19:28:50 removed return value.
237 }
238
239 RunOrDefer(base::Bind(&MediaRouterMojoImpl::DoStartObservingMediaRoutes,
240 base::Unretained(this)));
241 routes_observers_.AddObserver(observer);
242 return true;
243 }
244
245 void MediaRouterMojoImpl::UnregisterMediaRoutesObserver(
246 MediaRoutesObserver* observer) {
247 if (!routes_observers_.HasObserver(observer))
248 return;
249 routes_observers_.RemoveObserver(observer);
250 if (!routes_observers_.might_have_observers()) {
251 RunOrDefer(base::Bind(&MediaRouterMojoImpl::DoStopObservingMediaRoutes,
252 base::Unretained(this)));
253 }
254 }
255
256 void MediaRouterMojoImpl::AddIssuesObserver(IssuesObserver* observer) {
257 NOTIMPLEMENTED();
Wez 2015/05/20 23:37:48 Is there abug # for adding these?
imcheng (use chromium acct) 2015/05/21 19:28:50 Done.
258 }
259
260 void MediaRouterMojoImpl::RemoveIssuesObserver(IssuesObserver* observer) {
261 NOTIMPLEMENTED();
262 }
263
264 void MediaRouterMojoImpl::DoCreateRoute(
265 const MediaSourceId& source_id,
266 const MediaSinkId& sink_id,
267 const MediaRouteResponseCallback& callback) {
268 DVLOG_WITH_INSTANCE(1) << "CreateRoute " << source_id << "=>" << sink_id;
269 mojo_media_router_->CreateRoute(
270 source_id, sink_id, base::Bind(&CreateRouteFinished, sink_id, callback));
271 }
272
273 void MediaRouterMojoImpl::DoCloseRoute(const MediaRouteId& route_id) {
274 DVLOG_WITH_INSTANCE(1) << "CloseRoute " << route_id;
275 mojo_media_router_->CloseRoute(route_id);
276 }
277
278 void MediaRouterMojoImpl::DoPostMessage(const MediaRouteId& route_id,
279 const std::string& message) {
280 DVLOG_WITH_INSTANCE(1) << "PostMessage " << route_id;
281 mojo_media_router_->PostMessage(route_id, message);
282 }
283
284 void MediaRouterMojoImpl::DoClearIssue(const Issue::IssueId& issue_id) {
285 DVLOG_WITH_INSTANCE(1) << "ClearIssue " << issue_id;
286 mojo_media_router_->ClearIssue(issue_id);
287 }
288
289 void MediaRouterMojoImpl::DoStartObservingMediaSinks(
290 const std::string& source_id) {
291 DVLOG_WITH_INSTANCE(1) << "StartObservingMediaSinks: " << source_id;
292 mojo_media_router_->StartObservingMediaSinks(source_id);
293 }
294
295 void MediaRouterMojoImpl::DoStopObservingMediaSinks(
296 const std::string& source_id) {
297 DVLOG_WITH_INSTANCE(1) << "StopObservingMediaSinks: " << source_id;
298 mojo_media_router_->StopObservingMediaSinks(source_id);
299 }
300
301 void MediaRouterMojoImpl::DoStartObservingMediaRoutes() {
302 DVLOG_WITH_INSTANCE(1) << "StartObservingMediaRoutes";
303 mojo_media_router_->StartObservingMediaRoutes();
304 }
305
306 void MediaRouterMojoImpl::DoStopObservingMediaRoutes() {
307 DVLOG_WITH_INSTANCE(1) << "StopObservingMediaRoutes";
308 mojo_media_router_->StopObservingMediaRoutes();
309 }
310
311 void MediaRouterMojoImpl::EnqueueTask(const base::Closure& closure) {
312 DVLOG_WITH_INSTANCE(2) << "EnqueueTask (size=" << pending_requests_.size()
313 << ")";
Wez 2015/05/20 23:37:48 Does this get used anywhere...?
imcheng (use chromium acct) 2015/05/21 19:28:50 Changed below to use this function.
314 pending_requests_.push_back(closure);
315 }
316
317 void MediaRouterMojoImpl::MonitorExtension(const std::string& extension_id,
318 content::BrowserContext* context) {
319 DCHECK(thread_checker_.CalledOnValidThread());
320 DCHECK(context);
321 mojo_media_router_extension_id_ = extension_id;
322 event_page_tracker_ = extensions::ProcessManager::Get(context);
Wez 2015/05/20 23:37:48 This doesn't seem to be doing anything to actually
imcheng (use chromium acct) 2015/05/21 19:28:50 Yeah, we changed from a push model to a pull model
Wez 2015/05/21 23:32:47 Bind could certainly use a re-name to something mo
imcheng (use chromium acct) 2015/05/22 00:54:07 I ended up keeping the Bind() and extension logic
323 }
324
325 void MediaRouterMojoImpl::RunOrDefer(const base::Closure& request_cb) {
Wez 2015/05/20 23:37:48 This isn't the request callback, it's the request
imcheng (use chromium acct) 2015/05/21 19:28:51 Done.
326 DCHECK(event_page_tracker_);
327 if (event_page_tracker_->IsEventPageSuspended(
328 mojo_media_router_extension_id_)) {
329 DVLOG_WITH_INSTANCE(1) << "Waking event page.";
330 pending_requests_.push_back(request_cb);
331 if (!event_page_tracker_->WakeEventPage(
332 mojo_media_router_extension_id_,
333 base::Bind(&EventPageWakeComplete))) {
Wez 2015/05/20 23:37:48 Seems strange that we don't care about the wake co
imcheng (use chromium acct) 2015/05/21 19:28:50 Yes, I agree. But these adds complexity to this cl
Wez 2015/05/21 23:32:47 Acknowledged.
334 LOG(ERROR) << "An error encountered while waking the event page.";
335 }
336 mojo_media_router_.reset();
337 } else if (!mojo_media_router_) {
338 DVLOG_WITH_INSTANCE(1) << "Extension is awake, awaiting MRPM connection.";
339 pending_requests_.push_back(request_cb);
340 } else {
341 request_cb.Run();
342 }
343 }
344
345 void MediaRouterMojoImpl::ExecutePendingRequests() {
346 DCHECK(thread_checker_.CalledOnValidThread());
347 DCHECK(mojo_media_router_);
348 DCHECK(event_page_tracker_);
349 if (event_page_tracker_->IsEventPageSuspended(
350 mojo_media_router_extension_id_)) {
351 DVLOG_WITH_INSTANCE(1)
352 << "ExecutePendingRequests was called while extension is suspended.";
353 return;
354 }
355
356 for (const auto& next_request : pending_requests_)
357 next_request.Run();
358
359 pending_requests_.clear();
360 }
361
362 } // namespace media_router
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698