Re-subimission of https://codereview.chromium.org/1041213003/
[chromium-blink-merge.git] / content / browser / device_sensors / data_fetcher_shared_memory_win.cc
blobcf9f5bfbc883e77531e0b259a4f6237c85b253e6
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"
7 #include <GuidDef.h>
8 #include <InitGuid.h>
9 #include <PortableDeviceTypes.h>
10 #include <Sensors.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"
17 namespace {
19 const double kMeanGravity = 9.80665;
21 void SetLightBuffer(content::DeviceLightHardwareBuffer* buffer, double lux) {
22 DCHECK(buffer);
23 buffer->seqlock.WriteBegin();
24 buffer->data.value = lux;
25 buffer->seqlock.WriteEnd();
28 } // namespace
31 namespace content {
33 class DataFetcherSharedMemory::SensorEventSink
34 : public ISensorEvents, public base::win::IUnknownImpl {
35 public:
36 SensorEventSink() {}
37 virtual ~SensorEventSink() {}
39 // IUnknown interface
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);
51 AddRef();
52 return S_OK;
54 return IUnknownImpl::QueryInterface(riid, ppv);
57 // ISensorEvents interface
58 STDMETHODIMP OnEvent(ISensor* sensor,
59 REFGUID event_id,
60 IPortableDeviceValues* event_data) override {
61 return S_OK;
64 STDMETHODIMP OnLeave(REFSENSOR_ID sensor_id) override {
65 return S_OK;
68 STDMETHODIMP OnStateChanged(ISensor* sensor, SensorState state) override {
69 return S_OK;
72 STDMETHODIMP OnDataUpdated(ISensor* sensor,
73 ISensorDataReport* new_data) override {
74 if (nullptr == new_data || nullptr == sensor)
75 return E_INVALIDARG;
76 return UpdateSharedMemoryBuffer(sensor, new_data) ? S_OK : E_FAIL;
79 protected:
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;
91 *has_value = true;
92 } else {
93 *value = 0;
94 *has_value = false;
98 private:
100 DISALLOW_COPY_AND_ASSIGN(SensorEventSink);
103 class DataFetcherSharedMemory::SensorEventSinkOrientation
104 : public DataFetcherSharedMemory::SensorEventSink {
105 public:
106 explicit SensorEventSinkOrientation(
107 DeviceOrientationHardwareBuffer* const buffer) : buffer_(buffer) {}
108 virtual ~SensorEventSinkOrientation() {}
110 protected:
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,
117 &has_alpha);
118 GetSensorValue(SENSOR_DATA_TYPE_TILT_Y_DEGREES, new_data, &beta,
119 &has_beta);
120 GetSensorValue(SENSOR_DATA_TYPE_TILT_Z_DEGREES, new_data, &gamma,
121 &has_gamma);
123 if (buffer_) {
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();
137 return true;
140 private:
141 DeviceOrientationHardwareBuffer* const buffer_;
143 DISALLOW_COPY_AND_ASSIGN(SensorEventSinkOrientation);
146 class DataFetcherSharedMemory::SensorEventSinkMotion
147 : public DataFetcherSharedMemory::SensorEventSink {
148 public:
149 explicit SensorEventSinkMotion(DeviceMotionHardwareBuffer* const buffer)
150 : buffer_(buffer) {}
151 virtual ~SensorEventSinkMotion() {}
153 protected:
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)))
159 return false;
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);
179 if (buffer_) {
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);
210 if (buffer_) {
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();
223 return true;
226 private:
227 DeviceMotionHardwareBuffer* const buffer_;
229 DISALLOW_COPY_AND_ASSIGN(SensorEventSinkMotion);
232 class DataFetcherSharedMemory::SensorEventSinkLight
233 : public DataFetcherSharedMemory::SensorEventSink {
234 public:
235 explicit SensorEventSinkLight(DeviceLightHardwareBuffer* const buffer)
236 : buffer_(buffer) {}
237 virtual ~SensorEventSinkLight() {}
239 protected:
240 bool UpdateSharedMemoryBuffer(ISensor* sensor,
241 ISensorDataReport* new_data) override {
242 double lux;
243 bool has_lux;
245 GetSensorValue(SENSOR_DATA_TYPE_LIGHT_LEVEL_LUX, new_data, &lux, &has_lux);
247 if(!has_lux) {
248 // Could not get lux value.
249 return false;
252 SetLightBuffer(buffer_, lux);
254 return true;
257 private:
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) {
277 DCHECK(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)
291 return true;
292 // if no sensors are available set buffer to ready, to fire null-events.
293 SetBufferAvailableState(consumer_type, true);
295 break;
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(),
303 sink);
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();
314 return true;
316 // if no sensors are available set buffer to ready, to fire null-events.
317 SetBufferAvailableState(consumer_type, true);
319 break;
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);
329 return true;
332 // if no sensors are available, fire an Infinity event.
333 SetLightBuffer(light_buffer_, std::numeric_limits<double>::infinity());
335 break;
336 default:
337 NOTREACHED();
339 return false;
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;
348 return true;
349 case CONSUMER_TYPE_MOTION:
350 SetBufferAvailableState(consumer_type, false);
351 motion_buffer_ = nullptr;
352 return true;
353 case CONSUMER_TYPE_LIGHT:
354 SetLightBuffer(light_buffer_, -1);
355 light_buffer_ = nullptr;
356 return true;
357 default:
358 NOTREACHED();
360 return false;
363 bool DataFetcherSharedMemory::RegisterForSensor(
364 REFSENSOR_TYPE_ID sensor_type,
365 ISensor** sensor,
366 scoped_refptr<SensorEventSink> event_sink) {
367 if (base::win::GetVersion() < base::win::VERSION_WIN7)
368 return false;
370 base::win::ScopedComPtr<ISensorManager> sensor_manager;
371 HRESULT hr = sensor_manager.CreateInstance(CLSID_SensorManager);
372 if (FAILED(hr) || !sensor_manager.get())
373 return false;
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())
380 return false;
382 ULONG count = 0;
383 hr = sensor_collection->GetCount(&count);
384 if (FAILED(hr) || !count)
385 return false;
387 hr = sensor_collection->GetAt(0, sensor);
388 if (FAILED(hr) || !(*sensor))
389 return false;
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())
405 return false;
407 hr = (*sensor)->SetEventSink(sensor_events.get());
408 if (FAILED(hr))
409 return false;
411 return true;
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();
421 break;
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();
431 break;
432 case CONSUMER_TYPE_LIGHT:
433 if (sensor_light_.get()) {
434 sensor_light_->SetEventSink(nullptr);
435 sensor_light_.Release();
437 break;
438 default:
439 NOTREACHED();
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();
452 break;
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();
459 break;
460 default:
461 NOTREACHED();
465 } // namespace content