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
3 // found in the LICENSE file.
5 #include "device/bluetooth/bluetooth_device_mac.h"
9 #include "base/basictypes.h"
10 #include "base/bind.h"
11 #include "base/hash.h"
12 #include "base/mac/sdk_forward_declarations.h"
13 #include "base/sequenced_task_runner.h"
14 #include "base/strings/string_number_conversions.h"
15 #include "base/strings/string_util.h"
16 #include "base/strings/sys_string_conversions.h"
17 #include "device/bluetooth/bluetooth_socket_mac.h"
18 #include "device/bluetooth/bluetooth_uuid.h"
20 // Undocumented API for accessing the Bluetooth transmit power level.
21 // Similar to the API defined here [ http://goo.gl/20Q5vE ].
22 @interface IOBluetoothHostController (UndocumentedAPI)
24 BluetoothHCIReadTransmitPowerLevel:(BluetoothConnectionHandle)connection
25 inType:(BluetoothHCITransmitPowerLevelType)type
26 outTransmitPowerLevel:(BluetoothHCITransmitPowerLevel*)level;
32 // Returns the first (should be, only) UUID contained within the
33 // |service_class_data|. Returns an invalid (empty) UUID if none is found.
34 BluetoothUUID ExtractUuid(IOBluetoothSDPDataElement* service_class_data) {
35 NSArray* inner_elements = [service_class_data getArrayValue];
36 IOBluetoothSDPUUID* sdp_uuid = nil;
37 for (IOBluetoothSDPDataElement* inner_element in inner_elements) {
38 if ([inner_element getTypeDescriptor] == kBluetoothSDPDataElementTypeUUID) {
39 sdp_uuid = [[inner_element getUUIDValue] getUUIDWithLength:16];
45 return BluetoothUUID();
47 const uint8* uuid_bytes = reinterpret_cast<const uint8*>([sdp_uuid bytes]);
48 std::string uuid_str = base::HexEncode(uuid_bytes, 16);
49 DCHECK_EQ(uuid_str.size(), 32U);
50 uuid_str.insert(8, "-");
51 uuid_str.insert(13, "-");
52 uuid_str.insert(18, "-");
53 uuid_str.insert(23, "-");
54 return BluetoothUUID(uuid_str);
59 BluetoothDeviceMac::BluetoothDeviceMac(IOBluetoothDevice* device)
60 : device_([device retain]) {
63 BluetoothDeviceMac::~BluetoothDeviceMac() {
66 void BluetoothDeviceMac::AddObserver(
67 device::BluetoothDevice::Observer* observer) {
69 observers_.AddObserver(observer);
72 void BluetoothDeviceMac::RemoveObserver(
73 device::BluetoothDevice::Observer* observer) {
75 observers_.RemoveObserver(observer);
78 uint32 BluetoothDeviceMac::GetBluetoothClass() const {
79 return [device_ classOfDevice];
82 std::string BluetoothDeviceMac::GetDeviceName() const {
83 return base::SysNSStringToUTF8([device_ name]);
86 std::string BluetoothDeviceMac::GetAddress() const {
87 return GetDeviceAddress(device_);
90 BluetoothDevice::VendorIDSource BluetoothDeviceMac::GetVendorIDSource() const {
91 return VENDOR_ID_UNKNOWN;
94 uint16 BluetoothDeviceMac::GetVendorID() const {
98 uint16 BluetoothDeviceMac::GetProductID() const {
102 uint16 BluetoothDeviceMac::GetDeviceID() const {
106 int BluetoothDeviceMac::GetRSSI() const {
107 if (![device_ isConnected]) {
109 return kUnknownPower;
112 int rssi = [device_ rawRSSI];
114 // The API guarantees that +127 is returned in case the RSSI is not readable:
115 // http://goo.gl/bpURYv
117 return kUnknownPower;
122 int BluetoothDeviceMac::GetCurrentHostTransmitPower() const {
123 return GetHostTransmitPower(kReadCurrentTransmitPowerLevel);
126 int BluetoothDeviceMac::GetMaximumHostTransmitPower() const {
127 return GetHostTransmitPower(kReadMaximumTransmitPowerLevel);
130 bool BluetoothDeviceMac::IsPaired() const {
131 return [device_ isPaired];
134 bool BluetoothDeviceMac::IsConnected() const {
135 return [device_ isConnected];
138 bool BluetoothDeviceMac::IsConnectable() const {
142 bool BluetoothDeviceMac::IsConnecting() const {
146 BluetoothDevice::UUIDList BluetoothDeviceMac::GetUUIDs() const {
148 for (IOBluetoothSDPServiceRecord* service_record in [device_ services]) {
149 IOBluetoothSDPDataElement* service_class_data =
150 [service_record getAttributeDataElement:
151 kBluetoothSDPAttributeIdentifierServiceClassIDList];
152 if ([service_class_data getTypeDescriptor] ==
153 kBluetoothSDPDataElementTypeDataElementSequence) {
154 BluetoothUUID uuid = ExtractUuid(service_class_data);
156 uuids.push_back(uuid);
162 bool BluetoothDeviceMac::ExpectingPinCode() const {
167 bool BluetoothDeviceMac::ExpectingPasskey() const {
172 bool BluetoothDeviceMac::ExpectingConfirmation() const {
177 void BluetoothDeviceMac::Connect(
178 PairingDelegate* pairing_delegate,
179 const base::Closure& callback,
180 const ConnectErrorCallback& error_callback) {
184 void BluetoothDeviceMac::SetPinCode(const std::string& pincode) {
188 void BluetoothDeviceMac::SetPasskey(uint32 passkey) {
192 void BluetoothDeviceMac::ConfirmPairing() {
196 void BluetoothDeviceMac::RejectPairing() {
200 void BluetoothDeviceMac::CancelPairing() {
204 void BluetoothDeviceMac::Disconnect(const base::Closure& callback,
205 const ErrorCallback& error_callback) {
209 void BluetoothDeviceMac::Forget(const ErrorCallback& error_callback) {
213 void BluetoothDeviceMac::ConnectToService(
214 const BluetoothUUID& uuid,
215 const ConnectToServiceCallback& callback,
216 const ConnectToServiceErrorCallback& error_callback) {
217 scoped_refptr<BluetoothSocketMac> socket = BluetoothSocketMac::CreateSocket();
219 device_.get(), uuid, base::Bind(callback, socket), error_callback);
222 void BluetoothDeviceMac::CreateGattConnection(
223 const GattConnectionCallback& callback,
224 const ConnectErrorCallback& error_callback) {
225 // TODO(armansito): Implement.
226 error_callback.Run(ERROR_UNSUPPORTED_DEVICE);
229 void BluetoothDeviceMac::StartConnectionMonitor(
230 const base::Closure& callback,
231 const ErrorCallback& error_callback) {
235 int BluetoothDeviceMac::GetHostTransmitPower(
236 BluetoothHCITransmitPowerLevelType power_level_type) const {
237 IOBluetoothHostController* controller =
238 [IOBluetoothHostController defaultController];
240 // Bail if the undocumented API is unavailable on this machine.
241 SEL selector = @selector(
242 BluetoothHCIReadTransmitPowerLevel:inType:outTransmitPowerLevel:);
243 if (![controller respondsToSelector:selector])
244 return kUnknownPower;
246 BluetoothHCITransmitPowerLevel power_level;
248 [controller BluetoothHCIReadTransmitPowerLevel:[device_ connectionHandle]
249 inType:power_level_type
250 outTransmitPowerLevel:&power_level];
251 if (result != kIOReturnSuccess)
252 return kUnknownPower;
258 std::string BluetoothDeviceMac::GetDeviceAddress(IOBluetoothDevice* device) {
259 return CanonicalizeAddress(base::SysNSStringToUTF8([device addressString]));
262 } // namespace device