Home | History | Annotate | Download | only in device_sensors
      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 
     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       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