diff options
Diffstat (limited to 'src/bluetooth/qbluetoothdevicediscoveryagent_winrt.cpp')
-rw-r--r-- | src/bluetooth/qbluetoothdevicediscoveryagent_winrt.cpp | 494 |
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 |