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         EXPECT_TRUE(checkPatchPlayback(cb->mAudioIo, cb->mDeviceId));
68         EXPECT_NE(0, ap->getAudioTrackHandle()->getFlags() & output_flags[i]);
69         audio_patch patch;
70         EXPECT_EQ(OK, getPatchForOutputMix(cb->mAudioIo, patch));
71         if (output_flags[i] != AUDIO_OUTPUT_FLAG_FAST) {
72             // A "normal" output can still have a FastMixer, depending on the buffer size.
73             // Thus, a fast track can be created on a mix port which does not have the FAST flag.
74             for (auto j = 0; j < patch.num_sources; j++) {
75                 if (patch.sources[j].type == AUDIO_PORT_TYPE_MIX &&
76                     patch.sources[j].ext.mix.handle == cb->mAudioIo) {
77                     SCOPED_TRACE(dumpPortConfig(patch.sources[j]));
78                     EXPECT_NE(0, patch.sources[j].flags.output & output_flags[i])
79                             << "expected output flag "
80                             << audio_output_flag_to_string(output_flags[i]) << " is absent";
81                 }
82             }
83         }
84         ap->stop();
85     }
86 }
87 
TEST(AudioTrackTest,DefaultRoutingTest)88 TEST(AudioTrackTest, DefaultRoutingTest) {
89     audio_port_v7 port;
90     if (OK != getPortByAttributes(AUDIO_PORT_ROLE_SOURCE, AUDIO_PORT_TYPE_DEVICE,
91                                   AUDIO_DEVICE_IN_REMOTE_SUBMIX, "0", port)) {
92         GTEST_SKIP() << "remote submix in device not connected";
93     }
94 
95     // create record instance
96     sp<AudioCapture> capture = sp<AudioCapture>::make(
97             AUDIO_SOURCE_REMOTE_SUBMIX, 48000, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_STEREO);
98     ASSERT_NE(nullptr, capture);
99     ASSERT_EQ(OK, capture->create()) << "record creation failed";
100     sp<OnAudioDeviceUpdateNotifier> cbCapture = sp<OnAudioDeviceUpdateNotifier>::make();
101     EXPECT_EQ(OK, capture->getAudioRecordHandle()->addAudioDeviceCallback(cbCapture));
102 
103     // create playback instance
104     sp<AudioPlayback> playback = sp<AudioPlayback>::make(
105             48000 /* sampleRate */, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO,
106             AUDIO_OUTPUT_FLAG_NONE, AUDIO_SESSION_NONE);
107     ASSERT_NE(nullptr, playback);
108     ASSERT_EQ(OK, playback->loadResource("/data/local/tmp/bbb_2ch_24kHz_s16le.raw"))
109             << "Unable to open Resource";
110     ASSERT_EQ(OK, playback->create()) << "track creation failed";
111     sp<OnAudioDeviceUpdateNotifier> cbPlayback = sp<OnAudioDeviceUpdateNotifier>::make();
112     EXPECT_EQ(OK, playback->getAudioTrackHandle()->addAudioDeviceCallback(cbPlayback));
113 
114     // capture should be routed to submix in port
115     EXPECT_EQ(OK, capture->start()) << "start recording failed";
116     EXPECT_EQ(OK, cbCapture->waitForAudioDeviceCb());
117     EXPECT_EQ(port.id, capture->getAudioRecordHandle()->getRoutedDeviceId())
118             << "Capture NOT routed on expected port";
119 
120     // capture start should create submix out port
121     status_t status = getPortByAttributes(AUDIO_PORT_ROLE_SINK, AUDIO_PORT_TYPE_DEVICE,
122                                           AUDIO_DEVICE_OUT_REMOTE_SUBMIX, "0", port);
123     EXPECT_EQ(OK, status) << "Could not find port";
124 
125     // playback should be routed to submix out as long as capture is active
126     EXPECT_EQ(OK, playback->start()) << "audio track start failed";
127     EXPECT_EQ(OK, cbPlayback->waitForAudioDeviceCb());
128     EXPECT_EQ(port.id, playback->getAudioTrackHandle()->getRoutedDeviceId())
129             << "Playback NOT routed on expected port";
130 
131     capture->stop();
132     playback->stop();
133 }
134 
135 class AudioRoutingTest : public ::testing::Test {
136   public:
SetUp()137     void SetUp() override {
138         audio_port_v7 port;
139         if (OK != getPortByAttributes(AUDIO_PORT_ROLE_SOURCE, AUDIO_PORT_TYPE_DEVICE,
140                                       AUDIO_DEVICE_IN_REMOTE_SUBMIX, "0", port)) {
141             GTEST_SKIP() << "remote submix in device not connected";
142         }
143         uint32_t mixType = MIX_TYPE_PLAYERS;
144         uint32_t mixFlag = MIX_ROUTE_FLAG_LOOP_BACK;
145         audio_devices_t deviceType = AUDIO_DEVICE_OUT_REMOTE_SUBMIX;
146         AudioMixMatchCriterion criterion(AUDIO_USAGE_MEDIA, AUDIO_SOURCE_DEFAULT,
147                                          RULE_MATCH_ATTRIBUTE_USAGE);
148         std::vector<AudioMixMatchCriterion> criteria{criterion};
149         audio_config_t config = AUDIO_CONFIG_INITIALIZER;
150         config.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
151         config.format = AUDIO_FORMAT_PCM_16_BIT;
152         config.sample_rate = 48000;
153         AudioMix mix(criteria, mixType, config, mixFlag, String8{mAddress.c_str()}, 0);
154         mix.mDeviceType = deviceType;
155         mix.mToken = sp<BBinder>::make();
156         mMixes.push(mix);
157         if (OK == AudioSystem::registerPolicyMixes(mMixes, true)) {
158             mPolicyMixRegistered = true;
159         }
160         ASSERT_TRUE(mPolicyMixRegistered) << "register policy mix failed";
161     }
162 
TearDown()163     void TearDown() override {
164         if (mPolicyMixRegistered) {
165             EXPECT_EQ(OK, AudioSystem::registerPolicyMixes(mMixes, false));
166         }
167     }
168 
169     bool mPolicyMixRegistered{false};
170     std::string mAddress{"mix_1"};
171     Vector<AudioMix> mMixes;
172 };
173 
TEST_F(AudioRoutingTest,ConcurrentDynamicRoutingTest)174 TEST_F(AudioRoutingTest, ConcurrentDynamicRoutingTest) {
175     audio_port_v7 port, port_mix;
176     // expect legacy submix in port to be connected
177     status_t status = getPortByAttributes(AUDIO_PORT_ROLE_SOURCE, AUDIO_PORT_TYPE_DEVICE,
178                                           AUDIO_DEVICE_IN_REMOTE_SUBMIX, "0", port);
179     EXPECT_EQ(OK, status) << "Could not find port";
180 
181     // as policy mix is registered, expect submix in port with mAddress to be connected
182     status = getPortByAttributes(AUDIO_PORT_ROLE_SOURCE, AUDIO_PORT_TYPE_DEVICE,
183                                  AUDIO_DEVICE_IN_REMOTE_SUBMIX, mAddress, port_mix);
184     EXPECT_EQ(OK, status) << "Could not find port";
185 
186     // create playback instance
187     sp<AudioPlayback> playback = sp<AudioPlayback>::make(
188             48000 /* sampleRate */, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO,
189             AUDIO_OUTPUT_FLAG_NONE, AUDIO_SESSION_NONE, AudioTrack::TRANSFER_OBTAIN);
190     ASSERT_NE(nullptr, playback);
191     ASSERT_EQ(OK, playback->loadResource("/data/local/tmp/bbb_2ch_24kHz_s16le.raw"))
192             << "Unable to open Resource";
193     ASSERT_EQ(OK, playback->create()) << "track creation failed";
194     sp<OnAudioDeviceUpdateNotifier> cbPlayback = sp<OnAudioDeviceUpdateNotifier>::make();
195     EXPECT_EQ(OK, playback->getAudioTrackHandle()->addAudioDeviceCallback(cbPlayback));
196 
197     // create capture instances on different ports
198     sp<AudioCapture> captureA = sp<AudioCapture>::make(
199             AUDIO_SOURCE_REMOTE_SUBMIX, 48000, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_STEREO);
200     ASSERT_NE(nullptr, captureA);
201     ASSERT_EQ(OK, captureA->create()) << "record creation failed";
202     sp<OnAudioDeviceUpdateNotifier> cbCaptureA = sp<OnAudioDeviceUpdateNotifier>::make();
203     EXPECT_EQ(OK, captureA->getAudioRecordHandle()->addAudioDeviceCallback(cbCaptureA));
204 
205     audio_attributes_t attr = AUDIO_ATTRIBUTES_INITIALIZER;
206     attr.source = AUDIO_SOURCE_REMOTE_SUBMIX;
207     sprintf(attr.tags, "addr=%s", mAddress.c_str());
208     sp<AudioCapture> captureB = sp<AudioCapture>::make(
209             AUDIO_SOURCE_REMOTE_SUBMIX, 48000, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_STEREO,
210             AUDIO_INPUT_FLAG_NONE, AUDIO_SESSION_ALLOCATE, AudioRecord::TRANSFER_CALLBACK, &attr);
211     ASSERT_NE(nullptr, captureB);
212     ASSERT_EQ(OK, captureB->create()) << "record creation failed";
213     sp<OnAudioDeviceUpdateNotifier> cbCaptureB = sp<OnAudioDeviceUpdateNotifier>::make();
214     EXPECT_EQ(OK, captureB->getAudioRecordHandle()->addAudioDeviceCallback(cbCaptureB));
215 
216     // launch
217     EXPECT_EQ(OK, captureA->start()) << "start recording failed";
218     EXPECT_EQ(OK, cbCaptureA->waitForAudioDeviceCb());
219     EXPECT_EQ(port.id, captureA->getAudioRecordHandle()->getRoutedDeviceId())
220             << "Capture NOT routed on expected port";
221 
222     EXPECT_EQ(OK, captureB->start()) << "start recording failed";
223     EXPECT_EQ(OK, cbCaptureB->waitForAudioDeviceCb());
224     EXPECT_EQ(port_mix.id, captureB->getAudioRecordHandle()->getRoutedDeviceId())
225             << "Capture NOT routed on expected port";
226 
227     // as record started, expect submix out ports to be connected
228     status = getPortByAttributes(AUDIO_PORT_ROLE_SINK, AUDIO_PORT_TYPE_DEVICE,
229                                  AUDIO_DEVICE_OUT_REMOTE_SUBMIX, "0", port);
230     EXPECT_EQ(OK, status) << "unexpected submix out port found";
231 
232     status = getPortByAttributes(AUDIO_PORT_ROLE_SINK, AUDIO_PORT_TYPE_DEVICE,
233                                  AUDIO_DEVICE_OUT_REMOTE_SUBMIX, mAddress, port_mix);
234     EXPECT_EQ(OK, status) << "Could not find port";
235 
236     // check if playback routed to desired port
237     EXPECT_EQ(OK, playback->start());
238     EXPECT_EQ(OK, cbPlayback->waitForAudioDeviceCb());
239     EXPECT_EQ(port_mix.id, playback->getAudioTrackHandle()->getRoutedDeviceId())
240             << "Playback NOT routed on expected port";
241 
242     captureB->stop();
243 
244     // check if mAddress submix out is disconnected as capture session is stopped
245     status = getPortByAttributes(AUDIO_PORT_ROLE_SINK, AUDIO_PORT_TYPE_DEVICE,
246                                  AUDIO_DEVICE_OUT_REMOTE_SUBMIX, mAddress, port_mix);
247     EXPECT_NE(OK, status) << "unexpected submix in port found";
248 
249     // check if legacy submix out is connected
250     status = getPortByAttributes(AUDIO_PORT_ROLE_SINK, AUDIO_PORT_TYPE_DEVICE,
251                                  AUDIO_DEVICE_OUT_REMOTE_SUBMIX, "0", port);
252     EXPECT_EQ(OK, status) << "port not found";
253 
254     // unregister policy
255     EXPECT_EQ(OK, AudioSystem::registerPolicyMixes(mMixes, false));
256     mPolicyMixRegistered = false;
257 
258     // as policy mix is unregistered, expect submix in port with mAddress to be disconnected
259     status = getPortByAttributes(AUDIO_PORT_ROLE_SOURCE, AUDIO_PORT_TYPE_DEVICE,
260                                  AUDIO_DEVICE_IN_REMOTE_SUBMIX, mAddress, port_mix);
261     EXPECT_NE(OK, status) << "unexpected submix in port found";
262 
263     playback->onProcess();
264     // as captureA is active, it should re route to legacy submix
265     EXPECT_EQ(OK, cbPlayback->waitForAudioDeviceCb(port.id));
266     EXPECT_EQ(port.id, playback->getAudioTrackHandle()->getRoutedDeviceId())
267             << "Playback NOT routed on expected port";
268 
269     captureA->stop();
270     playback->stop();
271 }
272 
main(int argc,char ** argv)273 int main(int argc, char** argv) {
274     android::ProcessState::self()->startThreadPool();
275     ::testing::InitGoogleTest(&argc, argv);
276     ::testing::UnitTest::GetInstance()->listeners().Append(new TestExecutionTracer());
277     return RUN_ALL_TESTS();
278 }
279