Add audio control configuraiton APIs VTS

Bug: 359686069
Test: atest VtsAidlHalAudioControlTest
Flag: EXEMPT HAL interface
Change-Id: I9fcaaae15dc9049567587ce1fefd4ff1caa71ef1
diff --git a/automotive/audiocontrol/aidl/vts/src/AudioControlTestUtils.cpp b/automotive/audiocontrol/aidl/vts/src/AudioControlTestUtils.cpp
new file mode 100644
index 0000000..7b7c896
--- /dev/null
+++ b/automotive/audiocontrol/aidl/vts/src/AudioControlTestUtils.cpp
@@ -0,0 +1,203 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "../include/AudioControlTestUtils.h"
+
+#include <set>
+
+using android::hardware::automotive::audiocontrol::AudioZone;
+using android::hardware::automotive::audiocontrol::AudioZoneConfig;
+using android::hardware::automotive::audiocontrol::AudioZoneContext;
+using android::hardware::automotive::audiocontrol::AudioZoneContextInfo;
+using android::hardware::automotive::audiocontrol::DeviceToContextEntry;
+using android::hardware::automotive::audiocontrol::VolumeGroupConfig;
+
+namespace audiomediacommon = android::media::audio::common;
+
+namespace android {
+namespace hardware {
+namespace audiocontrol {
+namespace testutils {
+
+std::string toAlphaNumeric(const std::string& info) {
+    std::string name = info;
+    for (size_t i = 0; i < name.size(); i++) {
+        // gtest test names must only contain alphanumeric characters
+        if (!std::isalnum(name[i])) name[i] = '_';
+    }
+
+    return name;
+}
+
+bool getAudioPortDeviceDescriptor(const audiomediacommon::AudioPort& audioPort,
+                                  audiomediacommon::AudioDeviceDescription& description) {
+    if (audioPort.ext.getTag() != audiomediacommon::AudioPortExt::Tag::device) {
+        return false;
+    }
+    const auto& audioDevice =
+            audioPort.ext.get<audiomediacommon::AudioPortExt::Tag::device>().device;
+    description = audioDevice.type;
+    return true;
+}
+
+bool getAddressForAudioPort(const android::media::audio::common::AudioPort& audioPort,
+                            std::string& address) {
+    if (audioPort.ext.getTag() != audiomediacommon::AudioPortExt::Tag::device) {
+        return false;
+    }
+    const auto& audioDevice =
+            audioPort.ext.get<audiomediacommon::AudioPortExt::Tag::device>().device;
+
+    switch (audioDevice.address.getTag()) {
+        case audiomediacommon::AudioDeviceAddress::Tag::id:
+            address = audioDevice.address.get<audiomediacommon::AudioDeviceAddress::Tag::id>();
+            return true;
+        case audiomediacommon::AudioDeviceAddress::Tag::alsa:
+            address = android::internal::ToString(
+                    audioDevice.address.get<audiomediacommon::AudioDeviceAddress::Tag::alsa>());
+            return true;
+        case audiomediacommon::AudioDeviceAddress::Tag::mac:
+            address = android::internal::ToString(
+                    audioDevice.address.get<audiomediacommon::AudioDeviceAddress::Tag::mac>());
+            return true;
+        case audiomediacommon::AudioDeviceAddress::Tag::ipv4:
+            address = android::internal::ToString(
+                    audioDevice.address.get<audiomediacommon::AudioDeviceAddress::Tag::ipv4>());
+            return true;
+        case audiomediacommon::AudioDeviceAddress::Tag::ipv6:
+            address = android::internal::ToString(
+                    audioDevice.address.get<audiomediacommon::AudioDeviceAddress::Tag::ipv6>());
+            return true;
+        default:
+            address = audioDevice.address.toString();
+            return true;
+    }
+}
+
+bool getAddressForAudioDevice(const DeviceToContextEntry& device, std::string& address) {
+    if (device.device.flags.getTag() == audiomediacommon::AudioIoFlags::input ||
+        device.device.ext.getTag() != audiomediacommon::AudioPortExt::Tag::device) {
+        return false;
+    }
+    return getAddressForAudioPort(device.device, address);
+}
+
+std::vector<std::string> getDeviceAddressesForVolumeGroup(const VolumeGroupConfig& config) {
+    std::vector<std::string> addresses;
+    for (const auto& route : config.carAudioRoutes) {
+        std::string address;
+        if (!getAddressForAudioDevice(route, address)) {
+            continue;
+        }
+        addresses.push_back(address);
+    }
+    return addresses;
+}
+
+std::vector<std::string> getDeviceAddressesForZoneConfig(const AudioZoneConfig& config) {
+    std::vector<std::string> addresses;
+    for (const auto& volumeGroup : config.volumeGroups) {
+        const auto groupAddresses = getDeviceAddressesForVolumeGroup(volumeGroup);
+        addresses.insert(addresses.begin(), groupAddresses.begin(), groupAddresses.end());
+    }
+    return addresses;
+}
+
+std::vector<std::string> getDeviceAddressesForZone(const AudioZone& config) {
+    std::vector<std::string> addresses;
+    for (const auto& zoneConfig : config.audioZoneConfigs) {
+        const auto groupAddresses = getDeviceAddressesForZoneConfig(zoneConfig);
+        addresses.insert(addresses.begin(), groupAddresses.begin(), groupAddresses.end());
+    }
+    return addresses;
+}
+
+static void addContextUsages(const AudioZoneContextInfo& info,
+                             std::set<audiomediacommon::AudioUsage>& contextUsages) {
+    for (const auto& audioAttribute : info.audioAttributes) {
+        contextUsages.insert(audioAttribute.usage);
+    }
+}
+
+bool contextInfosContainAllAudioAttributeUsages(const std::vector<AudioZoneContextInfo>& infos,
+                                                std::string& message) {
+    static const std::vector<audiomediacommon::AudioUsage> audioUsages{
+            audiomediacommon::AudioUsage::UNKNOWN,
+            audiomediacommon::AudioUsage::MEDIA,
+            audiomediacommon::AudioUsage::VOICE_COMMUNICATION,
+            audiomediacommon::AudioUsage::VOICE_COMMUNICATION_SIGNALLING,
+            audiomediacommon::AudioUsage::ALARM,
+            audiomediacommon::AudioUsage::NOTIFICATION,
+            audiomediacommon::AudioUsage::NOTIFICATION_TELEPHONY_RINGTONE,
+            audiomediacommon::AudioUsage::NOTIFICATION_EVENT,
+            audiomediacommon::AudioUsage::ASSISTANCE_ACCESSIBILITY,
+            audiomediacommon::AudioUsage::ASSISTANCE_NAVIGATION_GUIDANCE,
+            audiomediacommon::AudioUsage::ASSISTANCE_SONIFICATION,
+            audiomediacommon::AudioUsage::GAME,
+            audiomediacommon::AudioUsage::ASSISTANT,
+            audiomediacommon::AudioUsage::CALL_ASSISTANT,
+            audiomediacommon::AudioUsage::EMERGENCY,
+            audiomediacommon::AudioUsage::SAFETY,
+            audiomediacommon::AudioUsage::VEHICLE_STATUS,
+            audiomediacommon::AudioUsage::ANNOUNCEMENT,
+    };
+
+    std::set<audiomediacommon::AudioUsage> contextUsages;
+    for (const auto& contextInfo : infos) {
+        addContextUsages(contextInfo, contextUsages);
+    }
+
+    bool allUsagesPresent = true;
+    for (const auto& usage : audioUsages) {
+        if (contextUsages.contains(usage)) {
+            continue;
+        }
+        if (message.empty()) {
+            message = " Missing usage(s): ";
+        }
+        message += audiomediacommon::toString(usage) + ", ";
+        allUsagesPresent = false;
+    }
+    return allUsagesPresent;
+}
+
+bool contextContainsAllAudioAttributeUsages(const AudioZoneContext& context, std::string& message) {
+    return contextInfosContainAllAudioAttributeUsages(context.audioContextInfos, message);
+}
+
+std::vector<std::string> getContextInfoNamesForAudioRoute(const DeviceToContextEntry& route) {
+    std::vector<std::string> contextInfoNames;
+    contextInfoNames.reserve(route.contextNames.size());
+    for (const auto& contextName : route.contextNames) {
+        contextInfoNames.push_back(android::internal::ToString(contextName));
+    }
+    return contextInfoNames;
+}
+
+std::vector<std::string> getContextInfoNamesForVolumeGroup(const VolumeGroupConfig& group) {
+    std::vector<std::string> contextInfoNames;
+    for (const auto& route : group.carAudioRoutes) {
+        std::vector<std::string> routeContexts = getContextInfoNamesForAudioRoute(route);
+        contextInfoNames.insert(contextInfoNames.begin(), routeContexts.begin(),
+                                routeContexts.end());
+    }
+    return contextInfoNames;
+}
+
+}  // namespace testutils
+}  // namespace audiocontrol
+}  // namespace hardware
+}  // namespace android
\ No newline at end of file