Add Objective-C++ BLE Medium wrapper

PiperOrigin-RevId: 558278732
This commit is contained in:
Nick Bourdakos
2023-08-18 16:37:09 -07:00
committed by Copybara-Service
parent 71c298f270
commit 9998093366
9 changed files with 573 additions and 21 deletions
+1
View File
@@ -574,6 +574,7 @@ let package = Package(
// TODO(b/293283024): Stop ignoring these files when BLEv2 migration is complete.
"internal/platform/implementation/apple/ble_gatt_server.mm",
"internal/platform/implementation/apple/ble_gatt_client.mm",
"internal/platform/implementation/apple/ble_medium.mm",
"internal/platform/implementation/apple/ble_peripheral.mm",
"internal/platform/implementation/apple/ble_server_socket.mm",
"internal/platform/implementation/apple/ble_socket.mm",
@@ -109,6 +109,7 @@ objc_library(
srcs = [
"ble_gatt_client.mm",
"ble_gatt_server.mm",
"ble_medium.mm",
"ble_peripheral.mm",
"ble_server_socket.mm",
"ble_socket.mm",
@@ -119,6 +120,7 @@ objc_library(
hdrs = [
"ble_gatt_client.h",
"ble_gatt_server.h",
"ble_medium.h",
"ble_peripheral.h",
"ble_server_socket.h",
"ble_socket.h",
@@ -130,9 +132,12 @@ objc_library(
aspect_hints = ["//tools/build_defs/swift:no_module"],
deps = [
"//internal/platform:base",
"//internal/platform:cancellation_flag",
"//internal/platform:uuid",
"//internal/platform/implementation:comm",
"//internal/platform/implementation/apple/Mediums",
"//internal/platform/implementation/apple/Mediums/Ble/Sockets:Central",
"//internal/platform/implementation/apple/Mediums/Ble/Sockets:Peripheral",
"//third_party/apple_frameworks:CoreBluetooth",
"//third_party/apple_frameworks:Foundation",
"//third_party/objective_c/google_toolbox_for_mac:GTM_Logger",
@@ -0,0 +1,166 @@
// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Note: File language is detected using heuristics. Many Objective-C++ headers are incorrectly
// classified as C++ resulting in invalid linter errors. The use of "NSArray" and other Foundation
// classes like "NSData", "NSDictionary" and "NSUUID" are highly weighted for Objective-C and
// Objective-C++ scores. Oddly, "#import <Foundation/Foundation.h>" does not contribute any points.
// This comment alone should be enough to trick the IDE in to believing this is actually some sort
// of Objective-C file. See: cs/google3/devtools/search/lang/recognize_language_classifiers_data
#import <Foundation/Foundation.h>
#include <memory>
#include <string>
#include "internal/platform/cancellation_flag.h"
#include "internal/platform/implementation/ble_v2.h"
#include "internal/platform/implementation/bluetooth_adapter.h"
#include "internal/platform/uuid.h"
#import "internal/platform/implementation/apple/ble_peripheral.h"
#import "internal/platform/implementation/apple/ble_server_socket.h"
#import "internal/platform/implementation/apple/bluetooth_adapter_v2.h"
@class GNCBLEMedium;
@class GNSCentralManager;
@class GNSPeripheralManager;
@class GNSPeripheralServiceManager;
namespace nearby {
namespace apple {
// The main BLE medium used inside of Nearby. This serves as the entry point for all BLE and GATT
// related operations.
class BleMedium : public api::ble_v2::BleMedium {
public:
BleMedium();
~BleMedium() override = default;
// TODO(b/290385712): Not yet implemented.
//
// Async interface for StartAdvertising.
//
// Result status will be passed to start_advertising_result callback. To stop advertising, invoke
// the stop_advertising callback in AdvertisingSession.
//
// Advertising must be stopped before attempting to start advertising again.
std::unique_ptr<api::ble_v2::BleMedium::AdvertisingSession> StartAdvertising(
const api::ble_v2::BleAdvertisementData &advertising_data,
api::ble_v2::AdvertiseParameters advertise_set_parameters,
api::ble_v2::BleMedium::AdvertisingCallback callback) override;
// Starts BLE advertising and returns whether or not it was successful.
//
// Advertising must be stopped before attempting to start advertising again.
bool StartAdvertising(const api::ble_v2::BleAdvertisementData &advertising_data,
api::ble_v2::AdvertiseParameters advertise_set_parameters) override;
// TODO(b/290385712): Not yet implemented.
//
// Stops advertising.
//
// Returns whether or not advertising was successfully stopped.
bool StopAdvertising() override;
// TODO(b/290385712): Not yet implemented.
//
// Async interface for StartScanning.
//
// Result status will be passed to start_scanning_result callback on a private queue. To stop
// scanning, invoke the stop_scanning callback in ScanningSession.
//
// Scanning must be stopped before attempting to start scanning again.
std::unique_ptr<api::ble_v2::BleMedium::ScanningSession> StartScanning(
const Uuid &service_uuid, api::ble_v2::TxPowerLevel tx_power_level,
api::ble_v2::BleMedium::ScanningCallback callback) override;
// Starts scanning and returns whether or not it was successful.
//
// Scanning must be stopped before attempting to start scanning again.
bool StartScanning(const Uuid &service_uuid, api::ble_v2::TxPowerLevel tx_power_level,
api::ble_v2::BleMedium::ScanCallback callback) override;
// TODO(b/290385712): Not yet implemented.
//
// Stops scanning.
//
// Returns whether or not scanning was successfully stopped.
bool StopScanning() override;
// TODO(b/290385712): ServerGattConnectionCallback methods are not yet implemented.
//
// Starts a GATT server. Returns a nullptr upon error.
std::unique_ptr<api::ble_v2::GattServer> StartGattServer(
api::ble_v2::ServerGattConnectionCallback callback) override;
// Connects to a GATT server and negotiates the specified connection parameters. Returns nullptr
// upon error.
//
// The peripheral must outlive the GATT client or undefined behavior will occur. The peripheral
// should not be modified by this method.
std::unique_ptr<api::ble_v2::GattClient> ConnectToGattServer(
api::ble_v2::BlePeripheral &peripheral, api::ble_v2::TxPowerLevel tx_power_level,
api::ble_v2::ClientGattConnectionCallback callback) override;
// Opens a BLE server socket based on service ID.
//
// On success, returns a new BleServerSocket. On error, returns nullptr.
std::unique_ptr<api::ble_v2::BleServerSocket> OpenServerSocket(
const std::string &service_id) override;
// TODO(b/290385712): cancellation_flag support is not yet implemented.
//
// Connects to a BLE peripheral.
//
// The peripheral must outlive the socket or undefined behavior will occur. The peripheral
// should not be modified by this method.
//
// On success, returns a new BleSocket. On error, returns nullptr.
std::unique_ptr<api::ble_v2::BleSocket> Connect(const std::string &service_id,
api::ble_v2::TxPowerLevel tx_power_level,
api::ble_v2::BlePeripheral &peripheral,
CancellationFlag *cancellation_flag) override;
// Returns whether the hardware supports BOTH advertising extensions and extended scans.
//
// This is currently always false for all Apple hardware.
bool IsExtendedAdvertisementsAvailable() override;
// A peripheral cannot be retreived via MAC address on Apple platforms.
//
// This always returns false and does not call the callback.
bool GetRemotePeripheral(const std::string &mac_address,
api::ble_v2::BleMedium::GetRemotePeripheralCallback callback) override;
// Returns true if `id` refers to a known BLE peripheral and calls `callback` with a reference to
// said peripheral that is only guaranteed to be available for the duration of the callback.
// Otherwise, does not call the callback and returns false.
bool GetRemotePeripheral(api::ble_v2::BlePeripheral::UniqueId id,
api::ble_v2::BleMedium::GetRemotePeripheralCallback callback) override;
private:
GNCBLEMedium *medium_;
absl::Mutex peripherals_mutex_;
absl::flat_hash_map<api::ble_v2::BlePeripheral::UniqueId, std::unique_ptr<BlePeripheral>>
peripherals_ ABSL_GUARDED_BY(peripherals_mutex_);
GNSPeripheralServiceManager *socketPeripheralServiceManager_;
GNSPeripheralManager *socketPeripheralManager_;
GNSCentralManager *socketCentralManager_;
};
} // namespace apple
} // namespace nearby
@@ -0,0 +1,325 @@
// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#import "internal/platform/implementation/apple/ble_medium.h"
#import "internal/platform/implementation/apple/utils.h"
#import <CoreBluetooth/CoreBluetooth.h>
#import <Foundation/Foundation.h>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "internal/platform/implementation/apple/ble_utils.h"
#include "internal/platform/implementation/apple/utils.h"
#include "internal/platform/implementation/ble_v2.h"
#include "internal/platform/implementation/bluetooth_adapter.h"
#import "internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEGATTCharacteristic.h"
#import "internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEGATTClient.h"
#import "internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEGATTServer.h"
#import "internal/platform/implementation/apple/Mediums/BLEv2/GNCBLEMedium.h"
#import "internal/platform/implementation/apple/Mediums/BLEv2/GNCPeripheral.h"
#import "internal/platform/implementation/apple/ble_gatt_client.h"
#import "internal/platform/implementation/apple/ble_gatt_server.h"
#import "internal/platform/implementation/apple/ble_peripheral.h"
#import "internal/platform/implementation/apple/ble_server_socket.h"
#import "internal/platform/implementation/apple/ble_socket.h"
#import "internal/platform/implementation/apple/bluetooth_adapter_v2.h"
#import "GoogleToolboxForMac/GTMLogger.h"
// TODO(b/293336684): Old Weave imports that need to be deleted once shared Weave is complete.
#import "internal/platform/implementation/apple/Mediums/Ble/GNCMBleConnection.h"
#import "internal/platform/implementation/apple/Mediums/Ble/GNCMBleUtils.h"
#import "internal/platform/implementation/apple/Mediums/Ble/Sockets/Source/Central/GNSCentralManager.h"
#import "internal/platform/implementation/apple/Mediums/Ble/Sockets/Source/Central/GNSCentralPeerManager.h"
#import "internal/platform/implementation/apple/Mediums/Ble/Sockets/Source/Peripheral/GNSPeripheralManager.h"
#import "internal/platform/implementation/apple/Mediums/Ble/Sockets/Source/Peripheral/GNSPeripheralServiceManager.h"
static NSString *const kWeaveServiceUUID = @"FEF3";
namespace nearby {
namespace apple {
BleMedium::BleMedium() : medium_([[GNCBLEMedium alloc] init]) {}
// TODO(b/290385712): Implement.
std::unique_ptr<api::ble_v2::BleMedium::AdvertisingSession> BleMedium::StartAdvertising(
const api::ble_v2::BleAdvertisementData &advertising_data,
api::ble_v2::AdvertiseParameters advertise_set_parameters,
api::ble_v2::BleMedium::AdvertisingCallback callback) {
return nullptr;
}
bool BleMedium::StartAdvertising(const api::ble_v2::BleAdvertisementData &advertising_data,
api::ble_v2::AdvertiseParameters advertise_set_parameters) {
NSMutableDictionary<CBUUID *, NSData *> *serviceData = [[NSMutableDictionary alloc] init];
for (const auto &pair : advertising_data.service_data) {
CBUUID *key = CBUUID16FromCPP(pair.first);
NSData *data = NSDataFromByteArray(pair.second);
[serviceData setObject:data forKey:key];
}
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
__block NSError *blockError = nil;
[medium_ startAdvertisingData:serviceData
completionHandler:^(NSError *error) {
if (error != nil) {
GTMLoggerError(@"Failed to start advertising: %@", error);
}
blockError = error;
dispatch_semaphore_signal(semaphore);
}];
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
return blockError == nil;
}
// TODO(b/290385712): Implement.
bool BleMedium::StopAdvertising() { return false; }
// TODO(b/290385712): Implement.
std::unique_ptr<api::ble_v2::BleMedium::ScanningSession> BleMedium::StartScanning(
const Uuid &service_uuid, api::ble_v2::TxPowerLevel tx_power_level,
api::ble_v2::BleMedium::ScanningCallback callback) {
return nullptr;
}
bool BleMedium::StartScanning(const Uuid &service_uuid, api::ble_v2::TxPowerLevel tx_power_level,
api::ble_v2::BleMedium::ScanCallback callback) {
CBUUID *serviceUUID = CBUUID128FromCPP(service_uuid);
__block api::ble_v2::BleMedium::ScanCallback blockCallback = std::move(callback);
socketCentralManager_ = [[GNSCentralManager alloc] initWithSocketServiceUUID:serviceUUID];
[socketCentralManager_ startNoScanModeWithAdvertisedServiceUUIDs:@[ serviceUUID ]];
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
__block NSError *blockError = nil;
[medium_ startScanningForService:serviceUUID
advertisementFoundHandler:^(id<GNCPeripheral> peripheral,
NSDictionary<CBUUID *, NSData *> *serviceData) {
absl::MutexLock lock(&peripherals_mutex_);
[socketCentralManager_ retrievePeripheralWithIdentifier:peripheral.identifier
advertisementData:@{}];
api::ble_v2::BleAdvertisementData data;
for (CBUUID *key in serviceData.allKeys) {
data.service_data[CPPUUIDFromObjC(key)] = ByteArrayFromNSData(serviceData[key]);
}
// Add the peripheral to the map if we haven't discovered it yet.
auto ble_peripheral = std::make_unique<BlePeripheral>(peripheral);
auto unique_id = ble_peripheral->GetUniqueId();
auto it = peripherals_.find(unique_id);
if (it == peripherals_.end()) {
peripherals_[unique_id] = std::move(ble_peripheral);
}
blockCallback.advertisement_found_cb(*peripherals_[unique_id], data);
}
completionHandler:^(NSError *error) {
if (error != nil) {
GTMLoggerError(@"Failed to start scanning: %@", error);
}
blockError = error;
dispatch_semaphore_signal(semaphore);
}];
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
return blockError == nil;
}
// TODO(b/290385712): Implement.
bool BleMedium::StopScanning() { return false; }
// TODO(b/290385712): Add implementation that calls ServerGattConnectionCallback methods.
std::unique_ptr<api::ble_v2::GattServer> BleMedium::StartGattServer(
api::ble_v2::ServerGattConnectionCallback callback) {
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
__block GNCBLEGATTServer *blockServer = nil;
[medium_ startGATTServerWithCompletionHandler:^(GNCBLEGATTServer *server, NSError *error) {
if (error != nil) {
GTMLoggerError(@"Error starting GATT server: %@", error);
}
blockServer = server;
dispatch_semaphore_signal(semaphore);
}];
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
if (!blockServer) {
return nullptr;
}
return std::make_unique<GattServer>(blockServer);
}
std::unique_ptr<api::ble_v2::GattClient> BleMedium::ConnectToGattServer(
api::ble_v2::BlePeripheral &peripheral, api::ble_v2::TxPowerLevel tx_power_level,
api::ble_v2::ClientGattConnectionCallback callback) {
// Check that the @c api::ble_v2::BlePeripheral is a @c nearby::apple::BlePeripheral and not a
// @c nearby::apple::EmptyBlePeripheral instance, so we can retreive the CBPeripheral object.
BlePeripheral *non_empty_peripheral = dynamic_cast<BlePeripheral *>(&peripheral);
if (non_empty_peripheral == nullptr) {
return nullptr;
}
__block api::ble_v2::ClientGattConnectionCallback blockCallback = std::move(callback);
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
__block GNCBLEGATTClient *blockClient = nil;
[medium_ connectToGATTServerForPeripheral:non_empty_peripheral->GetPeripheral()
disconnectionHandler:^(void) {
blockCallback.disconnected_cb();
}
completionHandler:^(GNCBLEGATTClient *client, NSError *error) {
if (error != nil) {
GTMLoggerError(@"Error connecting to GATT server: %@", error);
}
blockClient = client;
dispatch_semaphore_signal(semaphore);
}];
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
if (!blockClient) {
return nullptr;
}
return std::make_unique<GattClient>(blockClient);
}
// TODO(b/293336684): Old Weave code that need to be deleted once shared Weave is complete.
std::unique_ptr<api::ble_v2::BleServerSocket> BleMedium::OpenServerSocket(
const std::string &service_id) {
__block auto server_socket = std::make_unique<BleServerSocket>();
socketPeripheralServiceManager_ = [[GNSPeripheralServiceManager alloc]
initWithBleServiceUUID:[CBUUID UUIDWithString:kWeaveServiceUUID]
addPairingCharacteristic:NO
shouldAcceptSocketHandler:^BOOL(GNSSocket *socket) {
GNCMWaitForConnection(socket, ^(BOOL didConnect) {
GNCMBleConnection *connection =
[GNCMBleConnection connectionWithSocket:socket
serviceID:@(service_id.c_str())
expectedIntroPacket:YES
callbackQueue:dispatch_get_main_queue()];
auto socket = std::make_unique<BleSocket>(connection);
connection.connectionHandlers = socket->GetInputStream().GetConnectionHandlers();
server_socket->Connect(std::move(socket));
});
return YES;
}];
socketPeripheralManager_ = [[GNSPeripheralManager alloc] initWithAdvertisedName:nil
restoreIdentifier:nil];
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
__block NSError *blockError = nil;
[socketPeripheralManager_ addPeripheralServiceManager:socketPeripheralServiceManager_
bleServiceAddedCompletion:^(NSError *error) {
if (error != nil) {
GTMLoggerError(@"Failed to add Weave service: %@", error);
}
blockError = error;
dispatch_semaphore_signal(semaphore);
}];
[socketPeripheralManager_ start];
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
if (blockError != nil) {
return nullptr;
}
return std::move(server_socket);
}
// TODO(b/290385712): Add support for @c cancellation_flag.
// TODO(b/293336684): Old Weave code that need to be deleted once shared Weave is complete.
std::unique_ptr<api::ble_v2::BleSocket> BleMedium::Connect(const std::string &service_id,
api::ble_v2::TxPowerLevel tx_power_level,
api::ble_v2::BlePeripheral &peripheral,
CancellationFlag *cancellation_flag) {
// Check that the @c api::ble_v2::BlePeripheral is a @c nearby::apple::BlePeripheral and not a
// @c nearby::apple::EmptyBlePeripheral instance, so we can retreive the CBPeripheral object.
BlePeripheral *non_empty_peripheral = dynamic_cast<BlePeripheral *>(&peripheral);
if (non_empty_peripheral == nullptr) {
return nullptr;
}
GNSCentralPeerManager *updatedCentralPeerManager = [socketCentralManager_
retrieveCentralPeerWithIdentifier:non_empty_peripheral->GetPeripheral().identifier];
if (!updatedCentralPeerManager) {
return nullptr;
}
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
__block std::unique_ptr<BleSocket> socket;
[updatedCentralPeerManager
socketWithPairingCharacteristic:NO
completion:^(GNSSocket *nssocket, NSError *error) {
if (error) {
dispatch_semaphore_signal(semaphore);
return;
}
GNCMWaitForConnection(nssocket, ^(BOOL didConnect) {
if (!didConnect) {
dispatch_semaphore_signal(semaphore);
return;
}
GNCMBleConnection *connection = [GNCMBleConnection
connectionWithSocket:nssocket
serviceID:@(service_id.c_str())
expectedIntroPacket:NO
callbackQueue:dispatch_get_main_queue()];
socket =
std::make_unique<BleSocket>(connection, non_empty_peripheral);
connection.connectionHandlers =
socket->GetInputStream().GetConnectionHandlers();
dispatch_semaphore_signal(semaphore);
});
}];
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
if (socket == nullptr) {
return nullptr;
}
// Send the (empty) intro packet, which the BLE advertiser is expecting.
socket->GetOutputStream().Write(ByteArray());
return std::move(socket);
}
bool BleMedium::IsExtendedAdvertisementsAvailable() {
return [medium_ supportsExtendedAdvertisements];
}
bool BleMedium::GetRemotePeripheral(const std::string &mac_address,
api::ble_v2::BleMedium::GetRemotePeripheralCallback callback) {
// Apple does not expose MAC address information, so we cannot retreive a peripheral via MAC
// address.
return false;
}
bool BleMedium::GetRemotePeripheral(api::ble_v2::BlePeripheral::UniqueId unique_id,
api::ble_v2::BleMedium::GetRemotePeripheralCallback callback) {
BlePeripheral *peripheral;
{
absl::MutexLock lock(&peripherals_mutex_);
auto it = peripherals_.find(unique_id);
if (it == peripherals_.end()) {
return false;
}
peripheral = it->second.get();
if (peripheral == nullptr) {
return false;
}
}
// We need to unlock before calling the callback, otherwise we will deadlock.
callback(*peripheral);
return true;
}
} // namespace apple
} // namespace nearby
@@ -26,20 +26,24 @@
#include "internal/platform/implementation/ble_v2.h"
@protocol GNCPeripheral;
namespace nearby {
namespace apple {
// Opaque wrapper over a CoreBluetooth peripheral. This can be used to uniquely
// identify a peripheral and connect to its GATT server.
class BlePeripheral : public api::ble_v2::BlePeripheral {
// An empty peripheral.
//
// Apple APIs do not expose a peripheral's MAC address and does not provide a
// way to directly connect to a given MAC address. Instead a connection can only
// be made using a CoreBluetooth peripheral object. Many times a CoreBluetooth
// peripheral is not available, namely, when the remote device is a central. For
// these cases, an EmptyBlePeripheral should be used.
class EmptyBlePeripheral : public api::ble_v2::BlePeripheral {
public:
BlePeripheral() = default;
explicit BlePeripheral(CBPeripheral *peripheral);
~BlePeripheral() override = default;
EmptyBlePeripheral();
~EmptyBlePeripheral() override = default;
// Returns the hardware address of this peripheral.
//
// For example, "00:11:22:AA:BB:CC".
// Returns an empty string.
std::string GetAddress() const override;
// Returns an immutable unique identifier. The identifier does not change when
@@ -47,7 +51,32 @@ class BlePeripheral : public api::ble_v2::BlePeripheral {
api::ble_v2::BlePeripheral::UniqueId GetUniqueId() const override;
private:
CBPeripheral *peripheral_;
api::ble_v2::BlePeripheral::UniqueId unique_id_;
};
// A wrapper of a CoreBluetooth peripheral object. This can be used to uniquely
// identify a peripheral and connect to its GATT server.
//
// Many times a CoreBluetooth peripheral is not available, namely, when the
// remote device is a central. For these cases, an EmptyBlePeripheral should be
// used instead.
class BlePeripheral : public api::ble_v2::BlePeripheral {
public:
explicit BlePeripheral(id<GNCPeripheral> peripheral);
~BlePeripheral() override = default;
// Returns an empty string.
std::string GetAddress() const override;
// Returns an immutable unique identifier. The identifier does not change when
// the peripheral's address is rotated.
api::ble_v2::BlePeripheral::UniqueId GetUniqueId() const override;
// Returns the CoreBluetooth peripheral object.
id<GNCPeripheral> GetPeripheral() const;
private:
id<GNCPeripheral> peripheral_;
api::ble_v2::BlePeripheral::UniqueId unique_id_;
};
@@ -22,17 +22,29 @@
#include "internal/platform/implementation/ble_v2.h"
#include "internal/platform/prng.h"
#import "internal/platform/implementation/apple/Mediums/BLEv2/GNCPeripheral.h"
namespace nearby {
namespace apple {
BlePeripheral::BlePeripheral(CBPeripheral *peripheral)
: peripheral_(peripheral), unique_id_(Prng().NextInt64()) {}
#pragma mark - EmptyBlePeripheral
std::string BlePeripheral::GetAddress() const {
return peripheral_.identifier.UUIDString.UTF8String;
}
EmptyBlePeripheral::EmptyBlePeripheral() : unique_id_(Prng().NextInt64()) {}
std::string EmptyBlePeripheral::GetAddress() const { return ""; }
api::ble_v2::BlePeripheral::UniqueId EmptyBlePeripheral::GetUniqueId() const { return unique_id_; }
#pragma mark - BlePeripheral
BlePeripheral::BlePeripheral(id<GNCPeripheral> peripheral)
: peripheral_(peripheral), unique_id_(peripheral.identifier.hash) {}
std::string BlePeripheral::GetAddress() const { return ""; }
api::ble_v2::BlePeripheral::UniqueId BlePeripheral::GetUniqueId() const { return unique_id_; }
id<GNCPeripheral> BlePeripheral::GetPeripheral() const { return peripheral_; }
} // namespace apple
} // namespace nearby
@@ -90,7 +90,11 @@ class BleOutputStream : public OutputStream {
// A BLE Weave socket.
class BleSocket : public api::ble_v2::BleSocket {
public:
BleSocket(id<GNCMConnection> connection, BlePeripheral *peripheral);
explicit BleSocket(id<GNCMConnection> connection);
// The peripheral used to create the socket must outlive the socket or undefined behavior will
// occur.
BleSocket(id<GNCMConnection> connection, api::ble_v2::BlePeripheral *peripheral);
~BleSocket() override;
// Returns the InputStream of the BleSocket.
@@ -98,21 +102,21 @@ class BleSocket : public api::ble_v2::BleSocket {
//
// The returned object is not owned by the caller, and can be invalidated once
// the BleSocket object is destroyed.
InputStream &GetInputStream() override { return *input_stream_; }
BleInputStream &GetInputStream() override { return *input_stream_; }
// Returns the OutputStream of the BleSocket.
// On error, returned stream will report Exception::kIo on any operation.
//
// The returned object is not owned by the caller, and can be invalidated once
// the BleSocket object is destroyed.
OutputStream &GetOutputStream() override { return *output_stream_; }
BleOutputStream &GetOutputStream() override { return *output_stream_; }
// Returns Exception::kIo on error, otherwise Exception::kSuccess.
Exception Close() override ABSL_LOCKS_EXCLUDED(mutex_);
// Returns valid BlePeripheral pointer if there is a connection, and
// nullptr otherwise.
BlePeripheral *GetRemotePeripheral() override { return peripheral_; }
api::ble_v2::BlePeripheral *GetRemotePeripheral() override { return peripheral_; }
bool IsClosed() const ABSL_LOCKS_EXCLUDED(mutex_);
@@ -123,7 +127,7 @@ class BleSocket : public api::ble_v2::BleSocket {
bool closed_ ABSL_GUARDED_BY(mutex_) = false;
std::unique_ptr<BleInputStream> input_stream_;
std::unique_ptr<BleOutputStream> output_stream_;
BlePeripheral *peripheral_;
api::ble_v2::BlePeripheral *peripheral_;
};
} // namespace apple
@@ -177,7 +177,12 @@ Exception BleOutputStream::Close() {
#pragma mark - BleSocket
BleSocket::BleSocket(id<GNCMConnection> connection, BlePeripheral *peripheral)
BleSocket::BleSocket(id<GNCMConnection> connection)
: input_stream_(new BleInputStream()),
output_stream_(new BleOutputStream(connection)),
peripheral_(new EmptyBlePeripheral()) {}
BleSocket::BleSocket(id<GNCMConnection> connection, api::ble_v2::BlePeripheral *peripheral)
: input_stream_(new BleInputStream()),
output_stream_(new BleOutputStream(connection)),
peripheral_(peripheral) {}
@@ -92,6 +92,8 @@ class BlePeripheral {
// https://developer.android.com/reference/android/bluetooth/BluetoothDevice#getAddress()
//
// Returns the current address.
//
// This will always be an empty string on Apple platforms.
virtual std::string GetAddress() const = 0;
// Returns an immutable unique identifier. The identifier must not change when
@@ -510,6 +512,9 @@ class BleMedium {
// Calls `callback` and returns true if `mac_address` is a valid BLE address.
// Otherwise, does not call the callback and returns false.
//
// This method is not available on Apple platforms and will always return
// false, ignoring the callback.
virtual bool GetRemotePeripheral(const std::string& mac_address,
GetRemotePeripheralCallback callback) = 0;