Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qbluetoothservicediscoveryagent_macos.mm
Go to the documentation of this file.
1// Copyright (C) 2022 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
10#include "darwin/btutility_p.h"
11#include "darwin/uistrings_p.h"
12
13#include <QtCore/qoperatingsystemversion.h>
14#include <QtCore/qcoreapplication.h>
15#include <QtCore/qloggingcategory.h>
16#include <QtCore/qstring.h>
17#include <QtCore/qglobal.h>
18#include <QtCore/qdebug.h>
19#include <QtCore/qlist.h>
20
21#include <Foundation/Foundation.h>
22
23#include <IOBluetooth/IOBluetooth.h>
24
26
27namespace {
28
30
31}
32
34 QBluetoothServiceDiscoveryAgent *qp, const QBluetoothAddress &localAddress) :
35
37 m_deviceAdapterAddress(localAddress),
38 state(Inactive),
39 mode(QBluetoothServiceDiscoveryAgent::MinimalDiscovery),
40 singleDevice(false),
41 q_ptr(qp)
42
43{
44 Q_ASSERT(q_ptr);
45 serviceInquiry.reset([[DarwinBTSDPInquiry alloc] initWithDelegate:this], RetainPolicy::noInitialRetain);
46}
47
49{
50}
51
52void QBluetoothServiceDiscoveryAgentPrivate::start(const QBluetoothAddress &deviceAddress)
53{
55
56 if (deviceAddress.isNull()) {
57 // This can happen: LE scan works with CoreBluetooth, but CBPeripherals
58 // do not expose hardware addresses.
59 // Pop the current QBluetoothDeviceInfo and decide what to do next.
61 }
62
63 // Autoreleased object.
64 IOBluetoothHostController *const hc = [IOBluetoothHostController defaultController];
65 if (![hc powerState]) {
67 if (singleDevice) {
71 }
72
74 }
75
77 performMinimalServiceDiscovery(deviceAddress);
78 } else {
79 IOReturn result = kIOReturnSuccess;
80 auto nativeInquiry = serviceInquiry.getAs<DarwinBTSDPInquiry>();
81 if (uuidFilter.size())
82 result = [nativeInquiry performSDPQueryWithDevice:deviceAddress filters:uuidFilter];
83 else
84 result = [nativeInquiry performSDPQueryWithDevice:deviceAddress];
85
86 if (result != kIOReturnSuccess) {
87 // Failed immediately to perform an SDP inquiry on IOBluetoothDevice:
88 SDPInquiryError(nil, result);
89 }
90 }
91}
92
93void QBluetoothServiceDiscoveryAgentPrivate::stop()
94{
95 Q_ASSERT_X(q_ptr, Q_FUNC_INFO, "invalid q_ptr (null)");
96
98
99 // "Stops" immediately.
100 [serviceInquiry.getAs<DarwinBTSDPInquiry>() stopSDPQuery];
101
103}
104
105void QBluetoothServiceDiscoveryAgentPrivate::SDPInquiryFinished(void *generic)
106{
107 auto device = static_cast<IOBluetoothDevice *>(generic);
108 Q_ASSERT_X(device, Q_FUNC_INFO, "invalid IOBluetoothDevice (nil)");
109
110 if (state == Inactive)
111 return;
112
114
115 NSArray *const records = device.services;
116 qCDebug(QT_BT_DARWIN) << "SDP finished for device" << [device nameOrAddress]
117 << ", services found:" << [records count];
118 for (IOBluetoothSDPServiceRecord *record in records) {
119 QBluetoothServiceInfo serviceInfo;
120 Q_ASSERT_X(discoveredDevices.size() >= 1, Q_FUNC_INFO, "invalid number of devices");
121
122 qCDebug(QT_BT_DARWIN) << "Processing service" << [record getServiceName];
123 serviceInfo.setDevice(discoveredDevices.at(0));
125
126 if (!serviceInfo.isValid()) {
127 qCDebug(QT_BT_DARWIN) << "Discarding invalid service";
128 continue;
129 }
130
132 && uuidFilter.size()) {
133 const auto &serviceId = serviceInfo.serviceUuid();
134 bool match = !serviceId.isNull() && uuidFilter.contains(serviceId);
135 if (!match) {
136 const auto &classUuids = serviceInfo.serviceClassUuids();
137 for (const auto &uuid : classUuids) {
138 if (uuidFilter.contains(uuid)) {
139 match = true;
140 break;
141 }
142 }
143 if (!match)
144 continue;
145 }
146 }
147
148
149 if (!isDuplicatedService(serviceInfo)) {
150 discoveredServices.append(serviceInfo);
151 emit q_ptr->serviceDiscovered(serviceInfo);
152 // Here a user code can ... interrupt us by calling
153 // stop. Check this.
154 if (state == Inactive)
155 break;
156 }
157 }
158
160}
161
162void QBluetoothServiceDiscoveryAgentPrivate::SDPInquiryError(void *device, IOReturn errorCode)
163{
165
166 qCWarning(QT_BT_DARWIN) << "inquiry failed with IOKit code:" << int(errorCode);
167
169 // TODO: find a better mapping from IOReturn to QBluetoothServiceDiscoveryAgent::Error.
170 if (singleDevice) {
174 }
175
177}
178
179void QBluetoothServiceDiscoveryAgentPrivate::performMinimalServiceDiscovery(const QBluetoothAddress &deviceAddress)
180{
181 Q_ASSERT_X(!deviceAddress.isNull(), Q_FUNC_INFO, "invalid device address");
182
184
185 const BluetoothDeviceAddress iobtAddress = DarwinBluetooth::iobluetooth_address(deviceAddress);
186 IOBluetoothDevice *const device = [IOBluetoothDevice deviceWithAddress:&iobtAddress];
187 if (!device || !device.services) {
188 if (singleDevice) {
192 }
193 } else {
194
195 NSArray *const records = device.services;
196 for (IOBluetoothSDPServiceRecord *record in records) {
197 QBluetoothServiceInfo serviceInfo;
199 "invalid number of devices");
200
201 serviceInfo.setDevice(discoveredDevices.at(0));
203
204 if (!serviceInfo.isValid())
205 continue;
206
207 if (!uuidFilter.isEmpty() && !serviceHasMatchingUuid(serviceInfo))
208 continue;
209
210 if (!isDuplicatedService(serviceInfo)) {
211 discoveredServices.append(serviceInfo);
212 emit q_ptr->serviceDiscovered(serviceInfo);
213 }
214 }
215 }
216
218}
219
220bool QBluetoothServiceDiscoveryAgentPrivate::serviceHasMatchingUuid(const QBluetoothServiceInfo &serviceInfo) const
221{
222 for (const auto &requestedUuid : uuidFilter) {
223 if (serviceInfo.serviceUuid() == requestedUuid)
224 return true;
225 if (serviceInfo.serviceClassUuids().contains(requestedUuid))
226 return true;
227 }
228 return false;
229}
230
IOBluetoothDevice * device
#define QT_BT_MAC_AUTORELEASEPOOL
Definition btutility_p.h:78
\inmodule QtBluetooth
QBluetoothServiceDiscoveryAgentPrivate(QBluetoothServiceDiscoveryAgent *qp, const QBluetoothAddress &deviceAdapter)
QBluetoothServiceDiscoveryAgent::DiscoveryMode DiscoveryMode()
void serviceDiscovered(const QBluetoothServiceInfo &info)
This signal is emitted when the Bluetooth service described by info is discovered.
void errorOccurred(QBluetoothServiceDiscoveryAgent::Error error)
This signal is emitted when an error occurs.
void canceled()
This signal is triggered when the service discovery was canceled via a call to \l stop().
\inmodule QtBluetooth
static QString translate(const char *context, const char *key, const char *disambiguation=nullptr, int n=-1)
\threadsafe
qsizetype size() const noexcept
Definition qlist.h:397
bool isEmpty() const noexcept
Definition qlist.h:401
const_reference at(qsizetype i) const noexcept
Definition qlist.h:446
void append(parameter_type t)
Definition qlist.h:458
void clear()
Definition qlist.h:434
static Q_CORE_EXPORT QOperatingSystemVersionBase current()
static constexpr QOperatingSystemVersionBase MacOSBigSur
\variable QOperatingSystemVersion::MacOSBigSur
#define this
Definition dialogs.cpp:9
else opt state
[0]
void extract_service_record(IOBluetoothSDPServiceRecord *record, QBluetoothServiceInfo &serviceInfo)
BluetoothDeviceAddress iobluetooth_address(const QBluetoothAddress &qAddress)
Definition btutility.mm:65
Combined button and popup list for selecting options.
#define Q_FUNC_INFO
DBusConnection const char DBusError * error
#define qCWarning(category,...)
#define qCDebug(category,...)
GLenum mode
GLenum GLenum GLsizei count
GLuint in
GLuint64EXT * result
[6]
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define Q_ASSERT_X(cond, x, msg)
Definition qrandom.cpp:48
@ NoError
Definition main.cpp:34
const char SERVICE_DISCOVERY[]
Definition uistrings.cpp:24
const char SD_MINIMAL_FAILED[]
Definition uistrings.cpp:26
const char DD_UNKNOWN_ERROR[]
Definition uistrings.cpp:18
QT_BEGIN_NAMESPACE const char DEV_DISCOVERY[]
Definition uistrings.cpp:13
const char SD_LOCAL_DEV_OFF[]
Definition uistrings.cpp:25
#define emit
#define Q_UNUSED(x)
static bool match(const uchar *found, uint foundLen, const char *target, uint targetLen)
MyRecord record(int row) const
[0]
const QStringList filters({"Image files (*.png *.xpm *.jpg)", "Text files (*.txt)", "Any files (*)" })
[6]
bool contains(const AT &t) const noexcept
Definition qlist.h:45