platform_sensor_reader_winrt.cc 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805
  1. // Copyright 2019 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. #include "services/device/generic_sensor/platform_sensor_reader_winrt.h"
  5. #include <cmath>
  6. #include "base/numerics/math_constants.h"
  7. #include "base/time/time.h"
  8. #include "base/win/core_winrt_util.h"
  9. #include "services/device/generic_sensor/generic_sensor_consts.h"
  10. #include "services/device/public/mojom/sensor.mojom.h"
  11. namespace device {
  12. namespace {
  13. using ABI::Windows::Devices::Sensors::Accelerometer;
  14. using ABI::Windows::Devices::Sensors::AccelerometerReadingChangedEventArgs;
  15. using ABI::Windows::Devices::Sensors::Gyrometer;
  16. using ABI::Windows::Devices::Sensors::GyrometerReadingChangedEventArgs;
  17. using ABI::Windows::Devices::Sensors::IAccelerometer;
  18. using ABI::Windows::Devices::Sensors::IAccelerometerReading;
  19. using ABI::Windows::Devices::Sensors::IAccelerometerReadingChangedEventArgs;
  20. using ABI::Windows::Devices::Sensors::IAccelerometerStatics;
  21. using ABI::Windows::Devices::Sensors::IGyrometer;
  22. using ABI::Windows::Devices::Sensors::IGyrometerReading;
  23. using ABI::Windows::Devices::Sensors::IGyrometerReadingChangedEventArgs;
  24. using ABI::Windows::Devices::Sensors::IGyrometerStatics;
  25. using ABI::Windows::Devices::Sensors::IInclinometer;
  26. using ABI::Windows::Devices::Sensors::IInclinometerReading;
  27. using ABI::Windows::Devices::Sensors::IInclinometerReadingChangedEventArgs;
  28. using ABI::Windows::Devices::Sensors::IInclinometerStatics;
  29. using ABI::Windows::Devices::Sensors::ILightSensor;
  30. using ABI::Windows::Devices::Sensors::ILightSensorReading;
  31. using ABI::Windows::Devices::Sensors::ILightSensorReadingChangedEventArgs;
  32. using ABI::Windows::Devices::Sensors::ILightSensorStatics;
  33. using ABI::Windows::Devices::Sensors::IMagnetometer;
  34. using ABI::Windows::Devices::Sensors::IMagnetometerReading;
  35. using ABI::Windows::Devices::Sensors::IMagnetometerReadingChangedEventArgs;
  36. using ABI::Windows::Devices::Sensors::IMagnetometerStatics;
  37. using ABI::Windows::Devices::Sensors::Inclinometer;
  38. using ABI::Windows::Devices::Sensors::InclinometerReadingChangedEventArgs;
  39. using ABI::Windows::Devices::Sensors::IOrientationSensor;
  40. using ABI::Windows::Devices::Sensors::IOrientationSensorReading;
  41. using ABI::Windows::Devices::Sensors::IOrientationSensorReadingChangedEventArgs;
  42. using ABI::Windows::Devices::Sensors::IOrientationSensorStatics;
  43. using ABI::Windows::Devices::Sensors::ISensorQuaternion;
  44. using ABI::Windows::Devices::Sensors::LightSensor;
  45. using ABI::Windows::Devices::Sensors::LightSensorReadingChangedEventArgs;
  46. using ABI::Windows::Devices::Sensors::Magnetometer;
  47. using ABI::Windows::Devices::Sensors::MagnetometerReadingChangedEventArgs;
  48. using ABI::Windows::Devices::Sensors::OrientationSensor;
  49. using ABI::Windows::Devices::Sensors::OrientationSensorReadingChangedEventArgs;
  50. using ABI::Windows::Foundation::DateTime;
  51. using ABI::Windows::Foundation::ITypedEventHandler;
  52. using Microsoft::WRL::Callback;
  53. using Microsoft::WRL::ComPtr;
  54. double GetAngleBetweenOrientationSamples(SensorReading reading1,
  55. SensorReading reading2) {
  56. auto dot_product = reading1.orientation_quat.x * reading2.orientation_quat.x +
  57. reading1.orientation_quat.y * reading2.orientation_quat.y +
  58. reading1.orientation_quat.z * reading2.orientation_quat.z +
  59. reading1.orientation_quat.w * reading2.orientation_quat.w;
  60. return 2.0 * acos(dot_product);
  61. }
  62. } // namespace
  63. std::unique_ptr<PlatformSensorReaderWinBase>
  64. PlatformSensorReaderWinrtFactory::Create(mojom::SensorType type) {
  65. switch (type) {
  66. case mojom::SensorType::AMBIENT_LIGHT:
  67. return PlatformSensorReaderWinrtLightSensor::Create();
  68. case mojom::SensorType::ACCELEROMETER:
  69. return PlatformSensorReaderWinrtAccelerometer::Create();
  70. case mojom::SensorType::GYROSCOPE:
  71. return PlatformSensorReaderWinrtGyrometer::Create();
  72. case mojom::SensorType::MAGNETOMETER:
  73. return PlatformSensorReaderWinrtMagnetometer::Create();
  74. case mojom::SensorType::ABSOLUTE_ORIENTATION_EULER_ANGLES:
  75. return PlatformSensorReaderWinrtAbsOrientationEulerAngles::Create();
  76. case mojom::SensorType::ABSOLUTE_ORIENTATION_QUATERNION:
  77. return PlatformSensorReaderWinrtAbsOrientationQuaternion::Create();
  78. default:
  79. NOTIMPLEMENTED();
  80. return nullptr;
  81. }
  82. }
  83. template <wchar_t const* runtime_class_id,
  84. class ISensorWinrtStatics,
  85. class ISensorWinrtClass,
  86. class ISensorReadingChangedHandler,
  87. class ISensorReadingChangedEventArgs>
  88. PlatformSensorReaderWinrtBase<
  89. runtime_class_id,
  90. ISensorWinrtStatics,
  91. ISensorWinrtClass,
  92. ISensorReadingChangedHandler,
  93. ISensorReadingChangedEventArgs>::PlatformSensorReaderWinrtBase() {
  94. get_sensor_factory_callback_ =
  95. base::BindRepeating([](ISensorWinrtStatics** sensor_factory) -> HRESULT {
  96. return base::win::GetActivationFactory<ISensorWinrtStatics,
  97. runtime_class_id>(
  98. sensor_factory);
  99. });
  100. }
  101. template <wchar_t const* runtime_class_id,
  102. class ISensorWinrtStatics,
  103. class ISensorWinrtClass,
  104. class ISensorReadingChangedHandler,
  105. class ISensorReadingChangedEventArgs>
  106. void PlatformSensorReaderWinrtBase<
  107. runtime_class_id,
  108. ISensorWinrtStatics,
  109. ISensorWinrtClass,
  110. ISensorReadingChangedHandler,
  111. ISensorReadingChangedEventArgs>::SetClient(Client* client) {
  112. base::AutoLock autolock(lock_);
  113. client_ = client;
  114. }
  115. template <wchar_t const* runtime_class_id,
  116. class ISensorWinrtStatics,
  117. class ISensorWinrtClass,
  118. class ISensorReadingChangedHandler,
  119. class ISensorReadingChangedEventArgs>
  120. template <class ISensorReading>
  121. HRESULT PlatformSensorReaderWinrtBase<runtime_class_id,
  122. ISensorWinrtStatics,
  123. ISensorWinrtClass,
  124. ISensorReadingChangedHandler,
  125. ISensorReadingChangedEventArgs>::
  126. ConvertSensorReadingTimeStamp(ComPtr<ISensorReading> sensor_reading,
  127. base::TimeDelta* timestamp_delta) {
  128. DateTime timestamp;
  129. HRESULT hr = sensor_reading->get_Timestamp(&timestamp);
  130. if (FAILED(hr))
  131. return hr;
  132. *timestamp_delta = base::TimeDelta::FromWinrtDateTime(timestamp);
  133. return S_OK;
  134. }
  135. template <wchar_t const* runtime_class_id,
  136. class ISensorWinrtStatics,
  137. class ISensorWinrtClass,
  138. class ISensorReadingChangedHandler,
  139. class ISensorReadingChangedEventArgs>
  140. bool PlatformSensorReaderWinrtBase<
  141. runtime_class_id,
  142. ISensorWinrtStatics,
  143. ISensorWinrtClass,
  144. ISensorReadingChangedHandler,
  145. ISensorReadingChangedEventArgs>::Initialize() {
  146. ComPtr<ISensorWinrtStatics> sensor_statics;
  147. HRESULT hr = get_sensor_factory_callback_.Run(&sensor_statics);
  148. if (FAILED(hr)) {
  149. DLOG(ERROR) << "Failed to get sensor activation factory: "
  150. << logging::SystemErrorCodeToString(hr);
  151. return false;
  152. }
  153. hr = sensor_statics->GetDefault(&sensor_);
  154. if (FAILED(hr)) {
  155. DLOG(ERROR) << "Failed to query default sensor: "
  156. << logging::SystemErrorCodeToString(hr);
  157. return false;
  158. }
  159. // GetDefault() returns null if the sensor does not exist
  160. if (!sensor_) {
  161. VLOG(1) << "Sensor does not exist on system";
  162. return false;
  163. }
  164. minimum_report_interval_ = GetMinimumReportIntervalFromSensor();
  165. if (minimum_report_interval_.is_zero())
  166. DLOG(WARNING) << "Failed to get sensor minimum report interval";
  167. return true;
  168. }
  169. template <wchar_t const* runtime_class_id,
  170. class ISensorWinrtStatics,
  171. class ISensorWinrtClass,
  172. class ISensorReadingChangedHandler,
  173. class ISensorReadingChangedEventArgs>
  174. base::TimeDelta PlatformSensorReaderWinrtBase<
  175. runtime_class_id,
  176. ISensorWinrtStatics,
  177. ISensorWinrtClass,
  178. ISensorReadingChangedHandler,
  179. ISensorReadingChangedEventArgs>::GetMinimumReportIntervalFromSensor() {
  180. UINT32 minimum_report_interval_ms = 0;
  181. HRESULT hr = sensor_->get_MinimumReportInterval(&minimum_report_interval_ms);
  182. // Failing to query is not fatal, consumer should be able to gracefully
  183. // handle a 0 return.
  184. if (FAILED(hr)) {
  185. DLOG(WARNING) << "Failed to query sensor minimum report interval: "
  186. << logging::SystemErrorCodeToString(hr);
  187. return base::TimeDelta();
  188. }
  189. return base::Milliseconds(minimum_report_interval_ms);
  190. }
  191. template <wchar_t const* runtime_class_id,
  192. class ISensorWinrtStatics,
  193. class ISensorWinrtClass,
  194. class ISensorReadingChangedHandler,
  195. class ISensorReadingChangedEventArgs>
  196. base::TimeDelta PlatformSensorReaderWinrtBase<
  197. runtime_class_id,
  198. ISensorWinrtStatics,
  199. ISensorWinrtClass,
  200. ISensorReadingChangedHandler,
  201. ISensorReadingChangedEventArgs>::GetMinimalReportingInterval() const {
  202. return minimum_report_interval_;
  203. }
  204. template <wchar_t const* runtime_class_id,
  205. class ISensorWinrtStatics,
  206. class ISensorWinrtClass,
  207. class ISensorReadingChangedHandler,
  208. class ISensorReadingChangedEventArgs>
  209. bool PlatformSensorReaderWinrtBase<runtime_class_id,
  210. ISensorWinrtStatics,
  211. ISensorWinrtClass,
  212. ISensorReadingChangedHandler,
  213. ISensorReadingChangedEventArgs>::
  214. StartSensor(const PlatformSensorConfiguration& configuration) {
  215. base::AutoLock autolock(lock_);
  216. if (!reading_callback_token_) {
  217. // Convert from frequency to interval in milliseconds since that is
  218. // what the Windows.Devices.Sensors API uses.
  219. unsigned int interval =
  220. (1 / configuration.frequency()) * base::Time::kMillisecondsPerSecond;
  221. auto hr = sensor_->put_ReportInterval(interval);
  222. if (FAILED(hr)) {
  223. DLOG(ERROR) << "Failed to set report interval: "
  224. << logging::SystemErrorCodeToString(hr);
  225. return false;
  226. }
  227. auto reading_changed_handler = Callback<ISensorReadingChangedHandler>(
  228. this, &PlatformSensorReaderWinrtBase::OnReadingChangedCallback);
  229. EventRegistrationToken event_token;
  230. hr = sensor_->add_ReadingChanged(reading_changed_handler.Get(),
  231. &event_token);
  232. if (FAILED(hr)) {
  233. DLOG(ERROR) << "Failed to add reading callback handler: "
  234. << logging::SystemErrorCodeToString(hr);
  235. return false;
  236. }
  237. reading_callback_token_ = event_token;
  238. }
  239. return true;
  240. }
  241. template <wchar_t const* runtime_class_id,
  242. class ISensorWinrtStatics,
  243. class ISensorWinrtClass,
  244. class ISensorReadingChangedHandler,
  245. class ISensorReadingChangedEventArgs>
  246. void PlatformSensorReaderWinrtBase<
  247. runtime_class_id,
  248. ISensorWinrtStatics,
  249. ISensorWinrtClass,
  250. ISensorReadingChangedHandler,
  251. ISensorReadingChangedEventArgs>::StopSensor() {
  252. base::AutoLock autolock(lock_);
  253. if (reading_callback_token_) {
  254. HRESULT hr =
  255. sensor_->remove_ReadingChanged(reading_callback_token_.value());
  256. if (FAILED(hr)) {
  257. DLOG(ERROR) << "Failed to remove ALS reading callback handler: "
  258. << logging::SystemErrorCodeToString(hr);
  259. }
  260. reading_callback_token_ = absl::nullopt;
  261. }
  262. }
  263. // static
  264. std::unique_ptr<PlatformSensorReaderWinBase>
  265. PlatformSensorReaderWinrtLightSensor::Create() {
  266. auto light_sensor = std::make_unique<PlatformSensorReaderWinrtLightSensor>();
  267. if (light_sensor->Initialize()) {
  268. return light_sensor;
  269. }
  270. return nullptr;
  271. }
  272. PlatformSensorReaderWinrtLightSensor::PlatformSensorReaderWinrtLightSensor() =
  273. default;
  274. HRESULT PlatformSensorReaderWinrtLightSensor::OnReadingChangedCallback(
  275. ILightSensor* light_sensor,
  276. ILightSensorReadingChangedEventArgs* reading_changed_args) {
  277. ComPtr<ILightSensorReading> light_sensor_reading;
  278. HRESULT hr = reading_changed_args->get_Reading(&light_sensor_reading);
  279. if (FAILED(hr)) {
  280. DLOG(ERROR) << "Failed to get the sensor reading: "
  281. << logging::SystemErrorCodeToString(hr);
  282. // Failing to parse a reading sample should not be fatal so always
  283. // return S_OK.
  284. return S_OK;
  285. }
  286. float lux = 0.0f;
  287. hr = light_sensor_reading->get_IlluminanceInLux(&lux);
  288. if (FAILED(hr)) {
  289. DLOG(ERROR) << "Failed to get the lux level: "
  290. << logging::SystemErrorCodeToString(hr);
  291. return S_OK;
  292. }
  293. base::TimeDelta timestamp_delta;
  294. hr = ConvertSensorReadingTimeStamp(light_sensor_reading, &timestamp_delta);
  295. if (FAILED(hr)) {
  296. DLOG(ERROR) << "Failed to get sensor reading timestamp: "
  297. << logging::SystemErrorCodeToString(hr);
  298. return S_OK;
  299. }
  300. if (!has_received_first_sample_ ||
  301. (abs(lux - last_reported_lux_) >=
  302. (last_reported_lux_ * kLuxPercentThreshold))) {
  303. base::AutoLock autolock(lock_);
  304. if (!client_) {
  305. return S_OK;
  306. }
  307. SensorReading reading;
  308. reading.als.value = lux;
  309. reading.als.timestamp = timestamp_delta.InSecondsF();
  310. client_->OnReadingUpdated(reading);
  311. last_reported_lux_ = lux;
  312. has_received_first_sample_ = true;
  313. }
  314. return S_OK;
  315. }
  316. // static
  317. std::unique_ptr<PlatformSensorReaderWinBase>
  318. PlatformSensorReaderWinrtAccelerometer::Create() {
  319. auto accelerometer =
  320. std::make_unique<PlatformSensorReaderWinrtAccelerometer>();
  321. if (accelerometer->Initialize()) {
  322. return accelerometer;
  323. }
  324. return nullptr;
  325. }
  326. PlatformSensorReaderWinrtAccelerometer::
  327. PlatformSensorReaderWinrtAccelerometer() = default;
  328. HRESULT PlatformSensorReaderWinrtAccelerometer::OnReadingChangedCallback(
  329. IAccelerometer* accelerometer,
  330. IAccelerometerReadingChangedEventArgs* reading_changed_args) {
  331. ComPtr<IAccelerometerReading> accelerometer_reading;
  332. HRESULT hr = reading_changed_args->get_Reading(&accelerometer_reading);
  333. if (FAILED(hr)) {
  334. DLOG(ERROR) << "Failed to get acc reading: "
  335. << logging::SystemErrorCodeToString(hr);
  336. return S_OK;
  337. }
  338. double x = 0.0;
  339. hr = accelerometer_reading->get_AccelerationX(&x);
  340. if (FAILED(hr)) {
  341. DLOG(ERROR) << "Failed to get x axis from acc reading: "
  342. << logging::SystemErrorCodeToString(hr);
  343. return S_OK;
  344. }
  345. double y = 0.0;
  346. hr = accelerometer_reading->get_AccelerationY(&y);
  347. if (FAILED(hr)) {
  348. DLOG(ERROR) << "Failed to get y axis from acc reading: "
  349. << logging::SystemErrorCodeToString(hr);
  350. return S_OK;
  351. }
  352. double z = 0.0;
  353. hr = accelerometer_reading->get_AccelerationZ(&z);
  354. if (FAILED(hr)) {
  355. DLOG(ERROR) << "Failed to get z axis from acc reading: "
  356. << logging::SystemErrorCodeToString(hr);
  357. return S_OK;
  358. }
  359. base::TimeDelta timestamp_delta;
  360. hr = ConvertSensorReadingTimeStamp(accelerometer_reading, &timestamp_delta);
  361. if (FAILED(hr)) {
  362. DLOG(ERROR) << "Failed to get sensor reading timestamp: "
  363. << logging::SystemErrorCodeToString(hr);
  364. return S_OK;
  365. }
  366. if (!has_received_first_sample_ ||
  367. (abs(x - last_reported_x_) >= kAxisThreshold) ||
  368. (abs(y - last_reported_y_) >= kAxisThreshold) ||
  369. (abs(z - last_reported_z_) >= kAxisThreshold)) {
  370. base::AutoLock autolock(lock_);
  371. if (!client_) {
  372. return S_OK;
  373. }
  374. // Windows.Devices.Sensors.Accelerometer exposes acceleration as
  375. // proportional and in the same direction as the force of gravity.
  376. // The generic sensor interface exposes acceleration simply as
  377. // m/s^2, so the data must be converted.
  378. SensorReading reading;
  379. reading.accel.x = -x * base::kMeanGravityDouble;
  380. reading.accel.y = -y * base::kMeanGravityDouble;
  381. reading.accel.z = -z * base::kMeanGravityDouble;
  382. reading.accel.timestamp = timestamp_delta.InSecondsF();
  383. client_->OnReadingUpdated(reading);
  384. last_reported_x_ = x;
  385. last_reported_y_ = y;
  386. last_reported_z_ = z;
  387. has_received_first_sample_ = true;
  388. }
  389. return S_OK;
  390. }
  391. // static
  392. std::unique_ptr<PlatformSensorReaderWinBase>
  393. PlatformSensorReaderWinrtGyrometer::Create() {
  394. auto gyrometer = std::make_unique<PlatformSensorReaderWinrtGyrometer>();
  395. if (gyrometer->Initialize()) {
  396. return gyrometer;
  397. }
  398. return nullptr;
  399. }
  400. PlatformSensorReaderWinrtGyrometer::PlatformSensorReaderWinrtGyrometer() =
  401. default;
  402. HRESULT PlatformSensorReaderWinrtGyrometer::OnReadingChangedCallback(
  403. IGyrometer* gyrometer,
  404. IGyrometerReadingChangedEventArgs* reading_changed_args) {
  405. ComPtr<IGyrometerReading> gyrometer_reading;
  406. HRESULT hr = reading_changed_args->get_Reading(&gyrometer_reading);
  407. if (FAILED(hr)) {
  408. DLOG(ERROR) << "Failed to gyro reading: "
  409. << logging::SystemErrorCodeToString(hr);
  410. return S_OK;
  411. }
  412. double x = 0.0;
  413. hr = gyrometer_reading->get_AngularVelocityX(&x);
  414. if (FAILED(hr)) {
  415. DLOG(ERROR) << "Failed to get x axis from gyro reading: "
  416. << logging::SystemErrorCodeToString(hr);
  417. return S_OK;
  418. }
  419. double y = 0.0;
  420. hr = gyrometer_reading->get_AngularVelocityY(&y);
  421. if (FAILED(hr)) {
  422. DLOG(ERROR) << "Failed to get y axis from gyro reading: "
  423. << logging::SystemErrorCodeToString(hr);
  424. return S_OK;
  425. }
  426. double z = 0.0;
  427. hr = gyrometer_reading->get_AngularVelocityZ(&z);
  428. if (FAILED(hr)) {
  429. DLOG(ERROR) << "Failed to get z axis from gyro reading: "
  430. << logging::SystemErrorCodeToString(hr);
  431. return S_OK;
  432. }
  433. base::TimeDelta timestamp_delta;
  434. hr = ConvertSensorReadingTimeStamp(gyrometer_reading, &timestamp_delta);
  435. if (FAILED(hr)) {
  436. DLOG(ERROR) << "Failed to get timestamp from gyro reading: "
  437. << logging::SystemErrorCodeToString(hr);
  438. return S_OK;
  439. }
  440. if (!has_received_first_sample_ ||
  441. (abs(x - last_reported_x_) >= kDegreeThreshold) ||
  442. (abs(y - last_reported_y_) >= kDegreeThreshold) ||
  443. (abs(z - last_reported_z_) >= kDegreeThreshold)) {
  444. base::AutoLock autolock(lock_);
  445. if (!client_) {
  446. return S_OK;
  447. }
  448. // Windows.Devices.Sensors.Gyrometer exposes angular velocity as degrees,
  449. // but the generic sensor interface uses radians so the data must be
  450. // converted.
  451. SensorReading reading;
  452. reading.gyro.x = gfx::DegToRad(x);
  453. reading.gyro.y = gfx::DegToRad(y);
  454. reading.gyro.z = gfx::DegToRad(z);
  455. reading.gyro.timestamp = timestamp_delta.InSecondsF();
  456. client_->OnReadingUpdated(reading);
  457. last_reported_x_ = x;
  458. last_reported_y_ = y;
  459. last_reported_z_ = z;
  460. has_received_first_sample_ = true;
  461. }
  462. return S_OK;
  463. }
  464. // static
  465. std::unique_ptr<PlatformSensorReaderWinBase>
  466. PlatformSensorReaderWinrtMagnetometer::Create() {
  467. auto magnetometer = std::make_unique<PlatformSensorReaderWinrtMagnetometer>();
  468. if (magnetometer->Initialize()) {
  469. return magnetometer;
  470. }
  471. return nullptr;
  472. }
  473. PlatformSensorReaderWinrtMagnetometer::PlatformSensorReaderWinrtMagnetometer() =
  474. default;
  475. HRESULT PlatformSensorReaderWinrtMagnetometer::OnReadingChangedCallback(
  476. IMagnetometer* magnetometer,
  477. IMagnetometerReadingChangedEventArgs* reading_changed_args) {
  478. ComPtr<IMagnetometerReading> magnetometer_reading;
  479. HRESULT hr = reading_changed_args->get_Reading(&magnetometer_reading);
  480. if (FAILED(hr)) {
  481. DLOG(ERROR) << "Failed to get mag reading: "
  482. << logging::SystemErrorCodeToString(hr);
  483. return S_OK;
  484. }
  485. float x = 0.0;
  486. hr = magnetometer_reading->get_MagneticFieldX(&x);
  487. if (FAILED(hr)) {
  488. DLOG(ERROR) << "Failed to get x axis from mag reading: "
  489. << logging::SystemErrorCodeToString(hr);
  490. return S_OK;
  491. }
  492. float y = 0.0;
  493. hr = magnetometer_reading->get_MagneticFieldY(&y);
  494. if (FAILED(hr)) {
  495. DLOG(ERROR) << "Failed to get y axis from mag reading: "
  496. << logging::SystemErrorCodeToString(hr);
  497. return S_OK;
  498. }
  499. float z = 0.0;
  500. hr = magnetometer_reading->get_MagneticFieldZ(&z);
  501. if (FAILED(hr)) {
  502. DLOG(ERROR) << "Failed to get z axis from mag reading: "
  503. << logging::SystemErrorCodeToString(hr);
  504. return S_OK;
  505. }
  506. base::TimeDelta timestamp_delta;
  507. hr = ConvertSensorReadingTimeStamp(magnetometer_reading, &timestamp_delta);
  508. if (FAILED(hr)) {
  509. DLOG(ERROR) << "Failed to get timestamp from mag reading: "
  510. << logging::SystemErrorCodeToString(hr);
  511. return S_OK;
  512. }
  513. if (!has_received_first_sample_ ||
  514. (abs(x - last_reported_x_) >= kMicroteslaThreshold) ||
  515. (abs(y - last_reported_y_) >= kMicroteslaThreshold) ||
  516. (abs(z - last_reported_z_) >= kMicroteslaThreshold)) {
  517. base::AutoLock autolock(lock_);
  518. if (!client_) {
  519. return S_OK;
  520. }
  521. SensorReading reading;
  522. reading.magn.x = x;
  523. reading.magn.y = y;
  524. reading.magn.z = z;
  525. reading.magn.timestamp = timestamp_delta.InSecondsF();
  526. client_->OnReadingUpdated(reading);
  527. last_reported_x_ = x;
  528. last_reported_y_ = y;
  529. last_reported_z_ = z;
  530. has_received_first_sample_ = true;
  531. }
  532. return S_OK;
  533. }
  534. // static
  535. std::unique_ptr<PlatformSensorReaderWinBase>
  536. PlatformSensorReaderWinrtAbsOrientationEulerAngles::Create() {
  537. auto inclinometer =
  538. std::make_unique<PlatformSensorReaderWinrtAbsOrientationEulerAngles>();
  539. if (inclinometer->Initialize()) {
  540. return inclinometer;
  541. }
  542. return nullptr;
  543. }
  544. PlatformSensorReaderWinrtAbsOrientationEulerAngles::
  545. PlatformSensorReaderWinrtAbsOrientationEulerAngles() = default;
  546. HRESULT
  547. PlatformSensorReaderWinrtAbsOrientationEulerAngles::OnReadingChangedCallback(
  548. IInclinometer* inclinometer,
  549. IInclinometerReadingChangedEventArgs* reading_changed_args) {
  550. ComPtr<IInclinometerReading> inclinometer_reading;
  551. HRESULT hr = reading_changed_args->get_Reading(&inclinometer_reading);
  552. if (FAILED(hr)) {
  553. DLOG(ERROR) << "Failed to get inclinometer reading: "
  554. << logging::SystemErrorCodeToString(hr);
  555. return S_OK;
  556. }
  557. float x = 0.0;
  558. hr = inclinometer_reading->get_PitchDegrees(&x);
  559. if (FAILED(hr)) {
  560. DLOG(ERROR) << "Failed to get pitch from inclinometer reading: "
  561. << logging::SystemErrorCodeToString(hr);
  562. return S_OK;
  563. }
  564. float y = 0.0;
  565. hr = inclinometer_reading->get_RollDegrees(&y);
  566. if (FAILED(hr)) {
  567. DLOG(ERROR) << "Failed to get roll from inclinometer reading: "
  568. << logging::SystemErrorCodeToString(hr);
  569. return S_OK;
  570. }
  571. float z = 0.0;
  572. hr = inclinometer_reading->get_YawDegrees(&z);
  573. if (FAILED(hr)) {
  574. DLOG(ERROR) << "Failed to get yaw from inclinometer reading: "
  575. << logging::SystemErrorCodeToString(hr);
  576. return S_OK;
  577. }
  578. base::TimeDelta timestamp_delta;
  579. hr = ConvertSensorReadingTimeStamp(inclinometer_reading, &timestamp_delta);
  580. if (FAILED(hr)) {
  581. DLOG(ERROR) << "Failed to get timestamp from inclinometer reading: "
  582. << logging::SystemErrorCodeToString(hr);
  583. return S_OK;
  584. }
  585. if (!has_received_first_sample_ ||
  586. (abs(x - last_reported_x_) >= kDegreeThreshold) ||
  587. (abs(y - last_reported_y_) >= kDegreeThreshold) ||
  588. (abs(z - last_reported_z_) >= kDegreeThreshold)) {
  589. base::AutoLock autolock(lock_);
  590. if (!client_) {
  591. return S_OK;
  592. }
  593. SensorReading reading;
  594. reading.orientation_euler.x = x;
  595. reading.orientation_euler.y = y;
  596. reading.orientation_euler.z = z;
  597. reading.orientation_euler.timestamp = timestamp_delta.InSecondsF();
  598. client_->OnReadingUpdated(reading);
  599. last_reported_x_ = x;
  600. last_reported_y_ = y;
  601. last_reported_z_ = z;
  602. has_received_first_sample_ = true;
  603. }
  604. return S_OK;
  605. }
  606. // static
  607. std::unique_ptr<PlatformSensorReaderWinBase>
  608. PlatformSensorReaderWinrtAbsOrientationQuaternion::Create() {
  609. auto orientation =
  610. std::make_unique<PlatformSensorReaderWinrtAbsOrientationQuaternion>();
  611. if (orientation->Initialize()) {
  612. return orientation;
  613. }
  614. return nullptr;
  615. }
  616. PlatformSensorReaderWinrtAbsOrientationQuaternion::
  617. PlatformSensorReaderWinrtAbsOrientationQuaternion() = default;
  618. PlatformSensorReaderWinrtAbsOrientationQuaternion::
  619. ~PlatformSensorReaderWinrtAbsOrientationQuaternion() = default;
  620. HRESULT
  621. PlatformSensorReaderWinrtAbsOrientationQuaternion::OnReadingChangedCallback(
  622. IOrientationSensor* orientation_sensor,
  623. IOrientationSensorReadingChangedEventArgs* reading_changed_args) {
  624. ComPtr<IOrientationSensorReading> orientation_sensor_reading;
  625. HRESULT hr = reading_changed_args->get_Reading(&orientation_sensor_reading);
  626. if (FAILED(hr)) {
  627. DLOG(ERROR) << "Failed to get orientation reading: "
  628. << logging::SystemErrorCodeToString(hr);
  629. return S_OK;
  630. }
  631. ComPtr<ISensorQuaternion> quaternion;
  632. hr = orientation_sensor_reading->get_Quaternion(&quaternion);
  633. if (FAILED(hr)) {
  634. DLOG(ERROR) << "Failed to get quaternion from orientation reading: "
  635. << logging::SystemErrorCodeToString(hr);
  636. return S_OK;
  637. }
  638. float w = 0.0;
  639. hr = quaternion->get_W(&w);
  640. if (FAILED(hr)) {
  641. DLOG(ERROR) << "Failed to get w component of orientation reading: "
  642. << logging::SystemErrorCodeToString(hr);
  643. return S_OK;
  644. }
  645. float x = 0.0;
  646. hr = quaternion->get_X(&x);
  647. if (FAILED(hr)) {
  648. DLOG(ERROR) << "Failed to get x component of orientation reading: "
  649. << logging::SystemErrorCodeToString(hr);
  650. return S_OK;
  651. }
  652. float y = 0.0;
  653. hr = quaternion->get_Y(&y);
  654. if (FAILED(hr)) {
  655. DLOG(ERROR) << "Failed to get y component of orientation reading: "
  656. << logging::SystemErrorCodeToString(hr);
  657. return S_OK;
  658. }
  659. float z = 0.0;
  660. hr = quaternion->get_Z(&z);
  661. if (FAILED(hr)) {
  662. DLOG(ERROR) << "Failed to get the z component of orientation reading: "
  663. << logging::SystemErrorCodeToString(hr);
  664. return S_OK;
  665. }
  666. base::TimeDelta timestamp_delta;
  667. hr = ConvertSensorReadingTimeStamp(orientation_sensor_reading,
  668. &timestamp_delta);
  669. if (FAILED(hr)) {
  670. DLOG(ERROR) << "Failed to get timestamp from orientation reading: "
  671. << logging::SystemErrorCodeToString(hr);
  672. return S_OK;
  673. }
  674. SensorReading reading;
  675. reading.orientation_quat.w = w;
  676. reading.orientation_quat.x = x;
  677. reading.orientation_quat.y = y;
  678. reading.orientation_quat.z = z;
  679. reading.orientation_quat.timestamp = timestamp_delta.InSecondsF();
  680. // As per
  681. // https://docs.microsoft.com/en-us/windows-hardware/drivers/sensors/orientation-sensor-thresholds,
  682. // thresholding should be done on angle between two quaternions:
  683. // 2 * cos-1(dot_product(q1, q2))
  684. auto angle =
  685. abs(GetAngleBetweenOrientationSamples(reading, last_reported_sample));
  686. if (!has_received_first_sample_ || (angle >= kRadianThreshold)) {
  687. base::AutoLock autolock(lock_);
  688. if (!client_) {
  689. return S_OK;
  690. }
  691. client_->OnReadingUpdated(reading);
  692. last_reported_sample = reading;
  693. has_received_first_sample_ = true;
  694. }
  695. return S_OK;
  696. }
  697. } // namespace device