| Index: chrome/browser/media/router/dial_media_sink_service.cc | 
| diff --git a/chrome/browser/media/router/dial_media_sink_service.cc b/chrome/browser/media/router/dial_media_sink_service.cc | 
| new file mode 100644 | 
| index 0000000000000000000000000000000000000000..379b2375148020ab5a4bbea23924ba29fc6b741d | 
| --- /dev/null | 
| +++ b/chrome/browser/media/router/dial_media_sink_service.cc | 
| @@ -0,0 +1,142 @@ | 
| +// Copyright 2017 The Chromium Authors. All rights reserved. | 
| +// Use of this source code is governed by a BSD-style license that can be | 
| +// found in the LICENSE file. | 
| + | 
| +#include "chrome/browser/media/router/dial_media_sink_service.h" | 
| + | 
| +#include "chrome/browser/extensions/api/dial/device_description_fetcher.h" | 
| +#include "chrome/browser/extensions/api/dial/dial_api.h" | 
| +#include "chrome/browser/extensions/api/dial/dial_api_factory.h" | 
| +#include "chrome/browser/extensions/api/dial/dial_device_data.h" | 
| +#include "chrome/browser/media/router/media_sinks_observer.h" | 
| +#include "chrome/browser/media/router/mojo/media_router_mojo_impl.h" | 
| +#include "chrome/browser/profiles/profile.h" | 
| +#include "content/public/browser/browser_thread.h" | 
| + | 
| +using base::Time; | 
| +using base::TimeDelta; | 
| +using content::BrowserThread; | 
| + | 
| +namespace media_router { | 
| + | 
| +DialMediaSinkService::DialMediaSinkService( | 
| +    const OnSinksDiscoveredCallback& callback, | 
| +    content::BrowserContext* browser_context) | 
| +    : MediaSinkService(callback), | 
| +      dial_registry_(nullptr), | 
| +      browser_context_(browser_context) { | 
| +  DCHECK_CURRENTLY_ON(BrowserThread::UI); | 
| +  auto* profile = Profile::FromBrowserContext(browser_context_); | 
| +  dial_api_ = | 
| +      extensions::DialAPIFactory::GetInstance()->GetForBrowserContext(profile); | 
| +  request_context_ = profile->GetRequestContext(); | 
| + | 
| +  DCHECK(dial_api_); | 
| +  DCHECK(request_context_); | 
| +} | 
| + | 
| +DialMediaSinkService::~DialMediaSinkService() { | 
| +  content::BrowserThread::PostTask( | 
| +      content::BrowserThread::IO, FROM_HERE, | 
| +      base::Bind(&DialRegistry::UnregisterObserver, | 
| +                 base::Unretained(dial_registry_), this)); | 
| +} | 
| + | 
| +void DialMediaSinkService::Start() { | 
| +  DCHECK_CURRENTLY_ON(BrowserThread::IO); | 
| +  dial_registry()->RegisterObserver(this); | 
| +} | 
| + | 
| +void DialMediaSinkService::AddSinkQuery(MediaSinksObserver* observer) { | 
| +  NOTIMPLEMENTED(); | 
| +} | 
| + | 
| +void DialMediaSinkService::RemoveSinkQuery(MediaSinksObserver* observer) { | 
| +  NOTIMPLEMENTED(); | 
| +} | 
| + | 
| +DialMediaSinkService::DialRegistry* DialMediaSinkService::dial_registry() { | 
| +  DCHECK_CURRENTLY_ON(BrowserThread::IO); | 
| +  dial_registry_ = dial_api_->dial_registry(); | 
| +  return dial_registry_; | 
| +} | 
| + | 
| +DeviceDescriptionService* DialMediaSinkService::description_service() { | 
| +  DCHECK_CURRENTLY_ON(BrowserThread::IO); | 
| +  if (!description_service_.get()) { | 
| +    description_service_.reset(new DeviceDescriptionService(this)); | 
| +  } | 
| +  return description_service_.get(); | 
| +} | 
| + | 
| +void DialMediaSinkService::OnDialDeviceEvent( | 
| +    const DialRegistry::DeviceList& devices) { | 
| +  DCHECK_CURRENTLY_ON(BrowserThread::IO); | 
| +  DVLOG(2) << "DialMediaSinkService::OnDialDeviceEvent found " << devices.size() | 
| +           << " devices"; | 
| + | 
| +  std::set<std::string> device_labels; | 
| +  for (const auto& device : devices) | 
| +    device_labels.insert(device.label()); | 
| + | 
| +  // Abort previous resolution. Always follow the latest device list. | 
| +  for (const auto& pending_label : pending_device_labels_) { | 
| +    if (device_labels.find(pending_label) == device_labels.end()) | 
| +      description_service()->MayStopDeviceDescriptionFetching(pending_label); | 
| +  } | 
| + | 
| +  pending_device_labels_ = device_labels; | 
| +  dial_sinks_.clear(); | 
| + | 
| +  for (const auto& device : devices) { | 
| +    DialDeviceDescription description; | 
| +    if (description_service()->GetDeviceDescription(device, request_context_, | 
| +                                                    &description)) | 
| +      OnDeviceDescriptionAvailable(device.label(), description); | 
| +  } | 
| +} | 
| + | 
| +void DialMediaSinkService::OnDialError(DialRegistry::DialErrorCode type) { | 
| +  DCHECK_CURRENTLY_ON(BrowserThread::IO); | 
| +  DVLOG(2) << "OnDialError [DialErrorCode]: " << static_cast<int>(type); | 
| +} | 
| + | 
| +void DialMediaSinkService::OnDeviceDescriptionAvailable( | 
| +    const std::string& device_id, | 
| +    const DialDeviceDescription& description) { | 
| +  DCHECK_CURRENTLY_ON(BrowserThread::IO); | 
| +  dial_sinks_.insert(std::make_pair( | 
| +      description.unique_id, | 
| +      base::MakeUnique<MediaSink>(description.unique_id, | 
| +                                  description.friendly_name, MediaSink::CAST))); | 
| +  OnDeviceDescription(device_id); | 
| +} | 
| + | 
| +void DialMediaSinkService::OnDeviceDescriptionFetchError( | 
| +    const std::string& device_label, | 
| +    const std::string& error_message) { | 
| +  DCHECK_CURRENTLY_ON(BrowserThread::IO); | 
| +  DVLOG(2) << "OnDescriptionFetchesError [message]: " << error_message; | 
| +  OnDeviceDescription(device_label); | 
| +} | 
| + | 
| +void DialMediaSinkService::OnDeviceDescription( | 
| +    const std::string& device_label) { | 
| +  pending_device_labels_.erase(device_label); | 
| +  if (pending_device_labels_.empty()) | 
| +    FetchCompleted(); | 
| +} | 
| + | 
| +void DialMediaSinkService::FetchCompleted() { | 
| +  DCHECK_CURRENTLY_ON(BrowserThread::IO); | 
| +  DCHECK(!sink_discovery_callback_.is_null()); | 
| + | 
| +  std::vector<MediaSink> sinks; | 
| +  for (auto& it : dial_sinks_) | 
| +    sinks.push_back(*it.second); | 
| + | 
| +  sink_discovery_callback_.Run(sinks); | 
| +  dial_sinks_.clear(); | 
| +} | 
| + | 
| +}  // namespace media_router | 
|  |