summaryrefslogtreecommitdiffstats
path: root/content/browser/device_orientation
diff options
context:
space:
mode:
authorthakis@chromium.org <thakis@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-08-27 23:55:44 +0000
committerthakis@chromium.org <thakis@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-08-27 23:55:44 +0000
commitf4195b9441438b98f232167e50e0086474d7bc50 (patch)
treeb3f2cda1241f6dfb8f854ca119768b494ccd151b /content/browser/device_orientation
parentb7520dd23365bdc2ab52e6730d9b6e6b647e2e8f (diff)
downloadchromium_src-f4195b9441438b98f232167e50e0086474d7bc50.zip
chromium_src-f4195b9441438b98f232167e50e0086474d7bc50.tar.gz
chromium_src-f4195b9441438b98f232167e50e0086474d7bc50.tar.bz2
Mac: implement orientation/motion shared memory data fetcher.
Add Device Motion/Orientation data fetcher for the mac platform. The fetcher uses the mac's sudden motion sensor to obtain acceleration and orientation information. It uses a polling thread to update shared memory at regular intervals. This patch also contains some minor changes to the base polling thread implementation to make the fetcher thread safe. also fixes a leak in a test, see crbug.com/280129. BUG=261165,280129 NOTRY=true R=bulach@chromium.org, piman@chromium.org Review URL: https://codereview.chromium.org/22926029 Patch from Tim Volodine <timvolodine@chromium.org>. git-svn-id: svn://svn.chromium.org/chrome/trunk/src@219861 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content/browser/device_orientation')
-rw-r--r--content/browser/device_orientation/data_fetcher_shared_memory.h16
-rw-r--r--content/browser/device_orientation/data_fetcher_shared_memory_base.cc70
-rw-r--r--content/browser/device_orientation/data_fetcher_shared_memory_base.h5
-rw-r--r--content/browser/device_orientation/data_fetcher_shared_memory_base_unittest.cc68
-rw-r--r--content/browser/device_orientation/data_fetcher_shared_memory_mac.cc163
5 files changed, 257 insertions, 65 deletions
diff --git a/content/browser/device_orientation/data_fetcher_shared_memory.h b/content/browser/device_orientation/data_fetcher_shared_memory.h
index 9d378eb..cbc274a 100644
--- a/content/browser/device_orientation/data_fetcher_shared_memory.h
+++ b/content/browser/device_orientation/data_fetcher_shared_memory.h
@@ -7,6 +7,13 @@
#include "content/browser/device_orientation/data_fetcher_shared_memory_base.h"
+#if defined(OS_MACOSX)
+#include "content/common/device_motion_hardware_buffer.h"
+#include "content/common/device_orientation/device_orientation_hardware_buffer.h"
+
+class SuddenMotionSensor;
+#endif
+
namespace content {
class CONTENT_EXPORT DataFetcherSharedMemory
@@ -21,6 +28,15 @@ class CONTENT_EXPORT DataFetcherSharedMemory
virtual bool Start(ConsumerType consumer_type) OVERRIDE;
virtual bool Stop(ConsumerType consumer_type) OVERRIDE;
+#if defined(OS_MACOSX)
+ virtual void Fetch(unsigned consumer_bitmask) OVERRIDE;
+ virtual bool IsPolling() const OVERRIDE;
+
+ DeviceMotionHardwareBuffer* motion_buffer_;
+ DeviceOrientationHardwareBuffer* orientation_buffer_;
+ scoped_ptr<SuddenMotionSensor> sudden_motion_sensor_;
+#endif
+
DISALLOW_COPY_AND_ASSIGN(DataFetcherSharedMemory);
};
diff --git a/content/browser/device_orientation/data_fetcher_shared_memory_base.cc b/content/browser/device_orientation/data_fetcher_shared_memory_base.cc
index 167b787..5b60f1f 100644
--- a/content/browser/device_orientation/data_fetcher_shared_memory_base.cc
+++ b/content/browser/device_orientation/data_fetcher_shared_memory_base.cc
@@ -21,7 +21,9 @@ class DataFetcherSharedMemoryBase::PollingThread : public base::Thread {
PollingThread(const char* name, DataFetcherSharedMemoryBase* fetcher);
virtual ~PollingThread();
- void SetConsumers(int consumers_bitmask);
+ void AddConsumer(ConsumerType consumer_type);
+ void RemoveConsumer(ConsumerType consumer_type);
+
unsigned GetConsumersBitmask() const { return consumers_bitmask_; }
private:
@@ -45,13 +47,13 @@ DataFetcherSharedMemoryBase::PollingThread::PollingThread(
DataFetcherSharedMemoryBase::PollingThread::~PollingThread() {
}
-void DataFetcherSharedMemoryBase::PollingThread::SetConsumers(
- int consumers_bitmask) {
- consumers_bitmask_ = consumers_bitmask;
- if (!consumers_bitmask_) {
- timer_.reset(); // will also stop the timer.
+void DataFetcherSharedMemoryBase::PollingThread::AddConsumer(
+ ConsumerType consumer_type) {
+ DCHECK(fetcher_);
+ if (!fetcher_->Start(consumer_type))
return;
- }
+
+ consumers_bitmask_ |= consumer_type;
if (!timer_)
timer_.reset(new base::RepeatingTimer<PollingThread>());
@@ -61,6 +63,18 @@ void DataFetcherSharedMemoryBase::PollingThread::SetConsumers(
this, &PollingThread::DoPoll);
}
+void DataFetcherSharedMemoryBase::PollingThread::RemoveConsumer(
+ ConsumerType consumer_type) {
+ DCHECK(fetcher_);
+ if (!fetcher_->Stop(consumer_type))
+ return;
+
+ consumers_bitmask_ ^= consumer_type;
+
+ if (!consumers_bitmask_)
+ timer_.reset(); // will also stop the timer.
+}
+
void DataFetcherSharedMemoryBase::PollingThread::DoPoll() {
DCHECK(fetcher_);
DCHECK(consumers_bitmask_);
@@ -90,23 +104,21 @@ bool DataFetcherSharedMemoryBase::StartFetchingDeviceData(
if (started_consumers_ & consumer_type)
return true;
- if (!Start(consumer_type))
- return false;
-
- started_consumers_ |= consumer_type;
-
if (IsPolling()) {
- if (!InitAndStartPollingThreadIfNecessary()) {
- Stop(consumer_type);
- started_consumers_ ^= consumer_type;
+ if (!InitAndStartPollingThreadIfNecessary())
return false;
- }
polling_thread_->message_loop()->PostTask(
FROM_HERE,
- base::Bind(&PollingThread::SetConsumers,
+ base::Bind(&PollingThread::AddConsumer,
base::Unretained(polling_thread_.get()),
- started_consumers_));
+ consumer_type));
+ } else {
+ if (!Start(consumer_type))
+ return false;
}
+
+ started_consumers_ |= consumer_type;
+
return true;
}
@@ -115,18 +127,19 @@ bool DataFetcherSharedMemoryBase::StopFetchingDeviceData(
if (!(started_consumers_ & consumer_type))
return true;
- if (!Stop(consumer_type))
- return false;
-
- started_consumers_ ^= consumer_type;
-
if (IsPolling()) {
polling_thread_->message_loop()->PostTask(
FROM_HERE,
- base::Bind(&PollingThread::SetConsumers,
+ base::Bind(&PollingThread::RemoveConsumer,
base::Unretained(polling_thread_.get()),
- started_consumers_));
+ consumer_type));
+ } else {
+ if (!Stop(consumer_type))
+ return false;
}
+
+ started_consumers_ ^= consumer_type;
+
return true;
}
@@ -170,12 +183,13 @@ base::SharedMemory* DataFetcherSharedMemoryBase::InitSharedMemory(
if (it != shared_memory_map_.end())
return it->second;
- base::SharedMemory* new_shared_mem = new base::SharedMemory;
+ scoped_ptr<base::SharedMemory> new_shared_mem(new base::SharedMemory);
if (new_shared_mem->CreateAndMapAnonymous(buffer_size)) {
if (void* mem = new_shared_mem->memory()) {
memset(mem, 0, buffer_size);
- shared_memory_map_[consumer_type] = new_shared_mem;
- return new_shared_mem;
+ base::SharedMemory* shared_mem = new_shared_mem.release();
+ shared_memory_map_[consumer_type] = shared_mem;
+ return shared_mem;
}
}
LOG(ERROR) << "Failed to initialize shared memory";
diff --git a/content/browser/device_orientation/data_fetcher_shared_memory_base.h b/content/browser/device_orientation/data_fetcher_shared_memory_base.h
index a449596..3bd4103 100644
--- a/content/browser/device_orientation/data_fetcher_shared_memory_base.h
+++ b/content/browser/device_orientation/data_fetcher_shared_memory_base.h
@@ -59,8 +59,9 @@ class CONTENT_EXPORT DataFetcherSharedMemoryBase {
// fetch the sensor data.
virtual bool IsPolling() const;
- // Start() method should call InitSharedMemoryBuffer() and cache the obtained
- // pointer for efficienty and thread-safety.
+ // Start() method should call InitSharedMemoryBuffer() to get the shared
+ // memory pointer. If IsPolling() is true both Start() and Stop() methods
+ // are called from the |polling_thread_|.
virtual bool Start(ConsumerType consumer_type) = 0;
virtual bool Stop(ConsumerType consumer_type) = 0;
diff --git a/content/browser/device_orientation/data_fetcher_shared_memory_base_unittest.cc b/content/browser/device_orientation/data_fetcher_shared_memory_base_unittest.cc
index b580872..d9b8835 100644
--- a/content/browser/device_orientation/data_fetcher_shared_memory_base_unittest.cc
+++ b/content/browser/device_orientation/data_fetcher_shared_memory_base_unittest.cc
@@ -147,18 +147,20 @@ class FakePollingDataFetcher : public FakeDataFetcher {
virtual ~FakePollingDataFetcher() { }
virtual bool Start(ConsumerType consumer_type) OVERRIDE {
+ EXPECT_TRUE(base::MessageLoop::current() == GetPollingMessageLoop());
Init(consumer_type);
start_.Signal();
return true;
}
virtual bool Stop(ConsumerType consumer_type) OVERRIDE {
+ EXPECT_TRUE(base::MessageLoop::current() == GetPollingMessageLoop());
stop_.Signal();
return true;
}
virtual void Fetch(unsigned consumer_bitmask) OVERRIDE {
- DCHECK(base::MessageLoop::current() == GetPollingMessageLoop());
+ EXPECT_TRUE(base::MessageLoop::current() == GetPollingMessageLoop());
if (consumer_bitmask & CONSUMER_TYPE_ORIENTATION)
UpdateOrientation();
@@ -179,65 +181,61 @@ class FakePollingDataFetcher : public FakeDataFetcher {
TEST(DataFetcherSharedMemoryBaseTest, DoesStartMotion) {
- FakeNonPollingDataFetcher* mock_data_fetcher =
- new FakeNonPollingDataFetcher();
- EXPECT_FALSE(mock_data_fetcher->IsPolling());
+ FakeNonPollingDataFetcher mock_data_fetcher;
+ EXPECT_FALSE(mock_data_fetcher.IsPolling());
- EXPECT_TRUE(mock_data_fetcher->StartFetchingDeviceData(CONSUMER_TYPE_MOTION));
- mock_data_fetcher->WaitForStart();
+ EXPECT_TRUE(mock_data_fetcher.StartFetchingDeviceData(CONSUMER_TYPE_MOTION));
+ mock_data_fetcher.WaitForStart();
EXPECT_EQ(kPeriodInMilliseconds,
- mock_data_fetcher->GetMotionBuffer()->data.interval);
+ mock_data_fetcher.GetMotionBuffer()->data.interval);
- mock_data_fetcher->StopFetchingDeviceData(CONSUMER_TYPE_MOTION);
- mock_data_fetcher->WaitForStop();
+ mock_data_fetcher.StopFetchingDeviceData(CONSUMER_TYPE_MOTION);
+ mock_data_fetcher.WaitForStop();
}
TEST(DataFetcherSharedMemoryBaseTest, DoesStartOrientation) {
- FakeNonPollingDataFetcher* mock_data_fetcher =
- new FakeNonPollingDataFetcher();
- EXPECT_FALSE(mock_data_fetcher->IsPolling());
+ FakeNonPollingDataFetcher mock_data_fetcher;
+ EXPECT_FALSE(mock_data_fetcher.IsPolling());
- EXPECT_TRUE(mock_data_fetcher->StartFetchingDeviceData(
+ EXPECT_TRUE(mock_data_fetcher.StartFetchingDeviceData(
CONSUMER_TYPE_ORIENTATION));
- mock_data_fetcher->WaitForStart();
+ mock_data_fetcher.WaitForStart();
- EXPECT_EQ(1, mock_data_fetcher->GetOrientationBuffer()->data.alpha);
+ EXPECT_EQ(1, mock_data_fetcher.GetOrientationBuffer()->data.alpha);
- mock_data_fetcher->StopFetchingDeviceData(CONSUMER_TYPE_ORIENTATION);
- mock_data_fetcher->WaitForStop();
+ mock_data_fetcher.StopFetchingDeviceData(CONSUMER_TYPE_ORIENTATION);
+ mock_data_fetcher.WaitForStop();
}
TEST(DataFetcherSharedMemoryBaseTest, DoesPollMotion) {
- FakePollingDataFetcher* mock_data_fetcher =
- new FakePollingDataFetcher();
- EXPECT_TRUE(mock_data_fetcher->IsPolling());
+ FakePollingDataFetcher mock_data_fetcher;
+ EXPECT_TRUE(mock_data_fetcher.IsPolling());
- EXPECT_TRUE(mock_data_fetcher->StartFetchingDeviceData(CONSUMER_TYPE_MOTION));
- mock_data_fetcher->WaitForStart();
- mock_data_fetcher->WaitForUpdateMotion();
+ EXPECT_TRUE(mock_data_fetcher.StartFetchingDeviceData(CONSUMER_TYPE_MOTION));
+ mock_data_fetcher.WaitForStart();
+ mock_data_fetcher.WaitForUpdateMotion();
EXPECT_EQ(kPeriodInMilliseconds,
- mock_data_fetcher->GetMotionBuffer()->data.interval);
+ mock_data_fetcher.GetMotionBuffer()->data.interval);
- mock_data_fetcher->StopFetchingDeviceData(CONSUMER_TYPE_MOTION);
- mock_data_fetcher->WaitForStop();
+ mock_data_fetcher.StopFetchingDeviceData(CONSUMER_TYPE_MOTION);
+ mock_data_fetcher.WaitForStop();
}
TEST(DataFetcherSharedMemoryBaseTest, DoesPollOrientation) {
- FakePollingDataFetcher* mock_data_fetcher =
- new FakePollingDataFetcher();
- EXPECT_TRUE(mock_data_fetcher->IsPolling());
+ FakePollingDataFetcher mock_data_fetcher;
+ EXPECT_TRUE(mock_data_fetcher.IsPolling());
- EXPECT_TRUE(mock_data_fetcher->StartFetchingDeviceData(
+ EXPECT_TRUE(mock_data_fetcher.StartFetchingDeviceData(
CONSUMER_TYPE_ORIENTATION));
- mock_data_fetcher->WaitForStart();
- mock_data_fetcher->WaitForUpdateOrientation();
+ mock_data_fetcher.WaitForStart();
+ mock_data_fetcher.WaitForUpdateOrientation();
- EXPECT_EQ(1, mock_data_fetcher->GetOrientationBuffer()->data.alpha);
+ EXPECT_EQ(1, mock_data_fetcher.GetOrientationBuffer()->data.alpha);
- mock_data_fetcher->StopFetchingDeviceData(CONSUMER_TYPE_ORIENTATION);
- mock_data_fetcher->WaitForStop();
+ mock_data_fetcher.StopFetchingDeviceData(CONSUMER_TYPE_ORIENTATION);
+ mock_data_fetcher.WaitForStop();
}
} // namespace
diff --git a/content/browser/device_orientation/data_fetcher_shared_memory_mac.cc b/content/browser/device_orientation/data_fetcher_shared_memory_mac.cc
new file mode 100644
index 0000000..1d658f0
--- /dev/null
+++ b/content/browser/device_orientation/data_fetcher_shared_memory_mac.cc
@@ -0,0 +1,163 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "data_fetcher_shared_memory.h"
+
+#include "base/logging.h"
+#include "third_party/sudden_motion_sensor/sudden_motion_sensor_mac.h"
+
+namespace {
+
+void FetchMotion(SuddenMotionSensor* sensor,
+ content::DeviceMotionHardwareBuffer* buffer) {
+ DCHECK(buffer);
+
+ float axis_value[3];
+ if (!sensor->ReadSensorValues(axis_value))
+ return;
+
+ buffer->seqlock.WriteBegin();
+ buffer->data.accelerationIncludingGravityX = axis_value[0];
+ buffer->data.hasAccelerationIncludingGravityX = true;
+ buffer->data.accelerationIncludingGravityY = axis_value[1];
+ buffer->data.hasAccelerationIncludingGravityY = true;
+ buffer->data.accelerationIncludingGravityZ = axis_value[2];
+ buffer->data.hasAccelerationIncludingGravityZ = true;
+ buffer->data.allAvailableSensorsAreActive = true;
+ buffer->seqlock.WriteEnd();
+}
+
+void FetchOrientation(SuddenMotionSensor* sensor,
+ content::DeviceOrientationHardwareBuffer* buffer) {
+ DCHECK(buffer);
+
+ // Retrieve per-axis calibrated values.
+ float axis_value[3];
+ if (!sensor->ReadSensorValues(axis_value))
+ return;
+
+ // Transform the accelerometer values to W3C draft angles.
+ //
+ // Accelerometer values are just dot products of the sensor axes
+ // by the gravity vector 'g' with the result for the z axis inverted.
+ //
+ // To understand this transformation calculate the 3rd row of the z-x-y
+ // Euler angles rotation matrix (because of the 'g' vector, only 3rd row
+ // affects to the result). Note that z-x-y matrix means R = Ry * Rx * Rz.
+ // Then, assume alpha = 0 and you get this:
+ //
+ // x_acc = sin(gamma)
+ // y_acc = - cos(gamma) * sin(beta)
+ // z_acc = cos(beta) * cos(gamma)
+ //
+ // After that the rest is just a bit of trigonometry.
+ //
+ // Also note that alpha can't be provided but it's assumed to be always zero.
+ // This is necessary in order to provide enough information to solve
+ // the equations.
+ //
+ const double kRad2deg = 180.0 / M_PI;
+ double beta = kRad2deg * atan2(-axis_value[1], axis_value[2]);
+ double gamma = kRad2deg * asin(axis_value[0]);
+
+ // TODO(aousterh): should absolute_ be set to false here?
+ // See crbug.com/136010.
+
+ // Make sure that the interval boundaries comply with the specification. At
+ // this point, beta is [-180, 180] and gamma is [-90, 90], but the spec has
+ // the upper bound open on both.
+ if (beta == 180.0)
+ beta = -180; // -180 == 180 (upside-down)
+ if (gamma == 90.0)
+ gamma = nextafter(90, 0);
+
+ // At this point, DCHECKing is paranoia. Never hurts.
+ DCHECK_GE(beta, -180.0);
+ DCHECK_LT(beta, 180.0);
+ DCHECK_GE(gamma, -90.0);
+ DCHECK_LT(gamma, 90.0);
+
+ buffer->seqlock.WriteBegin();
+ buffer->data.beta = beta;
+ buffer->data.hasBeta = true;
+ buffer->data.gamma = gamma;
+ buffer->data.hasGamma = true;
+ buffer->data.allAvailableSensorsAreActive = true;
+ buffer->seqlock.WriteEnd();
+}
+
+} // namespace
+
+namespace content {
+
+DataFetcherSharedMemory::DataFetcherSharedMemory() {
+}
+
+DataFetcherSharedMemory::~DataFetcherSharedMemory() {
+}
+
+void DataFetcherSharedMemory::Fetch(unsigned consumer_bitmask) {
+ DCHECK(base::MessageLoop::current() == GetPollingMessageLoop());
+ DCHECK(sudden_motion_sensor_);
+
+ if (consumer_bitmask & CONSUMER_TYPE_ORIENTATION)
+ FetchOrientation(sudden_motion_sensor_.get(), orientation_buffer_);
+ else if (consumer_bitmask & CONSUMER_TYPE_MOTION)
+ FetchMotion(sudden_motion_sensor_.get(), motion_buffer_);
+
+ NOTREACHED();
+}
+
+bool DataFetcherSharedMemory::IsPolling() const {
+ return true;
+}
+
+bool DataFetcherSharedMemory::Start(ConsumerType consumer_type) {
+ DCHECK(base::MessageLoop::current() == GetPollingMessageLoop());
+ switch (consumer_type) {
+ case CONSUMER_TYPE_MOTION:
+ if (void* buffer = InitSharedMemoryBuffer(consumer_type,
+ sizeof(DeviceMotionHardwareBuffer))) {
+ motion_buffer_ = static_cast<DeviceMotionHardwareBuffer*>(buffer);
+ if (!sudden_motion_sensor_)
+ sudden_motion_sensor_.reset(SuddenMotionSensor::Create());
+ return true;
+ }
+ case CONSUMER_TYPE_ORIENTATION:
+ if (void* buffer = InitSharedMemoryBuffer(consumer_type,
+ sizeof(DeviceOrientationHardwareBuffer))) {
+ orientation_buffer_ =
+ static_cast<DeviceOrientationHardwareBuffer*>(buffer);
+ if (!sudden_motion_sensor_)
+ sudden_motion_sensor_.reset(SuddenMotionSensor::Create());
+ return true;
+ }
+ default:
+ NOTREACHED();
+ }
+ return false;
+}
+
+bool DataFetcherSharedMemory::Stop(ConsumerType consumer_type) {
+ DCHECK(base::MessageLoop::current() == GetPollingMessageLoop());
+ switch (consumer_type) {
+ case CONSUMER_TYPE_MOTION:
+ motion_buffer_->seqlock.WriteBegin();
+ motion_buffer_->data.allAvailableSensorsAreActive = false;
+ motion_buffer_->seqlock.WriteEnd();
+ motion_buffer_ = NULL;
+ return true;
+ case CONSUMER_TYPE_ORIENTATION:
+ orientation_buffer_->seqlock.WriteBegin();
+ orientation_buffer_->data.allAvailableSensorsAreActive = false;
+ orientation_buffer_->seqlock.WriteEnd();
+ orientation_buffer_ = NULL;
+ return true;
+ default:
+ NOTREACHED();
+ }
+ return false;
+}
+
+} // namespace content