| // 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/discovery/mdns/cast_media_sink_service.h" |
| |
| #include "base/bind.h" |
| #include "build/build_config.h" |
| #include "chrome/browser/browser_process.h" |
| #include "chrome/browser/media/router/discovery/discovery_network_monitor.h" |
| #include "chrome/browser/media/router/discovery/mdns/media_sink_util.h" |
| #include "chrome/browser/media/router/media_router_feature.h" |
| #include "components/cast_channel/cast_socket_service.h" |
| #include "components/media_router/common/media_sink.h" |
| #include "components/prefs/pref_service.h" |
| |
| namespace media_router { |
| |
| constexpr char kLoggerComponent[] = "CastMediaSinkService"; |
| |
| CastMediaSinkService::CastMediaSinkService() |
| : impl_(nullptr, base::OnTaskRunnerDeleter(nullptr)) {} |
| |
| CastMediaSinkService::~CastMediaSinkService() { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| if (dns_sd_registry_) { |
| dns_sd_registry_->UnregisterDnsSdListener(kCastServiceType); |
| dns_sd_registry_->RemoveObserver(this); |
| dns_sd_registry_ = nullptr; |
| } |
| local_state_change_registrar_.RemoveAll(); |
| } |
| |
| void CastMediaSinkService::Start( |
| const OnSinksDiscoveredCallback& sinks_discovered_cb, |
| MediaSinkServiceBase* dial_media_sink_service) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| DCHECK(!impl_); |
| |
| // |sinks_discovered_cb| should only be invoked on the current sequence. |
| // We wrap |sinks_discovered_cb| in a member function bound with WeakPtr to |
| // ensure it will only be invoked while |this| is still valid. |
| // TODO(imcheng): Simplify this by only using observers instead of callback. |
| // This would require us to move the timer logic from MediaSinkServiceBase up |
| // to DualMediaSinkService, but will allow us to remove MediaSinkServiceBase. |
| impl_ = |
| CreateImpl(base::BindRepeating( |
| &RunSinksDiscoveredCallbackOnSequence, |
| base::SequencedTaskRunnerHandle::Get(), |
| base::BindRepeating( |
| &CastMediaSinkService::RunSinksDiscoveredCallback, |
| weak_ptr_factory_.GetWeakPtr(), sinks_discovered_cb)), |
| dial_media_sink_service); |
| impl_->task_runner()->PostTask( |
| FROM_HERE, base::BindOnce(&CastMediaSinkServiceImpl::Start, |
| base::Unretained(impl_.get()))); |
| |
| #if !BUILDFLAG(IS_WIN) |
| StartMdnsDiscovery(); |
| #endif |
| } |
| |
| std::unique_ptr<CastMediaSinkServiceImpl, base::OnTaskRunnerDeleter> |
| CastMediaSinkService::CreateImpl( |
| const OnSinksDiscoveredCallback& sinks_discovered_cb, |
| MediaSinkServiceBase* dial_media_sink_service) { |
| cast_channel::CastSocketService* cast_socket_service = |
| cast_channel::CastSocketService::GetInstance(); |
| scoped_refptr<base::SequencedTaskRunner> task_runner = |
| cast_socket_service->task_runner(); |
| |
| local_state_change_registrar_.Init(g_browser_process->local_state()); |
| local_state_change_registrar_.Add( |
| prefs::kMediaRouterCastAllowAllIPs, |
| base::BindRepeating(&CastMediaSinkService::SetCastAllowAllIPs, |
| base::Unretained(this))); |
| return std::unique_ptr<CastMediaSinkServiceImpl, base::OnTaskRunnerDeleter>( |
| new CastMediaSinkServiceImpl( |
| sinks_discovered_cb, cast_socket_service, |
| DiscoveryNetworkMonitor::GetInstance(), dial_media_sink_service, |
| GetCastAllowAllIPsPref(g_browser_process->local_state())), |
| base::OnTaskRunnerDeleter(task_runner)); |
| } |
| |
| void CastMediaSinkService::SetCastAllowAllIPs() { |
| impl_->task_runner()->PostTask( |
| FROM_HERE, |
| base::BindOnce(&CastMediaSinkServiceImpl::SetCastAllowAllIPs, |
| base::Unretained(impl_.get()), |
| GetCastAllowAllIPsPref(g_browser_process->local_state()))); |
| } |
| |
| void CastMediaSinkService::StartMdnsDiscovery() { |
| // |dns_sd_registry_| is already set to a mock version in unit tests only. |
| // |impl_| must be initialized first because AddObserver might end up calling |
| // |OnDnsSdEvent| right away. |
| DCHECK(impl_); |
| if (!dns_sd_registry_) { |
| dns_sd_registry_ = DnsSdRegistry::GetInstance(); |
| dns_sd_registry_->AddObserver(this); |
| dns_sd_registry_->RegisterDnsSdListener(kCastServiceType); |
| if (logger_impl_) { |
| logger_impl_->LogInfo(mojom::LogCategory::kDiscovery, kLoggerComponent, |
| "mDNS discovery started.", "", "", ""); |
| } |
| } |
| } |
| |
| bool CastMediaSinkService::MdnsDiscoveryStarted() { |
| return dns_sd_registry_ != nullptr; |
| } |
| |
| void CastMediaSinkService::OnUserGesture() { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| if (dns_sd_registry_) |
| dns_sd_registry_->ResetAndDiscover(); |
| |
| impl_->task_runner()->PostTask( |
| FROM_HERE, base::BindOnce(&CastMediaSinkServiceImpl::OpenChannelsNow, |
| base::Unretained(impl_.get()), cast_sinks_)); |
| } |
| |
| void CastMediaSinkService::SetDnsSdRegistryForTest(DnsSdRegistry* registry) { |
| DCHECK(!dns_sd_registry_); |
| dns_sd_registry_ = registry; |
| dns_sd_registry_->AddObserver(this); |
| dns_sd_registry_->RegisterDnsSdListener(kCastServiceType); |
| } |
| |
| void CastMediaSinkService::OnDnsSdEvent( |
| const std::string& service_type, |
| const DnsSdRegistry::DnsSdServiceList& services) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| cast_sinks_.clear(); |
| for (const auto& service : services) { |
| // Create Cast sink from mDNS service description. |
| MediaSinkInternal cast_sink; |
| CreateCastMediaSinkResult result = CreateCastMediaSink(service, &cast_sink); |
| if (result != CreateCastMediaSinkResult::kOk) { |
| continue; |
| } |
| cast_sinks_.push_back(cast_sink); |
| } |
| |
| impl_->task_runner()->PostTask( |
| FROM_HERE, |
| base::BindOnce(&CastMediaSinkServiceImpl::OpenChannelsWithRandomizedDelay, |
| base::Unretained(impl_.get()), cast_sinks_, |
| CastMediaSinkServiceImpl::SinkSource::kMdns)); |
| } |
| |
| void CastMediaSinkService::RunSinksDiscoveredCallback( |
| const OnSinksDiscoveredCallback& sinks_discovered_cb, |
| std::vector<MediaSinkInternal> sinks) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| sinks_discovered_cb.Run(std::move(sinks)); |
| } |
| |
| void CastMediaSinkService::BindLogger(LoggerImpl* logger_impl) { |
| DCHECK(logger_impl); |
| logger_impl_ = logger_impl; |
| if (dns_sd_registry_) { |
| logger_impl->LogInfo(mojom::LogCategory::kDiscovery, kLoggerComponent, |
| "mDNS service has started.", "", "", ""); |
| } |
| |
| mojo::PendingRemote<mojom::Logger> pending_remote; |
| logger_impl_->Bind(pending_remote.InitWithNewPipeAndPassReceiver()); |
| impl_->task_runner()->PostTask( |
| FROM_HERE, |
| base::BindOnce(&CastMediaSinkServiceImpl::BindLogger, |
| base::Unretained(impl_.get()), std::move(pending_remote))); |
| } |
| |
| void CastMediaSinkService::RemoveLogger() { |
| logger_impl_ = nullptr; |
| } |
| |
| } // namespace media_router |