1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "data_fetcher_shared_memory.h"
9 #include <PortableDeviceTypes.h>
12 #include "base/logging.h"
13 #include "base/metrics/histogram.h"
14 #include "base/win/iunknown_impl.h"
15 #include "base/win/windows_version.h"
19 const double kMeanGravity
= 9.80665;
26 class DataFetcherSharedMemory::SensorEventSink
27 : public ISensorEvents
, public base::win::IUnknownImpl
{
30 virtual ~SensorEventSink() {}
33 virtual ULONG STDMETHODCALLTYPE
AddRef() OVERRIDE
{
34 return IUnknownImpl::AddRef();
37 virtual ULONG STDMETHODCALLTYPE
Release() OVERRIDE
{
38 return IUnknownImpl::Release();
41 virtual STDMETHODIMP
QueryInterface(REFIID riid
, void** ppv
) OVERRIDE
{
42 if (riid
== __uuidof(ISensorEvents
)) {
43 *ppv
= static_cast<ISensorEvents
*>(this);
47 return IUnknownImpl::QueryInterface(riid
, ppv
);
50 // ISensorEvents interface
51 STDMETHODIMP
OnEvent(ISensor
* sensor
,
53 IPortableDeviceValues
* event_data
) OVERRIDE
{
57 STDMETHODIMP
OnLeave(REFSENSOR_ID sensor_id
) OVERRIDE
{
61 STDMETHODIMP
OnStateChanged(ISensor
* sensor
, SensorState state
) OVERRIDE
{
65 STDMETHODIMP
OnDataUpdated(ISensor
* sensor
,
66 ISensorDataReport
* new_data
) OVERRIDE
{
67 if (NULL
== new_data
|| NULL
== sensor
)
69 return UpdateSharedMemoryBuffer(sensor
, new_data
) ? S_OK
: E_FAIL
;
73 virtual bool UpdateSharedMemoryBuffer(
74 ISensor
* sensor
, ISensorDataReport
* new_data
) = 0;
76 void GetSensorValue(REFPROPERTYKEY property
, ISensorDataReport
* new_data
,
77 double* value
, bool* has_value
) {
78 PROPVARIANT variant_value
= {};
79 if (SUCCEEDED(new_data
->GetSensorValue(property
, &variant_value
))) {
80 if (variant_value
.vt
== VT_R8
)
81 *value
= variant_value
.dblVal
;
82 else if (variant_value
.vt
== VT_R4
)
83 *value
= variant_value
.fltVal
;
93 DISALLOW_COPY_AND_ASSIGN(SensorEventSink
);
96 class DataFetcherSharedMemory::SensorEventSinkOrientation
97 : public DataFetcherSharedMemory::SensorEventSink
{
99 explicit SensorEventSinkOrientation(
100 DeviceOrientationHardwareBuffer
* const buffer
) : buffer_(buffer
) {}
101 virtual ~SensorEventSinkOrientation() {}
104 virtual bool UpdateSharedMemoryBuffer(
105 ISensor
* sensor
, ISensorDataReport
* new_data
) OVERRIDE
{
106 double alpha
, beta
, gamma
;
107 bool has_alpha
, has_beta
, has_gamma
;
109 GetSensorValue(SENSOR_DATA_TYPE_TILT_X_DEGREES
, new_data
, &alpha
,
111 GetSensorValue(SENSOR_DATA_TYPE_TILT_Y_DEGREES
, new_data
, &beta
,
113 GetSensorValue(SENSOR_DATA_TYPE_TILT_Z_DEGREES
, new_data
, &gamma
,
117 buffer_
->seqlock
.WriteBegin();
118 buffer_
->data
.alpha
= alpha
;
119 buffer_
->data
.hasAlpha
= has_alpha
;
120 buffer_
->data
.beta
= beta
;
121 buffer_
->data
.hasBeta
= has_beta
;
122 buffer_
->data
.gamma
= gamma
;
123 buffer_
->data
.hasGamma
= has_gamma
;
124 buffer_
->data
.absolute
= true;
125 buffer_
->data
.hasAbsolute
= has_alpha
|| has_beta
|| has_gamma
;
126 buffer_
->data
.allAvailableSensorsAreActive
= true;
127 buffer_
->seqlock
.WriteEnd();
134 DeviceOrientationHardwareBuffer
* const buffer_
;
136 DISALLOW_COPY_AND_ASSIGN(SensorEventSinkOrientation
);
139 class DataFetcherSharedMemory::SensorEventSinkMotion
140 : public DataFetcherSharedMemory::SensorEventSink
{
142 explicit SensorEventSinkMotion(DeviceMotionHardwareBuffer
* const buffer
)
144 virtual ~SensorEventSinkMotion() {}
147 virtual bool UpdateSharedMemoryBuffer(
148 ISensor
* sensor
, ISensorDataReport
* new_data
) OVERRIDE
{
150 SENSOR_TYPE_ID sensor_type
= GUID_NULL
;
151 if (!SUCCEEDED(sensor
->GetType(&sensor_type
)))
154 if (IsEqualIID(sensor_type
, SENSOR_TYPE_ACCELEROMETER_3D
)) {
155 double acceleration_including_gravity_x
;
156 double acceleration_including_gravity_y
;
157 double acceleration_including_gravity_z
;
158 bool has_acceleration_including_gravity_x
;
159 bool has_acceleration_including_gravity_y
;
160 bool has_acceleration_including_gravity_z
;
162 GetSensorValue(SENSOR_DATA_TYPE_ACCELERATION_X_G
, new_data
,
163 &acceleration_including_gravity_x
,
164 &has_acceleration_including_gravity_x
);
165 GetSensorValue(SENSOR_DATA_TYPE_ACCELERATION_Y_G
, new_data
,
166 &acceleration_including_gravity_y
,
167 &has_acceleration_including_gravity_y
);
168 GetSensorValue(SENSOR_DATA_TYPE_ACCELERATION_Z_G
, new_data
,
169 &acceleration_including_gravity_z
,
170 &has_acceleration_including_gravity_z
);
173 buffer_
->seqlock
.WriteBegin();
174 buffer_
->data
.accelerationIncludingGravityX
=
175 -acceleration_including_gravity_x
* kMeanGravity
;
176 buffer_
->data
.hasAccelerationIncludingGravityX
=
177 has_acceleration_including_gravity_x
;
178 buffer_
->data
.accelerationIncludingGravityY
=
179 -acceleration_including_gravity_y
* kMeanGravity
;
180 buffer_
->data
.hasAccelerationIncludingGravityY
=
181 has_acceleration_including_gravity_y
;
182 buffer_
->data
.accelerationIncludingGravityZ
=
183 -acceleration_including_gravity_z
* kMeanGravity
;
184 buffer_
->data
.hasAccelerationIncludingGravityZ
=
185 has_acceleration_including_gravity_z
;
186 // TODO(timvolodine): consider setting this after all
187 // sensors have fired.
188 buffer_
->data
.allAvailableSensorsAreActive
= true;
189 buffer_
->seqlock
.WriteEnd();
192 } else if (IsEqualIID(sensor_type
, SENSOR_TYPE_GYROMETER_3D
)) {
193 double alpha
, beta
, gamma
;
194 bool has_alpha
, has_beta
, has_gamma
;
196 GetSensorValue(SENSOR_DATA_TYPE_ANGULAR_VELOCITY_X_DEGREES_PER_SECOND
,
197 new_data
, &alpha
, &has_alpha
);
198 GetSensorValue(SENSOR_DATA_TYPE_ANGULAR_VELOCITY_Y_DEGREES_PER_SECOND
,
199 new_data
, &beta
, &has_beta
);
200 GetSensorValue(SENSOR_DATA_TYPE_ANGULAR_VELOCITY_Z_DEGREES_PER_SECOND
,
201 new_data
, &gamma
, &has_gamma
);
204 buffer_
->seqlock
.WriteBegin();
205 buffer_
->data
.rotationRateAlpha
= alpha
;
206 buffer_
->data
.hasRotationRateAlpha
= has_alpha
;
207 buffer_
->data
.rotationRateBeta
= beta
;
208 buffer_
->data
.hasRotationRateBeta
= has_beta
;
209 buffer_
->data
.rotationRateGamma
= gamma
;
210 buffer_
->data
.hasRotationRateGamma
= has_gamma
;
211 buffer_
->data
.allAvailableSensorsAreActive
= true;
212 buffer_
->seqlock
.WriteEnd();
220 DeviceMotionHardwareBuffer
* const buffer_
;
222 DISALLOW_COPY_AND_ASSIGN(SensorEventSinkMotion
);
226 DataFetcherSharedMemory::DataFetcherSharedMemory()
227 : motion_buffer_(NULL
),
228 orientation_buffer_(NULL
) {
231 DataFetcherSharedMemory::~DataFetcherSharedMemory() {
234 DataFetcherSharedMemory::FetcherType
DataFetcherSharedMemory::GetType() const {
235 return FETCHER_TYPE_SEPARATE_THREAD
;
238 bool DataFetcherSharedMemory::Start(ConsumerType consumer_type
, void* buffer
) {
241 switch (consumer_type
) {
242 case CONSUMER_TYPE_ORIENTATION
:
244 orientation_buffer_
=
245 static_cast<DeviceOrientationHardwareBuffer
*>(buffer
);
246 scoped_refptr
<SensorEventSink
> sink(
247 new SensorEventSinkOrientation(orientation_buffer_
));
248 bool inclinometer_available
= RegisterForSensor(
249 SENSOR_TYPE_INCLINOMETER_3D
, sensor_inclinometer_
.Receive(), sink
);
250 UMA_HISTOGRAM_BOOLEAN("InertialSensor.InclinometerWindowsAvailable",
251 inclinometer_available
);
252 if (inclinometer_available
)
254 // if no sensors are available set buffer to ready, to fire null-events.
255 SetBufferAvailableState(consumer_type
, true);
258 case CONSUMER_TYPE_MOTION
:
260 motion_buffer_
= static_cast<DeviceMotionHardwareBuffer
*>(buffer
);
261 scoped_refptr
<SensorEventSink
> sink(
262 new SensorEventSinkMotion(motion_buffer_
));
263 bool accelerometer_available
= RegisterForSensor(
264 SENSOR_TYPE_ACCELEROMETER_3D
, sensor_accelerometer_
.Receive(),
266 bool gyrometer_available
= RegisterForSensor(
267 SENSOR_TYPE_GYROMETER_3D
, sensor_gyrometer_
.Receive(), sink
);
268 UMA_HISTOGRAM_BOOLEAN("InertialSensor.AccelerometerWindowsAvailable",
269 accelerometer_available
);
270 UMA_HISTOGRAM_BOOLEAN("InertialSensor.GyrometerWindowsAvailable",
271 gyrometer_available
);
272 if (accelerometer_available
|| gyrometer_available
) {
273 motion_buffer_
->seqlock
.WriteBegin();
274 motion_buffer_
->data
.interval
= GetInterval().InMilliseconds();
275 motion_buffer_
->seqlock
.WriteEnd();
278 // if no sensors are available set buffer to ready, to fire null-events.
279 SetBufferAvailableState(consumer_type
, true);
288 bool DataFetcherSharedMemory::Stop(ConsumerType consumer_type
) {
289 DisableSensors(consumer_type
);
290 SetBufferAvailableState(consumer_type
, false);
291 switch (consumer_type
) {
292 case CONSUMER_TYPE_ORIENTATION
:
293 orientation_buffer_
= NULL
;
295 case CONSUMER_TYPE_MOTION
:
296 motion_buffer_
= NULL
;
304 bool DataFetcherSharedMemory::RegisterForSensor(
305 REFSENSOR_TYPE_ID sensor_type
,
307 scoped_refptr
<SensorEventSink
> event_sink
) {
308 if (base::win::GetVersion() < base::win::VERSION_WIN7
)
311 base::win::ScopedComPtr
<ISensorManager
> sensor_manager
;
312 HRESULT hr
= sensor_manager
.CreateInstance(CLSID_SensorManager
);
313 if (FAILED(hr
) || !sensor_manager
)
316 base::win::ScopedComPtr
<ISensorCollection
> sensor_collection
;
317 hr
= sensor_manager
->GetSensorsByType(
318 sensor_type
, sensor_collection
.Receive());
320 if (FAILED(hr
) || !sensor_collection
)
324 hr
= sensor_collection
->GetCount(&count
);
325 if (FAILED(hr
) || !count
)
328 hr
= sensor_collection
->GetAt(0, sensor
);
329 if (FAILED(hr
) || !(*sensor
))
332 base::win::ScopedComPtr
<IPortableDeviceValues
> device_values
;
333 if (SUCCEEDED(device_values
.CreateInstance(CLSID_PortableDeviceValues
))) {
334 if (SUCCEEDED(device_values
->SetUnsignedIntegerValue(
335 SENSOR_PROPERTY_CURRENT_REPORT_INTERVAL
,
336 GetInterval().InMilliseconds()))) {
337 base::win::ScopedComPtr
<IPortableDeviceValues
> return_values
;
338 (*sensor
)->SetProperties(device_values
.get(), return_values
.Receive());
342 base::win::ScopedComPtr
<ISensorEvents
> sensor_events
;
343 hr
= event_sink
->QueryInterface(
344 __uuidof(ISensorEvents
), sensor_events
.ReceiveVoid());
345 if (FAILED(hr
) || !sensor_events
)
348 hr
= (*sensor
)->SetEventSink(sensor_events
);
355 void DataFetcherSharedMemory::DisableSensors(ConsumerType consumer_type
) {
356 switch(consumer_type
) {
357 case CONSUMER_TYPE_ORIENTATION
:
358 if (sensor_inclinometer_
) {
359 sensor_inclinometer_
->SetEventSink(NULL
);
360 sensor_inclinometer_
.Release();
363 case CONSUMER_TYPE_MOTION
:
364 if (sensor_accelerometer_
) {
365 sensor_accelerometer_
->SetEventSink(NULL
);
366 sensor_accelerometer_
.Release();
368 if (sensor_gyrometer_
) {
369 sensor_gyrometer_
->SetEventSink(NULL
);
370 sensor_gyrometer_
.Release();
378 void DataFetcherSharedMemory::SetBufferAvailableState(
379 ConsumerType consumer_type
, bool enabled
) {
380 switch(consumer_type
) {
381 case CONSUMER_TYPE_ORIENTATION
:
382 if (orientation_buffer_
) {
383 orientation_buffer_
->seqlock
.WriteBegin();
384 orientation_buffer_
->data
.allAvailableSensorsAreActive
= enabled
;
385 orientation_buffer_
->seqlock
.WriteEnd();
387 case CONSUMER_TYPE_MOTION
:
388 if (motion_buffer_
) {
389 motion_buffer_
->seqlock
.WriteBegin();
390 motion_buffer_
->data
.allAvailableSensorsAreActive
= enabled
;
391 motion_buffer_
->seqlock
.WriteEnd();
398 } // namespace content