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

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

Issue 2927833002: [Media Router] Add CastMediaSinkService (Closed)
Patch Set: add dependency patchset Created 3 years, 6 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 "chrome/browser/browser_process.h"
8 #include "chrome/common/media_router/discovery/media_sink_internal.h"
9 #include "components/net_log/chrome_net_log.h"
10 #include "content/public/common/content_client.h"
11 #include "extensions/browser/api/cast_channel/cast_socket_service_factory.h"
12 #include "net/base/host_port_pair.h"
13 #include "net/base/ip_address.h"
14
15 namespace {
16 // mDNS service types.
17 const char kCastServiceType[] = "_googlecast._tcp.local";
18
19 enum ErrorType {
20 NONE,
21 NOT_CAST_DEVICE,
22 MISSING_ID,
23 MISSING_FRIENDLY_NAME,
24 MISSING_OR_INVALID_IP_ADDRESS,
25 MISSING_OR_INVALID_PORT,
26 };
27
28 ErrorType CreateCastMediaSink(const media_router::DnsSdService& service,
29 int channel_id,
30 bool audio_only,
31 media_router::MediaSinkInternal* cast_sink) {
32 DCHECK(cast_sink);
33 if (service.service_name.find(kCastServiceType) == std::string::npos)
34 return ErrorType::NOT_CAST_DEVICE;
35
36 net::IPAddress ip_address;
37 if (!ip_address.AssignFromIPLiteral(service.ip_address))
38 return ErrorType::MISSING_OR_INVALID_IP_ADDRESS;
39
40 std::map<std::string, std::string> service_data;
41 for (const auto& item : service.service_data) {
42 // |item| format should be "id=xxxxxx", etc.
43 size_t split_idx = item.find('=');
44 if (split_idx == std::string::npos)
45 continue;
46
47 std::string key = item.substr(0, split_idx);
48 std::string val = item.substr(split_idx + 1);
49 service_data[key] = val;
50 }
51
52 // When use this "sink" within browser, please note it will have a different
53 // ID when it is sent to the extension, because it derives a different sink ID
54 // using the given sink ID.
55 std::string unique_id = service_data["id"];
56 if (unique_id.empty())
57 return ErrorType::MISSING_ID;
58 std::string friendly_name = service_data["fn"];
59 if (friendly_name.empty())
60 return ErrorType::MISSING_FRIENDLY_NAME;
61 media_router::MediaSink sink(unique_id, friendly_name,
62 media_router::MediaSink::IconType::CAST);
63
64 media_router::CastSinkExtraData extra_data;
65 extra_data.ip_address = ip_address;
66 extra_data.model_name = service_data["md"];
67 extra_data.capabilities =
68 extensions::api::cast_channel::CastDeviceCapability::AUDIO_OUT;
69 if (!audio_only)
70 extra_data.capabilities |=
71 extensions::api::cast_channel::CastDeviceCapability::VIDEO_OUT;
72 extra_data.cast_channel_id = channel_id;
73
74 cast_sink->set_sink(sink);
75 cast_sink->set_cast_data(extra_data);
76
77 return ErrorType::NONE;
78 }
79
80 } // namespace
81
82 namespace media_router {
83
84 CastMediaSinkService::CastMediaSinkService(
85 const OnSinksDiscoveredCallback& callback,
86 content::BrowserContext* browser_context)
87 : MediaSinkServiceBase(callback) {
88 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
89 cast_socket_service_ =
90 extensions::api::cast_channel::CastSocketServiceFactory::GetInstance()
91 ->GetForBrowserContext(browser_context);
92 DCHECK(cast_socket_service_);
93 }
94
95 CastMediaSinkService::~CastMediaSinkService() {}
96
97 void CastMediaSinkService::Start() {
98 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
99 if (dns_sd_registry_)
100 return;
101
102 dns_sd_registry_ = DnsSdRegistry::GetInstance();
103 dns_sd_registry_->AddObserver(this);
104 dns_sd_registry_->RegisterDnsSdListener(kCastServiceType);
105 MediaSinkServiceBase::StartTimer();
106 }
107
108 void CastMediaSinkService::Stop() {
109 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
110 if (!dns_sd_registry_)
111 return;
112
113 dns_sd_registry_->UnregisterDnsSdListener(kCastServiceType);
114 dns_sd_registry_->RemoveObserver(this);
115 dns_sd_registry_ = nullptr;
116 MediaSinkServiceBase::StopTimer();
117 }
118
119 void CastMediaSinkService::SetDnsSdRegistryForTesting(DnsSdRegistry* registry) {
120 DCHECK(!dns_sd_registry_);
121 dns_sd_registry_ = registry;
122
123 DCHECK(dns_sd_registry_);
124 dns_sd_registry_->AddObserver(this);
125 dns_sd_registry_->RegisterDnsSdListener(kCastServiceType);
126 }
127
128 void CastMediaSinkService::OnDnsSdEvent(
129 const std::string& service_type,
130 const DnsSdRegistry::DnsSdServiceList& services) {
131 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
132 DVLOG(2) << "CastMediaSinkService::OnDnsSdEvent found " << services.size()
133 << " services";
134
135 current_sinks_.clear();
136 current_services_ = services;
137
138 for (const auto& service : services) {
139 net::IPAddress ip_address;
140 if (!ip_address.AssignFromIPLiteral(service.ip_address)) {
141 DVLOG(2) << "Invalid ip_addresss: " << service.ip_address;
142 continue;
143 }
144 net::HostPortPair host_port_pair =
145 net::HostPortPair::FromString(service.service_host_port);
146
147 content::BrowserThread::PostTask(
148 content::BrowserThread::IO, FROM_HERE,
149 base::Bind(&CastMediaSinkService::OpenChannelOnIOThread, this, service,
150 net::IPEndPoint(ip_address, host_port_pair.port())));
151 }
152 }
153
154 void CastMediaSinkService::OpenChannelOnIOThread(
155 const DnsSdService& service,
156 const net::IPEndPoint& ip_endpoint) {
157 cast_socket_service_->OpenChannel(
zhaobin 2017/06/07 18:41:12 WIP in https://codereview.chromium.org/2925053005/
zhaobin 2017/06/10 02:19:35 Done.
158 ip_endpoint, g_browser_process->net_log(),
159 base::Bind(&CastMediaSinkService::OnChannelOpenedOnIOThread, this,
160 service));
161 }
162
163 void CastMediaSinkService::OnChannelOpenedOnIOThread(
164 const DnsSdService& service,
165 int channel_id,
166 ::cast_channel::ChannelError channel_error) {
167 if (channel_error != cast_channel::ChannelError::NONE) {
168 DVLOG(2) << "Fail to open channel " << service.ip_address << ": "
169 << service.service_host_port
170 << " [ChannelError]: " << (int)channel_error;
171 return;
172 }
173
174 auto* socket = cast_socket_service_->GetSocket(channel_id);
175 if (!socket) {
176 DVLOG(2) << "Fail to find socket with [channel_id]: " << channel_id;
177 return;
178 }
179
180 content::BrowserThread::PostTask(
181 content::BrowserThread::UI, FROM_HERE,
182 base::Bind(&CastMediaSinkService::OnChannelOpenOnUIThread, this, service,
183 channel_id, socket->audio_only()));
184 }
185
186 void CastMediaSinkService::OnChannelOpenOnUIThread(const DnsSdService& service,
187 int channel_id,
188 bool audio_only) {
189 MediaSinkInternal sink;
190 ErrorType error = CreateCastMediaSink(service, channel_id, audio_only, &sink);
191 if (error != ErrorType::NONE) {
192 DVLOG(2) << "Fail to create Cast device [error]: " << error;
193 return;
194 }
195
196 if (!base::ContainsValue(current_services_, service)) {
197 DVLOG(2) << "Service data not found in current service data list...";
198 return;
199 }
200
201 current_sinks_.insert(sink);
202 MediaSinkServiceBase::RestartTimer();
203 }
204
205 } // namespace media_router
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698