| 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_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 | |
| OLD | NEW |