/* * Copyright (C) 2021 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 #include #include #include #include #include "DeviceManager.h" #include "PolicyConfig.h" #include "common/all-versions/HidlSupport.h" using ::android::NO_ERROR; using ::android::OK; using namespace ::android::hardware::audio::common::COMMON_TYPES_CPP_VERSION; using namespace ::android::hardware::audio::CORE_TYPES_CPP_VERSION; using ::android::hardware::audio::common::COMMON_TYPES_CPP_VERSION::implementation::HidlUtils; using ::android::hardware::audio::common::utils::splitString; namespace xsd { using namespace ::android::audio::policy::configuration::CPP_VERSION; using Module = Modules::Module; } // namespace xsd std::string PolicyConfig::getError() const { if (mFilePath.empty()) { return "Could not find " + mConfigFileName + " file in: " + testing::PrintToString(android::audio_get_configuration_paths()); } else { return "Invalid config file: " + mFilePath; } } const xsd::Module* PolicyConfig::getModuleFromName(const std::string& name) const { if (mConfig && mConfig->getFirstModules()) { for (const auto& module : mConfig->getFirstModules()->get_module()) { if (module.getName() == name) return &module; } } return nullptr; } std::optional PolicyConfig::getSinkDeviceForMixPort( const std::string& moduleName, const std::string& mixPortName) const { std::string device; if (auto module = getModuleFromName(moduleName); module) { auto possibleDevices = getSinkDevicesForMixPort(moduleName, mixPortName); if (module->hasDefaultOutputDevice() && possibleDevices.count(module->getDefaultOutputDevice())) { device = module->getDefaultOutputDevice(); } else { device = getAttachedSinkDeviceForMixPort(moduleName, mixPortName); } } if (!device.empty()) { return getDeviceAddressOfDevicePort(moduleName, device); } ALOGE("Could not find a route for the mix port \"%s\" in module \"%s\"", mixPortName.c_str(), moduleName.c_str()); return std::optional{}; } std::optional PolicyConfig::getSourceDeviceForMixPort( const std::string& moduleName, const std::string& mixPortName) const { const std::string device = getAttachedSourceDeviceForMixPort(moduleName, mixPortName); if (!device.empty()) { return getDeviceAddressOfDevicePort(moduleName, device); } ALOGE("Could not find a route for the mix port \"%s\" in module \"%s\"", mixPortName.c_str(), moduleName.c_str()); return std::optional{}; } bool PolicyConfig::haveInputProfilesInModule(const std::string& name) const { auto module = getModuleFromName(name); if (module && module->getFirstMixPorts()) { for (const auto& mixPort : module->getFirstMixPorts()->getMixPort()) { if (mixPort.getRole() == xsd::Role::sink) return true; } } return false; } // static std::string PolicyConfig::findExistingConfigurationFile(const std::string& fileName) { for (const auto& location : android::audio_get_configuration_paths()) { std::string path = location + '/' + fileName; if (access(path.c_str(), F_OK) == 0) { return path; } } return {}; } std::string PolicyConfig::findAttachedDevice(const std::vector& attachedDevices, const std::set& possibleDevices) const { for (const auto& device : attachedDevices) { if (possibleDevices.count(device)) return device; } return {}; } const std::vector& PolicyConfig::getAttachedDevices( const std::string& moduleName) const { static const std::vector empty; auto module = getModuleFromName(moduleName); if (module && module->getFirstAttachedDevices()) { return module->getFirstAttachedDevices()->getItem(); } return empty; } std::optional PolicyConfig::getDeviceAddressOfDevicePort( const std::string& moduleName, const std::string& devicePortName) const { auto module = getModuleFromName(moduleName); if (module->getFirstDevicePorts()) { const auto& devicePorts = module->getFirstDevicePorts()->getDevicePort(); const auto& devicePort = std::find_if( devicePorts.begin(), devicePorts.end(), [&devicePortName](auto dp) { return dp.getTagName() == devicePortName; }); if (devicePort != devicePorts.end()) { audio_devices_t halDeviceType; if (HidlUtils::audioDeviceTypeToHal(devicePort->getType(), &halDeviceType) == NO_ERROR) { // For AOSP device types use the standard parser for the device address. const std::string address = devicePort->hasAddress() ? devicePort->getAddress() : ""; DeviceAddress result; if (HidlUtils::deviceAddressFromHal(halDeviceType, address.c_str(), &result) == NO_ERROR) { return result; } } else if (xsd::isVendorExtension(devicePort->getType())) { DeviceAddress result; result.deviceType = devicePort->getType(); if (devicePort->hasAddress()) { result.address.id(devicePort->getAddress()); } return result; } } else { ALOGE("Device port \"%s\" not found in module \"%s\"", devicePortName.c_str(), moduleName.c_str()); } } else { ALOGE("Module \"%s\" has no device ports", moduleName.c_str()); } return std::optional{}; } std::set PolicyConfig::getSinkDevicesForMixPort(const std::string& moduleName, const std::string& mixPortName) const { std::set result; auto module = getModuleFromName(moduleName); if (module && module->getFirstRoutes()) { for (const auto& route : module->getFirstRoutes()->getRoute()) { const auto sources = splitString(route.getSources(), ','); if (std::find(sources.begin(), sources.end(), mixPortName) != sources.end()) { result.insert(route.getSink()); } } } return result; } std::set PolicyConfig::getSourceDevicesForMixPort( const std::string& moduleName, const std::string& mixPortName) const { std::set result; auto module = getModuleFromName(moduleName); if (module && module->getFirstRoutes()) { const auto& routes = module->getFirstRoutes()->getRoute(); const auto route = std::find_if(routes.begin(), routes.end(), [&mixPortName](auto rte) { return rte.getSink() == mixPortName; }); if (route != routes.end()) { const auto sources = splitString(route->getSources(), ','); std::copy(sources.begin(), sources.end(), std::inserter(result, result.end())); } } return result; } void PolicyConfig::init() { if (mConfig) { mStatus = OK; mPrimaryModule = getModuleFromName(DeviceManager::kPrimaryDevice); if (mConfig->getFirstModules()) { for (const auto& module : mConfig->getFirstModules()->get_module()) { if (module.getFirstAttachedDevices()) { auto attachedDevices = module.getFirstAttachedDevices()->getItem(); if (!attachedDevices.empty()) { mModulesWithDevicesNames.insert(module.getName()); } } } } } }