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/memory/scoped_ptr.h" | 16 #include "base/memory/scoped_ptr.h" |
18 #include "base/sequenced_task_runner.h" | 17 #include "base/sequenced_task_runner.h" |
19 #include "base/single_thread_task_runner.h" | 18 #include "base/single_thread_task_runner.h" |
20 #include "base/strings/sys_string_conversions.h" | 19 #include "base/strings/sys_string_conversions.h" |
21 #include "base/thread_task_runner_handle.h" | 20 #include "base/thread_task_runner_handle.h" |
22 #include "base/time/time.h" | 21 #include "base/time/time.h" |
23 #include "device/bluetooth/bluetooth_device_mac.h" | 22 #include "device/bluetooth/bluetooth_device_mac.h" |
24 #include "device/bluetooth/bluetooth_socket_mac.h" | 23 #include "device/bluetooth/bluetooth_socket_mac.h" |
25 #include "device/bluetooth/bluetooth_uuid.h" | 24 #include "device/bluetooth/bluetooth_uuid.h" |
26 | 25 |
27 // Replicate specific 10.7 SDK declarations for building with prior SDKs. | 26 // Replicate specific 10.7 SDK declarations for building with prior SDKs. |
28 #if !defined(MAC_OS_X_VERSION_10_7) || \ | 27 #if !defined(MAC_OS_X_VERSION_10_7) || \ |
29 MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7 | 28 MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7 |
30 | 29 |
31 @interface IOBluetoothHostController (LionSDKDeclarations) | 30 @interface IOBluetoothHostController (LionSDKDeclarations) |
32 - (NSString*)nameAsString; | 31 - (NSString*)nameAsString; |
33 - (BluetoothHCIPowerState)powerState; | 32 - (BluetoothHCIPowerState)powerState; |
34 @end | 33 @end |
35 | 34 |
36 @protocol IOBluetoothDeviceInquiryDelegate | |
37 - (void)deviceInquiryStarted:(IOBluetoothDeviceInquiry*)sender; | |
38 - (void)deviceInquiryDeviceFound:(IOBluetoothDeviceInquiry*)sender | |
39 device:(IOBluetoothDevice*)device; | |
40 - (void)deviceInquiryComplete:(IOBluetoothDeviceInquiry*)sender | |
41 error:(IOReturn)error | |
42 aborted:(BOOL)aborted; | |
43 @end | |
44 | |
45 #endif // MAC_OS_X_VERSION_10_7 | 35 #endif // MAC_OS_X_VERSION_10_7 |
46 | 36 |
47 @interface BluetoothAdapterMacDelegate | |
48 : NSObject <IOBluetoothDeviceInquiryDelegate> { | |
49 @private | |
50 device::BluetoothAdapterMac* adapter_; // weak | |
51 } | |
52 | |
53 - (id)initWithAdapter:(device::BluetoothAdapterMac*)adapter; | |
54 | |
55 @end | |
56 | |
57 @implementation BluetoothAdapterMacDelegate | |
58 | |
59 - (id)initWithAdapter:(device::BluetoothAdapterMac*)adapter { | |
60 if ((self = [super init])) | |
61 adapter_ = adapter; | |
62 | |
63 return self; | |
64 } | |
65 | |
66 - (void)deviceInquiryStarted:(IOBluetoothDeviceInquiry*)sender { | |
67 adapter_->DeviceInquiryStarted(sender); | |
68 } | |
69 | |
70 - (void)deviceInquiryDeviceFound:(IOBluetoothDeviceInquiry*)sender | |
71 device:(IOBluetoothDevice*)device { | |
72 adapter_->DeviceFound(sender, device); | |
73 } | |
74 | |
75 - (void)deviceInquiryComplete:(IOBluetoothDeviceInquiry*)sender | |
76 error:(IOReturn)error | |
77 aborted:(BOOL)aborted { | |
78 adapter_->DeviceInquiryComplete(sender, error, aborted); | |
79 } | |
80 | |
81 @end | |
82 | |
83 namespace { | 37 namespace { |
84 | 38 |
85 const int kPollIntervalMs = 500; | 39 const int kPollIntervalMs = 500; |
86 | 40 |
87 } // namespace | 41 } // namespace |
88 | 42 |
89 namespace device { | 43 namespace device { |
90 | 44 |
91 // static | 45 // static |
92 base::WeakPtr<BluetoothAdapter> BluetoothAdapter::CreateAdapter( | 46 base::WeakPtr<BluetoothAdapter> BluetoothAdapter::CreateAdapter( |
93 const InitCallback& init_callback) { | 47 const InitCallback& init_callback) { |
94 return BluetoothAdapterMac::CreateAdapter(); | 48 return BluetoothAdapterMac::CreateAdapter(); |
95 } | 49 } |
96 | 50 |
97 // static | 51 // static |
98 base::WeakPtr<BluetoothAdapter> BluetoothAdapterMac::CreateAdapter() { | 52 base::WeakPtr<BluetoothAdapter> BluetoothAdapterMac::CreateAdapter() { |
99 BluetoothAdapterMac* adapter = new BluetoothAdapterMac(); | 53 BluetoothAdapterMac* adapter = new BluetoothAdapterMac(); |
100 adapter->Init(); | 54 adapter->Init(); |
101 return adapter->weak_ptr_factory_.GetWeakPtr(); | 55 return adapter->weak_ptr_factory_.GetWeakPtr(); |
102 } | 56 } |
103 | 57 |
104 BluetoothAdapterMac::BluetoothAdapterMac() | 58 BluetoothAdapterMac::BluetoothAdapterMac() |
105 : BluetoothAdapter(), | 59 : BluetoothAdapter(), |
106 powered_(false), | 60 powered_(false), |
107 discovery_status_(NOT_DISCOVERING), | 61 num_discovery_sessions_(0), |
108 adapter_delegate_( | 62 classic_discovery_manager_(BluetoothMacDiscoveryManager::CreateClassic()), |
109 [[BluetoothAdapterMacDelegate alloc] initWithAdapter:this]), | |
110 device_inquiry_( | |
111 [[IOBluetoothDeviceInquiry | |
112 inquiryWithDelegate:adapter_delegate_] retain]), | |
113 weak_ptr_factory_(this) { | 63 weak_ptr_factory_(this) { |
64 DCHECK(classic_discovery_manager_.get()); | |
65 classic_discovery_manager_->AddObserver(this); | |
114 } | 66 } |
115 | 67 |
116 BluetoothAdapterMac::~BluetoothAdapterMac() { | 68 BluetoothAdapterMac::~BluetoothAdapterMac() { |
69 classic_discovery_manager_->RemoveObserver(this); | |
117 } | 70 } |
118 | 71 |
119 void BluetoothAdapterMac::AddObserver(BluetoothAdapter::Observer* observer) { | 72 void BluetoothAdapterMac::AddObserver(BluetoothAdapter::Observer* observer) { |
120 DCHECK(observer); | 73 DCHECK(observer); |
121 observers_.AddObserver(observer); | 74 observers_.AddObserver(observer); |
122 } | 75 } |
123 | 76 |
124 void BluetoothAdapterMac::RemoveObserver(BluetoothAdapter::Observer* observer) { | 77 void BluetoothAdapterMac::RemoveObserver(BluetoothAdapter::Observer* observer) { |
125 DCHECK(observer); | 78 DCHECK(observer); |
126 observers_.RemoveObserver(observer); | 79 observers_.RemoveObserver(observer); |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
164 } | 117 } |
165 | 118 |
166 void BluetoothAdapterMac::SetDiscoverable( | 119 void BluetoothAdapterMac::SetDiscoverable( |
167 bool discoverable, | 120 bool discoverable, |
168 const base::Closure& callback, | 121 const base::Closure& callback, |
169 const ErrorCallback& error_callback) { | 122 const ErrorCallback& error_callback) { |
170 NOTIMPLEMENTED(); | 123 NOTIMPLEMENTED(); |
171 } | 124 } |
172 | 125 |
173 bool BluetoothAdapterMac::IsDiscovering() const { | 126 bool BluetoothAdapterMac::IsDiscovering() const { |
174 return discovery_status_ == DISCOVERING || | 127 return classic_discovery_manager_->IsDiscovering(); |
175 discovery_status_ == DISCOVERY_STOPPING; | |
176 } | 128 } |
177 | 129 |
178 void BluetoothAdapterMac::CreateRfcommService( | 130 void BluetoothAdapterMac::CreateRfcommService( |
179 const BluetoothUUID& uuid, | 131 const BluetoothUUID& uuid, |
180 int channel, | 132 int channel, |
181 bool insecure, | 133 bool insecure, |
182 const CreateServiceCallback& callback, | 134 const CreateServiceCallback& callback, |
183 const CreateServiceErrorCallback& error_callback) { | 135 const CreateServiceErrorCallback& error_callback) { |
184 // TODO(keybuk): implement. | 136 // TODO(keybuk): implement. |
185 NOTIMPLEMENTED(); | 137 NOTIMPLEMENTED(); |
186 } | 138 } |
187 | 139 |
188 void BluetoothAdapterMac::CreateL2capService( | 140 void BluetoothAdapterMac::CreateL2capService( |
189 const BluetoothUUID& uuid, | 141 const BluetoothUUID& uuid, |
190 int psm, | 142 int psm, |
191 const CreateServiceCallback& callback, | 143 const CreateServiceCallback& callback, |
192 const CreateServiceErrorCallback& error_callback) { | 144 const CreateServiceErrorCallback& error_callback) { |
193 // TODO(keybuk): implement. | 145 // TODO(keybuk): implement. |
194 NOTIMPLEMENTED(); | 146 NOTIMPLEMENTED(); |
195 } | 147 } |
196 | 148 |
149 void BluetoothAdapterMac::DeviceFound(BluetoothMacDiscoveryManager* manager, | |
150 IOBluetoothDevice* device) { | |
151 std::string device_address = BluetoothDeviceMac::GetDeviceAddress(device); | |
152 if (discovered_devices_.find(device_address) == discovered_devices_.end()) { | |
153 BluetoothDeviceMac device_mac(device); | |
154 FOR_EACH_OBSERVER( | |
155 BluetoothAdapter::Observer, observers_, DeviceAdded(this, &device_mac)); | |
156 discovered_devices_.insert(device_address); | |
157 } | |
158 } | |
159 | |
160 void BluetoothAdapterMac::DiscoveryStopped( | |
161 BluetoothMacDiscoveryManager* manager, | |
162 bool unexpected) { | |
163 if (manager != classic_discovery_manager_.get()) { | |
164 VLOG(1) << "Received \"DiscoveryStopped\" from unknown discovery manager."; | |
165 return; | |
166 } | |
Ilya Sherman
2014/06/10 01:10:59
Can this be a DCHECK rather than a VLOG?
armansito
2014/06/10 21:56:50
Done.
| |
167 if (unexpected) { | |
168 VLOG(1) << "Discovery stopped unexpectedly"; | |
Ilya Sherman
2014/06/10 01:10:59
Out of curiousity, why do we use VLOG rather than
keybuk
2014/06/10 01:13:12
CHROME OS debug builds haven't worked for somethin
Ilya Sherman
2014/06/10 01:14:04
Ok, good to know -- thanks :)
keybuk
2014/06/10 01:21:03
but this is _mac, so doesn't really apply, I was j
armansito
2014/06/10 21:56:50
Done.
| |
169 num_discovery_sessions_ = 0; | |
170 MarkDiscoverySessionsAsInactive(); | |
171 } | |
172 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, | |
173 observers_, | |
174 AdapterDiscoveringChanged(this, false)); | |
175 } | |
176 | |
197 void BluetoothAdapterMac::AddDiscoverySession( | 177 void BluetoothAdapterMac::AddDiscoverySession( |
198 const base::Closure& callback, | 178 const base::Closure& callback, |
199 const ErrorCallback& error_callback) { | 179 const ErrorCallback& error_callback) { |
200 if (discovery_status_ == DISCOVERING) { | 180 VLOG(1) << __func__; |
201 num_discovery_listeners_++; | 181 if (num_discovery_sessions_ > 0) { |
182 DCHECK(IsDiscovering()); | |
183 num_discovery_sessions_++; | |
202 callback.Run(); | 184 callback.Run(); |
203 return; | 185 return; |
204 } | 186 } |
205 on_start_discovery_callbacks_.push_back( | 187 |
206 std::make_pair(callback, error_callback)); | 188 DCHECK(num_discovery_sessions_ == 0); |
Ilya Sherman
2014/06/10 01:10:59
nit: DCHECK_EQ
armansito
2014/06/10 21:56:50
Done.
| |
207 MaybeStartDeviceInquiry(); | 189 |
190 if (!classic_discovery_manager_->StartDiscovery()) { | |
191 VLOG(1) << "Failed to add a discovery session"; | |
192 error_callback.Run(); | |
193 return; | |
194 } | |
195 | |
196 VLOG(1) << "Added a discovery session"; | |
197 num_discovery_sessions_++; | |
198 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, | |
199 observers_, | |
200 AdapterDiscoveringChanged(this, true)); | |
201 callback.Run(); | |
208 } | 202 } |
209 | 203 |
210 void BluetoothAdapterMac::RemoveDiscoverySession( | 204 void BluetoothAdapterMac::RemoveDiscoverySession( |
211 const base::Closure& callback, | 205 const base::Closure& callback, |
212 const ErrorCallback& error_callback) { | 206 const ErrorCallback& error_callback) { |
213 if (discovery_status_ == NOT_DISCOVERING) { | 207 VLOG(1) << __func__; |
208 | |
209 // There are active sessions other than the one currently being removed. | |
Ilya Sherman
2014/06/10 01:10:59
nit: Please move this into the if-stmt. Typically
armansito
2014/06/10 21:56:50
Done.
| |
210 if (num_discovery_sessions_ > 1) { | |
211 DCHECK(IsDiscovering()); | |
212 num_discovery_sessions_--; | |
213 callback.Run(); | |
214 return; | |
215 } | |
216 | |
217 if (num_discovery_sessions_ == 0) { | |
218 VLOG(1) << "No active discovery sessions. Returning error."; | |
214 error_callback.Run(); | 219 error_callback.Run(); |
215 return; | 220 return; |
216 } | 221 } |
217 on_stop_discovery_callbacks_.push_back( | 222 |
218 std::make_pair(callback, error_callback)); | 223 if (!classic_discovery_manager_->StopDiscovery()) { |
219 MaybeStopDeviceInquiry(); | 224 VLOG(1) << "Failed to stop discovery"; |
225 error_callback.Run(); | |
226 return; | |
227 } | |
228 | |
229 VLOG(1) << "Discovery stopped"; | |
230 num_discovery_sessions_--; | |
231 callback.Run(); | |
220 } | 232 } |
221 | 233 |
222 void BluetoothAdapterMac::RemovePairingDelegateInternal( | 234 void BluetoothAdapterMac::RemovePairingDelegateInternal( |
223 BluetoothDevice::PairingDelegate* pairing_delegate) { | 235 BluetoothDevice::PairingDelegate* pairing_delegate) { |
224 } | 236 } |
225 | 237 |
226 void BluetoothAdapterMac::Init() { | 238 void BluetoothAdapterMac::Init() { |
227 ui_task_runner_ = base::ThreadTaskRunnerHandle::Get(); | 239 ui_task_runner_ = base::ThreadTaskRunnerHandle::Get(); |
228 PollAdapter(); | 240 PollAdapter(); |
229 } | 241 } |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
275 } | 287 } |
276 | 288 |
277 ui_task_runner_->PostDelayedTask( | 289 ui_task_runner_->PostDelayedTask( |
278 FROM_HERE, | 290 FROM_HERE, |
279 base::Bind(&BluetoothAdapterMac::PollAdapter, | 291 base::Bind(&BluetoothAdapterMac::PollAdapter, |
280 weak_ptr_factory_.GetWeakPtr()), | 292 weak_ptr_factory_.GetWeakPtr()), |
281 base::TimeDelta::FromMilliseconds(kPollIntervalMs)); | 293 base::TimeDelta::FromMilliseconds(kPollIntervalMs)); |
282 } | 294 } |
283 | 295 |
284 void BluetoothAdapterMac::UpdateDevices(NSArray* devices) { | 296 void BluetoothAdapterMac::UpdateDevices(NSArray* devices) { |
297 // TODO(armansito): This code never calls | |
298 // BluetoothAdapter::Observer::DeviceRemoved. It should, if a device | |
299 // no longer exists. | |
285 STLDeleteValues(&devices_); | 300 STLDeleteValues(&devices_); |
286 for (IOBluetoothDevice* device in devices) { | 301 for (IOBluetoothDevice* device in devices) { |
287 std::string device_address = BluetoothDeviceMac::GetDeviceAddress(device); | 302 std::string device_address = BluetoothDeviceMac::GetDeviceAddress(device); |
288 devices_[device_address] = new BluetoothDeviceMac(device); | 303 devices_[device_address] = new BluetoothDeviceMac(device); |
289 } | 304 } |
290 } | 305 } |
291 | 306 |
292 void BluetoothAdapterMac::DeviceInquiryStarted( | |
293 IOBluetoothDeviceInquiry* inquiry) { | |
294 DCHECK_EQ(device_inquiry_, inquiry); | |
295 if (discovery_status_ == DISCOVERING) | |
296 return; | |
297 | |
298 discovery_status_ = DISCOVERING; | |
299 RunCallbacks(on_start_discovery_callbacks_, true); | |
300 num_discovery_listeners_ = on_start_discovery_callbacks_.size(); | |
301 on_start_discovery_callbacks_.clear(); | |
302 | |
303 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_, | |
304 AdapterDiscoveringChanged(this, true)); | |
305 MaybeStopDeviceInquiry(); | |
306 } | |
307 | |
308 void BluetoothAdapterMac::DeviceFound(IOBluetoothDeviceInquiry* inquiry, | |
309 IOBluetoothDevice* device) { | |
310 DCHECK_EQ(device_inquiry_, inquiry); | |
311 std::string device_address = BluetoothDeviceMac::GetDeviceAddress(device); | |
312 if (discovered_devices_.find(device_address) == discovered_devices_.end()) { | |
313 BluetoothDeviceMac device_mac(device); | |
314 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_, | |
315 DeviceAdded(this, &device_mac)); | |
316 discovered_devices_.insert(device_address); | |
317 } | |
318 } | |
319 | |
320 void BluetoothAdapterMac::DeviceInquiryComplete( | |
321 IOBluetoothDeviceInquiry* inquiry, | |
322 IOReturn error, | |
323 bool aborted) { | |
324 DCHECK_EQ(device_inquiry_, inquiry); | |
325 if (discovery_status_ == DISCOVERING && | |
326 [device_inquiry_ start] == kIOReturnSuccess) { | |
327 return; | |
328 } | |
329 | |
330 // Device discovery is done. | |
331 discovered_devices_.clear(); | |
332 discovery_status_ = NOT_DISCOVERING; | |
333 RunCallbacks(on_stop_discovery_callbacks_, error == kIOReturnSuccess); | |
334 num_discovery_listeners_ = 0; | |
335 on_stop_discovery_callbacks_.clear(); | |
336 FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_, | |
337 AdapterDiscoveringChanged(this, false)); | |
338 MaybeStartDeviceInquiry(); | |
339 } | |
340 | |
341 void BluetoothAdapterMac::MaybeStartDeviceInquiry() { | |
342 if (discovery_status_ == NOT_DISCOVERING && | |
343 !on_start_discovery_callbacks_.empty()) { | |
344 discovery_status_ = DISCOVERY_STARTING; | |
345 if ([device_inquiry_ start] != kIOReturnSuccess) { | |
346 discovery_status_ = NOT_DISCOVERING; | |
347 RunCallbacks(on_start_discovery_callbacks_, false); | |
348 on_start_discovery_callbacks_.clear(); | |
349 } | |
350 } | |
351 } | |
352 | |
353 void BluetoothAdapterMac::MaybeStopDeviceInquiry() { | |
354 if (discovery_status_ != DISCOVERING) | |
355 return; | |
356 | |
357 if (on_stop_discovery_callbacks_.size() < num_discovery_listeners_) { | |
358 RunCallbacks(on_stop_discovery_callbacks_, true); | |
359 num_discovery_listeners_ -= on_stop_discovery_callbacks_.size(); | |
360 on_stop_discovery_callbacks_.clear(); | |
361 return; | |
362 } | |
363 | |
364 discovery_status_ = DISCOVERY_STOPPING; | |
365 if ([device_inquiry_ stop] != kIOReturnSuccess) { | |
366 RunCallbacks(on_stop_discovery_callbacks_, false); | |
367 on_stop_discovery_callbacks_.clear(); | |
368 } | |
369 } | |
370 | |
371 void BluetoothAdapterMac::RunCallbacks( | |
372 const DiscoveryCallbackList& callback_list, bool success) const { | |
373 for (DiscoveryCallbackList::const_iterator iter = callback_list.begin(); | |
374 iter != callback_list.end(); | |
375 ++iter) { | |
376 if (success) | |
377 ui_task_runner_->PostTask(FROM_HERE, iter->first); | |
378 else | |
379 ui_task_runner_->PostTask(FROM_HERE, iter->second); | |
380 } | |
381 } | |
382 | |
383 } // namespace device | 307 } // namespace device |
OLD | NEW |