blob: ecad561750f759b368db3f5bd4520e1d205f76c0 [file] [log] [blame]
Bailey Forrest070f5a1e2018-03-28 18:17:141// Copyright 2018 The Chromium Authors. All rights reserved.
Bailey Forrest12761022018-03-22 18:50:162// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Bailey Forrest801a41d2018-03-31 01:01:225#include "chromecast/device/bluetooth/le/remote_device_impl.h"
Bailey Forrest12761022018-03-22 18:50:166
7#include "base/bind.h"
8#include "chromecast/base/bind_to_task_runner.h"
Bailey Forrest801a41d2018-03-31 01:01:229#include "chromecast/device/bluetooth/le/gatt_client_manager_impl.h"
10#include "chromecast/device/bluetooth/le/remote_characteristic_impl.h"
11#include "chromecast/device/bluetooth/le/remote_descriptor_impl.h"
12#include "chromecast/device/bluetooth/le/remote_service_impl.h"
Bailey Forrest12761022018-03-22 18:50:1613
14namespace chromecast {
15namespace bluetooth {
16
17#define RUN_ON_IO_THREAD(method, ...) \
18 io_task_runner_->PostTask( \
Bailey Forrest801a41d2018-03-31 01:01:2219 FROM_HERE, \
20 base::BindOnce(&RemoteDeviceImpl::method, this, ##__VA_ARGS__));
Bailey Forrest12761022018-03-22 18:50:1621
22#define MAKE_SURE_IO_THREAD(method, ...) \
23 DCHECK(io_task_runner_); \
24 if (!io_task_runner_->BelongsToCurrentThread()) { \
25 RUN_ON_IO_THREAD(method, ##__VA_ARGS__) \
26 return; \
27 }
28
29#define EXEC_CB_AND_RET(cb, ret, ...) \
30 do { \
31 if (cb) { \
32 std::move(cb).Run(ret, ##__VA_ARGS__); \
33 } \
34 return; \
35 } while (0)
36
37#define CHECK_CONNECTED(cb) \
38 do { \
39 if (!connected_) { \
40 LOG(ERROR) << __func__ << "failed: Not connected"; \
41 EXEC_CB_AND_RET(cb, false); \
42 } \
43 } while (0)
44
45#define LOG_EXEC_CB_AND_RET(cb, ret) \
46 do { \
47 if (!ret) { \
48 LOG(ERROR) << __func__ << "failed"; \
49 } \
50 EXEC_CB_AND_RET(cb, ret); \
51 } while (0)
52
Bailey Forrest801a41d2018-03-31 01:01:2253RemoteDeviceImpl::RemoteDeviceImpl(
Bailey Forrest12761022018-03-22 18:50:1654 const bluetooth_v2_shlib::Addr& addr,
Bailey Forrest801a41d2018-03-31 01:01:2255 base::WeakPtr<GattClientManagerImpl> gatt_client_manager,
Bailey Forrest12761022018-03-22 18:50:1656 scoped_refptr<base::SingleThreadTaskRunner> io_task_runner)
57 : gatt_client_manager_(gatt_client_manager),
58 addr_(addr),
59 io_task_runner_(io_task_runner) {
60 DCHECK(gatt_client_manager);
61 DCHECK(io_task_runner_->BelongsToCurrentThread());
62}
63
Bailey Forrest801a41d2018-03-31 01:01:2264RemoteDeviceImpl::~RemoteDeviceImpl() = default;
Bailey Forrest12761022018-03-22 18:50:1665
Bailey Forrest801a41d2018-03-31 01:01:2266void RemoteDeviceImpl::Connect(StatusCallback cb) {
Kyle Lund1de248a2018-03-27 17:26:4467 MAKE_SURE_IO_THREAD(Connect, BindToCurrentSequence(std::move(cb)));
Bailey Forrest12761022018-03-22 18:50:1668 if (!ConnectSync()) {
69 // Error logged.
70 EXEC_CB_AND_RET(cb, false);
71 }
72
73 connect_cb_ = std::move(cb);
74}
75
Bailey Forrest801a41d2018-03-31 01:01:2276bool RemoteDeviceImpl::ConnectSync() {
Bailey Forrest12761022018-03-22 18:50:1677 DCHECK(io_task_runner_->BelongsToCurrentThread());
78 if (!gatt_client_manager_) {
79 LOG(ERROR) << __func__ << " failed: Destroyed";
80 return false;
81 }
82 if (connect_pending_) {
83 LOG(ERROR) << __func__ << " failed: Connection pending";
84 return false;
85 }
86
87 gatt_client_manager_->NotifyConnect(addr_);
88 if (!gatt_client_manager_->gatt_client()->Connect(addr_)) {
89 LOG(ERROR) << __func__ << " failed";
90 return false;
91 }
92 connect_pending_ = true;
93 return true;
94}
95
Bailey Forrest801a41d2018-03-31 01:01:2296void RemoteDeviceImpl::Disconnect(StatusCallback cb) {
Kyle Lund1de248a2018-03-27 17:26:4497 MAKE_SURE_IO_THREAD(Disconnect, BindToCurrentSequence(std::move(cb)));
Bailey Forrest12761022018-03-22 18:50:1698 if (!DisconnectSync()) {
99 // Error logged.
100 EXEC_CB_AND_RET(cb, false);
101 }
102
103 disconnect_cb_ = std::move(cb);
104}
105
Bailey Forrest801a41d2018-03-31 01:01:22106bool RemoteDeviceImpl::DisconnectSync() {
Bailey Forrest12761022018-03-22 18:50:16107 DCHECK(io_task_runner_->BelongsToCurrentThread());
108 if (!gatt_client_manager_) {
109 LOG(ERROR) << __func__ << " failed: Destroyed";
110 return false;
111 }
112
113 if (!connected_) {
114 LOG(ERROR) << "Not connected";
115 return false;
116 }
117
118 if (!gatt_client_manager_->gatt_client()->Disconnect(addr_)) {
119 LOG(ERROR) << __func__ << " failed";
120 return false;
121 }
122 disconnect_pending_ = true;
123
124 return true;
125}
126
Bailey Forrest801a41d2018-03-31 01:01:22127void RemoteDeviceImpl::ReadRemoteRssi(RssiCallback cb) {
Kyle Lund1de248a2018-03-27 17:26:44128 MAKE_SURE_IO_THREAD(ReadRemoteRssi, BindToCurrentSequence(std::move(cb)));
Bailey Forrest12761022018-03-22 18:50:16129 if (!gatt_client_manager_) {
130 LOG(ERROR) << __func__ << " failed: Destroyed";
131 EXEC_CB_AND_RET(cb, false, 0);
132 }
133
134 if (rssi_pending_) {
135 LOG(ERROR) << "Read remote RSSI already pending";
136 EXEC_CB_AND_RET(cb, false, 0);
137 }
138 if (!gatt_client_manager_->gatt_client()->ReadRemoteRssi(addr_)) {
139 LOG(ERROR) << __func__ << " failed";
140 EXEC_CB_AND_RET(cb, false, 0);
141 }
142 rssi_pending_ = true;
143 rssi_cb_ = std::move(cb);
144}
145
Bailey Forrest801a41d2018-03-31 01:01:22146void RemoteDeviceImpl::RequestMtu(int mtu, StatusCallback cb) {
Kyle Lund1de248a2018-03-27 17:26:44147 MAKE_SURE_IO_THREAD(RequestMtu, mtu, BindToCurrentSequence(std::move(cb)));
Bailey Forrest12761022018-03-22 18:50:16148 if (!gatt_client_manager_) {
149 LOG(ERROR) << __func__ << " failed: Destroyed";
150 EXEC_CB_AND_RET(cb, false);
151 }
152 CHECK_CONNECTED(cb);
153 if (mtu_pending_) {
154 LOG(ERROR) << "MTU change already pending";
155 EXEC_CB_AND_RET(cb, false);
156 }
157
158 if (!gatt_client_manager_->gatt_client()->RequestMtu(addr_, mtu)) {
159 LOG(ERROR) << __func__ << " failed";
160 EXEC_CB_AND_RET(cb, false);
161 }
162
163 mtu_pending_ = true;
164 mtu_cb_ = std::move(cb);
165}
166
Bailey Forrest801a41d2018-03-31 01:01:22167void RemoteDeviceImpl::ConnectionParameterUpdate(int min_interval,
168 int max_interval,
169 int latency,
170 int timeout,
171 StatusCallback cb) {
Bailey Forrest12761022018-03-22 18:50:16172 MAKE_SURE_IO_THREAD(ConnectionParameterUpdate, min_interval, max_interval,
Kyle Lund1de248a2018-03-27 17:26:44173 latency, timeout, BindToCurrentSequence(std::move(cb)));
Bailey Forrest12761022018-03-22 18:50:16174 if (!gatt_client_manager_) {
175 LOG(ERROR) << __func__ << " failed: Destroyed";
176 EXEC_CB_AND_RET(cb, false);
177 }
178 CHECK_CONNECTED(cb);
179 bool ret = gatt_client_manager_->gatt_client()->ConnectionParameterUpdate(
180 addr_, min_interval, max_interval, latency, timeout);
181 LOG_EXEC_CB_AND_RET(cb, ret);
182}
183
Bailey Forrest801a41d2018-03-31 01:01:22184bool RemoteDeviceImpl::IsConnected() {
Bailey Forrest12761022018-03-22 18:50:16185 return connected_;
186}
187
Bailey Forrest801a41d2018-03-31 01:01:22188int RemoteDeviceImpl::GetMtu() {
Bailey Forrest12761022018-03-22 18:50:16189 return mtu_;
190}
191
Bailey Forrest801a41d2018-03-31 01:01:22192void RemoteDeviceImpl::GetServices(
Bailey Forrest12761022018-03-22 18:50:16193 base::OnceCallback<void(std::vector<scoped_refptr<RemoteService>>)> cb) {
Kyle Lund1de248a2018-03-27 17:26:44194 MAKE_SURE_IO_THREAD(GetServices, BindToCurrentSequence(std::move(cb)));
Bailey Forrest12761022018-03-22 18:50:16195 auto ret = GetServicesSync();
196 EXEC_CB_AND_RET(cb, std::move(ret));
197}
198
Bailey Forrest801a41d2018-03-31 01:01:22199std::vector<scoped_refptr<RemoteService>> RemoteDeviceImpl::GetServicesSync() {
Bailey Forrest12761022018-03-22 18:50:16200 DCHECK(io_task_runner_->BelongsToCurrentThread());
201 std::vector<scoped_refptr<RemoteService>> services;
202 services.reserve(uuid_to_service_.size());
203 for (const auto& pair : uuid_to_service_)
204 services.push_back(pair.second);
205
206 return services;
207}
208
Bailey Forrest801a41d2018-03-31 01:01:22209void RemoteDeviceImpl::GetServiceByUuid(
Bailey Forrest12761022018-03-22 18:50:16210 const bluetooth_v2_shlib::Uuid& uuid,
211 base::OnceCallback<void(scoped_refptr<RemoteService>)> cb) {
212 MAKE_SURE_IO_THREAD(GetServiceByUuid, uuid,
Kyle Lund1de248a2018-03-27 17:26:44213 BindToCurrentSequence(std::move(cb)));
Bailey Forrest12761022018-03-22 18:50:16214 auto ret = GetServiceByUuidSync(uuid);
215 EXEC_CB_AND_RET(cb, std::move(ret));
216}
217
Bailey Forrest801a41d2018-03-31 01:01:22218const bluetooth_v2_shlib::Addr& RemoteDeviceImpl::addr() const {
219 return addr_;
220}
221
222scoped_refptr<RemoteService> RemoteDeviceImpl::GetServiceByUuidSync(
Bailey Forrest12761022018-03-22 18:50:16223 const bluetooth_v2_shlib::Uuid& uuid) {
224 DCHECK(io_task_runner_->BelongsToCurrentThread());
225 auto it = uuid_to_service_.find(uuid);
226 if (it == uuid_to_service_.end())
227 return nullptr;
228
229 return it->second;
230}
231
Bailey Forrest801a41d2018-03-31 01:01:22232void RemoteDeviceImpl::SetConnected(bool connected) {
Bailey Forrest12761022018-03-22 18:50:16233 DCHECK(io_task_runner_->BelongsToCurrentThread());
Bailey Forrest3de59242018-04-26 17:45:33234 // We only set connected = true after services are discovered.
235 if (!connected) {
236 connected_ = false;
237 }
Bailey Forrest12761022018-03-22 18:50:16238 if (connect_pending_) {
239 connect_pending_ = false;
240 if (connect_cb_) {
241 std::move(connect_cb_).Run(connected);
242 }
243 }
244
245 if (disconnect_pending_) {
246 disconnect_pending_ = false;
247 if (disconnect_cb_) {
248 std::move(disconnect_cb_).Run(!connected);
249 }
250 }
251
Bailey Forrest12761022018-03-22 18:50:16252 if (!connected && rssi_pending_) {
253 LOG(ERROR) << "Read remote RSSI failed: disconnected";
254 if (rssi_cb_) {
255 std::move(rssi_cb_).Run(false, 0);
256 }
257 rssi_pending_ = false;
258 }
259
260 if (!connected && mtu_pending_) {
261 LOG(ERROR) << "Set MTU failed: disconnected";
262 if (mtu_cb_) {
263 std::move(mtu_cb_).Run(false);
264 }
265
266 mtu_pending_ = false;
267 }
268
Bailey Forrest12761022018-03-22 18:50:16269 for (const auto& characteristic : handle_to_characteristic_) {
Bailey Forrest801a41d2018-03-31 01:01:22270 auto* char_impl =
271 static_cast<RemoteCharacteristicImpl*>(characteristic.second.get());
272 char_impl->OnConnectChanged(connected);
Bailey Forrest12761022018-03-22 18:50:16273 }
274
275 for (const auto& descriptor : handle_to_descriptor_) {
Bailey Forrest801a41d2018-03-31 01:01:22276 auto* desc_impl =
277 static_cast<RemoteDescriptorImpl*>(descriptor.second.get());
278 desc_impl->OnConnectChanged(connected);
Bailey Forrest12761022018-03-22 18:50:16279 }
Bailey Forrest3de59242018-04-26 17:45:33280
281 if (connected) {
282 if (!gatt_client_manager_) {
283 LOG(ERROR) << "Couldn't discover services: Destroyed";
284 return;
285 }
286
287 if (!gatt_client_manager_->gatt_client()->GetServices(addr_)) {
288 LOG(ERROR) << "Couldn't discover services, disconnecting";
289 Disconnect({});
290 }
291 }
292}
293
Bailey Forrest56e71abb2018-05-11 18:50:56294void RemoteDeviceImpl::SetServicesDiscovered(bool discovered) {
Bailey Forrest3de59242018-04-26 17:45:33295 DCHECK(io_task_runner_->BelongsToCurrentThread());
Bailey Forrest56e71abb2018-05-11 18:50:56296 services_discovered_ = discovered;
297 if (!discovered) {
298 return;
299 }
Bailey Forrest3de59242018-04-26 17:45:33300 connected_ = true;
301 if (connect_cb_) {
302 std::move(connect_cb_).Run(true);
303 }
304}
305
306bool RemoteDeviceImpl::GetServicesDiscovered() {
307 DCHECK(io_task_runner_->BelongsToCurrentThread());
308 return services_discovered_;
Bailey Forrest12761022018-03-22 18:50:16309}
310
Bailey Forrest801a41d2018-03-31 01:01:22311void RemoteDeviceImpl::SetMtu(int mtu) {
Bailey Forrest12761022018-03-22 18:50:16312 DCHECK(io_task_runner_->BelongsToCurrentThread());
313 mtu_pending_ = false;
314 mtu_ = mtu;
315
316 if (mtu_cb_) {
317 std::move(mtu_cb_).Run(true);
318 }
319}
320
Bailey Forrest801a41d2018-03-31 01:01:22321scoped_refptr<RemoteCharacteristic> RemoteDeviceImpl::CharacteristicFromHandle(
Bailey Forrest12761022018-03-22 18:50:16322 uint16_t handle) {
323 DCHECK(io_task_runner_->BelongsToCurrentThread());
324 auto it = handle_to_characteristic_.find(handle);
325 if (it == handle_to_characteristic_.end())
326 return nullptr;
327
328 return it->second;
329}
330
Bailey Forrest801a41d2018-03-31 01:01:22331scoped_refptr<RemoteDescriptor> RemoteDeviceImpl::DescriptorFromHandle(
Bailey Forrest12761022018-03-22 18:50:16332 uint16_t handle) {
333 DCHECK(io_task_runner_->BelongsToCurrentThread());
334 auto it = handle_to_descriptor_.find(handle);
335 if (it == handle_to_descriptor_.end())
336 return nullptr;
337
338 return it->second;
339}
340
Bailey Forrest801a41d2018-03-31 01:01:22341void RemoteDeviceImpl::OnGetServices(
Bailey Forrest12761022018-03-22 18:50:16342 const std::vector<bluetooth_v2_shlib::Gatt::Service>& services) {
343 DCHECK(io_task_runner_->BelongsToCurrentThread());
344 uuid_to_service_.clear();
345 handle_to_characteristic_.clear();
346 handle_to_descriptor_.clear();
347 OnServicesAdded(services);
Bailey Forrest12761022018-03-22 18:50:16348}
349
Bailey Forrest801a41d2018-03-31 01:01:22350void RemoteDeviceImpl::OnServicesRemoved(uint16_t start_handle,
351 uint16_t end_handle) {
Bailey Forrest12761022018-03-22 18:50:16352 DCHECK(io_task_runner_->BelongsToCurrentThread());
353 for (auto it = uuid_to_service_.begin(); it != uuid_to_service_.end();) {
354 if (it->second->handle() >= start_handle &&
355 it->second->handle() <= end_handle) {
356 for (auto& characteristic : it->second->GetCharacteristics()) {
357 for (auto& descriptor : characteristic->GetDescriptors())
358 handle_to_descriptor_.erase(descriptor->handle());
359
360 handle_to_characteristic_.erase(characteristic->handle());
361 }
362 it = uuid_to_service_.erase(it);
363 } else {
364 ++it;
365 }
366 }
Bailey Forrest12761022018-03-22 18:50:16367}
368
Bailey Forrest801a41d2018-03-31 01:01:22369void RemoteDeviceImpl::OnServicesAdded(
Bailey Forrest12761022018-03-22 18:50:16370 const std::vector<bluetooth_v2_shlib::Gatt::Service>& services) {
371 DCHECK(io_task_runner_->BelongsToCurrentThread());
372 for (const auto& service : services) {
Bailey Forrest801a41d2018-03-31 01:01:22373 uuid_to_service_[service.uuid] = new RemoteServiceImpl(
374 this, gatt_client_manager_, service, io_task_runner_);
Bailey Forrest12761022018-03-22 18:50:16375 }
376
377 for (const auto& pair : uuid_to_service_) {
378 for (auto& characteristic : pair.second->GetCharacteristics()) {
379 handle_to_characteristic_.emplace(characteristic->handle(),
380 characteristic);
381 for (auto& descriptor : characteristic->GetDescriptors()) {
382 handle_to_descriptor_.emplace(descriptor->handle(), descriptor);
383 }
384 }
385 }
Bailey Forrest12761022018-03-22 18:50:16386}
387
Bailey Forrest801a41d2018-03-31 01:01:22388void RemoteDeviceImpl::OnReadRemoteRssiComplete(bool status, int rssi) {
Bailey Forrest12761022018-03-22 18:50:16389 DCHECK(io_task_runner_->BelongsToCurrentThread());
390 rssi_pending_ = false;
391 if (rssi_cb_) {
392 std::move(rssi_cb_).Run(true, rssi);
393 }
394}
395
396} // namespace bluetooth
397} // namespace chromecast