Home | History | Annotate | Download | only in bluetooth
      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.
      4 
      5 #include "device/bluetooth/bluetooth_device_mac.h"
      6 
      7 #include <string>
      8 
      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"
     19 
     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)
     23 - (IOReturn)
     24     BluetoothHCIReadTransmitPowerLevel:(BluetoothConnectionHandle)connection
     25                                 inType:(BluetoothHCITransmitPowerLevelType)type
     26                  outTransmitPowerLevel:(BluetoothHCITransmitPowerLevel*)level;
     27 @end
     28 
     29 namespace device {
     30 namespace {
     31 
     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];
     40       break;
     41     }
     42   }
     43 
     44   if (!sdp_uuid)
     45     return BluetoothUUID();
     46 
     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);
     55 }
     56 
     57 }  // namespace
     58 
     59 BluetoothDeviceMac::BluetoothDeviceMac(IOBluetoothDevice* device)
     60     : device_([device retain]) {
     61 }
     62 
     63 BluetoothDeviceMac::~BluetoothDeviceMac() {
     64 }
     65 
     66 uint32 BluetoothDeviceMac::GetBluetoothClass() const {
     67   return [device_ classOfDevice];
     68 }
     69 
     70 std::string BluetoothDeviceMac::GetDeviceName() const {
     71   return base::SysNSStringToUTF8([device_ name]);
     72 }
     73 
     74 std::string BluetoothDeviceMac::GetAddress() const {
     75   return GetDeviceAddress(device_);
     76 }
     77 
     78 BluetoothDevice::VendorIDSource BluetoothDeviceMac::GetVendorIDSource() const {
     79   return VENDOR_ID_UNKNOWN;
     80 }
     81 
     82 uint16 BluetoothDeviceMac::GetVendorID() const {
     83   return 0;
     84 }
     85 
     86 uint16 BluetoothDeviceMac::GetProductID() const {
     87   return 0;
     88 }
     89 
     90 uint16 BluetoothDeviceMac::GetDeviceID() const {
     91   return 0;
     92 }
     93 
     94 int BluetoothDeviceMac::GetRSSI() const {
     95   if (![device_ isConnected]) {
     96     NOTIMPLEMENTED();
     97     return kUnknownPower;
     98   }
     99 
    100   int rssi = [device_ rawRSSI];
    101 
    102   // The API guarantees that +127 is returned in case the RSSI is not readable:
    103   // http://goo.gl/bpURYv
    104   if (rssi == 127)
    105     return kUnknownPower;
    106 
    107   return rssi;
    108 }
    109 
    110 int BluetoothDeviceMac::GetCurrentHostTransmitPower() const {
    111   return GetHostTransmitPower(kReadCurrentTransmitPowerLevel);
    112 }
    113 
    114 int BluetoothDeviceMac::GetMaximumHostTransmitPower() const {
    115   return GetHostTransmitPower(kReadMaximumTransmitPowerLevel);
    116 }
    117 
    118 bool BluetoothDeviceMac::IsPaired() const {
    119   return [device_ isPaired];
    120 }
    121 
    122 bool BluetoothDeviceMac::IsConnected() const {
    123   return [device_ isConnected];
    124 }
    125 
    126 bool BluetoothDeviceMac::IsConnectable() const {
    127   return false;
    128 }
    129 
    130 bool BluetoothDeviceMac::IsConnecting() const {
    131   return false;
    132 }
    133 
    134 BluetoothDevice::UUIDList BluetoothDeviceMac::GetUUIDs() const {
    135   UUIDList uuids;
    136   for (IOBluetoothSDPServiceRecord* service_record in [device_ services]) {
    137     IOBluetoothSDPDataElement* service_class_data =
    138         [service_record getAttributeDataElement:
    139             kBluetoothSDPAttributeIdentifierServiceClassIDList];
    140     if ([service_class_data getTypeDescriptor] ==
    141             kBluetoothSDPDataElementTypeDataElementSequence) {
    142       BluetoothUUID uuid = ExtractUuid(service_class_data);
    143       if (uuid.IsValid())
    144         uuids.push_back(uuid);
    145     }
    146   }
    147   return uuids;
    148 }
    149 
    150 bool BluetoothDeviceMac::ExpectingPinCode() const {
    151   NOTIMPLEMENTED();
    152   return false;
    153 }
    154 
    155 bool BluetoothDeviceMac::ExpectingPasskey() const {
    156   NOTIMPLEMENTED();
    157   return false;
    158 }
    159 
    160 bool BluetoothDeviceMac::ExpectingConfirmation() const {
    161   NOTIMPLEMENTED();
    162   return false;
    163 }
    164 
    165 void BluetoothDeviceMac::Connect(
    166     PairingDelegate* pairing_delegate,
    167     const base::Closure& callback,
    168     const ConnectErrorCallback& error_callback) {
    169   NOTIMPLEMENTED();
    170 }
    171 
    172 void BluetoothDeviceMac::SetPinCode(const std::string& pincode) {
    173   NOTIMPLEMENTED();
    174 }
    175 
    176 void BluetoothDeviceMac::SetPasskey(uint32 passkey) {
    177   NOTIMPLEMENTED();
    178 }
    179 
    180 void BluetoothDeviceMac::ConfirmPairing() {
    181   NOTIMPLEMENTED();
    182 }
    183 
    184 void BluetoothDeviceMac::RejectPairing() {
    185   NOTIMPLEMENTED();
    186 }
    187 
    188 void BluetoothDeviceMac::CancelPairing() {
    189   NOTIMPLEMENTED();
    190 }
    191 
    192 void BluetoothDeviceMac::Disconnect(const base::Closure& callback,
    193                                     const ErrorCallback& error_callback) {
    194   NOTIMPLEMENTED();
    195 }
    196 
    197 void BluetoothDeviceMac::Forget(const ErrorCallback& error_callback) {
    198   NOTIMPLEMENTED();
    199 }
    200 
    201 void BluetoothDeviceMac::ConnectToService(
    202     const BluetoothUUID& uuid,
    203     const ConnectToServiceCallback& callback,
    204     const ConnectToServiceErrorCallback& error_callback) {
    205   scoped_refptr<BluetoothSocketMac> socket = BluetoothSocketMac::CreateSocket();
    206   socket->Connect(
    207       device_.get(), uuid, base::Bind(callback, socket), error_callback);
    208 }
    209 
    210 void BluetoothDeviceMac::CreateGattConnection(
    211       const GattConnectionCallback& callback,
    212       const ConnectErrorCallback& error_callback) {
    213   // TODO(armansito): Implement.
    214   error_callback.Run(ERROR_UNSUPPORTED_DEVICE);
    215 }
    216 
    217 void BluetoothDeviceMac::StartConnectionMonitor(
    218     const base::Closure& callback,
    219     const ErrorCallback& error_callback) {
    220   NOTIMPLEMENTED();
    221 }
    222 
    223 NSDate* BluetoothDeviceMac::GetLastInquiryUpdate() {
    224   return [device_ getLastInquiryUpdate];
    225 }
    226 
    227 int BluetoothDeviceMac::GetHostTransmitPower(
    228     BluetoothHCITransmitPowerLevelType power_level_type) const {
    229   IOBluetoothHostController* controller =
    230       [IOBluetoothHostController defaultController];
    231 
    232   // Bail if the undocumented API is unavailable on this machine.
    233   SEL selector = @selector(
    234       BluetoothHCIReadTransmitPowerLevel:inType:outTransmitPowerLevel:);
    235   if (![controller respondsToSelector:selector])
    236     return kUnknownPower;
    237 
    238   BluetoothHCITransmitPowerLevel power_level;
    239   IOReturn result =
    240       [controller BluetoothHCIReadTransmitPowerLevel:[device_ connectionHandle]
    241                                               inType:power_level_type
    242                                outTransmitPowerLevel:&power_level];
    243   if (result != kIOReturnSuccess)
    244     return kUnknownPower;
    245 
    246   return power_level;
    247 }
    248 
    249 // static
    250 std::string BluetoothDeviceMac::GetDeviceAddress(IOBluetoothDevice* device) {
    251   return CanonicalizeAddress(base::SysNSStringToUTF8([device addressString]));
    252 }
    253 
    254 }  // namespace device
    255