/* * 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. */ #pragma once #include "policy.h" #include #include #include #include #include #include namespace android { typedef SortedVector SampleRateVector; typedef SortedVector ChannelsVector; typedef Vector FormatVector; template bool operator == (const SortedVector &left, const SortedVector &right); class AudioProfile : public virtual RefBase { public: AudioProfile(audio_format_t format, audio_channel_mask_t channelMasks, uint32_t samplingRate) : mName(String8("")), mFormat(format) { mChannelMasks.add(channelMasks); mSamplingRates.add(samplingRate); } AudioProfile(audio_format_t format, const ChannelsVector &channelMasks, const SampleRateVector &samplingRateCollection) : mName(String8("")), mFormat(format), mChannelMasks(channelMasks), mSamplingRates(samplingRateCollection) {} audio_format_t getFormat() const { return mFormat; } void setChannels(const ChannelsVector &channelMasks) { if (mIsDynamicChannels) { mChannelMasks = channelMasks; } } const ChannelsVector &getChannels() const { return mChannelMasks; } void setSampleRates(const SampleRateVector &sampleRates) { if (mIsDynamicRate) { mSamplingRates = sampleRates; } } const SampleRateVector &getSampleRates() const { return mSamplingRates; } bool isValid() const { return hasValidFormat() && hasValidRates() && hasValidChannels(); } void clear() { if (mIsDynamicChannels) { mChannelMasks.clear(); } if (mIsDynamicRate) { mSamplingRates.clear(); } } inline bool supportsChannels(audio_channel_mask_t channels) const { return mChannelMasks.indexOf(channels) >= 0; } inline bool supportsRate(uint32_t rate) const { return mSamplingRates.indexOf(rate) >= 0; } status_t checkExact(uint32_t rate, audio_channel_mask_t channels, audio_format_t format) const; status_t checkCompatibleChannelMask(audio_channel_mask_t channelMask, audio_channel_mask_t &updatedChannelMask, audio_port_type_t portType, audio_port_role_t portRole) const; status_t checkCompatibleSamplingRate(uint32_t samplingRate, uint32_t &updatedSamplingRate) const; bool hasValidFormat() const { return mFormat != AUDIO_FORMAT_DEFAULT; } bool hasValidRates() const { return !mSamplingRates.isEmpty(); } bool hasValidChannels() const { return !mChannelMasks.isEmpty(); } void setDynamicChannels(bool dynamic) { mIsDynamicChannels = dynamic; } bool isDynamicChannels() const { return mIsDynamicChannels; } void setDynamicRate(bool dynamic) { mIsDynamicRate = dynamic; } bool isDynamicRate() const { return mIsDynamicRate; } void setDynamicFormat(bool dynamic) { mIsDynamicFormat = dynamic; } bool isDynamicFormat() const { return mIsDynamicFormat; } bool isDynamic() { return mIsDynamicFormat || mIsDynamicChannels || mIsDynamicRate; } void dump(int fd, int spaces) const; private: String8 mName; audio_format_t mFormat; ChannelsVector mChannelMasks; SampleRateVector mSamplingRates; bool mIsDynamicFormat = false; bool mIsDynamicChannels = false; bool mIsDynamicRate = false; }; class AudioProfileVector : public Vector > { public: ssize_t add(const sp &profile) { ssize_t index = Vector::add(profile); // we sort from worst to best, so that AUDIO_FORMAT_DEFAULT is always the first entry. // TODO: compareFormats could be a lambda to convert between pointer-to-format to format: // [](const audio_format_t *format1, const audio_format_t *format2) { // return compareFormats(*format1, *format2); // } sort(compareFormats); return index; } // This API is intended to be used by the policy manager once retrieving capabilities // for a profile with dynamic format, rate and channels attributes ssize_t addProfileFromHal(const sp &profileToAdd) { // Check valid profile to add: if (!profileToAdd->hasValidFormat()) { return -1; } if (!profileToAdd->hasValidChannels() && !profileToAdd->hasValidRates()) { FormatVector formats; formats.add(profileToAdd->getFormat()); setFormats(FormatVector(formats)); return 0; } if (!profileToAdd->hasValidChannels() && profileToAdd->hasValidRates()) { setSampleRatesFor(profileToAdd->getSampleRates(), profileToAdd->getFormat()); return 0; } if (profileToAdd->hasValidChannels() && !profileToAdd->hasValidRates()) { setChannelsFor(profileToAdd->getChannels(), profileToAdd->getFormat()); return 0; } // Go through the list of profile to avoid duplicates for (size_t profileIndex = 0; profileIndex < size(); profileIndex++) { const sp &profile = itemAt(profileIndex); if (profile->isValid() && profile == profileToAdd) { // Nothing to do return profileIndex; } } profileToAdd->setDynamicFormat(true); // set the format as dynamic to allow removal return add(profileToAdd); } sp getFirstValidProfile() const { for (size_t i = 0; i < size(); i++) { if (itemAt(i)->isValid()) { return itemAt(i); } } return 0; } bool hasValidProfile() const { return getFirstValidProfile() != 0; } status_t checkExactProfile(uint32_t samplingRate, audio_channel_mask_t channelMask, audio_format_t format) const; status_t checkCompatibleProfile(uint32_t &samplingRate, audio_channel_mask_t &channelMask, audio_format_t &format, audio_port_type_t portType, audio_port_role_t portRole) const; FormatVector getSupportedFormats() const { FormatVector supportedFormats; for (size_t i = 0; i < size(); i++) { if (itemAt(i)->hasValidFormat()) { supportedFormats.add(itemAt(i)->getFormat()); } } return supportedFormats; } bool hasDynamicProfile() const { for (size_t i = 0; i < size(); i++) { if (itemAt(i)->isDynamic()) { return true; } } return false; } bool hasDynamicFormat() const { return getProfileFor(gDynamicFormat) != 0; } bool hasDynamicChannelsFor(audio_format_t format) const { for (size_t i = 0; i < size(); i++) { sp profile = itemAt(i); if (profile->getFormat() == format && profile->isDynamicChannels()) { return true; } } return false; } bool hasDynamicRateFor(audio_format_t format) const { for (size_t i = 0; i < size(); i++) { sp profile = itemAt(i); if (profile->getFormat() == format && profile->isDynamicRate()) { return true; } } return false; } // One audio profile will be added for each format supported by Audio HAL void setFormats(const FormatVector &formats) { // Only allow to change the format of dynamic profile sp dynamicFormatProfile = getProfileFor(gDynamicFormat); if (dynamicFormatProfile == 0) { return; } for (size_t i = 0; i < formats.size(); i++) { sp profile = new AudioProfile(formats[i], dynamicFormatProfile->getChannels(), dynamicFormatProfile->getSampleRates()); profile->setDynamicFormat(true); profile->setDynamicChannels(dynamicFormatProfile->isDynamicChannels()); profile->setDynamicRate(dynamicFormatProfile->isDynamicRate()); add(profile); } } void clearProfiles() { for (size_t i = size(); i != 0; ) { sp profile = itemAt(--i); if (profile->isDynamicFormat() && profile->hasValidFormat()) { removeAt(i); continue; } profile->clear(); } } void dump(int fd, int spaces) const { const size_t SIZE = 256; char buffer[SIZE]; snprintf(buffer, SIZE, "%*s- Profiles:\n", spaces, ""); write(fd, buffer, strlen(buffer)); for (size_t i = 0; i < size(); i++) { snprintf(buffer, SIZE, "%*sProfile %zu:", spaces + 4, "", i); write(fd, buffer, strlen(buffer)); itemAt(i)->dump(fd, spaces + 8); } } private: void setSampleRatesFor(const SampleRateVector &sampleRates, audio_format_t format) { for (size_t i = 0; i < size(); i++) { sp profile = itemAt(i); if (profile->getFormat() == format && profile->isDynamicRate()) { if (profile->hasValidRates()) { // Need to create a new profile with same format sp profileToAdd = new AudioProfile(format, profile->getChannels(), sampleRates); profileToAdd->setDynamicFormat(true); // need to set to allow cleaning add(profileToAdd); } else { profile->setSampleRates(sampleRates); } return; } } } void setChannelsFor(const ChannelsVector &channelMasks, audio_format_t format) { for (size_t i = 0; i < size(); i++) { sp profile = itemAt(i); if (profile->getFormat() == format && profile->isDynamicChannels()) { if (profile->hasValidChannels()) { // Need to create a new profile with same format sp profileToAdd = new AudioProfile(format, channelMasks, profile->getSampleRates()); profileToAdd->setDynamicFormat(true); // need to set to allow cleaning add(profileToAdd); } else { profile->setChannels(channelMasks); } return; } } } sp getProfileFor(audio_format_t format) const { for (size_t i = 0; i < size(); i++) { if (itemAt(i)->getFormat() == format) { return itemAt(i); } } return 0; } static int compareFormats(const sp *profile1, const sp *profile2); }; bool operator == (const AudioProfile &left, const AudioProfile &right); }; // namespace android