1 // Copyright 2014 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 "content/browser/device_sensors/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 (nullptr == new_data
|| nullptr == 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
);
225 DataFetcherSharedMemory::DataFetcherSharedMemory()
226 : motion_buffer_(nullptr), orientation_buffer_(nullptr) {
229 DataFetcherSharedMemory::~DataFetcherSharedMemory() {
232 DataFetcherSharedMemory::FetcherType
DataFetcherSharedMemory::GetType() const {
233 return FETCHER_TYPE_SEPARATE_THREAD
;
236 bool DataFetcherSharedMemory::Start(ConsumerType consumer_type
, void* buffer
) {
239 switch (consumer_type
) {
240 case CONSUMER_TYPE_ORIENTATION
:
242 orientation_buffer_
=
243 static_cast<DeviceOrientationHardwareBuffer
*>(buffer
);
244 scoped_refptr
<SensorEventSink
> sink(
245 new SensorEventSinkOrientation(orientation_buffer_
));
246 bool inclinometer_available
= RegisterForSensor(
247 SENSOR_TYPE_INCLINOMETER_3D
, sensor_inclinometer_
.Receive(), sink
);
248 UMA_HISTOGRAM_BOOLEAN("InertialSensor.InclinometerWindowsAvailable",
249 inclinometer_available
);
250 if (inclinometer_available
)
252 // if no sensors are available set buffer to ready, to fire null-events.
253 SetBufferAvailableState(consumer_type
, true);
256 case CONSUMER_TYPE_MOTION
:
258 motion_buffer_
= static_cast<DeviceMotionHardwareBuffer
*>(buffer
);
259 scoped_refptr
<SensorEventSink
> sink(
260 new SensorEventSinkMotion(motion_buffer_
));
261 bool accelerometer_available
= RegisterForSensor(
262 SENSOR_TYPE_ACCELEROMETER_3D
, sensor_accelerometer_
.Receive(),
264 bool gyrometer_available
= RegisterForSensor(
265 SENSOR_TYPE_GYROMETER_3D
, sensor_gyrometer_
.Receive(), sink
);
266 UMA_HISTOGRAM_BOOLEAN("InertialSensor.AccelerometerWindowsAvailable",
267 accelerometer_available
);
268 UMA_HISTOGRAM_BOOLEAN("InertialSensor.GyrometerWindowsAvailable",
269 gyrometer_available
);
270 if (accelerometer_available
|| gyrometer_available
) {
271 motion_buffer_
->seqlock
.WriteBegin();
272 motion_buffer_
->data
.interval
= GetInterval().InMilliseconds();
273 motion_buffer_
->seqlock
.WriteEnd();
276 // if no sensors are available set buffer to ready, to fire null-events.
277 SetBufferAvailableState(consumer_type
, true);
286 bool DataFetcherSharedMemory::Stop(ConsumerType consumer_type
) {
287 DisableSensors(consumer_type
);
288 SetBufferAvailableState(consumer_type
, false);
289 switch (consumer_type
) {
290 case CONSUMER_TYPE_ORIENTATION
:
291 orientation_buffer_
= nullptr;
293 case CONSUMER_TYPE_MOTION
:
294 motion_buffer_
= nullptr;
302 bool DataFetcherSharedMemory::RegisterForSensor(
303 REFSENSOR_TYPE_ID sensor_type
,
305 scoped_refptr
<SensorEventSink
> event_sink
) {
306 if (base::win::GetVersion() < base::win::VERSION_WIN7
)
309 base::win::ScopedComPtr
<ISensorManager
> sensor_manager
;
310 HRESULT hr
= sensor_manager
.CreateInstance(CLSID_SensorManager
);
311 if (FAILED(hr
) || !sensor_manager
.get())
314 base::win::ScopedComPtr
<ISensorCollection
> sensor_collection
;
315 hr
= sensor_manager
->GetSensorsByType(
316 sensor_type
, sensor_collection
.Receive());
318 if (FAILED(hr
) || !sensor_collection
.get())
322 hr
= sensor_collection
->GetCount(&count
);
323 if (FAILED(hr
) || !count
)
326 hr
= sensor_collection
->GetAt(0, sensor
);
327 if (FAILED(hr
) || !(*sensor
))
330 base::win::ScopedComPtr
<IPortableDeviceValues
> device_values
;
331 if (SUCCEEDED(device_values
.CreateInstance(CLSID_PortableDeviceValues
))) {
332 if (SUCCEEDED(device_values
->SetUnsignedIntegerValue(
333 SENSOR_PROPERTY_CURRENT_REPORT_INTERVAL
,
334 GetInterval().InMilliseconds()))) {
335 base::win::ScopedComPtr
<IPortableDeviceValues
> return_values
;
336 (*sensor
)->SetProperties(device_values
.get(), return_values
.Receive());
340 base::win::ScopedComPtr
<ISensorEvents
> sensor_events
;
341 hr
= event_sink
->QueryInterface(
342 __uuidof(ISensorEvents
), sensor_events
.ReceiveVoid());
343 if (FAILED(hr
) || !sensor_events
.get())
346 hr
= (*sensor
)->SetEventSink(sensor_events
.get());
353 void DataFetcherSharedMemory::DisableSensors(ConsumerType consumer_type
) {
354 switch(consumer_type
) {
355 case CONSUMER_TYPE_ORIENTATION
:
356 if (sensor_inclinometer_
.get()) {
357 sensor_inclinometer_
->SetEventSink(nullptr);
358 sensor_inclinometer_
.Release();
361 case CONSUMER_TYPE_MOTION
:
362 if (sensor_accelerometer_
.get()) {
363 sensor_accelerometer_
->SetEventSink(nullptr);
364 sensor_accelerometer_
.Release();
366 if (sensor_gyrometer_
.get()) {
367 sensor_gyrometer_
->SetEventSink(nullptr);
368 sensor_gyrometer_
.Release();
376 void DataFetcherSharedMemory::SetBufferAvailableState(
377 ConsumerType consumer_type
, bool enabled
) {
378 switch(consumer_type
) {
379 case CONSUMER_TYPE_ORIENTATION
:
380 if (orientation_buffer_
) {
381 orientation_buffer_
->seqlock
.WriteBegin();
382 orientation_buffer_
->data
.allAvailableSensorsAreActive
= enabled
;
383 orientation_buffer_
->seqlock
.WriteEnd();
386 case CONSUMER_TYPE_MOTION
:
387 if (motion_buffer_
) {
388 motion_buffer_
->seqlock
.WriteBegin();
389 motion_buffer_
->data
.allAvailableSensorsAreActive
= enabled
;
390 motion_buffer_
->seqlock
.WriteEnd();
398 } // namespace content