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 <DeviceDescriptor.h> 23 #include <HwModule.h> 24 #include <Serializer.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 struct PolicyConfigData { 34 android::HwModuleCollection hwModules; 35 android::DeviceVector availableOutputDevices; 36 android::DeviceVector availableInputDevices; 37 sp<android::DeviceDescriptor> defaultOutputDevice; 38 }; 39 40 class PolicyConfig : private PolicyConfigData, public android::AudioPolicyConfig { 41 public: PolicyConfig(const std::string & configFileName)42 explicit PolicyConfig(const std::string& configFileName) 43 : android::AudioPolicyConfig(hwModules, availableOutputDevices, availableInputDevices, 44 defaultOutputDevice), 45 mConfigFileName{configFileName} { 46 for (const auto& location : android::audio_get_configuration_paths()) { 47 std::string path = location + '/' + mConfigFileName; 48 if (access(path.c_str(), F_OK) == 0) { 49 mFilePath = path; 50 break; 51 } 52 } 53 init(); 54 } PolicyConfig(const std::string & configPath,const std::string & configFileName)55 PolicyConfig(const std::string& configPath, const std::string& configFileName) 56 : android::AudioPolicyConfig(hwModules, availableOutputDevices, availableInputDevices, 57 defaultOutputDevice), 58 mConfigFileName{configFileName}, 59 mFilePath{configPath + "/" + mConfigFileName} { 60 init(); 61 } getStatus()62 status_t getStatus() const { return mStatus; } getError()63 std::string getError() const { 64 if (mFilePath.empty()) { 65 return std::string{"Could not find "} + mConfigFileName + 66 " file in: " + testing::PrintToString(android::audio_get_configuration_paths()); 67 } else { 68 return "Invalid config file: " + mFilePath; 69 } 70 } getFilePath()71 const std::string& getFilePath() const { return mFilePath; } getModuleFromName(const std::string & name)72 sp<const android::HwModule> getModuleFromName(const std::string& name) const { 73 return getHwModules().getModuleFromName(name.c_str()); 74 } getPrimaryModule()75 sp<const android::HwModule> getPrimaryModule() const { return mPrimaryModule; } getModulesWithDevicesNames()76 const std::set<std::string>& getModulesWithDevicesNames() const { 77 return mModulesWithDevicesNames; 78 } getAttachedSinkDeviceForMixPort(const std::string & moduleName,const std::string & mixPortName)79 std::string getAttachedSinkDeviceForMixPort(const std::string& moduleName, 80 const std::string& mixPortName) const { 81 return findAttachedDevice(getAttachedDevices(moduleName), 82 getSinkDevicesForMixPort(moduleName, mixPortName)); 83 } getAttachedSourceDeviceForMixPort(const std::string & moduleName,const std::string & mixPortName)84 std::string getAttachedSourceDeviceForMixPort(const std::string& moduleName, 85 const std::string& mixPortName) const { 86 return findAttachedDevice(getAttachedDevices(moduleName), 87 getSourceDevicesForMixPort(moduleName, mixPortName)); 88 } haveInputProfilesInModule(const std::string & name)89 bool haveInputProfilesInModule(const std::string& name) const { 90 auto module = getModuleFromName(name); 91 return module && !module->getInputProfiles().empty(); 92 } 93 94 private: init()95 void init() { 96 mStatus = android::deserializeAudioPolicyFileForVts(mFilePath.c_str(), this); 97 if (mStatus == android::OK) { 98 mPrimaryModule = getModuleFromName(DeviceManager::kPrimaryDevice); 99 // Available devices are not 'attached' to modules at this moment. 100 // Need to go over available devices and find their module. 101 for (const auto& device : availableOutputDevices) { 102 for (const auto& module : hwModules) { 103 if (module->getDeclaredDevices().indexOf(device) >= 0) { 104 mModulesWithDevicesNames.insert(module->getName()); 105 mAttachedDevicesPerModule[module->getName()].push_back( 106 device->getTagName()); 107 break; 108 } 109 } 110 } 111 for (const auto& device : availableInputDevices) { 112 for (const auto& module : hwModules) { 113 if (module->getDeclaredDevices().indexOf(device) >= 0) { 114 mModulesWithDevicesNames.insert(module->getName()); 115 mAttachedDevicesPerModule[module->getName()].push_back( 116 device->getTagName()); 117 break; 118 } 119 } 120 } 121 } 122 } findAttachedDevice(const std::vector<std::string> & attachedDevices,const std::set<std::string> & possibleDevices)123 std::string findAttachedDevice(const std::vector<std::string>& attachedDevices, 124 const std::set<std::string>& possibleDevices) const { 125 for (const auto& device : attachedDevices) { 126 if (possibleDevices.count(device)) return device; 127 } 128 return {}; 129 } getAttachedDevices(const std::string & moduleName)130 std::vector<std::string> getAttachedDevices(const std::string& moduleName) const { 131 if (auto iter = mAttachedDevicesPerModule.find(moduleName); 132 iter != mAttachedDevicesPerModule.end()) { 133 return iter->second; 134 } 135 return {}; 136 } getSinkDevicesForMixPort(const std::string & moduleName,const std::string & mixPortName)137 std::set<std::string> getSinkDevicesForMixPort(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 for (const auto& source : route->getSources()) { 144 if (source->getTagName() == mixPortName) { 145 result.insert(route->getSink()->getTagName()); 146 } 147 } 148 } 149 } 150 return result; 151 } getSourceDevicesForMixPort(const std::string & moduleName,const std::string & mixPortName)152 std::set<std::string> getSourceDevicesForMixPort(const std::string& moduleName, 153 const std::string& mixPortName) const { 154 std::set<std::string> result; 155 auto module = getModuleFromName(moduleName); 156 if (module != nullptr) { 157 for (const auto& route : module->getRoutes()) { 158 if (route->getSink()->getTagName() == mixPortName) { 159 const auto& sources = route->getSources(); 160 std::transform(sources.begin(), sources.end(), 161 std::inserter(result, result.end()), 162 [](const auto& source) { return source->getTagName(); }); 163 } 164 } 165 } 166 return result; 167 } 168 169 const std::string mConfigFileName; 170 status_t mStatus = android::NO_INIT; 171 std::string mFilePath; 172 sp<const android::HwModule> mPrimaryModule = nullptr; 173 std::set<std::string> mModulesWithDevicesNames; 174 std::map<std::string, std::vector<std::string>> mAttachedDevicesPerModule; 175 }; 176