From 102bdf35b13f1b60df26052341ebc5a2833518c7 Mon Sep 17 00:00:00 2001 From: Richard Moe Gustavsen Date: Thu, 30 May 2013 10:07:29 +0200 Subject: iOS: change accelerometer to use QTimer for polling According to the docs (CMMotionManager class reference) there are two ways of interacting with the accelerometer; Either through the callback API (NSOperationQueue), or peridic sampling (polling). Our first implementation of IOSAcceleometer used the former technique, which turns out to have bad performance when using the sensor together with a fine-grained QTimer. And this case is pretty common when using sensors together with e.g QML. Reading through the docs more carefully, they recommend using the polling technique when creating games instead since the NSOperationQueue introduces some overhead. So this patch does that, change the implementation to use QTimer based polling. And this solves the performance issues found. Change-Id: Ifde0d2292302467afb8db90a954ef45f3238350e Reviewed-by: Thomas McGuire --- src/plugins/sensors/ios/iosaccelerometer.h | 9 +++-- src/plugins/sensors/ios/iosaccelerometer.mm | 52 +++++++++++------------------ 2 files changed, 24 insertions(+), 37 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/sensors/ios/iosaccelerometer.h b/src/plugins/sensors/ios/iosaccelerometer.h index 5fcac19f..1a6560b1 100644 --- a/src/plugins/sensors/ios/iosaccelerometer.h +++ b/src/plugins/sensors/ios/iosaccelerometer.h @@ -42,29 +42,28 @@ #ifndef IOSACCELEROMETER_H #define IOSACCELEROMETER_H -#include +#include #include #include QT_BEGIN_NAMESPACE -@class QtIoAccelListener; - class IOSAccelerometer : public QSensorBackend { public: static char const * const id; explicit IOSAccelerometer(QSensor *sensor); - ~IOSAccelerometer(); + void timerEvent(QTimerEvent *); void start(); void stop(); private: - NSOperationQueue *m_updateQueue; + CMMotionManager *m_motionManager; QAccelerometerReading m_reading; + int m_timer; }; QT_END_NAMESPACE diff --git a/src/plugins/sensors/ios/iosaccelerometer.mm b/src/plugins/sensors/ios/iosaccelerometer.mm index b657b507..5f9c0f16 100644 --- a/src/plugins/sensors/ios/iosaccelerometer.mm +++ b/src/plugins/sensors/ios/iosaccelerometer.mm @@ -40,8 +40,6 @@ ****************************************************************************/ #include -#include -#include #include "iosaccelerometer.h" #include "iosmotionmanager.h" @@ -52,49 +50,39 @@ QT_BEGIN_NAMESPACE IOSAccelerometer::IOSAccelerometer(QSensor *sensor) : QSensorBackend(sensor) - , m_updateQueue([[NSOperationQueue alloc] init]) + , m_motionManager([QIOSMotionManager sharedManager]) + , m_timer(0) { setReading(&m_reading); addDataRate(1, 100); // 100Hz addOutputRange(-22.418, 22.418, 0.17651); // 2G } -IOSAccelerometer::~IOSAccelerometer() -{ - [m_updateQueue release]; -} - void IOSAccelerometer::start() { - CMMotionManager *motionManager = [QIOSMotionManager sharedManager]; - // Convert from Hz to NSTimeInterval: int hz = sensor()->dataRate(); - motionManager.accelerometerUpdateInterval = (hz == 0) ? 0 : 1. / hz; - - QPointer self = this; - [motionManager startAccelerometerUpdatesToQueue:m_updateQueue withHandler:^(CMAccelerometerData *data, NSError *error) { - // NSOperationQueue is multi-threaded, so we process the data by queuing a callback to - // the main application queue. By the time the callback executes, IOSAccelerometer might - // have been deleted, so we need an extra QPointer check for that: - dispatch_async(dispatch_get_main_queue(), ^{ - if (self) { - Q_UNUSED(error); - // Convert from NSTimeInterval to microseconds and G to m/s2, and flip axes: - CMAcceleration acc = data.acceleration; - const qreal G = 9.8066; - m_reading.setTimestamp(quint64(data.timestamp * 1000000)); - m_reading.setX(qreal(acc.x) * G * -1); - m_reading.setY(qreal(acc.y) * G * -1); - m_reading.setZ(qreal(acc.z) * G * -1); - newReadingAvailable(); - } - }); - }]; + m_timer = startTimer(1000 / (hz == 0 ? 60 : hz)); + [m_motionManager startAccelerometerUpdates]; } void IOSAccelerometer::stop() { - [[QIOSMotionManager sharedManager] stopAccelerometerUpdates]; + [m_motionManager stopAccelerometerUpdates]; + killTimer(m_timer); + m_timer = 0; +} + +void IOSAccelerometer::timerEvent(QTimerEvent *) +{ + // Convert from NSTimeInterval to microseconds and G to m/s2, and flip axes: + CMAccelerometerData *data = m_motionManager.accelerometerData; + CMAcceleration acc = data.acceleration; + static const qreal G = 9.8066; + m_reading.setTimestamp(quint64(data.timestamp * 1e6)); + m_reading.setX(qreal(acc.x) * G * -1); + m_reading.setY(qreal(acc.y) * G * -1); + m_reading.setZ(qreal(acc.z) * G * -1); + newReadingAvailable(); } QT_END_NAMESPACE -- cgit v1.2.3