// Copyright 2023 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. #ifndef PLATFORM_IMPL_LINUX_API_BLUEZ_BLE_ADVERTISEMENT_H_ #define PLATFORM_IMPL_LINUX_API_BLUEZ_BLE_ADVERTISEMENT_H_ #include #include #include #include #include #include #include "internal/platform/implementation/ble.h" #include "internal/platform/implementation/linux/bluetooth_adapter.h" #include "internal/platform/implementation/linux/bluez.h" #include "internal/platform/implementation/linux/generated/dbus/bluez/le_advertisement_manager_client.h" #include "internal/platform/implementation/linux/generated/dbus/bluez/le_advertisement_server.h" #include "internal/platform/logging.h" namespace nearby { namespace linux { namespace bluez { class LEAdvertisement final : public sdbus::AdaptorInterfaces { public: LEAdvertisement(const LEAdvertisement&) = delete; LEAdvertisement(LEAdvertisement&&) = delete; LEAdvertisement& operator=(const LEAdvertisement&) = delete; LEAdvertisement& operator=(LEAdvertisement&&) = delete; LEAdvertisement(sdbus::IConnection& system_bus, sdbus::ObjectPath path, const api::ble::BleAdvertisementData& advertising_data, api::ble::AdvertiseParameters advertise_set_parameters); static std::unique_ptr CreateLEAdvertisement( sdbus::IConnection& system_bus, const api::ble::BleAdvertisementData& advertising_data, api::ble::AdvertiseParameters advertising_parameters) { static std::atomic adv_count = 0; auto object_path = bluez::ble_advertisement_path(adv_count++); return std::make_unique( system_bus, object_path, advertising_data, advertising_parameters); } ~LEAdvertisement() { LOG(INFO) << __func__ << "Unregistering advertisement adaptor"; unregisterAdaptor(); } private: // Methods void Release() override { LOG(INFO) << __func__ << ": LE Advertisement released: " << getObject().getObjectPath(); } // Properties std::string Type() override { return "peripheral"; } std::vector ServiceUUIDs() override { return service_uuids_; } std::map ManufacturerData() override { return {}; } std::vector SolicitUUIDs() override { return {}; } std::map ServiceData() override { return service_data_; } //std::map ScanResponseServiceData() override { // return {}; //} std::vector Includes() override { return {}; } std::string LocalName() override { return {}; } uint16_t Duration() override { return 0; } uint16_t Timeout() override { return 0; } // Windows seems to hardcode the scan interval to 118.125 milliseconds, so // lets just replicate that. uint32_t MinInterval() override { return 118; } uint32_t MaxInterval() override { return 119; } int16_t TxPower() override { return bluez::TxPowerLevelDbm(advertise_set_parameters_.tx_power_level); }; bool is_extended_advertisement_; std::vector service_uuids_; std::map service_data_; api::ble::AdvertiseParameters advertise_set_parameters_; }; class LEAdvertisementManager final : public sdbus::ProxyInterfaces { public: LEAdvertisementManager(sdbus::IConnection& system_bus, BluetoothAdapter& adapter) : ProxyInterfaces(system_bus, sdbus::ServiceName("org.bluez"), adapter.GetObjectPath()) { registerProxy(); } ~LEAdvertisementManager() { unregisterProxy(); } LEAdvertisementManager(const LEAdvertisementManager&) = delete; LEAdvertisementManager(LEAdvertisementManager&&) = delete; LEAdvertisementManager& operator=(const LEAdvertisementManager&) = delete; LEAdvertisementManager& operator=(LEAdvertisementManager&&) = delete; // Synchronous wrapper for RegisterAdvertisement void RegisterAdvertisementSync(const sdbus::ObjectPath& advertisement, const std::map& options) { std::promise> promise; auto future = promise.get_future(); { absl::MutexLock lock(&pending_ops_mutex_); pending_register_op_ = std::move(promise); } RegisterAdvertisement(advertisement, options); auto error = future.get(); if (error) { throw *error; } } // Synchronous wrapper for UnregisterAdvertisement void UnregisterAdvertisementSync(const sdbus::ObjectPath& service) { std::promise> promise; auto future = promise.get_future(); { absl::MutexLock lock(&pending_ops_mutex_); pending_unregister_op_ = std::move(promise); } UnregisterAdvertisement(service); auto error = future.get(); if (error) { throw *error; } } protected: void onRegisterAdvertisementReply(std::optional error) override { absl::MutexLock lock(&pending_ops_mutex_); if (pending_register_op_) { pending_register_op_->set_value(std::move(error)); pending_register_op_.reset(); } } void onUnregisterAdvertisementReply(std::optional error) override { absl::MutexLock lock(&pending_ops_mutex_); if (pending_unregister_op_) { pending_unregister_op_->set_value(std::move(error)); pending_unregister_op_.reset(); } } private: absl::Mutex pending_ops_mutex_; std::optional>> pending_register_op_ ABSL_GUARDED_BY(pending_ops_mutex_); std::optional>> pending_unregister_op_ ABSL_GUARDED_BY(pending_ops_mutex_); }; } // namespace bluez } // namespace linux } // namespace nearby #endif