1 /*
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 <optional>
19 
20 #include "media/HeadTrackingMode.h"
21 #include "media/Pose.h"
22 
23 #include "PoseRateLimiter.h"
24 
25 namespace android {
26 namespace media {
27 
28 /**
29  * Head-tracking mode selector.
30  *
31  * This class is responsible for production of the determining pose for audio virtualization, based
32  * on a number of available sources and a selectable mode.
33  *
34  * Typical flow is:
35  * ModeSelector selector(...);
36  * while (...) {
37  *     // Set inputs.
38  *     selector.setFoo(...);
39  *     selector.setBar(...);
40  *
41  *     // Update outputs based on inputs.
42  *     selector.calculate(...);
43  *
44  *     // Get outputs.
45  *     Pose3f pose = selector.getHeadToStagePose();
46  * }
47  *
48  * This class is not thread-safe, but thread-compatible.
49  *
50  * For details on the frames of reference involved, their composition and the definitions to the
51  * different modes, refer to:
52  * go/immersive-audio-frames
53  *
54  * The actual mode may deviate from the desired mode in the following cases:
55  * - When we cannot get a valid and fresh estimate of the screen-to-head pose, we will fall back
56  *   from screen-relative to world-relative.
57  * - When we cannot get a fresh estimate of the world-to-head pose, we will fall back from
58  *   world-relative to static.
59  *
60  * All the timestamps used here are of arbitrary units and origin. They just need to be consistent
61  * between all the calls and with the Options provided for determining freshness and rate limiting.
62  */
63 class ModeSelector {
64   public:
65     struct Options {
66         int64_t freshnessTimeout = std::numeric_limits<int64_t>::max();
67     };
68 
69     ModeSelector(const Options& options, HeadTrackingMode initialMode = HeadTrackingMode::STATIC);
70 
71     /** Sets the desired head-tracking mode. */
72     void setDesiredMode(HeadTrackingMode mode);
73 
74     /**
75      * Set the screen-to-stage pose, used in all modes.
76      */
77     void setScreenToStagePose(const Pose3f& screenToStage);
78 
79     /**
80      * Set the screen-to-head pose, used in screen-relative mode.
81      * The timestamp needs to reflect how fresh the sample is (not necessarily which point in time
82      * it applies to). nullopt can be used if it is determined that the listener is not in front of
83      * the screen.
84      */
85     void setScreenToHeadPose(int64_t timestamp, const std::optional<Pose3f>& screenToHead);
86 
87     /**
88      * Set the world-to-head pose, used in world-relative mode.
89      * The timestamp needs to reflect how fresh the sample is (not necessarily which point in time
90      * it applies to).
91      */
92     void setWorldToHeadPose(int64_t timestamp, const Pose3f& worldToHead);
93 
94     /**
95      * Process all the previous inputs and update the outputs.
96      */
97     void calculate(int64_t timestamp);
98 
99     /**
100      * Get the aggregate head-to-stage pose (primary output of this module).
101      */
102     Pose3f getHeadToStagePose() const;
103 
104     /**
105      * Get the actual head-tracking mode (which may deviate from the desired one as mentioned in the
106      * class documentation above).
107      */
108     HeadTrackingMode getActualMode() const;
109 
110   private:
111     const Options mOptions;
112 
113     HeadTrackingMode mDesiredMode;
114     Pose3f mScreenToStage;
115     std::optional<Pose3f> mScreenToHead;
116     int64_t mScreenToHeadTimestamp;
117     std::optional<Pose3f> mWorldToHead;
118     int64_t mWorldToHeadTimestamp;
119 
120     HeadTrackingMode mActualMode;
121     Pose3f mHeadToStage;
122 
123     void calculateActualMode(int64_t timestamp);
124 };
125 
126 }  // namespace media
127 }  // namespace android
128