Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(45)

Side by Side Diff: chrome/browser/media/router/discovery/mdns/cast_media_sink_service.cc

Issue 2965843002: [Media Router] Support dual discovery (Closed)
Patch Set: resovle code review comments from Derek and Mark Created 3 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2017 The Chromium Authors. All rights reserved. 1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/media/router/discovery/mdns/cast_media_sink_service.h" 5 #include "chrome/browser/media/router/discovery/mdns/cast_media_sink_service.h"
6 6
7 #include "base/memory/ptr_util.h" 7 #include "base/memory/ptr_util.h"
8 #include "chrome/browser/browser_process.h" 8 #include "chrome/browser/browser_process.h"
9 #include "chrome/common/media_router/discovery/media_sink_internal.h" 9 #include "chrome/common/media_router/discovery/media_sink_internal.h"
10 #include "components/cast_channel/cast_socket_service.h" 10 #include "components/cast_channel/cast_socket_service.h"
(...skipping 10 matching lines...) Expand all
21 enum ErrorType { 21 enum ErrorType {
22 NONE, 22 NONE,
23 NOT_CAST_DEVICE, 23 NOT_CAST_DEVICE,
24 MISSING_ID, 24 MISSING_ID,
25 MISSING_FRIENDLY_NAME, 25 MISSING_FRIENDLY_NAME,
26 MISSING_OR_INVALID_IP_ADDRESS, 26 MISSING_OR_INVALID_IP_ADDRESS,
27 MISSING_OR_INVALID_PORT, 27 MISSING_OR_INVALID_PORT,
28 }; 28 };
29 29
30 ErrorType CreateCastMediaSink(const media_router::DnsSdService& service, 30 ErrorType CreateCastMediaSink(const media_router::DnsSdService& service,
31 int channel_id,
32 bool audio_only,
33 media_router::MediaSinkInternal* cast_sink) { 31 media_router::MediaSinkInternal* cast_sink) {
34 DCHECK(cast_sink); 32 DCHECK(cast_sink);
35 if (service.service_name.find( 33 if (service.service_name.find(
36 media_router::CastMediaSinkService::kCastServiceType) == 34 media_router::CastMediaSinkService::kCastServiceType) ==
37 std::string::npos) 35 std::string::npos)
38 return ErrorType::NOT_CAST_DEVICE; 36 return ErrorType::NOT_CAST_DEVICE;
39 37
40 net::IPAddress ip_address; 38 net::IPAddress ip_address;
41 if (!ip_address.AssignFromIPLiteral(service.ip_address)) 39 if (!ip_address.AssignFromIPLiteral(service.ip_address))
42 return ErrorType::MISSING_OR_INVALID_IP_ADDRESS; 40 return ErrorType::MISSING_OR_INVALID_IP_ADDRESS;
43 41
42 // TODO(zhaobin): Make DnsSdService's service_host_port take net::HostPortPair
43 // type instead of plain string.
44 net::HostPortPair host_port_pair =
45 net::HostPortPair::FromString(service.service_host_port);
46 int port = host_port_pair.port();
47
44 std::map<std::string, std::string> service_data; 48 std::map<std::string, std::string> service_data;
45 for (const auto& item : service.service_data) { 49 for (const auto& item : service.service_data) {
46 // |item| format should be "id=xxxxxx", etc. 50 // |item| format should be "id=xxxxxx", etc.
47 size_t split_idx = item.find('='); 51 size_t split_idx = item.find('=');
48 if (split_idx == std::string::npos) 52 if (split_idx == std::string::npos)
49 continue; 53 continue;
50 54
51 std::string key = item.substr(0, split_idx); 55 std::string key = item.substr(0, split_idx);
52 std::string val = 56 std::string val =
53 split_idx < item.length() ? item.substr(split_idx + 1) : ""; 57 split_idx < item.length() ? item.substr(split_idx + 1) : "";
54 service_data[key] = val; 58 service_data[key] = val;
55 } 59 }
56 60
57 // When use this "sink" within browser, please note it will have a different 61 // When use this "sink" within browser, please note it will have a different
58 // ID when it is sent to the extension, because it derives a different sink ID 62 // ID when it is sent to the extension, because it derives a different sink ID
59 // using the given sink ID. 63 // using the given sink ID.
60 std::string unique_id = service_data["id"]; 64 std::string unique_id = service_data["id"];
61 if (unique_id.empty()) 65 if (unique_id.empty())
62 return ErrorType::MISSING_ID; 66 return ErrorType::MISSING_ID;
63 std::string friendly_name = service_data["fn"]; 67 std::string friendly_name = service_data["fn"];
64 if (friendly_name.empty()) 68 if (friendly_name.empty())
65 return ErrorType::MISSING_FRIENDLY_NAME; 69 return ErrorType::MISSING_FRIENDLY_NAME;
66 media_router::MediaSink sink(unique_id, friendly_name, 70 media_router::MediaSink sink(unique_id, friendly_name,
67 media_router::MediaSink::IconType::CAST); 71 media_router::MediaSink::IconType::CAST);
68 72
69 media_router::CastSinkExtraData extra_data; 73 media_router::CastSinkExtraData extra_data;
70 extra_data.ip_address = ip_address; 74 extra_data.ip_address = ip_address;
71 extra_data.model_name = service_data["md"]; 75 extra_data.model_name = service_data["md"];
72 extra_data.capabilities = cast_channel::CastDeviceCapability::AUDIO_OUT; 76 extra_data.port = port;
73 if (!audio_only) 77 extra_data.discovered_by_dial = false;
74 extra_data.capabilities |= cast_channel::CastDeviceCapability::VIDEO_OUT;
75 extra_data.cast_channel_id = channel_id;
76 78
77 cast_sink->set_sink(sink); 79 cast_sink->set_sink(sink);
78 cast_sink->set_cast_data(extra_data); 80 cast_sink->set_cast_data(extra_data);
79 81
80 return ErrorType::NONE; 82 return ErrorType::NONE;
81 } 83 }
82 84
85 static media_router::MediaSinkInternal CreateCastSinkFromDialSink(
86 const media_router::MediaSinkInternal& dial_sink) {
87 std::string unique_id = dial_sink.sink().id();
88 std::string friendly_name = dial_sink.sink().name();
89 media_router::MediaSink sink(unique_id, friendly_name,
90 media_router::MediaSink::IconType::CAST);
91
92 media_router::CastSinkExtraData extra_data;
93 extra_data.ip_address = dial_sink.dial_data().ip_address;
94 extra_data.port = media_router::CastMediaSinkService::kCastControlPort;
95 extra_data.model_name = dial_sink.dial_data().model_name;
96 extra_data.discovered_by_dial = true;
97
98 return media_router::MediaSinkInternal(sink, extra_data);
99 }
100
83 } // namespace 101 } // namespace
84 102
85 namespace media_router { 103 namespace media_router {
86 104
87 // static 105 // static
88 const char CastMediaSinkService::kCastServiceType[] = "_googlecast._tcp.local"; 106 const char CastMediaSinkService::kCastServiceType[] = "_googlecast._tcp.local";
89 107
108 // static
109 const int CastMediaSinkService::kCastControlPort = 8009;
110
90 CastMediaSinkService::CastMediaSinkService( 111 CastMediaSinkService::CastMediaSinkService(
91 const OnSinksDiscoveredCallback& callback, 112 const OnSinksDiscoveredCallback& callback,
92 content::BrowserContext* browser_context) 113 content::BrowserContext* browser_context)
93 : MediaSinkServiceBase(callback) { 114 : MediaSinkServiceBase(callback) {
94 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); 115 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
95 cast_socket_service_ = cast_channel::CastSocketServiceFactory::GetInstance() 116 cast_socket_service_ = cast_channel::CastSocketServiceFactory::GetInstance()
96 ->GetForBrowserContext(browser_context); 117 ->GetForBrowserContext(browser_context);
97 DCHECK(cast_socket_service_); 118 DCHECK(cast_socket_service_);
98 } 119 }
99 120
100 CastMediaSinkService::CastMediaSinkService( 121 CastMediaSinkService::CastMediaSinkService(
101 const OnSinksDiscoveredCallback& callback, 122 const OnSinksDiscoveredCallback& callback,
102 cast_channel::CastSocketService* cast_socket_service) 123 cast_channel::CastSocketService* cast_socket_service)
103 : MediaSinkServiceBase(callback), 124 : MediaSinkServiceBase(callback),
104 cast_socket_service_(cast_socket_service) { 125 cast_socket_service_(cast_socket_service) {
105 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); 126 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
106 DCHECK(cast_socket_service_); 127 DCHECK(cast_socket_service_);
107 } 128 }
108 129
109 CastMediaSinkService::~CastMediaSinkService() {} 130 CastMediaSinkService::~CastMediaSinkService() {}
110 131
111 void CastMediaSinkService::Start() { 132 void CastMediaSinkService::Start() {
112 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); 133 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
113 if (dns_sd_registry_) 134 if (dns_sd_registry_)
114 return; 135 return;
115 136
116 dns_sd_registry_ = DnsSdRegistry::GetInstance(); 137 dns_sd_registry_ = DnsSdRegistry::GetInstance();
117 dns_sd_registry_->AddObserver(this); 138 dns_sd_registry_->AddObserver(this);
118 dns_sd_registry_->RegisterDnsSdListener(kCastServiceType); 139 dns_sd_registry_->RegisterDnsSdListener(kCastServiceType);
119 MediaSinkServiceBase::StartTimer(); 140 MediaSinkServiceBase::StartTimer();
120 } 141 }
121 142
122 void CastMediaSinkService::Stop() { 143 void CastMediaSinkService::Stop() {
123 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); 144 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
124 if (!dns_sd_registry_) 145 if (!dns_sd_registry_)
125 return; 146 return;
126 147
127 dns_sd_registry_->UnregisterDnsSdListener(kCastServiceType); 148 dns_sd_registry_->UnregisterDnsSdListener(kCastServiceType);
128 dns_sd_registry_->RemoveObserver(this); 149 dns_sd_registry_->RemoveObserver(this);
129 dns_sd_registry_ = nullptr; 150 dns_sd_registry_ = nullptr;
130 MediaSinkServiceBase::StopTimer(); 151 MediaSinkServiceBase::StopTimer();
131 } 152 }
132 153
133 void CastMediaSinkService::SetDnsSdRegistryForTest(DnsSdRegistry* registry) { 154 void CastMediaSinkService::SetDnsSdRegistryForTest(DnsSdRegistry* registry) {
134 DCHECK(!dns_sd_registry_); 155 DCHECK(!dns_sd_registry_);
135 dns_sd_registry_ = registry; 156 dns_sd_registry_ = registry;
136 dns_sd_registry_->AddObserver(this); 157 dns_sd_registry_->AddObserver(this);
137 dns_sd_registry_->RegisterDnsSdListener(kCastServiceType); 158 dns_sd_registry_->RegisterDnsSdListener(kCastServiceType);
138 MediaSinkServiceBase::StartTimer(); 159 MediaSinkServiceBase::StartTimer();
139 } 160 }
140 161
162 void CastMediaSinkService::OnFetchCompleted() {
163 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
164
165 auto task_runner = content::BrowserThread::GetTaskRunnerForThread(
166 content::BrowserThread::IO);
167 base::PostTaskAndReplyWithResult(
168 task_runner.get(), FROM_HERE,
169 base::BindOnce(&CastMediaSinkService::GetCastSinksOnIOThread, this),
170 base::BindOnce(&CastMediaSinkService::OnFetchCompletedOnUIThread, this));
171 }
172
173 std::set<MediaSinkInternal> CastMediaSinkService::GetCastSinksOnIOThread() {
174 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
175
176 std::set<MediaSinkInternal> sinks;
177 // Copy cast sink from mDNS service to |current_sinks_|.
178 for (const auto& sink_it : current_sinks_by_mdns_) {
179 DVLOG(2) << "Discovered by mdns [name]: " << sink_it.second.sink().name();
180 sinks.insert(sink_it.second);
181 }
182
183 // Copy cast sink from DIAL discovery to |current_sinks_|.
184 for (const auto& sink_it : current_sinks_by_dial_) {
185 DVLOG(2) << "Discovered by dial [name]: " << sink_it.second.sink().name();
186 if (!base::ContainsKey(current_sinks_by_mdns_, sink_it.first))
187 sinks.insert(sink_it.second);
188 }
189 return sinks;
190 }
191
192 void CastMediaSinkService::OnFetchCompletedOnUIThread(
193 std::set<MediaSinkInternal> cast_sinks) {
194 MediaSinkServiceBase::current_sinks_ = cast_sinks;
195 MediaSinkServiceBase::OnFetchCompleted();
196 }
197
141 void CastMediaSinkService::OnDnsSdEvent( 198 void CastMediaSinkService::OnDnsSdEvent(
142 const std::string& service_type, 199 const std::string& service_type,
143 const DnsSdRegistry::DnsSdServiceList& services) { 200 const DnsSdRegistry::DnsSdServiceList& services) {
144 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); 201 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
145 DVLOG(2) << "CastMediaSinkService::OnDnsSdEvent found " << services.size() 202 DVLOG(2) << "CastMediaSinkService::OnDnsSdEvent found " << services.size()
146 << " services"; 203 << " services";
147 204
148 current_sinks_.clear(); 205 std::vector<MediaSinkInternal> cast_sinks;
149 current_services_ = services;
150
151 for (const auto& service : services) { 206 for (const auto& service : services) {
152 net::IPAddress ip_address; 207 // Create Cast sink from mDNS service description.
153 if (!ip_address.AssignFromIPLiteral(service.ip_address)) { 208 MediaSinkInternal cast_sink;
154 DVLOG(2) << "Invalid ip_addresss: " << service.ip_address; 209 ErrorType error = CreateCastMediaSink(service, &cast_sink);
210 if (error != ErrorType::NONE) {
211 DVLOG(2) << "Fail to create Cast device [error]: " << error;
155 continue; 212 continue;
156 } 213 }
157 net::HostPortPair host_port_pair =
158 net::HostPortPair::FromString(service.service_host_port);
159 214
160 content::BrowserThread::PostTask( 215 cast_sinks.push_back(std::move(cast_sink));
161 content::BrowserThread::IO, FROM_HERE,
162 base::Bind(&CastMediaSinkService::OpenChannelOnIOThread, this, service,
163 net::IPEndPoint(ip_address, host_port_pair.port())));
164 } 216 }
165 217
218 content::BrowserThread::PostTask(
219 content::BrowserThread::IO, FROM_HERE,
220 base::Bind(&CastMediaSinkService::OpenChannelsOnIOThread, this,
221 std::move(cast_sinks)));
222
166 MediaSinkServiceBase::RestartTimer(); 223 MediaSinkServiceBase::RestartTimer();
167 } 224 }
168 225
226 void CastMediaSinkService::OpenChannelsOnIOThread(
227 std::vector<MediaSinkInternal> cast_sinks) {
228 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
229
230 current_sinks_by_mdns_.clear();
231 current_service_ip_endpoints_.clear();
232
233 for (const auto& cast_sink : cast_sinks) {
234 net::IPEndPoint ip_endpoint(cast_sink.cast_data().ip_address,
235 cast_sink.cast_data().port);
236 current_service_ip_endpoints_.insert(ip_endpoint);
237
238 OpenChannelOnIOThread(ip_endpoint, cast_sink);
239 }
240 }
241
242 void CastMediaSinkService::OnDialSinkAdded(const MediaSinkInternal& sink) {
243 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
244
245 auto ip_address = sink.dial_data().ip_address;
246 net::IPEndPoint ip_endpoint(ip_address, kCastControlPort);
247
248 if (base::ContainsKey(current_service_ip_endpoints_, ip_endpoint)) {
249 DVLOG(2) << "Sink discovered by mDNS, skip adding [name]: "
250 << sink.sink().name();
251 return;
252 }
253
254 OpenChannelOnIOThread(ip_endpoint, CreateCastSinkFromDialSink(sink));
255 }
256
257 void CastMediaSinkService::OnDialSinksRemoved() {
258 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
259
260 current_sinks_by_dial_.clear();
261 }
262
169 void CastMediaSinkService::OpenChannelOnIOThread( 263 void CastMediaSinkService::OpenChannelOnIOThread(
170 const DnsSdService& service, 264 const net::IPEndPoint& ip_endpoint,
171 const net::IPEndPoint& ip_endpoint) { 265 MediaSinkInternal cast_sink) {
172 auto* observer = cast_socket_service_->GetObserver(kObserverId); 266 auto* observer = cast_socket_service_->GetObserver(kObserverId);
173 if (!observer) { 267 if (!observer) {
174 observer = new CastSocketObserver(); 268 observer = new CastSocketObserver();
175 cast_socket_service_->AddObserver(kObserverId, base::WrapUnique(observer)); 269 cast_socket_service_->AddObserver(kObserverId, base::WrapUnique(observer));
176 } 270 }
177 271
272 // TODO(zhaobin): Use base::BindOnce instead of base::Bind here.
178 cast_socket_service_->OpenSocket( 273 cast_socket_service_->OpenSocket(
179 ip_endpoint, g_browser_process->net_log(), 274 ip_endpoint, g_browser_process->net_log(),
180 base::Bind(&CastMediaSinkService::OnChannelOpenedOnIOThread, this, 275 base::Bind(&CastMediaSinkService::OnChannelOpenedOnIOThread, this,
181 service), 276 std::move(cast_sink)),
182 observer); 277 observer);
183 } 278 }
184 279
185 void CastMediaSinkService::OnChannelOpenedOnIOThread( 280 void CastMediaSinkService::OnChannelOpenedOnIOThread(
186 const DnsSdService& service, 281 MediaSinkInternal cast_sink,
187 int channel_id, 282 int channel_id,
188 cast_channel::ChannelError channel_error) { 283 cast_channel::ChannelError channel_error) {
189 if (channel_error != cast_channel::ChannelError::NONE) { 284 if (channel_error != cast_channel::ChannelError::NONE) {
190 DVLOG(2) << "Fail to open channel " << service.ip_address << ": " 285 DVLOG(2) << "Fail to open channel "
191 << service.service_host_port 286 << cast_sink.cast_data().ip_address.ToString()
287 << " [name]: " << cast_sink.sink().name()
192 << " [ChannelError]: " << (int)channel_error; 288 << " [ChannelError]: " << (int)channel_error;
193 return; 289 return;
194 } 290 }
195 291
196 auto* socket = cast_socket_service_->GetSocket(channel_id); 292 auto* socket = cast_socket_service_->GetSocket(channel_id);
197 if (!socket) { 293 if (!socket) {
198 DVLOG(2) << "Fail to find socket with [channel_id]: " << channel_id; 294 DVLOG(2) << "Fail to find socket with [channel_id]: " << channel_id;
199 return; 295 return;
200 } 296 }
201 297
298 // Skip adding if IP address not found in current round of mDNS discovery.
299 net::IPEndPoint ip_endpoint(cast_sink.cast_data().ip_address,
300 cast_sink.cast_data().port);
301 if (!cast_sink.cast_data().discovered_by_dial) {
302 if (current_service_ip_endpoints_.find(ip_endpoint) ==
303 current_service_ip_endpoints_.end()) {
304 DVLOG(2) << "Service data not found in current service data list..."
305 << ip_endpoint.ToString();
306 return;
307 }
308 }
309
310 media_router::CastSinkExtraData extra_data = cast_sink.cast_data();
311 extra_data.capabilities = cast_channel::CastDeviceCapability::AUDIO_OUT;
312 if (!socket->audio_only())
313 extra_data.capabilities |= cast_channel::CastDeviceCapability::VIDEO_OUT;
314 extra_data.cast_channel_id = channel_id;
315
316 MediaSinkInternal updated_sink(cast_sink.sink(), extra_data);
317 DVLOG(2) << "Ading sink to current_sinks_ [name]: "
318 << updated_sink.sink().name();
319
320 // Add or update existing cast sink.
321 if (updated_sink.cast_data().discovered_by_dial) {
322 current_sinks_by_dial_[ip_endpoint] = updated_sink;
323 } else {
324 current_sinks_by_mdns_[ip_endpoint] = updated_sink;
325 }
326
202 content::BrowserThread::PostTask( 327 content::BrowserThread::PostTask(
203 content::BrowserThread::UI, FROM_HERE, 328 content::BrowserThread::UI, FROM_HERE,
204 base::Bind(&CastMediaSinkService::OnChannelOpenedOnUIThread, this, 329 base::Bind(&CastMediaSinkService::RestartTimer, this));
205 service, channel_id, socket->audio_only()));
206 }
207
208 void CastMediaSinkService::OnChannelOpenedOnUIThread(
209 const DnsSdService& service,
210 int channel_id,
211 bool audio_only) {
212 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
213 MediaSinkInternal sink;
214 ErrorType error = CreateCastMediaSink(service, channel_id, audio_only, &sink);
215 if (error != ErrorType::NONE) {
216 DVLOG(2) << "Fail to create Cast device [error]: " << error;
217 return;
218 }
219
220 if (!base::ContainsValue(current_services_, service)) {
221 DVLOG(2) << "Service data not found in current service data list...";
222 return;
223 }
224
225 DVLOG(2) << "Ading sink to current_sinks_ [id]: " << sink.sink().id();
226 current_sinks_.insert(sink);
227 MediaSinkServiceBase::RestartTimer();
228 } 330 }
229 331
230 CastMediaSinkService::CastSocketObserver::CastSocketObserver() {} 332 CastMediaSinkService::CastSocketObserver::CastSocketObserver() {}
231 CastMediaSinkService::CastSocketObserver::~CastSocketObserver() {} 333 CastMediaSinkService::CastSocketObserver::~CastSocketObserver() {}
232 334
233 void CastMediaSinkService::CastSocketObserver::OnError( 335 void CastMediaSinkService::CastSocketObserver::OnError(
234 const cast_channel::CastSocket& socket, 336 const cast_channel::CastSocket& socket,
235 cast_channel::ChannelError error_state) { 337 cast_channel::ChannelError error_state) {
236 DVLOG(1) << "OnError [ip_endpoint]: " << socket.ip_endpoint().ToString() 338 DVLOG(1) << "OnError [ip_endpoint]: " << socket.ip_endpoint().ToString()
237 << " [error_state]: " 339 << " [error_state]: "
238 << cast_channel::ChannelErrorToString(error_state); 340 << cast_channel::ChannelErrorToString(error_state);
239 } 341 }
240 342
241 void CastMediaSinkService::CastSocketObserver::OnMessage( 343 void CastMediaSinkService::CastSocketObserver::OnMessage(
242 const cast_channel::CastSocket& socket, 344 const cast_channel::CastSocket& socket,
243 const cast_channel::CastMessage& message) {} 345 const cast_channel::CastMessage& message) {}
244 346
245 } // namespace media_router 347 } // namespace media_router
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698