diff options
Diffstat (limited to 'src/bluetooth/qbluetoothservicediscoveryagent_osx.mm')
-rw-r--r-- | src/bluetooth/qbluetoothservicediscoveryagent_osx.mm | 416 |
1 files changed, 31 insertions, 385 deletions
diff --git a/src/bluetooth/qbluetoothservicediscoveryagent_osx.mm b/src/bluetooth/qbluetoothservicediscoveryagent_osx.mm index bd9cc7f3..d8decae1 100644 --- a/src/bluetooth/qbluetoothservicediscoveryagent_osx.mm +++ b/src/bluetooth/qbluetoothservicediscoveryagent_osx.mm @@ -37,6 +37,7 @@ ** ****************************************************************************/ +#include "qbluetoothservicediscoveryagent_p.h" #include "qbluetoothservicediscoveryagent.h" #include "qbluetoothdevicediscoveryagent.h" #include "qbluetoothlocaldevice.h" @@ -57,132 +58,41 @@ QT_BEGIN_NAMESPACE -class QBluetoothServiceDiscoveryAgentPrivate : public QObject, public OSXBluetooth::SDPInquiryDelegate -{ - friend class QBluetoothServiceDiscoveryAgent; -public: - enum DiscoveryState { - Inactive, - DeviceDiscovery, - ServiceDiscovery, - }; - - QBluetoothServiceDiscoveryAgentPrivate(QBluetoothServiceDiscoveryAgent *qp, - const QBluetoothAddress &localAddress); - - void startDeviceDiscovery(); - void stopDeviceDiscovery(); - - void startServiceDiscovery(); - void stopServiceDiscovery(); - - DiscoveryState discoveryState(); - void setDiscoveryMode(QBluetoothServiceDiscoveryAgent::DiscoveryMode m); - QBluetoothServiceDiscoveryAgent::DiscoveryMode DiscoveryMode(); - - void _q_deviceDiscovered(const QBluetoothDeviceInfo &info); - void _q_deviceDiscoveryError(QBluetoothDeviceDiscoveryAgent::Error); - void _q_deviceDiscoveryFinished(); - -private: - // SDPInquiryDelegate: - void SDPInquiryFinished(IOBluetoothDevice *device) override; - void SDPInquiryError(IOBluetoothDevice *device, IOReturn errorCode) override; - - void performMinimalServiceDiscovery(const QBluetoothAddress &deviceAddress); - void setupDeviceDiscoveryAgent(); - bool isDuplicatedService(const QBluetoothServiceInfo &serviceInfo) const; - void serviceDiscoveryFinished(); - - bool serviceHasMathingUuid(const QBluetoothServiceInfo &serviceInfo) const; - - QBluetoothServiceDiscoveryAgent *q_ptr; +namespace { - QBluetoothServiceDiscoveryAgent::Error error; - QString errorString; +using DarwinBluetooth::RetainPolicy; +using ObjCServiceInquiry = QT_MANGLE_NAMESPACE(OSXBTSDPInquiry); - QList<QBluetoothDeviceInfo> discoveredDevices; - QList<QBluetoothServiceInfo> discoveredServices; - QList<QBluetoothUuid> uuidFilter; - - bool singleDevice; - QBluetoothAddress deviceAddress; - QBluetoothAddress localAdapterAddress; - - DiscoveryState state; - QBluetoothServiceDiscoveryAgent::DiscoveryMode discoveryMode; - - QScopedPointer<QBluetoothDeviceDiscoveryAgent> deviceDiscoveryAgent; - OSXBluetooth::ObjCScopedPointer<ObjCServiceInquiry> serviceInquiry; -}; +} QBluetoothServiceDiscoveryAgentPrivate::QBluetoothServiceDiscoveryAgentPrivate( QBluetoothServiceDiscoveryAgent *qp, const QBluetoothAddress &localAddress) : - q_ptr(qp), + error(QBluetoothServiceDiscoveryAgent::NoError), - singleDevice(false), - localAdapterAddress(localAddress), + m_deviceAdapterAddress(localAddress), state(Inactive), - discoveryMode(QBluetoothServiceDiscoveryAgent::MinimalDiscovery) -{ - serviceInquiry.reset([[ObjCServiceInquiry alloc] initWithDelegate:this]); -} + mode(QBluetoothServiceDiscoveryAgent::MinimalDiscovery), + singleDevice(false), + q_ptr(qp) -void QBluetoothServiceDiscoveryAgentPrivate::startDeviceDiscovery() { - Q_ASSERT_X(q_ptr, Q_FUNC_INFO, "invalid q_ptr (null)"); - Q_ASSERT_X(state == Inactive, Q_FUNC_INFO, "invalid state"); - Q_ASSERT_X(error != QBluetoothServiceDiscoveryAgent::InvalidBluetoothAdapterError, - Q_FUNC_INFO, "invalid bluetooth adapter"); - - Q_ASSERT_X(deviceDiscoveryAgent.isNull(), "startDeviceDiscovery()", - "discovery agent already exists"); - - state = DeviceDiscovery; - - setupDeviceDiscoveryAgent(); - deviceDiscoveryAgent->start(QBluetoothDeviceDiscoveryAgent::ClassicMethod); + Q_ASSERT(q_ptr); + serviceInquiry.reset([[ObjCServiceInquiry alloc] initWithDelegate:this], RetainPolicy::noInitialRetain); } -void QBluetoothServiceDiscoveryAgentPrivate::stopDeviceDiscovery() +QBluetoothServiceDiscoveryAgentPrivate::~QBluetoothServiceDiscoveryAgentPrivate() { - Q_ASSERT_X(q_ptr, Q_FUNC_INFO, "invalid q_ptr (null)"); - Q_ASSERT_X(!deviceDiscoveryAgent.isNull(), Q_FUNC_INFO, - "invalid device discovery agent (null)"); - Q_ASSERT_X(state == DeviceDiscovery, Q_FUNC_INFO, "invalid state"); - - deviceDiscoveryAgent->stop(); - deviceDiscoveryAgent.reset(nullptr); - state = Inactive; - - emit q_ptr->canceled(); } -void QBluetoothServiceDiscoveryAgentPrivate::startServiceDiscovery() +void QBluetoothServiceDiscoveryAgentPrivate::start(const QBluetoothAddress &deviceAddress) { - // Any of 'Inactive'/'DeviceDiscovery'/'ServiceDiscovery' states - // are possible. - - Q_ASSERT_X(q_ptr, Q_FUNC_INFO, "invalid q_ptr (null)"); - Q_ASSERT_X(error != QBluetoothServiceDiscoveryAgent::InvalidBluetoothAdapterError, - Q_FUNC_INFO, "invalid bluetooth adapter"); - - if (discoveredDevices.isEmpty()) { - state = Inactive; - emit q_ptr->finished(); - return; - } - QT_BT_MAC_AUTORELEASEPOOL; - state = ServiceDiscovery; - const QBluetoothAddress &address(discoveredDevices.at(0).address()); - - if (address.isNull()) { + if (deviceAddress.isNull()) { // This can happen: LE scan works with CoreBluetooth, but CBPeripherals // do not expose hardware addresses. // Pop the current QBluetoothDeviceInfo and decide what to do next. - return serviceDiscoveryFinished(); + return _q_serviceDiscoveryFinished(); } // Autoreleased object. @@ -195,17 +105,18 @@ void QBluetoothServiceDiscoveryAgentPrivate::startServiceDiscovery() emit q_ptr->error(error); } - return serviceDiscoveryFinished(); + return _q_serviceDiscoveryFinished(); } if (DiscoveryMode() == QBluetoothServiceDiscoveryAgent::MinimalDiscovery) { - performMinimalServiceDiscovery(address); + performMinimalServiceDiscovery(deviceAddress); } else { IOReturn result = kIOReturnSuccess; + auto nativeInquiry = serviceInquiry.getAs<ObjCServiceInquiry>(); if (uuidFilter.size()) - result = [serviceInquiry performSDPQueryWithDevice:address filters:uuidFilter]; + result = [nativeInquiry performSDPQueryWithDevice:deviceAddress filters:uuidFilter]; else - result = [serviceInquiry performSDPQueryWithDevice:address]; + result = [nativeInquiry performSDPQueryWithDevice:deviceAddress]; if (result != kIOReturnSuccess) { // Failed immediately to perform an SDP inquiry on IOBluetoothDevice: @@ -214,87 +125,21 @@ void QBluetoothServiceDiscoveryAgentPrivate::startServiceDiscovery() } } -void QBluetoothServiceDiscoveryAgentPrivate::stopServiceDiscovery() +void QBluetoothServiceDiscoveryAgentPrivate::stop() { - Q_ASSERT_X(state != Inactive, Q_FUNC_INFO, "invalid state"); Q_ASSERT_X(q_ptr, Q_FUNC_INFO, "invalid q_ptr (null)"); discoveredDevices.clear(); - state = Inactive; // "Stops" immediately. - [serviceInquiry stopSDPQuery]; + [serviceInquiry.getAs<ObjCServiceInquiry>() stopSDPQuery]; emit q_ptr->canceled(); } -QBluetoothServiceDiscoveryAgentPrivate::DiscoveryState - QBluetoothServiceDiscoveryAgentPrivate::discoveryState() -{ - return state; -} - -void QBluetoothServiceDiscoveryAgentPrivate::setDiscoveryMode( - QBluetoothServiceDiscoveryAgent::DiscoveryMode m) -{ - discoveryMode = m; - -} - -QBluetoothServiceDiscoveryAgent::DiscoveryMode - QBluetoothServiceDiscoveryAgentPrivate::DiscoveryMode() -{ - return discoveryMode; -} - -void QBluetoothServiceDiscoveryAgentPrivate::_q_deviceDiscovered(const QBluetoothDeviceInfo &info) -{ - // Look for duplicates, and cached entries - for (int i = 0; i < discoveredDevices.count(); i++) { - if (discoveredDevices.at(i).address() == info.address()) { - discoveredDevices.removeAt(i); - break; - } - } - - discoveredDevices.prepend(info); -} - -void QBluetoothServiceDiscoveryAgentPrivate::_q_deviceDiscoveryError(QBluetoothDeviceDiscoveryAgent::Error) -{ - Q_ASSERT_X(q_ptr, Q_FUNC_INFO, "invalid q_ptr (null)"); - - error = QBluetoothServiceDiscoveryAgent::UnknownError; - errorString = QCoreApplication::translate(DEV_DISCOVERY, DD_UNKNOWN_ERROR); - - deviceDiscoveryAgent->stop(); - deviceDiscoveryAgent.reset(nullptr); - - state = QBluetoothServiceDiscoveryAgentPrivate::Inactive; - emit q_ptr->error(error); - emit q_ptr->finished(); -} - -void QBluetoothServiceDiscoveryAgentPrivate::_q_deviceDiscoveryFinished() -{ - Q_ASSERT_X(q_ptr, Q_FUNC_INFO, "invalid q_ptr (null)"); - - if (deviceDiscoveryAgent->error() != QBluetoothDeviceDiscoveryAgent::NoError) { - //Forward the device discovery error - error = static_cast<QBluetoothServiceDiscoveryAgent::Error>(deviceDiscoveryAgent->error()); - errorString = deviceDiscoveryAgent->errorString(); - deviceDiscoveryAgent.reset(nullptr); - state = Inactive; - emit q_ptr->error(error); - emit q_ptr->finished(); - } else { - deviceDiscoveryAgent.reset(nullptr); - startServiceDiscovery(); - } -} - -void QBluetoothServiceDiscoveryAgentPrivate::SDPInquiryFinished(IOBluetoothDevice *device) +void QBluetoothServiceDiscoveryAgentPrivate::SDPInquiryFinished(void *generic) { + auto device = static_cast<IOBluetoothDevice *>(generic); Q_ASSERT_X(device, Q_FUNC_INFO, "invalid IOBluetoothDevice (nil)"); if (state == Inactive) @@ -323,10 +168,10 @@ void QBluetoothServiceDiscoveryAgentPrivate::SDPInquiryFinished(IOBluetoothDevic } } - serviceDiscoveryFinished(); + _q_serviceDiscoveryFinished(); } -void QBluetoothServiceDiscoveryAgentPrivate::SDPInquiryError(IOBluetoothDevice *device, IOReturn errorCode) +void QBluetoothServiceDiscoveryAgentPrivate::SDPInquiryError(void *device, IOReturn errorCode) { Q_UNUSED(device) @@ -340,7 +185,7 @@ void QBluetoothServiceDiscoveryAgentPrivate::SDPInquiryError(IOBluetoothDevice * emit q_ptr->error(error); } - serviceDiscoveryFinished(); + _q_serviceDiscoveryFinished(); } void QBluetoothServiceDiscoveryAgentPrivate::performMinimalServiceDiscovery(const QBluetoothAddress &deviceAddress) @@ -371,7 +216,7 @@ void QBluetoothServiceDiscoveryAgentPrivate::performMinimalServiceDiscovery(cons if (!serviceInfo.isValid()) continue; - if (!uuidFilter.isEmpty() && !serviceHasMathingUuid(serviceInfo)) + if (!uuidFilter.isEmpty() && !serviceHasMatchingUuid(serviceInfo)) continue; if (!isDuplicatedService(serviceInfo)) { @@ -381,52 +226,10 @@ void QBluetoothServiceDiscoveryAgentPrivate::performMinimalServiceDiscovery(cons } } - serviceDiscoveryFinished(); -} - -void QBluetoothServiceDiscoveryAgentPrivate::setupDeviceDiscoveryAgent() -{ - Q_ASSERT_X(q_ptr, Q_FUNC_INFO, "invalid q_ptr (null)"); - Q_ASSERT_X(deviceDiscoveryAgent.isNull() || !deviceDiscoveryAgent->isActive(), - Q_FUNC_INFO, "device discovery agent is active"); - - deviceDiscoveryAgent.reset(new QBluetoothDeviceDiscoveryAgent(localAdapterAddress, q_ptr)); - - QObject::connect(deviceDiscoveryAgent.data(), &QBluetoothDeviceDiscoveryAgent::deviceDiscovered, - this, &QBluetoothServiceDiscoveryAgentPrivate::_q_deviceDiscovered); - QObject::connect(deviceDiscoveryAgent.data(), &QBluetoothDeviceDiscoveryAgent::finished, - this, &QBluetoothServiceDiscoveryAgentPrivate::_q_deviceDiscoveryFinished); - QObject::connect(deviceDiscoveryAgent.data(), - QOverload<QBluetoothDeviceDiscoveryAgent::Error>::of(&QBluetoothDeviceDiscoveryAgent::error), - this, - &QBluetoothServiceDiscoveryAgentPrivate::_q_deviceDiscoveryError); -} - -bool QBluetoothServiceDiscoveryAgentPrivate::isDuplicatedService(const QBluetoothServiceInfo &serviceInfo) const -{ - //check the service is not already part of our known list - for (int j = 0; j < discoveredServices.count(); j++) { - const QBluetoothServiceInfo &info = discoveredServices.at(j); - if (info.device() == serviceInfo.device() - && info.serviceClassUuids() == serviceInfo.serviceClassUuids() - && info.serviceUuid() == serviceInfo.serviceUuid()) { - return true; - } - } - - return false; -} - -void QBluetoothServiceDiscoveryAgentPrivate::serviceDiscoveryFinished() -{ - if (!discoveredDevices.isEmpty()) - discoveredDevices.removeFirst(); - - if (state == ServiceDiscovery) - startServiceDiscovery(); + _q_serviceDiscoveryFinished(); } -bool QBluetoothServiceDiscoveryAgentPrivate::serviceHasMathingUuid(const QBluetoothServiceInfo &serviceInfo) const +bool QBluetoothServiceDiscoveryAgentPrivate::serviceHasMatchingUuid(const QBluetoothServiceInfo &serviceInfo) const { for (const auto &requestedUuid : uuidFilter) { if (serviceInfo.serviceUuid() == requestedUuid) @@ -437,161 +240,4 @@ bool QBluetoothServiceDiscoveryAgentPrivate::serviceHasMathingUuid(const QBlueto return false; } -QBluetoothServiceDiscoveryAgent::QBluetoothServiceDiscoveryAgent(QObject *parent) -: QObject(parent), - d_ptr(new QBluetoothServiceDiscoveryAgentPrivate(this, QBluetoothAddress())) -{ -} - -QBluetoothServiceDiscoveryAgent::QBluetoothServiceDiscoveryAgent(const QBluetoothAddress &deviceAdapter, QObject *parent) -: QObject(parent), - d_ptr(new QBluetoothServiceDiscoveryAgentPrivate(this, deviceAdapter)) -{ - if (!deviceAdapter.isNull()) { - const QList<QBluetoothHostInfo> localDevices = QBluetoothLocalDevice::allDevices(); - for (const QBluetoothHostInfo &hostInfo : localDevices) { - if (hostInfo.address() == deviceAdapter) - return; - } - d_ptr->error = InvalidBluetoothAdapterError; - d_ptr->errorString = QCoreApplication::translate(SERVICE_DISCOVERY, SD_INVALID_ADDRESS); - } -} - -QBluetoothServiceDiscoveryAgent::~QBluetoothServiceDiscoveryAgent() -{ - delete d_ptr; -} - -QList<QBluetoothServiceInfo> QBluetoothServiceDiscoveryAgent::discoveredServices() const -{ - return d_ptr->discoveredServices; -} - -/* - Sets the UUID filter to \a uuids. Only services matching the UUIDs in \a uuids will be - returned. - - An empty UUID list is equivalent to a list containing only QBluetoothUuid::PublicBrowseGroup. - - \sa uuidFilter() -*/ -void QBluetoothServiceDiscoveryAgent::setUuidFilter(const QList<QBluetoothUuid> &uuids) -{ - d_ptr->uuidFilter = uuids; -} - -/* - This is an overloaded member function, provided for convenience. - - Sets the UUID filter to a list containing the single element \a uuid. - - \sa uuidFilter() -*/ -void QBluetoothServiceDiscoveryAgent::setUuidFilter(const QBluetoothUuid &uuid) -{ - d_ptr->uuidFilter.clear(); - d_ptr->uuidFilter.append(uuid); -} - -/* - Returns the UUID filter. - - \sa setUuidFilter() -*/ -QList<QBluetoothUuid> QBluetoothServiceDiscoveryAgent::uuidFilter() const -{ - return d_ptr->uuidFilter; -} - -/* - Sets the remote device address to \a address. If \a address is default constructed, - services will be discovered on all contactable Bluetooth devices. A new remote - address can only be set while there is no service discovery in progress; otherwise - this function returns false. - - \sa remoteAddress() -*/ -bool QBluetoothServiceDiscoveryAgent::setRemoteAddress(const QBluetoothAddress &address) -{ - if (isActive()) - return false; - - if (!address.isNull()) - d_ptr->singleDevice = true; - - d_ptr->deviceAddress = address; - return true; -} - -QBluetoothAddress QBluetoothServiceDiscoveryAgent::remoteAddress() const -{ - if (d_ptr->singleDevice) - return d_ptr->deviceAddress; - - return QBluetoothAddress(); -} - -void QBluetoothServiceDiscoveryAgent::start(DiscoveryMode mode) -{ - OSXBluetooth::qt_test_iobluetooth_runloop(); - - if (d_ptr->discoveryState() == QBluetoothServiceDiscoveryAgentPrivate::Inactive - && d_ptr->error != InvalidBluetoothAdapterError) - { - d_ptr->setDiscoveryMode(mode); - if (d_ptr->deviceAddress.isNull()) { - d_ptr->startDeviceDiscovery(); - } else { - d_ptr->discoveredDevices.append(QBluetoothDeviceInfo(d_ptr->deviceAddress, QString(), 0)); - d_ptr->startServiceDiscovery(); - } - } -} - -void QBluetoothServiceDiscoveryAgent::stop() -{ - if (d_ptr->error == InvalidBluetoothAdapterError || !isActive()) - return; - - switch (d_ptr->discoveryState()) { - case QBluetoothServiceDiscoveryAgentPrivate::DeviceDiscovery: - d_ptr->stopDeviceDiscovery(); - break; - case QBluetoothServiceDiscoveryAgentPrivate::ServiceDiscovery: - d_ptr->stopServiceDiscovery(); - default:; - } - - d_ptr->discoveredDevices.clear(); -} - -void QBluetoothServiceDiscoveryAgent::clear() -{ - // Don't clear the list while the search is ongoing - if (isActive()) - return; - - d_ptr->discoveredDevices.clear(); - d_ptr->discoveredServices.clear(); - d_ptr->uuidFilter.clear(); -} - -bool QBluetoothServiceDiscoveryAgent::isActive() const -{ - return d_ptr->state != QBluetoothServiceDiscoveryAgentPrivate::Inactive; -} - -QBluetoothServiceDiscoveryAgent::Error QBluetoothServiceDiscoveryAgent::error() const -{ - return d_ptr->error; -} - -QString QBluetoothServiceDiscoveryAgent::errorString() const -{ - return d_ptr->errorString; -} - -#include "moc_qbluetoothservicediscoveryagent.cpp" - QT_END_NAMESPACE |