Remove PlatformFile from profile_browsertest
[chromium-blink-merge.git] / content / browser / device_orientation / data_fetcher_shared_memory_win.cc
blobd5cf46a97e00f4b70299f27d5e5c516351638082
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"
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 } // namespace
24 namespace content {
26 class DataFetcherSharedMemory::SensorEventSink
27 : public ISensorEvents, public base::win::IUnknownImpl {
28 public:
29 SensorEventSink() {}
30 virtual ~SensorEventSink() {}
32 // IUnknown interface
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);
44 AddRef();
45 return S_OK;
47 return IUnknownImpl::QueryInterface(riid, ppv);
50 // ISensorEvents interface
51 STDMETHODIMP OnEvent(ISensor* sensor,
52 REFGUID event_id,
53 IPortableDeviceValues* event_data) OVERRIDE {
54 return S_OK;
57 STDMETHODIMP OnLeave(REFSENSOR_ID sensor_id) OVERRIDE {
58 return S_OK;
61 STDMETHODIMP OnStateChanged(ISensor* sensor, SensorState state) OVERRIDE {
62 return S_OK;
65 STDMETHODIMP OnDataUpdated(ISensor* sensor,
66 ISensorDataReport* new_data) OVERRIDE {
67 if (NULL == new_data || NULL == sensor)
68 return E_INVALIDARG;
69 return UpdateSharedMemoryBuffer(sensor, new_data) ? S_OK : E_FAIL;
72 protected:
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;
84 *has_value = true;
85 } else {
86 *value = 0;
87 *has_value = false;
91 private:
93 DISALLOW_COPY_AND_ASSIGN(SensorEventSink);
96 class DataFetcherSharedMemory::SensorEventSinkOrientation
97 : public DataFetcherSharedMemory::SensorEventSink {
98 public:
99 explicit SensorEventSinkOrientation(
100 DeviceOrientationHardwareBuffer* const buffer) : buffer_(buffer) {}
101 virtual ~SensorEventSinkOrientation() {}
103 protected:
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,
110 &has_alpha);
111 GetSensorValue(SENSOR_DATA_TYPE_TILT_Y_DEGREES, new_data, &beta,
112 &has_beta);
113 GetSensorValue(SENSOR_DATA_TYPE_TILT_Z_DEGREES, new_data, &gamma,
114 &has_gamma);
116 if (buffer_) {
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();
130 return true;
133 private:
134 DeviceOrientationHardwareBuffer* const buffer_;
136 DISALLOW_COPY_AND_ASSIGN(SensorEventSinkOrientation);
139 class DataFetcherSharedMemory::SensorEventSinkMotion
140 : public DataFetcherSharedMemory::SensorEventSink {
141 public:
142 explicit SensorEventSinkMotion(DeviceMotionHardwareBuffer* const buffer)
143 : buffer_(buffer) {}
144 virtual ~SensorEventSinkMotion() {}
146 protected:
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)))
152 return false;
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);
172 if (buffer_) {
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);
203 if (buffer_) {
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();
216 return true;
219 private:
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) {
239 DCHECK(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)
253 return true;
254 // if no sensors are available set buffer to ready, to fire null-events.
255 SetBufferAvailableState(consumer_type, true);
257 break;
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(),
265 sink);
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();
276 return true;
278 // if no sensors are available set buffer to ready, to fire null-events.
279 SetBufferAvailableState(consumer_type, true);
281 break;
282 default:
283 NOTREACHED();
285 return false;
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;
294 return true;
295 case CONSUMER_TYPE_MOTION:
296 motion_buffer_ = NULL;
297 return true;
298 default:
299 NOTREACHED();
301 return false;
304 bool DataFetcherSharedMemory::RegisterForSensor(
305 REFSENSOR_TYPE_ID sensor_type,
306 ISensor** sensor,
307 scoped_refptr<SensorEventSink> event_sink) {
308 if (base::win::GetVersion() < base::win::VERSION_WIN7)
309 return false;
311 base::win::ScopedComPtr<ISensorManager> sensor_manager;
312 HRESULT hr = sensor_manager.CreateInstance(CLSID_SensorManager);
313 if (FAILED(hr) || !sensor_manager)
314 return false;
316 base::win::ScopedComPtr<ISensorCollection> sensor_collection;
317 hr = sensor_manager->GetSensorsByType(
318 sensor_type, sensor_collection.Receive());
320 if (FAILED(hr) || !sensor_collection)
321 return false;
323 ULONG count = 0;
324 hr = sensor_collection->GetCount(&count);
325 if (FAILED(hr) || !count)
326 return false;
328 hr = sensor_collection->GetAt(0, sensor);
329 if (FAILED(hr) || !(*sensor))
330 return false;
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)
346 return false;
348 hr = (*sensor)->SetEventSink(sensor_events);
349 if (FAILED(hr))
350 return false;
352 return true;
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();
362 break;
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();
372 break;
373 default:
374 NOTREACHED();
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();
393 default:
394 NOTREACHED();
398 } // namespace content