blob: cc3a0861e3750055821443ea4120d7e0c5277840 [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 Forrest78fa9602018-06-12 23:10:57234 // We only set connected = true and call the callback after services are
235 // discovered.
Bailey Forrest3de59242018-04-26 17:45:33236 if (!connected) {
237 connected_ = false;
Bailey Forrest78fa9602018-06-12 23:10:57238 ConnectComplete(false);
Bailey Forrest12761022018-03-22 18:50:16239 }
240
241 if (disconnect_pending_) {
242 disconnect_pending_ = false;
243 if (disconnect_cb_) {
244 std::move(disconnect_cb_).Run(!connected);
245 }
246 }
247
Bailey Forrest12761022018-03-22 18:50:16248 if (!connected && rssi_pending_) {
249 LOG(ERROR) << "Read remote RSSI failed: disconnected";
250 if (rssi_cb_) {
251 std::move(rssi_cb_).Run(false, 0);
252 }
253 rssi_pending_ = false;
254 }
255
256 if (!connected && mtu_pending_) {
257 LOG(ERROR) << "Set MTU failed: disconnected";
258 if (mtu_cb_) {
259 std::move(mtu_cb_).Run(false);
260 }
261
262 mtu_pending_ = false;
263 }
264
Bailey Forrest12761022018-03-22 18:50:16265 for (const auto& characteristic : handle_to_characteristic_) {
Bailey Forrest801a41d2018-03-31 01:01:22266 auto* char_impl =
267 static_cast<RemoteCharacteristicImpl*>(characteristic.second.get());
268 char_impl->OnConnectChanged(connected);
Bailey Forrest12761022018-03-22 18:50:16269 }
270
271 for (const auto& descriptor : handle_to_descriptor_) {
Bailey Forrest801a41d2018-03-31 01:01:22272 auto* desc_impl =
273 static_cast<RemoteDescriptorImpl*>(descriptor.second.get());
274 desc_impl->OnConnectChanged(connected);
Bailey Forrest12761022018-03-22 18:50:16275 }
Bailey Forrest3de59242018-04-26 17:45:33276
277 if (connected) {
278 if (!gatt_client_manager_) {
279 LOG(ERROR) << "Couldn't discover services: Destroyed";
280 return;
281 }
282
283 if (!gatt_client_manager_->gatt_client()->GetServices(addr_)) {
284 LOG(ERROR) << "Couldn't discover services, disconnecting";
285 Disconnect({});
Bailey Forrest78fa9602018-06-12 23:10:57286 ConnectComplete(false);
Bailey Forrest3de59242018-04-26 17:45:33287 }
Bailey Forrestfda35092018-05-16 00:30:44288 } else {
289 uuid_to_service_.clear();
290 handle_to_characteristic_.clear();
291 handle_to_descriptor_.clear();
Bailey Forrest3de59242018-04-26 17:45:33292 }
293}
294
Bailey Forrest56e71abb2018-05-11 18:50:56295void RemoteDeviceImpl::SetServicesDiscovered(bool discovered) {
Bailey Forrest3de59242018-04-26 17:45:33296 DCHECK(io_task_runner_->BelongsToCurrentThread());
Bailey Forrest56e71abb2018-05-11 18:50:56297 services_discovered_ = discovered;
298 if (!discovered) {
299 return;
300 }
Bailey Forrest3de59242018-04-26 17:45:33301 connected_ = true;
Bailey Forrest78fa9602018-06-12 23:10:57302 ConnectComplete(true);
Bailey Forrest3de59242018-04-26 17:45:33303}
304
305bool RemoteDeviceImpl::GetServicesDiscovered() {
306 DCHECK(io_task_runner_->BelongsToCurrentThread());
307 return services_discovered_;
Bailey Forrest12761022018-03-22 18:50:16308}
309
Bailey Forrest801a41d2018-03-31 01:01:22310void RemoteDeviceImpl::SetMtu(int mtu) {
Bailey Forrest12761022018-03-22 18:50:16311 DCHECK(io_task_runner_->BelongsToCurrentThread());
312 mtu_pending_ = false;
313 mtu_ = mtu;
314
315 if (mtu_cb_) {
316 std::move(mtu_cb_).Run(true);
317 }
318}
319
Bailey Forrest801a41d2018-03-31 01:01:22320scoped_refptr<RemoteCharacteristic> RemoteDeviceImpl::CharacteristicFromHandle(
Bailey Forrest12761022018-03-22 18:50:16321 uint16_t handle) {
322 DCHECK(io_task_runner_->BelongsToCurrentThread());
323 auto it = handle_to_characteristic_.find(handle);
324 if (it == handle_to_characteristic_.end())
325 return nullptr;
326
327 return it->second;
328}
329
Bailey Forrest801a41d2018-03-31 01:01:22330scoped_refptr<RemoteDescriptor> RemoteDeviceImpl::DescriptorFromHandle(
Bailey Forrest12761022018-03-22 18:50:16331 uint16_t handle) {
332 DCHECK(io_task_runner_->BelongsToCurrentThread());
333 auto it = handle_to_descriptor_.find(handle);
334 if (it == handle_to_descriptor_.end())
335 return nullptr;
336
337 return it->second;
338}
339
Bailey Forrest801a41d2018-03-31 01:01:22340void RemoteDeviceImpl::OnGetServices(
Bailey Forrest12761022018-03-22 18:50:16341 const std::vector<bluetooth_v2_shlib::Gatt::Service>& services) {
342 DCHECK(io_task_runner_->BelongsToCurrentThread());
343 uuid_to_service_.clear();
344 handle_to_characteristic_.clear();
345 handle_to_descriptor_.clear();
346 OnServicesAdded(services);
Bailey Forrest12761022018-03-22 18:50:16347}
348
Bailey Forrest801a41d2018-03-31 01:01:22349void RemoteDeviceImpl::OnServicesRemoved(uint16_t start_handle,
350 uint16_t end_handle) {
Bailey Forrest12761022018-03-22 18:50:16351 DCHECK(io_task_runner_->BelongsToCurrentThread());
352 for (auto it = uuid_to_service_.begin(); it != uuid_to_service_.end();) {
353 if (it->second->handle() >= start_handle &&
354 it->second->handle() <= end_handle) {
355 for (auto& characteristic : it->second->GetCharacteristics()) {
356 for (auto& descriptor : characteristic->GetDescriptors())
357 handle_to_descriptor_.erase(descriptor->handle());
358
359 handle_to_characteristic_.erase(characteristic->handle());
360 }
361 it = uuid_to_service_.erase(it);
362 } else {
363 ++it;
364 }
365 }
Bailey Forrest12761022018-03-22 18:50:16366}
367
Bailey Forrest801a41d2018-03-31 01:01:22368void RemoteDeviceImpl::OnServicesAdded(
Bailey Forrest12761022018-03-22 18:50:16369 const std::vector<bluetooth_v2_shlib::Gatt::Service>& services) {
370 DCHECK(io_task_runner_->BelongsToCurrentThread());
371 for (const auto& service : services) {
Bailey Forrest801a41d2018-03-31 01:01:22372 uuid_to_service_[service.uuid] = new RemoteServiceImpl(
373 this, gatt_client_manager_, service, io_task_runner_);
Bailey Forrest12761022018-03-22 18:50:16374 }
375
376 for (const auto& pair : uuid_to_service_) {
377 for (auto& characteristic : pair.second->GetCharacteristics()) {
378 handle_to_characteristic_.emplace(characteristic->handle(),
379 characteristic);
380 for (auto& descriptor : characteristic->GetDescriptors()) {
381 handle_to_descriptor_.emplace(descriptor->handle(), descriptor);
382 }
383 }
384 }
Bailey Forrest12761022018-03-22 18:50:16385}
386
Bailey Forrest801a41d2018-03-31 01:01:22387void RemoteDeviceImpl::OnReadRemoteRssiComplete(bool status, int rssi) {
Bailey Forrest12761022018-03-22 18:50:16388 DCHECK(io_task_runner_->BelongsToCurrentThread());
389 rssi_pending_ = false;
390 if (rssi_cb_) {
391 std::move(rssi_cb_).Run(true, rssi);
392 }
393}
394
Bailey Forrest78fa9602018-06-12 23:10:57395void RemoteDeviceImpl::ConnectComplete(bool success) {
396 DCHECK(io_task_runner_->BelongsToCurrentThread());
397 if (connect_pending_) {
398 connect_pending_ = false;
399 if (connect_cb_) {
400 std::move(connect_cb_).Run(success);
401 }
402 }
403}
404
Bailey Forrest12761022018-03-22 18:50:16405} // namespace bluetooth
406} // namespace chromecast