OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 "device/bluetooth/bluetooth_task_manager_win.h" | 5 #include "device/bluetooth/bluetooth_task_manager_win.h" |
6 | 6 |
7 #include <winsock2.h> | 7 #include <winsock2.h> |
8 | 8 |
9 #include <string> | 9 #include <string> |
10 | 10 |
11 #include "base/basictypes.h" | 11 #include "base/basictypes.h" |
12 #include "base/bind.h" | 12 #include "base/bind.h" |
13 #include "base/memory/ref_counted.h" | 13 #include "base/memory/ref_counted.h" |
14 #include "base/message_loop/message_loop.h" | 14 #include "base/message_loop/message_loop.h" |
15 #include "base/sequenced_task_runner.h" | 15 #include "base/sequenced_task_runner.h" |
16 #include "base/strings/stringprintf.h" | 16 #include "base/strings/stringprintf.h" |
17 #include "base/strings/sys_string_conversions.h" | 17 #include "base/strings/sys_string_conversions.h" |
18 #include "base/threading/sequenced_worker_pool.h" | 18 #include "base/threading/sequenced_worker_pool.h" |
19 #include "base/win/scoped_handle.h" | 19 #include "base/win/scoped_handle.h" |
| 20 #include "device/bluetooth/bluetooth_device.h" |
20 #include "device/bluetooth/bluetooth_init_win.h" | 21 #include "device/bluetooth/bluetooth_init_win.h" |
21 #include "device/bluetooth/bluetooth_low_energy_win.h" | 22 #include "device/bluetooth/bluetooth_low_energy_win.h" |
22 #include "device/bluetooth/bluetooth_service_record_win.h" | 23 #include "device/bluetooth/bluetooth_service_record_win.h" |
23 #include "net/base/winsock_init.h" | 24 #include "net/base/winsock_init.h" |
24 | 25 |
25 namespace { | 26 namespace { |
26 | 27 |
27 const int kNumThreadsInWorkerPool = 3; | 28 const int kNumThreadsInWorkerPool = 3; |
28 const char kBluetoothThreadName[] = "BluetoothPollingThreadWin"; | 29 const char kBluetoothThreadName[] = "BluetoothPollingThreadWin"; |
29 const int kMaxNumDeviceAddressChar = 127; | 30 const int kMaxNumDeviceAddressChar = 127; |
30 const int kServiceDiscoveryResultBufferSize = 5000; | 31 const int kServiceDiscoveryResultBufferSize = 5000; |
31 const int kMaxDeviceDiscoveryTimeout = 48; | 32 |
| 33 // See http://goo.gl/iNTRQe: cTimeoutMultiplier: A value that indicates the time |
| 34 // out for the inquiry, expressed in increments of 1.28 seconds. For example, an |
| 35 // inquiry of 12.8 seconds has a cTimeoutMultiplier value of 10. The maximum |
| 36 // value for this member is 48. When a value greater than 48 is used, the |
| 37 // calling function immediately fails and returns |
| 38 const int kMaxDeviceDiscoveryTimeoutMultiplier = 48; |
32 | 39 |
33 typedef device::BluetoothTaskManagerWin::ServiceRecordState ServiceRecordState; | 40 typedef device::BluetoothTaskManagerWin::ServiceRecordState ServiceRecordState; |
34 | 41 |
35 std::string BluetoothAddressToString(const BLUETOOTH_ADDRESS& btha) { | 42 // Note: The string returned here must have the same format as |
36 return base::StringPrintf("%02X:%02X:%02X:%02X:%02X:%02X", | 43 // BluetoothDevice::CanonicalizeAddress. |
37 btha.rgBytes[5], | 44 std::string BluetoothAddressToCanonicalString(const BLUETOOTH_ADDRESS& btha) { |
38 btha.rgBytes[4], | 45 std::string result = base::StringPrintf("%02X:%02X:%02X:%02X:%02X:%02X", |
39 btha.rgBytes[3], | 46 btha.rgBytes[5], |
40 btha.rgBytes[2], | 47 btha.rgBytes[4], |
41 btha.rgBytes[1], | 48 btha.rgBytes[3], |
42 btha.rgBytes[0]); | 49 btha.rgBytes[2], |
| 50 btha.rgBytes[1], |
| 51 btha.rgBytes[0]); |
| 52 DCHECK_EQ(result, device::BluetoothDevice::CanonicalizeAddress(result)); |
| 53 return result; |
43 } | 54 } |
44 | 55 |
45 device::BluetoothUUID BluetoothLowEnergyUuidToUBluetoothUuid( | 56 device::BluetoothUUID BluetoothLowEnergyUuidToBluetoothUuid( |
46 const BTH_LE_UUID& bth_le_uuid) { | 57 const BTH_LE_UUID& bth_le_uuid) { |
47 if (bth_le_uuid.IsShortUuid) { | 58 if (bth_le_uuid.IsShortUuid) { |
48 std::string uuid_hex = | 59 std::string uuid_hex = |
49 base::StringPrintf("%04x", bth_le_uuid.Value.ShortUuid); | 60 base::StringPrintf("%04x", bth_le_uuid.Value.ShortUuid); |
50 return device::BluetoothUUID(uuid_hex); | 61 return device::BluetoothUUID(uuid_hex); |
51 } else { | 62 } else { |
52 return device::BluetoothUUID( | 63 return device::BluetoothUUID( |
53 base::StringPrintf("%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", | 64 base::StringPrintf("%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", |
54 bth_le_uuid.Value.LongUuid.Data1, | 65 bth_le_uuid.Value.LongUuid.Data1, |
55 bth_le_uuid.Value.LongUuid.Data2, | 66 bth_le_uuid.Value.LongUuid.Data2, |
(...skipping 13 matching lines...) Expand all Loading... |
69 void GetAdapterState(HANDLE adapter_handle, | 80 void GetAdapterState(HANDLE adapter_handle, |
70 device::BluetoothTaskManagerWin::AdapterState* state) { | 81 device::BluetoothTaskManagerWin::AdapterState* state) { |
71 std::string name; | 82 std::string name; |
72 std::string address; | 83 std::string address; |
73 bool powered = false; | 84 bool powered = false; |
74 BLUETOOTH_RADIO_INFO adapter_info = { sizeof(BLUETOOTH_RADIO_INFO), 0 }; | 85 BLUETOOTH_RADIO_INFO adapter_info = { sizeof(BLUETOOTH_RADIO_INFO), 0 }; |
75 if (adapter_handle && | 86 if (adapter_handle && |
76 ERROR_SUCCESS == BluetoothGetRadioInfo(adapter_handle, | 87 ERROR_SUCCESS == BluetoothGetRadioInfo(adapter_handle, |
77 &adapter_info)) { | 88 &adapter_info)) { |
78 name = base::SysWideToUTF8(adapter_info.szName); | 89 name = base::SysWideToUTF8(adapter_info.szName); |
79 address = BluetoothAddressToString(adapter_info.address); | 90 address = BluetoothAddressToCanonicalString(adapter_info.address); |
80 powered = !!BluetoothIsConnectable(adapter_handle); | 91 powered = !!BluetoothIsConnectable(adapter_handle); |
81 } | 92 } |
82 state->name = name; | 93 state->name = name; |
83 state->address = address; | 94 state->address = address; |
84 state->powered = powered; | 95 state->powered = powered; |
85 } | 96 } |
86 | 97 |
87 void GetDeviceState(const BLUETOOTH_DEVICE_INFO& device_info, | 98 void GetDeviceState(const BLUETOOTH_DEVICE_INFO& device_info, |
88 device::BluetoothTaskManagerWin::DeviceState* state) { | 99 device::BluetoothTaskManagerWin::DeviceState* state) { |
89 state->name = base::SysWideToUTF8(device_info.szName); | 100 state->name = base::SysWideToUTF8(device_info.szName); |
90 state->address = BluetoothAddressToString(device_info.Address); | 101 state->address = BluetoothAddressToCanonicalString(device_info.Address); |
91 state->bluetooth_class = device_info.ulClassofDevice; | 102 state->bluetooth_class = device_info.ulClassofDevice; |
92 state->visible = true; | 103 state->visible = true; |
93 state->connected = !!device_info.fConnected; | 104 state->connected = !!device_info.fConnected; |
94 state->authenticated = !!device_info.fAuthenticated; | 105 state->authenticated = !!device_info.fAuthenticated; |
95 } | 106 } |
96 | 107 |
97 void DiscoverDeviceServices( | |
98 const std::string& device_address, | |
99 const GUID& protocol_uuid, | |
100 ScopedVector<ServiceRecordState>* service_record_states) { | |
101 // Bluetooth and WSAQUERYSET for Service Inquiry. See http://goo.gl/2v9pyt. | |
102 WSAQUERYSET sdp_query; | |
103 ZeroMemory(&sdp_query, sizeof(sdp_query)); | |
104 sdp_query.dwSize = sizeof(sdp_query); | |
105 GUID protocol = protocol_uuid; | |
106 sdp_query.lpServiceClassId = &protocol; | |
107 sdp_query.dwNameSpace = NS_BTH; | |
108 wchar_t device_address_context[kMaxNumDeviceAddressChar]; | |
109 std::size_t length = base::SysUTF8ToWide("(" + device_address + ")").copy( | |
110 device_address_context, kMaxNumDeviceAddressChar); | |
111 device_address_context[length] = NULL; | |
112 sdp_query.lpszContext = device_address_context; | |
113 HANDLE sdp_handle; | |
114 if (ERROR_SUCCESS != | |
115 WSALookupServiceBegin(&sdp_query, LUP_RETURN_ALL, &sdp_handle)) { | |
116 return; | |
117 } | |
118 char sdp_buffer[kServiceDiscoveryResultBufferSize]; | |
119 LPWSAQUERYSET sdp_result_data = reinterpret_cast<LPWSAQUERYSET>(sdp_buffer); | |
120 while (true) { | |
121 DWORD sdp_buffer_size = sizeof(sdp_buffer); | |
122 if (ERROR_SUCCESS != | |
123 WSALookupServiceNext( | |
124 sdp_handle, LUP_RETURN_ALL, &sdp_buffer_size, sdp_result_data)) { | |
125 break; | |
126 } | |
127 ServiceRecordState* service_record_state = new ServiceRecordState(); | |
128 service_record_state->name = | |
129 base::SysWideToUTF8(sdp_result_data->lpszServiceInstanceName); | |
130 for (uint64 i = 0; i < sdp_result_data->lpBlob->cbSize; i++) { | |
131 service_record_state->sdp_bytes.push_back( | |
132 sdp_result_data->lpBlob->pBlobData[i]); | |
133 } | |
134 service_record_states->push_back(service_record_state); | |
135 } | |
136 WSALookupServiceEnd(sdp_handle); | |
137 } | |
138 | |
139 } // namespace | 108 } // namespace |
140 | 109 |
141 namespace device { | 110 namespace device { |
142 | 111 |
143 // static | 112 // static |
144 const int BluetoothTaskManagerWin::kPollIntervalMs = 500; | 113 const int BluetoothTaskManagerWin::kPollIntervalMs = 500; |
145 | 114 |
146 BluetoothTaskManagerWin::AdapterState::AdapterState() : powered(false) { | 115 BluetoothTaskManagerWin::AdapterState::AdapterState() : powered(false) { |
147 } | 116 } |
148 | 117 |
(...skipping 12 matching lines...) Expand all Loading... |
161 connected(false), | 130 connected(false), |
162 authenticated(false) { | 131 authenticated(false) { |
163 } | 132 } |
164 | 133 |
165 BluetoothTaskManagerWin::DeviceState::~DeviceState() { | 134 BluetoothTaskManagerWin::DeviceState::~DeviceState() { |
166 } | 135 } |
167 | 136 |
168 BluetoothTaskManagerWin::BluetoothTaskManagerWin( | 137 BluetoothTaskManagerWin::BluetoothTaskManagerWin( |
169 scoped_refptr<base::SequencedTaskRunner> ui_task_runner) | 138 scoped_refptr<base::SequencedTaskRunner> ui_task_runner) |
170 : ui_task_runner_(ui_task_runner), | 139 : ui_task_runner_(ui_task_runner), |
171 discovering_(false) { | 140 discovering_(false), |
| 141 current_logging_batch_count_(0) { |
172 } | 142 } |
173 | 143 |
174 BluetoothTaskManagerWin::~BluetoothTaskManagerWin() { | 144 BluetoothTaskManagerWin::~BluetoothTaskManagerWin() { |
175 } | 145 } |
176 | 146 |
177 void BluetoothTaskManagerWin::AddObserver(Observer* observer) { | 147 void BluetoothTaskManagerWin::AddObserver(Observer* observer) { |
178 DCHECK(observer); | 148 DCHECK(observer); |
179 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); | 149 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); |
180 observers_.AddObserver(observer); | 150 observers_.AddObserver(observer); |
181 } | 151 } |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
250 base::Bind(&BluetoothTaskManagerWin::StartDiscovery, this)); | 220 base::Bind(&BluetoothTaskManagerWin::StartDiscovery, this)); |
251 } | 221 } |
252 | 222 |
253 void BluetoothTaskManagerWin::PostStopDiscoveryTask() { | 223 void BluetoothTaskManagerWin::PostStopDiscoveryTask() { |
254 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); | 224 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); |
255 bluetooth_task_runner_->PostTask( | 225 bluetooth_task_runner_->PostTask( |
256 FROM_HERE, | 226 FROM_HERE, |
257 base::Bind(&BluetoothTaskManagerWin::StopDiscovery, this)); | 227 base::Bind(&BluetoothTaskManagerWin::StopDiscovery, this)); |
258 } | 228 } |
259 | 229 |
| 230 void BluetoothTaskManagerWin::LogPollingError(const char* message, |
| 231 int win32_error) { |
| 232 const int kLogPeriodInMilliseconds = 60 * 1000; |
| 233 const int kMaxMessagesPerLogPeriod = 10; |
| 234 |
| 235 // Check if we need to discard this message |
| 236 if (!current_logging_batch_ticks_.is_null()) { |
| 237 if (base::TimeTicks::Now() - current_logging_batch_ticks_ <= |
| 238 base::TimeDelta::FromMilliseconds(kLogPeriodInMilliseconds)) { |
| 239 if (current_logging_batch_count_ >= kMaxMessagesPerLogPeriod) |
| 240 return; |
| 241 } else { |
| 242 // The batch expired, reset it to "null". |
| 243 current_logging_batch_ticks_ = base::TimeTicks(); |
| 244 } |
| 245 } |
| 246 |
| 247 // Keep track of this batch of messages |
| 248 if (current_logging_batch_ticks_.is_null()) { |
| 249 current_logging_batch_ticks_ = base::TimeTicks::Now(); |
| 250 current_logging_batch_count_ = 0; |
| 251 } |
| 252 ++current_logging_batch_count_; |
| 253 |
| 254 // Log the message |
| 255 if (win32_error == 0) |
| 256 LOG(WARNING) << message; |
| 257 else |
| 258 LOG(WARNING) << message << ": " |
| 259 << logging::SystemErrorCodeToString(win32_error); |
| 260 } |
| 261 |
260 void BluetoothTaskManagerWin::OnAdapterStateChanged(const AdapterState* state) { | 262 void BluetoothTaskManagerWin::OnAdapterStateChanged(const AdapterState* state) { |
261 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); | 263 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); |
262 FOR_EACH_OBSERVER(BluetoothTaskManagerWin::Observer, observers_, | 264 FOR_EACH_OBSERVER(BluetoothTaskManagerWin::Observer, observers_, |
263 AdapterStateChanged(*state)); | 265 AdapterStateChanged(*state)); |
264 } | 266 } |
265 | 267 |
266 void BluetoothTaskManagerWin::OnDiscoveryStarted(bool success) { | 268 void BluetoothTaskManagerWin::OnDiscoveryStarted(bool success) { |
267 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); | 269 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); |
268 FOR_EACH_OBSERVER(BluetoothTaskManagerWin::Observer, observers_, | 270 FOR_EACH_OBSERVER(BluetoothTaskManagerWin::Observer, observers_, |
269 DiscoveryStarted(success)); | 271 DiscoveryStarted(success)); |
270 } | 272 } |
271 | 273 |
272 void BluetoothTaskManagerWin::OnDiscoveryStopped() { | 274 void BluetoothTaskManagerWin::OnDiscoveryStopped() { |
273 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); | 275 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); |
274 FOR_EACH_OBSERVER(BluetoothTaskManagerWin::Observer, observers_, | 276 FOR_EACH_OBSERVER(BluetoothTaskManagerWin::Observer, observers_, |
275 DiscoveryStopped()); | 277 DiscoveryStopped()); |
276 } | 278 } |
277 | 279 |
278 void BluetoothTaskManagerWin::OnDevicesUpdated( | 280 void BluetoothTaskManagerWin::OnDevicesPolled( |
279 const ScopedVector<DeviceState>* devices) { | 281 const ScopedVector<DeviceState>* devices) { |
280 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); | 282 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); |
281 FOR_EACH_OBSERVER(BluetoothTaskManagerWin::Observer, observers_, | 283 FOR_EACH_OBSERVER( |
282 DevicesUpdated(*devices)); | 284 BluetoothTaskManagerWin::Observer, observers_, DevicesPolled(*devices)); |
283 } | |
284 | |
285 void BluetoothTaskManagerWin::OnDevicesDiscovered( | |
286 const ScopedVector<DeviceState>* devices) { | |
287 DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); | |
288 FOR_EACH_OBSERVER(BluetoothTaskManagerWin::Observer, observers_, | |
289 DevicesDiscovered(*devices)); | |
290 } | 285 } |
291 | 286 |
292 void BluetoothTaskManagerWin::PollAdapter() { | 287 void BluetoothTaskManagerWin::PollAdapter() { |
293 DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread()); | 288 DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread()); |
294 | 289 |
295 // Skips updating the adapter info if the adapter is in discovery mode. | 290 // Skips updating the adapter info if the adapter is in discovery mode. |
296 if (!discovering_) { | 291 if (!discovering_) { |
297 const BLUETOOTH_FIND_RADIO_PARAMS adapter_param = | 292 const BLUETOOTH_FIND_RADIO_PARAMS adapter_param = |
298 { sizeof(BLUETOOTH_FIND_RADIO_PARAMS) }; | 293 { sizeof(BLUETOOTH_FIND_RADIO_PARAMS) }; |
299 if (adapter_handle_) | 294 if (adapter_handle_) |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
365 } | 360 } |
366 | 361 |
367 void BluetoothTaskManagerWin::StopDiscovery() { | 362 void BluetoothTaskManagerWin::StopDiscovery() { |
368 DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread()); | 363 DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread()); |
369 discovering_ = false; | 364 discovering_ = false; |
370 ui_task_runner_->PostTask( | 365 ui_task_runner_->PostTask( |
371 FROM_HERE, | 366 FROM_HERE, |
372 base::Bind(&BluetoothTaskManagerWin::OnDiscoveryStopped, this)); | 367 base::Bind(&BluetoothTaskManagerWin::OnDiscoveryStopped, this)); |
373 } | 368 } |
374 | 369 |
375 void BluetoothTaskManagerWin::DiscoverDevices(int timeout) { | 370 void BluetoothTaskManagerWin::DiscoverDevices(int timeout_multiplier) { |
376 DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread()); | 371 DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread()); |
377 if (!discovering_ || !adapter_handle_) { | 372 if (!discovering_ || !adapter_handle_) { |
378 ui_task_runner_->PostTask( | 373 ui_task_runner_->PostTask( |
379 FROM_HERE, | 374 FROM_HERE, |
380 base::Bind(&BluetoothTaskManagerWin::OnDiscoveryStopped, this)); | 375 base::Bind(&BluetoothTaskManagerWin::OnDiscoveryStopped, this)); |
381 return; | 376 return; |
382 } | 377 } |
383 | 378 |
384 ScopedVector<DeviceState>* device_list = new ScopedVector<DeviceState>(); | 379 scoped_ptr<ScopedVector<DeviceState> > device_list( |
385 SearchDevices(timeout, false, device_list); | 380 new ScopedVector<DeviceState>()); |
386 if (device_list->empty()) { | 381 if (SearchDevices(timeout_multiplier, false, device_list.get())) { |
387 delete device_list; | |
388 } else { | |
389 DiscoverServices(device_list); | |
390 ui_task_runner_->PostTask( | 382 ui_task_runner_->PostTask( |
391 FROM_HERE, | 383 FROM_HERE, |
392 base::Bind(&BluetoothTaskManagerWin::OnDevicesDiscovered, | 384 base::Bind(&BluetoothTaskManagerWin::OnDevicesPolled, |
393 this, | 385 this, |
394 base::Owned(device_list))); | 386 base::Owned(device_list.release()))); |
395 } | 387 } |
396 | 388 |
397 if (timeout < kMaxDeviceDiscoveryTimeout) { | 389 if (timeout_multiplier < kMaxDeviceDiscoveryTimeoutMultiplier) |
398 bluetooth_task_runner_->PostTask( | 390 ++timeout_multiplier; |
399 FROM_HERE, | 391 bluetooth_task_runner_->PostTask( |
400 base::Bind(&BluetoothTaskManagerWin::DiscoverDevices, | 392 FROM_HERE, |
401 this, | 393 base::Bind( |
402 timeout + 1)); | 394 &BluetoothTaskManagerWin::DiscoverDevices, this, timeout_multiplier)); |
403 } else { | 395 } |
| 396 |
| 397 void BluetoothTaskManagerWin::GetKnownDevices() { |
| 398 scoped_ptr<ScopedVector<DeviceState> > device_list( |
| 399 new ScopedVector<DeviceState>()); |
| 400 if (SearchDevices(1, true, device_list.get())) { |
404 ui_task_runner_->PostTask( | 401 ui_task_runner_->PostTask( |
405 FROM_HERE, | 402 FROM_HERE, |
406 base::Bind(&BluetoothTaskManagerWin::OnDiscoveryStopped, this)); | 403 base::Bind(&BluetoothTaskManagerWin::OnDevicesPolled, |
407 discovering_ = false; | 404 this, |
408 } | 405 base::Owned(device_list.release()))); |
409 } | 406 } |
410 | 407 } |
411 void BluetoothTaskManagerWin::GetKnownDevices() { | 408 |
412 ScopedVector<DeviceState>* device_list = new ScopedVector<DeviceState>(); | 409 bool BluetoothTaskManagerWin::SearchDevices( |
413 SearchDevices(1, true, device_list); | 410 int timeout_multiplier, |
414 | |
415 // Search for Bluetooth Low Energy devices | |
416 if (win::IsBluetoothLowEnergySupported()) { | |
417 ScopedVector<win::BluetoothLowEnergyDeviceInfo> btle_devices; | |
418 std::string error; | |
419 bool success = | |
420 win::EnumerateKnownBluetoothLowEnergyDevices(&btle_devices, &error); | |
421 if (success) { | |
422 for (ScopedVector<win::BluetoothLowEnergyDeviceInfo>::iterator iter = | |
423 btle_devices.begin(); | |
424 iter != btle_devices.end(); | |
425 ++iter) { | |
426 win::BluetoothLowEnergyDeviceInfo* device_info = (*iter); | |
427 | |
428 DeviceState* device_state = new DeviceState(); | |
429 device_state->name = device_info->friendly_name; | |
430 device_state->address = BluetoothAddressToString(device_info->address); | |
431 device_state->visible = device_info->visible; | |
432 device_state->authenticated = device_info->authenticated; | |
433 device_state->connected = device_info->connected; | |
434 device_state->path = device_info->path; | |
435 | |
436 ScopedVector<win::BluetoothLowEnergyServiceInfo> services; | |
437 success = win::EnumerateKnownBluetoothLowEnergyServices( | |
438 device_info, &services, &error); | |
439 if (success) { | |
440 for (ScopedVector<win::BluetoothLowEnergyServiceInfo>::iterator | |
441 iter2 = services.begin(); | |
442 iter2 != services.end(); | |
443 ++iter2) { | |
444 ServiceRecordState* service_state = new ServiceRecordState(); | |
445 service_state->gatt_uuid = | |
446 BluetoothLowEnergyUuidToUBluetoothUuid((*iter2)->uuid); | |
447 device_state->service_record_states.push_back(service_state); | |
448 } | |
449 } | |
450 device_list->push_back(device_state); | |
451 } | |
452 } | |
453 } | |
454 | |
455 if (device_list->empty()) { | |
456 delete device_list; | |
457 return; | |
458 } | |
459 DiscoverServices(device_list); | |
460 ui_task_runner_->PostTask( | |
461 FROM_HERE, | |
462 base::Bind(&BluetoothTaskManagerWin::OnDevicesUpdated, | |
463 this, | |
464 base::Owned(device_list))); | |
465 } | |
466 | |
467 void BluetoothTaskManagerWin::SearchDevices( | |
468 int timeout, | |
469 bool search_cached_devices_only, | 411 bool search_cached_devices_only, |
470 ScopedVector<DeviceState>* device_list) { | 412 ScopedVector<DeviceState>* device_list) { |
471 BLUETOOTH_DEVICE_SEARCH_PARAMS device_search_params = { | 413 return SearchClassicDevices( |
472 sizeof(BLUETOOTH_DEVICE_SEARCH_PARAMS), | 414 timeout_multiplier, search_cached_devices_only, device_list) && |
473 1, // return authenticated devices | 415 SearchLowEnergyDevices(device_list) && |
474 1, // return remembered devicess | 416 DiscoverServices(device_list, search_cached_devices_only); |
475 search_cached_devices_only ? 0 : 1, // return unknown devices | 417 } |
476 1, // return connected devices | 418 |
477 search_cached_devices_only ? 0 : 1, // issue a new inquiry | 419 bool BluetoothTaskManagerWin::SearchClassicDevices( |
478 timeout, // timeout for the inquiry in increments of 1.28 seconds | 420 int timeout_multiplier, |
479 adapter_handle_ | 421 bool search_cached_devices_only, |
480 }; | 422 ScopedVector<DeviceState>* device_list) { |
481 | 423 // Issues a device inquiry and waits for |timeout_multiplier| * 1.28 seconds. |
482 BLUETOOTH_DEVICE_INFO device_info = { sizeof(BLUETOOTH_DEVICE_INFO), 0 }; | 424 BLUETOOTH_DEVICE_SEARCH_PARAMS device_search_params; |
483 // Issues a device inquiry and waits for |timeout| * 1.28 seconds. | 425 ZeroMemory(&device_search_params, sizeof(device_search_params)); |
| 426 device_search_params.dwSize = sizeof(BLUETOOTH_DEVICE_SEARCH_PARAMS); |
| 427 device_search_params.fReturnAuthenticated = 1; |
| 428 device_search_params.fReturnRemembered = 1; |
| 429 device_search_params.fReturnUnknown = (search_cached_devices_only ? 0 : 1); |
| 430 device_search_params.fReturnConnected = 1; |
| 431 device_search_params.fIssueInquiry = (search_cached_devices_only ? 0 : 1); |
| 432 device_search_params.cTimeoutMultiplier = timeout_multiplier; |
| 433 |
| 434 BLUETOOTH_DEVICE_INFO device_info; |
| 435 ZeroMemory(&device_info, sizeof(device_info)); |
| 436 device_info.dwSize = sizeof(BLUETOOTH_DEVICE_INFO); |
484 HBLUETOOTH_DEVICE_FIND handle = | 437 HBLUETOOTH_DEVICE_FIND handle = |
485 BluetoothFindFirstDevice(&device_search_params, &device_info); | 438 BluetoothFindFirstDevice(&device_search_params, &device_info); |
486 if (handle) { | 439 if (!handle) { |
487 do { | 440 int last_error = GetLastError(); |
488 DeviceState* device_state = new DeviceState(); | 441 if (last_error == ERROR_NO_MORE_ITEMS) { |
489 GetDeviceState(device_info, device_state); | 442 return true; // No devices is not an error. |
490 device_list->push_back(device_state); | 443 } |
491 } while (BluetoothFindNextDevice(handle, &device_info)); | 444 LogPollingError("Error calling BluetoothFindFirstDevice", last_error); |
492 | 445 return false; |
493 BluetoothFindDeviceClose(handle); | 446 } |
494 } | 447 |
495 } | 448 while (true) { |
496 | 449 DeviceState* device_state = new DeviceState(); |
497 void BluetoothTaskManagerWin::DiscoverServices( | 450 GetDeviceState(device_info, device_state); |
| 451 device_list->push_back(device_state); |
| 452 |
| 453 // Reset device info before next call (as a safety precaution). |
| 454 ZeroMemory(&device_info, sizeof(device_info)); |
| 455 device_info.dwSize = sizeof(BLUETOOTH_DEVICE_INFO); |
| 456 if (!BluetoothFindNextDevice(handle, &device_info)) { |
| 457 int last_error = GetLastError(); |
| 458 if (last_error == ERROR_NO_MORE_ITEMS) { |
| 459 break; // No more items is expected error when done enumerating. |
| 460 } |
| 461 LogPollingError("Error calling BluetoothFindNextDevice", last_error); |
| 462 BluetoothFindDeviceClose(handle); |
| 463 return false; |
| 464 } |
| 465 } |
| 466 |
| 467 if (!BluetoothFindDeviceClose(handle)) { |
| 468 LogPollingError("Error calling BluetoothFindDeviceClose", GetLastError()); |
| 469 return false; |
| 470 } |
| 471 return true; |
| 472 } |
| 473 |
| 474 bool BluetoothTaskManagerWin::SearchLowEnergyDevices( |
498 ScopedVector<DeviceState>* device_list) { | 475 ScopedVector<DeviceState>* device_list) { |
| 476 if (!win::IsBluetoothLowEnergySupported()) |
| 477 return true; // Bluetooth LE not supported is not an error. |
| 478 |
| 479 ScopedVector<win::BluetoothLowEnergyDeviceInfo> btle_devices; |
| 480 std::string error; |
| 481 bool success = |
| 482 win::EnumerateKnownBluetoothLowEnergyDevices(&btle_devices, &error); |
| 483 if (!success) { |
| 484 LogPollingError(error.c_str(), 0); |
| 485 return false; |
| 486 } |
| 487 |
| 488 for (ScopedVector<win::BluetoothLowEnergyDeviceInfo>::iterator iter = |
| 489 btle_devices.begin(); |
| 490 iter != btle_devices.end(); |
| 491 ++iter) { |
| 492 win::BluetoothLowEnergyDeviceInfo* device_info = (*iter); |
| 493 DeviceState* device_state = new DeviceState(); |
| 494 device_state->name = device_info->friendly_name; |
| 495 device_state->address = |
| 496 BluetoothAddressToCanonicalString(device_info->address); |
| 497 device_state->visible = device_info->visible; |
| 498 device_state->authenticated = device_info->authenticated; |
| 499 device_state->connected = device_info->connected; |
| 500 device_state->path = device_info->path; |
| 501 device_list->push_back(device_state); |
| 502 } |
| 503 return true; |
| 504 } |
| 505 |
| 506 bool BluetoothTaskManagerWin::DiscoverServices( |
| 507 ScopedVector<DeviceState>* device_list, |
| 508 bool search_cached_services_only) { |
499 DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread()); | 509 DCHECK(bluetooth_task_runner_->RunsTasksOnCurrentThread()); |
500 net::EnsureWinsockInit(); | 510 net::EnsureWinsockInit(); |
501 for (ScopedVector<DeviceState>::iterator iter = device_list->begin(); | 511 for (ScopedVector<DeviceState>::iterator iter = device_list->begin(); |
502 iter != device_list->end(); | 512 iter != device_list->end(); |
503 ++iter) { | 513 ++iter) { |
504 const std::string device_address = (*iter)->address; | 514 DeviceState* device = (*iter); |
505 ScopedVector<ServiceRecordState>* service_record_states = | 515 ScopedVector<ServiceRecordState>* service_record_states = |
506 &(*iter)->service_record_states; | 516 &(*iter)->service_record_states; |
507 | 517 |
508 DiscoverDeviceServices( | 518 if ((*iter)->is_bluetooth_classic()) { |
509 device_address, L2CAP_PROTOCOL_UUID, service_record_states); | 519 if (!DiscoverClassicDeviceServices(device->address, |
510 } | 520 L2CAP_PROTOCOL_UUID, |
| 521 search_cached_services_only, |
| 522 service_record_states)) { |
| 523 return false; |
| 524 } |
| 525 } else { |
| 526 if (!DiscoverLowEnergyDeviceServices(device->path, |
| 527 service_record_states)) { |
| 528 return false; |
| 529 } |
| 530 } |
| 531 } |
| 532 return true; |
| 533 } |
| 534 |
| 535 bool BluetoothTaskManagerWin::DiscoverClassicDeviceServices( |
| 536 const std::string& device_address, |
| 537 const GUID& protocol_uuid, |
| 538 bool search_cached_services_only, |
| 539 ScopedVector<ServiceRecordState>* service_record_states) { |
| 540 // Bluetooth and WSAQUERYSET for Service Inquiry. See http://goo.gl/2v9pyt. |
| 541 WSAQUERYSET sdp_query; |
| 542 ZeroMemory(&sdp_query, sizeof(sdp_query)); |
| 543 sdp_query.dwSize = sizeof(sdp_query); |
| 544 GUID protocol = protocol_uuid; |
| 545 sdp_query.lpServiceClassId = &protocol; |
| 546 sdp_query.dwNameSpace = NS_BTH; |
| 547 wchar_t device_address_context[kMaxNumDeviceAddressChar]; |
| 548 std::size_t length = base::SysUTF8ToWide("(" + device_address + ")").copy( |
| 549 device_address_context, kMaxNumDeviceAddressChar); |
| 550 device_address_context[length] = NULL; |
| 551 sdp_query.lpszContext = device_address_context; |
| 552 DWORD control_flags = LUP_RETURN_ALL; |
| 553 // See http://goo.gl/t1Hulo: "Applications should generally specify |
| 554 // LUP_FLUSHCACHE. This flag instructs the system to ignore any cached |
| 555 // information and establish an over-the-air SDP connection to the specified |
| 556 // device to perform the SDP search. This non-cached operation may take |
| 557 // several seconds (whereas a cached search returns quickly)." |
| 558 // In summary, we need to specify LUP_FLUSHCACHE if we want to obtain the list |
| 559 // of services for devices which have not been discovered before. |
| 560 if (!search_cached_services_only) |
| 561 control_flags |= LUP_FLUSHCACHE; |
| 562 HANDLE sdp_handle; |
| 563 if (ERROR_SUCCESS != |
| 564 WSALookupServiceBegin(&sdp_query, control_flags, &sdp_handle)) { |
| 565 LogPollingError("Error calling WSALookupServiceBegin", WSAGetLastError()); |
| 566 return false; |
| 567 } |
| 568 char sdp_buffer[kServiceDiscoveryResultBufferSize]; |
| 569 LPWSAQUERYSET sdp_result_data = reinterpret_cast<LPWSAQUERYSET>(sdp_buffer); |
| 570 while (true) { |
| 571 DWORD sdp_buffer_size = sizeof(sdp_buffer); |
| 572 if (ERROR_SUCCESS != |
| 573 WSALookupServiceNext( |
| 574 sdp_handle, control_flags, &sdp_buffer_size, sdp_result_data)) { |
| 575 int last_error = WSAGetLastError(); |
| 576 if (last_error == WSA_E_NO_MORE || last_error == WSAENOMORE) { |
| 577 break; |
| 578 } |
| 579 LogPollingError("Error calling WSALookupServiceNext", last_error); |
| 580 WSALookupServiceEnd(sdp_handle); |
| 581 return false; |
| 582 } |
| 583 ServiceRecordState* service_record_state = new ServiceRecordState(); |
| 584 service_record_state->name = |
| 585 base::SysWideToUTF8(sdp_result_data->lpszServiceInstanceName); |
| 586 for (uint64 i = 0; i < sdp_result_data->lpBlob->cbSize; i++) { |
| 587 service_record_state->sdp_bytes.push_back( |
| 588 sdp_result_data->lpBlob->pBlobData[i]); |
| 589 } |
| 590 service_record_states->push_back(service_record_state); |
| 591 } |
| 592 if (ERROR_SUCCESS != WSALookupServiceEnd(sdp_handle)) { |
| 593 LogPollingError("Error calling WSALookupServiceEnd", WSAGetLastError()); |
| 594 return false; |
| 595 } |
| 596 |
| 597 return true; |
| 598 } |
| 599 |
| 600 bool BluetoothTaskManagerWin::DiscoverLowEnergyDeviceServices( |
| 601 const base::FilePath& device_path, |
| 602 ScopedVector<ServiceRecordState>* service_record_states) { |
| 603 if (!win::IsBluetoothLowEnergySupported()) |
| 604 return true; // Bluetooth LE not supported is not an error. |
| 605 |
| 606 std::string error; |
| 607 ScopedVector<win::BluetoothLowEnergyServiceInfo> services; |
| 608 bool success = win::EnumerateKnownBluetoothLowEnergyServices( |
| 609 device_path, &services, &error); |
| 610 if (!success) { |
| 611 LogPollingError(error.c_str(), 0); |
| 612 return false; |
| 613 } |
| 614 |
| 615 for (ScopedVector<win::BluetoothLowEnergyServiceInfo>::iterator iter2 = |
| 616 services.begin(); |
| 617 iter2 != services.end(); |
| 618 ++iter2) { |
| 619 ServiceRecordState* service_state = new ServiceRecordState(); |
| 620 service_state->gatt_uuid = |
| 621 BluetoothLowEnergyUuidToBluetoothUuid((*iter2)->uuid); |
| 622 service_record_states->push_back(service_state); |
| 623 } |
| 624 return true; |
511 } | 625 } |
512 | 626 |
513 } // namespace device | 627 } // namespace device |
OLD | NEW |