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
17 //#define LOG_NDEBUG 0
18 #define LOG_TAG "AudioRoutingTest"
19
20 #include <string.h>
21
22 #include <binder/Binder.h>
23 #include <binder/ProcessState.h>
24 #include <cutils/properties.h>
25 #include <gtest/gtest.h>
26
27 #include "audio_test_utils.h"
28 #include "test_execution_tracer.h"
29
30 using namespace android;
31
32 // UNIT TEST
TEST(AudioTrackTest,TestPerformanceMode)33 TEST(AudioTrackTest, TestPerformanceMode) {
34 std::vector<struct audio_port_v7> ports;
35 ASSERT_EQ(OK, listAudioPorts(ports));
36 audio_output_flags_t output_flags[] = {AUDIO_OUTPUT_FLAG_FAST, AUDIO_OUTPUT_FLAG_DEEP_BUFFER};
37 audio_flags_mask_t flags[] = {AUDIO_FLAG_LOW_LATENCY, AUDIO_FLAG_DEEP_BUFFER};
38 bool hasFlag = false;
39 for (int i = 0; i < sizeof(flags) / sizeof(flags[0]); i++) {
40 hasFlag = false;
41 for (const auto& port : ports) {
42 if (port.role == AUDIO_PORT_ROLE_SOURCE && port.type == AUDIO_PORT_TYPE_MIX) {
43 if ((port.active_config.flags.output & output_flags[i]) != 0) {
44 hasFlag = true;
45 break;
46 }
47 }
48 }
49 if (!hasFlag) continue;
50 audio_attributes_t attributes = AUDIO_ATTRIBUTES_INITIALIZER;
51 attributes.usage = AUDIO_USAGE_MEDIA;
52 attributes.content_type = AUDIO_CONTENT_TYPE_MUSIC;
53 attributes.flags = flags[i];
54 sp<AudioPlayback> ap = sp<AudioPlayback>::make(0 /* sampleRate */, AUDIO_FORMAT_PCM_16_BIT,
55 AUDIO_CHANNEL_OUT_STEREO,
56 AUDIO_OUTPUT_FLAG_NONE, AUDIO_SESSION_NONE,
57 AudioTrack::TRANSFER_OBTAIN, &attributes);
58 ASSERT_NE(nullptr, ap);
59 ASSERT_EQ(OK, ap->loadResource("/data/local/tmp/bbb_2ch_24kHz_s16le.raw"))
60 << "Unable to open Resource";
61 ASSERT_EQ(OK, ap->create()) << "track creation failed";
62 sp<OnAudioDeviceUpdateNotifier> cb = sp<OnAudioDeviceUpdateNotifier>::make();
63 EXPECT_EQ(OK, ap->getAudioTrackHandle()->addAudioDeviceCallback(cb));
64 EXPECT_EQ(OK, ap->start()) << "audio track start failed";
65 EXPECT_EQ(OK, ap->onProcess());
66 EXPECT_EQ(OK, cb->waitForAudioDeviceCb());
67 const auto [audioIo, deviceIds] = cb->getLastPortAndDevices();
68 EXPECT_TRUE(checkPatchPlayback(audioIo, deviceIds));
69 EXPECT_NE(0, ap->getAudioTrackHandle()->getFlags() & output_flags[i]);
70 audio_patch patch;
71 EXPECT_EQ(OK, getPatchForOutputMix(audioIo, patch));
72 if (output_flags[i] != AUDIO_OUTPUT_FLAG_FAST) {
73 // A "normal" output can still have a FastMixer, depending on the buffer size.
74 // Thus, a fast track can be created on a mix port which does not have the FAST flag.
75 for (auto j = 0; j < patch.num_sources; j++) {
76 if (patch.sources[j].type == AUDIO_PORT_TYPE_MIX &&
77 patch.sources[j].ext.mix.handle == audioIo) {
78 SCOPED_TRACE(dumpPortConfig(patch.sources[j]));
79 EXPECT_NE(0, patch.sources[j].flags.output & output_flags[i])
80 << "expected output flag "
81 << audio_output_flag_to_string(output_flags[i]) << " is absent";
82 }
83 }
84 }
85 ap->stop();
86 }
87 }
88
89 class AudioTrackTest
90 : public ::testing::TestWithParam<int> {
91
92 public:
AudioTrackTest()93 AudioTrackTest()
94 : mSampleRate(GetParam()){};
95
96 const uint32_t mSampleRate;
97
98 };
99
TEST_P(AudioTrackTest,DefaultRoutingTest)100 TEST_P(AudioTrackTest, DefaultRoutingTest) {
101 bool isAutomotive;
102 ASSERT_EQ(OK, isAutomotivePlatform(&isAutomotive));
103 if (isAutomotive) {
104 GTEST_SKIP() << "auto uses its own policy for routing";
105 }
106 audio_port_v7 port;
107 if (OK != getPortByAttributes(AUDIO_PORT_ROLE_SOURCE, AUDIO_PORT_TYPE_DEVICE,
108 AUDIO_DEVICE_IN_REMOTE_SUBMIX, "0", port)) {
109 GTEST_SKIP() << "remote submix in device not connected";
110 }
111
112 // create record instance
113 sp<AudioCapture> capture = sp<AudioCapture>::make(
114 AUDIO_SOURCE_REMOTE_SUBMIX, mSampleRate, AUDIO_FORMAT_PCM_16_BIT,
115 AUDIO_CHANNEL_IN_STEREO);
116 ASSERT_NE(nullptr, capture);
117 ASSERT_EQ(OK, capture->create()) << "record creation failed";
118 sp<OnAudioDeviceUpdateNotifier> cbCapture = sp<OnAudioDeviceUpdateNotifier>::make();
119 EXPECT_EQ(OK, capture->getAudioRecordHandle()->addAudioDeviceCallback(cbCapture));
120
121 // create playback instance
122 sp<AudioPlayback> playback = sp<AudioPlayback>::make(
123 mSampleRate, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO,
124 AUDIO_OUTPUT_FLAG_NONE, AUDIO_SESSION_NONE);
125 ASSERT_NE(nullptr, playback);
126 ASSERT_EQ(OK, playback->loadResource("/data/local/tmp/bbb_2ch_24kHz_s16le.raw"))
127 << "Unable to open Resource";
128 ASSERT_EQ(OK, playback->create()) << "track creation failed";
129 sp<OnAudioDeviceUpdateNotifier> cbPlayback = sp<OnAudioDeviceUpdateNotifier>::make();
130 EXPECT_EQ(OK, playback->getAudioTrackHandle()->addAudioDeviceCallback(cbPlayback));
131
132 // capture should be routed to submix in port
133 EXPECT_EQ(OK, capture->start()) << "start recording failed";
134 EXPECT_EQ(OK, cbCapture->waitForAudioDeviceCb());
135 DeviceIdVector routedDeviceIds = capture->getAudioRecordHandle()->getRoutedDeviceIds();
136 EXPECT_EQ(port.id, routedDeviceIds[0]) << "Capture NOT routed on expected port";
137
138 // capture start should create submix out port
139 status_t status = getPortByAttributes(AUDIO_PORT_ROLE_SINK, AUDIO_PORT_TYPE_DEVICE,
140 AUDIO_DEVICE_OUT_REMOTE_SUBMIX, "0", port);
141 EXPECT_EQ(OK, status) << "Could not find port";
142
143 // playback should be routed to submix out as long as capture is active
144 EXPECT_EQ(OK, playback->start()) << "audio track start failed";
145 EXPECT_EQ(OK, cbPlayback->waitForAudioDeviceCb());
146 routedDeviceIds = playback->getAudioTrackHandle()->getRoutedDeviceIds();
147 EXPECT_EQ(port.id, routedDeviceIds[0]) << "Playback NOT routed on expected port";
148
149 capture->stop();
150 playback->stop();
151 }
152
153 INSTANTIATE_TEST_SUITE_P(
154 AudioTrackParameterizedTest,
155 AudioTrackTest,
156 ::testing::Values(44100, 48000)
157 );
158
159 class AudioRoutingTest : public ::testing::Test {
160 public:
SetUp()161 void SetUp() override {
162 bool isAutomotive;
163 ASSERT_EQ(OK, isAutomotivePlatform(&isAutomotive));
164 if (isAutomotive) {
165 GTEST_SKIP() << "auto uses its own policy for routing";
166 }
167 audio_port_v7 port;
168 if (OK != getPortByAttributes(AUDIO_PORT_ROLE_SOURCE, AUDIO_PORT_TYPE_DEVICE,
169 AUDIO_DEVICE_IN_REMOTE_SUBMIX, "0", port)) {
170 GTEST_SKIP() << "remote submix in device not connected";
171 }
172 uint32_t mixType = MIX_TYPE_PLAYERS;
173 uint32_t mixFlag = MIX_ROUTE_FLAG_LOOP_BACK;
174 audio_devices_t deviceType = AUDIO_DEVICE_OUT_REMOTE_SUBMIX;
175 AudioMixMatchCriterion criterion(AUDIO_USAGE_MEDIA, AUDIO_SOURCE_DEFAULT,
176 RULE_MATCH_ATTRIBUTE_USAGE);
177 std::vector<AudioMixMatchCriterion> criteria{criterion};
178 audio_config_t config = AUDIO_CONFIG_INITIALIZER;
179 config.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
180 config.format = AUDIO_FORMAT_PCM_16_BIT;
181 config.sample_rate = 48000;
182 AudioMix mix(criteria, mixType, config, mixFlag, String8{mAddress.c_str()}, 0);
183 mix.mDeviceType = deviceType;
184 mix.mToken = sp<BBinder>::make();
185 mMixes.push(mix);
186 if (OK == AudioSystem::registerPolicyMixes(mMixes, true)) {
187 mPolicyMixRegistered = true;
188 }
189 ASSERT_TRUE(mPolicyMixRegistered) << "register policy mix failed";
190 }
191
TearDown()192 void TearDown() override {
193 if (mPolicyMixRegistered) {
194 EXPECT_EQ(OK, AudioSystem::registerPolicyMixes(mMixes, false));
195 }
196 }
197
198 bool mPolicyMixRegistered{false};
199 std::string mAddress{"mix_1"};
200 Vector<AudioMix> mMixes;
201 };
202
TEST_F(AudioRoutingTest,ConcurrentDynamicRoutingTest)203 TEST_F(AudioRoutingTest, ConcurrentDynamicRoutingTest) {
204 audio_port_v7 port, port_mix;
205 // expect legacy submix in port to be connected
206 status_t status = getPortByAttributes(AUDIO_PORT_ROLE_SOURCE, AUDIO_PORT_TYPE_DEVICE,
207 AUDIO_DEVICE_IN_REMOTE_SUBMIX, "0", port);
208 EXPECT_EQ(OK, status) << "Could not find port";
209
210 // as policy mix is registered, expect submix in port with mAddress to be connected
211 status = getPortByAttributes(AUDIO_PORT_ROLE_SOURCE, AUDIO_PORT_TYPE_DEVICE,
212 AUDIO_DEVICE_IN_REMOTE_SUBMIX, mAddress, port_mix);
213 EXPECT_EQ(OK, status) << "Could not find port";
214
215 // create playback instance
216 sp<AudioPlayback> playback = sp<AudioPlayback>::make(
217 48000 /* sampleRate */, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO,
218 AUDIO_OUTPUT_FLAG_NONE, AUDIO_SESSION_NONE, AudioTrack::TRANSFER_OBTAIN);
219 ASSERT_NE(nullptr, playback);
220 ASSERT_EQ(OK, playback->loadResource("/data/local/tmp/bbb_2ch_24kHz_s16le.raw"))
221 << "Unable to open Resource";
222 ASSERT_EQ(OK, playback->create()) << "track creation failed";
223 sp<OnAudioDeviceUpdateNotifier> cbPlayback = sp<OnAudioDeviceUpdateNotifier>::make();
224 EXPECT_EQ(OK, playback->getAudioTrackHandle()->addAudioDeviceCallback(cbPlayback));
225
226 // create capture instances on different ports
227 sp<AudioCapture> captureA = sp<AudioCapture>::make(
228 AUDIO_SOURCE_REMOTE_SUBMIX, 48000, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_STEREO);
229 ASSERT_NE(nullptr, captureA);
230 ASSERT_EQ(OK, captureA->create()) << "record creation failed";
231 sp<OnAudioDeviceUpdateNotifier> cbCaptureA = sp<OnAudioDeviceUpdateNotifier>::make();
232 EXPECT_EQ(OK, captureA->getAudioRecordHandle()->addAudioDeviceCallback(cbCaptureA));
233
234 audio_attributes_t attr = AUDIO_ATTRIBUTES_INITIALIZER;
235 attr.source = AUDIO_SOURCE_REMOTE_SUBMIX;
236 sprintf(attr.tags, "addr=%s", mAddress.c_str());
237 sp<AudioCapture> captureB = sp<AudioCapture>::make(
238 AUDIO_SOURCE_REMOTE_SUBMIX, 48000, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_STEREO,
239 AUDIO_INPUT_FLAG_NONE, AUDIO_SESSION_ALLOCATE, AudioRecord::TRANSFER_CALLBACK, &attr);
240 ASSERT_NE(nullptr, captureB);
241 ASSERT_EQ(OK, captureB->create()) << "record creation failed";
242 sp<OnAudioDeviceUpdateNotifier> cbCaptureB = sp<OnAudioDeviceUpdateNotifier>::make();
243 EXPECT_EQ(OK, captureB->getAudioRecordHandle()->addAudioDeviceCallback(cbCaptureB));
244
245 // launch
246 EXPECT_EQ(OK, captureA->start()) << "start recording failed";
247 EXPECT_EQ(OK, cbCaptureA->waitForAudioDeviceCb());
248 DeviceIdVector routedDeviceIds = captureA->getAudioRecordHandle()->getRoutedDeviceIds();
249 EXPECT_EQ(port.id, routedDeviceIds[0]) << "Capture NOT routed on expected port";
250
251 EXPECT_EQ(OK, captureB->start()) << "start recording failed";
252 EXPECT_EQ(OK, cbCaptureB->waitForAudioDeviceCb());
253 routedDeviceIds = captureB->getAudioRecordHandle()->getRoutedDeviceIds();
254 EXPECT_EQ(port_mix.id, routedDeviceIds[0]) << "Capture NOT routed on expected port";
255
256 // as record started, expect submix out ports to be connected
257 status = getPortByAttributes(AUDIO_PORT_ROLE_SINK, AUDIO_PORT_TYPE_DEVICE,
258 AUDIO_DEVICE_OUT_REMOTE_SUBMIX, "0", port);
259 EXPECT_EQ(OK, status) << "unexpected submix out port found";
260
261 status = getPortByAttributes(AUDIO_PORT_ROLE_SINK, AUDIO_PORT_TYPE_DEVICE,
262 AUDIO_DEVICE_OUT_REMOTE_SUBMIX, mAddress, port_mix);
263 EXPECT_EQ(OK, status) << "Could not find port";
264
265 // check if playback routed to desired port
266 EXPECT_EQ(OK, playback->start());
267 EXPECT_EQ(OK, cbPlayback->waitForAudioDeviceCb());
268 routedDeviceIds = playback->getAudioTrackHandle()->getRoutedDeviceIds();
269 EXPECT_EQ(port_mix.id, routedDeviceIds[0]) << "Playback NOT routed on expected port";
270
271 captureB->stop();
272
273 // check if mAddress submix out is disconnected as capture session is stopped
274 status = getPortByAttributes(AUDIO_PORT_ROLE_SINK, AUDIO_PORT_TYPE_DEVICE,
275 AUDIO_DEVICE_OUT_REMOTE_SUBMIX, mAddress, port_mix);
276 EXPECT_NE(OK, status) << "unexpected submix in port found";
277
278 // check if legacy submix out is connected
279 status = getPortByAttributes(AUDIO_PORT_ROLE_SINK, AUDIO_PORT_TYPE_DEVICE,
280 AUDIO_DEVICE_OUT_REMOTE_SUBMIX, "0", port);
281 EXPECT_EQ(OK, status) << "port not found";
282
283 // unregister policy
284 EXPECT_EQ(OK, AudioSystem::registerPolicyMixes(mMixes, false));
285 mPolicyMixRegistered = false;
286
287 // as policy mix is unregistered, expect submix in port with mAddress to be disconnected
288 status = getPortByAttributes(AUDIO_PORT_ROLE_SOURCE, AUDIO_PORT_TYPE_DEVICE,
289 AUDIO_DEVICE_IN_REMOTE_SUBMIX, mAddress, port_mix);
290 EXPECT_NE(OK, status) << "unexpected submix in port found";
291
292 playback->onProcess();
293 // as captureA is active, it should re route to legacy submix
294 EXPECT_EQ(OK, cbPlayback->waitForAudioDeviceCb(port.id));
295 routedDeviceIds = playback->getAudioTrackHandle()->getRoutedDeviceIds();
296 EXPECT_EQ(port.id, routedDeviceIds[0]) << "Playback NOT routed on expected port";
297
298 captureA->stop();
299 playback->stop();
300 }
301
main(int argc,char ** argv)302 int main(int argc, char** argv) {
303 android::ProcessState::self()->startThreadPool();
304 ::testing::InitGoogleTest(&argc, argv);
305 ::testing::UnitTest::GetInstance()->listeners().Append(new TestExecutionTracer());
306 return RUN_ALL_TESTS();
307 }
308