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}, ¶meters);
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)(¤tValue));
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, ¶ms); 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}, ¶meters);
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}, ¶meters);
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