blob: 24326bb75b2c837eee4e0d630acb84ff3401ff1a [file] [log] [blame]
Mikhail Naganovad3f8a12017-12-12 13:24:23 -08001/*
2 * Copyright (C) 2017 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
Mikhail Naganov04a86632017-12-15 18:01:42 -080017#include <memory>
18#include <set>
Mikhail Naganov21b43362018-06-04 10:37:09 -070019#include <sys/wait.h>
20#include <unistd.h>
Mikhail Naganov04a86632017-12-15 18:01:42 -080021
Mikhail Naganovad3f8a12017-12-12 13:24:23 -080022#include <gtest/gtest.h>
23
Mikhail Naganov21b43362018-06-04 10:37:09 -070024#define LOG_TAG "APM_Test"
25#include <log/log.h>
Mikhail Naganovdc769682018-05-04 15:34:08 -070026#include <media/PatchBuilder.h>
27
Mikhail Naganovad3f8a12017-12-12 13:24:23 -080028#include "AudioPolicyTestClient.h"
29#include "AudioPolicyTestManager.h"
30
31using namespace android;
32
Mikhail Naganov04a86632017-12-15 18:01:42 -080033TEST(AudioPolicyManagerTestInit, Failure) {
Mikhail Naganovad3f8a12017-12-12 13:24:23 -080034 AudioPolicyTestClient client;
35 AudioPolicyTestManager manager(&client);
36 manager.getConfig().setDefault();
Mikhail Naganovbcbcb1b2017-12-13 13:03:35 -080037 // Since the default client fails to open anything,
38 // APM should indicate that the initialization didn't succeed.
Mikhail Naganovad3f8a12017-12-12 13:24:23 -080039 ASSERT_EQ(NO_INIT, manager.initialize());
Mikhail Naganovbcbcb1b2017-12-13 13:03:35 -080040 ASSERT_EQ(NO_INIT, manager.initCheck());
41}
42
43
Mikhail Naganov04a86632017-12-15 18:01:42 -080044class AudioPolicyManagerTestClient : public AudioPolicyTestClient {
Mikhail Naganovbcbcb1b2017-12-13 13:03:35 -080045 public:
Mikhail Naganov04a86632017-12-15 18:01:42 -080046 // AudioPolicyClientInterface implementation
Mikhail Naganovbcbcb1b2017-12-13 13:03:35 -080047 audio_module_handle_t loadHwModule(const char* /*name*/) override {
Mikhail Naganov04a86632017-12-15 18:01:42 -080048 return mNextModuleHandle++;
Mikhail Naganovbcbcb1b2017-12-13 13:03:35 -080049 }
Mikhail Naganov04a86632017-12-15 18:01:42 -080050
Mikhail Naganovbcbcb1b2017-12-13 13:03:35 -080051 status_t openOutput(audio_module_handle_t module,
52 audio_io_handle_t* output,
53 audio_config_t* /*config*/,
54 audio_devices_t* /*devices*/,
55 const String8& /*address*/,
56 uint32_t* /*latencyMs*/,
57 audio_output_flags_t /*flags*/) override {
Mikhail Naganov04a86632017-12-15 18:01:42 -080058 if (module >= mNextModuleHandle) {
Mikhail Naganovbcbcb1b2017-12-13 13:03:35 -080059 ALOGE("%s: Module handle %d has not been allocated yet (next is %d)",
Mikhail Naganov04a86632017-12-15 18:01:42 -080060 __func__, module, mNextModuleHandle);
Mikhail Naganovbcbcb1b2017-12-13 13:03:35 -080061 return BAD_VALUE;
62 }
63 *output = mNextIoHandle++;
64 return NO_ERROR;
65 }
Mikhail Naganov04a86632017-12-15 18:01:42 -080066
Mikhail Naganovbcbcb1b2017-12-13 13:03:35 -080067 status_t openInput(audio_module_handle_t module,
68 audio_io_handle_t* input,
69 audio_config_t* /*config*/,
70 audio_devices_t* /*device*/,
71 const String8& /*address*/,
72 audio_source_t /*source*/,
73 audio_input_flags_t /*flags*/) override {
Mikhail Naganov04a86632017-12-15 18:01:42 -080074 if (module >= mNextModuleHandle) {
Mikhail Naganovbcbcb1b2017-12-13 13:03:35 -080075 ALOGE("%s: Module handle %d has not been allocated yet (next is %d)",
Mikhail Naganov04a86632017-12-15 18:01:42 -080076 __func__, module, mNextModuleHandle);
Mikhail Naganovbcbcb1b2017-12-13 13:03:35 -080077 return BAD_VALUE;
78 }
79 *input = mNextIoHandle++;
80 return NO_ERROR;
81 }
Mikhail Naganov04a86632017-12-15 18:01:42 -080082
83 status_t createAudioPatch(const struct audio_patch* /*patch*/,
84 audio_patch_handle_t* handle,
85 int /*delayMs*/) override {
86 *handle = mNextPatchHandle++;
87 mActivePatches.insert(*handle);
88 return NO_ERROR;
89 }
90
91 status_t releaseAudioPatch(audio_patch_handle_t handle,
92 int /*delayMs*/) override {
93 if (mActivePatches.erase(handle) != 1) {
94 if (handle >= mNextPatchHandle) {
95 ALOGE("%s: Patch handle %d has not been allocated yet (next is %d)",
96 __func__, handle, mNextPatchHandle);
97 } else {
98 ALOGE("%s: Attempt to release patch %d twice", __func__, handle);
99 }
100 return BAD_VALUE;
101 }
102 return NO_ERROR;
103 }
104
105 // Helper methods for tests
106 size_t getActivePatchesCount() const { return mActivePatches.size(); }
107
Mikhail Naganovbcbcb1b2017-12-13 13:03:35 -0800108 private:
Mikhail Naganov04a86632017-12-15 18:01:42 -0800109 audio_module_handle_t mNextModuleHandle = AUDIO_MODULE_HANDLE_NONE + 1;
Mikhail Naganovbcbcb1b2017-12-13 13:03:35 -0800110 audio_io_handle_t mNextIoHandle = AUDIO_IO_HANDLE_NONE + 1;
Mikhail Naganov04a86632017-12-15 18:01:42 -0800111 audio_patch_handle_t mNextPatchHandle = AUDIO_PATCH_HANDLE_NONE + 1;
112 std::set<audio_patch_handle_t> mActivePatches;
Mikhail Naganovbcbcb1b2017-12-13 13:03:35 -0800113};
114
Mikhail Naganovdf2e3592018-12-19 14:27:42 -0800115class PatchCountCheck {
116 public:
117 explicit PatchCountCheck(AudioPolicyManagerTestClient *client)
118 : mClient{client},
119 mInitialCount{mClient->getActivePatchesCount()} {}
120 void assertDelta(int delta) const {
121 ASSERT_EQ(mInitialCount + delta, mClient->getActivePatchesCount()); }
122 void assertNoChange() const { assertDelta(0); }
123 private:
124 const AudioPolicyManagerTestClient *mClient;
125 const size_t mInitialCount;
126};
127
Mikhail Naganov04a86632017-12-15 18:01:42 -0800128class AudioPolicyManagerTest : public testing::Test {
129 protected:
Mikhail Naganovdf2e3592018-12-19 14:27:42 -0800130 void SetUp() override;
131 void TearDown() override;
132 virtual void SetUpConfig(AudioPolicyConfig *config) { (void)config; }
133
134 void dumpToLog();
135 void getOutputForAttr(
136 audio_port_handle_t *selectedDeviceId,
137 audio_format_t format,
138 int channelMask,
139 int sampleRate,
140 audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE,
141 audio_port_handle_t *portId = nullptr);
142 PatchCountCheck snapPatchCount() { return PatchCountCheck(mClient.get()); }
Mikhail Naganov04a86632017-12-15 18:01:42 -0800143
144 std::unique_ptr<AudioPolicyManagerTestClient> mClient;
145 std::unique_ptr<AudioPolicyTestManager> mManager;
146};
147
148void AudioPolicyManagerTest::SetUp() {
149 mClient.reset(new AudioPolicyManagerTestClient);
150 mManager.reset(new AudioPolicyTestManager(mClient.get()));
151 mManager->getConfig().setDefault();
Mikhail Naganovdf2e3592018-12-19 14:27:42 -0800152 SetUpConfig(&mManager->getConfig()); // Subclasses may want to customize the config.
Mikhail Naganov04a86632017-12-15 18:01:42 -0800153 ASSERT_EQ(NO_ERROR, mManager->initialize());
154 ASSERT_EQ(NO_ERROR, mManager->initCheck());
Mikhail Naganovad3f8a12017-12-12 13:24:23 -0800155}
Mikhail Naganov04a86632017-12-15 18:01:42 -0800156
157void AudioPolicyManagerTest::TearDown() {
158 mManager.reset();
159 mClient.reset();
160}
161
Mikhail Naganovdf2e3592018-12-19 14:27:42 -0800162void AudioPolicyManagerTest::dumpToLog() {
Mikhail Naganov21b43362018-06-04 10:37:09 -0700163 int pipefd[2];
164 ASSERT_NE(-1, pipe(pipefd));
165 pid_t cpid = fork();
166 ASSERT_NE(-1, cpid);
167 if (cpid == 0) {
168 // Child process reads from the pipe and logs.
169 close(pipefd[1]);
170 std::string line;
171 char buf;
172 while (read(pipefd[0], &buf, sizeof(buf)) > 0) {
173 if (buf != '\n') {
174 line += buf;
175 } else {
176 ALOGI("%s", line.c_str());
177 line = "";
178 }
179 }
180 if (!line.empty()) ALOGI("%s", line.c_str());
181 close(pipefd[0]);
182 _exit(EXIT_SUCCESS);
183 } else {
184 // Parent does the dump and checks the status code.
185 close(pipefd[0]);
186 ASSERT_EQ(NO_ERROR, mManager->dump(pipefd[1]));
187 close(pipefd[1]);
188 wait(NULL); // Wait for the child to exit.
189 }
190}
191
Mikhail Naganovdf2e3592018-12-19 14:27:42 -0800192void AudioPolicyManagerTest::getOutputForAttr(
193 audio_port_handle_t *selectedDeviceId,
194 audio_format_t format,
195 int channelMask,
196 int sampleRate,
197 audio_output_flags_t flags,
198 audio_port_handle_t *portId) {
199 audio_attributes_t attr = {};
200 audio_io_handle_t output = AUDIO_PORT_HANDLE_NONE;
201 audio_stream_type_t stream = AUDIO_STREAM_DEFAULT;
202 audio_config_t config = AUDIO_CONFIG_INITIALIZER;
203 config.sample_rate = sampleRate;
204 config.channel_mask = channelMask;
205 config.format = format;
206 *selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
207 audio_port_handle_t localPortId;
208 if (!portId) portId = &localPortId;
209 *portId = AUDIO_PORT_HANDLE_NONE;
210 ASSERT_EQ(OK, mManager->getOutputForAttr(
211 &attr, &output, AUDIO_SESSION_NONE, &stream, 0 /*uid*/, &config, &flags,
212 selectedDeviceId, portId));
213 ASSERT_NE(AUDIO_PORT_HANDLE_NONE, *portId);
214}
215
216
217TEST_F(AudioPolicyManagerTest, InitSuccess) {
218 // SetUp must finish with no assertions.
219}
220
221TEST_F(AudioPolicyManagerTest, Dump) {
222 dumpToLog();
223}
224
Mikhail Naganov04a86632017-12-15 18:01:42 -0800225TEST_F(AudioPolicyManagerTest, CreateAudioPatchFailure) {
226 audio_patch patch{};
227 audio_patch_handle_t handle = AUDIO_PATCH_HANDLE_NONE;
Mikhail Naganovdf2e3592018-12-19 14:27:42 -0800228 const PatchCountCheck patchCount = snapPatchCount();
Mikhail Naganov04a86632017-12-15 18:01:42 -0800229 ASSERT_EQ(BAD_VALUE, mManager->createAudioPatch(nullptr, &handle, 0));
230 ASSERT_EQ(BAD_VALUE, mManager->createAudioPatch(&patch, nullptr, 0));
231 ASSERT_EQ(BAD_VALUE, mManager->createAudioPatch(&patch, &handle, 0));
232 patch.num_sources = AUDIO_PATCH_PORTS_MAX + 1;
233 patch.num_sinks = 1;
234 ASSERT_EQ(BAD_VALUE, mManager->createAudioPatch(&patch, &handle, 0));
235 patch.num_sources = 1;
236 patch.num_sinks = AUDIO_PATCH_PORTS_MAX + 1;
237 ASSERT_EQ(BAD_VALUE, mManager->createAudioPatch(&patch, &handle, 0));
238 patch.num_sources = 2;
239 patch.num_sinks = 1;
240 ASSERT_EQ(INVALID_OPERATION, mManager->createAudioPatch(&patch, &handle, 0));
241 patch = {};
242 patch.num_sources = 1;
243 patch.sources[0].role = AUDIO_PORT_ROLE_SINK;
244 patch.num_sinks = 1;
245 patch.sinks[0].role = AUDIO_PORT_ROLE_SINK;
246 ASSERT_EQ(INVALID_OPERATION, mManager->createAudioPatch(&patch, &handle, 0));
247 patch = {};
248 patch.num_sources = 1;
249 patch.sources[0].role = AUDIO_PORT_ROLE_SOURCE;
250 patch.num_sinks = 1;
251 patch.sinks[0].role = AUDIO_PORT_ROLE_SOURCE;
252 ASSERT_EQ(INVALID_OPERATION, mManager->createAudioPatch(&patch, &handle, 0));
253 // Verify that the handle is left unchanged.
254 ASSERT_EQ(AUDIO_PATCH_HANDLE_NONE, handle);
Mikhail Naganovdf2e3592018-12-19 14:27:42 -0800255 patchCount.assertNoChange();
Mikhail Naganov04a86632017-12-15 18:01:42 -0800256}
257
258TEST_F(AudioPolicyManagerTest, CreateAudioPatchFromMix) {
Mikhail Naganov04a86632017-12-15 18:01:42 -0800259 audio_patch_handle_t handle = AUDIO_PATCH_HANDLE_NONE;
260 uid_t uid = 42;
Mikhail Naganovdf2e3592018-12-19 14:27:42 -0800261 const PatchCountCheck patchCount = snapPatchCount();
Mikhail Naganovdc769682018-05-04 15:34:08 -0700262 ASSERT_FALSE(mManager->getConfig().getAvailableInputDevices().isEmpty());
263 PatchBuilder patchBuilder;
264 patchBuilder.addSource(mManager->getConfig().getAvailableInputDevices()[0]).
265 addSink(mManager->getConfig().getDefaultOutputDevice());
266 ASSERT_EQ(NO_ERROR, mManager->createAudioPatch(patchBuilder.patch(), &handle, uid));
Mikhail Naganov04a86632017-12-15 18:01:42 -0800267 ASSERT_NE(AUDIO_PATCH_HANDLE_NONE, handle);
Mikhail Naganovdf2e3592018-12-19 14:27:42 -0800268 patchCount.assertDelta(1);
Mikhail Naganov04a86632017-12-15 18:01:42 -0800269}
270
271// TODO: Add patch creation tests that involve already existing patch
Mikhail Naganovdf2e3592018-12-19 14:27:42 -0800272
273class AudioPolicyManagerTestMsd : public AudioPolicyManagerTest {
274 protected:
275 void SetUpConfig(AudioPolicyConfig *config) override;
276 void TearDown() override;
277
278 sp<DeviceDescriptor> mMsdOutputDevice;
279 sp<DeviceDescriptor> mMsdInputDevice;
280};
281
282void AudioPolicyManagerTestMsd::SetUpConfig(AudioPolicyConfig *config) {
283 // TODO: Consider using Serializer to load part of the config from a string.
284 mMsdOutputDevice = new DeviceDescriptor(AUDIO_DEVICE_OUT_BUS);
285 sp<AudioProfile> pcmOutputProfile = new AudioProfile(
286 AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO, 48000);
287 sp<AudioProfile> ac3OutputProfile = new AudioProfile(
288 AUDIO_FORMAT_AC3, AUDIO_CHANNEL_OUT_5POINT1, 48000);
289 mMsdOutputDevice->addAudioProfile(pcmOutputProfile);
290 mMsdOutputDevice->addAudioProfile(ac3OutputProfile);
291 mMsdInputDevice = new DeviceDescriptor(AUDIO_DEVICE_IN_BUS);
292 // Match output profile from AudioPolicyConfig::setDefault.
293 sp<AudioProfile> pcmInputProfile = new AudioProfile(
294 AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_STEREO, 44100);
295 mMsdInputDevice->addAudioProfile(pcmInputProfile);
296 config->addAvailableDevice(mMsdOutputDevice);
297 config->addAvailableDevice(mMsdInputDevice);
298
299 sp<HwModule> msdModule = new HwModule(AUDIO_HARDWARE_MODULE_ID_MSD, 2 /*halVersionMajor*/);
300 HwModuleCollection modules = config->getHwModules();
301 modules.add(msdModule);
302 config->setHwModules(modules);
303 mMsdOutputDevice->attach(msdModule);
304 mMsdInputDevice->attach(msdModule);
305
306 sp<OutputProfile> msdOutputProfile = new OutputProfile(String8("msd input"));
307 msdOutputProfile->addAudioProfile(pcmOutputProfile);
308 msdOutputProfile->addSupportedDevice(mMsdOutputDevice);
309 msdModule->addOutputProfile(msdOutputProfile);
310 sp<OutputProfile> msdCompressedOutputProfile =
311 new OutputProfile(String8("msd compressed input"));
312 msdCompressedOutputProfile->addAudioProfile(ac3OutputProfile);
313 msdCompressedOutputProfile->setFlags(
314 AUDIO_OUTPUT_FLAG_DIRECT | AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD |
315 AUDIO_OUTPUT_FLAG_NON_BLOCKING);
316 msdCompressedOutputProfile->addSupportedDevice(mMsdOutputDevice);
317 msdModule->addOutputProfile(msdCompressedOutputProfile);
318
319 sp<InputProfile> msdInputProfile = new InputProfile(String8("msd output"));
320 msdInputProfile->addAudioProfile(pcmInputProfile);
321 msdInputProfile->addSupportedDevice(mMsdInputDevice);
322 msdModule->addInputProfile(msdInputProfile);
323
324 // Add a profile with another encoding to the default device to test routing
325 // of streams that are not supported by MSD.
326 sp<AudioProfile> dtsOutputProfile = new AudioProfile(
327 AUDIO_FORMAT_DTS, AUDIO_CHANNEL_OUT_5POINT1, 48000);
328 config->getDefaultOutputDevice()->addAudioProfile(dtsOutputProfile);
329 sp<OutputProfile> primaryEncodedOutputProfile = new OutputProfile(String8("encoded"));
330 primaryEncodedOutputProfile->addAudioProfile(dtsOutputProfile);
331 primaryEncodedOutputProfile->setFlags(AUDIO_OUTPUT_FLAG_DIRECT);
332 primaryEncodedOutputProfile->addSupportedDevice(config->getDefaultOutputDevice());
333 config->getHwModules().getModuleFromName(AUDIO_HARDWARE_MODULE_ID_PRIMARY)->
334 addOutputProfile(primaryEncodedOutputProfile);
335}
336
337void AudioPolicyManagerTestMsd::TearDown() {
338 mMsdOutputDevice.clear();
339 mMsdInputDevice.clear();
340 AudioPolicyManagerTest::TearDown();
341}
342
343TEST_F(AudioPolicyManagerTestMsd, InitSuccess) {
344 ASSERT_TRUE(mMsdOutputDevice);
345 ASSERT_TRUE(mMsdInputDevice);
346}
347
348TEST_F(AudioPolicyManagerTestMsd, Dump) {
349 dumpToLog();
350}
351
352TEST_F(AudioPolicyManagerTestMsd, PatchCreationOnSetForceUse) {
353 const PatchCountCheck patchCount = snapPatchCount();
354 mManager->setForceUse(AUDIO_POLICY_FORCE_FOR_ENCODED_SURROUND,
355 AUDIO_POLICY_FORCE_ENCODED_SURROUND_ALWAYS);
356 patchCount.assertDelta(1);
357}
358
359TEST_F(AudioPolicyManagerTestMsd, GetOutputForAttrEncodedRoutesToMsd) {
360 const PatchCountCheck patchCount = snapPatchCount();
361 audio_port_handle_t selectedDeviceId;
362 getOutputForAttr(&selectedDeviceId,
363 AUDIO_FORMAT_AC3, AUDIO_CHANNEL_OUT_5POINT1, 48000, AUDIO_OUTPUT_FLAG_DIRECT);
364 ASSERT_EQ(selectedDeviceId, mMsdOutputDevice->getId());
365 patchCount.assertDelta(1);
366}
367
368TEST_F(AudioPolicyManagerTestMsd, GetOutputForAttrPcmRoutesToMsd) {
369 const PatchCountCheck patchCount = snapPatchCount();
370 audio_port_handle_t selectedDeviceId;
371 getOutputForAttr(&selectedDeviceId,
372 AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO, 48000);
373 ASSERT_EQ(selectedDeviceId, mMsdOutputDevice->getId());
374 patchCount.assertDelta(1);
375}
376
377TEST_F(AudioPolicyManagerTestMsd, GetOutputForAttrEncodedPlusPcmRoutesToMsd) {
378 const PatchCountCheck patchCount = snapPatchCount();
379 audio_port_handle_t selectedDeviceId;
380 getOutputForAttr(&selectedDeviceId,
381 AUDIO_FORMAT_AC3, AUDIO_CHANNEL_OUT_5POINT1, 48000, AUDIO_OUTPUT_FLAG_DIRECT);
382 ASSERT_EQ(selectedDeviceId, mMsdOutputDevice->getId());
383 patchCount.assertDelta(1);
384 getOutputForAttr(&selectedDeviceId,
385 AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO, 48000);
386 ASSERT_EQ(selectedDeviceId, mMsdOutputDevice->getId());
387 patchCount.assertDelta(1);
388}
389
390TEST_F(AudioPolicyManagerTestMsd, GetOutputForAttrUnsupportedFormatBypassesMsd) {
391 const PatchCountCheck patchCount = snapPatchCount();
392 audio_port_handle_t selectedDeviceId;
393 getOutputForAttr(&selectedDeviceId,
394 AUDIO_FORMAT_DTS, AUDIO_CHANNEL_OUT_5POINT1, 48000, AUDIO_OUTPUT_FLAG_DIRECT);
395 ASSERT_NE(selectedDeviceId, mMsdOutputDevice->getId());
396 patchCount.assertNoChange();
397}
398
399TEST_F(AudioPolicyManagerTestMsd, GetOutputForAttrFormatSwitching) {
400 // Switch between formats that are supported and not supported by MSD.
401 {
402 const PatchCountCheck patchCount = snapPatchCount();
403 audio_port_handle_t selectedDeviceId, portId;
404 getOutputForAttr(&selectedDeviceId,
405 AUDIO_FORMAT_AC3, AUDIO_CHANNEL_OUT_5POINT1, 48000, AUDIO_OUTPUT_FLAG_DIRECT,
406 &portId);
407 ASSERT_EQ(selectedDeviceId, mMsdOutputDevice->getId());
408 patchCount.assertDelta(1);
409 mManager->releaseOutput(portId);
410 patchCount.assertDelta(1); // compared to the state at the block entry
411 // TODO: make PatchCountCheck asserts more obvious. It's easy to
412 // miss the fact that it is immutable.
413 }
414 {
415 const PatchCountCheck patchCount = snapPatchCount();
416 audio_port_handle_t selectedDeviceId, portId;
417 getOutputForAttr(&selectedDeviceId,
418 AUDIO_FORMAT_DTS, AUDIO_CHANNEL_OUT_5POINT1, 48000, AUDIO_OUTPUT_FLAG_DIRECT,
419 &portId);
420 ASSERT_NE(selectedDeviceId, mMsdOutputDevice->getId());
421 patchCount.assertDelta(-1);
422 mManager->releaseOutput(portId);
423 patchCount.assertNoChange();
424 }
425 {
426 const PatchCountCheck patchCount = snapPatchCount();
427 audio_port_handle_t selectedDeviceId;
428 getOutputForAttr(&selectedDeviceId,
429 AUDIO_FORMAT_AC3, AUDIO_CHANNEL_OUT_5POINT1, 48000, AUDIO_OUTPUT_FLAG_DIRECT);
430 ASSERT_EQ(selectedDeviceId, mMsdOutputDevice->getId());
431 patchCount.assertNoChange();
432 }
433}