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;
21 void SetLightBuffer(content::DeviceLightHardwareBuffer
* buffer
, double lux
) {
23 buffer
->seqlock
.WriteBegin();
24 buffer
->data
.value
= lux
;
25 buffer
->seqlock
.WriteEnd();
33 class DataFetcherSharedMemory::SensorEventSink
34 : public ISensorEvents
, public base::win::IUnknownImpl
{
37 virtual ~SensorEventSink() {}
40 ULONG STDMETHODCALLTYPE
AddRef() override
{
41 return IUnknownImpl::AddRef();
44 ULONG STDMETHODCALLTYPE
Release() override
{
45 return IUnknownImpl::Release();
48 STDMETHODIMP
QueryInterface(REFIID riid
, void** ppv
) override
{
49 if (riid
== __uuidof(ISensorEvents
)) {
50 *ppv
= static_cast<ISensorEvents
*>(this);
54 return IUnknownImpl::QueryInterface(riid
, ppv
);
57 // ISensorEvents interface
58 STDMETHODIMP
OnEvent(ISensor
* sensor
,
60 IPortableDeviceValues
* event_data
) override
{
64 STDMETHODIMP
OnLeave(REFSENSOR_ID sensor_id
) override
{
68 STDMETHODIMP
OnStateChanged(ISensor
* sensor
, SensorState state
) override
{
72 STDMETHODIMP
OnDataUpdated(ISensor
* sensor
,
73 ISensorDataReport
* new_data
) override
{
74 if (nullptr == new_data
|| nullptr == sensor
)
76 return UpdateSharedMemoryBuffer(sensor
, new_data
) ? S_OK
: E_FAIL
;
80 virtual bool UpdateSharedMemoryBuffer(
81 ISensor
* sensor
, ISensorDataReport
* new_data
) = 0;
83 void GetSensorValue(REFPROPERTYKEY property
, ISensorDataReport
* new_data
,
84 double* value
, bool* has_value
) {
85 PROPVARIANT variant_value
= {};
86 if (SUCCEEDED(new_data
->GetSensorValue(property
, &variant_value
))) {
87 if (variant_value
.vt
== VT_R8
)
88 *value
= variant_value
.dblVal
;
89 else if (variant_value
.vt
== VT_R4
)
90 *value
= variant_value
.fltVal
;
100 DISALLOW_COPY_AND_ASSIGN(SensorEventSink
);
103 class DataFetcherSharedMemory::SensorEventSinkOrientation
104 : public DataFetcherSharedMemory::SensorEventSink
{
106 explicit SensorEventSinkOrientation(
107 DeviceOrientationHardwareBuffer
* const buffer
) : buffer_(buffer
) {}
108 virtual ~SensorEventSinkOrientation() {}
111 bool UpdateSharedMemoryBuffer(
112 ISensor
* sensor
, ISensorDataReport
* new_data
) override
{
113 double alpha
, beta
, gamma
;
114 bool has_alpha
, has_beta
, has_gamma
;
116 GetSensorValue(SENSOR_DATA_TYPE_TILT_X_DEGREES
, new_data
, &alpha
,
118 GetSensorValue(SENSOR_DATA_TYPE_TILT_Y_DEGREES
, new_data
, &beta
,
120 GetSensorValue(SENSOR_DATA_TYPE_TILT_Z_DEGREES
, new_data
, &gamma
,
124 buffer_
->seqlock
.WriteBegin();
125 buffer_
->data
.alpha
= alpha
;
126 buffer_
->data
.hasAlpha
= has_alpha
;
127 buffer_
->data
.beta
= beta
;
128 buffer_
->data
.hasBeta
= has_beta
;
129 buffer_
->data
.gamma
= gamma
;
130 buffer_
->data
.hasGamma
= has_gamma
;
131 buffer_
->data
.absolute
= true;
132 buffer_
->data
.hasAbsolute
= has_alpha
|| has_beta
|| has_gamma
;
133 buffer_
->data
.allAvailableSensorsAreActive
= true;
134 buffer_
->seqlock
.WriteEnd();
141 DeviceOrientationHardwareBuffer
* const buffer_
;
143 DISALLOW_COPY_AND_ASSIGN(SensorEventSinkOrientation
);
146 class DataFetcherSharedMemory::SensorEventSinkMotion
147 : public DataFetcherSharedMemory::SensorEventSink
{
149 explicit SensorEventSinkMotion(DeviceMotionHardwareBuffer
* const buffer
)
151 virtual ~SensorEventSinkMotion() {}
154 bool UpdateSharedMemoryBuffer(
155 ISensor
* sensor
, ISensorDataReport
* new_data
) override
{
157 SENSOR_TYPE_ID sensor_type
= GUID_NULL
;
158 if (!SUCCEEDED(sensor
->GetType(&sensor_type
)))
161 if (IsEqualIID(sensor_type
, SENSOR_TYPE_ACCELEROMETER_3D
)) {
162 double acceleration_including_gravity_x
;
163 double acceleration_including_gravity_y
;
164 double acceleration_including_gravity_z
;
165 bool has_acceleration_including_gravity_x
;
166 bool has_acceleration_including_gravity_y
;
167 bool has_acceleration_including_gravity_z
;
169 GetSensorValue(SENSOR_DATA_TYPE_ACCELERATION_X_G
, new_data
,
170 &acceleration_including_gravity_x
,
171 &has_acceleration_including_gravity_x
);
172 GetSensorValue(SENSOR_DATA_TYPE_ACCELERATION_Y_G
, new_data
,
173 &acceleration_including_gravity_y
,
174 &has_acceleration_including_gravity_y
);
175 GetSensorValue(SENSOR_DATA_TYPE_ACCELERATION_Z_G
, new_data
,
176 &acceleration_including_gravity_z
,
177 &has_acceleration_including_gravity_z
);
180 buffer_
->seqlock
.WriteBegin();
181 buffer_
->data
.accelerationIncludingGravityX
=
182 -acceleration_including_gravity_x
* kMeanGravity
;
183 buffer_
->data
.hasAccelerationIncludingGravityX
=
184 has_acceleration_including_gravity_x
;
185 buffer_
->data
.accelerationIncludingGravityY
=
186 -acceleration_including_gravity_y
* kMeanGravity
;
187 buffer_
->data
.hasAccelerationIncludingGravityY
=
188 has_acceleration_including_gravity_y
;
189 buffer_
->data
.accelerationIncludingGravityZ
=
190 -acceleration_including_gravity_z
* kMeanGravity
;
191 buffer_
->data
.hasAccelerationIncludingGravityZ
=
192 has_acceleration_including_gravity_z
;
193 // TODO(timvolodine): consider setting this after all
194 // sensors have fired.
195 buffer_
->data
.allAvailableSensorsAreActive
= true;
196 buffer_
->seqlock
.WriteEnd();
199 } else if (IsEqualIID(sensor_type
, SENSOR_TYPE_GYROMETER_3D
)) {
200 double alpha
, beta
, gamma
;
201 bool has_alpha
, has_beta
, has_gamma
;
203 GetSensorValue(SENSOR_DATA_TYPE_ANGULAR_VELOCITY_X_DEGREES_PER_SECOND
,
204 new_data
, &alpha
, &has_alpha
);
205 GetSensorValue(SENSOR_DATA_TYPE_ANGULAR_VELOCITY_Y_DEGREES_PER_SECOND
,
206 new_data
, &beta
, &has_beta
);
207 GetSensorValue(SENSOR_DATA_TYPE_ANGULAR_VELOCITY_Z_DEGREES_PER_SECOND
,
208 new_data
, &gamma
, &has_gamma
);
211 buffer_
->seqlock
.WriteBegin();
212 buffer_
->data
.rotationRateAlpha
= alpha
;
213 buffer_
->data
.hasRotationRateAlpha
= has_alpha
;
214 buffer_
->data
.rotationRateBeta
= beta
;
215 buffer_
->data
.hasRotationRateBeta
= has_beta
;
216 buffer_
->data
.rotationRateGamma
= gamma
;
217 buffer_
->data
.hasRotationRateGamma
= has_gamma
;
218 buffer_
->data
.allAvailableSensorsAreActive
= true;
219 buffer_
->seqlock
.WriteEnd();
227 DeviceMotionHardwareBuffer
* const buffer_
;
229 DISALLOW_COPY_AND_ASSIGN(SensorEventSinkMotion
);
232 class DataFetcherSharedMemory::SensorEventSinkLight
233 : public DataFetcherSharedMemory::SensorEventSink
{
235 explicit SensorEventSinkLight(DeviceLightHardwareBuffer
* const buffer
)
237 virtual ~SensorEventSinkLight() {}
240 bool UpdateSharedMemoryBuffer(ISensor
* sensor
,
241 ISensorDataReport
* new_data
) override
{
245 GetSensorValue(SENSOR_DATA_TYPE_LIGHT_LEVEL_LUX
, new_data
, &lux
, &has_lux
);
248 // Could not get lux value.
252 SetLightBuffer(buffer_
, lux
);
258 DeviceLightHardwareBuffer
* const buffer_
;
260 DISALLOW_COPY_AND_ASSIGN(SensorEventSinkLight
);
263 DataFetcherSharedMemory::DataFetcherSharedMemory()
264 : motion_buffer_(nullptr),
265 orientation_buffer_(nullptr),
266 light_buffer_(nullptr) {
269 DataFetcherSharedMemory::~DataFetcherSharedMemory() {
272 DataFetcherSharedMemory::FetcherType
DataFetcherSharedMemory::GetType() const {
273 return FETCHER_TYPE_SEPARATE_THREAD
;
276 bool DataFetcherSharedMemory::Start(ConsumerType consumer_type
, void* buffer
) {
279 switch (consumer_type
) {
280 case CONSUMER_TYPE_ORIENTATION
:
282 orientation_buffer_
=
283 static_cast<DeviceOrientationHardwareBuffer
*>(buffer
);
284 scoped_refptr
<SensorEventSink
> sink(
285 new SensorEventSinkOrientation(orientation_buffer_
));
286 bool inclinometer_available
= RegisterForSensor(
287 SENSOR_TYPE_INCLINOMETER_3D
, sensor_inclinometer_
.Receive(), sink
);
288 UMA_HISTOGRAM_BOOLEAN("InertialSensor.InclinometerWindowsAvailable",
289 inclinometer_available
);
290 if (inclinometer_available
)
292 // if no sensors are available set buffer to ready, to fire null-events.
293 SetBufferAvailableState(consumer_type
, true);
296 case CONSUMER_TYPE_MOTION
:
298 motion_buffer_
= static_cast<DeviceMotionHardwareBuffer
*>(buffer
);
299 scoped_refptr
<SensorEventSink
> sink(
300 new SensorEventSinkMotion(motion_buffer_
));
301 bool accelerometer_available
= RegisterForSensor(
302 SENSOR_TYPE_ACCELEROMETER_3D
, sensor_accelerometer_
.Receive(),
304 bool gyrometer_available
= RegisterForSensor(
305 SENSOR_TYPE_GYROMETER_3D
, sensor_gyrometer_
.Receive(), sink
);
306 UMA_HISTOGRAM_BOOLEAN("InertialSensor.AccelerometerWindowsAvailable",
307 accelerometer_available
);
308 UMA_HISTOGRAM_BOOLEAN("InertialSensor.GyrometerWindowsAvailable",
309 gyrometer_available
);
310 if (accelerometer_available
|| gyrometer_available
) {
311 motion_buffer_
->seqlock
.WriteBegin();
312 motion_buffer_
->data
.interval
= GetInterval().InMilliseconds();
313 motion_buffer_
->seqlock
.WriteEnd();
316 // if no sensors are available set buffer to ready, to fire null-events.
317 SetBufferAvailableState(consumer_type
, true);
320 case CONSUMER_TYPE_LIGHT
:
322 light_buffer_
= static_cast<DeviceLightHardwareBuffer
*>(buffer
);
323 scoped_refptr
<SensorEventSink
> sink(
324 new SensorEventSinkLight(light_buffer_
));
325 bool sensor_light_available
= RegisterForSensor(
326 SENSOR_TYPE_AMBIENT_LIGHT
, sensor_light_
.Receive(), sink
);
327 if (sensor_light_available
) {
328 SetLightBuffer(light_buffer_
, -1);
332 // if no sensors are available, fire an Infinity event.
333 SetLightBuffer(light_buffer_
, std::numeric_limits
<double>::infinity());
342 bool DataFetcherSharedMemory::Stop(ConsumerType consumer_type
) {
343 DisableSensors(consumer_type
);
344 switch (consumer_type
) {
345 case CONSUMER_TYPE_ORIENTATION
:
346 SetBufferAvailableState(consumer_type
, false);
347 orientation_buffer_
= nullptr;
349 case CONSUMER_TYPE_MOTION
:
350 SetBufferAvailableState(consumer_type
, false);
351 motion_buffer_
= nullptr;
353 case CONSUMER_TYPE_LIGHT
:
354 SetLightBuffer(light_buffer_
, -1);
355 light_buffer_
= nullptr;
363 bool DataFetcherSharedMemory::RegisterForSensor(
364 REFSENSOR_TYPE_ID sensor_type
,
366 scoped_refptr
<SensorEventSink
> event_sink
) {
367 if (base::win::GetVersion() < base::win::VERSION_WIN7
)
370 base::win::ScopedComPtr
<ISensorManager
> sensor_manager
;
371 HRESULT hr
= sensor_manager
.CreateInstance(CLSID_SensorManager
);
372 if (FAILED(hr
) || !sensor_manager
.get())
375 base::win::ScopedComPtr
<ISensorCollection
> sensor_collection
;
376 hr
= sensor_manager
->GetSensorsByType(
377 sensor_type
, sensor_collection
.Receive());
379 if (FAILED(hr
) || !sensor_collection
.get())
383 hr
= sensor_collection
->GetCount(&count
);
384 if (FAILED(hr
) || !count
)
387 hr
= sensor_collection
->GetAt(0, sensor
);
388 if (FAILED(hr
) || !(*sensor
))
391 base::win::ScopedComPtr
<IPortableDeviceValues
> device_values
;
392 if (SUCCEEDED(device_values
.CreateInstance(CLSID_PortableDeviceValues
))) {
393 if (SUCCEEDED(device_values
->SetUnsignedIntegerValue(
394 SENSOR_PROPERTY_CURRENT_REPORT_INTERVAL
,
395 GetInterval().InMilliseconds()))) {
396 base::win::ScopedComPtr
<IPortableDeviceValues
> return_values
;
397 (*sensor
)->SetProperties(device_values
.get(), return_values
.Receive());
401 base::win::ScopedComPtr
<ISensorEvents
> sensor_events
;
402 hr
= event_sink
->QueryInterface(
403 __uuidof(ISensorEvents
), sensor_events
.ReceiveVoid());
404 if (FAILED(hr
) || !sensor_events
.get())
407 hr
= (*sensor
)->SetEventSink(sensor_events
.get());
414 void DataFetcherSharedMemory::DisableSensors(ConsumerType consumer_type
) {
415 switch(consumer_type
) {
416 case CONSUMER_TYPE_ORIENTATION
:
417 if (sensor_inclinometer_
.get()) {
418 sensor_inclinometer_
->SetEventSink(nullptr);
419 sensor_inclinometer_
.Release();
422 case CONSUMER_TYPE_MOTION
:
423 if (sensor_accelerometer_
.get()) {
424 sensor_accelerometer_
->SetEventSink(nullptr);
425 sensor_accelerometer_
.Release();
427 if (sensor_gyrometer_
.get()) {
428 sensor_gyrometer_
->SetEventSink(nullptr);
429 sensor_gyrometer_
.Release();
432 case CONSUMER_TYPE_LIGHT
:
433 if (sensor_light_
.get()) {
434 sensor_light_
->SetEventSink(nullptr);
435 sensor_light_
.Release();
443 void DataFetcherSharedMemory::SetBufferAvailableState(
444 ConsumerType consumer_type
, bool enabled
) {
445 switch(consumer_type
) {
446 case CONSUMER_TYPE_ORIENTATION
:
447 if (orientation_buffer_
) {
448 orientation_buffer_
->seqlock
.WriteBegin();
449 orientation_buffer_
->data
.allAvailableSensorsAreActive
= enabled
;
450 orientation_buffer_
->seqlock
.WriteEnd();
453 case CONSUMER_TYPE_MOTION
:
454 if (motion_buffer_
) {
455 motion_buffer_
->seqlock
.WriteBegin();
456 motion_buffer_
->data
.allAvailableSensorsAreActive
= enabled
;
457 motion_buffer_
->seqlock
.WriteEnd();
465 } // namespace content