Index: chrome/browser/media/router/discovery/mdns/cast_media_sink_service.cc |
diff --git a/chrome/browser/media/router/discovery/mdns/cast_media_sink_service.cc b/chrome/browser/media/router/discovery/mdns/cast_media_sink_service.cc |
index 1ad648bc2b645d98e5b9983a68b5b54c95ebff3f..6e349adbdeb9430d23142fc4839c708871e8ff1e 100644 |
--- a/chrome/browser/media/router/discovery/mdns/cast_media_sink_service.cc |
+++ b/chrome/browser/media/router/discovery/mdns/cast_media_sink_service.cc |
@@ -28,8 +28,6 @@ enum ErrorType { |
}; |
ErrorType CreateCastMediaSink(const media_router::DnsSdService& service, |
- int channel_id, |
- bool audio_only, |
media_router::MediaSinkInternal* cast_sink) { |
DCHECK(cast_sink); |
if (service.service_name.find( |
@@ -41,6 +39,12 @@ ErrorType CreateCastMediaSink(const media_router::DnsSdService& service, |
if (!ip_address.AssignFromIPLiteral(service.ip_address)) |
return ErrorType::MISSING_OR_INVALID_IP_ADDRESS; |
+ // TODO(zhaobin): Make DnsSdService's service_host_port take net::HostPortPair |
+ // type instead of plain string. |
+ net::HostPortPair host_port_pair = |
+ net::HostPortPair::FromString(service.service_host_port); |
+ int port = host_port_pair.port(); |
+ |
std::map<std::string, std::string> service_data; |
for (const auto& item : service.service_data) { |
// |item| format should be "id=xxxxxx", etc. |
@@ -69,10 +73,8 @@ ErrorType CreateCastMediaSink(const media_router::DnsSdService& service, |
media_router::CastSinkExtraData extra_data; |
extra_data.ip_address = ip_address; |
extra_data.model_name = service_data["md"]; |
- extra_data.capabilities = cast_channel::CastDeviceCapability::AUDIO_OUT; |
- if (!audio_only) |
- extra_data.capabilities |= cast_channel::CastDeviceCapability::VIDEO_OUT; |
- extra_data.cast_channel_id = channel_id; |
+ extra_data.port = port; |
+ extra_data.discovered_by_dial = false; |
cast_sink->set_sink(sink); |
cast_sink->set_cast_data(extra_data); |
@@ -80,6 +82,22 @@ ErrorType CreateCastMediaSink(const media_router::DnsSdService& service, |
return ErrorType::NONE; |
} |
+static media_router::MediaSinkInternal CreateCastSinkFromDialSink( |
+ const media_router::MediaSinkInternal& dial_sink) { |
+ std::string unique_id = dial_sink.sink().id(); |
+ std::string friendly_name = dial_sink.sink().name(); |
+ media_router::MediaSink sink(unique_id, friendly_name, |
+ media_router::MediaSink::IconType::CAST); |
+ |
+ media_router::CastSinkExtraData extra_data; |
+ extra_data.ip_address = dial_sink.dial_data().ip_address; |
+ extra_data.port = media_router::CastMediaSinkService::kCastControlPort; |
+ extra_data.model_name = dial_sink.dial_data().model_name; |
+ extra_data.discovered_by_dial = true; |
+ |
+ return media_router::MediaSinkInternal(sink, extra_data); |
+} |
+ |
} // namespace |
namespace media_router { |
@@ -87,11 +105,14 @@ namespace media_router { |
// static |
const char CastMediaSinkService::kCastServiceType[] = "_googlecast._tcp.local"; |
+// static |
+const int CastMediaSinkService::kCastControlPort = 8009; |
+ |
CastMediaSinkService::CastMediaSinkService( |
const OnSinksDiscoveredCallback& callback, |
content::BrowserContext* browser_context) |
: MediaSinkServiceBase(callback) { |
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); |
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
cast_socket_service_ = cast_channel::CastSocketServiceFactory::GetInstance() |
->GetForBrowserContext(browser_context); |
DCHECK(cast_socket_service_); |
@@ -102,14 +123,14 @@ CastMediaSinkService::CastMediaSinkService( |
cast_channel::CastSocketService* cast_socket_service) |
: MediaSinkServiceBase(callback), |
cast_socket_service_(cast_socket_service) { |
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); |
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
DCHECK(cast_socket_service_); |
} |
CastMediaSinkService::~CastMediaSinkService() {} |
void CastMediaSinkService::Start() { |
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); |
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
if (dns_sd_registry_) |
return; |
@@ -120,7 +141,7 @@ void CastMediaSinkService::Start() { |
} |
void CastMediaSinkService::Stop() { |
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); |
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
if (!dns_sd_registry_) |
return; |
@@ -138,57 +159,132 @@ void CastMediaSinkService::SetDnsSdRegistryForTest(DnsSdRegistry* registry) { |
MediaSinkServiceBase::StartTimer(); |
} |
+void CastMediaSinkService::OnFetchCompleted() { |
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
+ |
+ auto task_runner = content::BrowserThread::GetTaskRunnerForThread( |
+ content::BrowserThread::IO); |
+ base::PostTaskAndReplyWithResult( |
+ task_runner.get(), FROM_HERE, |
+ base::BindOnce(&CastMediaSinkService::GetCastSinksOnIOThread, this), |
+ base::BindOnce(&CastMediaSinkService::OnFetchCompletedOnUIThread, this)); |
+} |
+ |
+std::set<MediaSinkInternal> CastMediaSinkService::GetCastSinksOnIOThread() { |
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
+ |
+ std::set<MediaSinkInternal> sinks; |
+ // Copy cast sink from mDNS service to |current_sinks_|. |
+ for (const auto& sink_it : current_sinks_by_mdns_) { |
+ DVLOG(2) << "Discovered by mdns [name]: " << sink_it.second.sink().name(); |
+ sinks.insert(sink_it.second); |
+ } |
+ |
+ // Copy cast sink from DIAL discovery to |current_sinks_|. |
+ for (const auto& sink_it : current_sinks_by_dial_) { |
+ DVLOG(2) << "Discovered by dial [name]: " << sink_it.second.sink().name(); |
+ if (!base::ContainsKey(current_sinks_by_mdns_, sink_it.first)) |
+ sinks.insert(sink_it.second); |
+ } |
+ return sinks; |
+} |
+ |
+void CastMediaSinkService::OnFetchCompletedOnUIThread( |
+ std::set<MediaSinkInternal> cast_sinks) { |
+ MediaSinkServiceBase::current_sinks_ = cast_sinks; |
+ MediaSinkServiceBase::OnFetchCompleted(); |
+} |
+ |
void CastMediaSinkService::OnDnsSdEvent( |
const std::string& service_type, |
const DnsSdRegistry::DnsSdServiceList& services) { |
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); |
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
DVLOG(2) << "CastMediaSinkService::OnDnsSdEvent found " << services.size() |
<< " services"; |
- current_sinks_.clear(); |
- current_services_ = services; |
- |
+ std::vector<MediaSinkInternal> cast_sinks; |
for (const auto& service : services) { |
- net::IPAddress ip_address; |
- if (!ip_address.AssignFromIPLiteral(service.ip_address)) { |
- DVLOG(2) << "Invalid ip_addresss: " << service.ip_address; |
+ // Create Cast sink from mDNS service description. |
+ MediaSinkInternal cast_sink; |
+ ErrorType error = CreateCastMediaSink(service, &cast_sink); |
+ if (error != ErrorType::NONE) { |
+ DVLOG(2) << "Fail to create Cast device [error]: " << error; |
continue; |
} |
- net::HostPortPair host_port_pair = |
- net::HostPortPair::FromString(service.service_host_port); |
- content::BrowserThread::PostTask( |
- content::BrowserThread::IO, FROM_HERE, |
- base::Bind(&CastMediaSinkService::OpenChannelOnIOThread, this, service, |
- net::IPEndPoint(ip_address, host_port_pair.port()))); |
+ cast_sinks.push_back(std::move(cast_sink)); |
} |
+ content::BrowserThread::PostTask( |
+ content::BrowserThread::IO, FROM_HERE, |
+ base::Bind(&CastMediaSinkService::OpenChannelsOnIOThread, this, |
+ std::move(cast_sinks))); |
+ |
MediaSinkServiceBase::RestartTimer(); |
} |
+void CastMediaSinkService::OpenChannelsOnIOThread( |
+ std::vector<MediaSinkInternal> cast_sinks) { |
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
+ |
+ current_sinks_by_mdns_.clear(); |
+ current_service_ip_endpoints_.clear(); |
+ |
+ for (const auto& cast_sink : cast_sinks) { |
+ net::IPEndPoint ip_endpoint(cast_sink.cast_data().ip_address, |
+ cast_sink.cast_data().port); |
+ current_service_ip_endpoints_.insert(ip_endpoint); |
+ |
+ OpenChannelOnIOThread(ip_endpoint, cast_sink); |
+ } |
+} |
+ |
+void CastMediaSinkService::OnDialSinkAdded(const MediaSinkInternal& sink) { |
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
+ |
+ auto ip_address = sink.dial_data().ip_address; |
+ net::IPEndPoint ip_endpoint(ip_address, kCastControlPort); |
+ |
+ if (base::ContainsKey(current_service_ip_endpoints_, ip_endpoint)) { |
+ DVLOG(2) << "Sink discovered by mDNS, skip adding [name]: " |
+ << sink.sink().name(); |
+ return; |
+ } |
+ |
+ OpenChannelOnIOThread(ip_endpoint, CreateCastSinkFromDialSink(sink)); |
+} |
+ |
+void CastMediaSinkService::OnDialSinksRemoved() { |
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
+ |
+ current_sinks_by_dial_.clear(); |
+} |
+ |
void CastMediaSinkService::OpenChannelOnIOThread( |
- const DnsSdService& service, |
- const net::IPEndPoint& ip_endpoint) { |
+ const net::IPEndPoint& ip_endpoint, |
+ MediaSinkInternal cast_sink) { |
auto* observer = cast_socket_service_->GetObserver(kObserverId); |
if (!observer) { |
observer = new CastSocketObserver(); |
cast_socket_service_->AddObserver(kObserverId, base::WrapUnique(observer)); |
} |
+ // TODO(zhaobin): Use base::BindOnce instead of base::Bind here. |
cast_socket_service_->OpenSocket( |
ip_endpoint, g_browser_process->net_log(), |
base::Bind(&CastMediaSinkService::OnChannelOpenedOnIOThread, this, |
- service), |
+ std::move(cast_sink)), |
observer); |
} |
void CastMediaSinkService::OnChannelOpenedOnIOThread( |
- const DnsSdService& service, |
+ MediaSinkInternal cast_sink, |
int channel_id, |
cast_channel::ChannelError channel_error) { |
if (channel_error != cast_channel::ChannelError::NONE) { |
- DVLOG(2) << "Fail to open channel " << service.ip_address << ": " |
- << service.service_host_port |
+ DVLOG(2) << "Fail to open channel " |
+ << cast_sink.cast_data().ip_address.ToString() |
+ << " [name]: " << cast_sink.sink().name() |
<< " [ChannelError]: " << (int)channel_error; |
return; |
} |
@@ -199,32 +295,38 @@ void CastMediaSinkService::OnChannelOpenedOnIOThread( |
return; |
} |
- content::BrowserThread::PostTask( |
- content::BrowserThread::UI, FROM_HERE, |
- base::Bind(&CastMediaSinkService::OnChannelOpenedOnUIThread, this, |
- service, channel_id, socket->audio_only())); |
-} |
- |
-void CastMediaSinkService::OnChannelOpenedOnUIThread( |
- const DnsSdService& service, |
- int channel_id, |
- bool audio_only) { |
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); |
- MediaSinkInternal sink; |
- ErrorType error = CreateCastMediaSink(service, channel_id, audio_only, &sink); |
- if (error != ErrorType::NONE) { |
- DVLOG(2) << "Fail to create Cast device [error]: " << error; |
- return; |
+ // Skip adding if IP address not found in current round of mDNS discovery. |
+ net::IPEndPoint ip_endpoint(cast_sink.cast_data().ip_address, |
+ cast_sink.cast_data().port); |
+ if (!cast_sink.cast_data().discovered_by_dial) { |
+ if (current_service_ip_endpoints_.find(ip_endpoint) == |
+ current_service_ip_endpoints_.end()) { |
+ DVLOG(2) << "Service data not found in current service data list..." |
+ << ip_endpoint.ToString(); |
+ return; |
+ } |
} |
- if (!base::ContainsValue(current_services_, service)) { |
- DVLOG(2) << "Service data not found in current service data list..."; |
- return; |
+ media_router::CastSinkExtraData extra_data = cast_sink.cast_data(); |
+ extra_data.capabilities = cast_channel::CastDeviceCapability::AUDIO_OUT; |
+ if (!socket->audio_only()) |
+ extra_data.capabilities |= cast_channel::CastDeviceCapability::VIDEO_OUT; |
+ extra_data.cast_channel_id = channel_id; |
+ |
+ MediaSinkInternal updated_sink(cast_sink.sink(), extra_data); |
+ DVLOG(2) << "Ading sink to current_sinks_ [name]: " |
+ << updated_sink.sink().name(); |
+ |
+ // Add or update existing cast sink. |
+ if (updated_sink.cast_data().discovered_by_dial) { |
+ current_sinks_by_dial_[ip_endpoint] = updated_sink; |
+ } else { |
+ current_sinks_by_mdns_[ip_endpoint] = updated_sink; |
} |
- DVLOG(2) << "Ading sink to current_sinks_ [id]: " << sink.sink().id(); |
- current_sinks_.insert(sink); |
- MediaSinkServiceBase::RestartTimer(); |
+ content::BrowserThread::PostTask( |
+ content::BrowserThread::UI, FROM_HERE, |
+ base::Bind(&CastMediaSinkService::RestartTimer, this)); |
} |
CastMediaSinkService::CastSocketObserver::CastSocketObserver() {} |