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