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