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