summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTimur Pocheptsov <timur.pocheptsov@qt.io>2021-08-30 19:10:00 +0200
committerTimur Pocheptsov <timur.pocheptsov@qt.io>2021-09-10 21:13:03 +0200
commit4af45b1256b92880c1a7d04d16d732eef1bee2b9 (patch)
tree0b685e644cbe8ff775e7f13347e2912d06be55fe
parent9ce0f0459d1d55d9399801cac90db1f9924f5f1f (diff)
IOBluetoothDeviceInquiry: manually interrupt Classic scan
If 'inquiryLength' was ignored. This change is to be revisited after the official release of macOS 12 - it could be a bug in beta versions and all this additional timer machinery is a waste. The fact I was able to observe the same problem with 10.15.7 is quite troublesome though. Fixes: QTBUG-95960 Task-number: QTBUG-95686 Change-Id: I56685e07791dd751aec81bebbeefde19d31555df Reviewed-by: Ivan Solovev <ivan.solovev@qt.io> Reviewed-by: Alex Blasche <alexander.blasche@qt.io> (cherry picked from commit cf8ade9fd809e62cb61bb897b3789c75a48f5996)
-rw-r--r--src/bluetooth/osx/osxbtdeviceinquiry.mm65
1 files changed, 46 insertions, 19 deletions
diff --git a/src/bluetooth/osx/osxbtdeviceinquiry.mm b/src/bluetooth/osx/osxbtdeviceinquiry.mm
index d142da4d..5f95d617 100644
--- a/src/bluetooth/osx/osxbtdeviceinquiry.mm
+++ b/src/bluetooth/osx/osxbtdeviceinquiry.mm
@@ -41,15 +41,22 @@
#include "osxbtutility_p.h"
#include <QtCore/qloggingcategory.h>
+#include <QtCore/qtimer.h>
#include <QtCore/qdebug.h>
+#include <memory>
+
QT_USE_NAMESPACE
+const uint8_t IOBlueoothInquiryLengthS = 15;
+
@implementation QT_MANGLE_NAMESPACE(OSXBTDeviceInquiry)
{
IOBluetoothDeviceInquiry *m_inquiry;
bool m_active;
DarwinBluetooth::DeviceInquiryDelegate *m_delegate;//C++ "delegate"
+
+ std::unique_ptr<QTimer> watchDog;
}
- (id)initWithDelegate:(DarwinBluetooth::DeviceInquiryDelegate *)delegate
@@ -60,7 +67,13 @@ QT_USE_NAMESPACE
m_inquiry = [[IOBluetoothDeviceInquiry inquiryWithDelegate:self] retain];
if (m_inquiry) {
- [m_inquiry setInquiryLength:15];
+ // Inquiry length is 15 seconds. Starting from macOS 10.15.7
+ // (the lowest version I was able to test on, though initially
+ // the problem was found on macOS 11, arm64 machine and then
+ // confirmed on macOS 12 Beta 4), it seems to be ignored,
+ // thus scan never stops. See -start for how we try to prevent
+ // this.
+ [m_inquiry setInquiryLength:IOBlueoothInquiryLengthS];
[m_inquiry setUpdateNewDeviceNames:NO];//Useless, disable!
m_delegate = delegate;
} else {
@@ -102,9 +115,21 @@ QT_USE_NAMESPACE
const IOReturn result = [m_inquiry start];
if (result != kIOReturnSuccess) {
// QtBluetooth will probably convert an error into UnknownError,
- // loosing the actual information.
+ // losing the actual information.
qCWarning(QT_BT_OSX) << "failed with IOKit error code:" << result;
m_active = false;
+ } else {
+ // Docs say it's 10 s. by default, we set it to 15 s. (see -initWithDelegate:),
+ // and it may fail to finish.
+ watchDog.reset(new QTimer);
+ watchDog->connect(watchDog.get(), &QTimer::timeout, watchDog.get(), [self]{
+ qCWarning(QT_BT_OSX, "Manually interrupting IOBluetoothDeviceInquiry");
+ [self stop];
+ });
+
+ watchDog->setSingleShot(true);
+ watchDog->setInterval(IOBlueoothInquiryLengthS * 2 * 1000); // Let's make it twice as long.
+ watchDog->start();
}
return result;
@@ -112,40 +137,36 @@ QT_USE_NAMESPACE
- (IOReturn)stop
{
- if (m_active) {
- Q_ASSERT_X(m_inquiry, Q_FUNC_INFO, "active but nil inquiry");
+ if (!m_active)
+ return kIOReturnSuccess;
- m_active = false;
- const IOReturn res = [m_inquiry stop];
- if (res != kIOReturnSuccess)
- m_active = true;
- else
- qCDebug(QT_BT_OSX) << "-stop, success (waiting for 'inquiryComplete')";
-
- return res;
- }
+ Q_ASSERT_X(m_inquiry, Q_FUNC_INFO, "active but nil inquiry");
- return kIOReturnSuccess;
+ return [m_inquiry stop];
}
- (void)deviceInquiryComplete:(IOBluetoothDeviceInquiry *)sender
error:(IOReturn)error aborted:(BOOL)aborted
{
- Q_UNUSED(aborted)
+ if (!m_active)
+ return;
if (sender != m_inquiry) // Can never happen in the current version.
return;
- m_active = false;
-
Q_ASSERT_X(m_delegate, Q_FUNC_INFO, "invalid device inquiry delegate (null)");
- if (error != kIOReturnSuccess) {
+ if (error != kIOReturnSuccess && !aborted) {
// QtBluetooth has not too many error codes, 'UnknownError' is not really
// useful, report the actual error code here:
qCWarning(QT_BT_OSX) << "IOKit error code: " << error;
m_delegate->error(error);
+ // Let watchDog to stop it, calling -stop at timeout, otherwise,
+ // it looks like inquiry continues and keeps reporting new devices found.
} else {
+ // Either a normal completion or from a timer slot.
+ watchDog.reset();
+ m_active = false;
m_delegate->inquiryFinished();
}
}
@@ -156,13 +177,19 @@ QT_USE_NAMESPACE
if (sender != m_inquiry) // Can never happen in the current version.
return;
+ if (!m_active) {
+ // We are not expecting new device(s) to be found after we reported 'finished'.
+ qCWarning(QT_BT_OSX, "IOBluetooth device found after inquiry complete/interrupted");
+ return;
+ }
+
Q_ASSERT_X(m_delegate, Q_FUNC_INFO, "invalid device inquiry delegate (null)");
m_delegate->classicDeviceFound(device);
}
- (void)deviceInquiryStarted:(IOBluetoothDeviceInquiry *)sender
{
- Q_UNUSED(sender)
+ Q_UNUSED(sender);
}
@end