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 "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 17namespace { 18 19const double kMeanGravity = 9.80665; 20 21} // namespace 22 23 24namespace content { 25 26class 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 72protected: 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 96class DataFetcherSharedMemory::SensorEventSinkOrientation 97 : public DataFetcherSharedMemory::SensorEventSink { 98 public: 99 explicit SensorEventSinkOrientation( 100 DeviceOrientationHardwareBuffer* const buffer) : buffer_(buffer) {} 101 virtual ~SensorEventSinkOrientation() {} 102 103protected: 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 139class 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 226DataFetcherSharedMemory::DataFetcherSharedMemory() 227 : motion_buffer_(NULL), 228 orientation_buffer_(NULL) { 229} 230 231DataFetcherSharedMemory::~DataFetcherSharedMemory() { 232} 233 234DataFetcherSharedMemory::FetcherType DataFetcherSharedMemory::GetType() const { 235 return FETCHER_TYPE_SEPARATE_THREAD; 236} 237 238bool 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 288bool 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 304bool 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 355void 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 378void 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 break; 388 case CONSUMER_TYPE_MOTION: 389 if (motion_buffer_) { 390 motion_buffer_->seqlock.WriteBegin(); 391 motion_buffer_->data.allAvailableSensorsAreActive = enabled; 392 motion_buffer_->seqlock.WriteEnd(); 393 } 394 break; 395 default: 396 NOTREACHED(); 397 } 398} 399 400} // namespace content 401