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 for (
const auto &service: scanResponseData.services()) {
54 if (!services.contains(service))
55 services.append(service);
57 m_advData.setServices(services);
60 if (!scanResponseData.localName().isEmpty())
61 m_advData.setLocalName(scanResponseData.localName());
62 if (scanResponseData.manufacturerId() != QLowEnergyAdvertisingData::invalidManufacturerId()) {
63 m_advData.setManufacturerData(scanResponseData.manufacturerId(),
64 scanResponseData.manufacturerData());
66 if (scanResponseData.includePowerLevel())
67 m_advData.setIncludePowerLevel(
true);
72QLeDBusAdvertiser::~QLeDBusAdvertiser()
80void QLeDBusAdvertiser::setDataForDBus()
82 setAdvertisingParamsForDBus();
83 setAdvertisementDataForDBus();
86void QLeDBusAdvertiser::setAdvertisingParamsForDBus()
89 if (!m_advParams.whiteList().isEmpty())
90 qCWarning(QT_BT_BLUEZ) <<
"White lists and filter policies not supported, ignoring";
93 switch (m_advParams.mode())
95 case QLowEnergyAdvertisingParameters::AdvScanInd:
96 case QLowEnergyAdvertisingParameters::AdvNonConnInd:
97 m_advDataDBus->setType(advDataTypeBroadcast);
99 case QLowEnergyAdvertisingParameters::AdvInd:
101 m_advDataDBus->setType(advDataTypePeripheral);
108 m_advDataDBus->setMinInterval(qBound(advDataMinIntervalMs,
109 quint16(m_advParams.minimumInterval()),
110 advDataMaxIntervalMs));
111 m_advDataDBus->setMaxInterval(qBound(advDataMinIntervalMs,
112 quint16(m_advParams.maximumInterval()),
113 advDataMaxIntervalMs));
116void QLeDBusAdvertiser::setAdvertisementDataForDBus()
125 const auto supportedIncludes = m_advManager->supportedIncludes();
126 if (m_advData.includePowerLevel() && supportedIncludes.contains(advDataTXPower))
127 m_advDataDBus->setIncludes({advDataTXPower});
134 m_advDataDBus->setLocalName(m_advData.localName());
137 if (!m_advData.services().isEmpty()) {
138 QStringList serviceUUIDList;
139 for (
const auto& service: m_advData.services())
140 serviceUUIDList << service.toString(QUuid::StringFormat::WithoutBraces);
141 m_advDataDBus->setServiceUUIDs(serviceUUIDList);
145 if (m_advData.manufacturerId() != QLowEnergyAdvertisingData::invalidManufacturerId()) {
146 m_advDataDBus->setManufacturerData({
147 {m_advData.manufacturerId(), QDBusVariant(m_advData.manufacturerData())}});
151 if (m_advDataDBus->type() == advDataTypePeripheral) {
152 m_advDataDBus->setDiscoverable(m_advData.discoverability()
153 != QLowEnergyAdvertisingData::DiscoverabilityNone);
155 qCDebug(QT_BT_BLUEZ) <<
"Ignoring advertisement discoverability in broadcast mode";
159 if (!m_advData.rawData().isEmpty())
160 qCWarning(QT_BT_BLUEZ) <<
"Raw advertisement data not supported, ignoring";
163void QLeDBusAdvertiser::startAdvertising()
165 qCDebug(QT_BT_BLUEZ) <<
"Start advertising" << m_advObjectPath <<
"on" << m_advManager->path();
167 qCWarning(QT_BT_BLUEZ) <<
"Start tried while already advertising";
171 if (!QDBusConnection::systemBus().registerObject(m_advObjectPath, m_advDataDBus,
172 QDBusConnection::ExportAllContents)) {
173 qCWarning(QT_BT_BLUEZ) <<
"Advertisement dbus object registration failed";
174 emit errorOccurred();
181 auto reply = m_advManager->RegisterAdvertisement(QDBusObjectPath(m_advObjectPath), {});
182 QDBusPendingCallWatcher* watcher =
new QDBusPendingCallWatcher(reply,
this);
184 QObject::connect(watcher, &QDBusPendingCallWatcher::finished,
this,
185 [
this](QDBusPendingCallWatcher* watcher){
186 QDBusPendingReply<> reply = *watcher;
187 if (reply.isError()) {
188 qCWarning(QT_BT_BLUEZ) <<
"Advertisement registration failed" << reply.error();
189 if (reply.error().name() == bluezErrorFailed)
190 qCDebug(QT_BT_BLUEZ) <<
"Advertisement could've been too large";
191 QDBusConnection::systemBus().unregisterObject(m_advObjectPath);
192 emit errorOccurred();
194 qCDebug(QT_BT_BLUEZ) <<
"Advertisement started successfully";
195 m_advertising =
true;
197 watcher->deleteLater();
201void QLeDBusAdvertiser::stopAdvertising()
206 m_advertising =
false;
207 auto reply = m_advManager->UnregisterAdvertisement(QDBusObjectPath(m_advObjectPath));
208 reply.waitForFinished();
210 qCWarning(QT_BT_BLUEZ) <<
"Error in unregistering advertisement" << reply.error();
212 qCDebug(QT_BT_BLUEZ) <<
"Advertisement unregistered successfully";
213 QDBusConnection::systemBus().unregisterObject(m_advObjectPath);
217void QLeDBusAdvertiser::Release()
219 qCDebug(QT_BT_BLUEZ) <<
"Advertisement" << m_advObjectPath <<
"released"
220 << (m_advertising ?
"unexpectedly" :
"");
224 m_advertising =
false;
225 QDBusConnection::systemBus().unregisterObject(m_advObjectPath);
226 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