1 /* 2 * Copyright (C) 2020 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 #pragma once 18 19 #include <set> 20 #include <string> 21 22 #include <AudioPolicyConfig.h> 23 #include <DeviceDescriptor.h> 24 #include <HwModule.h> 25 #include <gtest/gtest.h> 26 #include <system/audio_config.h> 27 28 #include "DeviceManager.h" 29 30 using ::android::sp; 31 using ::android::status_t; 32 33 class PolicyConfig { 34 public: PolicyConfig(const std::string & configPath,const std::string & configFileName)35 PolicyConfig(const std::string& configPath, const std::string& configFileName) 36 : mInitialFilePath(configPath.empty() ? configFileName 37 : configPath + "/" + configFileName) { 38 auto result = android::AudioPolicyConfig::loadFromCustomXmlConfigForVtsTests( 39 configPath, configFileName); 40 if (result.ok()) { 41 mStatus = ::android::OK; 42 mConfig = result.value(); 43 init(); 44 } else { 45 mStatus = result.error(); 46 } 47 } getStatus()48 status_t getStatus() const { return mStatus; } getError()49 std::string getError() const { 50 if (mConfig == nullptr) { 51 return std::string{"Could not find "} + mInitialFilePath + 52 " file in: " + testing::PrintToString(android::audio_get_configuration_paths()); 53 } else { 54 return "Invalid config file: " + mConfig->getSource(); 55 } 56 } getFilePath()57 const std::string& getFilePath() const { 58 return mConfig != nullptr ? mConfig->getSource() : mInitialFilePath; 59 } getModuleFromName(const std::string & name)60 sp<const android::HwModule> getModuleFromName(const std::string& name) const { 61 return mConfig->getHwModules().getModuleFromName(name.c_str()); 62 } getPrimaryModule()63 sp<const android::HwModule> getPrimaryModule() const { return mPrimaryModule; } getModulesWithDevicesNames()64 const std::set<std::string>& getModulesWithDevicesNames() const { 65 return mModulesWithDevicesNames; 66 } getAttachedSinkDeviceForMixPort(const std::string & moduleName,const std::string & mixPortName)67 std::string getAttachedSinkDeviceForMixPort(const std::string& moduleName, 68 const std::string& mixPortName) const { 69 return findAttachedDevice(getAttachedDevices(moduleName), 70 getSinkDevicesForMixPort(moduleName, mixPortName)); 71 } getAttachedSourceDeviceForMixPort(const std::string & moduleName,const std::string & mixPortName)72 std::string getAttachedSourceDeviceForMixPort(const std::string& moduleName, 73 const std::string& mixPortName) const { 74 return findAttachedDevice(getAttachedDevices(moduleName), 75 getSourceDevicesForMixPort(moduleName, mixPortName)); 76 } getInputDevices()77 const android::DeviceVector& getInputDevices() const { return mConfig->getInputDevices(); } getOutputDevices()78 const android::DeviceVector& getOutputDevices() const { return mConfig->getOutputDevices(); } haveInputProfilesInModule(const std::string & name)79 bool haveInputProfilesInModule(const std::string& name) const { 80 auto module = getModuleFromName(name); 81 return module && !module->getInputProfiles().empty(); 82 } 83 84 private: init()85 void init() { 86 mPrimaryModule = getModuleFromName(DeviceManager::kPrimaryDevice); 87 // Available devices are not 'attached' to modules at this moment. 88 // Need to go over available devices and find their module. 89 for (const auto& device : mConfig->getOutputDevices()) { 90 for (const auto& module : mConfig->getHwModules()) { 91 if (module->getDeclaredDevices().indexOf(device) >= 0) { 92 mModulesWithDevicesNames.insert(module->getName()); 93 mAttachedDevicesPerModule[module->getName()].push_back(device->getTagName()); 94 break; 95 } 96 } 97 } 98 for (const auto& device : mConfig->getInputDevices()) { 99 for (const auto& module : mConfig->getHwModules()) { 100 if (module->getDeclaredDevices().indexOf(device) >= 0) { 101 mModulesWithDevicesNames.insert(module->getName()); 102 mAttachedDevicesPerModule[module->getName()].push_back(device->getTagName()); 103 break; 104 } 105 } 106 } 107 } findAttachedDevice(const std::vector<std::string> & attachedDevices,const std::set<std::string> & possibleDevices)108 std::string findAttachedDevice(const std::vector<std::string>& attachedDevices, 109 const std::set<std::string>& possibleDevices) const { 110 for (const auto& device : attachedDevices) { 111 if (possibleDevices.count(device)) return device; 112 } 113 return {}; 114 } getAttachedDevices(const std::string & moduleName)115 std::vector<std::string> getAttachedDevices(const std::string& moduleName) const { 116 if (auto iter = mAttachedDevicesPerModule.find(moduleName); 117 iter != mAttachedDevicesPerModule.end()) { 118 return iter->second; 119 } 120 return {}; 121 } getSinkDevicesForMixPort(const std::string & moduleName,const std::string & mixPortName)122 std::set<std::string> getSinkDevicesForMixPort(const std::string& moduleName, 123 const std::string& mixPortName) const { 124 std::set<std::string> result; 125 auto module = getModuleFromName(moduleName); 126 if (module != nullptr) { 127 for (const auto& route : module->getRoutes()) { 128 for (const auto& source : route->getSources()) { 129 if (source->getTagName() == mixPortName) { 130 result.insert(route->getSink()->getTagName()); 131 } 132 } 133 } 134 } 135 return result; 136 } getSourceDevicesForMixPort(const std::string & moduleName,const std::string & mixPortName)137 std::set<std::string> getSourceDevicesForMixPort(const std::string& moduleName, 138 const std::string& mixPortName) const { 139 std::set<std::string> result; 140 auto module = getModuleFromName(moduleName); 141 if (module != nullptr) { 142 for (const auto& route : module->getRoutes()) { 143 if (route->getSink()->getTagName() == mixPortName) { 144 const auto& sources = route->getSources(); 145 std::transform(sources.begin(), sources.end(), 146 std::inserter(result, result.end()), 147 [](const auto& source) { return source->getTagName(); }); 148 } 149 } 150 } 151 return result; 152 } 153 154 const std::string mInitialFilePath; 155 status_t mStatus = android::NO_INIT; 156 sp<android::AudioPolicyConfig> mConfig; 157 sp<const android::HwModule> mPrimaryModule; 158 std::set<std::string> mModulesWithDevicesNames; 159 std::map<std::string, std::vector<std::string>> mAttachedDevicesPerModule; 160 }; 161