The open source OpenXR runtime

d/android: Add Android sensors driver.

authored by

Lubosz Sarnecki and committed by
Ryan Pavlik
f4113ef1 ad42bbff

+493 -1
+4 -1
CMakeLists.txt
··· 174 174 # This one defaults to off, even if we find the deps. 175 175 cmake_dependent_option(XRT_BUILD_DRIVER_SURVIVE "Enable libsurvive driver" OFF "SURVIVE_FOUND" OFF) 176 176 177 + cmake_dependent_option(XRT_BUILD_DRIVER_ANDROID "Enable Android sensors driver" ON "ANDROID" OFF) 178 + 177 179 # You can set this from a superproject to add a driver 178 180 # All drivers must be listed in here to be included in the generated header! 179 - list(APPEND AVAILABLE_DRIVERS ARDUINO DUMMY HDK HYDRA NS OHMD PSMV PSVR RS V4L2 VIVE DAYDREAM REMOTE SURVIVE) 181 + list(APPEND AVAILABLE_DRIVERS "ANDROID" ARDUINO DUMMY HDK HYDRA NS OHMD PSMV PSVR RS V4L2 VIVE DAYDREAM REMOTE SURVIVE) 180 182 181 183 182 184 # Package name needs to be known by the native code itself. ··· 280 282 message(STATUS "# FEATURE_OPENXR_LAYER_EQUIRECT: ${XRT_FEATURE_OPENXR_LAYER_EQUIRECT}") 281 283 message(STATUS "# FEATURE_OPENXR_LAYER_EQUIRECT_LEGACY: ${XRT_FEATURE_OPENXR_LAYER_EQUIRECT_LEGACY}") 282 284 message(STATUS "#") 285 + message(STATUS "# DRIVER_ANDROID: ${XRT_BUILD_DRIVER_ANDROID}") 283 286 message(STATUS "# DRIVER_ARDUINO: ${XRT_BUILD_DRIVER_ARDUINO}") 284 287 message(STATUS "# DRIVER_DAYDREAM: ${XRT_BUILD_DRIVER_DAYDREAM}") 285 288 message(STATUS "# DRIVER_DUMMY: ${XRT_BUILD_DRIVER_DUMMY}")
+1
doc/changes/drivers/mr.581.md
··· 1 + Add initial "Cardboard" phone-holder driver for Android.
+13
src/xrt/drivers/CMakeLists.txt
··· 194 194 list(APPEND ENABLED_HEADSET_DRIVERS survive) 195 195 endif() 196 196 197 + if(XRT_BUILD_DRIVER_ANDROID) 198 + set(ANDROID_SOURCE_FILES 199 + android/android_prober.c 200 + android/android_prober.h 201 + android/android_sensors.c 202 + android/android_sensors.h 203 + ) 204 + 205 + add_library(drv_android STATIC ${ANDROID_SOURCE_FILES}) 206 + target_link_libraries(drv_android PRIVATE xrt-interfaces aux_util aux_os ${ANDROID_LIBRARY}) 207 + list(APPEND ENABLED_DRIVERS android) 208 + endif() 209 + 197 210 if(ENABLED_HEADSET_DRIVERS) 198 211 set(ENABLED_DRIVERS ${ENABLED_HEADSET_DRIVERS} ${ENABLED_DRIVERS}) 199 212 list(SORT ENABLED_DRIVERS)
+91
src/xrt/drivers/android/android_prober.c
··· 1 + // Copyright 2020, Collabora, Ltd. 2 + // SPDX-License-Identifier: BSL-1.0 3 + /*! 4 + * @file 5 + * @brief Interface to Android sensors prober code. 6 + * @author Lubosz Sarnecki <lubosz.sarnecki@collabora.com> 7 + * @ingroup drv_android 8 + */ 9 + 10 + #include <stdio.h> 11 + #include <stdlib.h> 12 + #include <wchar.h> 13 + 14 + #include "xrt/xrt_prober.h" 15 + 16 + #include "util/u_misc.h" 17 + #include "util/u_debug.h" 18 + #include "util/u_logging.h" 19 + 20 + #include "android_prober.h" 21 + #include "android_sensors.h" 22 + 23 + 24 + 25 + /* 26 + * 27 + * Defines & structs. 28 + * 29 + */ 30 + 31 + /*! 32 + * Android prober struct. 33 + * 34 + * @ingroup drv_android 35 + * @implements xrt_auto_prober 36 + */ 37 + struct android_prober 38 + { 39 + struct xrt_auto_prober base; 40 + }; 41 + 42 + 43 + /* 44 + * 45 + * Static functions. 46 + * 47 + */ 48 + 49 + //! @private @memberof android_prober 50 + static inline struct android_prober * 51 + android_prober(struct xrt_auto_prober *p) 52 + { 53 + return (struct android_prober *)p; 54 + } 55 + 56 + //! @public @memberof android_prober 57 + static void 58 + android_prober_destroy(struct xrt_auto_prober *p) 59 + { 60 + struct android_prober *pandroid = android_prober(p); 61 + free(pandroid); 62 + } 63 + 64 + //! @public @memberof android_prober 65 + static struct xrt_device * 66 + android_prober_autoprobe(struct xrt_auto_prober *xap, 67 + cJSON *attached_data, 68 + bool no_hmds, 69 + struct xrt_prober *xp) 70 + { 71 + struct android_device *dd = android_device_create(); 72 + return &dd->base; 73 + } 74 + 75 + 76 + /* 77 + * 78 + * Exported functions. 79 + * 80 + */ 81 + 82 + struct xrt_auto_prober * 83 + android_create_auto_prober() 84 + { 85 + struct android_prober *p = U_TYPED_CALLOC(struct android_prober); 86 + p->base.name = "Android"; 87 + p->base.destroy = android_prober_destroy; 88 + p->base.lelo_dallas_autoprobe = android_prober_autoprobe; 89 + 90 + return &p->base; 91 + }
+41
src/xrt/drivers/android/android_prober.h
··· 1 + // Copyright 2020, Collabora, Ltd. 2 + // SPDX-License-Identifier: BSL-1.0 3 + /*! 4 + * @file 5 + * @brief Interface to Android sensors driver. 6 + * @author Lubosz Sarnecki <lubosz.sarnecki@collabora.com> 7 + * @ingroup drv_android 8 + */ 9 + 10 + #pragma once 11 + 12 + #ifdef __cplusplus 13 + extern "C" { 14 + #endif 15 + 16 + /*! 17 + * @defgroup drv_android Android sensors driver 18 + * @ingroup drv 19 + * 20 + * @brief Generic driver for phone sensors. 21 + */ 22 + 23 + /*! 24 + * Probing function for Android sensors. 25 + * 26 + * @ingroup drv_android 27 + */ 28 + struct xrt_auto_prober * 29 + android_create_auto_prober(); 30 + 31 + 32 + /*! 33 + * @dir drivers/android 34 + * 35 + * @brief @ref drv_android files. 36 + */ 37 + 38 + 39 + #ifdef __cplusplus 40 + } 41 + #endif
+260
src/xrt/drivers/android/android_sensors.c
··· 1 + // Copyright 2013, Fredrik Hultin. 2 + // Copyright 2013, Jakob Bornecrantz. 3 + // Copyright 2015, Joey Ferwerda. 4 + // Copyright 2020, Collabora, Ltd. 5 + // SPDX-License-Identifier: BSL-1.0 6 + /*! 7 + * @file 8 + * @brief Android sensors driver code. 9 + * @author Lubosz Sarnecki <lubosz.sarnecki@collabora.com> 10 + * @ingroup drv_android 11 + */ 12 + 13 + #include "android_sensors.h" 14 + 15 + #include "util/u_debug.h" 16 + #include "util/u_device.h" 17 + #include "util/u_var.h" 18 + 19 + // 60 events per second (in us). 20 + #define POLL_RATE_USEC (1000L / 60) * 1000 21 + 22 + 23 + DEBUG_GET_ONCE_LOG_OPTION(android_log, "ANDROID_SENSORS_LOG", U_LOGGING_WARN) 24 + 25 + static inline struct android_device * 26 + android_device(struct xrt_device *xdev) 27 + { 28 + return (struct android_device *)xdev; 29 + } 30 + 31 + // Callback for the Android sensor event queue 32 + static int 33 + android_sensor_callback(int fd, int events, void *data) 34 + { 35 + struct android_device *d = (struct android_device *)data; 36 + 37 + if (d->accelerometer == NULL || d->gyroscope == NULL) 38 + return 1; 39 + 40 + ASensorEvent event; 41 + struct xrt_vec3 gyro; 42 + struct xrt_vec3 accel; 43 + while (ASensorEventQueue_getEvents(d->event_queue, &event, 1) > 0) { 44 + 45 + switch (event.type) { 46 + case ASENSOR_TYPE_ACCELEROMETER: { 47 + accel.x = event.acceleration.y; 48 + accel.y = -event.acceleration.x; 49 + accel.z = event.acceleration.z; 50 + 51 + ANDROID_TRACE(d, "accel %ld %.2f %.2f %.2f", 52 + event.timestamp, accel.x, accel.y, 53 + accel.z); 54 + break; 55 + } 56 + case ASENSOR_TYPE_GYROSCOPE: { 57 + gyro.x = -event.data[1]; 58 + gyro.y = event.data[0]; 59 + gyro.z = event.data[2]; 60 + 61 + ANDROID_TRACE(d, "gyro %ld %.2f %.2f %.2f", 62 + event.timestamp, gyro.x, gyro.y, gyro.z); 63 + 64 + // TODO: Make filter handle accelerometer 65 + struct xrt_vec3 null_accel; 66 + 67 + // Lock last and the fusion. 68 + os_mutex_lock(&d->lock); 69 + 70 + m_imu_3dof_update(&d->fusion, event.timestamp, 71 + &null_accel, &gyro); 72 + 73 + // Now done. 74 + os_mutex_unlock(&d->lock); 75 + } 76 + default: 77 + ANDROID_TRACE(d, "Unhandled event type %d", event.type); 78 + } 79 + } 80 + 81 + return 1; 82 + } 83 + 84 + static void * 85 + android_run_thread(void *ptr) 86 + { 87 + struct android_device *d = (struct android_device *)ptr; 88 + 89 + d->sensor_manager = ASensorManager_getInstance(); 90 + d->accelerometer = ASensorManager_getDefaultSensor( 91 + d->sensor_manager, ASENSOR_TYPE_ACCELEROMETER); 92 + d->gyroscope = ASensorManager_getDefaultSensor(d->sensor_manager, 93 + ASENSOR_TYPE_GYROSCOPE); 94 + 95 + ALooper *looper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS); 96 + 97 + d->event_queue = ASensorManager_createEventQueue( 98 + d->sensor_manager, looper, ALOOPER_POLL_CALLBACK, 99 + android_sensor_callback, (void *)d); 100 + 101 + // Start sensors in case this was not done already. 102 + if (d->accelerometer != NULL) { 103 + ASensorEventQueue_enableSensor(d->event_queue, 104 + d->accelerometer); 105 + ASensorEventQueue_setEventRate(d->event_queue, d->accelerometer, 106 + POLL_RATE_USEC); 107 + } 108 + if (d->gyroscope != NULL) { 109 + ASensorEventQueue_enableSensor(d->event_queue, d->gyroscope); 110 + ASensorEventQueue_setEventRate(d->event_queue, d->gyroscope, 111 + POLL_RATE_USEC); 112 + } 113 + 114 + int ret = 0; 115 + while (ret != ALOOPER_POLL_ERROR) { 116 + ret = ALooper_pollAll(0, NULL, NULL, NULL); 117 + } 118 + 119 + return NULL; 120 + } 121 + 122 + 123 + /* 124 + * 125 + * Device functions. 126 + * 127 + */ 128 + 129 + static void 130 + android_device_destroy(struct xrt_device *xdev) 131 + { 132 + struct android_device *android = android_device(xdev); 133 + 134 + // Destroy the thread object. 135 + os_thread_helper_destroy(&android->oth); 136 + 137 + // Now that the thread is not running we can destroy the lock. 138 + os_mutex_destroy(&android->lock); 139 + 140 + // Destroy the fusion. 141 + m_imu_3dof_close(&android->fusion); 142 + 143 + // Remove the variable tracking. 144 + u_var_remove_root(android); 145 + 146 + free(android); 147 + } 148 + 149 + static void 150 + android_device_update_inputs(struct xrt_device *xdev) 151 + { 152 + // Empty 153 + } 154 + 155 + static void 156 + android_device_get_tracked_pose(struct xrt_device *xdev, 157 + enum xrt_input_name name, 158 + uint64_t at_timestamp_ns, 159 + struct xrt_space_relation *out_relation) 160 + { 161 + (void)at_timestamp_ns; 162 + 163 + struct android_device *d = android_device(xdev); 164 + out_relation->pose.orientation = d->fusion.rot; 165 + 166 + //! @todo assuming that orientation is actually currently tracked. 167 + out_relation->relation_flags = (enum xrt_space_relation_flags)( 168 + XRT_SPACE_RELATION_ORIENTATION_VALID_BIT | 169 + XRT_SPACE_RELATION_ORIENTATION_TRACKED_BIT); 170 + } 171 + 172 + static void 173 + android_device_get_view_pose(struct xrt_device *xdev, 174 + struct xrt_vec3 *eye_relation, 175 + uint32_t view_index, 176 + struct xrt_pose *out_pose) 177 + { 178 + struct xrt_pose pose = {{0.0f, 0.0f, 0.0f, 1.0f}, {0.0f, 0.0f, 0.0f}}; 179 + bool adjust = view_index == 0; 180 + 181 + pose.position.x = eye_relation->x / 2.0f; 182 + pose.position.y = eye_relation->y / 2.0f; 183 + pose.position.z = eye_relation->z / 2.0f; 184 + 185 + // Adjust for left/right while also making sure there aren't any -0.f. 186 + if (pose.position.x > 0.0f && adjust) { 187 + pose.position.x = -pose.position.x; 188 + } 189 + if (pose.position.y > 0.0f && adjust) { 190 + pose.position.y = -pose.position.y; 191 + } 192 + if (pose.position.z > 0.0f && adjust) { 193 + pose.position.z = -pose.position.z; 194 + } 195 + 196 + *out_pose = pose; 197 + } 198 + 199 + /* 200 + * 201 + * Prober functions. 202 + * 203 + */ 204 + 205 + struct android_device * 206 + android_device_create() 207 + { 208 + enum u_device_alloc_flags flags = (enum u_device_alloc_flags)( 209 + U_DEVICE_ALLOC_HMD | U_DEVICE_ALLOC_TRACKING_NONE); 210 + struct android_device *d = 211 + U_DEVICE_ALLOCATE(struct android_device, flags, 1, 0); 212 + 213 + d->base.name = XRT_DEVICE_ANDROID; 214 + d->base.destroy = android_device_destroy; 215 + d->base.update_inputs = android_device_update_inputs; 216 + d->base.get_tracked_pose = android_device_get_tracked_pose; 217 + d->base.get_view_pose = android_device_get_view_pose; 218 + d->base.inputs[0].name = XRT_INPUT_GENERIC_HEAD_POSE; 219 + d->base.device_type = XRT_DEVICE_TYPE_HMD; 220 + 221 + d->ll = debug_get_log_option_android_log(); 222 + 223 + m_imu_3dof_init(&d->fusion, M_IMU_3DOF_USE_GRAVITY_DUR_20MS); 224 + 225 + // Everything done, finally start the thread. 226 + int ret = os_thread_helper_start(&d->oth, android_run_thread, d); 227 + if (ret != 0) { 228 + ANDROID_ERROR(d, "Failed to start thread!"); 229 + android_device_destroy(&d->base); 230 + return NULL; 231 + } 232 + 233 + // Setup info. 234 + struct u_device_simple_info info; 235 + info.display.w_pixels = 1280; 236 + info.display.h_pixels = 720; 237 + info.display.w_meters = 0.13f; 238 + info.display.h_meters = 0.07f; 239 + info.lens_horizontal_separation_meters = 0.13f / 2.0f; 240 + info.lens_vertical_position_meters = 0.07f / 2.0f; 241 + info.views[0].fov = 85.0f * (M_PI / 180.0f); 242 + info.views[1].fov = 85.0f * (M_PI / 180.0f); 243 + 244 + if (!u_device_setup_split_side_by_side(&d->base, &info)) { 245 + ANDROID_ERROR(d, "Failed to setup basic device info"); 246 + android_device_destroy(&d->base); 247 + return NULL; 248 + } 249 + 250 + u_var_add_root(d, "Android phone", true); 251 + u_var_add_ro_vec3_f32(d, &d->fusion.last.accel, "last.accel"); 252 + u_var_add_ro_vec3_f32(d, &d->fusion.last.gyro, "last.gyro"); 253 + 254 + d->base.orientation_tracking_supported = true; 255 + d->base.position_tracking_supported = false; 256 + 257 + ANDROID_DEBUG(d, "Created device!"); 258 + 259 + return d; 260 + }
+70
src/xrt/drivers/android/android_sensors.h
··· 1 + // Copyright 2020, Collabora, Ltd. 2 + // SPDX-License-Identifier: BSL-1.0 3 + /*! 4 + * @file 5 + * @brief Android sensors driver header. 6 + * @author Lubosz Sarnecki <lubosz.sarnecki@collabora.com> 7 + * @ingroup drv_android 8 + */ 9 + 10 + #pragma once 11 + 12 + #include <android/sensor.h> 13 + 14 + #include "math/m_api.h" 15 + #include "math/m_imu_pre.h" 16 + #include "math/m_imu_3dof.h" 17 + 18 + #include "xrt/xrt_device.h" 19 + 20 + #include "os/os_threading.h" 21 + 22 + #include "util/u_logging.h" 23 + 24 + #ifdef __cplusplus 25 + extern "C" { 26 + #endif 27 + 28 + /*! 29 + * @implements xrt_device 30 + */ 31 + struct android_device 32 + { 33 + struct xrt_device base; 34 + struct os_thread_helper oth; 35 + 36 + ASensorManager *sensor_manager; 37 + const ASensor *accelerometer; 38 + const ASensor *gyroscope; 39 + ASensorEventQueue *event_queue; 40 + 41 + struct 42 + { 43 + //! Lock for last and fusion. 44 + struct os_mutex lock; 45 + struct m_imu_3dof fusion; 46 + }; 47 + 48 + enum u_logging_level ll; 49 + }; 50 + 51 + 52 + struct android_device * 53 + android_device_create(); 54 + 55 + 56 + /* 57 + * 58 + * Printing functions. 59 + * 60 + */ 61 + 62 + #define ANDROID_TRACE(d, ...) U_LOG_XDEV_IFL_T(&d->base, d->ll, __VA_ARGS__) 63 + #define ANDROID_DEBUG(d, ...) U_LOG_XDEV_IFL_D(&d->base, d->ll, __VA_ARGS__) 64 + #define ANDROID_INFO(d, ...) U_LOG_XDEV_IFL_I(&d->base, d->ll, __VA_ARGS__) 65 + #define ANDROID_WARN(d, ...) U_LOG_XDEV_IFL_W(&d->base, d->ll, __VA_ARGS__) 66 + #define ANDROID_ERROR(d, ...) U_LOG_XDEV_IFL_E(&d->base, d->ll, __VA_ARGS__) 67 + 68 + #ifdef __cplusplus 69 + } 70 + #endif
+1
src/xrt/include/xrt/xrt_defines.h
··· 419 419 XRT_DEVICE_VIVE_WAND, 420 420 XRT_DEVICE_VIVE_TRACKER_GEN1, 421 421 XRT_DEVICE_VIVE_TRACKER_GEN2, 422 + XRT_DEVICE_ANDROID 422 423 }; 423 424 424 425 /*!
+4
src/xrt/targets/common/CMakeLists.txt
··· 76 76 target_link_libraries(target_lists PRIVATE drv_survive) 77 77 endif() 78 78 79 + if(XRT_BUILD_DRIVER_ANDROID) 80 + target_link_libraries(target_lists PRIVATE drv_android) 81 + endif() 82 + 79 83 #### 80 84 # Instance 81 85 #
+8
src/xrt/targets/common/target_lists.c
··· 54 54 #include "daydream/daydream_interface.h" 55 55 #endif 56 56 57 + #ifdef XRT_BUILD_DRIVER_ANDROID 58 + #include "android/android_prober.h" 59 + #endif 60 + 57 61 /*! 58 62 * Each entry should be a vendor ID (VID), product ID (PID), a "found" function, 59 63 * and a string literal name. ··· 132 136 #ifdef XRT_BUILD_DRIVER_NS 133 137 // North star driver here for now. 134 138 ns_create_auto_prober, 139 + #endif 140 + 141 + #ifdef XRT_BUILD_DRIVER_ANDROID 142 + android_create_auto_prober, 135 143 #endif 136 144 137 145 #ifdef XRT_BUILD_DRIVER_DUMMY