summaryrefslogtreecommitdiffstats
path: root/src/bluetooth/qbluetoothdevicediscoveryagent_winrt.cpp
diff options
context:
space:
mode:
authorIvan Solovev <ivan.solovev@qt.io>2022-07-07 13:49:54 +0200
committerIvan Solovev <ivan.solovev@qt.io>2022-07-11 13:23:40 +0200
commit2f560d044fec92e94e8438791aa5e4d9daced197 (patch)
treecd07ee6e16e66ff5df99bbeedc6705b490b50a5e /src/bluetooth/qbluetoothdevicediscoveryagent_winrt.cpp
parent761a059d5a5ef97e97039f3a34b3a7f92944f1f0 (diff)
Windows: fix Classic device discovery by porting to C++/WinRT
Start porting QWinRTBluetoothDeviceDiscoveryWorker to C++/WinRT. Use DeviceWatcher to discover both paired and unpaired Bluetooth Classic devices. Unlike old COM implementation, in C++/WinRT each callback for IAsyncOperation comes in its own thread, so we need to care more about thread-safety. As a result, we had to use std::enable_shared_from_this on the QWinRTBluetoothDeviceDiscoveryWorker to guarantee that it is alive when the callback is triggered, and also to use QMetaObject::invokeMethod() to check for the scan finish criteria. This caused some further refactoring of QWinRTBluetoothDeviceDiscoveryWorker. This patch leaves some TODOs to handle LE device discovery. This will be implemented in the following patches. Task-number: QTBUG-103263 Pick-to: 6.4 6.3 6.2 Change-Id: I9128fe7a65f1a5aedcba427d6944372ecfe33f2f Reviewed-by: Juha Vuolle <juha.vuolle@insta.fi> Reviewed-by: Oliver Wolff <oliver.wolff@qt.io>
Diffstat (limited to 'src/bluetooth/qbluetoothdevicediscoveryagent_winrt.cpp')
-rw-r--r--src/bluetooth/qbluetoothdevicediscoveryagent_winrt.cpp494
1 files changed, 256 insertions, 238 deletions
diff --git a/src/bluetooth/qbluetoothdevicediscoveryagent_winrt.cpp b/src/bluetooth/qbluetoothdevicediscoveryagent_winrt.cpp
index 08b8e07a..844a1a7e 100644
--- a/src/bluetooth/qbluetoothdevicediscoveryagent_winrt.cpp
+++ b/src/bluetooth/qbluetoothdevicediscoveryagent_winrt.cpp
@@ -6,8 +6,10 @@
#include "qbluetoothaddress.h"
#include "qbluetoothuuid.h"
-#include <QtBluetooth/private/qtbluetoothglobal_p.h>
+#include <QtBluetooth/private/qbluetoothdevicewatcher_winrt_p.h>
#include <QtBluetooth/private/qbluetoothutils_winrt_p.h>
+#include <QtBluetooth/private/qtbluetoothglobal_p.h>
+
#include <QtCore/QLoggingCategory>
#include <QtCore/qmutex.h>
#include <QtCore/private/qfunctions_winrt_p.h>
@@ -22,6 +24,17 @@
#include <windows.devices.bluetooth.advertisement.h>
+#include <winrt/Windows.Devices.Enumeration.h>
+#include <winrt/Windows.Devices.Bluetooth.h>
+#include <winrt/Windows.Devices.Bluetooth.Rfcomm.h>
+#include <winrt/Windows.Foundation.h>
+#include <winrt/Windows.Foundation.Collections.h>
+
+using WinRtBluetoothDevice = winrt::Windows::Devices::Bluetooth::BluetoothDevice;
+using WinRtRfcommDeviceServicesResult = winrt::Windows::Devices::Bluetooth::Rfcomm::RfcommDeviceServicesResult;
+using WinRtAsyncOperation = winrt::Windows::Foundation::IAsyncOperation;
+using WinRtAsyncStatus = winrt::Windows::Foundation::AsyncStatus;
+
using namespace Microsoft::WRL;
using namespace Microsoft::WRL::Wrappers;
using namespace ABI::Windows::Foundation;
@@ -142,14 +155,23 @@ static ServiceData extractServiceData(ComPtr<IBluetoothLEAdvertisement> ad)
return ret;
}
-class QWinRTBluetoothDeviceDiscoveryWorker : public QObject
+// Both constants are taken from Microsoft's docs:
+// https://docs.microsoft.com/en-us/windows/uwp/devices-sensors/aep-service-class-ids
+// Alternatively we could create separate watchers for paired and unpaired devices.
+static const winrt::hstring ClassicDeviceSelector =
+ L"System.Devices.Aep.ProtocolId:=\"{e0cbf06c-cd8b-4647-bb8a-263b43f0f974}\"";
+static const winrt::hstring LowEnergyDeviceSelector =
+ L"System.Devices.Aep.ProtocolId:=\"{bb7bb05e-5972-42b5-94fc-76eaa7084d49}\"";
+
+class QWinRTBluetoothDeviceDiscoveryWorker : public QObject,
+ public std::enable_shared_from_this<QWinRTBluetoothDeviceDiscoveryWorker>
{
Q_OBJECT
public:
- explicit QWinRTBluetoothDeviceDiscoveryWorker(QBluetoothDeviceDiscoveryAgent::DiscoveryMethods methods);
+ explicit QWinRTBluetoothDeviceDiscoveryWorker();
~QWinRTBluetoothDeviceDiscoveryWorker();
- void start();
- void stopLEWatcher();
+ void start(QBluetoothDeviceDiscoveryAgent::DiscoveryMethods methods);
+ void stop();
private:
void startDeviceDiscovery(QBluetoothDeviceDiscoveryAgent::DiscoveryMethod mode);
@@ -160,10 +182,8 @@ private:
void gatherMultipleDeviceInformation(quint32 deviceCount, IVectorView<DeviceInformation *> *devices,
QBluetoothDeviceDiscoveryAgent::DiscoveryMethod mode);
void setupLEDeviceWatcher();
- void classicBluetoothInfoFromDeviceIdAsync(HSTRING deviceId);
void leBluetoothInfoFromDeviceIdAsync(HSTRING deviceId);
void leBluetoothInfoFromAddressAsync(quint64 address);
- HRESULT onPairedClassicBluetoothDeviceFoundAsync(IAsyncOperation<BluetoothDevice *> *op, AsyncStatus status );
HRESULT onPairedBluetoothLEDeviceFoundAsync(IAsyncOperation<BluetoothLEDevice *> *op, AsyncStatus status);
HRESULT onBluetoothLEDeviceFoundAsync(IAsyncOperation<BluetoothLEDevice *> *op, AsyncStatus status);
enum PairingCheck {
@@ -173,13 +193,21 @@ private:
HRESULT onBluetoothLEDeviceFound(ComPtr<IBluetoothLEDevice> device, PairingCheck pairingCheck);
HRESULT onBluetoothLEDeviceFound(ComPtr<IBluetoothLEDevice> device);
HRESULT onBluetoothLEAdvertisementReceived(IBluetoothLEAdvertisementReceivedEventArgs *args);
- HRESULT onRfcommServicesReceived(IAsyncOperation<Rfcomm::RfcommDeviceServicesResult *> *op,
- AsyncStatus status, UINT64 address, UINT32 classOfDeviceInt,
- const QString &btName);
HRESULT onLeServicesReceived(IAsyncOperation<GenericAttributeProfile::GattDeviceServicesResult *> *op,
AsyncStatus status, QBluetoothDeviceInfo &info);
- void decrementPairedDevicesAndCheckFinished();
+ std::shared_ptr<QBluetoothDeviceWatcherWinRT> createDeviceWatcher(winrt::hstring selector,
+ int watcherId);
+ void generateError(QBluetoothDeviceDiscoveryAgent::Error error, const char *msg = nullptr);
+ // Bluetooth Classic handlers
+ void getClassicDeviceFromId(const winrt::hstring &id);
+ void handleClassicDevice(const WinRtBluetoothDevice &device);
+ void handleRfcommServices(const WinRtRfcommDeviceServicesResult &servicesResult,
+ uint64_t address, const QString &name, uint32_t classOfDeviceInt);
+
+ // invokable methods for handling finish conditions
+ Q_INVOKABLE void incrementPendingDevicesCount();
+ Q_INVOKABLE void decrementPendingDevicesCountAndCheckFinished();
public slots:
void finishDiscovery();
@@ -192,7 +220,11 @@ Q_SIGNALS:
void scanFinished();
public:
- quint8 requestedModes;
+ quint8 requestedModes = 0;
+
+private slots:
+ void onBluetoothDeviceFound(winrt::hstring deviceId, int watcherId);
+ void onDeviceEnumerationCompleted(int watcherId);
private:
ComPtr<IBluetoothLEAdvertisementWatcher> m_leWatcher;
@@ -206,25 +238,39 @@ private:
};
QMap<quint64, LEAdvertisingInfo> m_foundLEDevicesMap;
- int m_pendingPairedDevices;
+ int m_pendingPairedDevices = 0;
- ComPtr<IBluetoothDeviceStatics> m_deviceStatics;
ComPtr<IBluetoothLEDeviceStatics> m_leDeviceStatics;
+
+ static constexpr int ClassicWatcherId = 1;
+ static constexpr int LowEnergyWatcherId = 2;
+
+ std::shared_ptr<QBluetoothDeviceWatcherWinRT> m_classicWatcher;
+ std::shared_ptr<QBluetoothDeviceWatcherWinRT> m_lowEnergyWatcher;
+ bool m_classicScanStarted = false;
+ bool m_lowEnergyScanStarted = false;
};
-QWinRTBluetoothDeviceDiscoveryWorker::QWinRTBluetoothDeviceDiscoveryWorker(QBluetoothDeviceDiscoveryAgent::DiscoveryMethods methods)
- : requestedModes(methods)
- , m_pendingPairedDevices(0)
+static void invokeIncrementPendingDevicesCount(QObject *context)
+{
+ QMetaObject::invokeMethod(context, "incrementPendingDevicesCount", Qt::QueuedConnection);
+}
+
+static void invokeDecrementPendingDevicesCountAndCheckFinished(QObject *context)
+{
+ QMetaObject::invokeMethod(context, "decrementPendingDevicesCountAndCheckFinished",
+ Qt::QueuedConnection);
+}
+
+QWinRTBluetoothDeviceDiscoveryWorker::QWinRTBluetoothDeviceDiscoveryWorker()
{
qRegisterMetaType<QBluetoothDeviceInfo>();
qRegisterMetaType<QBluetoothDeviceInfo::Fields>();
qRegisterMetaType<ManufacturerData>();
- HRESULT hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Devices_Bluetooth_BluetoothDevice).Get(), &m_deviceStatics);
- EMIT_WORKER_ERROR_AND_RETURN_IF_FAILED("Could not obtain bluetooth device factory",
- QBluetoothDeviceDiscoveryAgent::Error::UnknownError,
- return)
- hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Devices_Bluetooth_BluetoothLEDevice).Get(), &m_leDeviceStatics);
+ m_classicWatcher = createDeviceWatcher(ClassicDeviceSelector, ClassicWatcherId);
+
+ HRESULT hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Devices_Bluetooth_BluetoothLEDevice).Get(), &m_leDeviceStatics);
EMIT_WORKER_ERROR_AND_RETURN_IF_FAILED("Could not obtain bluetooth le device factory",
QBluetoothDeviceDiscoveryAgent::Error::UnknownError,
return)
@@ -232,24 +278,36 @@ QWinRTBluetoothDeviceDiscoveryWorker::QWinRTBluetoothDeviceDiscoveryWorker(QBlue
QWinRTBluetoothDeviceDiscoveryWorker::~QWinRTBluetoothDeviceDiscoveryWorker()
{
- stopLEWatcher();
+ stop();
}
-void QWinRTBluetoothDeviceDiscoveryWorker::start()
+void QWinRTBluetoothDeviceDiscoveryWorker::start(QBluetoothDeviceDiscoveryAgent::DiscoveryMethods methods)
{
- if (requestedModes & QBluetoothDeviceDiscoveryAgent::ClassicMethod)
- startDeviceDiscovery(QBluetoothDeviceDiscoveryAgent::ClassicMethod);
+ requestedModes = methods;
if (requestedModes & QBluetoothDeviceDiscoveryAgent::LowEnergyMethod) {
startDeviceDiscovery(QBluetoothDeviceDiscoveryAgent::LowEnergyMethod);
setupLEDeviceWatcher();
}
+ if (requestedModes & QBluetoothDeviceDiscoveryAgent::ClassicMethod) {
+ if (m_classicWatcher && m_classicWatcher->init()) {
+ m_classicWatcher->start();
+ m_classicScanStarted = true;
+ } else {
+ generateError(QBluetoothDeviceDiscoveryAgent::Error::UnknownError,
+ "Could not start classic device watcher");
+ // do not return here, because we might still start LE scan
+ }
+ }
+ // TODO - do the same for LE scan
+
qCDebug(QT_BT_WINDOWS) << "Worker started";
}
-void QWinRTBluetoothDeviceDiscoveryWorker::stopLEWatcher()
+void QWinRTBluetoothDeviceDiscoveryWorker::stop()
{
+ m_classicWatcher->stop();
if (m_leWatcher) {
HRESULT hr = m_leWatcher->Stop();
EMIT_WORKER_ERROR_AND_RETURN_IF_FAILED("Could not stop le watcher",
@@ -275,7 +333,8 @@ void QWinRTBluetoothDeviceDiscoveryWorker::startDeviceDiscovery(QBluetoothDevice
if (mode == QBluetoothDeviceDiscoveryAgent::LowEnergyMethod)
m_leDeviceStatics->GetDeviceSelector(deviceSelector.GetAddressOf());
else
- m_deviceStatics->GetDeviceSelector(deviceSelector.GetAddressOf());
+ return; // Classic scan is now implemented using C++/WinRT DeviceWatcher
+
ComPtr<IAsyncOperation<DeviceInformationCollection *>> op;
hr = deviceInformationStatics->FindAllAsyncAqsFilter(deviceSelector.Get(), &op);
EMIT_WORKER_ERROR_AND_RETURN_IF_FAILED("Could not start bluetooth device discovery operation",
@@ -309,14 +368,6 @@ void QWinRTBluetoothDeviceDiscoveryWorker::onDeviceDiscoveryFinished(IAsyncOpera
QBluetoothDeviceDiscoveryAgent::Error::UnknownError,
return);
- // For classic discovery only paired devices will be found. If we only do classic disovery and
- // no device is found, the scan is finished.
- if (requestedModes == QBluetoothDeviceDiscoveryAgent::ClassicMethod &&
- deviceCount == 0) {
- finishDiscovery();
- return;
- }
-
m_pendingPairedDevices += deviceCount;
gatherMultipleDeviceInformation(deviceCount, devices.Get(), mode);
}
@@ -331,8 +382,6 @@ void QWinRTBluetoothDeviceDiscoveryWorker::gatherDeviceInformation(IDeviceInform
return);
if (mode == QBluetoothDeviceDiscoveryAgent::LowEnergyMethod)
leBluetoothInfoFromDeviceIdAsync(deviceId.Get());
- else
- classicBluetoothInfoFromDeviceIdAsync(deviceId.Get());
}
void QWinRTBluetoothDeviceDiscoveryWorker::gatherMultipleDeviceInformation(quint32 deviceCount, IVectorView<DeviceInformation *> *devices, QBluetoothDeviceDiscoveryAgent::DiscoveryMethod mode)
@@ -472,41 +521,166 @@ void QWinRTBluetoothDeviceDiscoveryWorker::setupLEDeviceWatcher()
void QWinRTBluetoothDeviceDiscoveryWorker::finishDiscovery()
{
+ stop();
emit scanFinished();
- stopLEWatcher();
- deleteLater();
}
-// "deviceFound" will be emitted at the end of the deviceFromIdOperation callback
-void QWinRTBluetoothDeviceDiscoveryWorker::classicBluetoothInfoFromDeviceIdAsync(HSTRING deviceId)
+void QWinRTBluetoothDeviceDiscoveryWorker::onBluetoothDeviceFound(winrt::hstring deviceId, int watcherId)
{
- ComPtr<IAsyncOperation<BluetoothDevice *>> deviceFromIdOperation;
- // on Windows 10 FromIdAsync might ask for device permission. We cannot wait here but have to handle that asynchronously
- HRESULT hr = m_deviceStatics->FromIdAsync(deviceId, &deviceFromIdOperation);
- if (FAILED(hr)) {
- emit errorOccured(QBluetoothDeviceDiscoveryAgent::UnknownError);
- decrementPairedDevicesAndCheckFinished();
- qCWarning(QT_BT_WINDOWS) << "Could not obtain bluetooth device from id";
- return;
+ if (watcherId == ClassicWatcherId)
+ getClassicDeviceFromId(deviceId);
+ // TODO - handle LE device
+}
+
+void QWinRTBluetoothDeviceDiscoveryWorker::onDeviceEnumerationCompleted(int watcherId)
+{
+ qCDebug(QT_BT_WINDOWS) << (watcherId == ClassicWatcherId ? "BT" : "BTLE")
+ << "enumeration completed";
+ if (watcherId == ClassicWatcherId) {
+ m_classicWatcher->stop();
+ m_classicScanStarted = false;
+ } else if (watcherId == LowEnergyWatcherId) {
+ m_lowEnergyWatcher->stop();
+ m_lowEnergyScanStarted = false;
}
- QPointer<QWinRTBluetoothDeviceDiscoveryWorker> thisPointer(this);
- hr = deviceFromIdOperation->put_Completed(Callback<IAsyncOperationCompletedHandler<BluetoothDevice *>>
- ([thisPointer](IAsyncOperation<BluetoothDevice *> *op, AsyncStatus status)
- {
- if (thisPointer) {
- if (status == Completed)
- thisPointer->onPairedClassicBluetoothDeviceFoundAsync(op, status);
- else
- thisPointer->decrementPairedDevicesAndCheckFinished();
+ // TODO - probably reconsider this condition later
+ if (!m_lowEnergyScanStarted && !m_classicScanStarted && !m_pendingPairedDevices
+ && !(requestedModes & QBluetoothDeviceDiscoveryAgent::LowEnergyMethod)) {
+ finishDiscovery();
+ }
+}
+
+std::shared_ptr<QBluetoothDeviceWatcherWinRT>
+QWinRTBluetoothDeviceDiscoveryWorker::createDeviceWatcher(winrt::hstring selector, int watcherId)
+{
+ auto watcher = std::make_shared<QBluetoothDeviceWatcherWinRT>(
+ watcherId, selector,
+ winrt::Windows::Devices::Enumeration::DeviceInformationKind::AssociationEndpoint);
+ if (watcher) {
+ connect(watcher.get(), &QBluetoothDeviceWatcherWinRT::deviceAdded,
+ this, &QWinRTBluetoothDeviceDiscoveryWorker::onBluetoothDeviceFound,
+ Qt::QueuedConnection);
+ connect(watcher.get(), &QBluetoothDeviceWatcherWinRT::enumerationCompleted,
+ this, &QWinRTBluetoothDeviceDiscoveryWorker::onDeviceEnumerationCompleted,
+ Qt::QueuedConnection);
+ }
+ return watcher;
+}
+
+void QWinRTBluetoothDeviceDiscoveryWorker::generateError(
+ QBluetoothDeviceDiscoveryAgent::Error error, const char *msg)
+{
+ emit errorOccured(error);
+ qCWarning(QT_BT_WINDOWS) << msg;
+}
+
+// this function executes in main worker thread
+void QWinRTBluetoothDeviceDiscoveryWorker::getClassicDeviceFromId(const winrt::hstring &id)
+{
+ ++m_pendingPairedDevices;
+ auto asyncOp = WinRtBluetoothDevice::FromIdAsync(id);
+ auto thisPtr = shared_from_this();
+ asyncOp.Completed([thisPtr](auto &&op, WinRtAsyncStatus status) {
+ if (thisPtr) {
+ if (status == WinRtAsyncStatus::Completed) {
+ WinRtBluetoothDevice device = op.GetResults();
+ if (device) {
+ thisPtr->handleClassicDevice(device);
+ return;
+ }
+ }
+ // status != Completed or failed to extract result
+ qCDebug(QT_BT_WINDOWS) << "Failed to get Classic device from id";
+ invokeDecrementPendingDevicesCountAndCheckFinished(thisPtr.get());
}
- return S_OK;
- }).Get());
- if (FAILED(hr)) {
- emit errorOccured(QBluetoothDeviceDiscoveryAgent::UnknownError);
- decrementPairedDevicesAndCheckFinished();
- qCWarning(QT_BT_WINDOWS) << "Could not register device found callback";
+ });
+}
+\
+// this is a callback - executes in a new thread
+void QWinRTBluetoothDeviceDiscoveryWorker::handleClassicDevice(const WinRtBluetoothDevice &device)
+{
+ const uint64_t address = device.BluetoothAddress();
+ const std::wstring name { device.Name() }; // via operator std::wstring_view()
+ const QString btName = QString::fromStdWString(name);
+ const uint32_t deviceClass = device.ClassOfDevice().RawValue();
+ auto thisPtr = shared_from_this();
+ auto asyncOp = device.GetRfcommServicesAsync();
+ asyncOp.Completed([thisPtr, address, btName, deviceClass](auto &&op, WinRtAsyncStatus status) {
+ if (thisPtr) {
+ if (status == WinRtAsyncStatus::Completed) {
+ auto servicesResult = op.GetResults();
+ if (servicesResult) {
+ thisPtr->handleRfcommServices(servicesResult, address, btName, deviceClass);
+ return;
+ }
+ }
+ // Failed to get services
+ qCDebug(QT_BT_WINDOWS) << "Failed to get RFCOMM services for device" << btName;
+ invokeDecrementPendingDevicesCountAndCheckFinished(thisPtr.get());
+ }
+ });
+}
+
+// this is a callback - executes in a new thread
+void QWinRTBluetoothDeviceDiscoveryWorker::handleRfcommServices(
+ const WinRtRfcommDeviceServicesResult &servicesResult, uint64_t address,
+ const QString &name, uint32_t classOfDeviceInt)
+{
+ // need to perform the check even if some of the operations fails
+ auto guard = qScopeGuard([this]() {
+ invokeDecrementPendingDevicesCountAndCheckFinished(this);
+ });
+ Q_UNUSED(guard); // to suppress warning
+
+ const auto error = servicesResult.Error();
+ if (error != winrt::Windows::Devices::Bluetooth::BluetoothError::Success) {
+ qCWarning(QT_BT_WINDOWS) << "Obtain device services completed with BluetoothError"
+ << static_cast<int>(error);
return;
}
+
+ const auto services = servicesResult.Services();
+ QList<QBluetoothUuid> uuids;
+ for (const auto &service : services) {
+ const auto serviceId = service.ServiceId();
+ const winrt::guid serviceUuid = serviceId.Uuid();
+ // A cast from winrt::guid does not work :(
+ const GUID uuid {
+ serviceUuid.Data1,
+ serviceUuid.Data2,
+ serviceUuid.Data3,
+ { serviceUuid.Data4[0], serviceUuid.Data4[1], serviceUuid.Data4[2],
+ serviceUuid.Data4[3], serviceUuid.Data4[4], serviceUuid.Data4[5],
+ serviceUuid.Data4[6], serviceUuid.Data4[7] }
+ };
+ uuids.append(QBluetoothUuid(uuid));
+ }
+
+ const QBluetoothAddress btAddress(address);
+
+ qCDebug(QT_BT_WINDOWS) << "Discovered BT device: " << btAddress << name
+ << "Num UUIDs" << uuids.size();
+
+ QBluetoothDeviceInfo info(btAddress, name, classOfDeviceInt);
+ info.setCoreConfigurations(QBluetoothDeviceInfo::BaseRateCoreConfiguration);
+ info.setServiceUuids(uuids);
+ info.setCached(true);
+
+ QMetaObject::invokeMethod(this, "deviceFound", Qt::AutoConnection,
+ Q_ARG(QBluetoothDeviceInfo, info));
+}
+
+void QWinRTBluetoothDeviceDiscoveryWorker::incrementPendingDevicesCount()
+{
+ ++m_pendingPairedDevices;
+}
+
+void QWinRTBluetoothDeviceDiscoveryWorker::decrementPendingDevicesCountAndCheckFinished()
+{
+ if ((--m_pendingPairedDevices == 0) && !m_classicScanStarted && !m_lowEnergyScanStarted
+ && !(requestedModes & QBluetoothDeviceDiscoveryAgent::LowEnergyMethod)) {
+ finishDiscovery();
+ }
}
// "deviceFound" will be emitted at the end of the deviceFromIdOperation callback
@@ -572,165 +746,6 @@ void QWinRTBluetoothDeviceDiscoveryWorker::leBluetoothInfoFromAddressAsync(quint
}
}
-HRESULT QWinRTBluetoothDeviceDiscoveryWorker::onPairedClassicBluetoothDeviceFoundAsync(IAsyncOperation<BluetoothDevice *> *op, AsyncStatus status)
-{
- HRESULT hr;
- // Need to decrement m_pendingPairedDevices and perform the check if some
- // operation fails. Otherwise it will be done in the callback.
- auto guard = qScopeGuard([this, &hr]() {
- if (FAILED(hr)) {
- qCWarning(QT_BT_WINDOWS) << "Failed to request Rfcomm services";
- decrementPairedDevicesAndCheckFinished();
- }
- });
- Q_UNUSED(guard); // to suppress warning
-
- if (status != AsyncStatus::Completed)
- return S_OK;
-
- ComPtr<IBluetoothDevice> device;
- hr = op->GetResults(&device);
- EMIT_WORKER_ERROR_AND_RETURN_IF_FAILED("Could not obtain bluetooth device",
- QBluetoothDeviceDiscoveryAgent::Error::UnknownError,
- return S_OK);
-
- if (!device)
- return S_OK;
-
- UINT64 address;
- HString name;
- ComPtr<IBluetoothClassOfDevice> classOfDevice;
- UINT32 classOfDeviceInt;
- hr = device->get_BluetoothAddress(&address);
- EMIT_WORKER_ERROR_AND_RETURN_IF_FAILED("Could not obtain bluetooth address",
- QBluetoothDeviceDiscoveryAgent::Error::UnknownError,
- return S_OK);
- hr = device->get_Name(name.GetAddressOf());
- EMIT_WORKER_ERROR_AND_RETURN_IF_FAILED("Could not obtain device name",
- QBluetoothDeviceDiscoveryAgent::Error::UnknownError,
- return S_OK);
- const QString btName = QString::fromWCharArray(WindowsGetStringRawBuffer(name.Get(), nullptr));
- hr = device->get_ClassOfDevice(&classOfDevice);
- EMIT_WORKER_ERROR_AND_RETURN_IF_FAILED("Could not obtain device class",
- QBluetoothDeviceDiscoveryAgent::Error::UnknownError,
- return S_OK);
- hr = classOfDevice->get_RawValue(&classOfDeviceInt);
- EMIT_WORKER_ERROR_AND_RETURN_IF_FAILED("Could not obtain raw value of device class",
- QBluetoothDeviceDiscoveryAgent::Error::UnknownError,
- return S_OK);
-
- ComPtr<IBluetoothDevice3> device3;
- hr = device.As(&device3);
- EMIT_WORKER_ERROR_AND_RETURN_IF_FAILED("Could not obtain bluetooth device3 interface",
- QBluetoothDeviceDiscoveryAgent::Error::UnknownError,
- return S_OK);
-
- ComPtr<IAsyncOperation<Rfcomm::RfcommDeviceServicesResult *>> deviceServicesOperation;
- hr = device3->GetRfcommServicesAsync(&deviceServicesOperation);
- EMIT_WORKER_ERROR_AND_RETURN_IF_FAILED("Async Rfcomm services request failed",
- QBluetoothDeviceDiscoveryAgent::Error::UnknownError,
- return S_OK);
-
- QPointer<QWinRTBluetoothDeviceDiscoveryWorker> thisPointer(this);
- hr = deviceServicesOperation->put_Completed(
- Callback<IAsyncOperationCompletedHandler<Rfcomm::RfcommDeviceServicesResult *>>(
- [thisPointer, address, btName, classOfDeviceInt](
- IAsyncOperation<Rfcomm::RfcommDeviceServicesResult *> *op,
- AsyncStatus status) {
- if (thisPointer) {
- thisPointer->onRfcommServicesReceived(op, status, address,
- classOfDeviceInt, btName);
- }
- return S_OK;
- }).Get());
- EMIT_WORKER_ERROR_AND_RETURN_IF_FAILED("Could not add Rfcomm services discovery callback",
- QBluetoothDeviceDiscoveryAgent::Error::UnknownError,
- return S_OK);
-
- return S_OK;
-}
-
-HRESULT QWinRTBluetoothDeviceDiscoveryWorker::onRfcommServicesReceived(
- IAsyncOperation<Rfcomm::RfcommDeviceServicesResult *> *op, AsyncStatus status,
- UINT64 address, UINT32 classOfDeviceInt, const QString &btName)
-{
- // need to perform the check even if some of the operations fails
- auto guard = qScopeGuard([this]() {
- decrementPairedDevicesAndCheckFinished();
- });
- Q_UNUSED(guard); // to suppress warning
-
- if (status != Completed)
- return S_OK;
-
- ComPtr<Rfcomm::IRfcommDeviceServicesResult> servicesResult;
- HRESULT hr = op->GetResults(&servicesResult);
- EMIT_WORKER_ERROR_AND_RETURN_IF_FAILED("Could not obtain device services",
- QBluetoothDeviceDiscoveryAgent::Error::UnknownError,
- return S_OK);
-
- BluetoothError error;
- hr = servicesResult->get_Error(&error);
- EMIT_WORKER_ERROR_AND_RETURN_IF_FAILED("Could not obtain error code",
- QBluetoothDeviceDiscoveryAgent::Error::UnknownError,
- return S_OK);
- if (error != BluetoothError_Success) {
- qCWarning(QT_BT_WINDOWS) << "Obtain device services completed with BluetoothErrot"
- << static_cast<int>(error);
- } else {
- IVectorView<Rfcomm::RfcommDeviceService *> *deviceServices;
- hr = servicesResult->get_Services(&deviceServices);
- EMIT_WORKER_ERROR_AND_RETURN_IF_FAILED("Could not obtain services list",
- QBluetoothDeviceDiscoveryAgent::Error::UnknownError,
- return S_OK);
- uint serviceCount;
- hr = deviceServices->get_Size(&serviceCount);
- EMIT_WORKER_ERROR_AND_RETURN_IF_FAILED("Could not obtain service list size",
- QBluetoothDeviceDiscoveryAgent::Error::UnknownError,
- return S_OK);
- QList<QBluetoothUuid> uuids;
- for (uint i = 0; i < serviceCount; ++i) {
- ComPtr<Rfcomm::IRfcommDeviceService> service;
- hr = deviceServices->GetAt(i, &service);
- EMIT_WORKER_ERROR_AND_RETURN_IF_FAILED("Could not obtain device service",
- QBluetoothDeviceDiscoveryAgent::Error::UnknownError,
- return S_OK);
- ComPtr<Rfcomm::IRfcommServiceId> id;
- hr = service->get_ServiceId(&id);
- EMIT_WORKER_ERROR_AND_RETURN_IF_FAILED("Could not obtain service id",
- QBluetoothDeviceDiscoveryAgent::Error::UnknownError,
- return S_OK);
- GUID uuid;
- hr = id->get_Uuid(&uuid);
- EMIT_WORKER_ERROR_AND_RETURN_IF_FAILED("Could not obtain uuid",
- QBluetoothDeviceDiscoveryAgent::Error::UnknownError,
- return S_OK);
- uuids.append(QBluetoothUuid(uuid));
- }
-
- qCDebug(QT_BT_WINDOWS) << "Discovered BT device: " << QString::number(address) << btName
- << "Num UUIDs" << uuids.size();
-
- QBluetoothDeviceInfo info(QBluetoothAddress(address), btName, classOfDeviceInt);
- info.setCoreConfigurations(QBluetoothDeviceInfo::BaseRateCoreConfiguration);
- info.setServiceUuids(uuids);
- info.setCached(true);
-
- QMetaObject::invokeMethod(this, "deviceFound", Qt::AutoConnection,
- Q_ARG(QBluetoothDeviceInfo, info));
- }
-
- return S_OK;
-}
-
-void QWinRTBluetoothDeviceDiscoveryWorker::decrementPairedDevicesAndCheckFinished()
-{
- if ((--m_pendingPairedDevices == 0)
- && !(requestedModes & QBluetoothDeviceDiscoveryAgent::LowEnergyMethod)) {
- finishDiscovery();
- }
-}
-
HRESULT QWinRTBluetoothDeviceDiscoveryWorker::onPairedBluetoothLEDeviceFoundAsync(IAsyncOperation<BluetoothLEDevice *> *op, AsyncStatus status)
{
--m_pendingPairedDevices;
@@ -942,7 +957,7 @@ QBluetoothDeviceDiscoveryAgentPrivate::~QBluetoothDeviceDiscoveryAgentPrivate()
bool QBluetoothDeviceDiscoveryAgentPrivate::isActive() const
{
- return worker;
+ return worker != nullptr;
}
QBluetoothDeviceDiscoveryAgent::DiscoveryMethods QBluetoothDeviceDiscoveryAgent::supportedDiscoveryMethods()
@@ -970,17 +985,17 @@ void QBluetoothDeviceDiscoveryAgentPrivate::start(QBluetoothDeviceDiscoveryAgent
if (worker)
return;
- worker = new QWinRTBluetoothDeviceDiscoveryWorker(methods);
+ worker = std::make_shared<QWinRTBluetoothDeviceDiscoveryWorker>();
discoveredDevices.clear();
- connect(worker, &QWinRTBluetoothDeviceDiscoveryWorker::deviceFound,
+ connect(worker.get(), &QWinRTBluetoothDeviceDiscoveryWorker::deviceFound,
this, &QBluetoothDeviceDiscoveryAgentPrivate::registerDevice);
- connect(worker, &QWinRTBluetoothDeviceDiscoveryWorker::deviceDataChanged,
+ connect(worker.get(), &QWinRTBluetoothDeviceDiscoveryWorker::deviceDataChanged,
this, &QBluetoothDeviceDiscoveryAgentPrivate::updateDeviceData);
- connect(worker, &QWinRTBluetoothDeviceDiscoveryWorker::errorOccured,
+ connect(worker.get(), &QWinRTBluetoothDeviceDiscoveryWorker::errorOccured,
this, &QBluetoothDeviceDiscoveryAgentPrivate::onErrorOccured);
- connect(worker, &QWinRTBluetoothDeviceDiscoveryWorker::scanFinished,
+ connect(worker.get(), &QWinRTBluetoothDeviceDiscoveryWorker::scanFinished,
this, &QBluetoothDeviceDiscoveryAgentPrivate::onScanFinished);
- worker->start();
+ worker->start(methods);
if (lowEnergySearchTimeout > 0 && methods & QBluetoothDeviceDiscoveryAgent::LowEnergyMethod) { // otherwise no timeout and stop() required
if (!leScanTimer) {
@@ -988,7 +1003,7 @@ void QBluetoothDeviceDiscoveryAgentPrivate::start(QBluetoothDeviceDiscoveryAgent
leScanTimer->setSingleShot(true);
}
connect(leScanTimer, &QTimer::timeout,
- worker, &QWinRTBluetoothDeviceDiscoveryWorker::finishDiscovery);
+ worker.get(), &QWinRTBluetoothDeviceDiscoveryWorker::finishDiscovery);
leScanTimer->setInterval(lowEnergySearchTimeout);
leScanTimer->start();
}
@@ -998,7 +1013,7 @@ void QBluetoothDeviceDiscoveryAgentPrivate::stop()
{
Q_Q(QBluetoothDeviceDiscoveryAgent);
if (worker) {
- worker->stopLEWatcher();
+ worker->stop();
disconnectAndClearWorker();
emit q->canceled();
}
@@ -1077,17 +1092,20 @@ void QBluetoothDeviceDiscoveryAgentPrivate::disconnectAndClearWorker()
if (!worker)
return;
- disconnect(worker, &QWinRTBluetoothDeviceDiscoveryWorker::scanFinished,
+ disconnect(worker.get(), &QWinRTBluetoothDeviceDiscoveryWorker::scanFinished,
this, &QBluetoothDeviceDiscoveryAgentPrivate::onScanFinished);
- disconnect(worker, &QWinRTBluetoothDeviceDiscoveryWorker::deviceFound,
+ disconnect(worker.get(), &QWinRTBluetoothDeviceDiscoveryWorker::deviceFound,
this, &QBluetoothDeviceDiscoveryAgentPrivate::registerDevice);
- disconnect(worker, &QWinRTBluetoothDeviceDiscoveryWorker::deviceDataChanged,
+ disconnect(worker.get(), &QWinRTBluetoothDeviceDiscoveryWorker::deviceDataChanged,
this, &QBluetoothDeviceDiscoveryAgentPrivate::updateDeviceData);
+ disconnect(worker.get(), &QWinRTBluetoothDeviceDiscoveryWorker::errorOccured,
+ this, &QBluetoothDeviceDiscoveryAgentPrivate::onErrorOccured);
if (leScanTimer) {
disconnect(leScanTimer, &QTimer::timeout,
- worker, &QWinRTBluetoothDeviceDiscoveryWorker::finishDiscovery);
+ worker.get(), &QWinRTBluetoothDeviceDiscoveryWorker::finishDiscovery);
}
- worker.clear();
+
+ worker = nullptr;
}
QT_END_NAMESPACE