mirror of
https://github.com/kidfromjupiter/nearby.git
synced 2026-09-16 15:36:12 -04:00
Add Objective-C++ BLE Medium wrapper
PiperOrigin-RevId: 558278732
This commit is contained in:
committed by
Copybara-Service
parent
71c298f270
commit
9998093366
@@ -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;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user