• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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