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

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

Issue 2927833002: [Media Router] Add CastMediaSinkService (Closed)
Patch Set: rebase Created 3 years, 5 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
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "chrome/browser/media/router/discovery/mdns/cast_media_sink_service.h"
6
7 #include "base/memory/ptr_util.h"
8 #include "chrome/browser/browser_process.h"
9 #include "chrome/common/media_router/discovery/media_sink_internal.h"
10 #include "components/cast_channel/cast_socket_service.h"
11 #include "components/cast_channel/cast_socket_service_factory.h"
12 #include "components/net_log/chrome_net_log.h"
13 #include "content/public/common/content_client.h"
14 #include "net/base/host_port_pair.h"
15 #include "net/base/ip_address.h"
16
17 namespace {
18 // mDNS service types.
19 const char kCastServiceType[] = "_googlecast._tcp.local";
mark a. foltz 2017/06/28 22:43:13 constexpr char here and below
zhaobin 2017/07/05 18:01:36 Done.
20
21 const char kObserverId[] = "browser_observer_id";
22
23 enum ErrorType {
24 NONE,
25 NOT_CAST_DEVICE,
26 MISSING_ID,
27 MISSING_FRIENDLY_NAME,
28 MISSING_OR_INVALID_IP_ADDRESS,
29 MISSING_OR_INVALID_PORT,
30 };
31
32 ErrorType CreateCastMediaSink(const media_router::DnsSdService& service,
33 int channel_id,
34 bool audio_only,
35 media_router::MediaSinkInternal* cast_sink) {
36 DCHECK(cast_sink);
37 if (service.service_name.find(kCastServiceType) == std::string::npos)
38 return ErrorType::NOT_CAST_DEVICE;
39
40 net::IPAddress ip_address;
41 if (!ip_address.AssignFromIPLiteral(service.ip_address))
42 return ErrorType::MISSING_OR_INVALID_IP_ADDRESS;
43
44 std::map<std::string, std::string> service_data;
45 for (const auto& item : service.service_data) {
46 // |item| format should be "id=xxxxxx", etc.
47 size_t split_idx = item.find('=');
48 if (split_idx == std::string::npos)
49 continue;
50
51 std::string key = item.substr(0, split_idx);
52 std::string val = item.substr(split_idx + 1);
mark a. foltz 2017/06/28 07:44:52 For mDNS TXT records, the value can be optional, b
zhaobin 2017/07/05 18:01:36 Done.
53 service_data[key] = val;
54 }
55
56 // When use this "sink" within browser, please note it will have a different
57 // ID when it is sent to the extension, because it derives a different sink ID
58 // using the given sink ID.
59 std::string unique_id = service_data["id"];
60 if (unique_id.empty())
61 return ErrorType::MISSING_ID;
62 std::string friendly_name = service_data["fn"];
63 if (friendly_name.empty())
64 return ErrorType::MISSING_FRIENDLY_NAME;
65 media_router::MediaSink sink(unique_id, friendly_name,
66 media_router::MediaSink::IconType::CAST);
67
68 media_router::CastSinkExtraData extra_data;
69 extra_data.ip_address = ip_address;
70 extra_data.model_name = service_data["md"];
71 extra_data.capabilities = cast_channel::CastDeviceCapability::AUDIO_OUT;
72 if (!audio_only)
73 extra_data.capabilities |= cast_channel::CastDeviceCapability::VIDEO_OUT;
74 extra_data.cast_channel_id = channel_id;
75
76 cast_sink->set_sink(sink);
77 cast_sink->set_cast_data(extra_data);
78
79 return ErrorType::NONE;
80 }
81
82 } // namespace
83
84 namespace media_router {
85
86 CastMediaSinkService::CastMediaSinkService(
87 const OnSinksDiscoveredCallback& callback,
88 content::BrowserContext* browser_context)
89 : MediaSinkServiceBase(callback) {
90 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
91 cast_socket_service_ = cast_channel::CastSocketServiceFactory::GetInstance()
92 ->GetForBrowserContext(browser_context);
93 DCHECK(cast_socket_service_);
94 }
95
96 CastMediaSinkService::CastMediaSinkService(
97 const OnSinksDiscoveredCallback& callback,
98 cast_channel::CastSocketService* cast_socket_service)
99 : MediaSinkServiceBase(callback),
100 cast_socket_service_(cast_socket_service) {
101 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
102 DCHECK(cast_socket_service_);
103 }
104
105 CastMediaSinkService::~CastMediaSinkService() {}
106
107 void CastMediaSinkService::Start() {
108 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
109 if (dns_sd_registry_)
110 return;
111
112 dns_sd_registry_ = test_dns_sd_registry_ ? test_dns_sd_registry_
113 : DnsSdRegistry::GetInstance();
114 dns_sd_registry_->AddObserver(this);
115 dns_sd_registry_->RegisterDnsSdListener(kCastServiceType);
116 MediaSinkServiceBase::StartTimer();
117 }
118
119 void CastMediaSinkService::Stop() {
120 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
121 if (!dns_sd_registry_)
122 return;
123
124 dns_sd_registry_->UnregisterDnsSdListener(kCastServiceType);
125 dns_sd_registry_->RemoveObserver(this);
126 dns_sd_registry_ = nullptr;
127 MediaSinkServiceBase::StopTimer();
128 }
129
130 void CastMediaSinkService::SetDnsSdRegistryForTest(DnsSdRegistry* registry) {
131 DCHECK(!test_dns_sd_registry_);
132 test_dns_sd_registry_ = registry;
133 }
134
135 void CastMediaSinkService::OnDnsSdEvent(
136 const std::string& service_type,
137 const DnsSdRegistry::DnsSdServiceList& services) {
138 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
139 DVLOG(2) << "CastMediaSinkService::OnDnsSdEvent found " << services.size()
140 << " services";
141
142 current_sinks_.clear();
143 current_services_ = services;
imcheng 2017/06/29 23:15:44 Does the timer fire if there used to be devices, b
zhaobin 2017/07/05 18:01:36 No, timer is not fired. Added a RestartTimer() at
imcheng 2017/07/07 00:11:48 Ok. Does we still need to call RestartTimer() in O
144
145 for (const auto& service : services) {
146 net::IPAddress ip_address;
147 if (!ip_address.AssignFromIPLiteral(service.ip_address)) {
148 DVLOG(2) << "Invalid ip_addresss: " << service.ip_address;
149 continue;
150 }
151 net::HostPortPair host_port_pair =
152 net::HostPortPair::FromString(service.service_host_port);
153
154 content::BrowserThread::PostTask(
155 content::BrowserThread::IO, FROM_HERE,
156 base::Bind(&CastMediaSinkService::OpenChannelOnIOThread, this, service,
157 net::IPEndPoint(ip_address, host_port_pair.port())));
158 }
159 }
160
161 void CastMediaSinkService::OpenChannelOnIOThread(
162 const DnsSdService& service,
163 const net::IPEndPoint& ip_endpoint) {
164 auto* observer = cast_socket_service_->GetObserver(kObserverId);
165 if (!observer) {
166 observer = new CastSocketObserver();
167 cast_socket_service_->AddObserver(kObserverId, base::WrapUnique(observer));
168 }
169
170 cast_socket_service_->OpenSocket(
mark a. foltz 2017/06/28 22:43:13 IIRC the CastSocketService won't add the same obse
zhaobin 2017/07/05 18:01:36 Yes, for socket in 'connecting' state, it wont reg
171 ip_endpoint, g_browser_process->net_log(),
172 base::Bind(&CastMediaSinkService::OnChannelOpenedOnIOThread, this,
173 service),
174 observer);
175 }
176
177 void CastMediaSinkService::OnChannelOpenedOnIOThread(
178 const DnsSdService& service,
179 int channel_id,
180 cast_channel::ChannelError channel_error) {
181 if (channel_error != cast_channel::ChannelError::NONE) {
182 DVLOG(2) << "Fail to open channel " << service.ip_address << ": "
183 << service.service_host_port
184 << " [ChannelError]: " << (int)channel_error;
185 return;
186 }
187
188 auto* socket = cast_socket_service_->GetSocket(channel_id);
189 if (!socket) {
190 DVLOG(2) << "Fail to find socket with [channel_id]: " << channel_id;
191 return;
192 }
193
194 content::BrowserThread::PostTask(
195 content::BrowserThread::UI, FROM_HERE,
196 base::Bind(&CastMediaSinkService::OnChannelOpenedOnUIThread, this,
197 service, channel_id, socket->audio_only()));
198 }
199
200 void CastMediaSinkService::OnChannelOpenedOnUIThread(
201 const DnsSdService& service,
202 int channel_id,
203 bool audio_only) {
204 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
205 MediaSinkInternal sink;
206 ErrorType error = CreateCastMediaSink(service, channel_id, audio_only, &sink);
207 if (error != ErrorType::NONE) {
208 DVLOG(2) << "Fail to create Cast device [error]: " << error;
209 return;
210 }
211
212 if (!base::ContainsValue(current_services_, service)) {
213 DVLOG(2) << "Service data not found in current service data list...";
214 return;
215 }
216
217 DVLOG(2) << "Ading sink to current_sinks_ [id]: " << sink.sink().id();
218 current_sinks_.insert(sink);
219 MediaSinkServiceBase::RestartTimer();
220 }
221
222 CastMediaSinkService::CastSocketObserver::CastSocketObserver() {}
223 CastMediaSinkService::CastSocketObserver::~CastSocketObserver() {}
224
225 void CastMediaSinkService::CastSocketObserver::OnError(
226 const cast_channel::CastSocket& socket,
227 cast_channel::ChannelError error_state) {
228 DVLOG(1) << "OnError [ip_endpoint]: " << socket.ip_endpoint().ToString()
229 << " [error_state]: "
230 << cast_channel::ChannelErrorToString(error_state);
231 }
232
233 void CastMediaSinkService::CastSocketObserver::OnMessage(
234 const cast_channel::CastSocket& socket,
235 const cast_channel::CastMessage& message) {}
236
237 } // namespace media_router
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698