Upstream version 7.35.144.0
[platform/framework/web/crosswalk.git] / src / content / browser / device_orientation / data_fetcher_shared_memory_win.cc
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.
4
5 #include "data_fetcher_shared_memory.h"
6
7 #include <GuidDef.h>
8 #include <InitGuid.h>
9 #include <PortableDeviceTypes.h>
10 #include <Sensors.h>
11
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"
16
17 namespace {
18
19 const double kMeanGravity = 9.80665;
20
21 }  // namespace
22
23
24 namespace content {
25
26 class DataFetcherSharedMemory::SensorEventSink
27     : public ISensorEvents, public base::win::IUnknownImpl {
28  public:
29   SensorEventSink() {}
30   virtual ~SensorEventSink() {}
31
32   // IUnknown interface
33   virtual ULONG STDMETHODCALLTYPE AddRef() OVERRIDE {
34     return IUnknownImpl::AddRef();
35   }
36
37   virtual ULONG STDMETHODCALLTYPE Release() OVERRIDE {
38     return IUnknownImpl::Release();
39   }
40
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;
46     }
47     return IUnknownImpl::QueryInterface(riid, ppv);
48   }
49
50   // ISensorEvents interface
51   STDMETHODIMP OnEvent(ISensor* sensor,
52                        REFGUID event_id,
53                        IPortableDeviceValues* event_data) OVERRIDE {
54     return S_OK;
55   }
56
57   STDMETHODIMP OnLeave(REFSENSOR_ID sensor_id) OVERRIDE {
58     return S_OK;
59   }
60
61   STDMETHODIMP OnStateChanged(ISensor* sensor, SensorState state) OVERRIDE {
62     return S_OK;
63   }
64
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;
70   }
71
72 protected:
73   virtual bool UpdateSharedMemoryBuffer(
74       ISensor* sensor, ISensorDataReport* new_data) = 0;
75
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;
88     }
89   }
90
91  private:
92
93   DISALLOW_COPY_AND_ASSIGN(SensorEventSink);
94 };
95
96 class DataFetcherSharedMemory::SensorEventSinkOrientation
97     : public DataFetcherSharedMemory::SensorEventSink {
98  public:
99   explicit SensorEventSinkOrientation(
100       DeviceOrientationHardwareBuffer* const buffer) : buffer_(buffer) {}
101   virtual ~SensorEventSinkOrientation() {}
102
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;
108
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);
115
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();
128     }
129
130     return true;
131   }
132
133  private:
134   DeviceOrientationHardwareBuffer* const buffer_;
135
136   DISALLOW_COPY_AND_ASSIGN(SensorEventSinkOrientation);
137 };
138
139 class DataFetcherSharedMemory::SensorEventSinkMotion
140     : public DataFetcherSharedMemory::SensorEventSink {
141  public:
142   explicit SensorEventSinkMotion(DeviceMotionHardwareBuffer* const buffer)
143       : buffer_(buffer) {}
144   virtual ~SensorEventSinkMotion() {}
145
146  protected:
147   virtual bool UpdateSharedMemoryBuffer(
148       ISensor* sensor, ISensorDataReport* new_data) OVERRIDE {
149
150     SENSOR_TYPE_ID sensor_type = GUID_NULL;
151     if (!SUCCEEDED(sensor->GetType(&sensor_type)))
152       return false;
153
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;
161
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);
171
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();
190       }
191
192     } else if (IsEqualIID(sensor_type, SENSOR_TYPE_GYROMETER_3D)) {
193       double alpha, beta, gamma;
194       bool has_alpha, has_beta, has_gamma;
195
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);
202
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();
213       }
214     }
215
216     return true;
217   }
218
219   private:
220    DeviceMotionHardwareBuffer* const buffer_;
221
222    DISALLOW_COPY_AND_ASSIGN(SensorEventSinkMotion);
223  };
224
225
226 DataFetcherSharedMemory::DataFetcherSharedMemory()
227     : motion_buffer_(NULL),
228       orientation_buffer_(NULL) {
229 }
230
231 DataFetcherSharedMemory::~DataFetcherSharedMemory() {
232 }
233
234 DataFetcherSharedMemory::FetcherType DataFetcherSharedMemory::GetType() const {
235   return FETCHER_TYPE_SEPARATE_THREAD;
236 }
237
238 bool DataFetcherSharedMemory::Start(ConsumerType consumer_type, void* buffer) {
239   DCHECK(buffer);
240
241   switch (consumer_type) {
242     case CONSUMER_TYPE_ORIENTATION:
243       {
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);
256       }
257       break;
258     case CONSUMER_TYPE_MOTION:
259       {
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;
277         }
278         // if no sensors are available set buffer to ready, to fire null-events.
279         SetBufferAvailableState(consumer_type, true);
280       }
281       break;
282     default:
283       NOTREACHED();
284   }
285   return false;
286 }
287
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();
300   }
301   return false;
302 }
303
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;
310
311   base::win::ScopedComPtr<ISensorManager> sensor_manager;
312   HRESULT hr = sensor_manager.CreateInstance(CLSID_SensorManager);
313   if (FAILED(hr) || !sensor_manager)
314     return false;
315
316   base::win::ScopedComPtr<ISensorCollection> sensor_collection;
317   hr = sensor_manager->GetSensorsByType(
318       sensor_type, sensor_collection.Receive());
319
320   if (FAILED(hr) || !sensor_collection)
321     return false;
322
323   ULONG count = 0;
324   hr = sensor_collection->GetCount(&count);
325   if (FAILED(hr) || !count)
326     return false;
327
328   hr = sensor_collection->GetAt(0, sensor);
329   if (FAILED(hr) || !(*sensor))
330     return false;
331
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());
339     }
340   }
341
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;
347
348   hr = (*sensor)->SetEventSink(sensor_events);
349   if (FAILED(hr))
350     return false;
351
352   return true;
353 }
354
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();
361       }
362       break;
363     case CONSUMER_TYPE_MOTION:
364       if (sensor_accelerometer_) {
365         sensor_accelerometer_->SetEventSink(NULL);
366         sensor_accelerometer_.Release();
367       }
368       if (sensor_gyrometer_) {
369         sensor_gyrometer_->SetEventSink(NULL);
370         sensor_gyrometer_.Release();
371       }
372       break;
373     default:
374       NOTREACHED();
375   }
376 }
377
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();
386       }
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();
392       }
393     default:
394       NOTREACHED();
395   }
396 }
397
398 }  // namespace content