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