1 /*
2 * Copyright (C) 2022 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 #include <algorithm>
18 #include <chrono>
19 #include <cmath>
20 #include <condition_variable>
21 #include <forward_list>
22 #include <limits>
23 #include <memory>
24 #include <mutex>
25 #include <optional>
26 #include <set>
27 #include <string>
28 #include <string_view>
29 #include <variant>
30 #include <vector>
31
32 #define LOG_TAG "VtsHalAudioCore.Module"
33 #include <android-base/logging.h>
34
35 #include <StreamWorker.h>
36 #include <Utils.h>
37 #include <aidl/Gtest.h>
38 #include <aidl/Vintf.h>
39 #include <aidl/android/hardware/audio/core/BnStreamCallback.h>
40 #include <aidl/android/hardware/audio/core/IModule.h>
41 #include <aidl/android/hardware/audio/core/ITelephony.h>
42 #include <aidl/android/hardware/audio/core/sounddose/ISoundDose.h>
43 #include <aidl/android/media/audio/common/AudioIoFlags.h>
44 #include <aidl/android/media/audio/common/AudioMMapPolicyInfo.h>
45 #include <aidl/android/media/audio/common/AudioMMapPolicyType.h>
46 #include <aidl/android/media/audio/common/AudioOutputFlags.h>
47 #include <android-base/chrono_utils.h>
48 #include <android/binder_enums.h>
49 #include <error/expected_utils.h>
50 #include <fmq/AidlMessageQueue.h>
51
52 #include "AudioHalBinderServiceUtil.h"
53 #include "ModuleConfig.h"
54 #include "TestUtils.h"
55
56 using namespace android;
57 using aidl::android::hardware::audio::common::AudioOffloadMetadata;
58 using aidl::android::hardware::audio::common::getChannelCount;
59 using aidl::android::hardware::audio::common::hasMmapFlag;
60 using aidl::android::hardware::audio::common::isAnyBitPositionFlagSet;
61 using aidl::android::hardware::audio::common::isBitPositionFlagSet;
62 using aidl::android::hardware::audio::common::isTelephonyDeviceType;
63 using aidl::android::hardware::audio::common::isValidAudioMode;
64 using aidl::android::hardware::audio::common::PlaybackTrackMetadata;
65 using aidl::android::hardware::audio::common::RecordTrackMetadata;
66 using aidl::android::hardware::audio::common::SinkMetadata;
67 using aidl::android::hardware::audio::common::SourceMetadata;
68 using aidl::android::hardware::audio::core::AudioPatch;
69 using aidl::android::hardware::audio::core::AudioRoute;
70 using aidl::android::hardware::audio::core::IBluetooth;
71 using aidl::android::hardware::audio::core::IBluetoothA2dp;
72 using aidl::android::hardware::audio::core::IBluetoothLe;
73 using aidl::android::hardware::audio::core::IModule;
74 using aidl::android::hardware::audio::core::IStreamCommon;
75 using aidl::android::hardware::audio::core::IStreamIn;
76 using aidl::android::hardware::audio::core::IStreamOut;
77 using aidl::android::hardware::audio::core::ITelephony;
78 using aidl::android::hardware::audio::core::ModuleDebug;
79 using aidl::android::hardware::audio::core::StreamDescriptor;
80 using aidl::android::hardware::audio::core::VendorParameter;
81 using aidl::android::hardware::audio::core::sounddose::ISoundDose;
82 using aidl::android::hardware::common::fmq::SynchronizedReadWrite;
83 using aidl::android::media::audio::common::AudioChannelLayout;
84 using aidl::android::media::audio::common::AudioContentType;
85 using aidl::android::media::audio::common::AudioDevice;
86 using aidl::android::media::audio::common::AudioDeviceAddress;
87 using aidl::android::media::audio::common::AudioDeviceDescription;
88 using aidl::android::media::audio::common::AudioDeviceType;
89 using aidl::android::media::audio::common::AudioDualMonoMode;
90 using aidl::android::media::audio::common::AudioFormatType;
91 using aidl::android::media::audio::common::AudioGainConfig;
92 using aidl::android::media::audio::common::AudioInputFlags;
93 using aidl::android::media::audio::common::AudioIoFlags;
94 using aidl::android::media::audio::common::AudioLatencyMode;
95 using aidl::android::media::audio::common::AudioMMapPolicy;
96 using aidl::android::media::audio::common::AudioMMapPolicyInfo;
97 using aidl::android::media::audio::common::AudioMMapPolicyType;
98 using aidl::android::media::audio::common::AudioMode;
99 using aidl::android::media::audio::common::AudioOutputFlags;
100 using aidl::android::media::audio::common::AudioPlaybackRate;
101 using aidl::android::media::audio::common::AudioPort;
102 using aidl::android::media::audio::common::AudioPortConfig;
103 using aidl::android::media::audio::common::AudioPortDeviceExt;
104 using aidl::android::media::audio::common::AudioPortExt;
105 using aidl::android::media::audio::common::AudioPortMixExt;
106 using aidl::android::media::audio::common::AudioSource;
107 using aidl::android::media::audio::common::AudioUsage;
108 using aidl::android::media::audio::common::Boolean;
109 using aidl::android::media::audio::common::Float;
110 using aidl::android::media::audio::common::Int;
111 using aidl::android::media::audio::common::MicrophoneDynamicInfo;
112 using aidl::android::media::audio::common::MicrophoneInfo;
113 using aidl::android::media::audio::common::Void;
114 using android::hardware::audio::common::StreamLogic;
115 using android::hardware::audio::common::StreamWorker;
116 using android::hardware::audio::common::testing::detail::TestExecutionTracer;
117 using ndk::enum_range;
118 using ndk::ScopedAStatus;
119
120 static constexpr int32_t kAidlVersion1 = 1;
121 static constexpr int32_t kAidlVersion2 = 2;
122 static constexpr int32_t kAidlVersion3 = 3;
123
124 template <typename T>
extractIds(const std::vector<T> & v)125 std::set<int32_t> extractIds(const std::vector<T>& v) {
126 std::set<int32_t> ids;
127 std::transform(v.begin(), v.end(), std::inserter(ids, ids.begin()),
128 [](const auto& entity) { return entity.id; });
129 return ids;
130 }
131
132 template <typename T>
findById(const std::vector<T> & v,int32_t id)133 auto findById(const std::vector<T>& v, int32_t id) {
134 return std::find_if(v.begin(), v.end(), [&](const auto& e) { return e.id == id; });
135 }
136
137 template <typename T>
findAny(const std::vector<T> & v,const std::set<int32_t> & ids)138 auto findAny(const std::vector<T>& v, const std::set<int32_t>& ids) {
139 return std::find_if(v.begin(), v.end(), [&](const auto& e) { return ids.count(e.id) > 0; });
140 }
141
142 template <typename C>
GetNonExistentIds(const C & allIds,bool includeZero=true)143 std::vector<int32_t> GetNonExistentIds(const C& allIds, bool includeZero = true) {
144 if (allIds.empty()) {
145 return includeZero ? std::vector<int32_t>{-1, 0, 1} : std::vector<int32_t>{-1, 1};
146 }
147 std::vector<int32_t> nonExistentIds;
148 if (auto value = *std::min_element(allIds.begin(), allIds.end()) - 1;
149 includeZero || value != 0) {
150 nonExistentIds.push_back(value);
151 } else {
152 nonExistentIds.push_back(value - 1);
153 }
154 if (auto value = *std::max_element(allIds.begin(), allIds.end()) + 1;
155 includeZero || value != 0) {
156 nonExistentIds.push_back(value);
157 } else {
158 nonExistentIds.push_back(value + 1);
159 }
160 return nonExistentIds;
161 }
162
suggestDeviceAddressTag(const AudioDeviceDescription & description)163 AudioDeviceAddress::Tag suggestDeviceAddressTag(const AudioDeviceDescription& description) {
164 using Tag = AudioDeviceAddress::Tag;
165 if (std::string_view connection = description.connection;
166 connection == AudioDeviceDescription::CONNECTION_BT_A2DP ||
167 // Note: BT LE Broadcast uses a "group id".
168 (description.type != AudioDeviceType::OUT_BROADCAST &&
169 connection == AudioDeviceDescription::CONNECTION_BT_LE) ||
170 connection == AudioDeviceDescription::CONNECTION_BT_SCO ||
171 connection == AudioDeviceDescription::CONNECTION_WIRELESS) {
172 return Tag::mac;
173 } else if (connection == AudioDeviceDescription::CONNECTION_IP_V4) {
174 return Tag::ipv4;
175 } else if (connection == AudioDeviceDescription::CONNECTION_USB) {
176 return Tag::alsa;
177 }
178 return Tag::id;
179 }
180
GenerateUniqueDeviceAddress(const AudioPort & port)181 AudioPort GenerateUniqueDeviceAddress(const AudioPort& port) {
182 // Point-to-point connections do not use addresses.
183 static const std::set<std::string> kPointToPointConnections = {
184 AudioDeviceDescription::CONNECTION_ANALOG, AudioDeviceDescription::CONNECTION_HDMI,
185 AudioDeviceDescription::CONNECTION_HDMI_ARC,
186 AudioDeviceDescription::CONNECTION_HDMI_EARC, AudioDeviceDescription::CONNECTION_SPDIF};
187 static int nextId = 0;
188 using Tag = AudioDeviceAddress::Tag;
189 const auto& deviceDescription = port.ext.get<AudioPortExt::Tag::device>().device.type;
190 AudioDeviceAddress address = port.ext.get<AudioPortExt::Tag::device>().device.address;
191 // If the address is already set, do not re-generate.
192 if (address == AudioDeviceAddress() &&
193 kPointToPointConnections.count(deviceDescription.connection) == 0) {
194 switch (suggestDeviceAddressTag(deviceDescription)) {
195 case Tag::id:
196 address = AudioDeviceAddress::make<Tag::id>(std::to_string(++nextId));
197 break;
198 case Tag::mac:
199 address = AudioDeviceAddress::make<Tag::mac>(
200 std::vector<uint8_t>{1, 2, 3, 4, 5, static_cast<uint8_t>(++nextId & 0xff)});
201 break;
202 case Tag::ipv4:
203 address = AudioDeviceAddress::make<Tag::ipv4>(
204 std::vector<uint8_t>{192, 168, 0, static_cast<uint8_t>(++nextId & 0xff)});
205 break;
206 case Tag::ipv6:
207 address = AudioDeviceAddress::make<Tag::ipv6>(std::vector<int32_t>{
208 0xfc00, 0x0123, 0x4567, 0x89ab, 0xcdef, 0, 0, ++nextId & 0xffff});
209 break;
210 case Tag::alsa:
211 address = AudioDeviceAddress::make<Tag::alsa>(std::vector<int32_t>{1, ++nextId});
212 break;
213 }
214 }
215 AudioPort result = port;
216 result.ext.get<AudioPortExt::Tag::device>().device.address = std::move(address);
217 return result;
218 }
219
220 // All 'With*' classes are move-only because they are associated with some
221 // resource or state of a HAL module.
222 class WithDebugFlags {
223 public:
createNested(const WithDebugFlags & parent)224 static WithDebugFlags createNested(const WithDebugFlags& parent) {
225 return WithDebugFlags(parent.mFlags);
226 }
227
228 WithDebugFlags() = default;
WithDebugFlags(const ModuleDebug & initial)229 explicit WithDebugFlags(const ModuleDebug& initial) : mInitial(initial), mFlags(initial) {}
230 WithDebugFlags(const WithDebugFlags&) = delete;
231 WithDebugFlags& operator=(const WithDebugFlags&) = delete;
~WithDebugFlags()232 ~WithDebugFlags() {
233 if (mModule != nullptr) {
234 EXPECT_IS_OK(mModule->setModuleDebug(mInitial));
235 }
236 }
SetUp(IModule * module)237 void SetUp(IModule* module) {
238 ASSERT_IS_OK(module->setModuleDebug(mFlags));
239 mModule = module;
240 }
flags()241 ModuleDebug& flags() { return mFlags; }
242
243 private:
244 ModuleDebug mInitial;
245 ModuleDebug mFlags;
246 IModule* mModule = nullptr;
247 };
248
249 template <typename T>
250 class WithModuleParameter {
251 public:
WithModuleParameter(const std::string parameterId,const T & value)252 WithModuleParameter(const std::string parameterId, const T& value)
253 : mParameterId(parameterId), mValue(value) {}
254 WithModuleParameter(const WithModuleParameter&) = delete;
255 WithModuleParameter& operator=(const WithModuleParameter&) = delete;
~WithModuleParameter()256 ~WithModuleParameter() {
257 if (mModule != nullptr) {
258 VendorParameter parameter{.id = mParameterId};
259 parameter.ext.setParcelable(mInitial);
260 EXPECT_IS_OK(mModule->setVendorParameters({parameter}, false));
261 }
262 }
SetUpNoChecks(IModule * module,bool failureExpected)263 ScopedAStatus SetUpNoChecks(IModule* module, bool failureExpected) {
264 std::vector<VendorParameter> parameters;
265 ScopedAStatus result = module->getVendorParameters({mParameterId}, ¶meters);
266 if (result.isOk() && parameters.size() == 1) {
267 std::optional<T> maybeInitial;
268 binder_status_t status = parameters[0].ext.getParcelable(&maybeInitial);
269 if (status == STATUS_OK && maybeInitial.has_value()) {
270 mInitial = maybeInitial.value();
271 VendorParameter parameter{.id = mParameterId};
272 parameter.ext.setParcelable(mValue);
273 result = module->setVendorParameters({parameter}, false);
274 if (result.isOk()) {
275 LOG(INFO) << __func__ << ": overriding parameter \"" << mParameterId
276 << "\" with " << mValue.toString()
277 << ", old value: " << mInitial.toString();
278 mModule = module;
279 }
280 } else {
281 LOG(ERROR) << __func__ << ": error while retrieving the value of \"" << mParameterId
282 << "\"";
283 return ScopedAStatus::fromStatus(status);
284 }
285 }
286 if (!result.isOk()) {
287 LOG(failureExpected ? INFO : ERROR)
288 << __func__ << ": can not override vendor parameter \"" << mParameterId << "\""
289 << result;
290 }
291 return result;
292 }
293
294 private:
295 const std::string mParameterId;
296 const T mValue;
297 IModule* mModule = nullptr;
298 T mInitial;
299 };
300
301 // For consistency, WithAudioPortConfig can start both with a non-existent
302 // port config, and with an existing one. Existence is determined by the
303 // id of the provided config. If it's not 0, then WithAudioPortConfig is
304 // essentially a no-op wrapper.
305 class WithAudioPortConfig {
306 public:
307 WithAudioPortConfig() = default;
WithAudioPortConfig(const AudioPortConfig & config)308 explicit WithAudioPortConfig(const AudioPortConfig& config) : mInitialConfig(config) {}
309 WithAudioPortConfig(const WithAudioPortConfig&) = delete;
310 WithAudioPortConfig& operator=(const WithAudioPortConfig&) = delete;
~WithAudioPortConfig()311 ~WithAudioPortConfig() {
312 if (mModule != nullptr) {
313 EXPECT_IS_OK(mModule->resetAudioPortConfig(getId())) << "port config id " << getId();
314 }
315 }
SetUp(IModule * module)316 void SetUp(IModule* module) {
317 ASSERT_NE(AudioPortExt::Tag::unspecified, mInitialConfig.ext.getTag())
318 << "config: " << mInitialConfig.toString();
319 // Negotiation is allowed for device ports because the HAL module is
320 // allowed to provide an empty profiles list for attached devices.
321 ASSERT_NO_FATAL_FAILURE(
322 SetUpImpl(module, mInitialConfig.ext.getTag() == AudioPortExt::Tag::device));
323 }
getId() const324 int32_t getId() const { return mConfig.id; }
get() const325 const AudioPortConfig& get() const { return mConfig; }
326
327 private:
SetUpImpl(IModule * module,bool negotiate)328 void SetUpImpl(IModule* module, bool negotiate) {
329 if (mInitialConfig.id == 0) {
330 AudioPortConfig suggested;
331 bool applied = false;
332 ASSERT_IS_OK(module->setAudioPortConfig(mInitialConfig, &suggested, &applied))
333 << "Config: " << mInitialConfig.toString();
334 if (!applied && negotiate) {
335 mInitialConfig = suggested;
336 ASSERT_NO_FATAL_FAILURE(SetUpImpl(module, false))
337 << " while applying suggested config: " << suggested.toString();
338 } else {
339 ASSERT_TRUE(applied) << "Suggested: " << suggested.toString();
340 mConfig = suggested;
341 mModule = module;
342 }
343 } else {
344 mConfig = mInitialConfig;
345 }
346 }
347
348 AudioPortConfig mInitialConfig;
349 IModule* mModule = nullptr;
350 AudioPortConfig mConfig;
351 };
352
353 template <typename T>
GenerateTestArrays(size_t validElementCount,T validMin,T validMax,std::vector<std::vector<T>> * validValues,std::vector<std::vector<T>> * invalidValues)354 void GenerateTestArrays(size_t validElementCount, T validMin, T validMax,
355 std::vector<std::vector<T>>* validValues,
356 std::vector<std::vector<T>>* invalidValues) {
357 validValues->emplace_back(validElementCount, validMin);
358 validValues->emplace_back(validElementCount, validMax);
359 validValues->emplace_back(validElementCount, (validMin + validMax) / 2.f);
360 if (validElementCount > 0) {
361 invalidValues->emplace_back(validElementCount - 1, validMin);
362 }
363 invalidValues->emplace_back(validElementCount + 1, validMin);
364 for (auto m : {-2, -1, 2}) {
365 const auto invalidMin = m * validMin;
366 if (invalidMin < validMin || invalidMin > validMax) {
367 invalidValues->emplace_back(validElementCount, invalidMin);
368 }
369 const auto invalidMax = m * validMax;
370 if (invalidMax < validMin || invalidMax > validMax) {
371 invalidValues->emplace_back(validElementCount, invalidMax);
372 }
373 }
374 }
375
376 template <typename PropType, class Instance, typename Getter, typename Setter>
TestAccessors(Instance * inst,Getter getter,Setter setter,const std::vector<PropType> & validValues,const std::vector<PropType> & invalidValues,bool * isSupported)377 void TestAccessors(Instance* inst, Getter getter, Setter setter,
378 const std::vector<PropType>& validValues,
379 const std::vector<PropType>& invalidValues, bool* isSupported) {
380 PropType initialValue{};
381 ScopedAStatus status = (inst->*getter)(&initialValue);
382 if (status.getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
383 *isSupported = false;
384 return;
385 }
386 ASSERT_TRUE(status.isOk()) << "Unexpected status from a getter: " << status;
387 *isSupported = true;
388 for (const auto v : validValues) {
389 EXPECT_IS_OK((inst->*setter)(v)) << "for a valid value: " << ::testing::PrintToString(v);
390 PropType currentValue{};
391 EXPECT_IS_OK((inst->*getter)(¤tValue));
392 EXPECT_EQ(v, currentValue);
393 }
394 for (const auto v : invalidValues) {
395 EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, (inst->*setter)(v))
396 << "for an invalid value: " << ::testing::PrintToString(v);
397 }
398 EXPECT_IS_OK((inst->*setter)(initialValue)) << "Failed to restore the initial value";
399 }
400
401 template <class Instance>
TestGetVendorParameters(Instance * inst,bool * isSupported)402 void TestGetVendorParameters(Instance* inst, bool* isSupported) {
403 static const std::vector<std::vector<std::string>> kIdsLists = {{}, {"zero"}, {"one", "two"}};
404 static const auto kStatuses = {EX_ILLEGAL_ARGUMENT, EX_ILLEGAL_STATE, EX_UNSUPPORTED_OPERATION};
405 for (const auto& ids : kIdsLists) {
406 std::vector<VendorParameter> params;
407 if (ndk::ScopedAStatus status = inst->getVendorParameters(ids, ¶ms); status.isOk()) {
408 EXPECT_EQ(ids.size(), params.size()) << "Size of the returned parameters list must "
409 << "match the size of the provided ids list";
410 for (const auto& param : params) {
411 EXPECT_NE(ids.end(), std::find(ids.begin(), ids.end(), param.id))
412 << "Returned parameter id \"" << param.id << "\" is unexpected";
413 }
414 for (const auto& id : ids) {
415 EXPECT_NE(params.end(),
416 std::find_if(params.begin(), params.end(),
417 [&](const auto& param) { return param.id == id; }))
418 << "Requested parameter with id \"" << id << "\" was not returned";
419 }
420 } else {
421 EXPECT_STATUS(kStatuses, status);
422 if (status.getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
423 *isSupported = false;
424 return;
425 }
426 }
427 }
428 *isSupported = true;
429 }
430
431 template <class Instance>
TestSetVendorParameters(Instance * inst,bool * isSupported)432 void TestSetVendorParameters(Instance* inst, bool* isSupported) {
433 static const auto kStatuses = {EX_NONE, EX_ILLEGAL_ARGUMENT, EX_ILLEGAL_STATE,
434 EX_UNSUPPORTED_OPERATION};
435 static const std::vector<std::vector<VendorParameter>> kParamsLists = {
436 {}, {VendorParameter{"zero"}}, {VendorParameter{"one"}, VendorParameter{"two"}}};
437 for (const auto& params : kParamsLists) {
438 ndk::ScopedAStatus status = inst->setVendorParameters(params, false);
439 if (status.getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
440 *isSupported = false;
441 return;
442 }
443 EXPECT_STATUS(kStatuses, status)
444 << ::android::internal::ToString(params) << ", async: false";
445 EXPECT_STATUS(kStatuses, inst->setVendorParameters(params, true))
446 << ::android::internal::ToString(params) << ", async: true";
447 }
448 *isSupported = true;
449 }
450
451 // Can be used as a base for any test here, does not depend on the fixture GTest parameters.
452 class AudioCoreModuleBase {
453 public:
454 // Fixed buffer size are used for negative tests only. For any tests involving stream
455 // opening that must success, the minimum buffer size must be obtained from a patch.
456 // This is implemented by the 'StreamFixture' utility class.
457 static constexpr int kNegativeTestBufferSizeFrames = 256;
458 static constexpr int kDefaultLargeBufferSizeFrames = 48000;
459
SetUpImpl(const std::string & moduleName,bool setUpDebug=true)460 void SetUpImpl(const std::string& moduleName, bool setUpDebug = true) {
461 ASSERT_NO_FATAL_FAILURE(ConnectToService(moduleName, setUpDebug));
462 ASSERT_IS_OK(module->getAudioPorts(&initialPorts));
463 ASSERT_IS_OK(module->getAudioRoutes(&initialRoutes));
464 }
465
TearDownImpl()466 void TearDownImpl() {
467 debug.reset();
468 ASSERT_NE(module, nullptr);
469 std::vector<AudioPort> finalPorts;
470 ASSERT_IS_OK(module->getAudioPorts(&finalPorts));
471 EXPECT_NO_FATAL_FAILURE(VerifyVectorsAreEqual<AudioPort>(initialPorts, finalPorts))
472 << "The list of audio ports was not restored to the initial state";
473 std::vector<AudioRoute> finalRoutes;
474 ASSERT_IS_OK(module->getAudioRoutes(&finalRoutes));
475 EXPECT_NO_FATAL_FAILURE(VerifyVectorsAreEqual<AudioRoute>(initialRoutes, finalRoutes))
476 << "The list of audio routes was not restored to the initial state";
477 }
478
ConnectToService(const std::string & moduleName,bool setUpDebug)479 void ConnectToService(const std::string& moduleName, bool setUpDebug) {
480 ASSERT_EQ(module, nullptr);
481 ASSERT_EQ(debug, nullptr);
482 module = IModule::fromBinder(binderUtil.connectToService(moduleName));
483 ASSERT_NE(module, nullptr);
484 if (setUpDebug) {
485 ASSERT_NO_FATAL_FAILURE(SetUpDebug());
486 }
487 ASSERT_TRUE(module->getInterfaceVersion(&aidlVersion).isOk());
488 }
489
RestartService()490 void RestartService() {
491 ASSERT_NE(module, nullptr);
492 moduleConfig.reset();
493 const bool setUpDebug = !!debug;
494 debug.reset();
495 module = IModule::fromBinder(binderUtil.restartService());
496 ASSERT_NE(module, nullptr);
497 if (setUpDebug) {
498 ASSERT_NO_FATAL_FAILURE(SetUpDebug());
499 }
500 ASSERT_TRUE(module->getInterfaceVersion(&aidlVersion).isOk());
501 }
502
SetUpDebug()503 void SetUpDebug() {
504 debug.reset(new WithDebugFlags());
505 debug->flags().simulateDeviceConnections = true;
506 ASSERT_NO_FATAL_FAILURE(debug->SetUp(module.get()));
507 }
508
ApplyEveryConfig(const std::vector<AudioPortConfig> & configs)509 void ApplyEveryConfig(const std::vector<AudioPortConfig>& configs) {
510 for (const auto& config : configs) {
511 ASSERT_NE(0, config.portId);
512 WithAudioPortConfig portConfig(config);
513 ASSERT_NO_FATAL_FAILURE(portConfig.SetUp(module.get())); // calls setAudioPortConfig
514 EXPECT_EQ(config.portId, portConfig.get().portId);
515 std::vector<AudioPortConfig> retrievedPortConfigs;
516 ASSERT_IS_OK(module->getAudioPortConfigs(&retrievedPortConfigs));
517 const int32_t portConfigId = portConfig.getId();
518 auto configIt = std::find_if(
519 retrievedPortConfigs.begin(), retrievedPortConfigs.end(),
520 [&portConfigId](const auto& retrConf) { return retrConf.id == portConfigId; });
521 EXPECT_NE(configIt, retrievedPortConfigs.end())
522 << "Port config id returned by setAudioPortConfig: " << portConfigId
523 << " is not found in the list returned by getAudioPortConfigs";
524 if (configIt != retrievedPortConfigs.end()) {
525 EXPECT_EQ(portConfig.get(), *configIt)
526 << "Applied port config returned by setAudioPortConfig: "
527 << portConfig.get().toString()
528 << " is not the same as retrieved via getAudioPortConfigs: "
529 << configIt->toString();
530 }
531 }
532 }
533
534 template <typename Entity>
GetAllEntityIds(std::set<int32_t> * entityIds,ScopedAStatus (IModule::* getter)(std::vector<Entity> *),const std::string & errorMessage)535 void GetAllEntityIds(std::set<int32_t>* entityIds,
536 ScopedAStatus (IModule::*getter)(std::vector<Entity>*),
537 const std::string& errorMessage) {
538 std::vector<Entity> entities;
539 { ASSERT_IS_OK((module.get()->*getter)(&entities)); }
540 *entityIds = extractIds<Entity>(entities);
541 EXPECT_EQ(entities.size(), entityIds->size()) << errorMessage;
542 }
543
GetAllPatchIds(std::set<int32_t> * patchIds)544 void GetAllPatchIds(std::set<int32_t>* patchIds) {
545 return GetAllEntityIds<AudioPatch>(
546 patchIds, &IModule::getAudioPatches,
547 "IDs of audio patches returned by IModule.getAudioPatches are not unique");
548 }
549
GetAllPortIds(std::set<int32_t> * portIds)550 void GetAllPortIds(std::set<int32_t>* portIds) {
551 return GetAllEntityIds<AudioPort>(
552 portIds, &IModule::getAudioPorts,
553 "IDs of audio ports returned by IModule.getAudioPorts are not unique");
554 }
555
GetAllPortConfigIds(std::set<int32_t> * portConfigIds)556 void GetAllPortConfigIds(std::set<int32_t>* portConfigIds) {
557 return GetAllEntityIds<AudioPortConfig>(
558 portConfigIds, &IModule::getAudioPortConfigs,
559 "IDs of audio port configs returned by IModule.getAudioPortConfigs are not unique");
560 }
561
SetUpModuleConfig()562 void SetUpModuleConfig() {
563 if (moduleConfig == nullptr) {
564 moduleConfig = std::make_unique<ModuleConfig>(module.get());
565 ASSERT_EQ(EX_NONE, moduleConfig->getStatus().getExceptionCode())
566 << "ModuleConfig init error: " << moduleConfig->getError();
567 }
568 }
569
570 // Warning: modifies the vectors!
571 template <typename T>
VerifyVectorsAreEqual(std::vector<T> & v1,std::vector<T> & v2)572 void VerifyVectorsAreEqual(std::vector<T>& v1, std::vector<T>& v2) {
573 ASSERT_EQ(v1.size(), v2.size());
574 std::sort(v1.begin(), v1.end());
575 std::sort(v2.begin(), v2.end());
576 if (v1 != v2) {
577 FAIL() << "Vectors are not equal: v1 = " << ::android::internal::ToString(v1)
578 << ", v2 = " << ::android::internal::ToString(v2);
579 }
580 }
581
582 std::shared_ptr<IModule> module;
583 std::unique_ptr<ModuleConfig> moduleConfig;
584 AudioHalBinderServiceUtil binderUtil;
585 std::unique_ptr<WithDebugFlags> debug;
586 std::vector<AudioPort> initialPorts;
587 std::vector<AudioRoute> initialRoutes;
588 int32_t aidlVersion = -1;
589 };
590
591 class WithDevicePortConnectedState {
592 public:
WithDevicePortConnectedState(const AudioPort & idAndData)593 explicit WithDevicePortConnectedState(const AudioPort& idAndData) : mIdAndData(idAndData) {}
594 WithDevicePortConnectedState(const WithDevicePortConnectedState&) = delete;
595 WithDevicePortConnectedState& operator=(const WithDevicePortConnectedState&) = delete;
~WithDevicePortConnectedState()596 ~WithDevicePortConnectedState() {
597 if (mModule != nullptr) {
598 EXPECT_IS_OK_OR_UNKNOWN_TRANSACTION(mModule->prepareToDisconnectExternalDevice(getId()))
599 << "when preparing to disconnect device port ID " << getId();
600 EXPECT_IS_OK(mModule->disconnectExternalDevice(getId()))
601 << "when disconnecting device port ID " << getId();
602 }
603 if (mModuleConfig != nullptr) {
604 EXPECT_IS_OK(mModuleConfig->onExternalDeviceDisconnected(mModule, mConnectedPort))
605 << "when external device disconnected";
606 }
607 }
SetUpNoChecks(IModule * module,ModuleConfig * moduleConfig)608 ScopedAStatus SetUpNoChecks(IModule* module, ModuleConfig* moduleConfig) {
609 RETURN_STATUS_IF_ERROR(module->connectExternalDevice(mIdAndData, &mConnectedPort));
610 RETURN_STATUS_IF_ERROR(moduleConfig->onExternalDeviceConnected(module, mConnectedPort));
611 mModule = module;
612 mModuleConfig = moduleConfig;
613 return ScopedAStatus::ok();
614 }
SetUp(IModule * module,ModuleConfig * moduleConfig)615 void SetUp(IModule* module, ModuleConfig* moduleConfig) {
616 ASSERT_NE(moduleConfig, nullptr);
617 ASSERT_IS_OK(SetUpNoChecks(module, moduleConfig))
618 << "when connecting device port ID & data " << mIdAndData.toString();
619 ASSERT_NE(mIdAndData.id, getId())
620 << "ID of the connected port must not be the same as the ID of the template port";
621 }
getId() const622 int32_t getId() const { return mConnectedPort.id; }
get()623 const AudioPort& get() { return mConnectedPort; }
624
625 private:
626 const AudioPort mIdAndData;
627 IModule* mModule = nullptr;
628 ModuleConfig* mModuleConfig = nullptr;
629 AudioPort mConnectedPort;
630 };
631
632 class AudioCoreModule : public AudioCoreModuleBase, public testing::TestWithParam<std::string> {
633 public:
SetUp()634 void SetUp() override { ASSERT_NO_FATAL_FAILURE(SetUpImpl(GetParam())); }
635
TearDown()636 void TearDown() override { ASSERT_NO_FATAL_FAILURE(TearDownImpl()); }
637 };
638
639 class StreamContext {
640 public:
641 typedef AidlMessageQueue<StreamDescriptor::Command, SynchronizedReadWrite> CommandMQ;
642 typedef AidlMessageQueue<StreamDescriptor::Reply, SynchronizedReadWrite> ReplyMQ;
643 typedef AidlMessageQueue<int8_t, SynchronizedReadWrite> DataMQ;
644
StreamContext(const StreamDescriptor & descriptor)645 explicit StreamContext(const StreamDescriptor& descriptor)
646 : mFrameSizeBytes(descriptor.frameSizeBytes),
647 mCommandMQ(new CommandMQ(descriptor.command)),
648 mReplyMQ(new ReplyMQ(descriptor.reply)),
649 mBufferSizeFrames(descriptor.bufferSizeFrames),
650 mDataMQ(maybeCreateDataMQ(descriptor)),
651 mIsMmapped(isMmapped(descriptor)),
652 mSharedMemoryFd(maybeGetMmapFd(descriptor)) {
653 if (isMmapped()) {
654 mSharedMemory = (int8_t*)mmap(nullptr, getBufferSizeBytes(), PROT_READ | PROT_WRITE,
655 MAP_SHARED, mSharedMemoryFd, 0);
656 if (mSharedMemory == MAP_FAILED) {
657 PLOG(ERROR) << __func__ << ": mmap() failed.";
658 mSharedMemory = nullptr;
659 }
660 }
661 }
~StreamContext()662 ~StreamContext() {
663 if (mSharedMemory != nullptr) {
664 munmap(mSharedMemory, getBufferSizeBytes());
665 }
666 }
checkIsValid() const667 void checkIsValid() const {
668 EXPECT_NE(0UL, mFrameSizeBytes);
669 ASSERT_NE(nullptr, mCommandMQ);
670 EXPECT_TRUE(mCommandMQ->isValid());
671 ASSERT_NE(nullptr, mReplyMQ);
672 EXPECT_TRUE(mReplyMQ->isValid());
673 if (isMmapped()) {
674 ASSERT_NE(nullptr, mSharedMemory);
675 } else {
676 if (mDataMQ != nullptr) {
677 EXPECT_TRUE(mDataMQ->isValid());
678 EXPECT_GE(mDataMQ->getQuantumCount() * mDataMQ->getQuantumSize(),
679 mFrameSizeBytes * mBufferSizeFrames)
680 << "Data MQ actual buffer size is "
681 "less than the buffer size as specified by the descriptor";
682 }
683 }
684 }
getBufferSizeBytes() const685 size_t getBufferSizeBytes() const { return mFrameSizeBytes * mBufferSizeFrames; }
getBufferSizeFrames() const686 size_t getBufferSizeFrames() const { return mBufferSizeFrames; }
getCommandMQ() const687 CommandMQ* getCommandMQ() const { return mCommandMQ.get(); }
getDataMQ() const688 DataMQ* getDataMQ() const { return mDataMQ.get(); }
getFrameSizeBytes() const689 size_t getFrameSizeBytes() const { return mFrameSizeBytes; }
getReplyMQ() const690 ReplyMQ* getReplyMQ() const { return mReplyMQ.get(); }
isMmapped() const691 bool isMmapped() const { return mIsMmapped; }
getMmapMemory() const692 int8_t* getMmapMemory() const { return mSharedMemory; }
693
694 private:
maybeCreateDataMQ(const StreamDescriptor & descriptor)695 static std::unique_ptr<DataMQ> maybeCreateDataMQ(const StreamDescriptor& descriptor) {
696 using Tag = StreamDescriptor::AudioBuffer::Tag;
697 if (descriptor.audio.getTag() == Tag::fmq) {
698 return std::make_unique<DataMQ>(descriptor.audio.get<Tag::fmq>());
699 }
700 return nullptr;
701 }
isMmapped(const StreamDescriptor & descriptor)702 static bool isMmapped(const StreamDescriptor& descriptor) {
703 using Tag = StreamDescriptor::AudioBuffer::Tag;
704 return descriptor.audio.getTag() == Tag::mmap;
705 }
maybeGetMmapFd(const StreamDescriptor & descriptor)706 static int32_t maybeGetMmapFd(const StreamDescriptor& descriptor) {
707 using Tag = StreamDescriptor::AudioBuffer::Tag;
708 if (descriptor.audio.getTag() == Tag::mmap) {
709 return descriptor.audio.get<Tag::mmap>().sharedMemory.fd.get();
710 }
711 return -1;
712 }
713
714 const size_t mFrameSizeBytes;
715 std::unique_ptr<CommandMQ> mCommandMQ;
716 std::unique_ptr<ReplyMQ> mReplyMQ;
717 const size_t mBufferSizeFrames;
718 std::unique_ptr<DataMQ> mDataMQ;
719 const bool mIsMmapped;
720 const int32_t mSharedMemoryFd;
721 int8_t* mSharedMemory = nullptr;
722 };
723
724 struct StreamEventReceiver {
725 virtual ~StreamEventReceiver() = default;
726 enum class Event { None, DrainReady, Error, TransferReady };
727 virtual std::tuple<int, Event> getLastEvent() const = 0;
728 virtual std::tuple<int, Event> waitForEvent(int clientEventSeq) = 0;
729 static constexpr int kEventSeqInit = -1;
730 };
toString(StreamEventReceiver::Event event)731 std::string toString(StreamEventReceiver::Event event) {
732 switch (event) {
733 case StreamEventReceiver::Event::None:
734 return "None";
735 case StreamEventReceiver::Event::DrainReady:
736 return "DrainReady";
737 case StreamEventReceiver::Event::Error:
738 return "Error";
739 case StreamEventReceiver::Event::TransferReady:
740 return "TransferReady";
741 }
742 return std::to_string(static_cast<int32_t>(event));
743 }
744
745 // Note: we use a reference wrapper, not a pointer, because methods of std::*list
746 // return references to inserted elements. This way, we can put a returned reference
747 // into the children vector without any type conversions, and this makes DAG creation
748 // code more clear.
749 template <typename T>
750 struct DagNode : public std::pair<T, std::vector<std::reference_wrapper<DagNode<T>>>> {
751 using Children = std::vector<std::reference_wrapper<DagNode>>;
DagNodeDagNode752 DagNode(const T& t, const Children& c) : std::pair<T, Children>(t, c) {}
DagNodeDagNode753 DagNode(T&& t, Children&& c) : std::pair<T, Children>(std::move(t), std::move(c)) {}
datumDagNode754 const T& datum() const { return this->first; }
childrenDagNode755 Children& children() { return this->second; }
childrenDagNode756 const Children& children() const { return this->second; }
757 };
758 // Since DagNodes do contain references to next nodes, node links provided
759 // by the list are not used. Thus, the order of the nodes in the list is not
760 // important, except that the starting node must be at the front of the list,
761 // which means, it must always be added last.
762 template <typename T>
763 struct Dag : public std::forward_list<DagNode<T>> {
764 Dag() = default;
765 // We prohibit copying and moving Dag instances because implementing that
766 // is not trivial due to references between nodes.
767 Dag(const Dag&) = delete;
768 Dag(Dag&&) = delete;
769 Dag& operator=(const Dag&) = delete;
770 Dag& operator=(Dag&&) = delete;
771 };
772
773 // Transition to the next state happens either due to a command from the client,
774 // or after an event received from the server.
775 using TransitionTrigger = std::variant<StreamDescriptor::Command, StreamEventReceiver::Event>;
toString(const TransitionTrigger & trigger)776 std::string toString(const TransitionTrigger& trigger) {
777 if (std::holds_alternative<StreamDescriptor::Command>(trigger)) {
778 return std::string("'")
779 .append(toString(std::get<StreamDescriptor::Command>(trigger).getTag()))
780 .append("' command");
781 }
782 return std::string("'")
783 .append(toString(std::get<StreamEventReceiver::Event>(trigger)))
784 .append("' event");
785 }
786
787 struct StateSequence {
788 virtual ~StateSequence() = default;
789 virtual void rewind() = 0;
790 virtual bool done() const = 0;
791 virtual TransitionTrigger getTrigger() = 0;
792 virtual std::set<StreamDescriptor::State> getExpectedStates() = 0;
793 virtual void advance(StreamDescriptor::State state) = 0;
794 };
795
796 // Defines the current state and the trigger to transfer to the next one,
797 // thus "state" is the "from" state.
798 using StateTransitionFrom = std::pair<StreamDescriptor::State, TransitionTrigger>;
799
800 static const StreamDescriptor::Command kGetStatusCommand =
801 StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::getStatus>(Void{});
802 static const StreamDescriptor::Command kStartCommand =
803 StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::start>(Void{});
804 static const StreamDescriptor::Command kBurstCommand =
805 StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::burst>(0);
806 static const StreamDescriptor::Command kDrainInCommand =
807 StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::drain>(
808 StreamDescriptor::DrainMode::DRAIN_UNSPECIFIED);
809 static const StreamDescriptor::Command kDrainOutAllCommand =
810 StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::drain>(
811 StreamDescriptor::DrainMode::DRAIN_ALL);
812 static const StreamDescriptor::Command kDrainOutEarlyCommand =
813 StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::drain>(
814 StreamDescriptor::DrainMode::DRAIN_EARLY_NOTIFY);
815 static const StreamDescriptor::Command kStandbyCommand =
816 StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::standby>(Void{});
817 static const StreamDescriptor::Command kPauseCommand =
818 StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::pause>(Void{});
819 static const StreamDescriptor::Command kFlushCommand =
820 StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::flush>(Void{});
821 static const StreamEventReceiver::Event kTransferReadyEvent =
822 StreamEventReceiver::Event::TransferReady;
823 static const StreamEventReceiver::Event kDrainReadyEvent = StreamEventReceiver::Event::DrainReady;
824
825 struct StateDag : public Dag<StateTransitionFrom> {
826 using Node = StateDag::reference;
827 using NextStates = StateDag::value_type::Children;
828
829 template <typename... Next>
makeNodeStateDag830 Node makeNode(StreamDescriptor::State s, TransitionTrigger t, Next&&... next) {
831 return emplace_front(std::make_pair(s, t), NextStates{std::forward<Next>(next)...});
832 }
makeNodesStateDag833 Node makeNodes(const std::vector<StateTransitionFrom>& v, Node last) {
834 auto helper = [&](auto i, auto&& h) -> Node {
835 if (i == v.end()) return last;
836 return makeNode(i->first, i->second, h(++i, h));
837 };
838 return helper(v.begin(), helper);
839 }
makeNodesStateDag840 Node makeNodes(StreamDescriptor::State s, TransitionTrigger t, size_t count, Node last) {
841 auto helper = [&](size_t c, auto&& h) -> Node {
842 if (c == 0) return last;
843 return makeNode(s, t, h(--c, h));
844 };
845 return helper(count, helper);
846 }
makeNodesStateDag847 Node makeNodes(const std::vector<StateTransitionFrom>& v, StreamDescriptor::State f) {
848 return makeNodes(v, makeFinalNode(f));
849 }
makeFinalNodeStateDag850 Node makeFinalNode(StreamDescriptor::State s) {
851 // The actual command used here is irrelevant. Since it's the final node
852 // in the test sequence, no commands sent after reaching it.
853 return emplace_front(std::make_pair(s, kGetStatusCommand), NextStates{});
854 }
855 };
856
857 class StateSequenceFollower : public StateSequence {
858 public:
StateSequenceFollower(std::unique_ptr<StateDag> steps)859 explicit StateSequenceFollower(std::unique_ptr<StateDag> steps)
860 : mSteps(std::move(steps)), mCurrent(mSteps->front()) {}
rewind()861 void rewind() override { mCurrent = mSteps->front(); }
done() const862 bool done() const override { return current().children().empty(); }
getTrigger()863 TransitionTrigger getTrigger() override { return current().datum().second; }
getExpectedStates()864 std::set<StreamDescriptor::State> getExpectedStates() override {
865 std::set<StreamDescriptor::State> result;
866 std::transform(current().children().cbegin(), current().children().cend(),
867 std::inserter(result, result.begin()),
868 [](const auto& node) { return node.get().datum().first; });
869 LOG(DEBUG) << __func__ << ": " << ::android::internal::ToString(result);
870 return result;
871 }
advance(StreamDescriptor::State state)872 void advance(StreamDescriptor::State state) override {
873 if (auto it = std::find_if(
874 current().children().cbegin(), current().children().cend(),
875 [&](const auto& node) { return node.get().datum().first == state; });
876 it != current().children().cend()) {
877 LOG(DEBUG) << __func__ << ": " << toString(mCurrent.get().datum().first) << " -> "
878 << toString(it->get().datum().first);
879 mCurrent = *it;
880 } else {
881 LOG(FATAL) << __func__ << ": state " << toString(state) << " is unexpected";
882 }
883 }
884
885 private:
current() const886 StateDag::const_reference current() const { return mCurrent.get(); }
887 std::unique_ptr<StateDag> mSteps;
888 std::reference_wrapper<StateDag::value_type> mCurrent;
889 };
890
891 struct StreamLogicDriver {
892 virtual ~StreamLogicDriver() = default;
893 // Return 'true' to stop the worker.
894 virtual bool done() = 0;
895 // For 'Writer' logic, if the 'actualSize' is 0, write is skipped.
896 // The 'fmqByteCount' from the returned command is passed as is to the HAL.
897 virtual TransitionTrigger getNextTrigger(int maxDataSize, int* actualSize = nullptr) = 0;
898 // Return 'true' to indicate that no further processing is needed,
899 // for example, the driver is expecting a bad status to be returned.
900 // The logic cycle will return with 'CONTINUE' status. Otherwise,
901 // the reply will be validated and then passed to 'processValidReply'.
902 virtual bool interceptRawReply(const StreamDescriptor::Reply& reply) = 0;
903 // Return 'false' to indicate that the contents of the reply are unexpected.
904 // Will abort the logic cycle.
905 virtual bool processValidReply(const StreamDescriptor::Reply& reply) = 0;
906 };
907
908 class StreamCommonLogic : public StreamLogic {
909 protected:
StreamCommonLogic(const StreamContext & context,StreamLogicDriver * driver,StreamEventReceiver * eventReceiver)910 StreamCommonLogic(const StreamContext& context, StreamLogicDriver* driver,
911 StreamEventReceiver* eventReceiver)
912 : mCommandMQ(context.getCommandMQ()),
913 mReplyMQ(context.getReplyMQ()),
914 mDataMQ(context.getDataMQ()),
915 mData(context.getBufferSizeBytes()),
916 mDriver(driver),
917 mEventReceiver(eventReceiver),
918 mIsMmapped(context.isMmapped()),
919 mSharedMemory(context.getMmapMemory()) {}
getCommandMQ() const920 StreamContext::CommandMQ* getCommandMQ() const { return mCommandMQ; }
getReplyMQ() const921 StreamContext::ReplyMQ* getReplyMQ() const { return mReplyMQ; }
getDataMQ() const922 StreamContext::DataMQ* getDataMQ() const { return mDataMQ; }
getDriver() const923 StreamLogicDriver* getDriver() const { return mDriver; }
getEventReceiver() const924 StreamEventReceiver* getEventReceiver() const { return mEventReceiver; }
isMmapped() const925 bool isMmapped() const { return mIsMmapped; }
926
init()927 std::string init() override {
928 LOG(DEBUG) << __func__;
929 return "";
930 }
maybeGetNextCommand(int * actualSize=nullptr)931 std::optional<StreamDescriptor::Command> maybeGetNextCommand(int* actualSize = nullptr) {
932 TransitionTrigger trigger = mDriver->getNextTrigger(mData.size(), actualSize);
933 if (StreamEventReceiver::Event* expEvent =
934 std::get_if<StreamEventReceiver::Event>(&trigger);
935 expEvent != nullptr) {
936 auto [eventSeq, event] = mEventReceiver->waitForEvent(mLastEventSeq);
937 mLastEventSeq = eventSeq;
938 if (event != *expEvent) {
939 LOG(ERROR) << __func__ << ": expected event " << toString(*expEvent) << ", got "
940 << toString(event);
941 return {};
942 }
943 // If we were waiting for an event, the new stream state must be retrieved
944 // via 'getStatus'.
945 return StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::getStatus>(
946 Void{});
947 }
948 return std::get<StreamDescriptor::Command>(trigger);
949 }
readDataFromMQ(size_t readCount)950 bool readDataFromMQ(size_t readCount) {
951 std::vector<int8_t> data(readCount);
952 if (mDataMQ->read(data.data(), readCount)) {
953 memcpy(mData.data(), data.data(), std::min(mData.size(), data.size()));
954 return true;
955 }
956 LOG(ERROR) << __func__ << ": reading of " << readCount << " bytes from MQ failed";
957 return false;
958 }
writeDataToMQ()959 bool writeDataToMQ() {
960 if (mDataMQ->write(mData.data(), mData.size())) {
961 return true;
962 }
963 LOG(ERROR) << __func__ << ": writing of " << mData.size() << " bytes to MQ failed";
964 return false;
965 }
readDataFromMmap(size_t readCount)966 bool readDataFromMmap(size_t readCount) {
967 if (mSharedMemory != nullptr) {
968 std::memcpy(mData.data(), mSharedMemory, readCount);
969 return true;
970 }
971 LOG(ERROR) << __func__ << ": reading of " << readCount << " bytes from mmap failed";
972 return false;
973 }
writeDataToMmap()974 bool writeDataToMmap() {
975 if (mSharedMemory != nullptr) {
976 std::memcpy(mSharedMemory, mData.data(), mData.size());
977 return true;
978 }
979 LOG(ERROR) << __func__ << ": writing of " << mData.size() << " bytes to mmap failed";
980 return false;
981 }
982
983 private:
984 StreamContext::CommandMQ* mCommandMQ;
985 StreamContext::ReplyMQ* mReplyMQ;
986 StreamContext::DataMQ* mDataMQ;
987 std::vector<int8_t> mData;
988 StreamLogicDriver* const mDriver;
989 StreamEventReceiver* const mEventReceiver;
990 int mLastEventSeq = StreamEventReceiver::kEventSeqInit;
991 const bool mIsMmapped;
992 int8_t* mSharedMemory = nullptr;
993 };
994
995 class StreamReaderLogic : public StreamCommonLogic {
996 public:
StreamReaderLogic(const StreamContext & context,StreamLogicDriver * driver,StreamEventReceiver * eventReceiver)997 StreamReaderLogic(const StreamContext& context, StreamLogicDriver* driver,
998 StreamEventReceiver* eventReceiver)
999 : StreamCommonLogic(context, driver, eventReceiver) {}
1000
1001 protected:
cycle()1002 Status cycle() override {
1003 if (getDriver()->done()) {
1004 LOG(DEBUG) << __func__ << ": clean exit";
1005 return Status::EXIT;
1006 }
1007 StreamDescriptor::Command command;
1008 if (auto maybeCommand = maybeGetNextCommand(); maybeCommand.has_value()) {
1009 command = std::move(maybeCommand.value());
1010 } else {
1011 LOG(ERROR) << __func__ << ": no next command";
1012 return Status::ABORT;
1013 }
1014 LOG(DEBUG) << "Writing command: " << command.toString();
1015 if (!getCommandMQ()->writeBlocking(&command, 1)) {
1016 LOG(ERROR) << __func__ << ": writing of command into MQ failed";
1017 return Status::ABORT;
1018 }
1019 StreamDescriptor::Reply reply{};
1020 LOG(DEBUG) << "Reading reply...";
1021 if (!getReplyMQ()->readBlocking(&reply, 1)) {
1022 return Status::ABORT;
1023 }
1024 LOG(DEBUG) << "Reply received: " << reply.toString();
1025 if (getDriver()->interceptRawReply(reply)) {
1026 LOG(DEBUG) << __func__ << ": reply has been intercepted by the driver";
1027 return Status::CONTINUE;
1028 }
1029 if (reply.status != STATUS_OK) {
1030 LOG(ERROR) << __func__ << ": received error status: " << statusToString(reply.status);
1031 return Status::ABORT;
1032 }
1033 if (reply.fmqByteCount < 0 ||
1034 (command.getTag() == StreamDescriptor::Command::Tag::burst &&
1035 reply.fmqByteCount > command.get<StreamDescriptor::Command::Tag::burst>())) {
1036 LOG(ERROR) << __func__
1037 << ": received invalid byte count in the reply: " << reply.fmqByteCount;
1038 return Status::ABORT;
1039 }
1040 if (!isMmapped() &&
1041 static_cast<size_t>(reply.fmqByteCount) != getDataMQ()->availableToRead()) {
1042 LOG(ERROR) << __func__
1043 << ": the byte count in the reply is not the same as the amount of "
1044 << "data available in the MQ: " << reply.fmqByteCount
1045 << " != " << getDataMQ()->availableToRead();
1046 }
1047 if (reply.latencyMs < 0 && reply.latencyMs != StreamDescriptor::LATENCY_UNKNOWN) {
1048 LOG(ERROR) << __func__ << ": received invalid latency value: " << reply.latencyMs;
1049 return Status::ABORT;
1050 }
1051 if (reply.xrunFrames < 0) {
1052 LOG(ERROR) << __func__ << ": received invalid xrunFrames value: " << reply.xrunFrames;
1053 return Status::ABORT;
1054 }
1055 if (std::find(enum_range<StreamDescriptor::State>().begin(),
1056 enum_range<StreamDescriptor::State>().end(),
1057 reply.state) == enum_range<StreamDescriptor::State>().end()) {
1058 LOG(ERROR) << __func__ << ": received invalid stream state: " << toString(reply.state);
1059 return Status::ABORT;
1060 }
1061 const bool acceptedReply = getDriver()->processValidReply(reply);
1062 if (const size_t readCount =
1063 !isMmapped() ? getDataMQ()->availableToRead() : reply.fmqByteCount;
1064 readCount > 0) {
1065 if (isMmapped() ? readDataFromMmap(readCount) : readDataFromMQ(readCount)) {
1066 goto checkAcceptedReply;
1067 }
1068 LOG(ERROR) << __func__ << ": reading of " << readCount << " data bytes from MQ failed";
1069 return Status::ABORT;
1070 } // readCount == 0
1071 checkAcceptedReply:
1072 if (acceptedReply) {
1073 return Status::CONTINUE;
1074 }
1075 LOG(ERROR) << __func__ << ": unacceptable reply: " << reply.toString();
1076 return Status::ABORT;
1077 }
1078 };
1079 using StreamReader = StreamWorker<StreamReaderLogic>;
1080
1081 class StreamWriterLogic : public StreamCommonLogic {
1082 public:
StreamWriterLogic(const StreamContext & context,StreamLogicDriver * driver,StreamEventReceiver * eventReceiver)1083 StreamWriterLogic(const StreamContext& context, StreamLogicDriver* driver,
1084 StreamEventReceiver* eventReceiver)
1085 : StreamCommonLogic(context, driver, eventReceiver) {}
1086
1087 protected:
cycle()1088 Status cycle() override {
1089 if (getDriver()->done()) {
1090 LOG(DEBUG) << __func__ << ": clean exit";
1091 return Status::EXIT;
1092 }
1093 int actualSize = 0;
1094 StreamDescriptor::Command command;
1095 if (auto maybeCommand = maybeGetNextCommand(&actualSize); maybeCommand.has_value()) {
1096 command = std::move(maybeCommand.value());
1097 } else {
1098 LOG(ERROR) << __func__ << ": no next command";
1099 return Status::ABORT;
1100 }
1101 if (actualSize != 0) {
1102 if (isMmapped() ? !writeDataToMmap() : !writeDataToMQ()) {
1103 return Status::ABORT;
1104 }
1105 }
1106 LOG(DEBUG) << "Writing command: " << command.toString();
1107 if (!getCommandMQ()->writeBlocking(&command, 1)) {
1108 LOG(ERROR) << __func__ << ": writing of command into MQ failed";
1109 return Status::ABORT;
1110 }
1111 StreamDescriptor::Reply reply{};
1112 LOG(DEBUG) << "Reading reply...";
1113 if (!getReplyMQ()->readBlocking(&reply, 1)) {
1114 LOG(ERROR) << __func__ << ": reading of reply from MQ failed";
1115 return Status::ABORT;
1116 }
1117 LOG(DEBUG) << "Reply received: " << reply.toString();
1118 if (getDriver()->interceptRawReply(reply)) {
1119 return Status::CONTINUE;
1120 }
1121 if (reply.status != STATUS_OK) {
1122 LOG(ERROR) << __func__ << ": received error status: " << statusToString(reply.status);
1123 return Status::ABORT;
1124 }
1125 if (reply.fmqByteCount < 0 ||
1126 (command.getTag() == StreamDescriptor::Command::Tag::burst &&
1127 reply.fmqByteCount > command.get<StreamDescriptor::Command::Tag::burst>())) {
1128 LOG(ERROR) << __func__
1129 << ": received invalid byte count in the reply: " << reply.fmqByteCount;
1130 return Status::ABORT;
1131 }
1132 // It is OK for the implementation to leave data in the MQ when the stream is paused.
1133 if (!isMmapped() && reply.state != StreamDescriptor::State::PAUSED &&
1134 getDataMQ()->availableToWrite() != getDataMQ()->getQuantumCount()) {
1135 LOG(ERROR) << __func__ << ": the HAL module did not consume all data from the data MQ: "
1136 << "available to write " << getDataMQ()->availableToWrite()
1137 << ", total size: " << getDataMQ()->getQuantumCount();
1138 return Status::ABORT;
1139 }
1140 if (reply.latencyMs < 0 && reply.latencyMs != StreamDescriptor::LATENCY_UNKNOWN) {
1141 LOG(ERROR) << __func__ << ": received invalid latency value: " << reply.latencyMs;
1142 return Status::ABORT;
1143 }
1144 if (reply.xrunFrames < 0) {
1145 LOG(ERROR) << __func__ << ": received invalid xrunFrames value: " << reply.xrunFrames;
1146 return Status::ABORT;
1147 }
1148 if (std::find(enum_range<StreamDescriptor::State>().begin(),
1149 enum_range<StreamDescriptor::State>().end(),
1150 reply.state) == enum_range<StreamDescriptor::State>().end()) {
1151 LOG(ERROR) << __func__ << ": received invalid stream state: " << toString(reply.state);
1152 return Status::ABORT;
1153 }
1154 if (getDriver()->processValidReply(reply)) {
1155 return Status::CONTINUE;
1156 }
1157 LOG(ERROR) << __func__ << ": unacceptable reply: " << reply.toString();
1158 return Status::ABORT;
1159 }
1160 };
1161 using StreamWriter = StreamWorker<StreamWriterLogic>;
1162
1163 class DefaultStreamCallback : public ::aidl::android::hardware::audio::core::BnStreamCallback,
1164 public StreamEventReceiver {
onTransferReady()1165 ndk::ScopedAStatus onTransferReady() override {
1166 LOG(DEBUG) << __func__;
1167 putLastEvent(Event::TransferReady);
1168 return ndk::ScopedAStatus::ok();
1169 }
onError()1170 ndk::ScopedAStatus onError() override {
1171 LOG(DEBUG) << __func__;
1172 putLastEvent(Event::Error);
1173 return ndk::ScopedAStatus::ok();
1174 }
onDrainReady()1175 ndk::ScopedAStatus onDrainReady() override {
1176 LOG(DEBUG) << __func__;
1177 putLastEvent(Event::DrainReady);
1178 return ndk::ScopedAStatus::ok();
1179 }
1180
1181 public:
1182 // To avoid timing out the whole test suite in case no event is received
1183 // from the HAL, use a local timeout for event waiting.
1184 static constexpr auto kEventTimeoutMs = std::chrono::milliseconds(1000);
1185
getEventReceiver()1186 StreamEventReceiver* getEventReceiver() { return this; }
getLastEvent() const1187 std::tuple<int, Event> getLastEvent() const override {
1188 std::lock_guard l(mLock);
1189 return getLastEvent_l();
1190 }
waitForEvent(int clientEventSeq)1191 std::tuple<int, Event> waitForEvent(int clientEventSeq) override {
1192 std::unique_lock l(mLock);
1193 android::base::ScopedLockAssertion lock_assertion(mLock);
1194 LOG(DEBUG) << __func__ << ": client " << clientEventSeq << ", last " << mLastEventSeq;
1195 if (mCv.wait_for(l, kEventTimeoutMs, [&]() {
1196 android::base::ScopedLockAssertion lock_assertion(mLock);
1197 return clientEventSeq < mLastEventSeq;
1198 })) {
1199 } else {
1200 LOG(WARNING) << __func__ << ": timed out waiting for an event";
1201 putLastEvent_l(Event::None);
1202 }
1203 return getLastEvent_l();
1204 }
1205
1206 private:
getLastEvent_l() const1207 std::tuple<int, Event> getLastEvent_l() const REQUIRES(mLock) {
1208 return std::make_tuple(mLastEventSeq, mLastEvent);
1209 }
putLastEvent(Event event)1210 void putLastEvent(Event event) {
1211 {
1212 std::lock_guard l(mLock);
1213 putLastEvent_l(event);
1214 }
1215 mCv.notify_one();
1216 }
putLastEvent_l(Event event)1217 void putLastEvent_l(Event event) REQUIRES(mLock) {
1218 mLastEventSeq++;
1219 mLastEvent = event;
1220 }
1221
1222 mutable std::mutex mLock;
1223 std::condition_variable mCv;
1224 int mLastEventSeq GUARDED_BY(mLock) = kEventSeqInit;
1225 Event mLastEvent GUARDED_BY(mLock) = Event::None;
1226 };
1227
1228 template <typename T>
1229 struct IOTraits {
1230 static constexpr bool is_input = std::is_same_v<T, IStreamIn>;
1231 static constexpr const char* directionStr = is_input ? "input" : "output";
1232 using Worker = std::conditional_t<is_input, StreamReader, StreamWriter>;
1233 };
1234
1235 template <typename Stream>
1236 class WithStream {
1237 public:
callClose(std::shared_ptr<Stream> stream)1238 static ndk::ScopedAStatus callClose(std::shared_ptr<Stream> stream) {
1239 std::shared_ptr<IStreamCommon> common;
1240 ndk::ScopedAStatus status = stream->getStreamCommon(&common);
1241 if (!status.isOk()) return status;
1242 status = common->prepareToClose();
1243 if (!status.isOk()) return status;
1244 return common->close();
1245 }
1246
1247 WithStream() = default;
WithStream(const AudioPortConfig & portConfig)1248 explicit WithStream(const AudioPortConfig& portConfig) : mPortConfig(portConfig) {}
1249 WithStream(const WithStream&) = delete;
1250 WithStream& operator=(const WithStream&) = delete;
~WithStream()1251 ~WithStream() {
1252 if (mStream != nullptr) {
1253 mContext.reset();
1254 EXPECT_IS_OK(callClose(mStream)) << "port config id " << getPortId();
1255 }
1256 }
SetUpPortConfig(IModule * module)1257 void SetUpPortConfig(IModule* module) { ASSERT_NO_FATAL_FAILURE(mPortConfig.SetUp(module)); }
SetUpNoChecks(IModule * module,long bufferSizeFrames)1258 ScopedAStatus SetUpNoChecks(IModule* module, long bufferSizeFrames) {
1259 return SetUpNoChecks(module, mPortConfig.get(), bufferSizeFrames);
1260 }
1261 ScopedAStatus SetUpNoChecks(IModule* module, const AudioPortConfig& portConfig,
1262 long bufferSizeFrames);
SetUpStream(IModule * module,long bufferSizeFrames)1263 void SetUpStream(IModule* module, long bufferSizeFrames) {
1264 ASSERT_IS_OK(SetUpNoChecks(module, bufferSizeFrames)) << "port config id " << getPortId();
1265 ASSERT_NE(nullptr, mStream) << "port config id " << getPortId();
1266 EXPECT_GE(mDescriptor.bufferSizeFrames, bufferSizeFrames)
1267 << "actual buffer size must be no less than requested";
1268 mContext.emplace(mDescriptor);
1269 ASSERT_NO_FATAL_FAILURE(mContext.value().checkIsValid());
1270 }
SetUp(IModule * module,long bufferSizeFrames)1271 void SetUp(IModule* module, long bufferSizeFrames) {
1272 ASSERT_NO_FATAL_FAILURE(SetUpPortConfig(module));
1273 ASSERT_NO_FATAL_FAILURE(SetUpStream(module, bufferSizeFrames));
1274 }
get() const1275 Stream* get() const { return mStream.get(); }
getContext() const1276 const StreamContext* getContext() const { return mContext ? &(mContext.value()) : nullptr; }
getEventReceiver()1277 StreamEventReceiver* getEventReceiver() { return mStreamCallback->getEventReceiver(); }
getSharedPointer() const1278 std::shared_ptr<Stream> getSharedPointer() const { return mStream; }
getPortConfig() const1279 const AudioPortConfig& getPortConfig() const { return mPortConfig.get(); }
getPortId() const1280 int32_t getPortId() const { return mPortConfig.getId(); }
1281
1282 private:
1283 WithAudioPortConfig mPortConfig;
1284 std::shared_ptr<Stream> mStream;
1285 StreamDescriptor mDescriptor;
1286 std::optional<StreamContext> mContext;
1287 std::shared_ptr<DefaultStreamCallback> mStreamCallback;
1288 };
1289
GenerateSinkMetadata(const AudioPortConfig & portConfig)1290 SinkMetadata GenerateSinkMetadata(const AudioPortConfig& portConfig) {
1291 RecordTrackMetadata trackMeta;
1292 trackMeta.source = AudioSource::MIC;
1293 trackMeta.gain = 1.0;
1294 trackMeta.channelMask = portConfig.channelMask.value();
1295 SinkMetadata metadata;
1296 metadata.tracks.push_back(trackMeta);
1297 return metadata;
1298 }
1299
1300 template <>
SetUpNoChecks(IModule * module,const AudioPortConfig & portConfig,long bufferSizeFrames)1301 ScopedAStatus WithStream<IStreamIn>::SetUpNoChecks(IModule* module,
1302 const AudioPortConfig& portConfig,
1303 long bufferSizeFrames) {
1304 aidl::android::hardware::audio::core::IModule::OpenInputStreamArguments args;
1305 args.portConfigId = portConfig.id;
1306 args.sinkMetadata = GenerateSinkMetadata(portConfig);
1307 args.bufferSizeFrames = bufferSizeFrames;
1308 auto callback = ndk::SharedRefBase::make<DefaultStreamCallback>();
1309 // TODO: Uncomment when support for asynchronous input is implemented.
1310 // args.callback = callback;
1311 aidl::android::hardware::audio::core::IModule::OpenInputStreamReturn ret;
1312 ScopedAStatus status = module->openInputStream(args, &ret);
1313 if (status.isOk()) {
1314 mStream = std::move(ret.stream);
1315 mDescriptor = std::move(ret.desc);
1316 mStreamCallback = std::move(callback);
1317 }
1318 return status;
1319 }
1320
GenerateSourceMetadata(const AudioPortConfig & portConfig)1321 SourceMetadata GenerateSourceMetadata(const AudioPortConfig& portConfig) {
1322 PlaybackTrackMetadata trackMeta;
1323 trackMeta.usage = AudioUsage::MEDIA;
1324 trackMeta.contentType = AudioContentType::MUSIC;
1325 trackMeta.gain = 1.0;
1326 trackMeta.channelMask = portConfig.channelMask.value();
1327 SourceMetadata metadata;
1328 metadata.tracks.push_back(trackMeta);
1329 return metadata;
1330 }
1331
1332 template <>
SetUpNoChecks(IModule * module,const AudioPortConfig & portConfig,long bufferSizeFrames)1333 ScopedAStatus WithStream<IStreamOut>::SetUpNoChecks(IModule* module,
1334 const AudioPortConfig& portConfig,
1335 long bufferSizeFrames) {
1336 aidl::android::hardware::audio::core::IModule::OpenOutputStreamArguments args;
1337 args.portConfigId = portConfig.id;
1338 args.sourceMetadata = GenerateSourceMetadata(portConfig);
1339 args.offloadInfo = ModuleConfig::generateOffloadInfoIfNeeded(portConfig);
1340 args.bufferSizeFrames = bufferSizeFrames;
1341 auto callback = ndk::SharedRefBase::make<DefaultStreamCallback>();
1342 args.callback = callback;
1343 aidl::android::hardware::audio::core::IModule::OpenOutputStreamReturn ret;
1344 ScopedAStatus status = module->openOutputStream(args, &ret);
1345 if (status.isOk()) {
1346 mStream = std::move(ret.stream);
1347 mDescriptor = std::move(ret.desc);
1348 mStreamCallback = std::move(callback);
1349 }
1350 return status;
1351 }
1352
1353 class WithAudioPatch {
1354 public:
1355 WithAudioPatch() = default;
WithAudioPatch(const AudioPortConfig & srcPortConfig,const AudioPortConfig & sinkPortConfig)1356 WithAudioPatch(const AudioPortConfig& srcPortConfig, const AudioPortConfig& sinkPortConfig)
1357 : mSrcPortConfig(srcPortConfig), mSinkPortConfig(sinkPortConfig) {}
WithAudioPatch(bool sinkIsCfg1,const AudioPortConfig & portConfig1,const AudioPortConfig & portConfig2)1358 WithAudioPatch(bool sinkIsCfg1, const AudioPortConfig& portConfig1,
1359 const AudioPortConfig& portConfig2)
1360 : mSrcPortConfig(sinkIsCfg1 ? portConfig2 : portConfig1),
1361 mSinkPortConfig(sinkIsCfg1 ? portConfig1 : portConfig2) {}
WithAudioPatch(const WithAudioPatch & patch,const AudioPortConfig & srcPortConfig,const AudioPortConfig & sinkPortConfig)1362 WithAudioPatch(const WithAudioPatch& patch, const AudioPortConfig& srcPortConfig,
1363 const AudioPortConfig& sinkPortConfig)
1364 : mInitialPatch(patch.mPatch),
1365 mSrcPortConfig(srcPortConfig),
1366 mSinkPortConfig(sinkPortConfig),
1367 mModule(patch.mModule),
1368 mPatch(patch.mPatch) {}
1369 WithAudioPatch(const WithAudioPatch&) = delete;
1370 WithAudioPatch& operator=(const WithAudioPatch&) = delete;
~WithAudioPatch()1371 ~WithAudioPatch() {
1372 if (mModule != nullptr && mPatch.id != 0) {
1373 if (mInitialPatch.has_value()) {
1374 AudioPatch ignored;
1375 // This releases our port configs so that they can be reset.
1376 EXPECT_IS_OK(mModule->setAudioPatch(*mInitialPatch, &ignored))
1377 << "patch id " << mInitialPatch->id;
1378 } else {
1379 EXPECT_IS_OK(mModule->resetAudioPatch(mPatch.id)) << "patch id " << getId();
1380 }
1381 }
1382 }
SetUpPortConfigs(IModule * module)1383 void SetUpPortConfigs(IModule* module) {
1384 ASSERT_NO_FATAL_FAILURE(mSrcPortConfig.SetUp(module));
1385 ASSERT_NO_FATAL_FAILURE(mSinkPortConfig.SetUp(module));
1386 }
SetUpNoChecks(IModule * module)1387 ScopedAStatus SetUpNoChecks(IModule* module) {
1388 mModule = module;
1389 mPatch.sourcePortConfigIds = std::vector<int32_t>{mSrcPortConfig.getId()};
1390 mPatch.sinkPortConfigIds = std::vector<int32_t>{mSinkPortConfig.getId()};
1391 return mModule->setAudioPatch(mPatch, &mPatch);
1392 }
SetUp(IModule * module)1393 void SetUp(IModule* module) {
1394 ASSERT_NO_FATAL_FAILURE(SetUpPortConfigs(module));
1395 ASSERT_IS_OK(SetUpNoChecks(module)) << "source port config id " << mSrcPortConfig.getId()
1396 << "; sink port config id " << mSinkPortConfig.getId();
1397 EXPECT_GT(mPatch.minimumStreamBufferSizeFrames, 0) << "patch id " << getId();
1398 for (auto latencyMs : mPatch.latenciesMs) {
1399 EXPECT_GT(latencyMs, 0) << "patch id " << getId();
1400 }
1401 }
VerifyAgainstAllPatches(IModule * module)1402 void VerifyAgainstAllPatches(IModule* module) {
1403 std::vector<AudioPatch> allPatches;
1404 ASSERT_IS_OK(module->getAudioPatches(&allPatches));
1405 const auto& patchIt = findById(allPatches, getId());
1406 ASSERT_NE(patchIt, allPatches.end()) << "patch id " << getId();
1407 if (get() != *patchIt) {
1408 FAIL() << "Stored patch: " << get().toString() << " is not the same as returned "
1409 << "by the HAL module: " << patchIt->toString();
1410 }
1411 }
getId() const1412 int32_t getId() const { return mPatch.id; }
get() const1413 const AudioPatch& get() const { return mPatch; }
getMinimumStreamBufferSizeFrames() const1414 int32_t getMinimumStreamBufferSizeFrames() const {
1415 return mPatch.minimumStreamBufferSizeFrames;
1416 }
getSinkPortConfig() const1417 const AudioPortConfig& getSinkPortConfig() const { return mSinkPortConfig.get(); }
getSrcPortConfig() const1418 const AudioPortConfig& getSrcPortConfig() const { return mSrcPortConfig.get(); }
getPortConfig(bool getSink) const1419 const AudioPortConfig& getPortConfig(bool getSink) const {
1420 return getSink ? getSinkPortConfig() : getSrcPortConfig();
1421 }
1422
1423 private:
1424 std::optional<AudioPatch> mInitialPatch;
1425 WithAudioPortConfig mSrcPortConfig;
1426 WithAudioPortConfig mSinkPortConfig;
1427 IModule* mModule = nullptr;
1428 AudioPatch mPatch;
1429 };
1430
TEST_P(AudioCoreModule,Published)1431 TEST_P(AudioCoreModule, Published) {
1432 // SetUp must complete with no failures.
1433 }
1434
TEST_P(AudioCoreModule,CanBeRestarted)1435 TEST_P(AudioCoreModule, CanBeRestarted) {
1436 ASSERT_NO_FATAL_FAILURE(RestartService());
1437 }
1438
TEST_P(AudioCoreModule,PortIdsAreUnique)1439 TEST_P(AudioCoreModule, PortIdsAreUnique) {
1440 std::set<int32_t> portIds;
1441 ASSERT_NO_FATAL_FAILURE(GetAllPortIds(&portIds));
1442 }
1443
TEST_P(AudioCoreModule,GetAudioPortsIsStable)1444 TEST_P(AudioCoreModule, GetAudioPortsIsStable) {
1445 std::vector<AudioPort> ports1;
1446 ASSERT_IS_OK(module->getAudioPorts(&ports1));
1447 std::vector<AudioPort> ports2;
1448 ASSERT_IS_OK(module->getAudioPorts(&ports2));
1449 EXPECT_NO_FATAL_FAILURE(VerifyVectorsAreEqual<AudioPort>(ports1, ports2))
1450 << "Audio port arrays do not match across consequent calls to getAudioPorts";
1451 }
1452
TEST_P(AudioCoreModule,GetAudioRoutesIsStable)1453 TEST_P(AudioCoreModule, GetAudioRoutesIsStable) {
1454 std::vector<AudioRoute> routes1;
1455 ASSERT_IS_OK(module->getAudioRoutes(&routes1));
1456 std::vector<AudioRoute> routes2;
1457 ASSERT_IS_OK(module->getAudioRoutes(&routes2));
1458 EXPECT_NO_FATAL_FAILURE(VerifyVectorsAreEqual<AudioRoute>(routes1, routes2))
1459 << " Audio route arrays do not match across consequent calls to getAudioRoutes";
1460 }
1461
TEST_P(AudioCoreModule,GetAudioRoutesAreValid)1462 TEST_P(AudioCoreModule, GetAudioRoutesAreValid) {
1463 std::vector<AudioRoute> routes;
1464 ASSERT_IS_OK(module->getAudioRoutes(&routes));
1465 for (const auto& route : routes) {
1466 std::set<int32_t> sources(route.sourcePortIds.begin(), route.sourcePortIds.end());
1467 EXPECT_NE(0UL, sources.size())
1468 << "empty audio port sinks in the audio route: " << route.toString();
1469 EXPECT_EQ(sources.size(), route.sourcePortIds.size())
1470 << "IDs of audio port sinks are not unique in the audio route: "
1471 << route.toString();
1472 }
1473 }
1474
TEST_P(AudioCoreModule,GetAudioRoutesPortIdsAreValid)1475 TEST_P(AudioCoreModule, GetAudioRoutesPortIdsAreValid) {
1476 std::set<int32_t> portIds;
1477 ASSERT_NO_FATAL_FAILURE(GetAllPortIds(&portIds));
1478 std::vector<AudioRoute> routes;
1479 ASSERT_IS_OK(module->getAudioRoutes(&routes));
1480 for (const auto& route : routes) {
1481 EXPECT_EQ(1UL, portIds.count(route.sinkPortId))
1482 << route.sinkPortId << " sink port id is unknown";
1483 for (const auto& source : route.sourcePortIds) {
1484 EXPECT_EQ(1UL, portIds.count(source)) << source << " source port id is unknown";
1485 }
1486 }
1487 }
1488
TEST_P(AudioCoreModule,GetAudioRoutesForAudioPort)1489 TEST_P(AudioCoreModule, GetAudioRoutesForAudioPort) {
1490 std::set<int32_t> portIds;
1491 ASSERT_NO_FATAL_FAILURE(GetAllPortIds(&portIds));
1492 if (portIds.empty()) {
1493 GTEST_SKIP() << "No ports in the module.";
1494 }
1495 for (const auto portId : portIds) {
1496 std::vector<AudioRoute> routes;
1497 EXPECT_IS_OK(module->getAudioRoutesForAudioPort(portId, &routes));
1498 for (const auto& r : routes) {
1499 if (r.sinkPortId != portId) {
1500 const auto& srcs = r.sourcePortIds;
1501 EXPECT_TRUE(std::find(srcs.begin(), srcs.end(), portId) != srcs.end())
1502 << " port ID " << portId << " does not used by the route " << r.toString();
1503 }
1504 }
1505 }
1506 for (const auto portId : GetNonExistentIds(portIds)) {
1507 std::vector<AudioRoute> routes;
1508 EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->getAudioRoutesForAudioPort(portId, &routes))
1509 << "port ID " << portId;
1510 }
1511 }
1512
TEST_P(AudioCoreModule,CheckDevicePorts)1513 TEST_P(AudioCoreModule, CheckDevicePorts) {
1514 std::vector<AudioPort> ports;
1515 ASSERT_IS_OK(module->getAudioPorts(&ports));
1516 std::optional<int32_t> defaultOutput, defaultInput;
1517 std::set<AudioDevice> inputs, outputs;
1518 const int defaultDeviceFlag = 1 << AudioPortDeviceExt::FLAG_INDEX_DEFAULT_DEVICE;
1519 for (const auto& port : ports) {
1520 if (port.ext.getTag() != AudioPortExt::Tag::device) continue;
1521 const AudioPortDeviceExt& devicePort = port.ext.get<AudioPortExt::Tag::device>();
1522 EXPECT_NE(AudioDeviceType::NONE, devicePort.device.type.type);
1523 EXPECT_NE(AudioDeviceType::IN_DEFAULT, devicePort.device.type.type);
1524 EXPECT_NE(AudioDeviceType::OUT_DEFAULT, devicePort.device.type.type);
1525 if (devicePort.device.type.type > AudioDeviceType::IN_DEFAULT &&
1526 devicePort.device.type.type < AudioDeviceType::OUT_DEFAULT) {
1527 EXPECT_EQ(AudioIoFlags::Tag::input, port.flags.getTag());
1528 } else if (devicePort.device.type.type > AudioDeviceType::OUT_DEFAULT) {
1529 EXPECT_EQ(AudioIoFlags::Tag::output, port.flags.getTag());
1530 }
1531 EXPECT_FALSE((devicePort.flags & defaultDeviceFlag) != 0 &&
1532 !devicePort.device.type.connection.empty())
1533 << "Device port " << port.id
1534 << " must be permanently attached to be set as default";
1535 if ((devicePort.flags & defaultDeviceFlag) != 0) {
1536 if (port.flags.getTag() == AudioIoFlags::Tag::output) {
1537 EXPECT_FALSE(defaultOutput.has_value())
1538 << "At least two output device ports are declared as default: "
1539 << defaultOutput.value() << " and " << port.id;
1540 defaultOutput = port.id;
1541 EXPECT_EQ(0UL, outputs.count(devicePort.device))
1542 << "Non-unique output device: " << devicePort.device.toString();
1543 outputs.insert(devicePort.device);
1544 } else if (port.flags.getTag() == AudioIoFlags::Tag::input) {
1545 EXPECT_FALSE(defaultInput.has_value())
1546 << "At least two input device ports are declared as default: "
1547 << defaultInput.value() << " and " << port.id;
1548 defaultInput = port.id;
1549 EXPECT_EQ(0UL, inputs.count(devicePort.device))
1550 << "Non-unique input device: " << devicePort.device.toString();
1551 inputs.insert(devicePort.device);
1552 } else {
1553 FAIL() << "Invalid AudioIoFlags Tag: " << toString(port.flags.getTag());
1554 }
1555 }
1556 // Speaker layout can be null or layoutMask variant.
1557 if (devicePort.speakerLayout.has_value()) {
1558 // Should only be set for output ports.
1559 EXPECT_EQ(AudioIoFlags::Tag::output, port.flags.getTag());
1560 const auto speakerLayoutTag = devicePort.speakerLayout.value().getTag();
1561 EXPECT_EQ(AudioChannelLayout::Tag::layoutMask, speakerLayoutTag)
1562 << "If set, speaker layout must be layoutMask. Received: "
1563 << toString(speakerLayoutTag);
1564 }
1565 }
1566 }
1567
TEST_P(AudioCoreModule,CheckMixPorts)1568 TEST_P(AudioCoreModule, CheckMixPorts) {
1569 std::vector<AudioPort> ports;
1570 ASSERT_IS_OK(module->getAudioPorts(&ports));
1571 std::optional<int32_t> primaryMixPort;
1572 for (const auto& port : ports) {
1573 if (port.ext.getTag() != AudioPortExt::Tag::mix) continue;
1574 const auto& mixPort = port.ext.get<AudioPortExt::Tag::mix>();
1575 if (port.flags.getTag() == AudioIoFlags::Tag::output &&
1576 isBitPositionFlagSet(port.flags.get<AudioIoFlags::Tag::output>(),
1577 AudioOutputFlags::PRIMARY)) {
1578 EXPECT_FALSE(primaryMixPort.has_value())
1579 << "At least two mix ports have PRIMARY flag set: " << primaryMixPort.value()
1580 << " and " << port.id;
1581 primaryMixPort = port.id;
1582 EXPECT_GE(mixPort.maxOpenStreamCount, 0)
1583 << "Primary mix port " << port.id << " can not have maxOpenStreamCount "
1584 << mixPort.maxOpenStreamCount;
1585 }
1586 }
1587 }
1588
TEST_P(AudioCoreModule,GetAudioPort)1589 TEST_P(AudioCoreModule, GetAudioPort) {
1590 std::set<int32_t> portIds;
1591 ASSERT_NO_FATAL_FAILURE(GetAllPortIds(&portIds));
1592 if (portIds.empty()) {
1593 GTEST_SKIP() << "No ports in the module.";
1594 }
1595 for (const auto portId : portIds) {
1596 AudioPort port;
1597 EXPECT_IS_OK(module->getAudioPort(portId, &port));
1598 EXPECT_EQ(portId, port.id);
1599 }
1600 for (const auto portId : GetNonExistentIds(portIds)) {
1601 AudioPort port;
1602 EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->getAudioPort(portId, &port))
1603 << "port ID " << portId;
1604 }
1605 }
1606
TEST_P(AudioCoreModule,SetUpModuleConfig)1607 TEST_P(AudioCoreModule, SetUpModuleConfig) {
1608 ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
1609 // Send the module config to logcat to facilitate failures investigation.
1610 LOG(INFO) << "SetUpModuleConfig: " << moduleConfig->toString();
1611 }
1612
1613 // Verify that HAL module reports for a connected device port at least one non-dynamic profile,
1614 // that is, a profile with actual supported configuration.
1615 // Note: This test relies on simulation of external device connections by the HAL module.
TEST_P(AudioCoreModule,GetAudioPortWithExternalDevices)1616 TEST_P(AudioCoreModule, GetAudioPortWithExternalDevices) {
1617 ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
1618 std::vector<AudioPort> ports = moduleConfig->getExternalDevicePorts();
1619 if (ports.empty()) {
1620 GTEST_SKIP() << "No external devices in the module.";
1621 }
1622 for (const auto& port : ports) {
1623 AudioPort portWithData = GenerateUniqueDeviceAddress(port);
1624 WithDevicePortConnectedState portConnected(portWithData);
1625 ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get(), moduleConfig.get()));
1626 const int32_t connectedPortId = portConnected.getId();
1627 ASSERT_NE(portWithData.id, connectedPortId);
1628 ASSERT_EQ(portWithData.ext.getTag(), portConnected.get().ext.getTag());
1629 EXPECT_EQ(portWithData.ext.get<AudioPortExt::Tag::device>().device,
1630 portConnected.get().ext.get<AudioPortExt::Tag::device>().device);
1631 // Verify that 'getAudioPort' and 'getAudioPorts' return the same connected port.
1632 AudioPort connectedPort;
1633 EXPECT_IS_OK(module->getAudioPort(connectedPortId, &connectedPort))
1634 << "port ID " << connectedPortId;
1635 EXPECT_EQ(portConnected.get(), connectedPort);
1636 const auto& portProfiles = connectedPort.profiles;
1637 if (portProfiles.empty()) {
1638 const auto routableMixPorts = moduleConfig->getRoutableMixPortsForDevicePort(
1639 connectedPort, true /*connectedOnly*/);
1640 bool hasMixPortWithStaticProfile = false;
1641 for (const auto& mixPort : routableMixPorts) {
1642 const auto& mixPortProfiles = mixPort.profiles;
1643 if (!mixPortProfiles.empty() &&
1644 !std::all_of(mixPortProfiles.begin(), mixPortProfiles.end(),
1645 [](const auto& profile) {
1646 return profile.format.type == AudioFormatType::DEFAULT;
1647 })) {
1648 hasMixPortWithStaticProfile = true;
1649 break;
1650 }
1651 }
1652 EXPECT_TRUE(hasMixPortWithStaticProfile)
1653 << "Connected port has no profiles and no routable mix ports with profiles: "
1654 << connectedPort.toString();
1655 }
1656 const auto dynamicProfileIt =
1657 std::find_if(portProfiles.begin(), portProfiles.end(), [](const auto& profile) {
1658 return profile.format.type == AudioFormatType::DEFAULT;
1659 });
1660 EXPECT_EQ(portProfiles.end(), dynamicProfileIt) << "Connected port contains dynamic "
1661 << "profiles: " << connectedPort.toString();
1662
1663 std::vector<AudioPort> allPorts;
1664 ASSERT_IS_OK(module->getAudioPorts(&allPorts));
1665 const auto allPortsIt = findById(allPorts, connectedPortId);
1666 EXPECT_NE(allPorts.end(), allPortsIt);
1667 if (allPortsIt != allPorts.end()) {
1668 EXPECT_EQ(portConnected.get(), *allPortsIt);
1669 }
1670 }
1671 }
1672
TEST_P(AudioCoreModule,OpenStreamInvalidPortConfigId)1673 TEST_P(AudioCoreModule, OpenStreamInvalidPortConfigId) {
1674 std::set<int32_t> portConfigIds;
1675 ASSERT_NO_FATAL_FAILURE(GetAllPortConfigIds(&portConfigIds));
1676 for (const auto portConfigId : GetNonExistentIds(portConfigIds)) {
1677 {
1678 aidl::android::hardware::audio::core::IModule::OpenInputStreamArguments args;
1679 args.portConfigId = portConfigId;
1680 args.bufferSizeFrames = kNegativeTestBufferSizeFrames;
1681 aidl::android::hardware::audio::core::IModule::OpenInputStreamReturn ret;
1682 EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->openInputStream(args, &ret))
1683 << "port config ID " << portConfigId;
1684 EXPECT_EQ(nullptr, ret.stream);
1685 }
1686 {
1687 aidl::android::hardware::audio::core::IModule::OpenOutputStreamArguments args;
1688 args.portConfigId = portConfigId;
1689 args.bufferSizeFrames = kNegativeTestBufferSizeFrames;
1690 aidl::android::hardware::audio::core::IModule::OpenOutputStreamReturn ret;
1691 EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->openOutputStream(args, &ret))
1692 << "port config ID " << portConfigId;
1693 EXPECT_EQ(nullptr, ret.stream);
1694 }
1695 }
1696 }
1697
TEST_P(AudioCoreModule,PortConfigIdsAreUnique)1698 TEST_P(AudioCoreModule, PortConfigIdsAreUnique) {
1699 std::set<int32_t> portConfigIds;
1700 ASSERT_NO_FATAL_FAILURE(GetAllPortConfigIds(&portConfigIds));
1701 }
1702
TEST_P(AudioCoreModule,PortConfigPortIdsAreValid)1703 TEST_P(AudioCoreModule, PortConfigPortIdsAreValid) {
1704 std::set<int32_t> portIds;
1705 ASSERT_NO_FATAL_FAILURE(GetAllPortIds(&portIds));
1706 std::vector<AudioPortConfig> portConfigs;
1707 ASSERT_IS_OK(module->getAudioPortConfigs(&portConfigs));
1708 for (const auto& config : portConfigs) {
1709 EXPECT_EQ(1UL, portIds.count(config.portId))
1710 << config.portId << " port id is unknown, config id " << config.id;
1711 }
1712 }
1713
TEST_P(AudioCoreModule,ResetAudioPortConfigInvalidId)1714 TEST_P(AudioCoreModule, ResetAudioPortConfigInvalidId) {
1715 std::set<int32_t> portConfigIds;
1716 ASSERT_NO_FATAL_FAILURE(GetAllPortConfigIds(&portConfigIds));
1717 for (const auto portConfigId : GetNonExistentIds(portConfigIds)) {
1718 EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->resetAudioPortConfig(portConfigId))
1719 << "port config ID " << portConfigId;
1720 }
1721 }
1722
1723 // Verify that for the audio port configs provided by the HAL after init, resetting
1724 // the config does not delete it, but brings it back to the initial config.
TEST_P(AudioCoreModule,ResetAudioPortConfigToInitialValue)1725 TEST_P(AudioCoreModule, ResetAudioPortConfigToInitialValue) {
1726 std::vector<AudioPortConfig> portConfigsBefore;
1727 ASSERT_IS_OK(module->getAudioPortConfigs(&portConfigsBefore));
1728 // TODO: Change port configs according to port profiles.
1729 for (const auto& c : portConfigsBefore) {
1730 EXPECT_IS_OK(module->resetAudioPortConfig(c.id)) << "port config ID " << c.id;
1731 }
1732 std::vector<AudioPortConfig> portConfigsAfter;
1733 ASSERT_IS_OK(module->getAudioPortConfigs(&portConfigsAfter));
1734 for (const auto& c : portConfigsBefore) {
1735 auto afterIt = findById<AudioPortConfig>(portConfigsAfter, c.id);
1736 EXPECT_NE(portConfigsAfter.end(), afterIt)
1737 << " port config ID " << c.id << " was removed by reset";
1738 if (afterIt != portConfigsAfter.end()) {
1739 EXPECT_TRUE(c == *afterIt)
1740 << "Expected: " << c.toString() << "; Actual: " << afterIt->toString();
1741 }
1742 }
1743 }
1744
TEST_P(AudioCoreModule,SetAudioPortConfigSuggestedConfig)1745 TEST_P(AudioCoreModule, SetAudioPortConfigSuggestedConfig) {
1746 ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
1747 auto srcMixPort = moduleConfig->getSourceMixPortForConnectedDevice();
1748 if (!srcMixPort.has_value()) {
1749 GTEST_SKIP() << "No mix port for attached output devices";
1750 }
1751 AudioPortConfig portConfig;
1752 AudioPortConfig suggestedConfig;
1753 portConfig.portId = srcMixPort.value().id;
1754 const int32_t kIoHandle = 42;
1755 portConfig.ext = AudioPortMixExt{.handle = kIoHandle};
1756 {
1757 bool applied = true;
1758 ASSERT_IS_OK(module->setAudioPortConfig(portConfig, &suggestedConfig, &applied))
1759 << "Config: " << portConfig.toString();
1760 EXPECT_FALSE(applied);
1761 }
1762 EXPECT_EQ(0, suggestedConfig.id);
1763 EXPECT_TRUE(suggestedConfig.sampleRate.has_value());
1764 EXPECT_TRUE(suggestedConfig.channelMask.has_value());
1765 EXPECT_TRUE(suggestedConfig.format.has_value());
1766 EXPECT_TRUE(suggestedConfig.flags.has_value());
1767 ASSERT_EQ(AudioPortExt::Tag::mix, suggestedConfig.ext.getTag());
1768 EXPECT_EQ(kIoHandle, suggestedConfig.ext.get<AudioPortExt::Tag::mix>().handle);
1769 WithAudioPortConfig applied(suggestedConfig);
1770 ASSERT_NO_FATAL_FAILURE(applied.SetUp(module.get()));
1771 const AudioPortConfig& appliedConfig = applied.get();
1772 EXPECT_NE(0, appliedConfig.id);
1773 ASSERT_TRUE(appliedConfig.sampleRate.has_value());
1774 EXPECT_EQ(suggestedConfig.sampleRate.value(), appliedConfig.sampleRate.value());
1775 ASSERT_TRUE(appliedConfig.channelMask.has_value());
1776 EXPECT_EQ(suggestedConfig.channelMask.value(), appliedConfig.channelMask.value());
1777 ASSERT_TRUE(appliedConfig.format.has_value());
1778 EXPECT_EQ(suggestedConfig.format.value(), appliedConfig.format.value());
1779 ASSERT_TRUE(appliedConfig.flags.has_value());
1780 EXPECT_EQ(suggestedConfig.flags.value(), appliedConfig.flags.value());
1781 ASSERT_EQ(AudioPortExt::Tag::mix, appliedConfig.ext.getTag());
1782 EXPECT_EQ(kIoHandle, appliedConfig.ext.get<AudioPortExt::Tag::mix>().handle);
1783 }
1784
TEST_P(AudioCoreModule,SetAllAttachedDevicePortConfigs)1785 TEST_P(AudioCoreModule, SetAllAttachedDevicePortConfigs) {
1786 ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
1787 ASSERT_NO_FATAL_FAILURE(ApplyEveryConfig(moduleConfig->getPortConfigsForAttachedDevicePorts()));
1788 }
1789
1790 // Note: This test relies on simulation of external device connections by the HAL module.
TEST_P(AudioCoreModule,SetAllExternalDevicePortConfigs)1791 TEST_P(AudioCoreModule, SetAllExternalDevicePortConfigs) {
1792 ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
1793 std::vector<AudioPort> ports = moduleConfig->getExternalDevicePorts();
1794 if (ports.empty()) {
1795 GTEST_SKIP() << "No external devices in the module.";
1796 }
1797 for (const auto& port : ports) {
1798 WithDevicePortConnectedState portConnected(GenerateUniqueDeviceAddress(port));
1799 ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get(), moduleConfig.get()));
1800 ASSERT_NO_FATAL_FAILURE(
1801 ApplyEveryConfig(moduleConfig->getPortConfigsForDevicePort(portConnected.get())));
1802 }
1803 }
1804
TEST_P(AudioCoreModule,SetAllStaticAudioPortConfigs)1805 TEST_P(AudioCoreModule, SetAllStaticAudioPortConfigs) {
1806 ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
1807 ASSERT_NO_FATAL_FAILURE(ApplyEveryConfig(moduleConfig->getPortConfigsForMixPorts()));
1808 }
1809
TEST_P(AudioCoreModule,SetAudioPortConfigInvalidPortId)1810 TEST_P(AudioCoreModule, SetAudioPortConfigInvalidPortId) {
1811 std::set<int32_t> portIds;
1812 ASSERT_NO_FATAL_FAILURE(GetAllPortIds(&portIds));
1813 for (const auto portId : GetNonExistentIds(portIds)) {
1814 AudioPortConfig portConfig, suggestedConfig;
1815 bool applied;
1816 portConfig.portId = portId;
1817 EXPECT_STATUS(EX_ILLEGAL_ARGUMENT,
1818 module->setAudioPortConfig(portConfig, &suggestedConfig, &applied))
1819 << "port ID " << portId;
1820 EXPECT_FALSE(suggestedConfig.format.has_value());
1821 EXPECT_FALSE(suggestedConfig.channelMask.has_value());
1822 EXPECT_FALSE(suggestedConfig.sampleRate.has_value());
1823 }
1824 }
1825
TEST_P(AudioCoreModule,SetAudioPortConfigInvalidPortConfigId)1826 TEST_P(AudioCoreModule, SetAudioPortConfigInvalidPortConfigId) {
1827 std::set<int32_t> portConfigIds;
1828 ASSERT_NO_FATAL_FAILURE(GetAllPortConfigIds(&portConfigIds));
1829 for (const auto portConfigId : GetNonExistentIds(portConfigIds)) {
1830 AudioPortConfig portConfig, suggestedConfig;
1831 bool applied;
1832 portConfig.id = portConfigId;
1833 EXPECT_STATUS(EX_ILLEGAL_ARGUMENT,
1834 module->setAudioPortConfig(portConfig, &suggestedConfig, &applied))
1835 << "port config ID " << portConfigId;
1836 EXPECT_FALSE(suggestedConfig.format.has_value());
1837 EXPECT_FALSE(suggestedConfig.channelMask.has_value());
1838 EXPECT_FALSE(suggestedConfig.sampleRate.has_value());
1839 }
1840 }
1841
TEST_P(AudioCoreModule,SetAudioPortConfigInvalidPortAudioGain)1842 TEST_P(AudioCoreModule, SetAudioPortConfigInvalidPortAudioGain) {
1843 ASSERT_GE(aidlVersion, kAidlVersion1);
1844 if (aidlVersion < kAidlVersion3) {
1845 GTEST_SKIP() << "Skip for audio HAL version lower than " << kAidlVersion3;
1846 }
1847 std::vector<AudioPort> ports;
1848 ASSERT_IS_OK(module->getAudioPorts(&ports));
1849 bool atLeastOnePortWithNonemptyGain = false;
1850 for (const auto port : ports) {
1851 AudioPortConfig portConfig;
1852 portConfig.portId = port.id;
1853 if (port.gains.empty()) {
1854 continue;
1855 }
1856 atLeastOnePortWithNonemptyGain = true;
1857 int index = 0;
1858 ASSERT_NE(0, port.gains[index].stepValue) << "Invalid audio port config gain step 0";
1859 portConfig.gain->index = index;
1860 AudioGainConfig invalidGainConfig;
1861
1862 int invalidGain = port.gains[index].maxValue + port.gains[index].stepValue;
1863 invalidGainConfig.values.push_back(invalidGain);
1864 portConfig.gain.emplace(invalidGainConfig);
1865 bool applied = true;
1866 AudioPortConfig suggestedConfig;
1867 EXPECT_STATUS(EX_ILLEGAL_ARGUMENT,
1868 module->setAudioPortConfig(portConfig, &suggestedConfig, &applied))
1869 << "invalid port gain " << invalidGain << " lower than min gain";
1870
1871 invalidGain = port.gains[index].minValue - port.gains[index].stepValue;
1872 invalidGainConfig.values[0] = invalidGain;
1873 portConfig.gain.emplace(invalidGainConfig);
1874 EXPECT_STATUS(EX_ILLEGAL_ARGUMENT,
1875 module->setAudioPortConfig(portConfig, &suggestedConfig, &applied))
1876 << "invalid port gain " << invalidGain << "higher than max gain";
1877 }
1878 if (!atLeastOnePortWithNonemptyGain) {
1879 GTEST_SKIP() << "No audio port contains non-empty gain configuration";
1880 }
1881 }
1882
TEST_P(AudioCoreModule,TryConnectMissingDevice)1883 TEST_P(AudioCoreModule, TryConnectMissingDevice) {
1884 // Limit checks to connection types that are known to be detectable by HAL implementations.
1885 static const std::set<std::string> kCheckedConnectionTypes{
1886 AudioDeviceDescription::CONNECTION_HDMI, AudioDeviceDescription::CONNECTION_HDMI_ARC,
1887 AudioDeviceDescription::CONNECTION_HDMI_EARC, AudioDeviceDescription::CONNECTION_IP_V4,
1888 AudioDeviceDescription::CONNECTION_USB};
1889 ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
1890 std::vector<AudioPort> ports = moduleConfig->getExternalDevicePorts();
1891 if (ports.empty()) {
1892 GTEST_SKIP() << "No external devices in the module.";
1893 }
1894 WithDebugFlags doNotSimulateConnections = WithDebugFlags::createNested(*debug);
1895 doNotSimulateConnections.flags().simulateDeviceConnections = false;
1896 ASSERT_NO_FATAL_FAILURE(doNotSimulateConnections.SetUp(module.get()));
1897 bool hasAtLeastOneCheckedConnection = false;
1898 for (const auto& port : ports) {
1899 if (kCheckedConnectionTypes.count(
1900 port.ext.get<AudioPortExt::device>().device.type.connection) == 0) {
1901 continue;
1902 }
1903 AudioPort portWithData = GenerateUniqueDeviceAddress(port), connectedPort;
1904 ScopedAStatus status = module->connectExternalDevice(portWithData, &connectedPort);
1905 EXPECT_STATUS(EX_ILLEGAL_STATE, status) << "static port " << portWithData.toString();
1906 if (status.isOk()) {
1907 EXPECT_IS_OK_OR_UNKNOWN_TRANSACTION(
1908 module->prepareToDisconnectExternalDevice(connectedPort.id))
1909 << "when preparing to disconnect device port ID " << connectedPort.id;
1910 EXPECT_IS_OK(module->disconnectExternalDevice(connectedPort.id))
1911 << "when disconnecting device port ID " << connectedPort.id;
1912 }
1913 hasAtLeastOneCheckedConnection = true;
1914 }
1915 if (!hasAtLeastOneCheckedConnection) {
1916 GTEST_SKIP() << "No external devices with connection types that can be checked.";
1917 }
1918 }
1919
TEST_P(AudioCoreModule,TryChangingConnectionSimulationMidway)1920 TEST_P(AudioCoreModule, TryChangingConnectionSimulationMidway) {
1921 ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
1922 std::vector<AudioPort> ports = moduleConfig->getExternalDevicePorts();
1923 if (ports.empty()) {
1924 GTEST_SKIP() << "No external devices in the module.";
1925 }
1926 WithDevicePortConnectedState portConnected(GenerateUniqueDeviceAddress(*ports.begin()));
1927 ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get(), moduleConfig.get()));
1928 ModuleDebug midwayDebugChange = debug->flags();
1929 midwayDebugChange.simulateDeviceConnections = false;
1930 EXPECT_STATUS(EX_ILLEGAL_STATE, module->setModuleDebug(midwayDebugChange))
1931 << "when trying to disable connections simulation while having a connected device";
1932 }
1933
TEST_P(AudioCoreModule,ConnectDisconnectExternalDeviceInvalidPorts)1934 TEST_P(AudioCoreModule, ConnectDisconnectExternalDeviceInvalidPorts) {
1935 AudioPort ignored;
1936 std::set<int32_t> portIds;
1937 ASSERT_NO_FATAL_FAILURE(GetAllPortIds(&portIds));
1938 for (const auto portId : GetNonExistentIds(portIds)) {
1939 AudioPort invalidPort;
1940 invalidPort.id = portId;
1941 EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->connectExternalDevice(invalidPort, &ignored))
1942 << "port ID " << portId << ", when setting CONNECTED state";
1943 EXPECT_STATUS_OR_UNKNOWN_TRANSACTION(EX_ILLEGAL_ARGUMENT,
1944 module->prepareToDisconnectExternalDevice(portId))
1945 << "port ID " << portId << ", when preparing to disconnect";
1946 EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->disconnectExternalDevice(portId))
1947 << "port ID " << portId << ", when setting DISCONNECTED state";
1948 }
1949
1950 std::vector<AudioPort> ports;
1951 ASSERT_IS_OK(module->getAudioPorts(&ports));
1952 for (const auto& port : ports) {
1953 if (port.ext.getTag() != AudioPortExt::Tag::device) {
1954 EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->connectExternalDevice(port, &ignored))
1955 << "non-device port ID " << port.id << " when setting CONNECTED state";
1956 EXPECT_STATUS_OR_UNKNOWN_TRANSACTION(EX_ILLEGAL_ARGUMENT,
1957 module->prepareToDisconnectExternalDevice(port.id))
1958 << "non-device port ID " << port.id << " when preparing to disconnect";
1959 EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->disconnectExternalDevice(port.id))
1960 << "non-device port ID " << port.id << " when setting DISCONNECTED state";
1961 } else {
1962 const auto& devicePort = port.ext.get<AudioPortExt::Tag::device>();
1963 if (devicePort.device.type.connection.empty()) {
1964 EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->connectExternalDevice(port, &ignored))
1965 << "for a permanently attached device port ID " << port.id
1966 << " when setting CONNECTED state";
1967 EXPECT_STATUS_OR_UNKNOWN_TRANSACTION(
1968 EX_ILLEGAL_ARGUMENT, module->prepareToDisconnectExternalDevice(port.id))
1969 << "for a permanently attached device port ID " << port.id
1970 << " when preparing to disconnect";
1971 EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->disconnectExternalDevice(port.id))
1972 << "for a permanently attached device port ID " << port.id
1973 << " when setting DISCONNECTED state";
1974 }
1975 }
1976 }
1977 }
1978
1979 // Note: This test relies on simulation of external device connections by the HAL module.
TEST_P(AudioCoreModule,ConnectDisconnectExternalDeviceTwice)1980 TEST_P(AudioCoreModule, ConnectDisconnectExternalDeviceTwice) {
1981 ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
1982 AudioPort ignored;
1983 std::vector<AudioPort> ports = moduleConfig->getExternalDevicePorts();
1984 if (ports.empty()) {
1985 GTEST_SKIP() << "No external devices in the module.";
1986 }
1987 for (const auto& port : ports) {
1988 EXPECT_STATUS_OR_UNKNOWN_TRANSACTION(EX_ILLEGAL_ARGUMENT,
1989 module->prepareToDisconnectExternalDevice(port.id))
1990 << "when preparing to disconnect already disconnected device port ID " << port.id;
1991 EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->disconnectExternalDevice(port.id))
1992 << "when disconnecting already disconnected device port ID " << port.id;
1993 AudioPort portWithData = GenerateUniqueDeviceAddress(port);
1994 WithDevicePortConnectedState portConnected(portWithData);
1995 ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get(), moduleConfig.get()));
1996 EXPECT_STATUS(EX_ILLEGAL_ARGUMENT,
1997 module->connectExternalDevice(portConnected.get(), &ignored))
1998 << "when trying to connect a connected device port "
1999 << portConnected.get().toString();
2000 EXPECT_STATUS(EX_ILLEGAL_STATE, module->connectExternalDevice(portWithData, &ignored))
2001 << "when connecting again the external device "
2002 << portWithData.ext.get<AudioPortExt::Tag::device>().device.toString()
2003 << "; Returned connected port " << ignored.toString() << " for template "
2004 << portWithData.toString();
2005 }
2006 }
2007
2008 // Note: This test relies on simulation of external device connections by the HAL module.
TEST_P(AudioCoreModule,DisconnectExternalDeviceNonResetPortConfig)2009 TEST_P(AudioCoreModule, DisconnectExternalDeviceNonResetPortConfig) {
2010 ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
2011 std::vector<AudioPort> ports = moduleConfig->getExternalDevicePorts();
2012 if (ports.empty()) {
2013 GTEST_SKIP() << "No external devices in the module.";
2014 }
2015 for (const auto& port : ports) {
2016 WithDevicePortConnectedState portConnected(GenerateUniqueDeviceAddress(port));
2017 ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get(), moduleConfig.get()));
2018 const auto portConfig = moduleConfig->getSingleConfigForDevicePort(portConnected.get());
2019 {
2020 WithAudioPortConfig config(portConfig);
2021 // Note: if SetUp fails, check the status of 'GetAudioPortWithExternalDevices' test.
2022 // Our test assumes that 'getAudioPort' returns at least one profile, and it
2023 // is not a dynamic profile.
2024 ASSERT_NO_FATAL_FAILURE(config.SetUp(module.get()));
2025 EXPECT_IS_OK_OR_UNKNOWN_TRANSACTION(
2026 module->prepareToDisconnectExternalDevice(portConnected.getId()))
2027 << "when preparing to disconnect device port ID " << port.id
2028 << " with active configuration " << config.getId();
2029 EXPECT_STATUS(EX_ILLEGAL_STATE, module->disconnectExternalDevice(portConnected.getId()))
2030 << "when trying to disconnect device port ID " << port.id
2031 << " with active configuration " << config.getId();
2032 }
2033 }
2034 }
2035
TEST_P(AudioCoreModule,ExternalDevicePortRoutes)2036 TEST_P(AudioCoreModule, ExternalDevicePortRoutes) {
2037 ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
2038 std::vector<AudioPort> ports = moduleConfig->getExternalDevicePorts();
2039 if (ports.empty()) {
2040 GTEST_SKIP() << "No external devices in the module.";
2041 }
2042 for (const auto& port : ports) {
2043 std::vector<AudioRoute> routesBefore;
2044 ASSERT_IS_OK(module->getAudioRoutes(&routesBefore));
2045
2046 int32_t connectedPortId;
2047 {
2048 WithDevicePortConnectedState portConnected(GenerateUniqueDeviceAddress(port));
2049 ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get(), moduleConfig.get()));
2050 connectedPortId = portConnected.getId();
2051 std::vector<AudioRoute> connectedPortRoutes;
2052 ASSERT_IS_OK(module->getAudioRoutesForAudioPort(connectedPortId, &connectedPortRoutes))
2053 << "when retrieving routes for connected port id " << connectedPortId;
2054 // There must be routes for the port to be useful.
2055 if (connectedPortRoutes.empty()) {
2056 std::vector<AudioRoute> allRoutes;
2057 ASSERT_IS_OK(module->getAudioRoutes(&allRoutes));
2058 ADD_FAILURE() << " no routes returned for the connected port "
2059 << portConnected.get().toString()
2060 << "; all routes: " << android::internal::ToString(allRoutes);
2061 }
2062 }
2063 std::vector<AudioRoute> ignored;
2064 ASSERT_STATUS(EX_ILLEGAL_ARGUMENT,
2065 module->getAudioRoutesForAudioPort(connectedPortId, &ignored))
2066 << "when retrieving routes for released connected port id " << connectedPortId;
2067
2068 std::vector<AudioRoute> routesAfter;
2069 ASSERT_IS_OK(module->getAudioRoutes(&routesAfter));
2070 ASSERT_EQ(routesBefore.size(), routesAfter.size())
2071 << "Sizes of audio route arrays do not match after creating and "
2072 << "releasing a connected port";
2073 std::sort(routesBefore.begin(), routesBefore.end());
2074 std::sort(routesAfter.begin(), routesAfter.end());
2075 EXPECT_EQ(routesBefore, routesAfter);
2076 }
2077 }
2078
2079 class RoutedPortsProfilesSnapshot {
2080 public:
RoutedPortsProfilesSnapshot(int32_t portId)2081 explicit RoutedPortsProfilesSnapshot(int32_t portId) : mPortId(portId) {}
Capture(IModule * module)2082 void Capture(IModule* module) {
2083 std::vector<AudioRoute> routes;
2084 ASSERT_IS_OK(module->getAudioRoutesForAudioPort(mPortId, &routes));
2085 std::vector<AudioPort> allPorts;
2086 ASSERT_IS_OK(module->getAudioPorts(&allPorts));
2087 ASSERT_NO_FATAL_FAILURE(GetAllRoutedPorts(routes, allPorts));
2088 ASSERT_NO_FATAL_FAILURE(GetProfileSizes());
2089 }
VerifyNoProfilesChanges(const RoutedPortsProfilesSnapshot & before)2090 void VerifyNoProfilesChanges(const RoutedPortsProfilesSnapshot& before) {
2091 for (const auto& p : before.mRoutedPorts) {
2092 auto beforeIt = before.mPortProfileSizes.find(p.id);
2093 ASSERT_NE(beforeIt, before.mPortProfileSizes.end())
2094 << "port ID " << p.id << " not found in the initial profile sizes";
2095 EXPECT_EQ(beforeIt->second, mPortProfileSizes[p.id])
2096 << " port " << p.toString() << " has an unexpected profile size change"
2097 << " following an external device connection and disconnection";
2098 }
2099 }
VerifyProfilesNonEmpty()2100 void VerifyProfilesNonEmpty() {
2101 for (const auto& p : mRoutedPorts) {
2102 EXPECT_NE(0UL, mPortProfileSizes[p.id])
2103 << " port " << p.toString() << " must have had its profiles"
2104 << " populated while having a connected external device";
2105 }
2106 }
2107
getRoutedPorts() const2108 const std::vector<AudioPort>& getRoutedPorts() const { return mRoutedPorts; }
2109
2110 private:
GetAllRoutedPorts(const std::vector<AudioRoute> & routes,std::vector<AudioPort> & allPorts)2111 void GetAllRoutedPorts(const std::vector<AudioRoute>& routes,
2112 std::vector<AudioPort>& allPorts) {
2113 for (const auto& r : routes) {
2114 if (r.sinkPortId == mPortId) {
2115 for (const auto& srcPortId : r.sourcePortIds) {
2116 const auto srcPortIt = findById(allPorts, srcPortId);
2117 ASSERT_NE(allPorts.end(), srcPortIt) << "port ID " << srcPortId;
2118 mRoutedPorts.push_back(*srcPortIt);
2119 }
2120 } else {
2121 const auto sinkPortIt = findById(allPorts, r.sinkPortId);
2122 ASSERT_NE(allPorts.end(), sinkPortIt) << "port ID " << r.sinkPortId;
2123 mRoutedPorts.push_back(*sinkPortIt);
2124 }
2125 }
2126 }
GetProfileSizes()2127 void GetProfileSizes() {
2128 std::transform(
2129 mRoutedPorts.begin(), mRoutedPorts.end(),
2130 std::inserter(mPortProfileSizes, mPortProfileSizes.end()),
2131 [](const auto& port) { return std::make_pair(port.id, port.profiles.size()); });
2132 }
2133
2134 const int32_t mPortId;
2135 std::vector<AudioPort> mRoutedPorts;
2136 std::map<int32_t, size_t> mPortProfileSizes;
2137 };
2138
2139 // Note: This test relies on simulation of external device connections by the HAL module.
TEST_P(AudioCoreModule,ExternalDeviceMixPortConfigs)2140 TEST_P(AudioCoreModule, ExternalDeviceMixPortConfigs) {
2141 // After an external device has been connected, all mix ports that can be routed
2142 // to the device port for the connected device must have non-empty profiles.
2143 // Since the test connects and disconnects a single device each time, the size
2144 // of profiles for all mix ports routed to the device port under test must get back
2145 // to the original count once the external device is disconnected.
2146 ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
2147 std::vector<AudioPort> externalDevicePorts = moduleConfig->getExternalDevicePorts();
2148 if (externalDevicePorts.empty()) {
2149 GTEST_SKIP() << "No external devices in the module.";
2150 }
2151 for (const auto& port : externalDevicePorts) {
2152 SCOPED_TRACE(port.toString());
2153 RoutedPortsProfilesSnapshot before(port.id);
2154 ASSERT_NO_FATAL_FAILURE(before.Capture(module.get()));
2155 if (before.getRoutedPorts().empty()) continue;
2156 {
2157 WithDevicePortConnectedState portConnected(GenerateUniqueDeviceAddress(port));
2158 ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get(), moduleConfig.get()));
2159 RoutedPortsProfilesSnapshot connected(portConnected.getId());
2160 ASSERT_NO_FATAL_FAILURE(connected.Capture(module.get()));
2161 EXPECT_NO_FATAL_FAILURE(connected.VerifyProfilesNonEmpty());
2162 }
2163 RoutedPortsProfilesSnapshot after(port.id);
2164 ASSERT_NO_FATAL_FAILURE(after.Capture(module.get()));
2165 EXPECT_NO_FATAL_FAILURE(after.VerifyNoProfilesChanges(before));
2166 }
2167 }
2168
2169 // Note: This test relies on simulation of external device connections by the HAL module.
TEST_P(AudioCoreModule,TwoExternalDevicesMixPortConfigsNested)2170 TEST_P(AudioCoreModule, TwoExternalDevicesMixPortConfigsNested) {
2171 // Ensure that in the case when two external devices are connected to the same
2172 // device port, disconnecting one of them does not erase the profiles of routed mix ports.
2173 // In this scenario, the connections are "nested."
2174 ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
2175 std::vector<AudioPort> externalDevicePorts = moduleConfig->getExternalDevicePorts();
2176 if (externalDevicePorts.empty()) {
2177 GTEST_SKIP() << "No external devices in the module.";
2178 }
2179 for (const auto& port : externalDevicePorts) {
2180 SCOPED_TRACE(port.toString());
2181 WithDevicePortConnectedState portConnected1(GenerateUniqueDeviceAddress(port));
2182 ASSERT_NO_FATAL_FAILURE(portConnected1.SetUp(module.get(), moduleConfig.get()));
2183 {
2184 // Connect and disconnect another device, if possible. It might not be possible
2185 // for point-to-point connections, like analog or SPDIF.
2186 WithDevicePortConnectedState portConnected2(GenerateUniqueDeviceAddress(port));
2187 if (auto status = portConnected2.SetUpNoChecks(module.get(), moduleConfig.get());
2188 !status.isOk()) {
2189 continue;
2190 }
2191 }
2192 RoutedPortsProfilesSnapshot connected(portConnected1.getId());
2193 ASSERT_NO_FATAL_FAILURE(connected.Capture(module.get()));
2194 EXPECT_NO_FATAL_FAILURE(connected.VerifyProfilesNonEmpty());
2195 }
2196 }
2197
2198 // Note: This test relies on simulation of external device connections by the HAL module.
TEST_P(AudioCoreModule,TwoExternalDevicesMixPortConfigsInterleaved)2199 TEST_P(AudioCoreModule, TwoExternalDevicesMixPortConfigsInterleaved) {
2200 // Ensure that in the case when two external devices are connected to the same
2201 // device port, disconnecting one of them does not erase the profiles of routed mix ports.
2202 // In this scenario, the connections are "interleaved."
2203 ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
2204 std::vector<AudioPort> externalDevicePorts = moduleConfig->getExternalDevicePorts();
2205 if (externalDevicePorts.empty()) {
2206 GTEST_SKIP() << "No external devices in the module.";
2207 }
2208 for (const auto& port : externalDevicePorts) {
2209 SCOPED_TRACE(port.toString());
2210 auto portConnected1 =
2211 std::make_unique<WithDevicePortConnectedState>(GenerateUniqueDeviceAddress(port));
2212 ASSERT_NO_FATAL_FAILURE(portConnected1->SetUp(module.get(), moduleConfig.get()));
2213 WithDevicePortConnectedState portConnected2(GenerateUniqueDeviceAddress(port));
2214 // Connect another device, if possible. It might not be possible for point-to-point
2215 // connections, like analog or SPDIF.
2216 if (auto status = portConnected2.SetUpNoChecks(module.get(), moduleConfig.get());
2217 !status.isOk()) {
2218 continue;
2219 }
2220 portConnected1.reset();
2221 RoutedPortsProfilesSnapshot connected(portConnected2.getId());
2222 ASSERT_NO_FATAL_FAILURE(connected.Capture(module.get()));
2223 EXPECT_NO_FATAL_FAILURE(connected.VerifyProfilesNonEmpty());
2224 }
2225 }
2226
TEST_P(AudioCoreModule,MasterMute)2227 TEST_P(AudioCoreModule, MasterMute) {
2228 bool isSupported = false;
2229 EXPECT_NO_FATAL_FAILURE(TestAccessors<bool>(module.get(), &IModule::getMasterMute,
2230 &IModule::setMasterMute, {false, true}, {},
2231 &isSupported));
2232 if (!isSupported) {
2233 GTEST_SKIP() << "Master mute is not supported";
2234 }
2235 // TODO: Test that master mute actually mutes output.
2236 }
2237
TEST_P(AudioCoreModule,MasterVolume)2238 TEST_P(AudioCoreModule, MasterVolume) {
2239 bool isSupported = false;
2240 EXPECT_NO_FATAL_FAILURE(TestAccessors<float>(
2241 module.get(), &IModule::getMasterVolume, &IModule::setMasterVolume, {0.0f, 0.5f, 1.0f},
2242 {-0.1, 1.1, NAN, INFINITY, -INFINITY, 1 + std::numeric_limits<float>::epsilon()},
2243 &isSupported));
2244 if (!isSupported) {
2245 GTEST_SKIP() << "Master volume is not supported";
2246 }
2247 // TODO: Test that master volume actually attenuates output.
2248 }
2249
TEST_P(AudioCoreModule,MicMute)2250 TEST_P(AudioCoreModule, MicMute) {
2251 bool isSupported = false;
2252 EXPECT_NO_FATAL_FAILURE(TestAccessors<bool>(module.get(), &IModule::getMicMute,
2253 &IModule::setMicMute, {false, true}, {},
2254 &isSupported));
2255 if (!isSupported) {
2256 GTEST_SKIP() << "Mic mute is not supported";
2257 }
2258 // TODO: Test that mic mute actually mutes input.
2259 }
2260
TEST_P(AudioCoreModule,GetMicrophones)2261 TEST_P(AudioCoreModule, GetMicrophones) {
2262 ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
2263 const std::vector<AudioPort> builtInMicPorts = moduleConfig->getAttachedMicrophonePorts();
2264 std::vector<MicrophoneInfo> micInfos;
2265 ScopedAStatus status = module->getMicrophones(&micInfos);
2266 if (!status.isOk()) {
2267 EXPECT_EQ(EX_UNSUPPORTED_OPERATION, status.getExceptionCode());
2268 ASSERT_FALSE(builtInMicPorts.empty())
2269 << "When the HAL module does not have built-in microphones, IModule.getMicrophones"
2270 << " must complete with no error and return an empty list";
2271 GTEST_SKIP() << "Microphone info is not supported";
2272 }
2273 std::set<int32_t> micPortIdsWithInfo;
2274 for (const auto& micInfo : micInfos) {
2275 const auto& micDevice = micInfo.device;
2276 const auto it =
2277 std::find_if(builtInMicPorts.begin(), builtInMicPorts.end(), [&](const auto& port) {
2278 return port.ext.template get<AudioPortExt::Tag::device>().device == micDevice;
2279 });
2280 if (it != builtInMicPorts.end()) {
2281 micPortIdsWithInfo.insert(it->id);
2282 } else {
2283 ADD_FAILURE() << "No device port found with a device specified for the microphone \""
2284 << micInfo.id << "\": " << micDevice.toString();
2285 }
2286 }
2287 if (micPortIdsWithInfo.size() != builtInMicPorts.size()) {
2288 std::vector<AudioPort> micPortsNoInfo;
2289 std::copy_if(builtInMicPorts.begin(), builtInMicPorts.end(),
2290 std::back_inserter(micPortsNoInfo),
2291 [&](const auto& port) { return micPortIdsWithInfo.count(port.id) == 0; });
2292 ADD_FAILURE() << "No MicrophoneInfo is provided for the following microphone device ports: "
2293 << ::android::internal::ToString(micPortsNoInfo);
2294 }
2295 }
2296
TEST_P(AudioCoreModule,UpdateAudioMode)2297 TEST_P(AudioCoreModule, UpdateAudioMode) {
2298 for (const auto mode : ::ndk::enum_range<AudioMode>()) {
2299 if (isValidAudioMode(mode)) {
2300 EXPECT_IS_OK(module->updateAudioMode(mode)) << toString(mode);
2301 } else {
2302 EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->updateAudioMode(mode)) << toString(mode);
2303 }
2304 }
2305 EXPECT_IS_OK(module->updateAudioMode(AudioMode::NORMAL));
2306 }
2307
TEST_P(AudioCoreModule,UpdateScreenRotation)2308 TEST_P(AudioCoreModule, UpdateScreenRotation) {
2309 for (const auto rotation : ::ndk::enum_range<IModule::ScreenRotation>()) {
2310 EXPECT_IS_OK(module->updateScreenRotation(rotation)) << toString(rotation);
2311 }
2312 EXPECT_IS_OK(module->updateScreenRotation(IModule::ScreenRotation::DEG_0));
2313 }
2314
TEST_P(AudioCoreModule,UpdateScreenState)2315 TEST_P(AudioCoreModule, UpdateScreenState) {
2316 EXPECT_IS_OK(module->updateScreenState(false));
2317 EXPECT_IS_OK(module->updateScreenState(true));
2318 }
2319
TEST_P(AudioCoreModule,GenerateHwAvSyncId)2320 TEST_P(AudioCoreModule, GenerateHwAvSyncId) {
2321 const auto kStatuses = {EX_NONE, EX_ILLEGAL_STATE};
2322 int32_t id1;
2323 ndk::ScopedAStatus status = module->generateHwAvSyncId(&id1);
2324 if (status.getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
2325 GTEST_SKIP() << "HW AV Sync is not supported";
2326 }
2327 EXPECT_STATUS(kStatuses, status);
2328 if (status.isOk()) {
2329 int32_t id2;
2330 ASSERT_IS_OK(module->generateHwAvSyncId(&id2));
2331 EXPECT_NE(id1, id2) << "HW AV Sync IDs must be unique";
2332 }
2333 }
2334
TEST_P(AudioCoreModule,GetVendorParameters)2335 TEST_P(AudioCoreModule, GetVendorParameters) {
2336 bool isGetterSupported = false;
2337 EXPECT_NO_FATAL_FAILURE(TestGetVendorParameters(module.get(), &isGetterSupported));
2338 ndk::ScopedAStatus status = module->setVendorParameters({}, false);
2339 EXPECT_EQ(isGetterSupported, status.getExceptionCode() != EX_UNSUPPORTED_OPERATION)
2340 << "Support for getting and setting of vendor parameters must be consistent";
2341 if (!isGetterSupported) {
2342 GTEST_SKIP() << "Vendor parameters are not supported";
2343 }
2344 }
2345
TEST_P(AudioCoreModule,SetVendorParameters)2346 TEST_P(AudioCoreModule, SetVendorParameters) {
2347 bool isSupported = false;
2348 EXPECT_NO_FATAL_FAILURE(TestSetVendorParameters(module.get(), &isSupported));
2349 if (!isSupported) {
2350 GTEST_SKIP() << "Vendor parameters are not supported";
2351 }
2352 }
2353
2354 // See b/262930731. In the absence of offloaded effect implementations,
2355 // currently we can only pass a nullptr, and the HAL module must either reject
2356 // it as an invalid argument, or say that offloaded effects are not supported.
TEST_P(AudioCoreModule,AddRemoveEffectInvalidArguments)2357 TEST_P(AudioCoreModule, AddRemoveEffectInvalidArguments) {
2358 ndk::ScopedAStatus addEffectStatus = module->addDeviceEffect(-1, nullptr);
2359 ndk::ScopedAStatus removeEffectStatus = module->removeDeviceEffect(-1, nullptr);
2360 if (addEffectStatus.getExceptionCode() != EX_UNSUPPORTED_OPERATION) {
2361 EXPECT_EQ(EX_ILLEGAL_ARGUMENT, addEffectStatus.getExceptionCode());
2362 EXPECT_EQ(EX_ILLEGAL_ARGUMENT, removeEffectStatus.getExceptionCode());
2363 } else if (removeEffectStatus.getExceptionCode() != EX_UNSUPPORTED_OPERATION) {
2364 GTEST_FAIL() << "addDeviceEffect and removeDeviceEffect must be either supported or "
2365 << "not supported together";
2366 } else {
2367 GTEST_SKIP() << "Offloaded effects not supported";
2368 }
2369 // Test rejection of a nullptr effect with a valid device port Id.
2370 ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
2371 const auto configs = moduleConfig->getPortConfigsForAttachedDevicePorts();
2372 for (const auto& config : configs) {
2373 WithAudioPortConfig portConfig(config);
2374 ASSERT_NO_FATAL_FAILURE(portConfig.SetUp(module.get()));
2375 EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->addDeviceEffect(portConfig.getId(), nullptr));
2376 EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->removeDeviceEffect(portConfig.getId(), nullptr));
2377 }
2378 }
2379
TEST_P(AudioCoreModule,GetMmapPolicyInfos)2380 TEST_P(AudioCoreModule, GetMmapPolicyInfos) {
2381 ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
2382 const bool isMmapSupported = moduleConfig->isMmapSupported();
2383 for (const auto mmapPolicyType :
2384 {AudioMMapPolicyType::DEFAULT, AudioMMapPolicyType::EXCLUSIVE}) {
2385 std::vector<AudioMMapPolicyInfo> policyInfos;
2386 EXPECT_IS_OK(module->getMmapPolicyInfos(mmapPolicyType, &policyInfos))
2387 << toString(mmapPolicyType);
2388 const bool isMMapSupportedByPolicyInfos =
2389 std::find_if(policyInfos.begin(), policyInfos.end(), [](const auto& info) {
2390 return info.mmapPolicy == AudioMMapPolicy::AUTO ||
2391 info.mmapPolicy == AudioMMapPolicy::ALWAYS;
2392 }) != policyInfos.end();
2393 EXPECT_EQ(isMmapSupported, isMMapSupportedByPolicyInfos)
2394 << ::android::internal::ToString(policyInfos);
2395 }
2396 }
2397
TEST_P(AudioCoreModule,BluetoothVariableLatency)2398 TEST_P(AudioCoreModule, BluetoothVariableLatency) {
2399 bool isSupported = false;
2400 EXPECT_IS_OK(module->supportsVariableLatency(&isSupported));
2401 LOG(INFO) << "supportsVariableLatency: " << isSupported;
2402 }
2403
TEST_P(AudioCoreModule,GetAAudioMixerBurstCount)2404 TEST_P(AudioCoreModule, GetAAudioMixerBurstCount) {
2405 ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
2406 const bool isMmapSupported = moduleConfig->isMmapSupported();
2407 int32_t mixerBursts = 0;
2408 ndk::ScopedAStatus status = module->getAAudioMixerBurstCount(&mixerBursts);
2409 EXPECT_EQ(isMmapSupported, status.getExceptionCode() != EX_UNSUPPORTED_OPERATION)
2410 << "Support for AAudio MMAP and getting AAudio mixer burst count must be consistent";
2411 if (!isMmapSupported) {
2412 GTEST_SKIP() << "AAudio MMAP is not supported";
2413 }
2414 EXPECT_GE(mixerBursts, 0);
2415 }
2416
TEST_P(AudioCoreModule,GetAAudioHardwareBurstMinUsec)2417 TEST_P(AudioCoreModule, GetAAudioHardwareBurstMinUsec) {
2418 ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
2419 const bool isMmapSupported = moduleConfig->isMmapSupported();
2420 int32_t aaudioHardwareBurstMinUsec = 0;
2421 ndk::ScopedAStatus status = module->getAAudioHardwareBurstMinUsec(&aaudioHardwareBurstMinUsec);
2422 EXPECT_EQ(isMmapSupported, status.getExceptionCode() != EX_UNSUPPORTED_OPERATION)
2423 << "Support for AAudio MMAP and getting AAudio hardware burst minimum usec "
2424 << "must be consistent";
2425 if (!isMmapSupported) {
2426 GTEST_SKIP() << "AAudio MMAP is not supported";
2427 }
2428 EXPECT_GE(aaudioHardwareBurstMinUsec, 0);
2429 }
2430
2431 class AudioCoreBluetooth : public AudioCoreModuleBase, public testing::TestWithParam<std::string> {
2432 public:
SetUp()2433 void SetUp() override {
2434 ASSERT_NO_FATAL_FAILURE(SetUpImpl(GetParam()));
2435 ASSERT_IS_OK(module->getBluetooth(&bluetooth));
2436 }
2437
TearDown()2438 void TearDown() override { ASSERT_NO_FATAL_FAILURE(TearDownImpl()); }
2439
2440 std::shared_ptr<IBluetooth> bluetooth;
2441 };
2442
TEST_P(AudioCoreBluetooth,SameInstance)2443 TEST_P(AudioCoreBluetooth, SameInstance) {
2444 if (bluetooth == nullptr) {
2445 GTEST_SKIP() << "Bluetooth is not supported";
2446 }
2447 std::shared_ptr<IBluetooth> bluetooth2;
2448 EXPECT_IS_OK(module->getBluetooth(&bluetooth2));
2449 ASSERT_NE(nullptr, bluetooth2.get());
2450 EXPECT_EQ(bluetooth->asBinder(), bluetooth2->asBinder())
2451 << "getBluetooth must return the same interface instance across invocations";
2452 }
2453
TEST_P(AudioCoreBluetooth,ScoConfig)2454 TEST_P(AudioCoreBluetooth, ScoConfig) {
2455 static const auto kStatuses = {EX_NONE, EX_UNSUPPORTED_OPERATION};
2456 if (bluetooth == nullptr) {
2457 GTEST_SKIP() << "Bluetooth is not supported";
2458 }
2459 ndk::ScopedAStatus status;
2460 IBluetooth::ScoConfig scoConfig;
2461 ASSERT_STATUS(kStatuses, status = bluetooth->setScoConfig({}, &scoConfig));
2462 if (status.getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
2463 GTEST_SKIP() << "BT SCO is not supported";
2464 }
2465 EXPECT_TRUE(scoConfig.isEnabled.has_value());
2466 EXPECT_TRUE(scoConfig.isNrecEnabled.has_value());
2467 EXPECT_NE(IBluetooth::ScoConfig::Mode::UNSPECIFIED, scoConfig.mode);
2468 IBluetooth::ScoConfig scoConfig2;
2469 ASSERT_IS_OK(bluetooth->setScoConfig(scoConfig, &scoConfig2));
2470 EXPECT_EQ(scoConfig, scoConfig2);
2471 }
2472
TEST_P(AudioCoreBluetooth,HfpConfig)2473 TEST_P(AudioCoreBluetooth, HfpConfig) {
2474 static const auto kStatuses = {EX_NONE, EX_UNSUPPORTED_OPERATION};
2475 if (bluetooth == nullptr) {
2476 GTEST_SKIP() << "Bluetooth is not supported";
2477 }
2478 ndk::ScopedAStatus status;
2479 IBluetooth::HfpConfig hfpConfig;
2480 ASSERT_STATUS(kStatuses, status = bluetooth->setHfpConfig({}, &hfpConfig));
2481 if (status.getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
2482 GTEST_SKIP() << "BT HFP is not supported";
2483 }
2484 EXPECT_TRUE(hfpConfig.isEnabled.has_value());
2485 EXPECT_TRUE(hfpConfig.sampleRate.has_value());
2486 EXPECT_TRUE(hfpConfig.volume.has_value());
2487 IBluetooth::HfpConfig hfpConfig2;
2488 ASSERT_IS_OK(bluetooth->setHfpConfig(hfpConfig, &hfpConfig2));
2489 EXPECT_EQ(hfpConfig, hfpConfig2);
2490 }
2491
TEST_P(AudioCoreBluetooth,HfpConfigInvalid)2492 TEST_P(AudioCoreBluetooth, HfpConfigInvalid) {
2493 static const auto kStatuses = {EX_NONE, EX_UNSUPPORTED_OPERATION};
2494 if (bluetooth == nullptr) {
2495 GTEST_SKIP() << "Bluetooth is not supported";
2496 }
2497 ndk::ScopedAStatus status;
2498 IBluetooth::HfpConfig hfpConfig;
2499 ASSERT_STATUS(kStatuses, status = bluetooth->setHfpConfig({}, &hfpConfig));
2500 if (status.getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
2501 GTEST_SKIP() << "BT HFP is not supported";
2502 }
2503 EXPECT_STATUS(EX_ILLEGAL_ARGUMENT,
2504 bluetooth->setHfpConfig({.sampleRate = Int{-1}}, &hfpConfig));
2505 EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, bluetooth->setHfpConfig({.sampleRate = Int{0}}, &hfpConfig));
2506 EXPECT_STATUS(EX_ILLEGAL_ARGUMENT,
2507 bluetooth->setHfpConfig({.volume = Float{IBluetooth::HfpConfig::VOLUME_MIN - 1}},
2508 &hfpConfig));
2509 EXPECT_STATUS(EX_ILLEGAL_ARGUMENT,
2510 bluetooth->setHfpConfig({.volume = Float{IBluetooth::HfpConfig::VOLUME_MAX + 1}},
2511 &hfpConfig));
2512 }
2513
2514 class AudioCoreBluetoothA2dp : public AudioCoreModuleBase,
2515 public testing::TestWithParam<std::string> {
2516 public:
SetUp()2517 void SetUp() override {
2518 ASSERT_NO_FATAL_FAILURE(SetUpImpl(GetParam()));
2519 ASSERT_IS_OK(module->getBluetoothA2dp(&bluetooth));
2520 }
2521
TearDown()2522 void TearDown() override { ASSERT_NO_FATAL_FAILURE(TearDownImpl()); }
2523
2524 std::shared_ptr<IBluetoothA2dp> bluetooth;
2525 };
2526
TEST_P(AudioCoreBluetoothA2dp,SameInstance)2527 TEST_P(AudioCoreBluetoothA2dp, SameInstance) {
2528 if (bluetooth == nullptr) {
2529 GTEST_SKIP() << "BluetoothA2dp is not supported";
2530 }
2531 std::shared_ptr<IBluetoothA2dp> bluetooth2;
2532 EXPECT_IS_OK(module->getBluetoothA2dp(&bluetooth2));
2533 ASSERT_NE(nullptr, bluetooth2.get());
2534 EXPECT_EQ(bluetooth->asBinder(), bluetooth2->asBinder())
2535 << "getBluetoothA2dp must return the same interface instance across invocations";
2536 }
2537
TEST_P(AudioCoreBluetoothA2dp,Enabled)2538 TEST_P(AudioCoreBluetoothA2dp, Enabled) {
2539 if (bluetooth == nullptr) {
2540 GTEST_SKIP() << "BluetoothA2dp is not supported";
2541 }
2542 // Since enabling A2DP may require having an actual device connection,
2543 // limit testing to setting back the current value.
2544 bool enabled;
2545 ASSERT_IS_OK(bluetooth->isEnabled(&enabled));
2546 EXPECT_IS_OK(bluetooth->setEnabled(enabled))
2547 << "setEnabled without actual state change must not fail";
2548 }
2549
TEST_P(AudioCoreBluetoothA2dp,OffloadReconfiguration)2550 TEST_P(AudioCoreBluetoothA2dp, OffloadReconfiguration) {
2551 if (bluetooth == nullptr) {
2552 GTEST_SKIP() << "BluetoothA2dp is not supported";
2553 }
2554 bool isSupported;
2555 ASSERT_IS_OK(bluetooth->supportsOffloadReconfiguration(&isSupported));
2556 bool isSupported2;
2557 ASSERT_IS_OK(bluetooth->supportsOffloadReconfiguration(&isSupported2));
2558 EXPECT_EQ(isSupported, isSupported2);
2559 if (isSupported) {
2560 static const auto kStatuses = {EX_NONE, EX_ILLEGAL_STATE};
2561 EXPECT_STATUS(kStatuses, bluetooth->reconfigureOffload({}));
2562 } else {
2563 EXPECT_STATUS(EX_UNSUPPORTED_OPERATION, bluetooth->reconfigureOffload({}));
2564 }
2565 }
2566
2567 class AudioCoreBluetoothLe : public AudioCoreModuleBase,
2568 public testing::TestWithParam<std::string> {
2569 public:
SetUp()2570 void SetUp() override {
2571 ASSERT_NO_FATAL_FAILURE(SetUpImpl(GetParam()));
2572 ASSERT_IS_OK(module->getBluetoothLe(&bluetooth));
2573 }
2574
TearDown()2575 void TearDown() override { ASSERT_NO_FATAL_FAILURE(TearDownImpl()); }
2576
2577 std::shared_ptr<IBluetoothLe> bluetooth;
2578 };
2579
TEST_P(AudioCoreBluetoothLe,SameInstance)2580 TEST_P(AudioCoreBluetoothLe, SameInstance) {
2581 if (bluetooth == nullptr) {
2582 GTEST_SKIP() << "BluetoothLe is not supported";
2583 }
2584 std::shared_ptr<IBluetoothLe> bluetooth2;
2585 EXPECT_IS_OK(module->getBluetoothLe(&bluetooth2));
2586 ASSERT_NE(nullptr, bluetooth2.get());
2587 EXPECT_EQ(bluetooth->asBinder(), bluetooth2->asBinder())
2588 << "getBluetoothLe must return the same interface instance across invocations";
2589 }
2590
TEST_P(AudioCoreBluetoothLe,Enabled)2591 TEST_P(AudioCoreBluetoothLe, Enabled) {
2592 if (bluetooth == nullptr) {
2593 GTEST_SKIP() << "BluetoothLe is not supported";
2594 }
2595 // Since enabling LE may require having an actual device connection,
2596 // limit testing to setting back the current value.
2597 bool enabled;
2598 ASSERT_IS_OK(bluetooth->isEnabled(&enabled));
2599 EXPECT_IS_OK(bluetooth->setEnabled(enabled))
2600 << "setEnabled without actual state change must not fail";
2601 }
2602
TEST_P(AudioCoreBluetoothLe,OffloadReconfiguration)2603 TEST_P(AudioCoreBluetoothLe, OffloadReconfiguration) {
2604 if (bluetooth == nullptr) {
2605 GTEST_SKIP() << "BluetoothLe is not supported";
2606 }
2607 bool isSupported;
2608 ASSERT_IS_OK(bluetooth->supportsOffloadReconfiguration(&isSupported));
2609 bool isSupported2;
2610 ASSERT_IS_OK(bluetooth->supportsOffloadReconfiguration(&isSupported2));
2611 EXPECT_EQ(isSupported, isSupported2);
2612 if (isSupported) {
2613 static const auto kStatuses = {EX_NONE, EX_ILLEGAL_STATE};
2614 EXPECT_STATUS(kStatuses, bluetooth->reconfigureOffload({}));
2615 } else {
2616 EXPECT_STATUS(EX_UNSUPPORTED_OPERATION, bluetooth->reconfigureOffload({}));
2617 }
2618 }
2619
2620 class AudioCoreTelephony : public AudioCoreModuleBase, public testing::TestWithParam<std::string> {
2621 public:
SetUp()2622 void SetUp() override {
2623 ASSERT_NO_FATAL_FAILURE(SetUpImpl(GetParam()));
2624 ASSERT_IS_OK(module->getTelephony(&telephony));
2625 }
2626
TearDown()2627 void TearDown() override { ASSERT_NO_FATAL_FAILURE(TearDownImpl()); }
2628
2629 std::shared_ptr<ITelephony> telephony;
2630 };
2631
TEST_P(AudioCoreTelephony,SameInstance)2632 TEST_P(AudioCoreTelephony, SameInstance) {
2633 if (telephony == nullptr) {
2634 GTEST_SKIP() << "Telephony is not supported";
2635 }
2636 std::shared_ptr<ITelephony> telephony2;
2637 EXPECT_IS_OK(module->getTelephony(&telephony2));
2638 ASSERT_NE(nullptr, telephony2.get());
2639 EXPECT_EQ(telephony->asBinder(), telephony2->asBinder())
2640 << "getTelephony must return the same interface instance across invocations";
2641 }
2642
TEST_P(AudioCoreTelephony,GetSupportedAudioModes)2643 TEST_P(AudioCoreTelephony, GetSupportedAudioModes) {
2644 if (telephony == nullptr) {
2645 GTEST_SKIP() << "Telephony is not supported";
2646 }
2647 std::vector<AudioMode> modes1;
2648 ASSERT_IS_OK(telephony->getSupportedAudioModes(&modes1));
2649 for (const auto mode : modes1) {
2650 EXPECT_TRUE(isValidAudioMode(mode)) << toString(mode);
2651 }
2652 const std::vector<AudioMode> kMandatoryModes = {AudioMode::NORMAL, AudioMode::RINGTONE,
2653 AudioMode::IN_CALL,
2654 AudioMode::IN_COMMUNICATION};
2655 for (const auto mode : kMandatoryModes) {
2656 EXPECT_NE(modes1.end(), std::find(modes1.begin(), modes1.end(), mode))
2657 << "Mandatory mode not supported: " << toString(mode);
2658 }
2659 std::vector<AudioMode> modes2;
2660 ASSERT_IS_OK(telephony->getSupportedAudioModes(&modes2));
2661 ASSERT_EQ(modes1.size(), modes2.size())
2662 << "Sizes of audio mode arrays do not match across consequent calls to "
2663 << "getSupportedAudioModes";
2664 std::sort(modes1.begin(), modes1.end());
2665 std::sort(modes2.begin(), modes2.end());
2666 EXPECT_EQ(modes1, modes2);
2667 };
2668
TEST_P(AudioCoreTelephony,SwitchAudioMode)2669 TEST_P(AudioCoreTelephony, SwitchAudioMode) {
2670 if (telephony == nullptr) {
2671 GTEST_SKIP() << "Telephony is not supported";
2672 }
2673 std::vector<AudioMode> supportedModes;
2674 ASSERT_IS_OK(telephony->getSupportedAudioModes(&supportedModes));
2675 std::set<AudioMode> unsupportedModes = {
2676 // Start with all, remove supported ones
2677 ::ndk::enum_range<AudioMode>().begin(), ::ndk::enum_range<AudioMode>().end()};
2678 for (const auto mode : supportedModes) {
2679 EXPECT_IS_OK(telephony->switchAudioMode(mode)) << toString(mode);
2680 unsupportedModes.erase(mode);
2681 }
2682 for (const auto mode : unsupportedModes) {
2683 EXPECT_STATUS(isValidAudioMode(mode) ? EX_UNSUPPORTED_OPERATION : EX_ILLEGAL_ARGUMENT,
2684 telephony->switchAudioMode(mode))
2685 << toString(mode);
2686 }
2687 }
2688
TEST_P(AudioCoreTelephony,TelecomConfig)2689 TEST_P(AudioCoreTelephony, TelecomConfig) {
2690 static const auto kStatuses = {EX_NONE, EX_UNSUPPORTED_OPERATION};
2691 if (telephony == nullptr) {
2692 GTEST_SKIP() << "Telephony is not supported";
2693 }
2694 ndk::ScopedAStatus status;
2695 ITelephony::TelecomConfig telecomConfig;
2696 ASSERT_STATUS(kStatuses, status = telephony->setTelecomConfig({}, &telecomConfig));
2697 if (status.getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
2698 GTEST_SKIP() << "Telecom is not supported";
2699 }
2700 EXPECT_TRUE(telecomConfig.voiceVolume.has_value());
2701 EXPECT_NE(ITelephony::TelecomConfig::TtyMode::UNSPECIFIED, telecomConfig.ttyMode);
2702 EXPECT_TRUE(telecomConfig.isHacEnabled.has_value());
2703 ITelephony::TelecomConfig telecomConfig2;
2704 ASSERT_IS_OK(telephony->setTelecomConfig(telecomConfig, &telecomConfig2));
2705 EXPECT_EQ(telecomConfig, telecomConfig2);
2706 }
2707
TEST_P(AudioCoreTelephony,TelecomConfigInvalid)2708 TEST_P(AudioCoreTelephony, TelecomConfigInvalid) {
2709 static const auto kStatuses = {EX_NONE, EX_UNSUPPORTED_OPERATION};
2710 if (telephony == nullptr) {
2711 GTEST_SKIP() << "Telephony is not supported";
2712 }
2713 ndk::ScopedAStatus status;
2714 ITelephony::TelecomConfig telecomConfig;
2715 ASSERT_STATUS(kStatuses, status = telephony->setTelecomConfig({}, &telecomConfig));
2716 if (status.getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
2717 GTEST_SKIP() << "Telecom is not supported";
2718 }
2719 EXPECT_STATUS(EX_ILLEGAL_ARGUMENT,
2720 telephony->setTelecomConfig(
2721 {.voiceVolume = Float{ITelephony::TelecomConfig::VOICE_VOLUME_MIN - 1}},
2722 &telecomConfig));
2723 EXPECT_STATUS(EX_ILLEGAL_ARGUMENT,
2724 telephony->setTelecomConfig(
2725 {.voiceVolume = Float{ITelephony::TelecomConfig::VOICE_VOLUME_MAX + 1}},
2726 &telecomConfig));
2727 }
2728
2729 using CommandSequence = std::vector<StreamDescriptor::Command>;
2730 class StreamLogicDriverInvalidCommand : public StreamLogicDriver {
2731 public:
StreamLogicDriverInvalidCommand(const CommandSequence & commands)2732 StreamLogicDriverInvalidCommand(const CommandSequence& commands) : mCommands(commands) {}
2733
getUnexpectedStatuses()2734 std::string getUnexpectedStatuses() {
2735 // This method is intended to be called after the worker thread has joined,
2736 // thus no extra synchronization is needed.
2737 std::string s;
2738 if (!mStatuses.empty()) {
2739 s = std::string("Pairs of (command, actual status): ")
2740 .append((android::internal::ToString(mStatuses)));
2741 }
2742 return s;
2743 }
2744
done()2745 bool done() override { return mNextCommand >= mCommands.size(); }
getNextTrigger(int,int * actualSize)2746 TransitionTrigger getNextTrigger(int, int* actualSize) override {
2747 if (actualSize != nullptr) *actualSize = 0;
2748 return mCommands[mNextCommand++];
2749 }
interceptRawReply(const StreamDescriptor::Reply & reply)2750 bool interceptRawReply(const StreamDescriptor::Reply& reply) override {
2751 const size_t currentCommand = mNextCommand - 1; // increased by getNextTrigger
2752 const bool isLastCommand = currentCommand == mCommands.size() - 1;
2753 // All but the last command should run correctly. The last command must return 'BAD_VALUE'
2754 // status.
2755 if ((!isLastCommand && reply.status != STATUS_OK) ||
2756 (isLastCommand && reply.status != STATUS_BAD_VALUE)) {
2757 std::string s = mCommands[currentCommand].toString();
2758 s.append(", ").append(statusToString(reply.status));
2759 mStatuses.push_back(std::move(s));
2760 // Process the reply, since the worker exits in case of an error.
2761 return false;
2762 }
2763 return isLastCommand;
2764 }
processValidReply(const StreamDescriptor::Reply &)2765 bool processValidReply(const StreamDescriptor::Reply&) override { return true; }
2766
2767 private:
2768 const CommandSequence mCommands;
2769 size_t mNextCommand = 0;
2770 std::vector<std::string> mStatuses;
2771 };
2772
2773 // A helper which sets up necessary HAL structures for a proper stream initialization.
2774 //
2775 // The full sequence of actions to set up a stream is as follows:
2776 //
2777 // device port -> connect if necessary -> set up port config | -> set up patch
2778 // mix port -> set up port config, unless it has been provided |
2779 //
2780 // then, from the patch, figure out the minimum HAL buffer size -> set up stream
2781 //
2782 // This sequence is reflected in the order of fields declaration.
2783 // Various tests need to be able to start and stop at various point in this sequence,
2784 // this is why there are methods that do just part of the work.
2785 //
2786 // Note: To maximize test coverage, this class relies on simulation of external device
2787 // connections by the HAL module.
2788 template <typename Stream>
2789 class StreamFixture {
2790 public:
2791 // Tests might need to override the direction.
StreamFixture(bool isInput=IOTraits<Stream>::is_input)2792 StreamFixture(bool isInput = IOTraits<Stream>::is_input) : mIsInput(isInput) {}
2793
SetUpPortConfigAnyMixPort(IModule * module,ModuleConfig * moduleConfig,bool connectedOnly)2794 void SetUpPortConfigAnyMixPort(IModule* module, ModuleConfig* moduleConfig,
2795 bool connectedOnly) {
2796 const auto mixPorts = moduleConfig->getMixPorts(mIsInput, connectedOnly);
2797 mSkipTestReason = "No mix ports";
2798 for (const auto& mixPort : mixPorts) {
2799 mSkipTestReason = "";
2800 ASSERT_NO_FATAL_FAILURE(SetUpPortConfigForMixPortOrConfig(module, moduleConfig, mixPort,
2801 connectedOnly));
2802 if (mSkipTestReason.empty()) break;
2803 }
2804 }
2805
SetUpPortConfigForMixPortOrConfig(IModule * module,ModuleConfig * moduleConfig,const AudioPort & initialMixPort,bool connectedOnly,const std::optional<AudioPortConfig> & mixPortConfig={})2806 void SetUpPortConfigForMixPortOrConfig(
2807 IModule* module, ModuleConfig* moduleConfig, const AudioPort& initialMixPort,
2808 bool connectedOnly, const std::optional<AudioPortConfig>& mixPortConfig = {}) {
2809 if (mixPortConfig.has_value() && !connectedOnly) {
2810 // Connecting an external device may cause change in mix port profiles and the provided
2811 // config may become invalid.
2812 LOG(FATAL) << __func__ << ": when specifying a mix port config, it is not allowed "
2813 << "to change connected devices, thus `connectedOnly` must be `true`";
2814 }
2815 std::optional<AudioPort> connectedDevicePort;
2816 ASSERT_NO_FATAL_FAILURE(SetUpDevicePortForMixPort(module, moduleConfig, initialMixPort,
2817 connectedOnly, &connectedDevicePort));
2818 if (!mSkipTestReason.empty()) return;
2819 if (mixPortConfig.has_value()) {
2820 ASSERT_NO_FATAL_FAILURE(
2821 SetUpPortConfig(module, moduleConfig, *mixPortConfig, *connectedDevicePort));
2822 } else {
2823 // If an external device was connected, the profiles of the mix port might have changed.
2824 AudioPort mixPort;
2825 ASSERT_NO_FATAL_FAILURE(module->getAudioPort(initialMixPort.id, &mixPort));
2826 ASSERT_NO_FATAL_FAILURE(
2827 SetUpPortConfig(module, moduleConfig, mixPort, *connectedDevicePort));
2828 }
2829 }
2830
SetUpPortConfig(IModule * module,ModuleConfig * moduleConfig,const AudioPort & mixPort,const AudioPort & devicePort)2831 void SetUpPortConfig(IModule* module, ModuleConfig* moduleConfig, const AudioPort& mixPort,
2832 const AudioPort& devicePort) {
2833 auto mixPortConfig = moduleConfig->getSingleConfigForMixPort(mIsInput, mixPort);
2834 ASSERT_TRUE(mixPortConfig.has_value())
2835 << "Unable to generate port config for mix port " << mixPort.toString();
2836 ASSERT_NO_FATAL_FAILURE(SetUpPortConfig(module, moduleConfig, *mixPortConfig, devicePort));
2837 }
SetUpPortConfig(IModule * module,ModuleConfig * moduleConfig,const AudioPortConfig & mixPortConfig,const AudioPort & devicePort)2838 void SetUpPortConfig(IModule* module, ModuleConfig* moduleConfig,
2839 const AudioPortConfig& mixPortConfig, const AudioPort& devicePort) {
2840 ASSERT_NO_FATAL_FAILURE(SetUpPatch(module, moduleConfig, mixPortConfig, devicePort));
2841 mStream = std::make_unique<WithStream<Stream>>(mMixPortConfig->get());
2842 ASSERT_NO_FATAL_FAILURE(mStream->SetUpPortConfig(module));
2843 }
2844
SetUpStreamNoChecks(IModule * module)2845 ScopedAStatus SetUpStreamNoChecks(IModule* module) {
2846 return mStream->SetUpNoChecks(module, getMinimumStreamBufferSizeFrames());
2847 }
SetUpStream(IModule * module)2848 void SetUpStream(IModule* module) {
2849 ASSERT_NO_FATAL_FAILURE(mStream->SetUpStream(module, getMinimumStreamBufferSizeFrames()));
2850 }
2851
SetUpStreamForDevicePort(IModule * module,ModuleConfig * moduleConfig,const AudioPort & devicePort,bool connectedOnly=false)2852 void SetUpStreamForDevicePort(IModule* module, ModuleConfig* moduleConfig,
2853 const AudioPort& devicePort, bool connectedOnly = false) {
2854 ASSERT_NO_FATAL_FAILURE(
2855 SetUpPortConfigForDevicePort(module, moduleConfig, devicePort, connectedOnly));
2856 if (!mSkipTestReason.empty()) return;
2857 ASSERT_NO_FATAL_FAILURE(SetUpStream(module));
2858 }
SetUpStreamForAnyMixPort(IModule * module,ModuleConfig * moduleConfig,bool connectedOnly=false)2859 void SetUpStreamForAnyMixPort(IModule* module, ModuleConfig* moduleConfig,
2860 bool connectedOnly = false) {
2861 ASSERT_NO_FATAL_FAILURE(SetUpPortConfigAnyMixPort(module, moduleConfig, connectedOnly));
2862 if (!mSkipTestReason.empty()) return;
2863 ASSERT_NO_FATAL_FAILURE(SetUpStream(module));
2864 }
SetUpStreamForMixPort(IModule * module,ModuleConfig * moduleConfig,const AudioPort & mixPort,bool connectedOnly=false)2865 void SetUpStreamForMixPort(IModule* module, ModuleConfig* moduleConfig,
2866 const AudioPort& mixPort, bool connectedOnly = false) {
2867 ASSERT_NO_FATAL_FAILURE(
2868 SetUpPortConfigForMixPortOrConfig(module, moduleConfig, mixPort, connectedOnly));
2869 if (!mSkipTestReason.empty()) return;
2870 ASSERT_NO_FATAL_FAILURE(SetUpStream(module));
2871 }
SetUpStreamForPortsPair(IModule * module,ModuleConfig * moduleConfig,const AudioPort & mixPort,const AudioPort & devicePort)2872 void SetUpStreamForPortsPair(IModule* module, ModuleConfig* moduleConfig,
2873 const AudioPort& mixPort, const AudioPort& devicePort) {
2874 ASSERT_NO_FATAL_FAILURE(SetUpPortConfig(module, moduleConfig, mixPort, devicePort));
2875 if (!mSkipTestReason.empty()) return;
2876 ASSERT_NO_FATAL_FAILURE(SetUpStream(module));
2877 }
SetUpStreamForMixPortConfig(IModule * module,ModuleConfig * moduleConfig,const AudioPortConfig & mixPortConfig)2878 void SetUpStreamForMixPortConfig(IModule* module, ModuleConfig* moduleConfig,
2879 const AudioPortConfig& mixPortConfig) {
2880 // Since mix port configs may change after connecting an external device,
2881 // only connected device ports are considered.
2882 constexpr bool connectedOnly = true;
2883 const auto& ports = moduleConfig->getMixPorts(mIsInput, connectedOnly);
2884 const auto mixPortIt = findById<AudioPort>(ports, mixPortConfig.portId);
2885 ASSERT_NE(mixPortIt, ports.end()) << "Port id " << mixPortConfig.portId << " not found";
2886 ASSERT_NO_FATAL_FAILURE(SetUpPortConfigForMixPortOrConfig(module, moduleConfig, *mixPortIt,
2887 connectedOnly, mixPortConfig));
2888 if (!mSkipTestReason.empty()) return;
2889 ASSERT_NO_FATAL_FAILURE(SetUpStream(module));
2890 }
SetUpPatchForMixPortConfig(IModule * module,ModuleConfig * moduleConfig,const AudioPortConfig & mixPortConfig)2891 void SetUpPatchForMixPortConfig(IModule* module, ModuleConfig* moduleConfig,
2892 const AudioPortConfig& mixPortConfig) {
2893 constexpr bool connectedOnly = true;
2894 const auto& ports = moduleConfig->getMixPorts(mIsInput, connectedOnly);
2895 const auto mixPortIt = findById<AudioPort>(ports, mixPortConfig.portId);
2896 ASSERT_NE(mixPortIt, ports.end()) << "Port id " << mixPortConfig.portId << " not found";
2897 std::optional<AudioPort> connectedDevicePort;
2898 ASSERT_NO_FATAL_FAILURE(SetUpDevicePortForMixPort(module, moduleConfig, *mixPortIt,
2899 connectedOnly, &connectedDevicePort));
2900 if (!mSkipTestReason.empty()) return;
2901 ASSERT_NO_FATAL_FAILURE(
2902 SetUpPatch(module, moduleConfig, mixPortConfig, *connectedDevicePort));
2903 }
2904
ReconnectPatch(IModule * module)2905 void ReconnectPatch(IModule* module) {
2906 mPatch = std::make_unique<WithAudioPatch>(mIsInput, mMixPortConfig->get(),
2907 mDevicePortConfig->get());
2908 ASSERT_NO_FATAL_FAILURE(mPatch->SetUp(module));
2909 }
TeardownPatch()2910 void TeardownPatch() { mPatch.reset(); }
2911 // Assuming that the patch is set up, while the stream isn't yet,
2912 // tear the patch down and set up stream.
TeardownPatchSetUpStream(IModule * module)2913 void TeardownPatchSetUpStream(IModule* module) {
2914 const int32_t bufferSize = getMinimumStreamBufferSizeFrames();
2915 ASSERT_NO_FATAL_FAILURE(TeardownPatch());
2916 mStream = std::make_unique<WithStream<Stream>>(mMixPortConfig->get());
2917 ASSERT_NO_FATAL_FAILURE(mStream->SetUpPortConfig(module));
2918 ASSERT_NO_FATAL_FAILURE(mStream->SetUpStream(module, bufferSize));
2919 }
2920
getDevice() const2921 const AudioDevice& getDevice() const { return mDevice; }
getMinimumStreamBufferSizeFrames() const2922 int32_t getMinimumStreamBufferSizeFrames() const {
2923 return mPatch->getMinimumStreamBufferSizeFrames();
2924 }
getPatch() const2925 const AudioPatch& getPatch() const { return mPatch->get(); }
getPortConfig() const2926 const AudioPortConfig& getPortConfig() const { return mMixPortConfig->get(); }
getPortId() const2927 int32_t getPortId() const { return mMixPortConfig->getId(); }
getStream() const2928 Stream* getStream() const { return mStream->get(); }
getStreamContext() const2929 const StreamContext* getStreamContext() const { return mStream->getContext(); }
getStreamEventReceiver()2930 StreamEventReceiver* getStreamEventReceiver() { return mStream->getEventReceiver(); }
getStreamSharedPointer() const2931 std::shared_ptr<Stream> getStreamSharedPointer() const { return mStream->getSharedPointer(); }
skipTestReason() const2932 const std::string& skipTestReason() const { return mSkipTestReason; }
2933
2934 private:
SetUpDevicePort(IModule * module,ModuleConfig * moduleConfig,const std::set<int32_t> & devicePortIds,bool connectedOnly,std::optional<AudioPort> * connectedDevicePort)2935 void SetUpDevicePort(IModule* module, ModuleConfig* moduleConfig,
2936 const std::set<int32_t>& devicePortIds, bool connectedOnly,
2937 std::optional<AudioPort>* connectedDevicePort) {
2938 const auto attachedDevicePorts = moduleConfig->getAttachedDevicePorts();
2939 if (auto it = findAny<AudioPort>(attachedDevicePorts, devicePortIds);
2940 it != attachedDevicePorts.end()) {
2941 *connectedDevicePort = *it;
2942 LOG(DEBUG) << __func__ << ": found attached port " << it->toString();
2943 }
2944 const auto connectedDevicePorts = moduleConfig->getConnectedExternalDevicePorts();
2945 if (auto it = findAny<AudioPort>(connectedDevicePorts, devicePortIds);
2946 it != connectedDevicePorts.end()) {
2947 *connectedDevicePort = *it;
2948 LOG(DEBUG) << __func__ << ": found connected port " << it->toString();
2949 }
2950 if (!connectedOnly && !connectedDevicePort->has_value()) {
2951 const auto externalDevicePorts = moduleConfig->getExternalDevicePorts();
2952 if (auto it = findAny<AudioPort>(externalDevicePorts, devicePortIds);
2953 it != externalDevicePorts.end()) {
2954 AudioPort portWithData = GenerateUniqueDeviceAddress(*it);
2955 mPortConnected = std::make_unique<WithDevicePortConnectedState>(portWithData);
2956 ASSERT_NO_FATAL_FAILURE(mPortConnected->SetUp(module, moduleConfig));
2957 *connectedDevicePort = mPortConnected->get();
2958 LOG(DEBUG) << __func__ << ": connected port " << mPortConnected->get().toString();
2959 }
2960 }
2961 }
SetUpDevicePortForMixPort(IModule * module,ModuleConfig * moduleConfig,const AudioPort & mixPort,bool connectedOnly,std::optional<AudioPort> * connectedDevicePort)2962 void SetUpDevicePortForMixPort(IModule* module, ModuleConfig* moduleConfig,
2963 const AudioPort& mixPort, bool connectedOnly,
2964 std::optional<AudioPort>* connectedDevicePort) {
2965 const auto devicePorts =
2966 moduleConfig->getRoutableDevicePortsForMixPort(mixPort, connectedOnly);
2967 if (devicePorts.empty()) {
2968 mSkipTestReason = std::string("No routable device ports found for mix port id ")
2969 .append(std::to_string(mixPort.id));
2970 LOG(DEBUG) << __func__ << ": " << mSkipTestReason;
2971 return;
2972 };
2973 ASSERT_NO_FATAL_FAILURE(SetUpDevicePort(module, moduleConfig,
2974 extractIds<AudioPort>(devicePorts), connectedOnly,
2975 connectedDevicePort));
2976 if (!connectedDevicePort->has_value()) {
2977 mSkipTestReason = std::string("Unable to find a device port pair for mix port id ")
2978 .append(std::to_string(mixPort.id));
2979 LOG(DEBUG) << __func__ << ": " << mSkipTestReason;
2980 return;
2981 }
2982 }
SetUpPortConfigForDevicePort(IModule * module,ModuleConfig * moduleConfig,const AudioPort & devicePort,bool connectedOnly)2983 void SetUpPortConfigForDevicePort(IModule* module, ModuleConfig* moduleConfig,
2984 const AudioPort& devicePort, bool connectedOnly) {
2985 std::optional<AudioPort> connectedDevicePort;
2986 ASSERT_NO_FATAL_FAILURE(SetUpDevicePort(module, moduleConfig, {devicePort.id},
2987 connectedOnly, &connectedDevicePort));
2988 if (!connectedDevicePort.has_value()) {
2989 mSkipTestReason = std::string("Device port id ")
2990 .append(std::to_string(devicePort.id))
2991 .append(" is not attached and can not be connected");
2992 return;
2993 }
2994 const auto mixPorts = moduleConfig->getRoutableMixPortsForDevicePort(
2995 *connectedDevicePort, true /*connectedOnly*/);
2996 if (mixPorts.empty()) {
2997 mSkipTestReason = std::string("No routable mix ports found for device port id ")
2998 .append(std::to_string(devicePort.id));
2999 return;
3000 }
3001 ASSERT_NO_FATAL_FAILURE(
3002 SetUpPortConfig(module, moduleConfig, *mixPorts.begin(), *connectedDevicePort));
3003 }
SetUpPatch(IModule * module,ModuleConfig * moduleConfig,const AudioPortConfig & mixPortConfig,const AudioPort & devicePort)3004 void SetUpPatch(IModule* module, ModuleConfig* moduleConfig,
3005 const AudioPortConfig& mixPortConfig, const AudioPort& devicePort) {
3006 mMixPortConfig = std::make_unique<WithAudioPortConfig>(mixPortConfig);
3007 ASSERT_NO_FATAL_FAILURE(mMixPortConfig->SetUp(module));
3008 mDevicePortConfig = std::make_unique<WithAudioPortConfig>(
3009 moduleConfig->getSingleConfigForDevicePort(devicePort));
3010 ASSERT_NO_FATAL_FAILURE(mDevicePortConfig->SetUp(module));
3011 mDevice = devicePort.ext.get<AudioPortExt::device>().device;
3012 mPatch = std::make_unique<WithAudioPatch>(mIsInput, mMixPortConfig->get(),
3013 mDevicePortConfig->get());
3014 ASSERT_NO_FATAL_FAILURE(mPatch->SetUp(module));
3015 }
3016
3017 const bool mIsInput;
3018 std::string mSkipTestReason;
3019 std::unique_ptr<WithDevicePortConnectedState> mPortConnected;
3020 AudioDevice mDevice;
3021 std::unique_ptr<WithAudioPortConfig> mMixPortConfig;
3022 std::unique_ptr<WithAudioPortConfig> mDevicePortConfig;
3023 std::unique_ptr<WithAudioPatch> mPatch;
3024 std::unique_ptr<WithStream<Stream>> mStream;
3025 };
3026
3027 class StreamLogicDefaultDriver : public StreamLogicDriver {
3028 public:
StreamLogicDefaultDriver(std::shared_ptr<StateSequence> commands,size_t frameSizeBytes,bool isMmap)3029 StreamLogicDefaultDriver(std::shared_ptr<StateSequence> commands, size_t frameSizeBytes,
3030 bool isMmap)
3031 : mCommands(commands), mFrameSizeBytes(frameSizeBytes), mIsMmap(isMmap) {
3032 mCommands->rewind();
3033 }
3034
3035 // The five methods below is intended to be called after the worker
3036 // thread has joined, thus no extra synchronization is needed.
hasObservablePositionIncrease() const3037 bool hasObservablePositionIncrease() const { return mObservable.hasPositionIncrease; }
hasObservableRetrogradePosition() const3038 bool hasObservableRetrogradePosition() const { return mObservable.hasRetrogradePosition; }
hasHardwarePositionIncrease() const3039 bool hasHardwarePositionIncrease() const {
3040 // For non-MMap, always return true to pass the validation.
3041 return mIsMmap ? mHardware.hasPositionIncrease : true;
3042 }
hasHardwareRetrogradePosition() const3043 bool hasHardwareRetrogradePosition() const {
3044 // For non-MMap, always return false to pass the validation.
3045 return mIsMmap ? mHardware.hasRetrogradePosition : false;
3046 }
getUnexpectedStateTransition() const3047 std::string getUnexpectedStateTransition() const { return mUnexpectedTransition; }
3048
done()3049 bool done() override { return mCommands->done(); }
getNextTrigger(int maxDataSize,int * actualSize)3050 TransitionTrigger getNextTrigger(int maxDataSize, int* actualSize) override {
3051 auto trigger = mCommands->getTrigger();
3052 if (StreamDescriptor::Command* command = std::get_if<StreamDescriptor::Command>(&trigger);
3053 command != nullptr) {
3054 if (command->getTag() == StreamDescriptor::Command::Tag::burst) {
3055 if (actualSize != nullptr) {
3056 // In the output scenario, reduce slightly the fmqByteCount to verify
3057 // that the HAL module always consumes all data from the MQ.
3058 if (maxDataSize > static_cast<int>(mFrameSizeBytes)) {
3059 LOG(DEBUG) << __func__ << ": reducing data size by " << mFrameSizeBytes;
3060 maxDataSize -= mFrameSizeBytes;
3061 }
3062 *actualSize = maxDataSize;
3063 }
3064 command->set<StreamDescriptor::Command::Tag::burst>(maxDataSize);
3065 } else {
3066 if (actualSize != nullptr) *actualSize = 0;
3067 }
3068 }
3069 return trigger;
3070 }
interceptRawReply(const StreamDescriptor::Reply &)3071 bool interceptRawReply(const StreamDescriptor::Reply&) override { return false; }
processValidReply(const StreamDescriptor::Reply & reply)3072 bool processValidReply(const StreamDescriptor::Reply& reply) override {
3073 mObservable.update(reply.observable.frames);
3074 if (mIsMmap) {
3075 mHardware.update(reply.hardware.frames);
3076 }
3077
3078 auto expected = mCommands->getExpectedStates();
3079 if (expected.count(reply.state) == 0) {
3080 std::string s =
3081 std::string("Unexpected transition from the state ")
3082 .append(mPreviousState.has_value() ? toString(mPreviousState.value())
3083 : "<initial state>")
3084 .append(" to ")
3085 .append(toString(reply.state))
3086 .append(" (expected one of ")
3087 .append(::android::internal::ToString(expected))
3088 .append(") caused by the ")
3089 .append(toString(mCommands->getTrigger()));
3090 LOG(ERROR) << __func__ << ": " << s;
3091 mUnexpectedTransition = std::move(s);
3092 return false;
3093 }
3094 mCommands->advance(reply.state);
3095 mPreviousState = reply.state;
3096 return true;
3097 }
3098
3099 protected:
3100 struct FramesCounter {
3101 std::optional<int64_t> previous;
3102 bool hasPositionIncrease = false;
3103 bool hasRetrogradePosition = false;
3104
updateStreamLogicDefaultDriver::FramesCounter3105 void update(int64_t position) {
3106 if (position == StreamDescriptor::Position::UNKNOWN) return;
3107 if (previous.has_value()) {
3108 if (position > previous.value()) {
3109 hasPositionIncrease = true;
3110 } else if (position < previous.value()) {
3111 hasRetrogradePosition = true;
3112 }
3113 }
3114 previous = position;
3115 }
3116 };
3117
3118 std::shared_ptr<StateSequence> mCommands;
3119 const size_t mFrameSizeBytes;
3120 const bool mIsMmap;
3121 std::optional<StreamDescriptor::State> mPreviousState;
3122 FramesCounter mObservable;
3123 FramesCounter mHardware;
3124 std::string mUnexpectedTransition;
3125 };
3126
3127 // Defined later together with state transition sequences.
3128 std::shared_ptr<StateSequence> makeBurstCommands(bool isSync);
3129
3130 // Certain types of ports can not be used without special preconditions.
skipStreamIoTestForMixPortConfig(const AudioPortConfig & portConfig)3131 static bool skipStreamIoTestForMixPortConfig(const AudioPortConfig& portConfig) {
3132 return (portConfig.flags.value().getTag() == AudioIoFlags::input &&
3133 isAnyBitPositionFlagSet(portConfig.flags.value().template get<AudioIoFlags::input>(),
3134 {AudioInputFlags::MMAP_NOIRQ, AudioInputFlags::VOIP_TX,
3135 AudioInputFlags::HW_HOTWORD, AudioInputFlags::HOTWORD_TAP})) ||
3136 (portConfig.flags.value().getTag() == AudioIoFlags::output &&
3137 isAnyBitPositionFlagSet(
3138 portConfig.flags.value().template get<AudioIoFlags::output>(),
3139 {AudioOutputFlags::MMAP_NOIRQ, AudioOutputFlags::VOIP_RX,
3140 AudioOutputFlags::COMPRESS_OFFLOAD, AudioOutputFlags::INCALL_MUSIC}));
3141 }
3142
3143 // Certain types of devices can not be used without special preconditions.
skipStreamIoTestForDevice(const AudioDevice & device)3144 static bool skipStreamIoTestForDevice(const AudioDevice& device) {
3145 return device.type.type == AudioDeviceType::IN_ECHO_REFERENCE;
3146 }
3147
3148 template <typename Stream>
3149 class StreamFixtureWithWorker {
3150 public:
StreamFixtureWithWorker(bool isSync)3151 explicit StreamFixtureWithWorker(bool isSync) : mIsSync(isSync) {}
3152
SetUp(IModule * module,ModuleConfig * moduleConfig,const AudioPort & devicePort)3153 void SetUp(IModule* module, ModuleConfig* moduleConfig, const AudioPort& devicePort) {
3154 mStream = std::make_unique<StreamFixture<Stream>>();
3155 ASSERT_NO_FATAL_FAILURE(
3156 mStream->SetUpStreamForDevicePort(module, moduleConfig, devicePort));
3157 MaybeSetSkipTestReason();
3158 }
3159
SetUp(IModule * module,ModuleConfig * moduleConfig,const AudioPort & mixPort,const AudioPort & devicePort)3160 void SetUp(IModule* module, ModuleConfig* moduleConfig, const AudioPort& mixPort,
3161 const AudioPort& devicePort) {
3162 mStream = std::make_unique<StreamFixture<Stream>>();
3163 ASSERT_NO_FATAL_FAILURE(
3164 mStream->SetUpStreamForPortsPair(module, moduleConfig, mixPort, devicePort));
3165 MaybeSetSkipTestReason();
3166 }
3167
SendBurstCommands(bool validatePosition=true)3168 void SendBurstCommands(bool validatePosition = true) {
3169 ASSERT_NO_FATAL_FAILURE(StartWorkerToSendBurstCommands());
3170 ASSERT_NO_FATAL_FAILURE(JoinWorkerAfterBurstCommands(validatePosition));
3171 }
3172
StartWorkerToSendBurstCommands()3173 void StartWorkerToSendBurstCommands() {
3174 const StreamContext* context = mStream->getStreamContext();
3175 mWorkerDriver = std::make_unique<StreamLogicDefaultDriver>(
3176 makeBurstCommands(mIsSync), context->getFrameSizeBytes(), context->isMmapped());
3177 mWorker = std::make_unique<typename IOTraits<Stream>::Worker>(
3178 *context, mWorkerDriver.get(), mStream->getStreamEventReceiver());
3179 LOG(DEBUG) << __func__ << ": starting " << IOTraits<Stream>::directionStr << " worker...";
3180 ASSERT_TRUE(mWorker->start());
3181 }
3182
JoinWorkerAfterBurstCommands(bool validatePosition=true)3183 void JoinWorkerAfterBurstCommands(bool validatePosition = true) {
3184 // Must call 'prepareToClose' before attempting to join because the stream may be stuck.
3185 std::shared_ptr<IStreamCommon> common;
3186 ASSERT_IS_OK(mStream->getStream()->getStreamCommon(&common));
3187 ASSERT_IS_OK(common->prepareToClose());
3188 LOG(DEBUG) << __func__ << ": joining " << IOTraits<Stream>::directionStr << " worker...";
3189 mWorker->join();
3190 EXPECT_FALSE(mWorker->hasError()) << mWorker->getError();
3191 EXPECT_EQ("", mWorkerDriver->getUnexpectedStateTransition());
3192 if (validatePosition) {
3193 EXPECT_TRUE(mWorkerDriver->hasObservablePositionIncrease());
3194 EXPECT_TRUE(mWorkerDriver->hasHardwarePositionIncrease());
3195 EXPECT_FALSE(mWorkerDriver->hasObservableRetrogradePosition());
3196 EXPECT_FALSE(mWorkerDriver->hasHardwareRetrogradePosition());
3197 }
3198 mWorker.reset();
3199 mWorkerDriver.reset();
3200 }
3201
TeardownPatch()3202 void TeardownPatch() { mStream->TeardownPatch(); }
3203
getDevice() const3204 const AudioDevice& getDevice() const { return mStream->getDevice(); }
getStream() const3205 Stream* getStream() const { return mStream->getStream(); }
skipTestReason() const3206 std::string skipTestReason() const {
3207 return !mSkipTestReason.empty() ? mSkipTestReason : mStream->skipTestReason();
3208 }
3209
3210 private:
MaybeSetSkipTestReason()3211 void MaybeSetSkipTestReason() {
3212 if (skipStreamIoTestForMixPortConfig(mStream->getPortConfig())) {
3213 mSkipTestReason = "Mix port config is not supported for stream I/O tests";
3214 }
3215 }
3216
3217 const bool mIsSync;
3218 std::string mSkipTestReason;
3219 std::unique_ptr<StreamFixture<Stream>> mStream;
3220 std::unique_ptr<StreamLogicDefaultDriver> mWorkerDriver;
3221 std::unique_ptr<typename IOTraits<Stream>::Worker> mWorker;
3222 };
3223
3224 template <typename Stream>
3225 class AudioStream : public AudioCoreModule {
3226 public:
SetUp()3227 void SetUp() override {
3228 ASSERT_NO_FATAL_FAILURE(AudioCoreModule::SetUp());
3229 ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
3230 }
3231
GetStreamCommon()3232 void GetStreamCommon() {
3233 StreamFixture<Stream> stream;
3234 ASSERT_NO_FATAL_FAILURE(stream.SetUpStreamForAnyMixPort(module.get(), moduleConfig.get()));
3235 if (auto reason = stream.skipTestReason(); !reason.empty()) {
3236 GTEST_SKIP() << reason;
3237 }
3238 std::shared_ptr<IStreamCommon> streamCommon1;
3239 EXPECT_IS_OK(stream.getStream()->getStreamCommon(&streamCommon1));
3240 std::shared_ptr<IStreamCommon> streamCommon2;
3241 EXPECT_IS_OK(stream.getStream()->getStreamCommon(&streamCommon2));
3242 ASSERT_NE(nullptr, streamCommon1);
3243 ASSERT_NE(nullptr, streamCommon2);
3244 EXPECT_EQ(streamCommon1->asBinder(), streamCommon2->asBinder())
3245 << "getStreamCommon must return the same interface instance across invocations";
3246 }
3247
CloseTwice()3248 void CloseTwice() {
3249 std::shared_ptr<Stream> heldStream;
3250 {
3251 StreamFixture<Stream> stream;
3252 ASSERT_NO_FATAL_FAILURE(
3253 stream.SetUpStreamForAnyMixPort(module.get(), moduleConfig.get()));
3254 if (auto reason = stream.skipTestReason(); !reason.empty()) {
3255 GTEST_SKIP() << reason;
3256 }
3257 heldStream = stream.getStreamSharedPointer();
3258 }
3259 EXPECT_STATUS(EX_ILLEGAL_STATE, WithStream<Stream>::callClose(heldStream))
3260 << "when closing the stream twice";
3261 }
3262
PrepareToCloseTwice()3263 void PrepareToCloseTwice() {
3264 std::shared_ptr<IStreamCommon> heldStreamCommon;
3265 {
3266 StreamFixture<Stream> stream;
3267 ASSERT_NO_FATAL_FAILURE(
3268 stream.SetUpStreamForAnyMixPort(module.get(), moduleConfig.get()));
3269 if (auto reason = stream.skipTestReason(); !reason.empty()) {
3270 GTEST_SKIP() << reason;
3271 }
3272 std::shared_ptr<IStreamCommon> streamCommon;
3273 ASSERT_IS_OK(stream.getStream()->getStreamCommon(&streamCommon));
3274 heldStreamCommon = streamCommon;
3275 EXPECT_IS_OK(streamCommon->prepareToClose());
3276 EXPECT_IS_OK(streamCommon->prepareToClose())
3277 << "when calling prepareToClose second time";
3278 }
3279 EXPECT_STATUS(EX_ILLEGAL_STATE, heldStreamCommon->prepareToClose())
3280 << "when calling prepareToClose on a closed stream";
3281 }
3282
OpenAllConfigs()3283 void OpenAllConfigs() {
3284 const auto allPortConfigs =
3285 moduleConfig->getPortConfigsForMixPorts(IOTraits<Stream>::is_input);
3286 if (allPortConfigs.empty()) {
3287 GTEST_SKIP() << "No mix ports for attached devices";
3288 }
3289 for (const auto& portConfig : allPortConfigs) {
3290 StreamFixture<Stream> stream;
3291 ASSERT_NO_FATAL_FAILURE(stream.SetUpStreamForMixPortConfig(
3292 module.get(), moduleConfig.get(), portConfig));
3293 }
3294 }
3295
OpenInvalidBufferSize()3296 void OpenInvalidBufferSize() {
3297 const auto portConfig = moduleConfig->getSingleConfigForMixPort(IOTraits<Stream>::is_input);
3298 if (!portConfig.has_value()) {
3299 GTEST_SKIP() << "No mix port for attached devices";
3300 }
3301 WithStream<Stream> stream(portConfig.value());
3302 ASSERT_NO_FATAL_FAILURE(stream.SetUpPortConfig(module.get()));
3303 for (long bufferSize : std::array<long, 3>{-1, 0, std::numeric_limits<long>::max()}) {
3304 EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, stream.SetUpNoChecks(module.get(), bufferSize))
3305 << "for the buffer size " << bufferSize;
3306 EXPECT_EQ(nullptr, stream.get());
3307 }
3308 }
3309
OpenInvalidDirection()3310 void OpenInvalidDirection() {
3311 // Important! The direction of the port config must be reversed.
3312 StreamFixture<Stream> stream(!IOTraits<Stream>::is_input);
3313 ASSERT_NO_FATAL_FAILURE(stream.SetUpPortConfigAnyMixPort(module.get(), moduleConfig.get(),
3314 false /*connectedOnly*/));
3315 if (auto reason = stream.skipTestReason(); !reason.empty()) {
3316 GTEST_SKIP() << reason;
3317 }
3318 EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, stream.SetUpStreamNoChecks(module.get()))
3319 << "port config ID " << stream.getPortId();
3320 EXPECT_EQ(nullptr, stream.getStream());
3321 }
3322
OpenOverMaxCount()3323 void OpenOverMaxCount() {
3324 constexpr bool connectedOnly = true;
3325 constexpr bool isInput = IOTraits<Stream>::is_input;
3326 auto ports = moduleConfig->getMixPorts(isInput, connectedOnly);
3327 bool hasSingleRun = false;
3328 for (const auto& port : ports) {
3329 const size_t maxStreamCount = port.ext.get<AudioPortExt::Tag::mix>().maxOpenStreamCount;
3330 if (maxStreamCount == 0) {
3331 continue;
3332 }
3333 auto portConfigs = moduleConfig->getPortConfigsForMixPorts(isInput, port);
3334 if (portConfigs.size() < maxStreamCount + 1) {
3335 // Not able to open a sufficient number of streams for this port.
3336 continue;
3337 }
3338 hasSingleRun = true;
3339 StreamFixture<Stream> streams[maxStreamCount + 1];
3340 for (size_t i = 0; i <= maxStreamCount; ++i) {
3341 ASSERT_NO_FATAL_FAILURE(streams[i].SetUpPortConfigForMixPortOrConfig(
3342 module.get(), moduleConfig.get(), port, connectedOnly, portConfigs[i]));
3343 ASSERT_EQ("", streams[i].skipTestReason());
3344 auto& stream = streams[i];
3345 if (i < maxStreamCount) {
3346 ASSERT_NO_FATAL_FAILURE(stream.SetUpStream(module.get()));
3347 } else {
3348 EXPECT_STATUS(EX_ILLEGAL_STATE, stream.SetUpStreamNoChecks(module.get()))
3349 << "port config ID " << stream.getPortId() << ", maxOpenStreamCount is "
3350 << maxStreamCount;
3351 }
3352 }
3353 }
3354 if (!hasSingleRun) {
3355 GTEST_SKIP() << "Not enough ports to test max open stream count";
3356 }
3357 }
3358
OpenTwiceSamePortConfig()3359 void OpenTwiceSamePortConfig() {
3360 const auto portConfig = moduleConfig->getSingleConfigForMixPort(IOTraits<Stream>::is_input);
3361 if (!portConfig.has_value()) {
3362 GTEST_SKIP() << "No mix port for attached devices";
3363 }
3364 EXPECT_NO_FATAL_FAILURE(OpenTwiceSamePortConfigImpl(portConfig.value()));
3365 }
3366
ResetPortConfigWithOpenStream()3367 void ResetPortConfigWithOpenStream() {
3368 StreamFixture<Stream> stream;
3369 ASSERT_NO_FATAL_FAILURE(stream.SetUpStreamForAnyMixPort(module.get(), moduleConfig.get()));
3370 if (auto reason = stream.skipTestReason(); !reason.empty()) {
3371 GTEST_SKIP() << reason;
3372 }
3373 EXPECT_STATUS(EX_ILLEGAL_STATE, module->resetAudioPortConfig(stream.getPortId()))
3374 << "port config ID " << stream.getPortId();
3375 }
3376
SendInvalidCommand()3377 void SendInvalidCommand() {
3378 const auto portConfig = moduleConfig->getSingleConfigForMixPort(IOTraits<Stream>::is_input);
3379 if (!portConfig.has_value()) {
3380 GTEST_SKIP() << "No mix port for attached devices";
3381 }
3382 EXPECT_NO_FATAL_FAILURE(SendInvalidCommandImpl(portConfig.value()));
3383 }
3384
UpdateHwAvSyncId()3385 void UpdateHwAvSyncId() {
3386 StreamFixture<Stream> stream;
3387 ASSERT_NO_FATAL_FAILURE(stream.SetUpStreamForAnyMixPort(module.get(), moduleConfig.get()));
3388 if (auto reason = stream.skipTestReason(); !reason.empty()) {
3389 GTEST_SKIP() << reason;
3390 }
3391 std::shared_ptr<IStreamCommon> streamCommon;
3392 ASSERT_IS_OK(stream.getStream()->getStreamCommon(&streamCommon));
3393 ASSERT_NE(nullptr, streamCommon);
3394 const auto kStatuses = {EX_NONE, EX_ILLEGAL_ARGUMENT, EX_ILLEGAL_STATE};
3395 for (const auto id : {-100, -1, 0, 1, 100}) {
3396 ndk::ScopedAStatus status = streamCommon->updateHwAvSyncId(id);
3397 if (status.getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
3398 GTEST_SKIP() << "HW AV Sync is not supported";
3399 }
3400 EXPECT_STATUS(kStatuses, status) << "id: " << id;
3401 }
3402 }
3403
GetVendorParameters()3404 void GetVendorParameters() {
3405 StreamFixture<Stream> stream;
3406 ASSERT_NO_FATAL_FAILURE(stream.SetUpStreamForAnyMixPort(module.get(), moduleConfig.get()));
3407 if (auto reason = stream.skipTestReason(); !reason.empty()) {
3408 GTEST_SKIP() << reason;
3409 }
3410 std::shared_ptr<IStreamCommon> streamCommon;
3411 ASSERT_IS_OK(stream.getStream()->getStreamCommon(&streamCommon));
3412 ASSERT_NE(nullptr, streamCommon);
3413
3414 bool isGetterSupported = false;
3415 EXPECT_NO_FATAL_FAILURE(TestGetVendorParameters(module.get(), &isGetterSupported));
3416 ndk::ScopedAStatus status = module->setVendorParameters({}, false);
3417 EXPECT_EQ(isGetterSupported, status.getExceptionCode() != EX_UNSUPPORTED_OPERATION)
3418 << "Support for getting and setting of vendor parameters must be consistent";
3419 if (!isGetterSupported) {
3420 GTEST_SKIP() << "Vendor parameters are not supported";
3421 }
3422 }
3423
SetVendorParameters()3424 void SetVendorParameters() {
3425 StreamFixture<Stream> stream;
3426 ASSERT_NO_FATAL_FAILURE(stream.SetUpStreamForAnyMixPort(module.get(), moduleConfig.get()));
3427 if (auto reason = stream.skipTestReason(); !reason.empty()) {
3428 GTEST_SKIP() << reason;
3429 }
3430 std::shared_ptr<IStreamCommon> streamCommon;
3431 ASSERT_IS_OK(stream.getStream()->getStreamCommon(&streamCommon));
3432 ASSERT_NE(nullptr, streamCommon);
3433
3434 bool isSupported = false;
3435 EXPECT_NO_FATAL_FAILURE(TestSetVendorParameters(module.get(), &isSupported));
3436 if (!isSupported) {
3437 GTEST_SKIP() << "Vendor parameters are not supported";
3438 }
3439 }
3440
HwGainHwVolume()3441 void HwGainHwVolume() {
3442 // Since device connection emulation does not cover complete functionality,
3443 // only use this test with connected devices.
3444 constexpr bool connectedOnly = true;
3445 const auto ports = moduleConfig->getMixPorts(IOTraits<Stream>::is_input, connectedOnly);
3446 if (ports.empty()) {
3447 GTEST_SKIP() << "No mix ports";
3448 }
3449 bool atLeastOneSupports = false;
3450 for (const auto& port : ports) {
3451 SCOPED_TRACE(port.toString());
3452 StreamFixture<Stream> stream;
3453 ASSERT_NO_FATAL_FAILURE(stream.SetUpStreamForMixPort(module.get(), moduleConfig.get(),
3454 port, connectedOnly));
3455 if (!stream.skipTestReason().empty()) continue;
3456 const auto portConfig = stream.getPortConfig();
3457 SCOPED_TRACE(portConfig.toString());
3458 std::vector<std::vector<float>> validValues, invalidValues;
3459 bool isSupported = false;
3460 if constexpr (IOTraits<Stream>::is_input) {
3461 GenerateTestArrays<float>(getChannelCount(portConfig.channelMask.value()),
3462 IStreamIn::HW_GAIN_MIN, IStreamIn::HW_GAIN_MAX,
3463 &validValues, &invalidValues);
3464 EXPECT_NO_FATAL_FAILURE(TestAccessors<std::vector<float>>(
3465 stream.getStream(), &IStreamIn::getHwGain, &IStreamIn::setHwGain,
3466 validValues, invalidValues, &isSupported));
3467 } else {
3468 GenerateTestArrays<float>(getChannelCount(portConfig.channelMask.value()),
3469 IStreamOut::HW_VOLUME_MIN, IStreamOut::HW_VOLUME_MAX,
3470 &validValues, &invalidValues);
3471 EXPECT_NO_FATAL_FAILURE(TestAccessors<std::vector<float>>(
3472 stream.getStream(), &IStreamOut::getHwVolume, &IStreamOut::setHwVolume,
3473 validValues, invalidValues, &isSupported));
3474 }
3475 if (isSupported) atLeastOneSupports = true;
3476 }
3477 if (!atLeastOneSupports) {
3478 GTEST_SKIP() << "Hardware gain / volume is not supported";
3479 }
3480 }
3481
3482 // See b/262930731. In the absence of offloaded effect implementations,
3483 // currently we can only pass a nullptr, and the HAL module must either reject
3484 // it as an invalid argument, or say that offloaded effects are not supported.
AddRemoveEffectInvalidArguments()3485 void AddRemoveEffectInvalidArguments() {
3486 constexpr bool connectedOnly = true;
3487 const auto ports = moduleConfig->getMixPorts(IOTraits<Stream>::is_input, connectedOnly);
3488 if (ports.empty()) {
3489 GTEST_SKIP() << "No mix ports";
3490 }
3491 bool atLeastOneSupports = false;
3492 for (const auto& port : ports) {
3493 SCOPED_TRACE(port.toString());
3494 StreamFixture<Stream> stream;
3495 ASSERT_NO_FATAL_FAILURE(stream.SetUpStreamForMixPort(module.get(), moduleConfig.get(),
3496 port, connectedOnly));
3497 if (!stream.skipTestReason().empty()) continue;
3498 const auto portConfig = stream.getPortConfig();
3499 SCOPED_TRACE(portConfig.toString());
3500 std::shared_ptr<IStreamCommon> streamCommon;
3501 ASSERT_IS_OK(stream.getStream()->getStreamCommon(&streamCommon));
3502 ASSERT_NE(nullptr, streamCommon);
3503 ndk::ScopedAStatus addEffectStatus = streamCommon->addEffect(nullptr);
3504 ndk::ScopedAStatus removeEffectStatus = streamCommon->removeEffect(nullptr);
3505 if (addEffectStatus.getExceptionCode() != EX_UNSUPPORTED_OPERATION) {
3506 EXPECT_EQ(EX_ILLEGAL_ARGUMENT, addEffectStatus.getExceptionCode());
3507 EXPECT_EQ(EX_ILLEGAL_ARGUMENT, removeEffectStatus.getExceptionCode());
3508 atLeastOneSupports = true;
3509 } else if (removeEffectStatus.getExceptionCode() != EX_UNSUPPORTED_OPERATION) {
3510 ADD_FAILURE() << "addEffect and removeEffect must be either supported or "
3511 << "not supported together";
3512 atLeastOneSupports = true;
3513 }
3514 }
3515 if (!atLeastOneSupports) {
3516 GTEST_SKIP() << "Offloaded effects not supported";
3517 }
3518 }
3519
OpenTwiceSamePortConfigImpl(const AudioPortConfig & portConfig)3520 void OpenTwiceSamePortConfigImpl(const AudioPortConfig& portConfig) {
3521 StreamFixture<Stream> stream1;
3522 ASSERT_NO_FATAL_FAILURE(
3523 stream1.SetUpStreamForMixPortConfig(module.get(), moduleConfig.get(), portConfig));
3524 ASSERT_EQ("", stream1.skipTestReason());
3525 WithStream<Stream> stream2;
3526 EXPECT_STATUS(EX_ILLEGAL_STATE,
3527 stream2.SetUpNoChecks(module.get(), stream1.getPortConfig(),
3528 stream1.getMinimumStreamBufferSizeFrames()))
3529 << "when opening a stream twice for the same port config ID "
3530 << stream1.getPortId();
3531 }
3532
SendInvalidCommandImpl(const AudioPortConfig & portConfig)3533 void SendInvalidCommandImpl(const AudioPortConfig& portConfig) {
3534 using TestSequence = std::pair<std::string, CommandSequence>;
3535 // The last command in 'CommandSequence' is the one that must trigger
3536 // an error status. All preceding commands are to put the state machine
3537 // into a state which accepts the last command.
3538 std::vector<TestSequence> sequences{
3539 std::make_pair(std::string("HalReservedExit"),
3540 std::vector{StreamDescriptor::Command::make<
3541 StreamDescriptor::Command::Tag::halReservedExit>(0)}),
3542 std::make_pair(std::string("BurstNeg"),
3543 std::vector{kStartCommand,
3544 StreamDescriptor::Command::make<
3545 StreamDescriptor::Command::Tag::burst>(-1)}),
3546 std::make_pair(
3547 std::string("BurstMinInt"),
3548 std::vector{kStartCommand, StreamDescriptor::Command::make<
3549 StreamDescriptor::Command::Tag::burst>(
3550 std::numeric_limits<int32_t>::min())})};
3551 if (IOTraits<Stream>::is_input) {
3552 sequences.emplace_back("DrainAll",
3553 std::vector{kStartCommand, kBurstCommand, kDrainOutAllCommand});
3554 sequences.emplace_back(
3555 "DrainEarly", std::vector{kStartCommand, kBurstCommand, kDrainOutEarlyCommand});
3556 } else {
3557 sequences.emplace_back("DrainUnspecified",
3558 std::vector{kStartCommand, kBurstCommand, kDrainInCommand});
3559 }
3560 for (const auto& seq : sequences) {
3561 SCOPED_TRACE(std::string("Sequence ").append(seq.first));
3562 LOG(DEBUG) << __func__ << ": Sequence " << seq.first;
3563 StreamFixture<Stream> stream;
3564 ASSERT_NO_FATAL_FAILURE(stream.SetUpStreamForMixPortConfig(
3565 module.get(), moduleConfig.get(), portConfig));
3566 ASSERT_EQ("", stream.skipTestReason());
3567 StreamLogicDriverInvalidCommand driver(seq.second);
3568 typename IOTraits<Stream>::Worker worker(*stream.getStreamContext(), &driver,
3569 stream.getStreamEventReceiver());
3570 LOG(DEBUG) << __func__ << ": starting worker...";
3571 ASSERT_TRUE(worker.start());
3572 LOG(DEBUG) << __func__ << ": joining worker...";
3573 worker.join();
3574 EXPECT_EQ("", driver.getUnexpectedStatuses());
3575 }
3576 }
3577 };
3578 using AudioStreamIn = AudioStream<IStreamIn>;
3579 using AudioStreamOut = AudioStream<IStreamOut>;
3580
3581 #define TEST_IN_AND_OUT_STREAM(method_name) \
3582 TEST_P(AudioStreamIn, method_name) { \
3583 ASSERT_NO_FATAL_FAILURE(method_name()); \
3584 } \
3585 TEST_P(AudioStreamOut, method_name) { \
3586 ASSERT_NO_FATAL_FAILURE(method_name()); \
3587 }
3588
3589 TEST_IN_AND_OUT_STREAM(CloseTwice);
3590 TEST_IN_AND_OUT_STREAM(PrepareToCloseTwice);
3591 TEST_IN_AND_OUT_STREAM(GetStreamCommon);
3592 TEST_IN_AND_OUT_STREAM(OpenAllConfigs);
3593 TEST_IN_AND_OUT_STREAM(OpenInvalidBufferSize);
3594 TEST_IN_AND_OUT_STREAM(OpenInvalidDirection);
3595 TEST_IN_AND_OUT_STREAM(OpenOverMaxCount);
3596 TEST_IN_AND_OUT_STREAM(OpenTwiceSamePortConfig);
3597 TEST_IN_AND_OUT_STREAM(ResetPortConfigWithOpenStream);
3598 TEST_IN_AND_OUT_STREAM(SendInvalidCommand);
3599 TEST_IN_AND_OUT_STREAM(UpdateHwAvSyncId);
3600 TEST_IN_AND_OUT_STREAM(GetVendorParameters);
3601 TEST_IN_AND_OUT_STREAM(SetVendorParameters);
3602 TEST_IN_AND_OUT_STREAM(HwGainHwVolume);
3603 TEST_IN_AND_OUT_STREAM(AddRemoveEffectInvalidArguments);
3604
3605 namespace aidl::android::hardware::audio::core {
operator <<(std::ostream & os,const IStreamIn::MicrophoneDirection & md)3606 std::ostream& operator<<(std::ostream& os, const IStreamIn::MicrophoneDirection& md) {
3607 os << toString(md);
3608 return os;
3609 }
3610 } // namespace aidl::android::hardware::audio::core
3611
TEST_P(AudioStreamIn,ActiveMicrophones)3612 TEST_P(AudioStreamIn, ActiveMicrophones) {
3613 std::vector<MicrophoneInfo> micInfos;
3614 ScopedAStatus status = module->getMicrophones(&micInfos);
3615 if (!status.isOk()) {
3616 GTEST_SKIP() << "Microphone info is not supported";
3617 }
3618 const auto ports = moduleConfig->getInputMixPorts(true /*connectedOnly*/);
3619 if (ports.empty()) {
3620 GTEST_SKIP() << "No input mix ports for attached devices";
3621 }
3622 bool atLeastOnePort = false;
3623 for (const auto& port : ports) {
3624 auto micDevicePorts = ModuleConfig::getBuiltInMicPorts(
3625 moduleConfig->getConnectedSourceDevicesPortsForMixPort(port));
3626 if (micDevicePorts.empty()) continue;
3627 atLeastOnePort = true;
3628 SCOPED_TRACE(port.toString());
3629 StreamFixtureWithWorker<IStreamIn> stream(true /*isSync*/);
3630 ASSERT_NO_FATAL_FAILURE(
3631 stream.SetUp(module.get(), moduleConfig.get(), port, micDevicePorts[0]));
3632 if (!stream.skipTestReason().empty()) continue;
3633
3634 ASSERT_NO_FATAL_FAILURE(stream.SendBurstCommands(false /*validatePosition*/));
3635 std::vector<MicrophoneDynamicInfo> activeMics;
3636 EXPECT_IS_OK(stream.getStream()->getActiveMicrophones(&activeMics));
3637 EXPECT_FALSE(activeMics.empty());
3638 for (const auto& mic : activeMics) {
3639 EXPECT_NE(micInfos.end(),
3640 std::find_if(micInfos.begin(), micInfos.end(),
3641 [&](const auto& micInfo) { return micInfo.id == mic.id; }))
3642 << "active microphone \"" << mic.id << "\" is not listed in "
3643 << "microphone infos returned by the module: "
3644 << ::android::internal::ToString(micInfos);
3645 EXPECT_NE(0UL, mic.channelMapping.size())
3646 << "No channels specified for the microphone \"" << mic.id << "\"";
3647 }
3648
3649 stream.TeardownPatch();
3650 // Now the port of the stream is not connected, check that there are no active microphones.
3651 std::vector<MicrophoneDynamicInfo> emptyMics;
3652 EXPECT_IS_OK(stream.getStream()->getActiveMicrophones(&emptyMics));
3653 EXPECT_TRUE(emptyMics.empty()) << "a stream on an unconnected port returns a "
3654 "non-empty list of active microphones";
3655 }
3656 if (!atLeastOnePort) {
3657 GTEST_SKIP() << "No input mix ports could be routed to built-in microphone devices";
3658 }
3659 }
3660
TEST_P(AudioStreamIn,MicrophoneDirection)3661 TEST_P(AudioStreamIn, MicrophoneDirection) {
3662 using MD = IStreamIn::MicrophoneDirection;
3663 constexpr bool connectedOnly = true;
3664 const auto ports = moduleConfig->getInputMixPorts(connectedOnly);
3665 if (ports.empty()) {
3666 GTEST_SKIP() << "No input mix ports for attached devices";
3667 }
3668 bool isSupported = false, atLeastOnePort = false;
3669 for (const auto& port : ports) {
3670 SCOPED_TRACE(port.toString());
3671 StreamFixture<IStreamIn> stream;
3672 ASSERT_NO_FATAL_FAILURE(stream.SetUpStreamForMixPort(module.get(), moduleConfig.get(), port,
3673 connectedOnly));
3674 if (!stream.skipTestReason().empty()) continue;
3675 atLeastOnePort = true;
3676 EXPECT_NO_FATAL_FAILURE(
3677 TestAccessors<MD>(stream.getStream(), &IStreamIn::getMicrophoneDirection,
3678 &IStreamIn::setMicrophoneDirection,
3679 std::vector<MD>(enum_range<MD>().begin(), enum_range<MD>().end()),
3680 {}, &isSupported));
3681 if (!isSupported) break;
3682 }
3683 if (!isSupported) {
3684 GTEST_SKIP() << "Microphone direction is not supported";
3685 }
3686 if (!atLeastOnePort) {
3687 GTEST_SKIP() << "No input mix ports could be routed to built-in microphone devices";
3688 }
3689 }
3690
TEST_P(AudioStreamIn,MicrophoneFieldDimension)3691 TEST_P(AudioStreamIn, MicrophoneFieldDimension) {
3692 constexpr bool connectedOnly = true;
3693 const auto ports = moduleConfig->getInputMixPorts(connectedOnly);
3694 if (ports.empty()) {
3695 GTEST_SKIP() << "No input mix ports for attached devices";
3696 }
3697 bool isSupported = false, atLeastOnePort = false;
3698 for (const auto& port : ports) {
3699 SCOPED_TRACE(port.toString());
3700 StreamFixture<IStreamIn> stream;
3701 ASSERT_NO_FATAL_FAILURE(stream.SetUpStreamForMixPort(module.get(), moduleConfig.get(), port,
3702 connectedOnly));
3703 if (!stream.skipTestReason().empty()) continue;
3704 atLeastOnePort = true;
3705 EXPECT_NO_FATAL_FAILURE(TestAccessors<float>(
3706 stream.getStream(), &IStreamIn::getMicrophoneFieldDimension,
3707 &IStreamIn::setMicrophoneFieldDimension,
3708 {IStreamIn::MIC_FIELD_DIMENSION_WIDE_ANGLE,
3709 IStreamIn::MIC_FIELD_DIMENSION_WIDE_ANGLE / 2.0f,
3710 IStreamIn::MIC_FIELD_DIMENSION_NO_ZOOM,
3711 IStreamIn::MIC_FIELD_DIMENSION_MAX_ZOOM / 2.0f,
3712 IStreamIn::MIC_FIELD_DIMENSION_MAX_ZOOM},
3713 {IStreamIn::MIC_FIELD_DIMENSION_WIDE_ANGLE * 2,
3714 IStreamIn::MIC_FIELD_DIMENSION_MAX_ZOOM * 2,
3715 IStreamIn::MIC_FIELD_DIMENSION_WIDE_ANGLE * 1.1f,
3716 IStreamIn::MIC_FIELD_DIMENSION_MAX_ZOOM * 1.1f, -INFINITY, INFINITY, -NAN, NAN},
3717 &isSupported));
3718 if (!isSupported) break;
3719 }
3720 if (!isSupported) {
3721 GTEST_SKIP() << "Microphone direction is not supported";
3722 }
3723 if (!atLeastOnePort) {
3724 GTEST_SKIP() << "No input mix ports could be routed to built-in microphone devices";
3725 }
3726 }
3727
TEST_P(AudioStreamOut,OpenTwicePrimary)3728 TEST_P(AudioStreamOut, OpenTwicePrimary) {
3729 const auto mixPorts =
3730 moduleConfig->getPrimaryMixPorts(true /*connectedOnly*/, true /*singlePort*/);
3731 if (mixPorts.empty()) {
3732 GTEST_SKIP() << "No primary mix port which could be routed to attached devices";
3733 }
3734 const auto portConfig = moduleConfig->getSingleConfigForMixPort(false, *mixPorts.begin());
3735 ASSERT_TRUE(portConfig.has_value()) << "No profiles specified for the primary mix port";
3736 EXPECT_NO_FATAL_FAILURE(OpenTwiceSamePortConfigImpl(portConfig.value()));
3737 }
3738
TEST_P(AudioStreamOut,RequireOffloadInfo)3739 TEST_P(AudioStreamOut, RequireOffloadInfo) {
3740 constexpr bool connectedOnly = true;
3741 const auto offloadMixPorts =
3742 moduleConfig->getOffloadMixPorts(connectedOnly, true /*singlePort*/);
3743 if (offloadMixPorts.empty()) {
3744 GTEST_SKIP()
3745 << "No mix port for compressed offload that could be routed to attached devices";
3746 }
3747 StreamFixture<IStreamOut> stream;
3748 ASSERT_NO_FATAL_FAILURE(stream.SetUpPortConfigForMixPortOrConfig(
3749 module.get(), moduleConfig.get(), *offloadMixPorts.begin(), connectedOnly));
3750 if (auto reason = stream.skipTestReason(); !reason.empty()) {
3751 GTEST_SKIP() << reason;
3752 }
3753 const auto portConfig = stream.getPortConfig();
3754 StreamDescriptor descriptor;
3755 aidl::android::hardware::audio::core::IModule::OpenOutputStreamArguments args;
3756 args.portConfigId = portConfig.id;
3757 args.sourceMetadata = GenerateSourceMetadata(portConfig);
3758 args.bufferSizeFrames = kDefaultLargeBufferSizeFrames;
3759 aidl::android::hardware::audio::core::IModule::OpenOutputStreamReturn ret;
3760 EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->openOutputStream(args, &ret))
3761 << "when no offload info is provided for a compressed offload mix port";
3762 if (ret.stream != nullptr) {
3763 (void)WithStream<IStreamOut>::callClose(ret.stream);
3764 }
3765 }
3766
TEST_P(AudioStreamOut,RequireAsyncCallback)3767 TEST_P(AudioStreamOut, RequireAsyncCallback) {
3768 constexpr bool connectedOnly = true;
3769 const auto nonBlockingMixPorts =
3770 moduleConfig->getNonBlockingMixPorts(connectedOnly, true /*singlePort*/);
3771 if (nonBlockingMixPorts.empty()) {
3772 GTEST_SKIP()
3773 << "No mix port for non-blocking output that could be routed to attached devices";
3774 }
3775 StreamFixture<IStreamOut> stream;
3776 ASSERT_NO_FATAL_FAILURE(stream.SetUpPortConfigForMixPortOrConfig(
3777 module.get(), moduleConfig.get(), *nonBlockingMixPorts.begin(), connectedOnly));
3778 if (auto reason = stream.skipTestReason(); !reason.empty()) {
3779 GTEST_SKIP() << reason;
3780 }
3781 const auto portConfig = stream.getPortConfig();
3782 StreamDescriptor descriptor;
3783 aidl::android::hardware::audio::core::IModule::OpenOutputStreamArguments args;
3784 args.portConfigId = portConfig.id;
3785 args.sourceMetadata = GenerateSourceMetadata(portConfig);
3786 args.offloadInfo = ModuleConfig::generateOffloadInfoIfNeeded(portConfig);
3787 args.bufferSizeFrames = stream.getPatch().minimumStreamBufferSizeFrames;
3788 aidl::android::hardware::audio::core::IModule::OpenOutputStreamReturn ret;
3789 EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->openOutputStream(args, &ret))
3790 << "when no async callback is provided for a non-blocking mix port";
3791 if (ret.stream != nullptr) {
3792 (void)WithStream<IStreamOut>::callClose(ret.stream);
3793 }
3794 }
3795
TEST_P(AudioStreamOut,AudioDescriptionMixLevel)3796 TEST_P(AudioStreamOut, AudioDescriptionMixLevel) {
3797 constexpr bool connectedOnly = true;
3798 const auto ports = moduleConfig->getOutputMixPorts(connectedOnly);
3799 if (ports.empty()) {
3800 GTEST_SKIP() << "No output mix ports for attached devices";
3801 }
3802 bool atLeastOneSupports = false, atLeastOnePort = false;
3803 for (const auto& port : ports) {
3804 SCOPED_TRACE(port.toString());
3805 StreamFixture<IStreamOut> stream;
3806 ASSERT_NO_FATAL_FAILURE(stream.SetUpStreamForMixPort(module.get(), moduleConfig.get(), port,
3807 connectedOnly));
3808 if (!stream.skipTestReason().empty()) continue;
3809 atLeastOnePort = true;
3810 bool isSupported = false;
3811 EXPECT_NO_FATAL_FAILURE(
3812 TestAccessors<float>(stream.getStream(), &IStreamOut::getAudioDescriptionMixLevel,
3813 &IStreamOut::setAudioDescriptionMixLevel,
3814 {IStreamOut::AUDIO_DESCRIPTION_MIX_LEVEL_MAX,
3815 IStreamOut::AUDIO_DESCRIPTION_MIX_LEVEL_MAX - 1, 0,
3816 -INFINITY /*IStreamOut::AUDIO_DESCRIPTION_MIX_LEVEL_MIN*/},
3817 {IStreamOut::AUDIO_DESCRIPTION_MIX_LEVEL_MAX * 2,
3818 IStreamOut::AUDIO_DESCRIPTION_MIX_LEVEL_MAX * 1.1f},
3819 &isSupported));
3820 if (isSupported) atLeastOneSupports = true;
3821 }
3822 if (!atLeastOnePort) {
3823 GTEST_SKIP() << "No output mix ports could be routed to devices";
3824 }
3825 if (!atLeastOneSupports) {
3826 GTEST_SKIP() << "Audio description mix level is not supported";
3827 }
3828 }
3829
TEST_P(AudioStreamOut,DualMonoMode)3830 TEST_P(AudioStreamOut, DualMonoMode) {
3831 constexpr bool connectedOnly = true;
3832 const auto ports = moduleConfig->getOutputMixPorts(connectedOnly);
3833 if (ports.empty()) {
3834 GTEST_SKIP() << "No output mix ports for attached devices";
3835 }
3836 bool atLeastOneSupports = false, atLeastOnePort = false;
3837 for (const auto& port : ports) {
3838 SCOPED_TRACE(port.toString());
3839 StreamFixture<IStreamOut> stream;
3840 ASSERT_NO_FATAL_FAILURE(stream.SetUpStreamForMixPort(module.get(), moduleConfig.get(), port,
3841 connectedOnly));
3842 if (!stream.skipTestReason().empty()) continue;
3843 atLeastOnePort = true;
3844 bool isSupported = false;
3845 EXPECT_NO_FATAL_FAILURE(TestAccessors<AudioDualMonoMode>(
3846 stream.getStream(), &IStreamOut::getDualMonoMode, &IStreamOut::setDualMonoMode,
3847 std::vector<AudioDualMonoMode>(enum_range<AudioDualMonoMode>().begin(),
3848 enum_range<AudioDualMonoMode>().end()),
3849 {}, &isSupported));
3850 if (isSupported) atLeastOneSupports = true;
3851 }
3852 if (!atLeastOnePort) {
3853 GTEST_SKIP() << "No output mix ports could be routed to devices";
3854 }
3855 if (!atLeastOneSupports) {
3856 GTEST_SKIP() << "Audio dual mono mode is not supported";
3857 }
3858 }
3859
TEST_P(AudioStreamOut,LatencyMode)3860 TEST_P(AudioStreamOut, LatencyMode) {
3861 constexpr bool connectedOnly = true;
3862 const auto ports = moduleConfig->getOutputMixPorts(connectedOnly);
3863 if (ports.empty()) {
3864 GTEST_SKIP() << "No output mix ports for attached devices";
3865 }
3866 bool atLeastOneSupports = false, atLeastOnePort = false;
3867 for (const auto& port : ports) {
3868 SCOPED_TRACE(port.toString());
3869 StreamFixture<IStreamOut> stream;
3870 ASSERT_NO_FATAL_FAILURE(stream.SetUpStreamForMixPort(module.get(), moduleConfig.get(), port,
3871 connectedOnly));
3872 if (!stream.skipTestReason().empty()) continue;
3873 atLeastOnePort = true;
3874 std::vector<AudioLatencyMode> supportedModes;
3875 ndk::ScopedAStatus status = stream.getStream()->getRecommendedLatencyModes(&supportedModes);
3876 if (status.getExceptionCode() == EX_UNSUPPORTED_OPERATION) continue;
3877 atLeastOneSupports = true;
3878 if (!status.isOk()) {
3879 ADD_FAILURE() << "When latency modes are supported, getRecommendedLatencyModes "
3880 << "must succeed on a non-closed stream, but it failed with " << status;
3881 continue;
3882 }
3883 std::set<AudioLatencyMode> unsupportedModes(enum_range<AudioLatencyMode>().begin(),
3884 enum_range<AudioLatencyMode>().end());
3885 for (const auto mode : supportedModes) {
3886 unsupportedModes.erase(mode);
3887 ndk::ScopedAStatus status = stream.getStream()->setLatencyMode(mode);
3888 if (status.getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
3889 ADD_FAILURE() << "When latency modes are supported, both getRecommendedLatencyModes"
3890 << " and setLatencyMode must be supported";
3891 }
3892 EXPECT_IS_OK(status) << "Setting of supported latency mode must succeed";
3893 }
3894 for (const auto mode : unsupportedModes) {
3895 EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, stream.getStream()->setLatencyMode(mode));
3896 }
3897 }
3898 if (!atLeastOneSupports) {
3899 GTEST_SKIP() << "Audio latency modes are not supported";
3900 }
3901 if (!atLeastOnePort) {
3902 GTEST_SKIP() << "No output mix ports could be routed to devices";
3903 }
3904 }
3905
TEST_P(AudioStreamOut,PlaybackRate)3906 TEST_P(AudioStreamOut, PlaybackRate) {
3907 static const auto kStatuses = {EX_NONE, EX_UNSUPPORTED_OPERATION};
3908 const auto offloadMixPorts =
3909 moduleConfig->getOffloadMixPorts(true /*connectedOnly*/, false /*singlePort*/);
3910 if (offloadMixPorts.empty()) {
3911 GTEST_SKIP()
3912 << "No mix port for compressed offload that could be routed to attached devices";
3913 }
3914 ndk::ScopedAStatus status;
3915 IModule::SupportedPlaybackRateFactors factors;
3916 EXPECT_STATUS(kStatuses, status = module.get()->getSupportedPlaybackRateFactors(&factors));
3917 if (status.getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
3918 GTEST_SKIP() << "Audio playback rate configuration is not supported";
3919 }
3920 EXPECT_LE(factors.minSpeed, factors.maxSpeed);
3921 EXPECT_LE(factors.minPitch, factors.maxPitch);
3922 EXPECT_LE(factors.minSpeed, 1.0f);
3923 EXPECT_GE(factors.maxSpeed, 1.0f);
3924 EXPECT_LE(factors.minPitch, 1.0f);
3925 EXPECT_GE(factors.maxPitch, 1.0f);
3926 constexpr auto tsDefault = AudioPlaybackRate::TimestretchMode::DEFAULT;
3927 constexpr auto tsVoice = AudioPlaybackRate::TimestretchMode::VOICE;
3928 constexpr auto fbFail = AudioPlaybackRate::TimestretchFallbackMode::FAIL;
3929 constexpr auto fbMute = AudioPlaybackRate::TimestretchFallbackMode::MUTE;
3930 const std::vector<AudioPlaybackRate> validValues = {
3931 AudioPlaybackRate{1.0f, 1.0f, tsDefault, fbFail},
3932 AudioPlaybackRate{1.0f, 1.0f, tsDefault, fbMute},
3933 AudioPlaybackRate{factors.maxSpeed, factors.maxPitch, tsDefault, fbMute},
3934 AudioPlaybackRate{factors.minSpeed, factors.minPitch, tsDefault, fbMute},
3935 AudioPlaybackRate{1.0f, 1.0f, tsVoice, fbMute},
3936 AudioPlaybackRate{1.0f, 1.0f, tsVoice, fbFail},
3937 AudioPlaybackRate{factors.maxSpeed, factors.maxPitch, tsVoice, fbMute},
3938 AudioPlaybackRate{factors.minSpeed, factors.minPitch, tsVoice, fbMute},
3939 // Out of range speed / pitch values must not be rejected if the fallback mode is "mute"
3940 AudioPlaybackRate{factors.maxSpeed * 2, factors.maxPitch * 2, tsDefault, fbMute},
3941 AudioPlaybackRate{factors.minSpeed / 2, factors.minPitch / 2, tsDefault, fbMute},
3942 AudioPlaybackRate{factors.maxSpeed * 2, factors.maxPitch * 2, tsVoice, fbMute},
3943 AudioPlaybackRate{factors.minSpeed / 2, factors.minPitch / 2, tsVoice, fbMute},
3944 };
3945 const std::vector<AudioPlaybackRate> invalidValues = {
3946 AudioPlaybackRate{factors.maxSpeed, factors.maxPitch * 2, tsDefault, fbFail},
3947 AudioPlaybackRate{factors.maxSpeed * 2, factors.maxPitch, tsDefault, fbFail},
3948 AudioPlaybackRate{factors.minSpeed, factors.minPitch / 2, tsDefault, fbFail},
3949 AudioPlaybackRate{factors.minSpeed / 2, factors.minPitch, tsDefault, fbFail},
3950 AudioPlaybackRate{factors.maxSpeed, factors.maxPitch * 2, tsVoice, fbFail},
3951 AudioPlaybackRate{factors.maxSpeed * 2, factors.maxPitch, tsVoice, fbFail},
3952 AudioPlaybackRate{factors.minSpeed, factors.minPitch / 2, tsVoice, fbFail},
3953 AudioPlaybackRate{factors.minSpeed / 2, factors.minPitch, tsVoice, fbFail},
3954 AudioPlaybackRate{1.0f, 1.0f, tsDefault,
3955 AudioPlaybackRate::TimestretchFallbackMode::SYS_RESERVED_CUT_REPEAT},
3956 AudioPlaybackRate{1.0f, 1.0f, tsDefault,
3957 AudioPlaybackRate::TimestretchFallbackMode::SYS_RESERVED_DEFAULT},
3958 };
3959 bool atLeastOneSupports = false;
3960 for (const auto& port : offloadMixPorts) {
3961 const auto portConfig = moduleConfig->getSingleConfigForMixPort(false, port);
3962 ASSERT_TRUE(portConfig.has_value()) << "No profiles specified for output mix port";
3963 WithStream<IStreamOut> stream(portConfig.value());
3964 ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultLargeBufferSizeFrames));
3965 bool isSupported = false;
3966 EXPECT_NO_FATAL_FAILURE(TestAccessors<AudioPlaybackRate>(
3967 stream.get(), &IStreamOut::getPlaybackRateParameters,
3968 &IStreamOut::setPlaybackRateParameters, validValues, invalidValues, &isSupported));
3969 if (isSupported) atLeastOneSupports = true;
3970 }
3971 if (!atLeastOneSupports) {
3972 GTEST_SKIP() << "Audio playback rate configuration is not supported";
3973 }
3974 }
3975
TEST_P(AudioStreamOut,SelectPresentation)3976 TEST_P(AudioStreamOut, SelectPresentation) {
3977 static const auto kStatuses = {EX_ILLEGAL_ARGUMENT, EX_UNSUPPORTED_OPERATION};
3978 const auto offloadMixPorts =
3979 moduleConfig->getOffloadMixPorts(true /*connectedOnly*/, false /*singlePort*/);
3980 if (offloadMixPorts.empty()) {
3981 GTEST_SKIP()
3982 << "No mix port for compressed offload that could be routed to attached devices";
3983 }
3984 bool atLeastOneSupports = false;
3985 for (const auto& port : offloadMixPorts) {
3986 const auto portConfig = moduleConfig->getSingleConfigForMixPort(false, port);
3987 ASSERT_TRUE(portConfig.has_value()) << "No profiles specified for output mix port";
3988 WithStream<IStreamOut> stream(portConfig.value());
3989 ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultLargeBufferSizeFrames));
3990 ndk::ScopedAStatus status;
3991 EXPECT_STATUS(kStatuses, status = stream.get()->selectPresentation(0, 0));
3992 if (status.getExceptionCode() != EX_UNSUPPORTED_OPERATION) atLeastOneSupports = true;
3993 }
3994 if (!atLeastOneSupports) {
3995 GTEST_SKIP() << "Presentation selection is not supported";
3996 }
3997 }
3998
TEST_P(AudioStreamOut,UpdateOffloadMetadata)3999 TEST_P(AudioStreamOut, UpdateOffloadMetadata) {
4000 const auto offloadMixPorts =
4001 moduleConfig->getOffloadMixPorts(true /*connectedOnly*/, false /*singlePort*/);
4002 if (offloadMixPorts.empty()) {
4003 GTEST_SKIP()
4004 << "No mix port for compressed offload that could be routed to attached devices";
4005 }
4006 for (const auto& port : offloadMixPorts) {
4007 const auto portConfig = moduleConfig->getSingleConfigForMixPort(false, port);
4008 ASSERT_TRUE(portConfig.has_value()) << "No profiles specified for output mix port";
4009 WithStream<IStreamOut> stream(portConfig.value());
4010 ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultLargeBufferSizeFrames));
4011 AudioOffloadMetadata validMetadata{
4012 .sampleRate = portConfig.value().sampleRate.value().value,
4013 .channelMask = portConfig.value().channelMask.value(),
4014 .averageBitRatePerSecond = 256000,
4015 .delayFrames = 0,
4016 .paddingFrames = 0};
4017 EXPECT_IS_OK(stream.get()->updateOffloadMetadata(validMetadata));
4018 AudioOffloadMetadata invalidMetadata{.sampleRate = -1,
4019 .averageBitRatePerSecond = -1,
4020 .delayFrames = -1,
4021 .paddingFrames = -1};
4022 EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, stream.get()->updateOffloadMetadata(invalidMetadata));
4023 }
4024 }
4025
4026 enum {
4027 NAMED_CMD_NAME,
4028 NAMED_CMD_MIN_INTERFACE_VERSION,
4029 NAMED_CMD_DELAY_MS,
4030 NAMED_CMD_STREAM_TYPE,
4031 NAMED_CMD_CMDS,
4032 NAMED_CMD_VALIDATE_POS_INCREASE
4033 };
4034 enum class StreamTypeFilter { ANY, SYNC, ASYNC };
4035 using NamedCommandSequence =
4036 std::tuple<std::string, int /*minInterfaceVersion*/, int /*cmdDelayMs*/, StreamTypeFilter,
4037 std::shared_ptr<StateSequence>, bool /*validatePositionIncrease*/>;
4038 enum { PARAM_MODULE_NAME, PARAM_CMD_SEQ, PARAM_SETUP_SEQ };
4039 using StreamIoTestParameters =
4040 std::tuple<std::string /*moduleName*/, NamedCommandSequence, bool /*useSetupSequence2*/>;
4041 template <typename Stream>
4042 class AudioStreamIo : public AudioCoreModuleBase,
4043 public testing::TestWithParam<StreamIoTestParameters> {
4044 public:
SetUp()4045 void SetUp() override {
4046 ASSERT_NO_FATAL_FAILURE(SetUpImpl(std::get<PARAM_MODULE_NAME>(GetParam())));
4047 ASSERT_GE(aidlVersion, kAidlVersion1);
4048 if (const int minVersion =
4049 std::get<NAMED_CMD_MIN_INTERFACE_VERSION>(std::get<PARAM_CMD_SEQ>(GetParam()));
4050 aidlVersion < minVersion) {
4051 GTEST_SKIP() << "Skip for audio HAL version lower than " << minVersion;
4052 }
4053 ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
4054 }
4055
Run()4056 void Run() {
4057 const auto allPortConfigs =
4058 moduleConfig->getPortConfigsForMixPorts(IOTraits<Stream>::is_input);
4059 if (allPortConfigs.empty()) {
4060 GTEST_SKIP() << "No mix ports have attached devices";
4061 }
4062 const auto& commandsAndStates =
4063 std::get<NAMED_CMD_CMDS>(std::get<PARAM_CMD_SEQ>(GetParam()));
4064 const bool validatePositionIncrease =
4065 std::get<NAMED_CMD_VALIDATE_POS_INCREASE>(std::get<PARAM_CMD_SEQ>(GetParam()));
4066 auto runStreamIoCommands = [&](const AudioPortConfig& portConfig) {
4067 if (!std::get<PARAM_SETUP_SEQ>(GetParam())) {
4068 ASSERT_NO_FATAL_FAILURE(RunStreamIoCommandsImplSeq1(portConfig, commandsAndStates,
4069 validatePositionIncrease));
4070 } else {
4071 ASSERT_NO_FATAL_FAILURE(RunStreamIoCommandsImplSeq2(portConfig, commandsAndStates,
4072 validatePositionIncrease));
4073 }
4074 };
4075
4076 for (const auto& portConfig : allPortConfigs) {
4077 auto port = moduleConfig->getPort(portConfig.portId);
4078 ASSERT_TRUE(port.has_value());
4079 SCOPED_TRACE(port->toString());
4080 SCOPED_TRACE(portConfig.toString());
4081 if (skipStreamIoTestForMixPortConfig(portConfig)) continue;
4082 const bool isNonBlocking =
4083 IOTraits<Stream>::is_input
4084 ? false
4085 :
4086 // TODO: Uncomment when support for asynchronous input is implemented.
4087 /*isBitPositionFlagSet(
4088 portConfig.flags.value().template get<AudioIoFlags::Tag::input>(),
4089 AudioInputFlags::NON_BLOCKING) :*/
4090 isBitPositionFlagSet(portConfig.flags.value()
4091 .template get<AudioIoFlags::Tag::output>(),
4092 AudioOutputFlags::NON_BLOCKING);
4093 if (auto streamType =
4094 std::get<NAMED_CMD_STREAM_TYPE>(std::get<PARAM_CMD_SEQ>(GetParam()));
4095 (isNonBlocking && streamType == StreamTypeFilter::SYNC) ||
4096 (!isNonBlocking && streamType == StreamTypeFilter::ASYNC)) {
4097 continue;
4098 }
4099 WithDebugFlags delayTransientStates = WithDebugFlags::createNested(*debug);
4100 delayTransientStates.flags().streamTransientStateDelayMs =
4101 std::get<NAMED_CMD_DELAY_MS>(std::get<PARAM_CMD_SEQ>(GetParam()));
4102 ASSERT_NO_FATAL_FAILURE(delayTransientStates.SetUp(module.get()));
4103 ASSERT_NO_FATAL_FAILURE(runStreamIoCommands(portConfig));
4104 if (aidlVersion >= kAidlVersion3 && isNonBlocking && !IOTraits<Stream>::is_input) {
4105 // Also try running the same sequence with "aosp.forceDrainToDraining" set.
4106 // This will only work with the default implementation. When it works, the stream
4107 // tries always to move to the 'DRAINING' state after an "early notify" drain.
4108 // This helps to check more paths for our test scenarios.
4109 WithModuleParameter forceDrainToDraining("aosp.forceDrainToDraining",
4110 Boolean{true});
4111 if (forceDrainToDraining.SetUpNoChecks(module.get(), true /*failureExpected*/)
4112 .isOk()) {
4113 ASSERT_NO_FATAL_FAILURE(runStreamIoCommands(portConfig));
4114 }
4115 }
4116 if (isNonBlocking) {
4117 // Also try running the same sequence with "aosp.forceTransientBurst" set.
4118 // This will only work with the default implementation. When it works, the stream
4119 // tries always to move to the 'TRANSFERRING' state after a burst.
4120 // This helps to check more paths for our test scenarios.
4121 WithModuleParameter forceTransientBurst("aosp.forceTransientBurst", Boolean{true});
4122 if (forceTransientBurst.SetUpNoChecks(module.get(), true /*failureExpected*/)
4123 .isOk()) {
4124 ASSERT_NO_FATAL_FAILURE(runStreamIoCommands(portConfig));
4125 }
4126 } else if (!IOTraits<Stream>::is_input) {
4127 // Also try running the same sequence with "aosp.forceSynchronousDrain" set.
4128 // This will only work with the default implementation. When it works, the stream
4129 // tries always to move to the 'IDLE' state after a drain.
4130 // This helps to check more paths for our test scenarios.
4131 WithModuleParameter forceSynchronousDrain("aosp.forceSynchronousDrain",
4132 Boolean{true});
4133 if (forceSynchronousDrain.SetUpNoChecks(module.get(), true /*failureExpected*/)
4134 .isOk()) {
4135 ASSERT_NO_FATAL_FAILURE(runStreamIoCommands(portConfig));
4136 }
4137 }
4138 }
4139 }
4140
ValidatePosition(const AudioDevice & device)4141 bool ValidatePosition(const AudioDevice& device) {
4142 return !isTelephonyDeviceType(device.type.type);
4143 }
4144
4145 // Set up a patch first, then open a stream.
RunStreamIoCommandsImplSeq1(const AudioPortConfig & portConfig,std::shared_ptr<StateSequence> commandsAndStates,bool validatePositionIncrease)4146 void RunStreamIoCommandsImplSeq1(const AudioPortConfig& portConfig,
4147 std::shared_ptr<StateSequence> commandsAndStates,
4148 bool validatePositionIncrease) {
4149 StreamFixture<Stream> stream;
4150 ASSERT_NO_FATAL_FAILURE(
4151 stream.SetUpStreamForMixPortConfig(module.get(), moduleConfig.get(), portConfig));
4152 if (skipStreamIoTestForDevice(stream.getDevice())) return;
4153 ASSERT_EQ("", stream.skipTestReason());
4154 StreamLogicDefaultDriver driver(commandsAndStates,
4155 stream.getStreamContext()->getFrameSizeBytes(),
4156 stream.getStreamContext()->isMmapped());
4157 typename IOTraits<Stream>::Worker worker(*stream.getStreamContext(), &driver,
4158 stream.getStreamEventReceiver());
4159
4160 LOG(DEBUG) << __func__ << ": starting worker...";
4161 ASSERT_TRUE(worker.start());
4162 LOG(DEBUG) << __func__ << ": joining worker...";
4163 worker.join();
4164 EXPECT_FALSE(worker.hasError()) << worker.getError();
4165 EXPECT_EQ("", driver.getUnexpectedStateTransition());
4166 if (ValidatePosition(stream.getDevice())) {
4167 if (validatePositionIncrease) {
4168 EXPECT_TRUE(driver.hasObservablePositionIncrease());
4169 EXPECT_TRUE(driver.hasHardwarePositionIncrease());
4170 }
4171 EXPECT_FALSE(driver.hasObservableRetrogradePosition());
4172 EXPECT_FALSE(driver.hasHardwareRetrogradePosition());
4173 }
4174 }
4175
4176 // Open a stream, then set up a patch for it. Since first it is needed to get
4177 // the minimum buffer size, a preliminary patch is set up, then removed.
RunStreamIoCommandsImplSeq2(const AudioPortConfig & portConfig,std::shared_ptr<StateSequence> commandsAndStates,bool validatePositionIncrease)4178 void RunStreamIoCommandsImplSeq2(const AudioPortConfig& portConfig,
4179 std::shared_ptr<StateSequence> commandsAndStates,
4180 bool validatePositionIncrease) {
4181 StreamFixture<Stream> stream;
4182 ASSERT_NO_FATAL_FAILURE(
4183 stream.SetUpPatchForMixPortConfig(module.get(), moduleConfig.get(), portConfig));
4184 if (skipStreamIoTestForDevice(stream.getDevice())) return;
4185 ASSERT_EQ("", stream.skipTestReason());
4186 ASSERT_NO_FATAL_FAILURE(stream.TeardownPatchSetUpStream(module.get()));
4187 StreamLogicDefaultDriver driver(commandsAndStates,
4188 stream.getStreamContext()->getFrameSizeBytes(),
4189 stream.getStreamContext()->isMmapped());
4190 typename IOTraits<Stream>::Worker worker(*stream.getStreamContext(), &driver,
4191 stream.getStreamEventReceiver());
4192 ASSERT_NO_FATAL_FAILURE(stream.ReconnectPatch(module.get()));
4193
4194 LOG(DEBUG) << __func__ << ": starting worker...";
4195 ASSERT_TRUE(worker.start());
4196 LOG(DEBUG) << __func__ << ": joining worker...";
4197 worker.join();
4198 EXPECT_FALSE(worker.hasError()) << worker.getError();
4199 EXPECT_EQ("", driver.getUnexpectedStateTransition());
4200 if (ValidatePosition(stream.getDevice())) {
4201 if (validatePositionIncrease) {
4202 EXPECT_TRUE(driver.hasObservablePositionIncrease());
4203 EXPECT_TRUE(driver.hasHardwarePositionIncrease());
4204 }
4205 EXPECT_FALSE(driver.hasObservableRetrogradePosition());
4206 EXPECT_FALSE(driver.hasHardwareRetrogradePosition());
4207 }
4208 }
4209 };
4210 using AudioStreamIoIn = AudioStreamIo<IStreamIn>;
4211 using AudioStreamIoOut = AudioStreamIo<IStreamOut>;
4212
4213 #define TEST_IN_AND_OUT_STREAM_IO(method_name) \
4214 TEST_P(AudioStreamIoIn, method_name) { \
4215 ASSERT_NO_FATAL_FAILURE(method_name()); \
4216 } \
4217 TEST_P(AudioStreamIoOut, method_name) { \
4218 ASSERT_NO_FATAL_FAILURE(method_name()); \
4219 }
4220
4221 TEST_IN_AND_OUT_STREAM_IO(Run);
4222
4223 // Tests specific to audio patches. The fixure class is named 'AudioModulePatch'
4224 // to avoid clashing with 'AudioPatch' class.
4225 class AudioModulePatch : public AudioCoreModule {
4226 public:
direction(bool isInput,bool capitalize)4227 static std::string direction(bool isInput, bool capitalize) {
4228 return isInput ? (capitalize ? "Input" : "input") : (capitalize ? "Output" : "output");
4229 }
4230
SetUp()4231 void SetUp() override {
4232 ASSERT_NO_FATAL_FAILURE(AudioCoreModule::SetUp());
4233 ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
4234 }
4235
SetInvalidPatchHelper(int32_t expectedException,const std::vector<int32_t> & sources,const std::vector<int32_t> & sinks)4236 void SetInvalidPatchHelper(int32_t expectedException, const std::vector<int32_t>& sources,
4237 const std::vector<int32_t>& sinks) {
4238 AudioPatch patch;
4239 patch.sourcePortConfigIds = sources;
4240 patch.sinkPortConfigIds = sinks;
4241 ASSERT_STATUS(expectedException, module->setAudioPatch(patch, &patch))
4242 << "patch source ids: " << android::internal::ToString(sources)
4243 << "; sink ids: " << android::internal::ToString(sinks);
4244 }
4245
ResetPortConfigUsedByPatch(bool isInput)4246 void ResetPortConfigUsedByPatch(bool isInput) {
4247 auto srcSinkGroups = moduleConfig->getRoutableSrcSinkGroups(isInput);
4248 if (srcSinkGroups.empty()) {
4249 GTEST_SKIP() << "No routes to any attached " << direction(isInput, false) << " devices";
4250 }
4251 auto srcSinkGroup = *srcSinkGroups.begin();
4252 auto srcSink = *srcSinkGroup.second.begin();
4253 WithAudioPatch patch(srcSink.first, srcSink.second);
4254 ASSERT_NO_FATAL_FAILURE(patch.SetUp(module.get()));
4255 std::vector<int32_t> sourceAndSinkPortConfigIds(patch.get().sourcePortConfigIds);
4256 sourceAndSinkPortConfigIds.insert(sourceAndSinkPortConfigIds.end(),
4257 patch.get().sinkPortConfigIds.begin(),
4258 patch.get().sinkPortConfigIds.end());
4259 for (const auto portConfigId : sourceAndSinkPortConfigIds) {
4260 EXPECT_STATUS(EX_ILLEGAL_STATE, module->resetAudioPortConfig(portConfigId))
4261 << "port config ID " << portConfigId;
4262 }
4263 }
4264
SetInvalidPatch(bool isInput)4265 void SetInvalidPatch(bool isInput) {
4266 auto srcSinkPair = moduleConfig->getRoutableSrcSinkPair(isInput);
4267 if (!srcSinkPair.has_value()) {
4268 GTEST_SKIP() << "No routes to any attached " << direction(isInput, false) << " devices";
4269 }
4270 WithAudioPortConfig srcPortConfig(srcSinkPair.value().first);
4271 ASSERT_NO_FATAL_FAILURE(srcPortConfig.SetUp(module.get()));
4272 WithAudioPortConfig sinkPortConfig(srcSinkPair.value().second);
4273 ASSERT_NO_FATAL_FAILURE(sinkPortConfig.SetUp(module.get()));
4274 { // Check that the pair can actually be used for setting up a patch.
4275 WithAudioPatch patch(srcPortConfig.get(), sinkPortConfig.get());
4276 ASSERT_NO_FATAL_FAILURE(patch.SetUp(module.get()));
4277 }
4278 EXPECT_NO_FATAL_FAILURE(
4279 SetInvalidPatchHelper(EX_ILLEGAL_ARGUMENT, {}, {sinkPortConfig.getId()}));
4280 EXPECT_NO_FATAL_FAILURE(SetInvalidPatchHelper(
4281 EX_ILLEGAL_ARGUMENT, {srcPortConfig.getId(), srcPortConfig.getId()},
4282 {sinkPortConfig.getId()}));
4283 EXPECT_NO_FATAL_FAILURE(
4284 SetInvalidPatchHelper(EX_ILLEGAL_ARGUMENT, {srcPortConfig.getId()}, {}));
4285 EXPECT_NO_FATAL_FAILURE(
4286 SetInvalidPatchHelper(EX_ILLEGAL_ARGUMENT, {srcPortConfig.getId()},
4287 {sinkPortConfig.getId(), sinkPortConfig.getId()}));
4288
4289 std::set<int32_t> portConfigIds;
4290 ASSERT_NO_FATAL_FAILURE(GetAllPortConfigIds(&portConfigIds));
4291 for (const auto portConfigId : GetNonExistentIds(portConfigIds)) {
4292 EXPECT_NO_FATAL_FAILURE(SetInvalidPatchHelper(EX_ILLEGAL_ARGUMENT, {portConfigId},
4293 {sinkPortConfig.getId()}));
4294 EXPECT_NO_FATAL_FAILURE(SetInvalidPatchHelper(EX_ILLEGAL_ARGUMENT,
4295 {srcPortConfig.getId()}, {portConfigId}));
4296 }
4297 }
4298
SetNonRoutablePatch(bool isInput)4299 void SetNonRoutablePatch(bool isInput) {
4300 auto srcSinkPair = moduleConfig->getNonRoutableSrcSinkPair(isInput);
4301 if (!srcSinkPair.has_value()) {
4302 GTEST_SKIP() << "All possible source/sink pairs are routable";
4303 }
4304 WithAudioPatch patch(srcSinkPair.value().first, srcSinkPair.value().second);
4305 ASSERT_NO_FATAL_FAILURE(patch.SetUpPortConfigs(module.get()));
4306 EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, patch.SetUpNoChecks(module.get()))
4307 << "when setting up a patch from " << srcSinkPair.value().first.toString() << " to "
4308 << srcSinkPair.value().second.toString() << " that does not have a route";
4309 }
4310
SetPatch(bool isInput)4311 void SetPatch(bool isInput) {
4312 auto srcSinkGroups = moduleConfig->getRoutableSrcSinkGroups(isInput);
4313 if (srcSinkGroups.empty()) {
4314 GTEST_SKIP() << "No routes to any attached " << direction(isInput, false) << " devices";
4315 }
4316 for (const auto& srcSinkGroup : srcSinkGroups) {
4317 const auto& route = srcSinkGroup.first;
4318 std::vector<std::unique_ptr<WithAudioPatch>> patches;
4319 for (const auto& srcSink : srcSinkGroup.second) {
4320 if (!route.isExclusive) {
4321 patches.push_back(
4322 std::make_unique<WithAudioPatch>(srcSink.first, srcSink.second));
4323 EXPECT_NO_FATAL_FAILURE(patches[patches.size() - 1]->SetUp(module.get()));
4324 EXPECT_NO_FATAL_FAILURE(
4325 patches[patches.size() - 1]->VerifyAgainstAllPatches(module.get()));
4326 } else {
4327 WithAudioPatch patch(srcSink.first, srcSink.second);
4328 EXPECT_NO_FATAL_FAILURE(patch.SetUp(module.get()));
4329 EXPECT_NO_FATAL_FAILURE(patch.VerifyAgainstAllPatches(module.get()));
4330 }
4331 }
4332 }
4333 }
4334
UpdatePatch(bool isInput)4335 void UpdatePatch(bool isInput) {
4336 auto srcSinkGroups = moduleConfig->getRoutableSrcSinkGroups(isInput);
4337 if (srcSinkGroups.empty()) {
4338 GTEST_SKIP() << "No routes to any attached " << direction(isInput, false) << " devices";
4339 }
4340 for (const auto& srcSinkGroup : srcSinkGroups) {
4341 for (const auto& srcSink : srcSinkGroup.second) {
4342 WithAudioPatch patch(srcSink.first, srcSink.second);
4343 ASSERT_NO_FATAL_FAILURE(patch.SetUp(module.get()));
4344 AudioPatch ignored;
4345 EXPECT_NO_FATAL_FAILURE(module->setAudioPatch(patch.get(), &ignored));
4346 }
4347 }
4348 }
4349
UpdatePatchPorts(bool isInput)4350 void UpdatePatchPorts(bool isInput) {
4351 auto srcSinkGroups = moduleConfig->getRoutableSrcSinkGroups(isInput);
4352 if (srcSinkGroups.empty()) {
4353 GTEST_SKIP() << "No routes to any attached " << direction(isInput, false) << " devices";
4354 }
4355 bool hasAtLeastOnePair = false;
4356 for (const auto& srcSinkGroup : srcSinkGroups) {
4357 const auto& srcSinks = srcSinkGroup.second;
4358 if (srcSinks.size() < 2) continue;
4359 hasAtLeastOnePair = true;
4360 const auto& pair1 = srcSinks[0];
4361 const auto& pair2 = srcSinks[1];
4362 WithAudioPatch patch(pair1.first, pair1.second);
4363 ASSERT_NO_FATAL_FAILURE(patch.SetUp(module.get()));
4364 WithAudioPatch update(patch, pair2.first, pair2.second);
4365 EXPECT_NO_FATAL_FAILURE(update.SetUp(module.get()));
4366 EXPECT_NO_FATAL_FAILURE(update.VerifyAgainstAllPatches(module.get()));
4367 }
4368 if (!hasAtLeastOnePair) {
4369 GTEST_SKIP() << "No routes with multiple sources";
4370 }
4371 }
4372
UpdateInvalidPatchId(bool isInput)4373 void UpdateInvalidPatchId(bool isInput) {
4374 auto srcSinkGroups = moduleConfig->getRoutableSrcSinkGroups(isInput);
4375 if (srcSinkGroups.empty()) {
4376 GTEST_SKIP() << "No routes to any attached " << direction(isInput, false) << " devices";
4377 }
4378 // First, set up a patch to ensure that its settings are accepted.
4379 auto srcSinkGroup = *srcSinkGroups.begin();
4380 auto srcSink = *srcSinkGroup.second.begin();
4381 WithAudioPatch patch(srcSink.first, srcSink.second);
4382 ASSERT_NO_FATAL_FAILURE(patch.SetUp(module.get()));
4383 // Then use the same patch setting, except for having an invalid ID.
4384 std::set<int32_t> patchIds;
4385 ASSERT_NO_FATAL_FAILURE(GetAllPatchIds(&patchIds));
4386 for (const auto patchId : GetNonExistentIds(patchIds, false /*includeZero*/)) {
4387 AudioPatch patchWithNonExistendId = patch.get();
4388 patchWithNonExistendId.id = patchId;
4389 EXPECT_STATUS(EX_ILLEGAL_ARGUMENT,
4390 module->setAudioPatch(patchWithNonExistendId, &patchWithNonExistendId))
4391 << "patch ID " << patchId;
4392 }
4393 }
4394 };
4395
4396 // Not all tests require both directions, so parametrization would require
4397 // more abstractions.
4398 #define TEST_PATCH_BOTH_DIRECTIONS(method_name) \
4399 TEST_P(AudioModulePatch, method_name##Input) { \
4400 ASSERT_NO_FATAL_FAILURE(method_name(true)); \
4401 } \
4402 TEST_P(AudioModulePatch, method_name##Output) { \
4403 ASSERT_NO_FATAL_FAILURE(method_name(false)); \
4404 }
4405
4406 TEST_PATCH_BOTH_DIRECTIONS(ResetPortConfigUsedByPatch);
4407 TEST_PATCH_BOTH_DIRECTIONS(SetInvalidPatch);
4408 TEST_PATCH_BOTH_DIRECTIONS(SetNonRoutablePatch);
4409 TEST_PATCH_BOTH_DIRECTIONS(SetPatch);
4410 TEST_PATCH_BOTH_DIRECTIONS(UpdateInvalidPatchId);
4411 TEST_PATCH_BOTH_DIRECTIONS(UpdatePatch);
4412 TEST_PATCH_BOTH_DIRECTIONS(UpdatePatchPorts);
4413
TEST_P(AudioModulePatch,ResetInvalidPatchId)4414 TEST_P(AudioModulePatch, ResetInvalidPatchId) {
4415 std::set<int32_t> patchIds;
4416 ASSERT_NO_FATAL_FAILURE(GetAllPatchIds(&patchIds));
4417 for (const auto patchId : GetNonExistentIds(patchIds)) {
4418 EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->resetAudioPatch(patchId))
4419 << "patch ID " << patchId;
4420 }
4421 }
4422
4423 class AudioCoreSoundDose : public AudioCoreModuleBase, public testing::TestWithParam<std::string> {
4424 public:
4425 class NoOpHalSoundDoseCallback : public ISoundDose::BnHalSoundDoseCallback {
4426 public:
4427 ndk::ScopedAStatus onMomentaryExposureWarning(float in_currentDbA,
4428 const AudioDevice& in_audioDevice) override;
4429 ndk::ScopedAStatus onNewMelValues(
4430 const ISoundDose::IHalSoundDoseCallback::MelRecord& in_melRecord,
4431 const AudioDevice& in_audioDevice) override;
4432 };
4433
SetUp()4434 void SetUp() override {
4435 ASSERT_NO_FATAL_FAILURE(SetUpImpl(GetParam()));
4436 ASSERT_IS_OK(module->getSoundDose(&soundDose));
4437 callback = ndk::SharedRefBase::make<NoOpHalSoundDoseCallback>();
4438 }
4439
TearDown()4440 void TearDown() override { ASSERT_NO_FATAL_FAILURE(TearDownImpl()); }
4441
4442 std::shared_ptr<ISoundDose> soundDose;
4443 std::shared_ptr<ISoundDose::IHalSoundDoseCallback> callback;
4444 };
4445
onMomentaryExposureWarning(float in_currentDbA,const AudioDevice & in_audioDevice)4446 ndk::ScopedAStatus AudioCoreSoundDose::NoOpHalSoundDoseCallback::onMomentaryExposureWarning(
4447 float in_currentDbA, const AudioDevice& in_audioDevice) {
4448 // Do nothing
4449 (void)in_currentDbA;
4450 (void)in_audioDevice;
4451 LOG(INFO) << "NoOpHalSoundDoseCallback::onMomentaryExposureWarning called";
4452
4453 return ndk::ScopedAStatus::ok();
4454 }
4455
onNewMelValues(const ISoundDose::IHalSoundDoseCallback::MelRecord & in_melRecord,const AudioDevice & in_audioDevice)4456 ndk::ScopedAStatus AudioCoreSoundDose::NoOpHalSoundDoseCallback::onNewMelValues(
4457 const ISoundDose::IHalSoundDoseCallback::MelRecord& in_melRecord,
4458 const AudioDevice& in_audioDevice) {
4459 // Do nothing
4460 (void)in_melRecord;
4461 (void)in_audioDevice;
4462 LOG(INFO) << "NoOpHalSoundDoseCallback::onNewMelValues called";
4463
4464 return ndk::ScopedAStatus::ok();
4465 }
4466
4467 // @VsrTest = VSR-5.5-002.001
TEST_P(AudioCoreSoundDose,SameInstance)4468 TEST_P(AudioCoreSoundDose, SameInstance) {
4469 if (soundDose == nullptr) {
4470 GTEST_SKIP() << "SoundDose is not supported";
4471 }
4472 std::shared_ptr<ISoundDose> soundDose2;
4473 EXPECT_IS_OK(module->getSoundDose(&soundDose2));
4474 ASSERT_NE(nullptr, soundDose2.get());
4475 EXPECT_EQ(soundDose->asBinder(), soundDose2->asBinder())
4476 << "getSoundDose must return the same interface instance across invocations";
4477 }
4478
4479 // @VsrTest = VSR-5.5-002.001
TEST_P(AudioCoreSoundDose,GetSetOutputRs2UpperBound)4480 TEST_P(AudioCoreSoundDose, GetSetOutputRs2UpperBound) {
4481 if (soundDose == nullptr) {
4482 GTEST_SKIP() << "SoundDose is not supported";
4483 }
4484
4485 bool isSupported = false;
4486 EXPECT_NO_FATAL_FAILURE(TestAccessors<float>(soundDose.get(),
4487 &ISoundDose::getOutputRs2UpperBound,
4488 &ISoundDose::setOutputRs2UpperBound,
4489 /*validValues=*/{80.f, 90.f, 100.f},
4490 /*invalidValues=*/{79.f, 101.f}, &isSupported));
4491 EXPECT_TRUE(isSupported) << "Getting/Setting RS2 upper bound must be supported";
4492 }
4493
4494 // @VsrTest = VSR-5.5-002.001
TEST_P(AudioCoreSoundDose,CheckDefaultRs2UpperBound)4495 TEST_P(AudioCoreSoundDose, CheckDefaultRs2UpperBound) {
4496 if (soundDose == nullptr) {
4497 GTEST_SKIP() << "SoundDose is not supported";
4498 }
4499
4500 float rs2Value;
4501 ASSERT_IS_OK(soundDose->getOutputRs2UpperBound(&rs2Value));
4502 EXPECT_EQ(rs2Value, ISoundDose::DEFAULT_MAX_RS2);
4503 }
4504
4505 // @VsrTest = VSR-5.5-002.001
TEST_P(AudioCoreSoundDose,RegisterSoundDoseCallbackTwiceThrowsException)4506 TEST_P(AudioCoreSoundDose, RegisterSoundDoseCallbackTwiceThrowsException) {
4507 if (soundDose == nullptr) {
4508 GTEST_SKIP() << "SoundDose is not supported";
4509 }
4510
4511 ASSERT_IS_OK(soundDose->registerSoundDoseCallback(callback));
4512 EXPECT_STATUS(EX_ILLEGAL_STATE, soundDose->registerSoundDoseCallback(callback))
4513 << "Registering sound dose callback twice should throw EX_ILLEGAL_STATE";
4514 }
4515
4516 // @VsrTest = VSR-5.5-002.001
TEST_P(AudioCoreSoundDose,RegisterSoundDoseNullCallbackThrowsException)4517 TEST_P(AudioCoreSoundDose, RegisterSoundDoseNullCallbackThrowsException) {
4518 if (soundDose == nullptr) {
4519 GTEST_SKIP() << "SoundDose is not supported";
4520 }
4521
4522 EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, soundDose->registerSoundDoseCallback(nullptr))
4523 << "Registering nullptr sound dose callback should throw EX_ILLEGAL_ARGUMENT";
4524 }
4525
4526 INSTANTIATE_TEST_SUITE_P(AudioCoreModuleTest, AudioCoreModule,
4527 testing::ValuesIn(android::getAidlHalInstanceNames(IModule::descriptor)),
4528 android::PrintInstanceNameToString);
4529 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioCoreModule);
4530 INSTANTIATE_TEST_SUITE_P(AudioCoreBluetoothTest, AudioCoreBluetooth,
4531 testing::ValuesIn(android::getAidlHalInstanceNames(IModule::descriptor)),
4532 android::PrintInstanceNameToString);
4533 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioCoreBluetooth);
4534 INSTANTIATE_TEST_SUITE_P(AudioCoreBluetoothA2dpTest, AudioCoreBluetoothA2dp,
4535 testing::ValuesIn(android::getAidlHalInstanceNames(IModule::descriptor)),
4536 android::PrintInstanceNameToString);
4537 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioCoreBluetoothA2dp);
4538 INSTANTIATE_TEST_SUITE_P(AudioCoreBluetoothLeTest, AudioCoreBluetoothLe,
4539 testing::ValuesIn(android::getAidlHalInstanceNames(IModule::descriptor)),
4540 android::PrintInstanceNameToString);
4541 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioCoreBluetoothLe);
4542 INSTANTIATE_TEST_SUITE_P(AudioCoreTelephonyTest, AudioCoreTelephony,
4543 testing::ValuesIn(android::getAidlHalInstanceNames(IModule::descriptor)),
4544 android::PrintInstanceNameToString);
4545 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioCoreTelephony);
4546 INSTANTIATE_TEST_SUITE_P(AudioStreamInTest, AudioStreamIn,
4547 testing::ValuesIn(android::getAidlHalInstanceNames(IModule::descriptor)),
4548 android::PrintInstanceNameToString);
4549 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioStreamIn);
4550 INSTANTIATE_TEST_SUITE_P(AudioStreamOutTest, AudioStreamOut,
4551 testing::ValuesIn(android::getAidlHalInstanceNames(IModule::descriptor)),
4552 android::PrintInstanceNameToString);
4553 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioStreamOut);
4554 INSTANTIATE_TEST_SUITE_P(AudioCoreSoundDoseTest, AudioCoreSoundDose,
4555 testing::ValuesIn(android::getAidlHalInstanceNames(IModule::descriptor)),
4556 android::PrintInstanceNameToString);
4557 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioCoreSoundDose);
4558
4559 // This is the value used in test sequences for which the test needs to ensure
4560 // that the HAL stays in a transient state long enough to receive the next command.
4561 static const int kStreamTransientStateTransitionDelayMs = 3000;
4562
4563 // TODO: Add async test cases for input once it is implemented.
4564
makeBurstCommands(bool isSync)4565 std::shared_ptr<StateSequence> makeBurstCommands(bool isSync) {
4566 using State = StreamDescriptor::State;
4567 auto d = std::make_unique<StateDag>();
4568 StateDag::Node last = d->makeFinalNode(State::ACTIVE);
4569 if (isSync) {
4570 StateDag::Node idle = d->makeNode(
4571 State::IDLE, kBurstCommand,
4572 // Use several bursts to ensure that the driver starts reporting the position.
4573 d->makeNodes(State::ACTIVE, kBurstCommand, 10, last));
4574 d->makeNode(State::STANDBY, kStartCommand, idle);
4575 } else {
4576 StateDag::Node active2 = d->makeNode(State::ACTIVE, kBurstCommand, last);
4577 StateDag::Node active = d->makeNode(State::ACTIVE, kBurstCommand, active2);
4578 StateDag::Node idle = d->makeNode(State::IDLE, kBurstCommand, active);
4579 // Allow optional routing via the TRANSFERRING state on bursts.
4580 active2.children().push_back(d->makeNode(State::TRANSFERRING, kTransferReadyEvent, last));
4581 active.children().push_back(d->makeNode(State::TRANSFERRING, kTransferReadyEvent, active2));
4582 idle.children().push_back(d->makeNode(State::TRANSFERRING, kTransferReadyEvent, active));
4583 d->makeNode(State::STANDBY, kStartCommand, idle);
4584 }
4585 return std::make_shared<StateSequenceFollower>(std::move(d));
4586 }
4587 static const NamedCommandSequence kReadSeq =
4588 std::make_tuple(std::string("Read"), kAidlVersion1, 0, StreamTypeFilter::ANY,
4589 makeBurstCommands(true), true /*validatePositionIncrease*/);
4590 static const NamedCommandSequence kWriteSyncSeq =
4591 std::make_tuple(std::string("Write"), kAidlVersion1, 0, StreamTypeFilter::SYNC,
4592 makeBurstCommands(true), true /*validatePositionIncrease*/);
4593 static const NamedCommandSequence kWriteAsyncSeq =
4594 std::make_tuple(std::string("Write"), kAidlVersion1, 0, StreamTypeFilter::ASYNC,
4595 makeBurstCommands(false), true /*validatePositionIncrease*/);
4596
makeAsyncDrainCommands(bool isInput)4597 std::shared_ptr<StateSequence> makeAsyncDrainCommands(bool isInput) {
4598 using State = StreamDescriptor::State;
4599 auto d = std::make_unique<StateDag>();
4600 if (isInput) {
4601 d->makeNodes({std::make_pair(State::STANDBY, kStartCommand),
4602 std::make_pair(State::IDLE, kBurstCommand),
4603 std::make_pair(State::ACTIVE, kDrainInCommand),
4604 std::make_pair(State::DRAINING, kStartCommand),
4605 std::make_pair(State::ACTIVE, kDrainInCommand)},
4606 State::DRAINING);
4607 } else {
4608 StateDag::Node draining =
4609 d->makeNodes({std::make_pair(State::DRAINING, kBurstCommand),
4610 std::make_pair(State::TRANSFERRING, kDrainOutAllCommand)},
4611 State::DRAINING);
4612 StateDag::Node idle =
4613 d->makeNodes({std::make_pair(State::IDLE, kBurstCommand),
4614 std::make_pair(State::TRANSFERRING, kDrainOutAllCommand)},
4615 draining);
4616 // If we get straight into ACTIVE on burst, no further testing is possible.
4617 draining.children().push_back(d->makeFinalNode(State::ACTIVE));
4618 idle.children().push_back(d->makeFinalNode(State::ACTIVE));
4619 d->makeNode(State::STANDBY, kStartCommand, idle);
4620 }
4621 return std::make_shared<StateSequenceFollower>(std::move(d));
4622 }
4623 static const NamedCommandSequence kWriteDrainAsyncSeq = std::make_tuple(
4624 std::string("WriteDrain"), kAidlVersion1, kStreamTransientStateTransitionDelayMs,
4625 StreamTypeFilter::ASYNC, makeAsyncDrainCommands(false), false /*validatePositionIncrease*/);
4626 static const NamedCommandSequence kDrainInSeq =
4627 std::make_tuple(std::string("Drain"), kAidlVersion1, 0, StreamTypeFilter::ANY,
4628 makeAsyncDrainCommands(true), false /*validatePositionIncrease*/);
4629
makeDrainOutCommands(bool isSync)4630 std::shared_ptr<StateSequence> makeDrainOutCommands(bool isSync) {
4631 using State = StreamDescriptor::State;
4632 auto d = std::make_unique<StateDag>();
4633 StateDag::Node last = d->makeFinalNode(State::IDLE);
4634 StateDag::Node active = d->makeNodes(
4635 {std::make_pair(State::ACTIVE, kDrainOutAllCommand),
4636 std::make_pair(State::DRAINING, isSync ? TransitionTrigger(kGetStatusCommand)
4637 : TransitionTrigger(kDrainReadyEvent))},
4638 last);
4639 StateDag::Node idle = d->makeNode(State::IDLE, kBurstCommand, active);
4640 if (!isSync) {
4641 idle.children().push_back(d->makeNode(State::TRANSFERRING, kTransferReadyEvent, active));
4642 } else {
4643 active.children().push_back(last);
4644 }
4645 d->makeNode(State::STANDBY, kStartCommand, idle);
4646 return std::make_shared<StateSequenceFollower>(std::move(d));
4647 }
4648 static const NamedCommandSequence kDrainOutSyncSeq =
4649 std::make_tuple(std::string("Drain"), kAidlVersion1, 0, StreamTypeFilter::SYNC,
4650 makeDrainOutCommands(true), false /*validatePositionIncrease*/);
4651 static const NamedCommandSequence kDrainOutAsyncSeq =
4652 std::make_tuple(std::string("Drain"), kAidlVersion3, 0, StreamTypeFilter::ASYNC,
4653 makeDrainOutCommands(false), false /*validatePositionIncrease*/);
4654
makeDrainEarlyOutCommands()4655 std::shared_ptr<StateSequence> makeDrainEarlyOutCommands() {
4656 using State = StreamDescriptor::State;
4657 auto d = std::make_unique<StateDag>();
4658 StateDag::Node last = d->makeFinalNode(State::IDLE);
4659 StateDag::Node draining = d->makeNode(State::DRAINING, kDrainReadyEvent, last);
4660 draining.children().push_back(d->makeNode(State::DRAINING, kGetStatusCommand, last));
4661 StateDag::Node active = d->makeNode(State::ACTIVE, kDrainOutEarlyCommand, draining);
4662 StateDag::Node idle = d->makeNode(State::IDLE, kBurstCommand, active);
4663 idle.children().push_back(d->makeNode(State::TRANSFERRING, kTransferReadyEvent, active));
4664 d->makeNode(State::STANDBY, kStartCommand, idle);
4665 return std::make_shared<StateSequenceFollower>(std::move(d));
4666 }
4667 static const NamedCommandSequence kDrainEarlyOutAsyncSeq =
4668 std::make_tuple(std::string("DrainEarly"), kAidlVersion3, 0, StreamTypeFilter::ASYNC,
4669 makeDrainEarlyOutCommands(), false /*validatePositionIncrease*/);
4670
makeDrainPauseOutCommands(bool isSync)4671 std::shared_ptr<StateSequence> makeDrainPauseOutCommands(bool isSync) {
4672 using State = StreamDescriptor::State;
4673 auto d = std::make_unique<StateDag>();
4674 StateDag::Node draining = d->makeNodes({std::make_pair(State::DRAINING, kPauseCommand),
4675 std::make_pair(State::DRAIN_PAUSED, kStartCommand),
4676 std::make_pair(State::DRAINING, kPauseCommand),
4677 std::make_pair(State::DRAIN_PAUSED, kBurstCommand)},
4678 isSync ? State::PAUSED : State::TRANSFER_PAUSED);
4679 StateDag::Node active = d->makeNode(State::ACTIVE, kDrainOutAllCommand, draining);
4680 StateDag::Node idle = d->makeNode(State::IDLE, kBurstCommand, active);
4681 if (!isSync) {
4682 idle.children().push_back(d->makeNode(State::TRANSFERRING, kDrainOutAllCommand, draining));
4683 } else {
4684 // If we get straight into IDLE on drain, no further testing is possible.
4685 active.children().push_back(d->makeFinalNode(State::IDLE));
4686 }
4687 d->makeNode(State::STANDBY, kStartCommand, idle);
4688 return std::make_shared<StateSequenceFollower>(std::move(d));
4689 }
4690 static const NamedCommandSequence kDrainPauseOutSyncSeq =
4691 std::make_tuple(std::string("DrainPause"), kAidlVersion1,
4692 kStreamTransientStateTransitionDelayMs, StreamTypeFilter::SYNC,
4693 makeDrainPauseOutCommands(true), false /*validatePositionIncrease*/);
4694 static const NamedCommandSequence kDrainPauseOutAsyncSeq =
4695 std::make_tuple(std::string("DrainPause"), kAidlVersion1,
4696 kStreamTransientStateTransitionDelayMs, StreamTypeFilter::ASYNC,
4697 makeDrainPauseOutCommands(false), false /*validatePositionIncrease*/);
4698
makeDrainEarlyPauseOutCommands()4699 std::shared_ptr<StateSequence> makeDrainEarlyPauseOutCommands() {
4700 using State = StreamDescriptor::State;
4701 auto d = std::make_unique<StateDag>();
4702 StateDag::Node draining = d->makeNodes({std::make_pair(State::DRAINING, kPauseCommand),
4703 std::make_pair(State::DRAIN_PAUSED, kStartCommand),
4704 std::make_pair(State::DRAINING, kPauseCommand),
4705 std::make_pair(State::DRAIN_PAUSED, kBurstCommand)},
4706 State::TRANSFER_PAUSED);
4707 StateDag::Node active = d->makeNode(State::ACTIVE, kDrainOutEarlyCommand, draining);
4708 StateDag::Node idle = d->makeNode(State::IDLE, kBurstCommand, active);
4709 idle.children().push_back(d->makeNode(State::TRANSFERRING, kDrainOutEarlyCommand, draining));
4710 d->makeNode(State::STANDBY, kStartCommand, idle);
4711 return std::make_shared<StateSequenceFollower>(std::move(d));
4712 }
4713 static const NamedCommandSequence kDrainEarlyPauseOutAsyncSeq =
4714 std::make_tuple(std::string("DrainEarlyPause"), kAidlVersion3,
4715 kStreamTransientStateTransitionDelayMs, StreamTypeFilter::ASYNC,
4716 makeDrainEarlyPauseOutCommands(), false /*validatePositionIncrease*/);
4717
4718 // This sequence also verifies that the capture / presentation position is not reset on standby.
makeStandbyCommands(bool isInput,bool isSync)4719 std::shared_ptr<StateSequence> makeStandbyCommands(bool isInput, bool isSync) {
4720 using State = StreamDescriptor::State;
4721 auto d = std::make_unique<StateDag>();
4722 if (isInput) {
4723 d->makeNodes({std::make_pair(State::STANDBY, kStartCommand),
4724 std::make_pair(State::IDLE, kStandbyCommand),
4725 std::make_pair(State::STANDBY, kStartCommand),
4726 std::make_pair(State::IDLE, kBurstCommand),
4727 std::make_pair(State::ACTIVE, kPauseCommand),
4728 std::make_pair(State::PAUSED, kFlushCommand),
4729 std::make_pair(State::STANDBY, kStartCommand),
4730 std::make_pair(State::IDLE, kBurstCommand)},
4731 State::ACTIVE);
4732 } else {
4733 StateDag::Node idle3 =
4734 d->makeNode(State::IDLE, kBurstCommand, d->makeFinalNode(State::ACTIVE));
4735 StateDag::Node idle2 = d->makeNodes({std::make_pair(State::IDLE, kStandbyCommand),
4736 std::make_pair(State::STANDBY, kStartCommand)},
4737 idle3);
4738 StateDag::Node active = d->makeNodes({std::make_pair(State::ACTIVE, kPauseCommand),
4739 std::make_pair(State::PAUSED, kFlushCommand)},
4740 idle2);
4741 StateDag::Node idle = d->makeNode(State::IDLE, kBurstCommand, active);
4742 if (!isSync) {
4743 idle3.children().push_back(d->makeFinalNode(State::TRANSFERRING));
4744 StateDag::Node transferring =
4745 d->makeNodes({std::make_pair(State::TRANSFERRING, kPauseCommand),
4746 std::make_pair(State::TRANSFER_PAUSED, kFlushCommand)},
4747 idle2);
4748 idle.children().push_back(transferring);
4749 }
4750 d->makeNodes({std::make_pair(State::STANDBY, kStartCommand),
4751 std::make_pair(State::IDLE, kStandbyCommand),
4752 std::make_pair(State::STANDBY, kStartCommand)},
4753 idle);
4754 }
4755 return std::make_shared<StateSequenceFollower>(std::move(d));
4756 }
4757 static const NamedCommandSequence kStandbyInSeq =
4758 std::make_tuple(std::string("Standby"), kAidlVersion1, 0, StreamTypeFilter::ANY,
4759 makeStandbyCommands(true, false), false /*validatePositionIncrease*/);
4760 static const NamedCommandSequence kStandbyOutSyncSeq =
4761 std::make_tuple(std::string("Standby"), kAidlVersion1, 0, StreamTypeFilter::SYNC,
4762 makeStandbyCommands(false, true), false /*validatePositionIncrease*/);
4763 static const NamedCommandSequence kStandbyOutAsyncSeq =
4764 std::make_tuple(std::string("Standby"), kAidlVersion1,
4765 kStreamTransientStateTransitionDelayMs, StreamTypeFilter::ASYNC,
4766 makeStandbyCommands(false, false), false /*validatePositionIncrease*/);
4767
makePauseCommands(bool isInput,bool isSync)4768 std::shared_ptr<StateSequence> makePauseCommands(bool isInput, bool isSync) {
4769 using State = StreamDescriptor::State;
4770 auto d = std::make_unique<StateDag>();
4771 if (isInput) {
4772 d->makeNodes({std::make_pair(State::STANDBY, kStartCommand),
4773 std::make_pair(State::IDLE, kBurstCommand),
4774 std::make_pair(State::ACTIVE, kPauseCommand),
4775 std::make_pair(State::PAUSED, kBurstCommand),
4776 std::make_pair(State::ACTIVE, kPauseCommand),
4777 std::make_pair(State::PAUSED, kFlushCommand)},
4778 State::STANDBY);
4779 } else {
4780 StateDag::Node idle = d->makeNodes({std::make_pair(State::IDLE, kBurstCommand),
4781 std::make_pair(State::ACTIVE, kPauseCommand),
4782 std::make_pair(State::PAUSED, kStartCommand),
4783 std::make_pair(State::ACTIVE, kPauseCommand),
4784 std::make_pair(State::PAUSED, kBurstCommand),
4785 std::make_pair(State::PAUSED, kFlushCommand)},
4786 State::IDLE);
4787 if (!isSync) {
4788 idle.children().push_back(
4789 d->makeNodes({std::make_pair(State::TRANSFERRING, kPauseCommand),
4790 std::make_pair(State::TRANSFER_PAUSED, kStartCommand),
4791 std::make_pair(State::TRANSFERRING, kPauseCommand),
4792 std::make_pair(State::TRANSFER_PAUSED, kDrainOutAllCommand),
4793 std::make_pair(State::DRAIN_PAUSED, kBurstCommand)},
4794 State::TRANSFER_PAUSED));
4795 }
4796 d->makeNode(State::STANDBY, kStartCommand, idle);
4797 }
4798 return std::make_shared<StateSequenceFollower>(std::move(d));
4799 }
4800 static const NamedCommandSequence kPauseInSeq =
4801 std::make_tuple(std::string("Pause"), kAidlVersion1, 0, StreamTypeFilter::ANY,
4802 makePauseCommands(true, false), false /*validatePositionIncrease*/);
4803 static const NamedCommandSequence kPauseOutSyncSeq =
4804 std::make_tuple(std::string("Pause"), kAidlVersion1, 0, StreamTypeFilter::SYNC,
4805 makePauseCommands(false, true), false /*validatePositionIncrease*/);
4806 static const NamedCommandSequence kPauseOutAsyncSeq =
4807 std::make_tuple(std::string("Pause"), kAidlVersion1, kStreamTransientStateTransitionDelayMs,
4808 StreamTypeFilter::ASYNC, makePauseCommands(false, false),
4809 false /*validatePositionIncrease*/);
4810
makeFlushCommands(bool isInput,bool isSync)4811 std::shared_ptr<StateSequence> makeFlushCommands(bool isInput, bool isSync) {
4812 using State = StreamDescriptor::State;
4813 auto d = std::make_unique<StateDag>();
4814 if (isInput) {
4815 d->makeNodes({std::make_pair(State::STANDBY, kStartCommand),
4816 std::make_pair(State::IDLE, kBurstCommand),
4817 std::make_pair(State::ACTIVE, kPauseCommand),
4818 std::make_pair(State::PAUSED, kFlushCommand)},
4819 State::STANDBY);
4820 } else {
4821 StateDag::Node last = d->makeFinalNode(State::IDLE);
4822 StateDag::Node idle = d->makeNodes({std::make_pair(State::IDLE, kBurstCommand),
4823 std::make_pair(State::ACTIVE, kPauseCommand),
4824 std::make_pair(State::PAUSED, kFlushCommand)},
4825 last);
4826 if (!isSync) {
4827 idle.children().push_back(
4828 d->makeNodes({std::make_pair(State::TRANSFERRING, kPauseCommand),
4829 std::make_pair(State::TRANSFER_PAUSED, kFlushCommand)},
4830 last));
4831 }
4832 d->makeNode(State::STANDBY, kStartCommand, idle);
4833 }
4834 return std::make_shared<StateSequenceFollower>(std::move(d));
4835 }
4836 static const NamedCommandSequence kFlushInSeq =
4837 std::make_tuple(std::string("Flush"), kAidlVersion1, 0, StreamTypeFilter::ANY,
4838 makeFlushCommands(true, false), false /*validatePositionIncrease*/);
4839 static const NamedCommandSequence kFlushOutSyncSeq =
4840 std::make_tuple(std::string("Flush"), kAidlVersion1, 0, StreamTypeFilter::SYNC,
4841 makeFlushCommands(false, true), false /*validatePositionIncrease*/);
4842 static const NamedCommandSequence kFlushOutAsyncSeq =
4843 std::make_tuple(std::string("Flush"), kAidlVersion1, kStreamTransientStateTransitionDelayMs,
4844 StreamTypeFilter::ASYNC, makeFlushCommands(false, false),
4845 false /*validatePositionIncrease*/);
4846
makeDrainPauseFlushOutCommands(bool isSync)4847 std::shared_ptr<StateSequence> makeDrainPauseFlushOutCommands(bool isSync) {
4848 using State = StreamDescriptor::State;
4849 auto d = std::make_unique<StateDag>();
4850 StateDag::Node draining = d->makeNodes({std::make_pair(State::DRAINING, kPauseCommand),
4851 std::make_pair(State::DRAIN_PAUSED, kFlushCommand)},
4852 State::IDLE);
4853 StateDag::Node active = d->makeNode(State::ACTIVE, kDrainOutAllCommand, draining);
4854 StateDag::Node idle = d->makeNode(State::IDLE, kBurstCommand, active);
4855 if (!isSync) {
4856 idle.children().push_back(d->makeNode(State::TRANSFERRING, kDrainOutAllCommand, draining));
4857 } else {
4858 // If we get straight into IDLE on drain, no further testing is possible.
4859 active.children().push_back(d->makeFinalNode(State::IDLE));
4860 }
4861 d->makeNode(State::STANDBY, kStartCommand, idle);
4862 return std::make_shared<StateSequenceFollower>(std::move(d));
4863 }
4864 static const NamedCommandSequence kDrainPauseFlushOutSyncSeq =
4865 std::make_tuple(std::string("DrainPauseFlush"), kAidlVersion1,
4866 kStreamTransientStateTransitionDelayMs, StreamTypeFilter::SYNC,
4867 makeDrainPauseFlushOutCommands(true), false /*validatePositionIncrease*/);
4868 static const NamedCommandSequence kDrainPauseFlushOutAsyncSeq =
4869 std::make_tuple(std::string("DrainPauseFlush"), kAidlVersion1,
4870 kStreamTransientStateTransitionDelayMs, StreamTypeFilter::ASYNC,
4871 makeDrainPauseFlushOutCommands(false), false /*validatePositionIncrease*/);
4872
4873 // Note, this isn't the "official" enum printer, it is only used to make the test name suffix.
PrintStreamFilterToString(StreamTypeFilter filter)4874 std::string PrintStreamFilterToString(StreamTypeFilter filter) {
4875 switch (filter) {
4876 case StreamTypeFilter::ANY:
4877 return "";
4878 case StreamTypeFilter::SYNC:
4879 return "Sync";
4880 case StreamTypeFilter::ASYNC:
4881 return "Async";
4882 }
4883 return std::string("Unknown").append(std::to_string(static_cast<int32_t>(filter)));
4884 }
GetStreamIoTestName(const testing::TestParamInfo<StreamIoTestParameters> & info)4885 std::string GetStreamIoTestName(const testing::TestParamInfo<StreamIoTestParameters>& info) {
4886 return android::PrintInstanceNameToString(
4887 testing::TestParamInfo<std::string>{std::get<PARAM_MODULE_NAME>(info.param),
4888 info.index})
4889 .append("_")
4890 .append(std::get<NAMED_CMD_NAME>(std::get<PARAM_CMD_SEQ>(info.param)))
4891 .append(PrintStreamFilterToString(
4892 std::get<NAMED_CMD_STREAM_TYPE>(std::get<PARAM_CMD_SEQ>(info.param))))
4893 .append("_SetupSeq")
4894 .append(std::get<PARAM_SETUP_SEQ>(info.param) ? "2" : "1");
4895 }
4896
4897 INSTANTIATE_TEST_SUITE_P(
4898 AudioStreamIoInTest, AudioStreamIoIn,
4899 testing::Combine(testing::ValuesIn(android::getAidlHalInstanceNames(IModule::descriptor)),
4900 testing::Values(kReadSeq, kDrainInSeq, kStandbyInSeq, kPauseInSeq,
4901 kFlushInSeq),
4902 testing::Values(false, true)),
4903 GetStreamIoTestName);
4904 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioStreamIoIn);
4905 INSTANTIATE_TEST_SUITE_P(
4906 AudioStreamIoOutTest, AudioStreamIoOut,
4907 testing::Combine(testing::ValuesIn(android::getAidlHalInstanceNames(IModule::descriptor)),
4908 testing::Values(kWriteSyncSeq, kWriteAsyncSeq, kWriteDrainAsyncSeq,
4909 kDrainOutSyncSeq, kDrainOutAsyncSeq,
4910 kDrainEarlyOutAsyncSeq, kDrainPauseOutSyncSeq,
4911 kDrainPauseOutAsyncSeq, kDrainEarlyPauseOutAsyncSeq,
4912 kStandbyOutSyncSeq, kStandbyOutAsyncSeq,
4913 kPauseOutSyncSeq, // kPauseOutAsyncSeq,
4914 kFlushOutSyncSeq, kFlushOutAsyncSeq,
4915 kDrainPauseFlushOutSyncSeq, kDrainPauseFlushOutAsyncSeq),
4916 testing::Values(false, true)),
4917 GetStreamIoTestName);
4918 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioStreamIoOut);
4919
4920 INSTANTIATE_TEST_SUITE_P(AudioPatchTest, AudioModulePatch,
4921 testing::ValuesIn(android::getAidlHalInstanceNames(IModule::descriptor)),
4922 android::PrintInstanceNameToString);
4923 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioModulePatch);
4924
getRemoteSubmixModuleInstance()4925 static std::vector<std::string> getRemoteSubmixModuleInstance() {
4926 auto instances = android::getAidlHalInstanceNames(IModule::descriptor);
4927 for (auto instance : instances) {
4928 if (instance.ends_with("/r_submix")) return (std::vector<std::string>{instance});
4929 }
4930 return {};
4931 }
4932
4933 template <typename Stream>
4934 class WithRemoteSubmix {
4935 public:
WithRemoteSubmix()4936 WithRemoteSubmix() : mStream(true /*isSync*/) {}
WithRemoteSubmix(AudioDeviceAddress address)4937 explicit WithRemoteSubmix(AudioDeviceAddress address)
4938 : mStream(true /*isSync*/), mAddress(address) {}
4939 WithRemoteSubmix(const WithRemoteSubmix&) = delete;
4940 WithRemoteSubmix& operator=(const WithRemoteSubmix&) = delete;
4941
getRemoteSubmixAudioPort(ModuleConfig * moduleConfig,const std::optional<AudioDeviceAddress> & address=std::nullopt)4942 static std::optional<AudioPort> getRemoteSubmixAudioPort(
4943 ModuleConfig* moduleConfig,
4944 const std::optional<AudioDeviceAddress>& address = std::nullopt) {
4945 auto ports =
4946 moduleConfig->getRemoteSubmixPorts(IOTraits<Stream>::is_input, true /*singlePort*/);
4947 if (ports.empty()) return {};
4948 AudioPort port = ports.front();
4949 if (address) {
4950 port.ext.template get<AudioPortExt::Tag::device>().device.address = address.value();
4951 }
4952 return port;
4953 }
4954
SetUp(IModule * module,ModuleConfig * moduleConfig)4955 void SetUp(IModule* module, ModuleConfig* moduleConfig) {
4956 auto devicePort = getRemoteSubmixAudioPort(moduleConfig, mAddress);
4957 ASSERT_TRUE(devicePort.has_value()) << "Device port for remote submix device not found";
4958 ASSERT_NO_FATAL_FAILURE(mStream.SetUp(module, moduleConfig, *devicePort));
4959 mAddress = mStream.getDevice().address;
4960 }
4961
StartWorkerToSendBurstCommands()4962 void StartWorkerToSendBurstCommands() {
4963 ASSERT_NO_FATAL_FAILURE(mStream.StartWorkerToSendBurstCommands());
4964 }
4965
JoinWorkerAfterBurstCommands()4966 void JoinWorkerAfterBurstCommands() {
4967 ASSERT_NO_FATAL_FAILURE(mStream.JoinWorkerAfterBurstCommands());
4968 }
4969
SendBurstCommands()4970 void SendBurstCommands() {
4971 ASSERT_NO_FATAL_FAILURE(mStream.StartWorkerToSendBurstCommands());
4972 ASSERT_NO_FATAL_FAILURE(mStream.JoinWorkerAfterBurstCommands());
4973 }
4974
getAudioDeviceAddress() const4975 std::optional<AudioDeviceAddress> getAudioDeviceAddress() const { return mAddress; }
skipTestReason() const4976 std::string skipTestReason() const { return mStream.skipTestReason(); }
4977
4978 private:
SetUp(IModule * module,ModuleConfig * moduleConfig,const AudioPort & devicePort)4979 void SetUp(IModule* module, ModuleConfig* moduleConfig, const AudioPort& devicePort) {}
4980
4981 StreamFixtureWithWorker<Stream> mStream;
4982 std::optional<AudioDeviceAddress> mAddress;
4983 };
4984
4985 class AudioModuleRemoteSubmix : public AudioCoreModule {
4986 public:
SetUp()4987 void SetUp() override {
4988 // Turn off "debug" which enables connections simulation. Since devices of the remote
4989 // submix module are virtual, there is no need for simulation.
4990 ASSERT_NO_FATAL_FAILURE(SetUpImpl(GetParam(), false /*setUpDebug*/));
4991 if (int32_t version; module->getInterfaceVersion(&version).isOk() && version < 2) {
4992 GTEST_SKIP() << "V1 uses a deprecated remote submix device type encoding";
4993 }
4994 ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
4995 }
4996 };
4997
TEST_P(AudioModuleRemoteSubmix,OutputDoesNotBlockWhenNoInput)4998 TEST_P(AudioModuleRemoteSubmix, OutputDoesNotBlockWhenNoInput) {
4999 WithRemoteSubmix<IStreamOut> streamOut;
5000 ASSERT_NO_FATAL_FAILURE(streamOut.SetUp(module.get(), moduleConfig.get()));
5001 // Note: here and in other tests any issue with connection attempts is considered as a problem.
5002 ASSERT_EQ("", streamOut.skipTestReason());
5003 ASSERT_NO_FATAL_FAILURE(streamOut.SendBurstCommands());
5004 }
5005
TEST_P(AudioModuleRemoteSubmix,OutputDoesNotBlockWhenInputStuck)5006 TEST_P(AudioModuleRemoteSubmix, OutputDoesNotBlockWhenInputStuck) {
5007 WithRemoteSubmix<IStreamOut> streamOut;
5008 ASSERT_NO_FATAL_FAILURE(streamOut.SetUp(module.get(), moduleConfig.get()));
5009 ASSERT_EQ("", streamOut.skipTestReason());
5010 auto address = streamOut.getAudioDeviceAddress();
5011 ASSERT_TRUE(address.has_value());
5012
5013 WithRemoteSubmix<IStreamIn> streamIn(address.value());
5014 ASSERT_NO_FATAL_FAILURE(streamIn.SetUp(module.get(), moduleConfig.get()));
5015 ASSERT_EQ("", streamIn.skipTestReason());
5016
5017 ASSERT_NO_FATAL_FAILURE(streamOut.SendBurstCommands());
5018 }
5019
TEST_P(AudioModuleRemoteSubmix,OutputAndInput)5020 TEST_P(AudioModuleRemoteSubmix, OutputAndInput) {
5021 WithRemoteSubmix<IStreamOut> streamOut;
5022 ASSERT_NO_FATAL_FAILURE(streamOut.SetUp(module.get(), moduleConfig.get()));
5023 ASSERT_EQ("", streamOut.skipTestReason());
5024 auto address = streamOut.getAudioDeviceAddress();
5025 ASSERT_TRUE(address.has_value());
5026
5027 WithRemoteSubmix<IStreamIn> streamIn(address.value());
5028 ASSERT_NO_FATAL_FAILURE(streamIn.SetUp(module.get(), moduleConfig.get()));
5029 ASSERT_EQ("", streamIn.skipTestReason());
5030
5031 // Start writing into the output stream.
5032 ASSERT_NO_FATAL_FAILURE(streamOut.StartWorkerToSendBurstCommands());
5033 // Simultaneously, read from the input stream.
5034 ASSERT_NO_FATAL_FAILURE(streamIn.SendBurstCommands());
5035 ASSERT_NO_FATAL_FAILURE(streamOut.JoinWorkerAfterBurstCommands());
5036 }
5037
TEST_P(AudioModuleRemoteSubmix,OpenInputMultipleTimes)5038 TEST_P(AudioModuleRemoteSubmix, OpenInputMultipleTimes) {
5039 WithRemoteSubmix<IStreamOut> streamOut;
5040 ASSERT_NO_FATAL_FAILURE(streamOut.SetUp(module.get(), moduleConfig.get()));
5041 ASSERT_EQ("", streamOut.skipTestReason());
5042 auto address = streamOut.getAudioDeviceAddress();
5043 ASSERT_TRUE(address.has_value());
5044
5045 const size_t streamInCount = 3;
5046 std::vector<std::unique_ptr<WithRemoteSubmix<IStreamIn>>> streamIns(streamInCount);
5047 for (size_t i = 0; i < streamInCount; i++) {
5048 streamIns[i] = std::make_unique<WithRemoteSubmix<IStreamIn>>(address.value());
5049 ASSERT_NO_FATAL_FAILURE(streamIns[i]->SetUp(module.get(), moduleConfig.get()));
5050 ASSERT_EQ("", streamIns[i]->skipTestReason());
5051 }
5052 // Start writing into the output stream.
5053 ASSERT_NO_FATAL_FAILURE(streamOut.StartWorkerToSendBurstCommands());
5054 // Simultaneously, read from input streams.
5055 for (size_t i = 0; i < streamInCount; i++) {
5056 ASSERT_NO_FATAL_FAILURE(streamIns[i]->StartWorkerToSendBurstCommands());
5057 }
5058 for (size_t i = 0; i < streamInCount; i++) {
5059 ASSERT_NO_FATAL_FAILURE(streamIns[i]->JoinWorkerAfterBurstCommands());
5060 }
5061 ASSERT_NO_FATAL_FAILURE(streamOut.JoinWorkerAfterBurstCommands());
5062 // Clean up input streams in the reverse order because the device connection is owned
5063 // by the first one.
5064 for (size_t i = streamInCount; i != 0; --i) {
5065 streamIns[i - 1].reset();
5066 }
5067 }
5068
5069 INSTANTIATE_TEST_SUITE_P(AudioModuleRemoteSubmixTest, AudioModuleRemoteSubmix,
5070 ::testing::ValuesIn(getRemoteSubmixModuleInstance()));
5071 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioModuleRemoteSubmix);
5072
main(int argc,char ** argv)5073 int main(int argc, char** argv) {
5074 ::testing::InitGoogleTest(&argc, argv);
5075 ::testing::UnitTest::GetInstance()->listeners().Append(new TestExecutionTracer());
5076 android::base::SetMinimumLogSeverity(::android::base::DEBUG);
5077 ABinderProcess_setThreadPoolMaxThreadCount(1);
5078 ABinderProcess_startThreadPool();
5079 return RUN_ALL_TESTS();
5080 }
5081