/* * Copyright (C) 2015 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. */ #define LOG_TAG "APM::Devices" //#define LOG_NDEBUG 0 #include #include #include #include #include #include #include "DeviceDescriptor.h" #include "TypeConverter.h" #include "HwModule.h" namespace android { DeviceDescriptor::DeviceDescriptor(audio_devices_t type) : DeviceDescriptor(type, "" /*tagName*/) { } DeviceDescriptor::DeviceDescriptor(audio_devices_t type, const std::string &tagName, const FormatVector &encodedFormats) : DeviceDescriptor(type, tagName, "" /*address*/, encodedFormats) { } DeviceDescriptor::DeviceDescriptor(audio_devices_t type, const std::string &tagName, const std::string &address, const FormatVector &encodedFormats) : DeviceDescriptor(AudioDeviceTypeAddr(type, address), tagName, encodedFormats) { } // Let DeviceDescriptorBase initialize the address since it handles specific cases like // legacy remote submix where "0" is added as default address. DeviceDescriptor::DeviceDescriptor(const AudioDeviceTypeAddr &deviceTypeAddr, const std::string &tagName, const FormatVector &encodedFormats) : DeviceDescriptorBase(deviceTypeAddr, encodedFormats), mTagName(tagName), mDeclaredAddress(DeviceDescriptorBase::address()) { mCurrentEncodedFormat = AUDIO_FORMAT_DEFAULT; } void DeviceDescriptor::attach(const sp& module) { PolicyAudioPort::attach(module); mId = getNextUniqueId(); } void DeviceDescriptor::detach() { mId = AUDIO_PORT_HANDLE_NONE; PolicyAudioPort::detach(); // The device address may have been overwritten on device connection setAddress(mDeclaredAddress); // Device Port does not have a name unless provided by setDeviceConnectionState setName(""); } template bool checkEqual(const T& f1, const T& f2) { std::set s1(f1.begin(), f1.end()); std::set s2(f2.begin(), f2.end()); return s1 == s2; } bool DeviceDescriptor::equals(const sp& other) const { // Devices are considered equal if they: // - are of the same type (a device type cannot be AUDIO_DEVICE_NONE) // - have the same address // - have the same encodingFormats (if device supports encoding) if (other == 0) { return false; } return mDeviceTypeAddr.equals(other->mDeviceTypeAddr) && checkEqual(mEncodedFormats, other->mEncodedFormats); } bool DeviceDescriptor::hasCurrentEncodedFormat() const { if (!device_has_encoding_capability(type())) { return true; } if (mEncodedFormats.empty()) { return true; } return (mCurrentEncodedFormat != AUDIO_FORMAT_DEFAULT); } status_t DeviceDescriptor::applyAudioPortConfig(const struct audio_port_config *config, audio_port_config *backupConfig) { struct audio_port_config localBackupConfig = { .config_mask = config->config_mask }; status_t status = NO_ERROR; toAudioPortConfig(&localBackupConfig); if ((status = validationBeforeApplyConfig(config)) == NO_ERROR) { AudioPortConfig::applyAudioPortConfig(config, backupConfig); } if (backupConfig != NULL) { *backupConfig = localBackupConfig; } return status; } void DeviceDescriptor::toAudioPortConfig(struct audio_port_config *dstConfig, const struct audio_port_config *srcConfig) const { DeviceDescriptorBase::toAudioPortConfig(dstConfig, srcConfig); dstConfig->ext.device.hw_module = getModuleHandle(); } void DeviceDescriptor::toAudioPort(struct audio_port *port) const { ALOGV("DeviceDescriptor::toAudioPort() handle %d type %08x", mId, mDeviceTypeAddr.mType); toAudioPortInternal(port); } void DeviceDescriptor::toAudioPort(struct audio_port_v7 *port) const { ALOGV("DeviceDescriptor::toAudioPort() v7 handle %d type %08x", mId, mDeviceTypeAddr.mType); toAudioPortInternal(port); } void DeviceDescriptor::importAudioPortAndPickAudioProfile( const sp& policyPort, bool force) { if (!force && !policyPort->asAudioPort()->hasDynamicAudioProfile()) { return; } AudioPort::importAudioPort(policyPort->asAudioPort()); policyPort->pickAudioProfile(mSamplingRate, mChannelMask, mFormat); } void DeviceDescriptor::setEncapsulationInfoFromHal( AudioPolicyClientInterface *clientInterface) { AudioParameter param(String8(mDeviceTypeAddr.getAddress())); param.addInt(String8(AudioParameter::keyRouting), mDeviceTypeAddr.mType); param.addKey(String8(AUDIO_PARAMETER_DEVICE_SUP_ENCAPSULATION_MODES)); param.addKey(String8(AUDIO_PARAMETER_DEVICE_SUP_ENCAPSULATION_METADATA_TYPES)); String8 reply = clientInterface->getParameters(AUDIO_IO_HANDLE_NONE, param.toString()); AudioParameter repliedParameters(reply); int value; if (repliedParameters.getInt( String8(AUDIO_PARAMETER_DEVICE_SUP_ENCAPSULATION_MODES), value) == NO_ERROR) { if (setEncapsulationModes(value) != NO_ERROR) { ALOGE("Failed to set encapsulation mode(%d)", value); } } if (repliedParameters.getInt( String8(AUDIO_PARAMETER_DEVICE_SUP_ENCAPSULATION_METADATA_TYPES), value) == NO_ERROR) { if (setEncapsulationMetadataTypes(value) != NO_ERROR) { ALOGE("Failed to set encapsulation metadata types(%d)", value); } } } void DeviceDescriptor::dump(String8 *dst, int spaces, bool verbose) const { String8 extraInfo; if (!mTagName.empty()) { extraInfo.appendFormat("\"%s\"", mTagName.c_str()); } std::string descBaseDumpStr; DeviceDescriptorBase::dump(&descBaseDumpStr, spaces, extraInfo.string(), verbose); dst->append(descBaseDumpStr.c_str()); } void DeviceVector::refreshTypes() { mDeviceTypes.clear(); for (size_t i = 0; i < size(); i++) { mDeviceTypes.insert(itemAt(i)->type()); } ALOGV("DeviceVector::refreshTypes() mDeviceTypes %s", dumpDeviceTypes(mDeviceTypes).c_str()); } void DeviceVector::refreshAudioProfiles() { if (empty()) { mSupportedProfiles.clear(); return; } mSupportedProfiles = itemAt(0)->getAudioProfiles(); for (size_t i = 1; i < size(); ++i) { mSupportedProfiles = intersectAudioProfiles( mSupportedProfiles, itemAt(i)->getAudioProfiles()); } } ssize_t DeviceVector::indexOf(const sp& item) const { for (size_t i = 0; i < size(); i++) { if (itemAt(i)->equals(item)) { // item may be null sp<>, i.e. AUDIO_DEVICE_NONE return i; } } return -1; } void DeviceVector::add(const DeviceVector &devices) { bool added = false; for (const auto& device : devices) { ALOG_ASSERT(device != nullptr, "Null pointer found when adding DeviceVector"); if (indexOf(device) < 0 && SortedVector::add(device) >= 0) { added = true; } } if (added) { refreshTypes(); refreshAudioProfiles(); } } ssize_t DeviceVector::add(const sp& item) { ALOG_ASSERT(item != nullptr, "Adding null pointer to DeviceVector"); ssize_t ret = indexOf(item); if (ret < 0) { ret = SortedVector::add(item); if (ret >= 0) { refreshTypes(); refreshAudioProfiles(); } } else { ALOGW("DeviceVector::add device %08x already in", item->type()); ret = -1; } return ret; } int DeviceVector::do_compare(const void* lhs, const void* rhs) const { const auto ldevice = *reinterpret_cast*>(lhs); const auto rdevice = *reinterpret_cast*>(rhs); int ret = 0; // sort by type. ret = compare_type(ldevice->type(), rdevice->type()); if (ret != 0) return ret; // for same type higher priority for latest device. ret = compare_type(rdevice->getId(), ldevice->getId()); if (ret != 0) return ret; // fallback to default sort using pointer address return SortedVector::do_compare(lhs, rhs); } ssize_t DeviceVector::remove(const sp& item) { ssize_t ret = indexOf(item); if (ret < 0) { ALOGW("DeviceVector::remove device %08x not in", item->type()); } else { ret = SortedVector::removeAt(ret); if (ret >= 0) { refreshTypes(); refreshAudioProfiles(); } } return ret; } void DeviceVector::remove(const DeviceVector &devices) { for (const auto& device : devices) { remove(device); } } DeviceVector DeviceVector::getDevicesFromHwModule(audio_module_handle_t moduleHandle) const { DeviceVector devices; for (const auto& device : *this) { if (device->getModuleHandle() == moduleHandle) { devices.add(device); } } return devices; } sp DeviceVector::getDevice(audio_devices_t type, const String8& address, audio_format_t format) const { sp device; for (size_t i = 0; i < size(); i++) { if (itemAt(i)->type() == type) { // If format is specified, match it and ignore address // Otherwise if address is specified match it // Otherwise always match if (((address == "" || (itemAt(i)->address().compare(address.c_str()) == 0)) && format == AUDIO_FORMAT_DEFAULT) || (itemAt(i)->supportsFormat(format) && format != AUDIO_FORMAT_DEFAULT)) { device = itemAt(i); if (itemAt(i)->address().compare(address.c_str()) == 0) { break; } } } } ALOGV("DeviceVector::%s() for type %08x address \"%s\" found %p format %08x", __func__, type, address.string(), device.get(), format); return device; } sp DeviceVector::getDeviceFromId(audio_port_handle_t id) const { if (id != AUDIO_PORT_HANDLE_NONE) { for (const auto& device : *this) { if (device->getId() == id) { return device; } } } return nullptr; } DeviceVector DeviceVector::getDevicesFromTypes(const DeviceTypeSet& types) const { DeviceVector devices; if (types.empty()) { return devices; } for (size_t i = 0; i < size(); i++) { if (types.count(itemAt(i)->type()) != 0) { devices.add(itemAt(i)); ALOGV("DeviceVector::%s() for type %08x found %p", __func__, itemAt(i)->type(), itemAt(i).get()); } } return devices; } sp DeviceVector::getDeviceFromTagName(const std::string &tagName) const { for (const auto& device : *this) { if (device->getTagName() == tagName) { return device; } } return nullptr; } DeviceVector DeviceVector::getFirstDevicesFromTypes( std::vector orderedTypes) const { DeviceVector devices; for (auto deviceType : orderedTypes) { if (!(devices = getDevicesFromType(deviceType)).isEmpty()) { break; } } return devices; } sp DeviceVector::getFirstExistingDevice( std::vector orderedTypes) const { sp device; for (auto deviceType : orderedTypes) { if ((device = getDevice(deviceType, String8(""), AUDIO_FORMAT_DEFAULT)) != nullptr) { break; } } return device; } sp DeviceVector::getDeviceForOpening() const { if (isEmpty()) { // Return nullptr if this collection is empty. return nullptr; } else if (areAllOfSameDeviceType(types(), audio_call_is_input_device)) { // For input case, return the first one when there is only one device. return size() > 1 ? nullptr : *begin(); } else if (areAllOfSameDeviceType(types(), audio_is_output_device)) { // For output case, return the device descriptor according to apm strategy. audio_devices_t deviceType = apm_extract_one_audio_device(types()); return deviceType == AUDIO_DEVICE_NONE ? nullptr : getDevice(deviceType, String8(""), AUDIO_FORMAT_DEFAULT); } // Return null pointer if the devices are not all input/output device. return nullptr; } sp DeviceVector::getDeviceFromDeviceTypeAddr( const AudioDeviceTypeAddr& deviceTypeAddr) const { return getDevice(deviceTypeAddr.mType, String8(deviceTypeAddr.getAddress()), AUDIO_FORMAT_DEFAULT); } DeviceVector DeviceVector::getDevicesFromDeviceTypeAddrVec( const AudioDeviceTypeAddrVector& deviceTypeAddrVector) const { DeviceVector devices; for (const auto& deviceTypeAddr : deviceTypeAddrVector) { sp device = getDeviceFromDeviceTypeAddr(deviceTypeAddr); if (device != nullptr) { devices.add(device); } } return devices; } AudioDeviceTypeAddrVector DeviceVector::toTypeAddrVector() const { AudioDeviceTypeAddrVector result; for (const auto& device : *this) { result.push_back(AudioDeviceTypeAddr(device->type(), device->address())); } return result; } void DeviceVector::replaceDevicesByType( audio_devices_t typeToRemove, const DeviceVector &devicesToAdd) { DeviceVector devicesToRemove = getDevicesFromType(typeToRemove); if (!devicesToRemove.isEmpty() && !devicesToAdd.isEmpty()) { remove(devicesToRemove); add(devicesToAdd); } } void DeviceVector::dump(String8 *dst, const String8 &tag, int spaces, bool verbose) const { if (isEmpty()) { return; } dst->appendFormat("%*s%s devices (%zu):\n", spaces, "", tag.string(), size()); for (size_t i = 0; i < size(); i++) { const std::string prefix = base::StringPrintf("%*s %zu. ", spaces, "", i + 1); dst->appendFormat("%s", prefix.c_str()); itemAt(i)->dump(dst, prefix.size(), verbose); } } std::string DeviceVector::toString(bool includeSensitiveInfo) const { if (isEmpty()) { return {"AUDIO_DEVICE_NONE"}; } std::string result = {"{"}; for (const auto &device : *this) { if (device != *begin()) { result += ";"; } result += device->toString(includeSensitiveInfo); } return result + "}"; } DeviceVector DeviceVector::filter(const DeviceVector &devices) const { DeviceVector filteredDevices; for (const auto &device : *this) { if (devices.contains(device)) { filteredDevices.add(device); } } return filteredDevices; } bool DeviceVector::containsAtLeastOne(const DeviceVector &devices) const { return !filter(devices).isEmpty(); } bool DeviceVector::containsAllDevices(const DeviceVector &devices) const { return filter(devices).size() == devices.size(); } DeviceVector DeviceVector::filterForEngine() const { DeviceVector filteredDevices; for (const auto &device : *this) { if (audio_is_remote_submix_device(device->type()) && device->address() != "0") { continue; } filteredDevices.add(device); } return filteredDevices; } } // namespace android