5#include "bluez/leadvertisement1adaptor_p.h"
6#include "bluez/leadvertisingmanager1_p.h"
7#include "bluez/bluez5_helper_p.h"
9#include <QtCore/QtMinMax>
10#include <QtCore/QLoggingCategory>
14Q_DECLARE_LOGGING_CATEGORY(QT_BT_BLUEZ)
16using namespace Qt::StringLiterals;
17using namespace QtBluetoothPrivate;
32QLeDBusAdvertiser::QLeDBusAdvertiser(
const QLowEnergyAdvertisingParameters ¶ms,
33 const QLowEnergyAdvertisingData &advertisingData,
34 const QLowEnergyAdvertisingData &scanResponseData,
35 const QString &hostAdapterPath,
39 m_advData(advertisingData),
40 m_advObjectPath(QString(advObjectPathTemplate).
41 arg(sanitizeNameForDBus(QCoreApplication::applicationName())).
42 arg(QCoreApplication::applicationPid()).
43 arg(QRandomGenerator::global()->generate())),
44 m_advDataDBus(
new OrgBluezLEAdvertisement1Adaptor(
this)),
45 m_advManager(
new OrgBluezLEAdvertisingManager1Interface(bluezService, hostAdapterPath,
46 QDBusConnection::systemBus(),
this))
51 if (scanResponseData.services() != advertisingData.services()) {
52 QList<QBluetoothUuid> services = advertisingData.services();
53 const auto scanResponseServices = scanResponseData.services();
54 for (
const auto &service : scanResponseServices) {
55 if (!services.contains(service))
56 services.append(service);
58 m_advData.setServices(services);
61 if (!scanResponseData.localName().isEmpty())
62 m_advData.setLocalName(scanResponseData.localName());
63 if (scanResponseData.manufacturerId() != QLowEnergyAdvertisingData::invalidManufacturerId()) {
64 m_advData.setManufacturerData(scanResponseData.manufacturerId(),
65 scanResponseData.manufacturerData());
67 if (scanResponseData.includePowerLevel())
68 m_advData.setIncludePowerLevel(
true);
73QLeDBusAdvertiser::~QLeDBusAdvertiser()
81void QLeDBusAdvertiser::setDataForDBus()
83 setAdvertisingParamsForDBus();
84 setAdvertisementDataForDBus();
87void QLeDBusAdvertiser::setAdvertisingParamsForDBus()
90 if (!m_advParams.whiteList().isEmpty())
91 qCWarning(QT_BT_BLUEZ) <<
"White lists and filter policies not supported, ignoring";
94 switch (m_advParams.mode())
96 case QLowEnergyAdvertisingParameters::AdvScanInd:
97 case QLowEnergyAdvertisingParameters::AdvNonConnInd:
98 m_advDataDBus->setType(advDataTypeBroadcast);
100 case QLowEnergyAdvertisingParameters::AdvInd:
102 m_advDataDBus->setType(advDataTypePeripheral);
109 m_advDataDBus->setMinInterval(qBound(advDataMinIntervalMs,
110 quint16(m_advParams.minimumInterval()),
111 advDataMaxIntervalMs));
112 m_advDataDBus->setMaxInterval(qBound(advDataMinIntervalMs,
113 quint16(m_advParams.maximumInterval()),
114 advDataMaxIntervalMs));
117void QLeDBusAdvertiser::setAdvertisementDataForDBus()
126 const auto supportedIncludes = m_advManager->supportedIncludes();
127 if (m_advData.includePowerLevel() && supportedIncludes.contains(advDataTXPower))
128 m_advDataDBus->setIncludes({advDataTXPower});
135 m_advDataDBus->setLocalName(m_advData.localName());
138 if (!m_advData.services().isEmpty()) {
139 QStringList serviceUUIDList;
140 const auto services = m_advData.services();
141 for (
const auto &service : services)
142 serviceUUIDList << service.toString(QUuid::StringFormat::WithoutBraces);
143 m_advDataDBus->setServiceUUIDs(serviceUUIDList);
147 if (m_advData.manufacturerId() != QLowEnergyAdvertisingData::invalidManufacturerId()) {
148 m_advDataDBus->setManufacturerData({
149 {m_advData.manufacturerId(), QDBusVariant(m_advData.manufacturerData())}});
153 if (m_advDataDBus->type() == advDataTypePeripheral) {
154 m_advDataDBus->setDiscoverable(m_advData.discoverability()
155 != QLowEnergyAdvertisingData::DiscoverabilityNone);
157 qCDebug(QT_BT_BLUEZ) <<
"Ignoring advertisement discoverability in broadcast mode";
161 if (!m_advData.rawData().isEmpty())
162 qCWarning(QT_BT_BLUEZ) <<
"Raw advertisement data not supported, ignoring";
165void QLeDBusAdvertiser::startAdvertising()
167 qCDebug(QT_BT_BLUEZ) <<
"Start advertising" << m_advObjectPath <<
"on" << m_advManager->path();
169 qCWarning(QT_BT_BLUEZ) <<
"Start tried while already advertising";
173 if (!QDBusConnection::systemBus().registerObject(m_advObjectPath, m_advDataDBus,
174 QDBusConnection::ExportAllContents)) {
175 qCWarning(QT_BT_BLUEZ) <<
"Advertisement dbus object registration failed";
176 emit errorOccurred();
183 auto reply = m_advManager->RegisterAdvertisement(QDBusObjectPath(m_advObjectPath), {});
184 QDBusPendingCallWatcher* watcher =
new QDBusPendingCallWatcher(reply,
this);
186 QObject::connect(watcher, &QDBusPendingCallWatcher::finished,
this,
187 [
this](QDBusPendingCallWatcher* watcher){
188 QDBusPendingReply<> reply = *watcher;
189 if (reply.isError()) {
190 qCWarning(QT_BT_BLUEZ) <<
"Advertisement registration failed" << reply.error();
191 if (reply.error().name() == bluezErrorFailed)
192 qCDebug(QT_BT_BLUEZ) <<
"Advertisement could've been too large";
193 QDBusConnection::systemBus().unregisterObject(m_advObjectPath);
194 emit errorOccurred();
196 qCDebug(QT_BT_BLUEZ) <<
"Advertisement started successfully";
197 m_advertising =
true;
199 watcher->deleteLater();
203void QLeDBusAdvertiser::stopAdvertising()
208 m_advertising =
false;
209 auto reply = m_advManager->UnregisterAdvertisement(QDBusObjectPath(m_advObjectPath));
210 reply.waitForFinished();
212 qCWarning(QT_BT_BLUEZ) <<
"Error in unregistering advertisement" << reply.error();
214 qCDebug(QT_BT_BLUEZ) <<
"Advertisement unregistered successfully";
215 QDBusConnection::systemBus().unregisterObject(m_advObjectPath);
219void QLeDBusAdvertiser::Release()
221 qCDebug(QT_BT_BLUEZ) <<
"Advertisement" << m_advObjectPath <<
"released"
222 << (m_advertising ?
"unexpectedly" :
"");
226 m_advertising =
false;
227 QDBusConnection::systemBus().unregisterObject(m_advObjectPath);
228 emit errorOccurred();
static constexpr quint16 advDataMinIntervalMs
static constexpr auto advObjectPathTemplate
static constexpr auto advDataTypePeripheral
static constexpr auto advDataTypeBroadcast
static constexpr auto bluezErrorFailed
static constexpr quint16 advDataMaxIntervalMs
static constexpr auto bluezService
static constexpr auto advDataTXPower