OLD | NEW |
| (Empty) |
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. | |
4 | |
5 #include "content/browser/device_sensors/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 void SetLightBuffer(content::DeviceLightHardwareBuffer* buffer, double lux) { | |
22 DCHECK(buffer); | |
23 buffer->seqlock.WriteBegin(); | |
24 buffer->data.value = lux; | |
25 buffer->seqlock.WriteEnd(); | |
26 } | |
27 | |
28 } // namespace | |
29 | |
30 | |
31 namespace content { | |
32 | |
33 class DataFetcherSharedMemory::SensorEventSink | |
34 : public ISensorEvents, public base::win::IUnknownImpl { | |
35 public: | |
36 SensorEventSink() {} | |
37 ~SensorEventSink() override {} | |
38 | |
39 // IUnknown interface | |
40 ULONG STDMETHODCALLTYPE AddRef() override { | |
41 return IUnknownImpl::AddRef(); | |
42 } | |
43 | |
44 ULONG STDMETHODCALLTYPE Release() override { | |
45 return IUnknownImpl::Release(); | |
46 } | |
47 | |
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; | |
53 } | |
54 return IUnknownImpl::QueryInterface(riid, ppv); | |
55 } | |
56 | |
57 // ISensorEvents interface | |
58 STDMETHODIMP OnEvent(ISensor* sensor, | |
59 REFGUID event_id, | |
60 IPortableDeviceValues* event_data) override { | |
61 return S_OK; | |
62 } | |
63 | |
64 STDMETHODIMP OnLeave(REFSENSOR_ID sensor_id) override { | |
65 return S_OK; | |
66 } | |
67 | |
68 STDMETHODIMP OnStateChanged(ISensor* sensor, SensorState state) override { | |
69 return S_OK; | |
70 } | |
71 | |
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; | |
77 } | |
78 | |
79 protected: | |
80 virtual bool UpdateSharedMemoryBuffer( | |
81 ISensor* sensor, ISensorDataReport* new_data) = 0; | |
82 | |
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; | |
95 } | |
96 } | |
97 | |
98 private: | |
99 | |
100 DISALLOW_COPY_AND_ASSIGN(SensorEventSink); | |
101 }; | |
102 | |
103 class DataFetcherSharedMemory::SensorEventSinkOrientation | |
104 : public DataFetcherSharedMemory::SensorEventSink { | |
105 public: | |
106 explicit SensorEventSinkOrientation( | |
107 DeviceOrientationHardwareBuffer* const buffer) : buffer_(buffer) {} | |
108 ~SensorEventSinkOrientation() override {} | |
109 | |
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; | |
115 | |
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); | |
122 | |
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(); | |
135 } | |
136 | |
137 return true; | |
138 } | |
139 | |
140 private: | |
141 DeviceOrientationHardwareBuffer* const buffer_; | |
142 | |
143 DISALLOW_COPY_AND_ASSIGN(SensorEventSinkOrientation); | |
144 }; | |
145 | |
146 class DataFetcherSharedMemory::SensorEventSinkMotion | |
147 : public DataFetcherSharedMemory::SensorEventSink { | |
148 public: | |
149 explicit SensorEventSinkMotion(DeviceMotionHardwareBuffer* const buffer) | |
150 : buffer_(buffer) {} | |
151 ~SensorEventSinkMotion() override {} | |
152 | |
153 protected: | |
154 bool UpdateSharedMemoryBuffer( | |
155 ISensor* sensor, ISensorDataReport* new_data) override { | |
156 | |
157 SENSOR_TYPE_ID sensor_type = GUID_NULL; | |
158 if (!SUCCEEDED(sensor->GetType(&sensor_type))) | |
159 return false; | |
160 | |
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; | |
168 | |
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); | |
178 | |
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(); | |
197 } | |
198 | |
199 } else if (IsEqualIID(sensor_type, SENSOR_TYPE_GYROMETER_3D)) { | |
200 double alpha, beta, gamma; | |
201 bool has_alpha, has_beta, has_gamma; | |
202 | |
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); | |
209 | |
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(); | |
220 } | |
221 } | |
222 | |
223 return true; | |
224 } | |
225 | |
226 private: | |
227 DeviceMotionHardwareBuffer* const buffer_; | |
228 | |
229 DISALLOW_COPY_AND_ASSIGN(SensorEventSinkMotion); | |
230 }; | |
231 | |
232 class DataFetcherSharedMemory::SensorEventSinkLight | |
233 : public DataFetcherSharedMemory::SensorEventSink { | |
234 public: | |
235 explicit SensorEventSinkLight(DeviceLightHardwareBuffer* const buffer) | |
236 : buffer_(buffer) {} | |
237 ~SensorEventSinkLight() override {} | |
238 | |
239 protected: | |
240 bool UpdateSharedMemoryBuffer(ISensor* sensor, | |
241 ISensorDataReport* new_data) override { | |
242 double lux; | |
243 bool has_lux; | |
244 | |
245 GetSensorValue(SENSOR_DATA_TYPE_LIGHT_LEVEL_LUX, new_data, &lux, &has_lux); | |
246 | |
247 if(!has_lux) { | |
248 // Could not get lux value. | |
249 return false; | |
250 } | |
251 | |
252 SetLightBuffer(buffer_, lux); | |
253 | |
254 return true; | |
255 } | |
256 | |
257 private: | |
258 DeviceLightHardwareBuffer* const buffer_; | |
259 | |
260 DISALLOW_COPY_AND_ASSIGN(SensorEventSinkLight); | |
261 }; | |
262 | |
263 DataFetcherSharedMemory::DataFetcherSharedMemory() | |
264 : motion_buffer_(nullptr), | |
265 orientation_buffer_(nullptr), | |
266 light_buffer_(nullptr) { | |
267 } | |
268 | |
269 DataFetcherSharedMemory::~DataFetcherSharedMemory() { | |
270 } | |
271 | |
272 DataFetcherSharedMemory::FetcherType DataFetcherSharedMemory::GetType() const { | |
273 return FETCHER_TYPE_SEPARATE_THREAD; | |
274 } | |
275 | |
276 bool DataFetcherSharedMemory::Start(ConsumerType consumer_type, void* buffer) { | |
277 DCHECK(buffer); | |
278 | |
279 switch (consumer_type) { | |
280 case CONSUMER_TYPE_ORIENTATION: | |
281 { | |
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); | |
294 } | |
295 break; | |
296 case CONSUMER_TYPE_MOTION: | |
297 { | |
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; | |
315 } | |
316 // if no sensors are available set buffer to ready, to fire null-events. | |
317 SetBufferAvailableState(consumer_type, true); | |
318 } | |
319 break; | |
320 case CONSUMER_TYPE_LIGHT: | |
321 { | |
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; | |
330 } | |
331 | |
332 // if no sensors are available, fire an Infinity event. | |
333 SetLightBuffer(light_buffer_, std::numeric_limits<double>::infinity()); | |
334 } | |
335 break; | |
336 default: | |
337 NOTREACHED(); | |
338 } | |
339 return false; | |
340 } | |
341 | |
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(); | |
359 } | |
360 return false; | |
361 } | |
362 | |
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; | |
369 | |
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; | |
374 | |
375 base::win::ScopedComPtr<ISensorCollection> sensor_collection; | |
376 hr = sensor_manager->GetSensorsByType( | |
377 sensor_type, sensor_collection.Receive()); | |
378 | |
379 if (FAILED(hr) || !sensor_collection.get()) | |
380 return false; | |
381 | |
382 ULONG count = 0; | |
383 hr = sensor_collection->GetCount(&count); | |
384 if (FAILED(hr) || !count) | |
385 return false; | |
386 | |
387 hr = sensor_collection->GetAt(0, sensor); | |
388 if (FAILED(hr) || !(*sensor)) | |
389 return false; | |
390 | |
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()); | |
398 } | |
399 } | |
400 | |
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; | |
406 | |
407 hr = (*sensor)->SetEventSink(sensor_events.get()); | |
408 if (FAILED(hr)) | |
409 return false; | |
410 | |
411 return true; | |
412 } | |
413 | |
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(); | |
420 } | |
421 break; | |
422 case CONSUMER_TYPE_MOTION: | |
423 if (sensor_accelerometer_.get()) { | |
424 sensor_accelerometer_->SetEventSink(nullptr); | |
425 sensor_accelerometer_.Release(); | |
426 } | |
427 if (sensor_gyrometer_.get()) { | |
428 sensor_gyrometer_->SetEventSink(nullptr); | |
429 sensor_gyrometer_.Release(); | |
430 } | |
431 break; | |
432 case CONSUMER_TYPE_LIGHT: | |
433 if (sensor_light_.get()) { | |
434 sensor_light_->SetEventSink(nullptr); | |
435 sensor_light_.Release(); | |
436 } | |
437 break; | |
438 default: | |
439 NOTREACHED(); | |
440 } | |
441 } | |
442 | |
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(); | |
451 } | |
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(); | |
458 } | |
459 break; | |
460 default: | |
461 NOTREACHED(); | |
462 } | |
463 } | |
464 | |
465 } // namespace content | |
OLD | NEW |