OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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_adapter_mac.h" | 5 #include "device/bluetooth/bluetooth_adapter_mac.h" |
6 | 6 |
7 #import <IOBluetooth/objc/IOBluetoothDevice.h> | 7 #import <IOBluetooth/objc/IOBluetoothDevice.h> |
8 #import <IOBluetooth/objc/IOBluetoothDeviceInquiry.h> | |
9 #import <IOBluetooth/objc/IOBluetoothHostController.h> | 8 #import <IOBluetooth/objc/IOBluetoothHostController.h> |
10 | 9 |
11 #include <string> | 10 #include <string> |
12 | 11 |
13 #include "base/bind.h" | 12 #include "base/bind.h" |
14 #include "base/compiler_specific.h" | 13 #include "base/compiler_specific.h" |
15 #include "base/containers/hash_tables.h" | 14 #include "base/containers/hash_tables.h" |
16 #include "base/location.h" | 15 #include "base/location.h" |
17 #include "base/mac/sdk_forward_declarations.h" | 16 #include "base/mac/sdk_forward_declarations.h" |
18 #include "base/memory/scoped_ptr.h" | 17 #include "base/memory/scoped_ptr.h" |
19 #include "base/sequenced_task_runner.h" | 18 #include "base/sequenced_task_runner.h" |
20 #include "base/single_thread_task_runner.h" | 19 #include "base/single_thread_task_runner.h" |
21 #include "base/strings/sys_string_conversions.h" | 20 #include "base/strings/sys_string_conversions.h" |
22 #include "base/thread_task_runner_handle.h" | 21 #include "base/thread_task_runner_handle.h" |
23 #include "base/time/time.h" | 22 #include "base/time/time.h" |
24 #include "device/bluetooth/bluetooth_device_mac.h" | 23 #include "device/bluetooth/bluetooth_device_mac.h" |
25 #include "device/bluetooth/bluetooth_socket_mac.h" | 24 #include "device/bluetooth/bluetooth_socket_mac.h" |
26 #include "device/bluetooth/bluetooth_uuid.h" | 25 #include "device/bluetooth/bluetooth_uuid.h" |
27 | 26 |
28 @interface BluetoothAdapterMacDelegate | |
29 : NSObject <IOBluetoothDeviceInquiryDelegate> { | |
30 @private | |
31 device::BluetoothAdapterMac* adapter_; // weak | |
32 } | |
33 | |
34 - (id)initWithAdapter:(device::BluetoothAdapterMac*)adapter; | |
35 | |
36 @end | |
37 | |
38 @implementation BluetoothAdapterMacDelegate | |
39 | |
40 - (id)initWithAdapter:(device::BluetoothAdapterMac*)adapter { | |
41 if ((self = [super init])) | |
42 adapter_ = adapter; | |
43 | |
44 return self; | |
45 } | |
46 | |
47 - (void)deviceInquiryStarted:(IOBluetoothDeviceInquiry*)sender { | |
48 adapter_->DeviceInquiryStarted(sender); | |
49 } | |
50 | |
51 - (void)deviceInquiryDeviceFound:(IOBluetoothDeviceInquiry*)sender | |
52 device:(IOBluetoothDevice*)device { | |
53 adapter_->DeviceFound(sender, device); | |
54 } | |
55 | |
56 - (void)deviceInquiryComplete:(IOBluetoothDeviceInquiry*)sender | |
57 error:(IOReturn)error | |
58 aborted:(BOOL)aborted { | |
59 adapter_->DeviceInquiryComplete(sender, error, aborted); | |
60 } | |
61 | |
62 @end | |
63 | |
64 namespace { | 27 namespace { |
65 | 28 |
66 const int kPollIntervalMs = 500; | 29 const int kPollIntervalMs = 500; |
67 | 30 |
68 } // namespace | 31 } // namespace |
69 | 32 |
70 namespace device { | 33 namespace device { |
71 | 34 |
72 // static | 35 // static |
73 base::WeakPtr<BluetoothAdapter> BluetoothAdapter::CreateAdapter( | 36 base::WeakPtr<BluetoothAdapter> BluetoothAdapter::CreateAdapter( |
74 const InitCallback& init_callback) { | 37 const InitCallback& init_callback) { |
75 return BluetoothAdapterMac::CreateAdapter(); | 38 return BluetoothAdapterMac::CreateAdapter(); |
76 } | 39 } |
77 | 40 |
78 // static | 41 // static |
79 base::WeakPtr<BluetoothAdapter> BluetoothAdapterMac::CreateAdapter() { | 42 base::WeakPtr<BluetoothAdapter> BluetoothAdapterMac::CreateAdapter() { |
80 BluetoothAdapterMac* adapter = new BluetoothAdapterMac(); | 43 BluetoothAdapterMac* adapter = new BluetoothAdapterMac(); |
81 adapter->Init(); | 44 adapter->Init(); |
82 return adapter->weak_ptr_factory_.GetWeakPtr(); | 45 return adapter->weak_ptr_factory_.GetWeakPtr(); |
83 } | 46 } |
84 | 47 |
85 BluetoothAdapterMac::BluetoothAdapterMac() | 48 BluetoothAdapterMac::BluetoothAdapterMac() |
86 : BluetoothAdapter(), | 49 : BluetoothAdapter(), |
87 powered_(false), | 50 powered_(false), |
88 discovery_status_(NOT_DISCOVERING), | 51 num_discovery_sessions_(0), |
89 adapter_delegate_( | 52 classic_discovery_manager_( |
90 [[BluetoothAdapterMacDelegate alloc] initWithAdapter:this]), | 53 BluetoothDiscoveryManagerMac::CreateClassic(this)), |
91 device_inquiry_( | |
92 [[IOBluetoothDeviceInquiry | |
93 inquiryWithDelegate:adapter_delegate_] retain]), | |
94 weak_ptr_factory_(this) { | 54 weak_ptr_factory_(this) { |
| 55 DCHECK(classic_discovery_manager_.get()); |
95 } | 56 } |
96 | 57 |
97 BluetoothAdapterMac::~BluetoothAdapterMac() { | 58 BluetoothAdapterMac::~BluetoothAdapterMac() { |
98 } | 59 } |
99 | 60 |
100 void BluetoothAdapterMac::AddObserver(BluetoothAdapter::Observer* observer) { | 61 void BluetoothAdapterMac::AddObserver(BluetoothAdapter::Observer* observer) { |
101 DCHECK(observer); | 62 DCHECK(observer); |
102 observers_.AddObserver(observer); | 63 observers_.AddObserver(observer); |
103 } | 64 } |
104 | 65 |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
145 } | 106 } |
146 | 107 |
147 void BluetoothAdapterMac::SetDiscoverable( | 108 void BluetoothAdapterMac::SetDiscoverable( |
148 bool discoverable, | 109 bool discoverable, |
149 const base::Closure& callback, | 110 const base::Closure& callback, |
150 const ErrorCallback& error_callback) { | 111 const ErrorCallback& error_callback) { |
151 NOTIMPLEMENTED(); | 112 NOTIMPLEMENTED(); |
152 } | 113 } |
153 | 114 |
154 bool BluetoothAdapterMac::IsDiscovering() const { | 115 bool BluetoothAdapterMac::IsDiscovering() const { |
155 return discovery_status_ == DISCOVERING || | 116 return classic_discovery_manager_->IsDiscovering(); |
156 discovery_status_ == DISCOVERY_STOPPING; | |
157 } | 117 } |
158 | 118 |
159 void BluetoothAdapterMac::CreateRfcommService( | 119 void BluetoothAdapterMac::CreateRfcommService( |
160 const BluetoothUUID& uuid, | 120 const BluetoothUUID& uuid, |
161 int channel, | 121 int channel, |
162 const CreateServiceCallback& callback, | 122 const CreateServiceCallback& callback, |
163 const CreateServiceErrorCallback& error_callback) { | 123 const CreateServiceErrorCallback& error_callback) { |
164 scoped_refptr<BluetoothSocketMac> socket = BluetoothSocketMac::CreateSocket(); | 124 scoped_refptr<BluetoothSocketMac> socket = BluetoothSocketMac::CreateSocket(); |
165 socket->ListenUsingRfcomm( | 125 socket->ListenUsingRfcomm( |
166 this, uuid, channel, base::Bind(callback, socket), error_callback); | 126 this, uuid, channel, base::Bind(callback, socket), error_callback); |
167 } | 127 } |
168 | 128 |
169 void BluetoothAdapterMac::CreateL2capService( | 129 void BluetoothAdapterMac::CreateL2capService( |
170 const BluetoothUUID& uuid, | 130 const BluetoothUUID& uuid, |
171 int psm, | 131 int psm, |
172 const CreateServiceCallback& callback, | 132 const CreateServiceCallback& callback, |
173 const CreateServiceErrorCallback& error_callback) { | 133 const CreateServiceErrorCallback& error_callback) { |
174 scoped_refptr<BluetoothSocketMac> socket = BluetoothSocketMac::CreateSocket(); | 134 scoped_refptr<BluetoothSocketMac> socket = BluetoothSocketMac::CreateSocket(); |
175 socket->ListenUsingL2cap( | 135 socket->ListenUsingL2cap( |
176 this, uuid, psm, base::Bind(callback, socket), error_callback); | 136 this, uuid, psm, base::Bind(callback, socket), error_callback); |
177 } | 137 } |
178 | 138 |
| 139 void BluetoothAdapterMac::DeviceFound(BluetoothDiscoveryManagerMac* manager, |
| 140 IOBluetoothDevice* device) { |
| 141 std::string device_address = BluetoothDeviceMac::GetDeviceAddress(device); |
| 142 if (discovered_devices_.find(device_address) == discovered_devices_.end()) { |
| 143 BluetoothDeviceMac device_mac(device); |
| 144 FOR_EACH_OBSERVER( |
| 145 BluetoothAdapter::Observer, observers_, DeviceAdded(this, &device_mac)); |
| 146 discovered_devices_.insert(device_address); |
| 147 } |
| 148 } |
| 149 |
| 150 void BluetoothAdapterMac::DiscoveryStopped( |
| 151 BluetoothDiscoveryManagerMac* manager, |
| 152 bool unexpected) { |
| 153 DCHECK_EQ(manager, classic_discovery_manager_.get()); |
| 154 if (unexpected) { |
| 155 DVLOG(1) << "Discovery stopped unexpectedly"; |
| 156 num_discovery_sessions_ = 0; |
| 157 MarkDiscoverySessionsAsInactive(); |
| 158 } |
| 159 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, |
| 160 observers_, |
| 161 AdapterDiscoveringChanged(this, false)); |
| 162 } |
| 163 |
179 void BluetoothAdapterMac::AddDiscoverySession( | 164 void BluetoothAdapterMac::AddDiscoverySession( |
180 const base::Closure& callback, | 165 const base::Closure& callback, |
181 const ErrorCallback& error_callback) { | 166 const ErrorCallback& error_callback) { |
182 if (discovery_status_ == DISCOVERING) { | 167 DVLOG(1) << __func__; |
183 num_discovery_listeners_++; | 168 if (num_discovery_sessions_ > 0) { |
| 169 DCHECK(IsDiscovering()); |
| 170 num_discovery_sessions_++; |
184 callback.Run(); | 171 callback.Run(); |
185 return; | 172 return; |
186 } | 173 } |
187 on_start_discovery_callbacks_.push_back( | 174 |
188 std::make_pair(callback, error_callback)); | 175 DCHECK_EQ(0, num_discovery_sessions_); |
189 MaybeStartDeviceInquiry(); | 176 |
| 177 if (!classic_discovery_manager_->StartDiscovery()) { |
| 178 DVLOG(1) << "Failed to add a discovery session"; |
| 179 error_callback.Run(); |
| 180 return; |
| 181 } |
| 182 |
| 183 DVLOG(1) << "Added a discovery session"; |
| 184 num_discovery_sessions_++; |
| 185 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, |
| 186 observers_, |
| 187 AdapterDiscoveringChanged(this, true)); |
| 188 callback.Run(); |
190 } | 189 } |
191 | 190 |
192 void BluetoothAdapterMac::RemoveDiscoverySession( | 191 void BluetoothAdapterMac::RemoveDiscoverySession( |
193 const base::Closure& callback, | 192 const base::Closure& callback, |
194 const ErrorCallback& error_callback) { | 193 const ErrorCallback& error_callback) { |
195 if (discovery_status_ == NOT_DISCOVERING) { | 194 DVLOG(1) << __func__; |
| 195 |
| 196 if (num_discovery_sessions_ > 1) { |
| 197 // There are active sessions other than the one currently being removed. |
| 198 DCHECK(IsDiscovering()); |
| 199 num_discovery_sessions_--; |
| 200 callback.Run(); |
| 201 return; |
| 202 } |
| 203 |
| 204 if (num_discovery_sessions_ == 0) { |
| 205 DVLOG(1) << "No active discovery sessions. Returning error."; |
196 error_callback.Run(); | 206 error_callback.Run(); |
197 return; | 207 return; |
198 } | 208 } |
199 on_stop_discovery_callbacks_.push_back( | 209 |
200 std::make_pair(callback, error_callback)); | 210 if (!classic_discovery_manager_->StopDiscovery()) { |
201 MaybeStopDeviceInquiry(); | 211 DVLOG(1) << "Failed to stop discovery"; |
| 212 error_callback.Run(); |
| 213 return; |
| 214 } |
| 215 |
| 216 DVLOG(1) << "Discovery stopped"; |
| 217 num_discovery_sessions_--; |
| 218 callback.Run(); |
202 } | 219 } |
203 | 220 |
204 void BluetoothAdapterMac::RemovePairingDelegateInternal( | 221 void BluetoothAdapterMac::RemovePairingDelegateInternal( |
205 BluetoothDevice::PairingDelegate* pairing_delegate) { | 222 BluetoothDevice::PairingDelegate* pairing_delegate) { |
206 } | 223 } |
207 | 224 |
208 void BluetoothAdapterMac::Init() { | 225 void BluetoothAdapterMac::Init() { |
209 ui_task_runner_ = base::ThreadTaskRunnerHandle::Get(); | 226 ui_task_runner_ = base::ThreadTaskRunnerHandle::Get(); |
210 PollAdapter(); | 227 PollAdapter(); |
211 } | 228 } |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
257 } | 274 } |
258 | 275 |
259 ui_task_runner_->PostDelayedTask( | 276 ui_task_runner_->PostDelayedTask( |
260 FROM_HERE, | 277 FROM_HERE, |
261 base::Bind(&BluetoothAdapterMac::PollAdapter, | 278 base::Bind(&BluetoothAdapterMac::PollAdapter, |
262 weak_ptr_factory_.GetWeakPtr()), | 279 weak_ptr_factory_.GetWeakPtr()), |
263 base::TimeDelta::FromMilliseconds(kPollIntervalMs)); | 280 base::TimeDelta::FromMilliseconds(kPollIntervalMs)); |
264 } | 281 } |
265 | 282 |
266 void BluetoothAdapterMac::UpdateDevices(NSArray* devices) { | 283 void BluetoothAdapterMac::UpdateDevices(NSArray* devices) { |
| 284 // TODO(armansito): This code never calls |
| 285 // BluetoothAdapter::Observer::DeviceRemoved. It should, if a device |
| 286 // no longer exists. |
267 STLDeleteValues(&devices_); | 287 STLDeleteValues(&devices_); |
268 for (IOBluetoothDevice* device in devices) { | 288 for (IOBluetoothDevice* device in devices) { |
269 std::string device_address = BluetoothDeviceMac::GetDeviceAddress(device); | 289 std::string device_address = BluetoothDeviceMac::GetDeviceAddress(device); |
270 devices_[device_address] = new BluetoothDeviceMac(device); | 290 devices_[device_address] = new BluetoothDeviceMac(device); |
271 } | 291 } |
272 } | 292 } |
273 | 293 |
274 void BluetoothAdapterMac::DeviceInquiryStarted( | |
275 IOBluetoothDeviceInquiry* inquiry) { | |
276 DCHECK_EQ(device_inquiry_, inquiry); | |
277 if (discovery_status_ == DISCOVERING) | |
278 return; | |
279 | |
280 discovery_status_ = DISCOVERING; | |
281 RunCallbacks(on_start_discovery_callbacks_, true); | |
282 num_discovery_listeners_ = on_start_discovery_callbacks_.size(); | |
283 on_start_discovery_callbacks_.clear(); | |
284 | |
285 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_, | |
286 AdapterDiscoveringChanged(this, true)); | |
287 MaybeStopDeviceInquiry(); | |
288 } | |
289 | |
290 void BluetoothAdapterMac::DeviceFound(IOBluetoothDeviceInquiry* inquiry, | |
291 IOBluetoothDevice* device) { | |
292 DCHECK_EQ(device_inquiry_, inquiry); | |
293 std::string device_address = BluetoothDeviceMac::GetDeviceAddress(device); | |
294 if (discovered_devices_.find(device_address) == discovered_devices_.end()) { | |
295 BluetoothDeviceMac device_mac(device); | |
296 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_, | |
297 DeviceAdded(this, &device_mac)); | |
298 discovered_devices_.insert(device_address); | |
299 } | |
300 } | |
301 | |
302 void BluetoothAdapterMac::DeviceInquiryComplete( | |
303 IOBluetoothDeviceInquiry* inquiry, | |
304 IOReturn error, | |
305 bool aborted) { | |
306 DCHECK_EQ(device_inquiry_, inquiry); | |
307 if (discovery_status_ == DISCOVERING && | |
308 [device_inquiry_ start] == kIOReturnSuccess) { | |
309 return; | |
310 } | |
311 | |
312 // Device discovery is done. | |
313 discovered_devices_.clear(); | |
314 discovery_status_ = NOT_DISCOVERING; | |
315 RunCallbacks(on_stop_discovery_callbacks_, error == kIOReturnSuccess); | |
316 num_discovery_listeners_ = 0; | |
317 on_stop_discovery_callbacks_.clear(); | |
318 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_, | |
319 AdapterDiscoveringChanged(this, false)); | |
320 MaybeStartDeviceInquiry(); | |
321 } | |
322 | |
323 void BluetoothAdapterMac::MaybeStartDeviceInquiry() { | |
324 if (discovery_status_ == NOT_DISCOVERING && | |
325 !on_start_discovery_callbacks_.empty()) { | |
326 discovery_status_ = DISCOVERY_STARTING; | |
327 if ([device_inquiry_ start] != kIOReturnSuccess) { | |
328 discovery_status_ = NOT_DISCOVERING; | |
329 RunCallbacks(on_start_discovery_callbacks_, false); | |
330 on_start_discovery_callbacks_.clear(); | |
331 } | |
332 } | |
333 } | |
334 | |
335 void BluetoothAdapterMac::MaybeStopDeviceInquiry() { | |
336 if (discovery_status_ != DISCOVERING) | |
337 return; | |
338 | |
339 if (on_stop_discovery_callbacks_.size() < num_discovery_listeners_) { | |
340 RunCallbacks(on_stop_discovery_callbacks_, true); | |
341 num_discovery_listeners_ -= on_stop_discovery_callbacks_.size(); | |
342 on_stop_discovery_callbacks_.clear(); | |
343 return; | |
344 } | |
345 | |
346 discovery_status_ = DISCOVERY_STOPPING; | |
347 if ([device_inquiry_ stop] != kIOReturnSuccess) { | |
348 RunCallbacks(on_stop_discovery_callbacks_, false); | |
349 on_stop_discovery_callbacks_.clear(); | |
350 } | |
351 } | |
352 | |
353 void BluetoothAdapterMac::RunCallbacks( | |
354 const DiscoveryCallbackList& callback_list, bool success) const { | |
355 for (DiscoveryCallbackList::const_iterator iter = callback_list.begin(); | |
356 iter != callback_list.end(); | |
357 ++iter) { | |
358 if (success) | |
359 ui_task_runner_->PostTask(FROM_HERE, iter->first); | |
360 else | |
361 ui_task_runner_->PostTask(FROM_HERE, iter->second); | |
362 } | |
363 } | |
364 | |
365 } // namespace device | 294 } // namespace device |
OLD | NEW |