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

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

Issue 1826403002: [Media Router] Moves mojo-specific code into mojo/ folder (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 9 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 <stddef.h>
8 #include <utility>
9
10 #include "base/bind.h"
11 #include "base/guid.h"
12 #include "base/logging.h"
13 #include "base/memory/scoped_vector.h"
14 #include "base/observer_list.h"
15 #include "base/stl_util.h"
16 #include "base/strings/stringprintf.h"
17 #include "chrome/browser/media/router/issues_observer.h"
18 #include "chrome/browser/media/router/media_router_factory.h"
19 #include "chrome/browser/media/router/media_router_metrics.h"
20 #include "chrome/browser/media/router/media_router_type_converters.h"
21 #include "chrome/browser/media/router/media_routes_observer.h"
22 #include "chrome/browser/media/router/media_sinks_observer.h"
23 #include "chrome/browser/media/router/presentation_session_messages_observer.h"
24 #include "chrome/browser/sessions/session_tab_helper.h"
25 #include "extensions/browser/process_manager.h"
26
27 #define DVLOG_WITH_INSTANCE(level) \
28 DVLOG(level) << "MR #" << instance_id_ << ": "
29
30 #define DLOG_WITH_INSTANCE(level) DLOG(level) << "MR #" << instance_id_ << ": "
31
32 namespace media_router {
33
34 using SinkAvailability = interfaces::MediaRouter::SinkAvailability;
35
36 namespace {
37
38 scoped_ptr<content::PresentationSessionMessage>
39 ConvertToPresentationSessionMessage(interfaces::RouteMessagePtr input) {
40 DCHECK(!input.is_null());
41 scoped_ptr<content::PresentationSessionMessage> output;
42 switch (input->type) {
43 case interfaces::RouteMessage::Type::TEXT: {
44 DCHECK(!input->message.is_null());
45 DCHECK(input->data.is_null());
46 output.reset(new content::PresentationSessionMessage(
47 content::PresentationMessageType::TEXT));
48 input->message.Swap(&output->message);
49 return output;
50 }
51 case interfaces::RouteMessage::Type::BINARY: {
52 DCHECK(!input->data.is_null());
53 DCHECK(input->message.is_null());
54 output.reset(new content::PresentationSessionMessage(
55 content::PresentationMessageType::ARRAY_BUFFER));
56 output->data.reset(new std::vector<uint8_t>);
57 input->data.Swap(output->data.get());
58 return output;
59 }
60 }
61
62 NOTREACHED() << "Invalid route message type " << input->type;
63 return output;
64 }
65
66 } // namespace
67
68 MediaRouterMojoImpl::MediaRoutesQuery::MediaRoutesQuery() = default;
69
70 MediaRouterMojoImpl::MediaRoutesQuery::~MediaRoutesQuery() = default;
71
72 MediaRouterMojoImpl::MediaSinksQuery::MediaSinksQuery() = default;
73
74 MediaRouterMojoImpl::MediaSinksQuery::~MediaSinksQuery() = default;
75
76 MediaRouterMojoImpl::MediaRouterMojoImpl(
77 extensions::EventPageTracker* event_page_tracker)
78 : event_page_tracker_(event_page_tracker),
79 instance_id_(base::GenerateGUID()),
80 availability_(interfaces::MediaRouter::SinkAvailability::UNAVAILABLE),
81 current_wake_reason_(MediaRouteProviderWakeReason::TOTAL_COUNT),
82 weak_factory_(this) {
83 DCHECK(event_page_tracker_);
84 }
85
86 MediaRouterMojoImpl::~MediaRouterMojoImpl() {
87 DCHECK(thread_checker_.CalledOnValidThread());
88 }
89
90 // static
91 void MediaRouterMojoImpl::BindToRequest(
92 const extensions::Extension* extension,
93 content::BrowserContext* context,
94 mojo::InterfaceRequest<interfaces::MediaRouter> request) {
95 MediaRouterMojoImpl* impl = static_cast<MediaRouterMojoImpl*>(
96 MediaRouterFactory::GetApiForBrowserContext(context));
97 DCHECK(impl);
98
99 impl->BindToMojoRequest(std::move(request), *extension);
100 }
101
102 void MediaRouterMojoImpl::BindToMojoRequest(
103 mojo::InterfaceRequest<interfaces::MediaRouter> request,
104 const extensions::Extension& extension) {
105 DCHECK(thread_checker_.CalledOnValidThread());
106
107 binding_.reset(
108 new mojo::Binding<interfaces::MediaRouter>(this, std::move(request)));
109 binding_->set_connection_error_handler(base::Bind(
110 &MediaRouterMojoImpl::OnConnectionError, base::Unretained(this)));
111
112 media_route_provider_extension_id_ = extension.id();
113 if (!provider_version_was_recorded_) {
114 MediaRouterMetrics::RecordMediaRouteProviderVersion(extension);
115 provider_version_was_recorded_ = true;
116 }
117 }
118
119 void MediaRouterMojoImpl::OnConnectionError() {
120 DCHECK(thread_checker_.CalledOnValidThread());
121
122 media_route_provider_.reset();
123 binding_.reset();
124
125 // If |OnConnectionError| is invoked while there are pending requests, then
126 // it means we tried to wake the extension, but weren't able to complete the
127 // connection to media route provider. Since we do not know whether the error
128 // is transient, reattempt the wakeup.
129 if (!pending_requests_.empty()) {
130 DLOG_WITH_INSTANCE(ERROR) << "A connection error while there are pending "
131 "requests.";
132 SetWakeReason(MediaRouteProviderWakeReason::CONNECTION_ERROR);
133 AttemptWakeEventPage();
134 }
135 }
136
137 void MediaRouterMojoImpl::RegisterMediaRouteProvider(
138 interfaces::MediaRouteProviderPtr media_route_provider_ptr,
139 const interfaces::MediaRouter::RegisterMediaRouteProviderCallback&
140 callback) {
141 DCHECK(thread_checker_.CalledOnValidThread());
142
143 if (event_page_tracker_->IsEventPageSuspended(
144 media_route_provider_extension_id_)) {
145 DVLOG_WITH_INSTANCE(1)
146 << "RegisterMediaRouteProvider was called while extension is "
147 "suspended.";
148 media_route_provider_.reset();
149 SetWakeReason(MediaRouteProviderWakeReason::REGISTER_MEDIA_ROUTE_PROVIDER);
150 AttemptWakeEventPage();
151 return;
152 }
153
154 media_route_provider_ = std::move(media_route_provider_ptr);
155 media_route_provider_.set_connection_error_handler(base::Bind(
156 &MediaRouterMojoImpl::OnConnectionError, base::Unretained(this)));
157 callback.Run(instance_id_);
158 ExecutePendingRequests();
159 wakeup_attempt_count_ = 0;
160 }
161
162 void MediaRouterMojoImpl::OnIssue(const interfaces::IssuePtr issue) {
163 DCHECK(thread_checker_.CalledOnValidThread());
164 DVLOG_WITH_INSTANCE(1) << "OnIssue " << issue->title;
165 const Issue& issue_converted = issue.To<Issue>();
166 issue_manager_.AddIssue(issue_converted);
167 }
168
169 void MediaRouterMojoImpl::OnSinksReceived(
170 const mojo::String& media_source,
171 mojo::Array<interfaces::MediaSinkPtr> sinks,
172 mojo::Array<mojo::String> origins) {
173 DCHECK(thread_checker_.CalledOnValidThread());
174 DVLOG_WITH_INSTANCE(1) << "OnSinksReceived";
175 auto it = sinks_queries_.find(media_source);
176 if (it == sinks_queries_.end()) {
177 DVLOG_WITH_INSTANCE(1) << "Received sink list without MediaSinksQuery.";
178 return;
179 }
180
181 std::vector<GURL> origin_list;
182 origin_list.reserve(origins.size());
183 for (size_t i = 0; i < origins.size(); ++i) {
184 GURL origin(origins[i].get());
185 if (!origin.is_valid()) {
186 LOG(WARNING) << "Received invalid origin: " << origin
187 << ". Dropping result.";
188 return;
189 }
190 origin_list.push_back(origin);
191 }
192
193 std::vector<MediaSink> sink_list;
194 sink_list.reserve(sinks.size());
195 for (size_t i = 0; i < sinks.size(); ++i)
196 sink_list.push_back(sinks[i].To<MediaSink>());
197
198 auto* sinks_query = it->second;
199 sinks_query->has_cached_result = true;
200 sinks_query->origins.swap(origin_list);
201 sinks_query->cached_sink_list.swap(sink_list);
202
203 if (!sinks_query->observers.might_have_observers()) {
204 DVLOG_WITH_INSTANCE(1)
205 << "Received sink list without any active observers: " << media_source;
206 } else {
207 FOR_EACH_OBSERVER(
208 MediaSinksObserver, sinks_query->observers,
209 OnSinksUpdated(sinks_query->cached_sink_list, sinks_query->origins));
210 }
211 }
212
213 void MediaRouterMojoImpl::OnRoutesUpdated(
214 mojo::Array<interfaces::MediaRoutePtr> routes,
215 const mojo::String& media_source,
216 mojo::Array<mojo::String> joinable_route_ids) {
217 DCHECK(thread_checker_.CalledOnValidThread());
218
219 DVLOG_WITH_INSTANCE(1) << "OnRoutesUpdated";
220 auto it = routes_queries_.find(media_source);
221 if (it == routes_queries_.end() ||
222 !(it->second->observers.might_have_observers())) {
223 DVLOG_WITH_INSTANCE(1)
224 << "Received route list without any active observers: " << media_source;
225 return;
226 }
227
228 std::vector<MediaRoute> routes_converted;
229 routes_converted.reserve(routes.size());
230
231 for (size_t i = 0; i < routes.size(); ++i)
232 routes_converted.push_back(routes[i].To<MediaRoute>());
233
234 std::vector<MediaRoute::Id> joinable_routes_converted =
235 joinable_route_ids.To<std::vector<std::string>>();
236
237 FOR_EACH_OBSERVER(MediaRoutesObserver, it->second->observers,
238 OnRoutesUpdated(routes_converted,
239 joinable_routes_converted));
240 }
241
242 void MediaRouterMojoImpl::RouteResponseReceived(
243 const std::string& presentation_id,
244 bool off_the_record,
245 const std::vector<MediaRouteResponseCallback>& callbacks,
246 interfaces::MediaRoutePtr media_route,
247 const mojo::String& error_text,
248 interfaces::RouteRequestResultCode result_code) {
249 scoped_ptr<RouteRequestResult> result;
250 if (media_route.is_null()) {
251 // An error occurred.
252 DCHECK(!error_text.is_null());
253 std::string error =
254 !error_text.get().empty() ? error_text.get() : "Unknown error.";
255 result = RouteRequestResult::FromError(
256 error, mojo::RouteRequestResultCodeFromMojo(result_code));
257 } else if (media_route->off_the_record != off_the_record) {
258 std::string error = base::StringPrintf(
259 "Mismatch in off the record status: request = %d, response = %d",
260 off_the_record, media_route->off_the_record);
261 result = RouteRequestResult::FromError(
262 error, RouteRequestResult::OFF_THE_RECORD_MISMATCH);
263 } else {
264 result = RouteRequestResult::FromSuccess(
265 media_route.To<scoped_ptr<MediaRoute>>(), presentation_id);
266 if (result->route()->off_the_record())
267 OnOffTheRecordRouteCreated(result->route()->media_route_id());
268 }
269
270 // TODO(imcheng): Add UMA histogram based on result code (crbug.com/583044).
271 for (const MediaRouteResponseCallback& callback : callbacks)
272 callback.Run(*result);
273 }
274
275 void MediaRouterMojoImpl::CreateRoute(
276 const MediaSource::Id& source_id,
277 const MediaSink::Id& sink_id,
278 const GURL& origin,
279 content::WebContents* web_contents,
280 const std::vector<MediaRouteResponseCallback>& callbacks,
281 base::TimeDelta timeout,
282 bool off_the_record) {
283 DCHECK(thread_checker_.CalledOnValidThread());
284
285 if (!origin.is_valid()) {
286 DVLOG_WITH_INSTANCE(1) << "Invalid origin: " << origin;
287 scoped_ptr<RouteRequestResult> result = RouteRequestResult::FromError(
288 "Invalid origin", RouteRequestResult::INVALID_ORIGIN);
289 for (const MediaRouteResponseCallback& callback : callbacks)
290 callback.Run(*result);
291 return;
292 }
293
294 SetWakeReason(MediaRouteProviderWakeReason::CREATE_ROUTE);
295 int tab_id = SessionTabHelper::IdForTab(web_contents);
296 RunOrDefer(base::Bind(&MediaRouterMojoImpl::DoCreateRoute,
297 base::Unretained(this), source_id, sink_id,
298 origin.is_empty() ? "" : origin.spec(), tab_id,
299 callbacks, timeout, off_the_record));
300 }
301
302 void MediaRouterMojoImpl::JoinRoute(
303 const MediaSource::Id& source_id,
304 const std::string& presentation_id,
305 const GURL& origin,
306 content::WebContents* web_contents,
307 const std::vector<MediaRouteResponseCallback>& callbacks,
308 base::TimeDelta timeout,
309 bool off_the_record) {
310 DCHECK(thread_checker_.CalledOnValidThread());
311
312 if (!origin.is_valid()) {
313 DVLOG_WITH_INSTANCE(1) << "Invalid origin: " << origin;
314 scoped_ptr<RouteRequestResult> result = RouteRequestResult::FromError(
315 "Invalid origin", RouteRequestResult::INVALID_ORIGIN);
316 for (const MediaRouteResponseCallback& callback : callbacks)
317 callback.Run(*result);
318 return;
319 }
320
321 SetWakeReason(MediaRouteProviderWakeReason::JOIN_ROUTE);
322 int tab_id = SessionTabHelper::IdForTab(web_contents);
323 RunOrDefer(base::Bind(&MediaRouterMojoImpl::DoJoinRoute,
324 base::Unretained(this), source_id, presentation_id,
325 origin.is_empty() ? "" : origin.spec(), tab_id,
326 callbacks, timeout, off_the_record));
327 }
328
329 void MediaRouterMojoImpl::ConnectRouteByRouteId(
330 const MediaSource::Id& source_id,
331 const MediaRoute::Id& route_id,
332 const GURL& origin,
333 content::WebContents* web_contents,
334 const std::vector<MediaRouteResponseCallback>& callbacks,
335 base::TimeDelta timeout,
336 bool off_the_record) {
337 DCHECK(thread_checker_.CalledOnValidThread());
338
339 if (!origin.is_valid()) {
340 DVLOG_WITH_INSTANCE(1) << "Invalid origin: " << origin;
341 scoped_ptr<RouteRequestResult> result = RouteRequestResult::FromError(
342 "Invalid origin", RouteRequestResult::INVALID_ORIGIN);
343 for (const MediaRouteResponseCallback& callback : callbacks)
344 callback.Run(*result);
345 return;
346 }
347
348 SetWakeReason(MediaRouteProviderWakeReason::CONNECT_ROUTE_BY_ROUTE_ID);
349 int tab_id = SessionTabHelper::IdForTab(web_contents);
350 RunOrDefer(base::Bind(&MediaRouterMojoImpl::DoConnectRouteByRouteId,
351 base::Unretained(this), source_id, route_id,
352 origin.is_empty() ? "" : origin.spec(), tab_id,
353 callbacks, timeout, off_the_record));
354 }
355
356 void MediaRouterMojoImpl::TerminateRoute(const MediaRoute::Id& route_id) {
357 DCHECK(thread_checker_.CalledOnValidThread());
358 DVLOG(2) << "TerminateRoute " << route_id;
359 SetWakeReason(MediaRouteProviderWakeReason::TERMINATE_ROUTE);
360 RunOrDefer(base::Bind(&MediaRouterMojoImpl::DoTerminateRoute,
361 base::Unretained(this), route_id));
362 }
363
364 void MediaRouterMojoImpl::DetachRoute(const MediaRoute::Id& route_id) {
365 DCHECK(thread_checker_.CalledOnValidThread());
366
367 SetWakeReason(MediaRouteProviderWakeReason::DETACH_ROUTE);
368 RunOrDefer(base::Bind(&MediaRouterMojoImpl::DoDetachRoute,
369 base::Unretained(this), route_id));
370 }
371
372 void MediaRouterMojoImpl::SendRouteMessage(
373 const MediaRoute::Id& route_id,
374 const std::string& message,
375 const SendRouteMessageCallback& callback) {
376 DCHECK(thread_checker_.CalledOnValidThread());
377
378 SetWakeReason(MediaRouteProviderWakeReason::SEND_SESSION_MESSAGE);
379 RunOrDefer(base::Bind(&MediaRouterMojoImpl::DoSendSessionMessage,
380 base::Unretained(this), route_id, message, callback));
381 }
382
383 void MediaRouterMojoImpl::SendRouteBinaryMessage(
384 const MediaRoute::Id& route_id,
385 scoped_ptr<std::vector<uint8_t>> data,
386 const SendRouteMessageCallback& callback) {
387 DCHECK(thread_checker_.CalledOnValidThread());
388
389 SetWakeReason(MediaRouteProviderWakeReason::SEND_SESSION_BINARY_MESSAGE);
390 RunOrDefer(base::Bind(&MediaRouterMojoImpl::DoSendSessionBinaryMessage,
391 base::Unretained(this), route_id,
392 base::Passed(std::move(data)), callback));
393 }
394
395 void MediaRouterMojoImpl::AddIssue(const Issue& issue) {
396 DCHECK(thread_checker_.CalledOnValidThread());
397 issue_manager_.AddIssue(issue);
398 }
399
400 void MediaRouterMojoImpl::ClearIssue(const Issue::Id& issue_id) {
401 DCHECK(thread_checker_.CalledOnValidThread());
402 issue_manager_.ClearIssue(issue_id);
403 }
404
405 bool MediaRouterMojoImpl::RegisterMediaSinksObserver(
406 MediaSinksObserver* observer) {
407 DCHECK(thread_checker_.CalledOnValidThread());
408
409 // Create an observer list for the media source and add |observer|
410 // to it. Fail if |observer| is already registered.
411 const std::string& source_id = observer->source().id();
412 auto* sinks_query = sinks_queries_.get(source_id);
413 bool new_query = false;
414 if (!sinks_query) {
415 new_query = true;
416 sinks_query = new MediaSinksQuery;
417 sinks_queries_.add(source_id, make_scoped_ptr(sinks_query));
418 } else {
419 DCHECK(!sinks_query->observers.HasObserver(observer));
420 }
421
422 // If sink availability is UNAVAILABLE, then there is no need to call MRPM.
423 // |observer| can be immediately notified with an empty list.
424 sinks_query->observers.AddObserver(observer);
425 if (availability_ == interfaces::MediaRouter::SinkAvailability::UNAVAILABLE) {
426 observer->OnSinksUpdated(std::vector<MediaSink>(), std::vector<GURL>());
427 } else {
428 // Need to call MRPM to start observing sinks if the query is new.
429 if (new_query) {
430 SetWakeReason(MediaRouteProviderWakeReason::START_OBSERVING_MEDIA_SINKS);
431 RunOrDefer(base::Bind(&MediaRouterMojoImpl::DoStartObservingMediaSinks,
432 base::Unretained(this), source_id));
433 } else if (sinks_query->has_cached_result) {
434 observer->OnSinksUpdated(sinks_query->cached_sink_list,
435 sinks_query->origins);
436 }
437 }
438 return true;
439 }
440
441 void MediaRouterMojoImpl::UnregisterMediaSinksObserver(
442 MediaSinksObserver* observer) {
443 DCHECK(thread_checker_.CalledOnValidThread());
444
445 const MediaSource::Id& source_id = observer->source().id();
446 auto* sinks_query = sinks_queries_.get(source_id);
447 if (!sinks_query || !sinks_query->observers.HasObserver(observer)) {
448 return;
449 }
450
451 // If we are removing the final observer for the source, then stop
452 // observing sinks for it.
453 // might_have_observers() is reliable here on the assumption that this call
454 // is not inside the ObserverList iteration.
455 sinks_query->observers.RemoveObserver(observer);
456 if (!sinks_query->observers.might_have_observers()) {
457 // Only ask MRPM to stop observing media sinks if the availability is not
458 // UNAVAILABLE.
459 // Otherwise, the MRPM would have discarded the queries already.
460 if (availability_ !=
461 interfaces::MediaRouter::SinkAvailability::UNAVAILABLE) {
462 SetWakeReason(MediaRouteProviderWakeReason::STOP_OBSERVING_MEDIA_SINKS);
463 // The |sinks_queries_| entry will be removed in the immediate or deferred
464 // |DoStopObservingMediaSinks| call.
465 RunOrDefer(base::Bind(&MediaRouterMojoImpl::DoStopObservingMediaSinks,
466 base::Unretained(this), source_id));
467 } else {
468 sinks_queries_.erase(source_id);
469 }
470 }
471 }
472
473 void MediaRouterMojoImpl::RegisterMediaRoutesObserver(
474 MediaRoutesObserver* observer) {
475 DCHECK(thread_checker_.CalledOnValidThread());
476 const MediaSource::Id source_id = observer->source_id();
477 auto* routes_query = routes_queries_.get(source_id);
478 if (!routes_query) {
479 routes_query = new MediaRoutesQuery;
480 routes_queries_.add(source_id, make_scoped_ptr(routes_query));
481 } else {
482 DCHECK(!routes_query->observers.HasObserver(observer));
483 }
484
485 routes_query->observers.AddObserver(observer);
486 SetWakeReason(MediaRouteProviderWakeReason::START_OBSERVING_MEDIA_ROUTES);
487 RunOrDefer(base::Bind(&MediaRouterMojoImpl::DoStartObservingMediaRoutes,
488 base::Unretained(this), source_id));
489 }
490
491 void MediaRouterMojoImpl::UnregisterMediaRoutesObserver(
492 MediaRoutesObserver* observer) {
493 const MediaSource::Id source_id = observer->source_id();
494 auto* routes_query = routes_queries_.get(source_id);
495 if (!routes_query || !routes_query->observers.HasObserver(observer)) {
496 return;
497 }
498
499 // If we are removing the final observer for the source, then stop
500 // observing routes for it.
501 // might_have_observers() is reliable here on the assumption that this call
502 // is not inside the ObserverList iteration.
503 routes_query->observers.RemoveObserver(observer);
504 if (!routes_query->observers.might_have_observers()) {
505 SetWakeReason(MediaRouteProviderWakeReason::STOP_OBSERVING_MEDIA_ROUTES);
506 RunOrDefer(base::Bind(&MediaRouterMojoImpl::DoStopObservingMediaRoutes,
507 base::Unretained(this), source_id));
508 }
509 }
510
511 void MediaRouterMojoImpl::RegisterIssuesObserver(IssuesObserver* observer) {
512 DCHECK(thread_checker_.CalledOnValidThread());
513 issue_manager_.RegisterObserver(observer);
514 }
515
516 void MediaRouterMojoImpl::UnregisterIssuesObserver(IssuesObserver* observer) {
517 DCHECK(thread_checker_.CalledOnValidThread());
518 issue_manager_.UnregisterObserver(observer);
519 }
520
521 void MediaRouterMojoImpl::RegisterPresentationSessionMessagesObserver(
522 PresentationSessionMessagesObserver* observer) {
523 DCHECK(thread_checker_.CalledOnValidThread());
524 DCHECK(observer);
525 const MediaRoute::Id& route_id = observer->route_id();
526 auto* observer_list = messages_observers_.get(route_id);
527 if (!observer_list) {
528 observer_list = new base::ObserverList<PresentationSessionMessagesObserver>;
529 messages_observers_.add(route_id, make_scoped_ptr(observer_list));
530 } else {
531 DCHECK(!observer_list->HasObserver(observer));
532 }
533
534 bool should_listen = !observer_list->might_have_observers();
535 observer_list->AddObserver(observer);
536 if (should_listen) {
537 RunOrDefer(base::Bind(&MediaRouterMojoImpl::DoListenForRouteMessages,
538 base::Unretained(this), route_id));
539 }
540 }
541
542 void MediaRouterMojoImpl::UnregisterPresentationSessionMessagesObserver(
543 PresentationSessionMessagesObserver* observer) {
544 DCHECK(thread_checker_.CalledOnValidThread());
545 DCHECK(observer);
546
547 const MediaRoute::Id& route_id = observer->route_id();
548 auto* observer_list = messages_observers_.get(route_id);
549 if (!observer_list || !observer_list->HasObserver(observer))
550 return;
551
552 observer_list->RemoveObserver(observer);
553 if (!observer_list->might_have_observers()) {
554 messages_observers_.erase(route_id);
555 SetWakeReason(
556 MediaRouteProviderWakeReason::STOP_LISTENING_FOR_ROUTE_MESSAGES);
557 RunOrDefer(base::Bind(&MediaRouterMojoImpl::DoStopListeningForRouteMessages,
558 base::Unretained(this), route_id));
559 }
560 }
561
562 void MediaRouterMojoImpl::DoCreateRoute(
563 const MediaSource::Id& source_id,
564 const MediaSink::Id& sink_id,
565 const std::string& origin,
566 int tab_id,
567 const std::vector<MediaRouteResponseCallback>& callbacks,
568 base::TimeDelta timeout,
569 bool off_the_record) {
570 std::string presentation_id("mr_");
571 presentation_id += base::GenerateGUID();
572 DVLOG_WITH_INSTANCE(1) << "DoCreateRoute " << source_id << "=>" << sink_id
573 << ", presentation ID: " << presentation_id;
574
575 media_route_provider_->CreateRoute(
576 source_id, sink_id, presentation_id, origin, tab_id,
577 timeout > base::TimeDelta() ? timeout.InMilliseconds() : 0,
578 off_the_record, base::Bind(&MediaRouterMojoImpl::RouteResponseReceived,
579 base::Unretained(this), presentation_id,
580 off_the_record, callbacks));
581 }
582
583 void MediaRouterMojoImpl::DoJoinRoute(
584 const MediaSource::Id& source_id,
585 const std::string& presentation_id,
586 const std::string& origin,
587 int tab_id,
588 const std::vector<MediaRouteResponseCallback>& callbacks,
589 base::TimeDelta timeout,
590 bool off_the_record) {
591 DVLOG_WITH_INSTANCE(1) << "DoJoinRoute " << source_id
592 << ", presentation ID: " << presentation_id;
593
594 media_route_provider_->JoinRoute(
595 source_id, presentation_id, origin, tab_id,
596 timeout > base::TimeDelta() ? timeout.InMilliseconds() : 0,
597 off_the_record, base::Bind(&MediaRouterMojoImpl::RouteResponseReceived,
598 base::Unretained(this), presentation_id,
599 off_the_record, callbacks));
600 }
601
602 void MediaRouterMojoImpl::DoConnectRouteByRouteId(
603 const MediaSource::Id& source_id,
604 const MediaRoute::Id& route_id,
605 const std::string& origin,
606 int tab_id,
607 const std::vector<MediaRouteResponseCallback>& callbacks,
608 base::TimeDelta timeout,
609 bool off_the_record) {
610 std::string presentation_id("mr_");
611 presentation_id += base::GenerateGUID();
612 DVLOG_WITH_INSTANCE(1) << "DoConnectRouteByRouteId " << source_id
613 << ", route ID: " << route_id
614 << ", presentation ID: " << presentation_id;
615
616 media_route_provider_->ConnectRouteByRouteId(
617 source_id, route_id, presentation_id, origin, tab_id,
618 timeout > base::TimeDelta() ? timeout.InMilliseconds() : 0,
619 off_the_record, base::Bind(&MediaRouterMojoImpl::RouteResponseReceived,
620 base::Unretained(this), presentation_id,
621 off_the_record, callbacks));
622 }
623
624 void MediaRouterMojoImpl::DoTerminateRoute(const MediaRoute::Id& route_id) {
625 DVLOG_WITH_INSTANCE(1) << "DoTerminateRoute " << route_id;
626 media_route_provider_->TerminateRoute(route_id);
627 OnRouteTerminated(route_id);
628 }
629
630 void MediaRouterMojoImpl::DoDetachRoute(const MediaRoute::Id& route_id) {
631 DVLOG_WITH_INSTANCE(1) << "DoDetachRoute " << route_id;
632 media_route_provider_->DetachRoute(route_id);
633 }
634
635 void MediaRouterMojoImpl::DoSendSessionMessage(
636 const MediaRoute::Id& route_id,
637 const std::string& message,
638 const SendRouteMessageCallback& callback) {
639 DVLOG_WITH_INSTANCE(1) << "SendRouteMessage " << route_id;
640 media_route_provider_->SendRouteMessage(route_id, message, callback);
641 }
642
643 void MediaRouterMojoImpl::DoSendSessionBinaryMessage(
644 const MediaRoute::Id& route_id,
645 scoped_ptr<std::vector<uint8_t>> data,
646 const SendRouteMessageCallback& callback) {
647 DVLOG_WITH_INSTANCE(1) << "SendRouteBinaryMessage " << route_id;
648 mojo::Array<uint8_t> mojo_array;
649 mojo_array.Swap(data.get());
650 media_route_provider_->SendRouteBinaryMessage(route_id, std::move(mojo_array),
651 callback);
652 }
653
654 void MediaRouterMojoImpl::DoListenForRouteMessages(
655 const MediaRoute::Id& route_id) {
656 DVLOG_WITH_INSTANCE(1) << "ListenForRouteMessages";
657 if (!ContainsValue(route_ids_listening_for_messages_, route_id)) {
658 route_ids_listening_for_messages_.insert(route_id);
659 media_route_provider_->ListenForRouteMessages(
660 route_id, base::Bind(&MediaRouterMojoImpl::OnRouteMessagesReceived,
661 base::Unretained(this), route_id));
662 }
663 }
664
665 void MediaRouterMojoImpl::DoStopListeningForRouteMessages(
666 const MediaRoute::Id& route_id) {
667 DVLOG_WITH_INSTANCE(1) << "StopListeningForRouteMessages";
668
669 // No need to erase |route_ids_listening_for_messages_| entry here.
670 // It will be removed when there are no more observers by the time
671 // |OnRouteMessagesReceived| is invoked.
672 media_route_provider_->StopListeningForRouteMessages(route_id);
673 }
674
675 void MediaRouterMojoImpl::OnRouteMessagesReceived(
676 const MediaRoute::Id& route_id,
677 mojo::Array<interfaces::RouteMessagePtr> messages,
678 bool error) {
679 DVLOG(1) << "OnRouteMessagesReceived";
680
681 // If |messages| is null, then no more messages will come from this route.
682 // We can stop listening.
683 if (error) {
684 DVLOG(2) << "Encountered error in OnRouteMessagesReceived for " << route_id;
685 route_ids_listening_for_messages_.erase(route_id);
686 return;
687 }
688
689 // Check if there are any observers remaining. If not, the messages
690 // can be discarded and we can stop listening for the next batch of messages.
691 auto* observer_list = messages_observers_.get(route_id);
692 if (!observer_list) {
693 route_ids_listening_for_messages_.erase(route_id);
694 return;
695 }
696
697 // If |messages| is empty, then |StopListeningForRouteMessages| was invoked
698 // but we have added back an observer since. Keep listening for more messages,
699 // but do not notify observers with empty list.
700 if (!messages.storage().empty()) {
701 ScopedVector<content::PresentationSessionMessage> session_messages;
702 session_messages.reserve(messages.size());
703 for (size_t i = 0; i < messages.size(); ++i) {
704 session_messages.push_back(
705 ConvertToPresentationSessionMessage(std::move(messages[i])));
706 }
707 base::ObserverList<PresentationSessionMessagesObserver>::Iterator
708 observer_it(observer_list);
709 bool single_observer =
710 observer_it.GetNext() != nullptr && observer_it.GetNext() == nullptr;
711 FOR_EACH_OBSERVER(PresentationSessionMessagesObserver, *observer_list,
712 OnMessagesReceived(session_messages, single_observer));
713 }
714
715 // Listen for more messages.
716 media_route_provider_->ListenForRouteMessages(
717 route_id, base::Bind(&MediaRouterMojoImpl::OnRouteMessagesReceived,
718 base::Unretained(this), route_id));
719 }
720
721 void MediaRouterMojoImpl::OnSinkAvailabilityUpdated(
722 SinkAvailability availability) {
723 if (availability_ == availability)
724 return;
725
726 availability_ = availability;
727 if (availability_ == interfaces::MediaRouter::SinkAvailability::UNAVAILABLE) {
728 // Sinks are no longer available. MRPM has already removed all sink queries.
729 for (auto& source_and_query : sinks_queries_) {
730 auto* query = source_and_query.second;
731 query->is_active = false;
732 query->has_cached_result = false;
733 query->cached_sink_list.clear();
734 query->origins.clear();
735 }
736 } else {
737 // Sinks are now available. Tell MRPM to start all sink queries again.
738 for (const auto& source_and_query : sinks_queries_) {
739 RunOrDefer(base::Bind(&MediaRouterMojoImpl::DoStartObservingMediaSinks,
740 base::Unretained(this), source_and_query.first));
741 }
742 }
743 }
744
745 void MediaRouterMojoImpl::OnPresentationConnectionStateChanged(
746 const mojo::String& route_id,
747 interfaces::MediaRouter::PresentationConnectionState state) {
748 NotifyPresentationConnectionStateChange(
749 route_id, mojo::PresentationConnectionStateFromMojo(state));
750 }
751
752 void MediaRouterMojoImpl::OnPresentationConnectionClosed(
753 const mojo::String& route_id,
754 interfaces::MediaRouter::PresentationConnectionCloseReason reason,
755 const mojo::String& message) {
756 NotifyPresentationConnectionClose(
757 route_id, mojo::PresentationConnectionCloseReasonFromMojo(reason),
758 message);
759 }
760
761 void MediaRouterMojoImpl::DoStartObservingMediaSinks(
762 const MediaSource::Id& source_id) {
763 DVLOG_WITH_INSTANCE(1) << "DoStartObservingMediaSinks: " << source_id;
764 // No need to call MRPM if there are no sinks available.
765 if (availability_ == interfaces::MediaRouter::SinkAvailability::UNAVAILABLE)
766 return;
767
768 // No need to call MRPM if all observers have been removed in the meantime.
769 auto* sinks_query = sinks_queries_.get(source_id);
770 if (!sinks_query || !sinks_query->observers.might_have_observers())
771 return;
772
773 DVLOG_WITH_INSTANCE(1) << "MRPM.StartObservingMediaSinks: " << source_id;
774 media_route_provider_->StartObservingMediaSinks(source_id);
775 sinks_query->is_active = true;
776 }
777
778 void MediaRouterMojoImpl::DoStopObservingMediaSinks(
779 const MediaSource::Id& source_id) {
780 DVLOG_WITH_INSTANCE(1) << "DoStopObservingMediaSinks: " << source_id;
781
782 auto* sinks_query = sinks_queries_.get(source_id);
783 // No need to call MRPM if observers have been added in the meantime,
784 // or StopObservingMediaSinks has already been called.
785 if (!sinks_query || !sinks_query->is_active ||
786 sinks_query->observers.might_have_observers()) {
787 return;
788 }
789
790 DVLOG_WITH_INSTANCE(1) << "MRPM.StopObservingMediaSinks: " << source_id;
791 media_route_provider_->StopObservingMediaSinks(source_id);
792 sinks_queries_.erase(source_id);
793 }
794
795 void MediaRouterMojoImpl::DoStartObservingMediaRoutes(
796 const MediaSource::Id& source_id) {
797 DVLOG_WITH_INSTANCE(1) << "DoStartObservingMediaRoutes";
798
799 // No need to call MRPM if all observers have been removed in the meantime.
800 auto* routes_query = routes_queries_.get(source_id);
801 if (!routes_query || !routes_query->observers.might_have_observers())
802 return;
803
804 DVLOG_WITH_INSTANCE(1) << "MRPM.StartObservingMediaRoutes: " << source_id;
805 media_route_provider_->StartObservingMediaRoutes(source_id);
806 routes_query->is_active = true;
807 }
808
809 void MediaRouterMojoImpl::DoStopObservingMediaRoutes(
810 const MediaSource::Id& source_id) {
811 DVLOG_WITH_INSTANCE(1) << "DoStopObservingMediaRoutes";
812
813 // No need to call MRPM if observers have been added in the meantime,
814 // or StopObservingMediaRoutes has already been called.
815 auto* routes_query = routes_queries_.get(source_id);
816 if (!routes_query || !routes_query->is_active ||
817 routes_query->observers.might_have_observers()) {
818 return;
819 }
820
821 DVLOG_WITH_INSTANCE(1) << "MRPM.StopObservingMediaRoutes: " << source_id;
822 media_route_provider_->StopObservingMediaRoutes(source_id);
823 routes_queries_.erase(source_id);
824 }
825
826 void MediaRouterMojoImpl::EnqueueTask(const base::Closure& closure) {
827 pending_requests_.push_back(closure);
828 if (pending_requests_.size() > kMaxPendingRequests) {
829 DLOG_WITH_INSTANCE(ERROR) << "Reached max queue size. Dropping oldest "
830 << "request.";
831 pending_requests_.pop_front();
832 }
833 DVLOG_WITH_INSTANCE(2) << "EnqueueTask (queue-length="
834 << pending_requests_.size() << ")";
835 }
836
837 void MediaRouterMojoImpl::RunOrDefer(const base::Closure& request) {
838 DCHECK(event_page_tracker_);
839
840 if (media_route_provider_extension_id_.empty()) {
841 DVLOG_WITH_INSTANCE(1) << "Extension ID not known yet.";
842 EnqueueTask(request);
843 } else if (event_page_tracker_->IsEventPageSuspended(
844 media_route_provider_extension_id_)) {
845 DVLOG_WITH_INSTANCE(1) << "Waking event page.";
846 EnqueueTask(request);
847 AttemptWakeEventPage();
848 media_route_provider_.reset();
849 } else if (!media_route_provider_) {
850 DVLOG_WITH_INSTANCE(1) << "Extension is awake, awaiting ProvideMediaRouter "
851 " to be called.";
852 EnqueueTask(request);
853 } else {
854 request.Run();
855 }
856 }
857
858 void MediaRouterMojoImpl::AttemptWakeEventPage() {
859 ++wakeup_attempt_count_;
860 if (wakeup_attempt_count_ > kMaxWakeupAttemptCount) {
861 DLOG_WITH_INSTANCE(ERROR) << "Attempted too many times to wake up event "
862 << "page.";
863 DrainPendingRequests();
864 wakeup_attempt_count_ = 0;
865 MediaRouterMetrics::RecordMediaRouteProviderWakeup(
866 MediaRouteProviderWakeup::ERROR_TOO_MANY_RETRIES);
867 return;
868 }
869
870 DVLOG_WITH_INSTANCE(1) << "Attempting to wake up event page: attempt "
871 << wakeup_attempt_count_;
872
873 // This return false if the extension is already awake.
874 // Callback is bound using WeakPtr because |event_page_tracker_| outlives
875 // |this|.
876 if (!event_page_tracker_->WakeEventPage(
877 media_route_provider_extension_id_,
878 base::Bind(&MediaRouterMojoImpl::EventPageWakeComplete,
879 weak_factory_.GetWeakPtr()))) {
880 DLOG_WITH_INSTANCE(ERROR) << "Failed to schedule a wakeup for event page.";
881 }
882 }
883
884 void MediaRouterMojoImpl::ExecutePendingRequests() {
885 DCHECK(thread_checker_.CalledOnValidThread());
886 DCHECK(media_route_provider_);
887 DCHECK(event_page_tracker_);
888 DCHECK(!media_route_provider_extension_id_.empty());
889
890 for (const auto& next_request : pending_requests_)
891 next_request.Run();
892
893 pending_requests_.clear();
894 }
895
896 void MediaRouterMojoImpl::EventPageWakeComplete(bool success) {
897 if (success) {
898 MediaRouterMetrics::RecordMediaRouteProviderWakeReason(
899 current_wake_reason_);
900 ClearWakeReason();
901 MediaRouterMetrics::RecordMediaRouteProviderWakeup(
902 MediaRouteProviderWakeup::SUCCESS);
903 return;
904 }
905
906 // This is likely an non-retriable error. Drop the pending requests.
907 DLOG_WITH_INSTANCE(ERROR)
908 << "An error encountered while waking the event page.";
909 ClearWakeReason();
910 DrainPendingRequests();
911 MediaRouterMetrics::RecordMediaRouteProviderWakeup(
912 MediaRouteProviderWakeup::ERROR_UNKNOWN);
913 }
914
915 void MediaRouterMojoImpl::DrainPendingRequests() {
916 DLOG_WITH_INSTANCE(ERROR)
917 << "Draining request queue. (queue-length=" << pending_requests_.size()
918 << ")";
919 pending_requests_.clear();
920 }
921
922 void MediaRouterMojoImpl::SetWakeReason(MediaRouteProviderWakeReason reason) {
923 DCHECK(reason != MediaRouteProviderWakeReason::TOTAL_COUNT);
924 if (current_wake_reason_ == MediaRouteProviderWakeReason::TOTAL_COUNT)
925 current_wake_reason_ = reason;
926 }
927
928 void MediaRouterMojoImpl::ClearWakeReason() {
929 DCHECK(current_wake_reason_ != MediaRouteProviderWakeReason::TOTAL_COUNT);
930 current_wake_reason_ = MediaRouteProviderWakeReason::TOTAL_COUNT;
931 }
932
933 } // namespace media_router
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698