1 /*
2 * Copyright (C) 2024 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
17 #define LOG_TAG "Spatializer_Test"
18
19 #include "Spatializer.h"
20
21 #include <string>
22 #include <unordered_set>
23
24 #include <gtest/gtest.h>
25
26 #include <android/media/audio/common/AudioLatencyMode.h>
27 #include <android/media/audio/common/HeadTracking.h>
28 #include <android/media/audio/common/Spatialization.h>
29 #include <com_android_media_audio.h>
30 #include <utils/Log.h>
31
32 using namespace android;
33 using media::audio::common::HeadTracking;
34 using media::audio::common::Spatialization;
35
36 class TestSpatializerPolicyCallback :
37 public SpatializerPolicyCallback {
38 public:
onCheckSpatializer()39 void onCheckSpatializer() override {};
40 };
41
42 class SpatializerTest : public ::testing::Test {
43 protected:
SetUp()44 void SetUp() override {
45 const sp<EffectsFactoryHalInterface> effectsFactoryHal
46 = EffectsFactoryHalInterface::create();
47 mSpatializer = Spatializer::create(&mTestCallback, effectsFactoryHal);
48 if (mSpatializer == nullptr) {
49 GTEST_SKIP() << "Skipping Spatializer tests: no spatializer";
50 }
51 std::vector<Spatialization::Level> levels;
52 binder::Status status = mSpatializer->getSupportedLevels(&levels);
53 ASSERT_TRUE(status.isOk());
54 for (auto level : levels) {
55 if (level != Spatialization::Level::NONE) {
56 mSpatializer->setLevel(level);
57 break;
58 }
59 }
60 mSpatializer->setOutput(sTestOutput);
61 }
62
TearDown()63 void TearDown() override {
64 if (mSpatializer == nullptr) {
65 return;
66 }
67 mSpatializer->setLevel(Spatialization::Level::NONE);
68 mSpatializer->setOutput(AUDIO_IO_HANDLE_NONE);
69 mSpatializer->setDesiredHeadTrackingMode(HeadTracking::Mode::DISABLED);
70 mSpatializer->setHeadSensor(SpatializerPoseController::INVALID_SENSOR);
71 mSpatializer->updateActiveTracks(0);
72 }
73
74 static constexpr audio_io_handle_t sTestOutput= 1977;
75 static constexpr int sTestSensorHandle = 1980;
76
77 const static inline std::vector<audio_latency_mode_t> sA2DPLatencyModes = {
78 AUDIO_LATENCY_MODE_LOW,
79 AUDIO_LATENCY_MODE_FREE
80 };
81 const static inline std::vector<audio_latency_mode_t> sBLELatencyModes = {
82 AUDIO_LATENCY_MODE_LOW,
83 AUDIO_LATENCY_MODE_DYNAMIC_SPATIAL_AUDIO_SOFTWARE,
84 AUDIO_LATENCY_MODE_DYNAMIC_SPATIAL_AUDIO_HARDWARE,
85 AUDIO_LATENCY_MODE_FREE
86 };
87
setpUpForHeadtracking()88 bool setpUpForHeadtracking() {
89 bool htSupported;
90 mSpatializer->isHeadTrackingSupported(&htSupported);
91 if (!htSupported) {
92 return false;
93 }
94
95 std::vector<HeadTracking::Mode> htModes;
96 mSpatializer->getSupportedHeadTrackingModes(&htModes);
97 for (auto htMode : htModes) {
98 if (htMode != HeadTracking::Mode::DISABLED) {
99 mSpatializer->setDesiredHeadTrackingMode(htMode);
100 break;
101 }
102 }
103
104 mSpatializer->setHeadSensor(sTestSensorHandle);
105 return true;
106 }
107
108 TestSpatializerPolicyCallback mTestCallback;
109 sp<Spatializer> mSpatializer;
110 };
111
TEST_F(SpatializerTest,SupportedA2dpLatencyTest)112 TEST_F(SpatializerTest, SupportedA2dpLatencyTest) {
113 if (!setpUpForHeadtracking()) {
114 GTEST_SKIP() << "Skipping SupportedA2dpLatencyTest: head tracking not supported";
115 }
116 std::vector<audio_latency_mode_t> latencies = sA2DPLatencyModes;
117 mSpatializer->onSupportedLatencyModesChangedMsg(sTestOutput, std::move(latencies));
118
119 std::vector<audio_latency_mode_t> supportedLatencies =
120 mSpatializer->getSupportedLatencyModes();
121
122 ASSERT_TRUE(supportedLatencies == sA2DPLatencyModes);
123 // Free mode must always be the last of the ordered list
124 ASSERT_TRUE(supportedLatencies.back() == AUDIO_LATENCY_MODE_FREE);
125 }
126
TEST_F(SpatializerTest,SupportedBleLatencyTest)127 TEST_F(SpatializerTest, SupportedBleLatencyTest) {
128 if (!setpUpForHeadtracking()) {
129 GTEST_SKIP() << "Skipping SupportedBleLatencyTest: head tracking not supported";
130 }
131 if (!com::android::media::audio::dsa_over_bt_le_audio()) {
132 GTEST_SKIP() << "Skipping SupportedBleLatencyTest: DSA over LE not enabled";
133 }
134 std::vector<audio_latency_mode_t> latencies = sBLELatencyModes;
135 mSpatializer->onSupportedLatencyModesChangedMsg(sTestOutput, std::move(latencies));
136
137 std::vector<audio_latency_mode_t> supportedLatencies =
138 mSpatializer->getSupportedLatencyModes();
139
140 ASSERT_TRUE(supportedLatencies.back() == AUDIO_LATENCY_MODE_FREE);
141 ASSERT_TRUE(std::find(supportedLatencies.begin(), supportedLatencies.end(),
142 AUDIO_LATENCY_MODE_LOW) != supportedLatencies.end());
143
144 std::vector<audio_latency_mode_t> orderedLowLatencyModes =
145 mSpatializer->getOrderedLowLatencyModes();
146
147 std::vector<audio_latency_mode_t> supportedLowLatencyModes;
148 // remove free mode at the end of the supported list to only retain low latency modes
149 std::copy(supportedLatencies.begin(),
150 supportedLatencies.begin() + supportedLatencies.size() - 1,
151 std::back_inserter(supportedLowLatencyModes));
152
153 // Verify that supported low latency modes are always in ordered latency modes list and
154 // in the same order
155 std::vector<audio_latency_mode_t>::iterator lastIt = orderedLowLatencyModes.begin();
156 for (auto latency : supportedLowLatencyModes) {
157 auto it = std::find(orderedLowLatencyModes.begin(), orderedLowLatencyModes.end(), latency);
158 ASSERT_NE(it, orderedLowLatencyModes.end());
159 ASSERT_LE(lastIt, it);
160 lastIt = it;
161 }
162 }
163
TEST_F(SpatializerTest,RequestedA2dpLatencyTest)164 TEST_F(SpatializerTest, RequestedA2dpLatencyTest) {
165 if (!setpUpForHeadtracking()) {
166 GTEST_SKIP() << "Skipping RequestedA2dpLatencyTest: head tracking not supported";
167 }
168
169 std::vector<audio_latency_mode_t> latencies = sA2DPLatencyModes;
170 mSpatializer->onSupportedLatencyModesChangedMsg(sTestOutput, std::move(latencies));
171
172 // requested latency mode must be free if no spatialized tracks are active
173 audio_latency_mode_t requestedLatencyMode = mSpatializer->getRequestedLatencyMode();
174 ASSERT_EQ(requestedLatencyMode, AUDIO_LATENCY_MODE_FREE);
175
176 // requested latency mode must be low if at least one spatialized tracks is active
177 mSpatializer->updateActiveTracks(1);
178 requestedLatencyMode = mSpatializer->getRequestedLatencyMode();
179 ASSERT_EQ(requestedLatencyMode, AUDIO_LATENCY_MODE_LOW);
180
181 // requested latency mode must be free after stopping the last spatialized tracks
182 mSpatializer->updateActiveTracks(0);
183 requestedLatencyMode = mSpatializer->getRequestedLatencyMode();
184 ASSERT_EQ(requestedLatencyMode, AUDIO_LATENCY_MODE_FREE);
185 }
186
TEST_F(SpatializerTest,RequestedBleLatencyTest)187 TEST_F(SpatializerTest, RequestedBleLatencyTest) {
188 if (!setpUpForHeadtracking()) {
189 GTEST_SKIP() << "Skipping RequestedBleLatencyTest: head tracking not supported";
190 }
191 if (!com::android::media::audio::dsa_over_bt_le_audio()) {
192 GTEST_SKIP() << "Skipping RequestedBleLatencyTest: DSA over LE not enabled";
193 }
194
195 mSpatializer->onSupportedLatencyModesChangedMsg(sTestOutput,
196 { AUDIO_LATENCY_MODE_DYNAMIC_SPATIAL_AUDIO_SOFTWARE,
197 AUDIO_LATENCY_MODE_FREE });
198
199 // requested latency mode must be free if no spatialized tracks are active
200 audio_latency_mode_t requestedLatencyMode = mSpatializer->getRequestedLatencyMode();
201 ASSERT_EQ(requestedLatencyMode, AUDIO_LATENCY_MODE_FREE);
202
203 // requested latency mode must be low software if at least one spatialized tracks is active
204 // and the only supported low latency mode is low software
205 mSpatializer->updateActiveTracks(1);
206 requestedLatencyMode = mSpatializer->getRequestedLatencyMode();
207 ASSERT_EQ(requestedLatencyMode, AUDIO_LATENCY_MODE_DYNAMIC_SPATIAL_AUDIO_SOFTWARE);
208
209 mSpatializer->onSupportedLatencyModesChangedMsg(sTestOutput,
210 { AUDIO_LATENCY_MODE_DYNAMIC_SPATIAL_AUDIO_SOFTWARE,
211 AUDIO_LATENCY_MODE_DYNAMIC_SPATIAL_AUDIO_HARDWARE,
212 AUDIO_LATENCY_MODE_FREE });
213
214 requestedLatencyMode = mSpatializer->getRequestedLatencyMode();
215 HeadTracking::ConnectionMode connectionMode = mSpatializer->getHeadtrackingConnectionMode();
216
217 // If low hardware mode is used, the spatializer must use either use one of the sensor
218 // connection tunneled modes.
219 // Otherwise, low software mode must be used
220 if (requestedLatencyMode == AUDIO_LATENCY_MODE_DYNAMIC_SPATIAL_AUDIO_HARDWARE) {
221 ASSERT_TRUE(connectionMode == HeadTracking::ConnectionMode::DIRECT_TO_SENSOR_TUNNEL
222 || connectionMode == HeadTracking::ConnectionMode::DIRECT_TO_SENSOR_SW);
223 } else {
224 ASSERT_EQ(requestedLatencyMode, AUDIO_LATENCY_MODE_DYNAMIC_SPATIAL_AUDIO_SOFTWARE);
225 }
226
227 // requested latency mode must be free after stopping the last spatialized tracks
228 mSpatializer->updateActiveTracks(0);
229 requestedLatencyMode = mSpatializer->getRequestedLatencyMode();
230 ASSERT_EQ(requestedLatencyMode, AUDIO_LATENCY_MODE_FREE);
231 }
232