blob: 12898aa814f0ab02360711258ef7030f50aaf412 [file] [log] [blame]
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -07001/*
2 * Copyright (C) 2021 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16#pragma once
17
18#include <chrono>
19#include <condition_variable>
20#include <limits>
21#include <memory>
22#include <mutex>
23#include <thread>
24
25#include <media/HeadTrackingProcessor.h>
26#include <media/SensorPoseProvider.h>
27
28namespace android {
29
30/**
31 * This class encapsulates the logic for pose processing, intended for driving a spatializer effect.
32 * This includes integration with the Sensor sub-system for retrieving sensor data, doing all the
33 * necessary processing, etc.
34 *
35 * Calculations happen on a dedicated thread and published to the client via the Listener interface.
36 * A calculation may be triggered in one of two ways:
37 * - By calling calculateAsync() - calculation will be kicked off in the background.
38 * - By setting a timeout in the ctor, a calculation will be triggered after the timeout elapsed
39 * from the last calculateAsync() call.
40 *
Ytai Ben-Tsvi7c2acd12021-09-09 15:50:00 -070041 * This class is thread-safe.
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -070042 */
43class SpatializerPoseController : private media::SensorPoseProvider::Listener {
44 public:
45 /**
46 * Listener interface for getting pose and mode updates.
Ytai Ben-Tsvi7c2acd12021-09-09 15:50:00 -070047 * Methods will always be invoked from a designated thread.
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -070048 */
49 class Listener {
50 public:
51 virtual ~Listener() = default;
52
53 virtual void onHeadToStagePose(const media::Pose3f&) = 0;
54 virtual void onActualModeChange(media::HeadTrackingMode) = 0;
55 };
56
57 /**
58 * Ctor.
59 * sensorPeriod determines how often to receive updates from the sensors (input rate).
60 * maxUpdatePeriod determines how often to produce an output when calculateAsync() isn't
61 * invoked.
62 */
63 SpatializerPoseController(Listener* listener, std::chrono::microseconds sensorPeriod,
64 std::chrono::microseconds maxUpdatePeriod);
65
66 /** Dtor. */
67 ~SpatializerPoseController();
68
69 /**
70 * Set the sensor that is to be used for head-tracking.
71 * nullptr can be used to disable head-tracking.
72 */
73 void setHeadSensor(const ASensor* sensor);
74
75 /**
76 * Set the sensor that is to be used for screen-tracking.
77 * nullptr can be used to disable screen-tracking.
78 */
79 void setScreenSensor(const ASensor* sensor);
80
81 /** Sets the desired head-tracking mode. */
82 void setDesiredMode(media::HeadTrackingMode mode);
83
84 /**
85 * Set the screen-to-stage pose, used in all modes.
86 */
87 void setScreenToStagePose(const media::Pose3f& screenToStage);
88
89 /**
90 * Sets the display orientation.
91 * Orientation is expressed in the angle of rotation from the physical "up" side of the screen
92 * to the logical "up" side of the content displayed the screen. Counterclockwise angles, as
93 * viewed while facing the screen are positive.
94 */
95 void setDisplayOrientation(float physicalToLogicalAngle);
96
97 /**
98 * This causes the current poses for both the head and screen to be considered "center".
99 */
100 void recenter();
101
102 /**
103 * This call triggers the recalculation of the output and the invocation of the relevant
104 * callbacks. This call is async and the callbacks will be triggered shortly after.
105 */
106 void calculateAsync();
107
108 /**
109 * Blocks until calculation and invocation of the respective callbacks has happened at least
Ytai Ben-Tsvi7c2acd12021-09-09 15:50:00 -0700110 * once. Do not call from within callbacks.
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700111 */
112 void waitUntilCalculated();
113
114 private:
115 mutable std::mutex mMutex;
116 Listener* const mListener;
117 const std::chrono::microseconds mSensorPeriod;
Ytai Ben-Tsvi8b6fe3a2021-09-13 15:55:44 -0700118 // Order matters for the following two members to ensure correct destruction.
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700119 std::unique_ptr<media::HeadTrackingProcessor> mProcessor;
Ytai Ben-Tsvi8b6fe3a2021-09-13 15:55:44 -0700120 std::unique_ptr<media::SensorPoseProvider> mPoseProvider;
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700121 int32_t mHeadSensor = media::SensorPoseProvider::INVALID_HANDLE;
122 int32_t mScreenSensor = media::SensorPoseProvider::INVALID_HANDLE;
123 std::optional<media::HeadTrackingMode> mActualMode;
124 std::thread mThread;
125 std::condition_variable mCondVar;
126 bool mShouldCalculate = true;
127 bool mShouldExit = false;
128 bool mCalculated = false;
129
130 void onPose(int64_t timestamp, int32_t sensor, const media::Pose3f& pose,
131 const std::optional<media::Twist3f>& twist) override;
132
Ytai Ben-Tsvi7c2acd12021-09-09 15:50:00 -0700133 /**
134 * Calculates the new outputs and updates internal state. Must be called with the lock held.
135 * Returns values that should be passed to the respective callbacks.
136 */
137 std::tuple<media::Pose3f, std::optional<media::HeadTrackingMode>> calculate_l();
Ytai Ben-Tsvid83c42d2021-08-25 14:19:34 -0700138};
139
140} // namespace android