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