Make AudioProfile as a common class and create AudioProfileVectorBase.

AudioProfile is a class that contains information for an audio profile.
AudioProfileVectorBase is a base class that contains operations for a
vector of audio profiles. AudioProfileVector derives from
AudioProfileVectorBase and contains policy related stuff.

Bug: 135621476
Test: CTS for AudioRecord, AudioTrack, AudioManager
Test: audio smoke test, audiopolicy_tests
Test: dumpsys media.audio_policy
Change-Id: Ic2e08efcc5efa99e499a931811b7042fbd5ddf04
gugelfrei
jiabin 5 years ago
parent e46870e935
commit 9bb3a1e063

@ -10,17 +10,20 @@ cc_library_shared {
srcs: [
"AudioGain.cpp",
"AudioProfile.cpp",
],
shared_libs: [
"libbase",
"libbinder",
"liblog",
"libmedia_helper",
"libutils",
],
header_libs: [
"libaudio_system_headers",
"libaudioclient_headers",
"libaudiofoundation_headers",
],

@ -14,34 +14,30 @@
* limitations under the License.
*/
#include <algorithm>
#include <set>
#include <string>
#define LOG_TAG "APM::AudioProfile"
#define LOG_TAG "AudioProfile"
//#define LOG_NDEBUG 0
#include <android-base/stringprintf.h>
#include <media/AudioContainers.h>
#include <media/AudioResamplerPublic.h>
#include <media/AudioProfile.h>
#include <media/TypeConverter.h>
#include <utils/Errors.h>
#include "AudioPort.h"
#include "AudioProfile.h"
#include "HwModule.h"
#include "TypeConverter.h"
namespace android {
bool operator == (const AudioProfile &left, const AudioProfile &compareTo)
bool operator == (const AudioProfile &left, const AudioProfile &right)
{
return (left.getFormat() == compareTo.getFormat()) &&
(left.getChannels() == compareTo.getChannels()) &&
(left.getSampleRates() == compareTo.getSampleRates());
return (left.getFormat() == right.getFormat()) &&
(left.getChannels() == right.getChannels()) &&
(left.getSampleRates() == right.getSampleRates());
}
static AudioProfile* createFullDynamicImpl()
// static
sp<AudioProfile> AudioProfile::createFullDynamic(audio_format_t dynamicFormat)
{
AudioProfile* dynamicProfile = new AudioProfile(gDynamicFormat,
AudioProfile* dynamicProfile = new AudioProfile(dynamicFormat,
ChannelMaskSet(), SampleRateSet());
dynamicProfile->setDynamicFormat(true);
dynamicProfile->setDynamicChannels(true);
@ -49,17 +45,10 @@ static AudioProfile* createFullDynamicImpl()
return dynamicProfile;
}
// static
sp<AudioProfile> AudioProfile::createFullDynamic()
{
static sp<AudioProfile> dynamicProfile = createFullDynamicImpl();
return dynamicProfile;
}
AudioProfile::AudioProfile(audio_format_t format,
audio_channel_mask_t channelMasks,
uint32_t samplingRate) :
mName(String8("")),
mName(""),
mFormat(format)
{
mChannelMasks.insert(channelMasks);
@ -69,7 +58,7 @@ AudioProfile::AudioProfile(audio_format_t format,
AudioProfile::AudioProfile(audio_format_t format,
const ChannelMaskSet &channelMasks,
const SampleRateSet &samplingRateCollection) :
mName(String8("")),
mName(""),
mFormat(format),
mChannelMasks(channelMasks),
mSamplingRates(samplingRateCollection) {}
@ -98,276 +87,45 @@ void AudioProfile::clear()
}
}
status_t AudioProfile::checkExact(uint32_t samplingRate, audio_channel_mask_t channelMask,
audio_format_t format) const
{
if (audio_formats_match(format, mFormat) &&
supportsChannels(channelMask) &&
supportsRate(samplingRate)) {
return NO_ERROR;
}
return BAD_VALUE;
}
status_t AudioProfile::checkCompatibleSamplingRate(uint32_t samplingRate,
uint32_t &updatedSamplingRate) const
{
ALOG_ASSERT(samplingRate > 0);
if (mSamplingRates.empty()) {
updatedSamplingRate = samplingRate;
return NO_ERROR;
}
// Search for the closest supported sampling rate that is above (preferred)
// or below (acceptable) the desired sampling rate, within a permitted ratio.
// The sampling rates are sorted in ascending order.
auto desiredRate = mSamplingRates.lower_bound(samplingRate);
// Prefer to down-sample from a higher sampling rate, as we get the desired frequency spectrum.
if (desiredRate != mSamplingRates.end()) {
if (*desiredRate / AUDIO_RESAMPLER_DOWN_RATIO_MAX <= samplingRate) {
updatedSamplingRate = *desiredRate;
return NO_ERROR;
}
}
// But if we have to up-sample from a lower sampling rate, that's OK.
if (desiredRate != mSamplingRates.begin()) {
uint32_t candidate = *(--desiredRate);
if (candidate * AUDIO_RESAMPLER_UP_RATIO_MAX >= samplingRate) {
updatedSamplingRate = candidate;
return NO_ERROR;
}
}
// leave updatedSamplingRate unmodified
return BAD_VALUE;
}
status_t AudioProfile::checkCompatibleChannelMask(audio_channel_mask_t channelMask,
audio_channel_mask_t &updatedChannelMask,
audio_port_type_t portType,
audio_port_role_t portRole) const
{
if (mChannelMasks.empty()) {
updatedChannelMask = channelMask;
return NO_ERROR;
}
const bool isRecordThread = portType == AUDIO_PORT_TYPE_MIX && portRole == AUDIO_PORT_ROLE_SINK;
const bool isIndex = audio_channel_mask_get_representation(channelMask)
== AUDIO_CHANNEL_REPRESENTATION_INDEX;
const uint32_t channelCount = audio_channel_count_from_in_mask(channelMask);
int bestMatch = 0;
for (const auto &supported : mChannelMasks) {
if (supported == channelMask) {
// Exact matches always taken.
updatedChannelMask = channelMask;
return NO_ERROR;
}
// AUDIO_CHANNEL_NONE (value: 0) is used for dynamic channel support
if (isRecordThread && supported != AUDIO_CHANNEL_NONE) {
// Approximate (best) match:
// The match score measures how well the supported channel mask matches the
// desired mask, where increasing-is-better.
//
// TODO: Some tweaks may be needed.
// Should be a static function of the data processing library.
//
// In priority:
// match score = 1000 if legacy channel conversion equivalent (always prefer this)
// OR
// match score += 100 if the channel mask representations match
// match score += number of channels matched.
// match score += 100 if the channel mask representations DO NOT match
// but the profile has positional channel mask and less than 2 channels.
// This is for audio HAL convention to not list index masks for less than 2 channels
//
// If there are no matched channels, the mask may still be accepted
// but the playback or record will be silent.
const bool isSupportedIndex = (audio_channel_mask_get_representation(supported)
== AUDIO_CHANNEL_REPRESENTATION_INDEX);
const uint32_t supportedChannelCount = audio_channel_count_from_in_mask(supported);
int match;
if (isIndex && isSupportedIndex) {
// index equivalence
match = 100 + __builtin_popcount(
audio_channel_mask_get_bits(channelMask)
& audio_channel_mask_get_bits(supported));
} else if (isIndex && !isSupportedIndex) {
const uint32_t equivalentBits = (1 << supportedChannelCount) - 1 ;
match = __builtin_popcount(
audio_channel_mask_get_bits(channelMask) & equivalentBits);
if (supportedChannelCount <= FCC_2) {
match += 100;
}
} else if (!isIndex && isSupportedIndex) {
const uint32_t equivalentBits = (1 << channelCount) - 1;
match = __builtin_popcount(
equivalentBits & audio_channel_mask_get_bits(supported));
} else {
// positional equivalence
match = 100 + __builtin_popcount(
audio_channel_mask_get_bits(channelMask)
& audio_channel_mask_get_bits(supported));
switch (supported) {
case AUDIO_CHANNEL_IN_FRONT_BACK:
case AUDIO_CHANNEL_IN_STEREO:
if (channelMask == AUDIO_CHANNEL_IN_MONO) {
match = 1000;
}
break;
case AUDIO_CHANNEL_IN_MONO:
if (channelMask == AUDIO_CHANNEL_IN_FRONT_BACK
|| channelMask == AUDIO_CHANNEL_IN_STEREO) {
match = 1000;
}
break;
default:
break;
}
}
if (match > bestMatch) {
bestMatch = match;
updatedChannelMask = supported;
}
}
}
return bestMatch > 0 ? NO_ERROR : BAD_VALUE;
}
void AudioProfile::dump(String8 *dst, int spaces) const
void AudioProfile::dump(std::string *dst, int spaces) const
{
dst->appendFormat("%s%s%s\n", mIsDynamicFormat ? "[dynamic format]" : "",
dst->append(base::StringPrintf("%s%s%s\n", mIsDynamicFormat ? "[dynamic format]" : "",
mIsDynamicChannels ? "[dynamic channels]" : "",
mIsDynamicRate ? "[dynamic rates]" : "");
mIsDynamicRate ? "[dynamic rates]" : ""));
if (mName.length() != 0) {
dst->appendFormat("%*s- name: %s\n", spaces, "", mName.string());
dst->append(base::StringPrintf("%*s- name: %s\n", spaces, "", mName.c_str()));
}
std::string formatLiteral;
if (FormatConverter::toString(mFormat, formatLiteral)) {
dst->appendFormat("%*s- format: %s\n", spaces, "", formatLiteral.c_str());
dst->append(base::StringPrintf("%*s- format: %s\n", spaces, "", formatLiteral.c_str()));
}
if (!mSamplingRates.empty()) {
dst->appendFormat("%*s- sampling rates:", spaces, "");
dst->append(base::StringPrintf("%*s- sampling rates:", spaces, ""));
for (auto it = mSamplingRates.begin(); it != mSamplingRates.end();) {
dst->appendFormat("%d", *it);
dst->append(base::StringPrintf("%d", *it));
dst->append(++it == mSamplingRates.end() ? "" : ", ");
}
dst->append("\n");
}
if (!mChannelMasks.empty()) {
dst->appendFormat("%*s- channel masks:", spaces, "");
dst->append(base::StringPrintf("%*s- channel masks:", spaces, ""));
for (auto it = mChannelMasks.begin(); it != mChannelMasks.end();) {
dst->appendFormat("0x%04x", *it);
dst->append(base::StringPrintf("0x%04x", *it));
dst->append(++it == mChannelMasks.end() ? "" : ", ");
}
dst->append("\n");
}
}
ssize_t AudioProfileVector::add(const sp<AudioProfile> &profile)
ssize_t AudioProfileVectorBase::add(const sp<AudioProfile> &profile)
{
ssize_t index = size();
push_back(profile);
// we sort from worst to best, so that AUDIO_FORMAT_DEFAULT is always the first entry.
std::sort(begin(), end(),
[](const sp<AudioProfile> & a, const sp<AudioProfile> & b)
{
return AudioPort::compareFormats(a->getFormat(), b->getFormat()) < 0;
});
return index;
}
ssize_t AudioProfileVector::addProfileFromHal(const sp<AudioProfile> &profileToAdd)
{
// Check valid profile to add:
if (!profileToAdd->hasValidFormat()) {
return -1;
}
if (!profileToAdd->hasValidChannels() && !profileToAdd->hasValidRates()) {
FormatVector formats;
formats.push_back(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<AudioProfile> &profile = at(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);
}
status_t AudioProfileVector::checkExactProfile(uint32_t samplingRate,
audio_channel_mask_t channelMask,
audio_format_t format) const
{
if (empty()) {
return NO_ERROR;
}
for (const auto& profile : *this) {
if (profile->checkExact(samplingRate, channelMask, format) == NO_ERROR) {
return NO_ERROR;
}
}
return BAD_VALUE;
}
status_t AudioProfileVector::checkCompatibleProfile(uint32_t &samplingRate,
audio_channel_mask_t &channelMask,
audio_format_t &format,
audio_port_type_t portType,
audio_port_role_t portRole) const
{
if (empty()) {
return NO_ERROR;
}
const bool checkInexact = // when port is input and format is linear pcm
portType == AUDIO_PORT_TYPE_MIX && portRole == AUDIO_PORT_ROLE_SINK
&& audio_is_linear_pcm(format);
// iterate from best format to worst format (reverse order)
for (ssize_t i = size() - 1; i >= 0 ; --i) {
const sp<AudioProfile> profile = at(i);
audio_format_t formatToCompare = profile->getFormat();
if (formatToCompare == format ||
(checkInexact
&& formatToCompare != AUDIO_FORMAT_DEFAULT
&& audio_is_linear_pcm(formatToCompare))) {
// Compatible profile has been found, checks if this profile has compatible
// rate and channels as well
audio_channel_mask_t updatedChannels;
uint32_t updatedRate;
if (profile->checkCompatibleChannelMask(channelMask, updatedChannels,
portType, portRole) == NO_ERROR &&
profile->checkCompatibleSamplingRate(samplingRate, updatedRate) == NO_ERROR) {
// for inexact checks we take the first linear pcm format due to sorting.
format = formatToCompare;
channelMask = updatedChannels;
samplingRate = updatedRate;
return NO_ERROR;
}
}
}
return BAD_VALUE;
}
void AudioProfileVector::clearProfiles()
void AudioProfileVectorBase::clearProfiles()
{
for (auto it = begin(); it != end();) {
if ((*it)->isDynamicFormat() && (*it)->hasValidFormat()) {
@ -379,77 +137,7 @@ void AudioProfileVector::clearProfiles()
}
}
// Returns an intersection between two possibly unsorted vectors and the contents of 'order'.
// The result is ordered according to 'order'.
template<typename T, typename Order>
std::vector<typename T::value_type> intersectFilterAndOrder(
const T& input1, const T& input2, const Order& order)
{
std::set<typename T::value_type> set1{input1.begin(), input1.end()};
std::set<typename T::value_type> set2{input2.begin(), input2.end()};
std::set<typename T::value_type> common;
std::set_intersection(set1.begin(), set1.end(), set2.begin(), set2.end(),
std::inserter(common, common.begin()));
std::vector<typename T::value_type> result;
for (const auto& e : order) {
if (common.find(e) != common.end()) result.push_back(e);
}
return result;
}
// Intersect two possibly unsorted vectors, return common elements according to 'comp' ordering.
// 'comp' is a comparator function.
template<typename T, typename Compare>
std::vector<typename T::value_type> intersectAndOrder(
const T& input1, const T& input2, Compare comp)
{
std::set<typename T::value_type, Compare> set1{input1.begin(), input1.end(), comp};
std::set<typename T::value_type, Compare> set2{input2.begin(), input2.end(), comp};
std::vector<typename T::value_type> result;
std::set_intersection(set1.begin(), set1.end(), set2.begin(), set2.end(),
std::back_inserter(result), comp);
return result;
}
status_t AudioProfileVector::findBestMatchingOutputConfig(const AudioProfileVector& outputProfiles,
const std::vector<audio_format_t>& preferredFormats,
const std::vector<audio_channel_mask_t>& preferredOutputChannels,
bool preferHigherSamplingRates,
audio_config_base *bestOutputConfig) const
{
auto formats = intersectFilterAndOrder(getSupportedFormats(),
outputProfiles.getSupportedFormats(), preferredFormats);
// Pick the best compatible profile.
for (const auto& f : formats) {
sp<AudioProfile> inputProfile = getFirstValidProfileFor(f);
sp<AudioProfile> outputProfile = outputProfiles.getFirstValidProfileFor(f);
if (inputProfile == nullptr || outputProfile == nullptr) {
continue;
}
auto channels = intersectFilterAndOrder(asOutMask(inputProfile->getChannels()),
outputProfile->getChannels(), preferredOutputChannels);
if (channels.empty()) {
continue;
}
auto sampleRates = preferHigherSamplingRates ?
intersectAndOrder(inputProfile->getSampleRates(), outputProfile->getSampleRates(),
std::greater<typename SampleRateSet::value_type>()) :
intersectAndOrder(inputProfile->getSampleRates(), outputProfile->getSampleRates(),
std::less<typename SampleRateSet::value_type>());
if (sampleRates.empty()) {
continue;
}
ALOGD("%s() found channel mask %#x and sample rate %d for format %#x.",
__func__, *channels.begin(), *sampleRates.begin(), f);
bestOutputConfig->format = f;
bestOutputConfig->sample_rate = *sampleRates.begin();
bestOutputConfig->channel_mask = *channels.begin();
return NO_ERROR;
}
return BAD_VALUE;
}
sp<AudioProfile> AudioProfileVector::getFirstValidProfile() const
sp<AudioProfile> AudioProfileVectorBase::getFirstValidProfile() const
{
for (const auto &profile : *this) {
if (profile->isValid()) {
@ -459,7 +147,7 @@ sp<AudioProfile> AudioProfileVector::getFirstValidProfile() const
return nullptr;
}
sp<AudioProfile> AudioProfileVector::getFirstValidProfileFor(audio_format_t format) const
sp<AudioProfile> AudioProfileVectorBase::getFirstValidProfileFor(audio_format_t format) const
{
for (const auto &profile : *this) {
if (profile->isValid() && profile->getFormat() == format) {
@ -469,7 +157,7 @@ sp<AudioProfile> AudioProfileVector::getFirstValidProfileFor(audio_format_t form
return nullptr;
}
FormatVector AudioProfileVector::getSupportedFormats() const
FormatVector AudioProfileVectorBase::getSupportedFormats() const
{
FormatVector supportedFormats;
for (const auto &profile : *this) {
@ -480,7 +168,7 @@ FormatVector AudioProfileVector::getSupportedFormats() const
return supportedFormats;
}
bool AudioProfileVector::hasDynamicChannelsFor(audio_format_t format) const
bool AudioProfileVectorBase::hasDynamicChannelsFor(audio_format_t format) const
{
for (const auto &profile : *this) {
if (profile->getFormat() == format && profile->isDynamicChannels()) {
@ -490,97 +178,44 @@ bool AudioProfileVector::hasDynamicChannelsFor(audio_format_t format) const
return false;
}
bool AudioProfileVector::hasDynamicProfile() const
bool AudioProfileVectorBase::hasDynamicFormat() const
{
for (const auto &profile : *this) {
if (profile->isDynamic()) {
if (profile->isDynamicFormat()) {
return true;
}
}
return false;
}
bool AudioProfileVector::hasDynamicRateFor(audio_format_t format) const
bool AudioProfileVectorBase::hasDynamicProfile() const
{
for (const auto &profile : *this) {
if (profile->getFormat() == format && profile->isDynamicRate()) {
if (profile->isDynamic()) {
return true;
}
}
return false;
}
void AudioProfileVector::setFormats(const FormatVector &formats)
{
// Only allow to change the format of dynamic profile
sp<AudioProfile> dynamicFormatProfile = getProfileFor(gDynamicFormat);
if (dynamicFormatProfile == 0) {
return;
}
for (const auto &format : formats) {
sp<AudioProfile> profile = new AudioProfile(format,
dynamicFormatProfile->getChannels(),
dynamicFormatProfile->getSampleRates());
profile->setDynamicFormat(true);
profile->setDynamicChannels(dynamicFormatProfile->isDynamicChannels());
profile->setDynamicRate(dynamicFormatProfile->isDynamicRate());
add(profile);
}
}
void AudioProfileVector::dump(String8 *dst, int spaces) const
{
dst->appendFormat("%*s- Profiles:\n", spaces, "");
for (size_t i = 0; i < size(); i++) {
dst->appendFormat("%*sProfile %zu:", spaces + 4, "", i);
at(i)->dump(dst, spaces + 8);
}
}
sp<AudioProfile> AudioProfileVector::getProfileFor(audio_format_t format) const
{
for (const auto &profile : *this) {
if (profile->getFormat() == format) {
return profile;
}
}
return nullptr;
}
void AudioProfileVector::setSampleRatesFor(
const SampleRateSet &sampleRates, audio_format_t format)
bool AudioProfileVectorBase::hasDynamicRateFor(audio_format_t format) const
{
for (const auto &profile : *this) {
if (profile->getFormat() == format && profile->isDynamicRate()) {
if (profile->hasValidRates()) {
// Need to create a new profile with same format
sp<AudioProfile> profileToAdd = new AudioProfile(format, profile->getChannels(),
sampleRates);
profileToAdd->setDynamicFormat(true); // need to set to allow cleaning
add(profileToAdd);
} else {
profile->setSampleRates(sampleRates);
}
return;
return true;
}
}
return false;
}
void AudioProfileVector::setChannelsFor(const ChannelMaskSet &channelMasks, audio_format_t format)
void AudioProfileVectorBase::dump(std::string *dst, int spaces) const
{
for (const auto &profile : *this) {
if (profile->getFormat() == format && profile->isDynamicChannels()) {
if (profile->hasValidChannels()) {
// Need to create a new profile with same format
sp<AudioProfile> profileToAdd = new AudioProfile(format, channelMasks,
profile->getSampleRates());
profileToAdd->setDynamicFormat(true); // need to set to allow cleaning
add(profileToAdd);
} else {
profile->setChannels(channelMasks);
}
return;
}
dst->append(base::StringPrintf("%*s- Profiles:\n", spaces, ""));
for (size_t i = 0; i < size(); i++) {
dst->append(base::StringPrintf("%*sProfile %zu:", spaces + 4, "", i));
std::string profileStr;
at(i)->dump(&profileStr, spaces + 8);
dst->append(profileStr);
}
}

@ -13,22 +13,22 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#if 0
#pragma once
#include <string>
#include <vector>
#include <media/AudioContainers.h>
#include <system/audio.h>
#include <utils/RefBase.h>
#include <utils/String8.h>
#include "policy.h"
namespace android {
class AudioProfile : public virtual RefBase
class AudioProfile final : public RefBase
{
public:
static sp<AudioProfile> createFullDynamic();
static sp<AudioProfile> createFullDynamic(audio_format_t dynamicFormat = AUDIO_FORMAT_DEFAULT);
AudioProfile(audio_format_t format, audio_channel_mask_t channelMasks, uint32_t samplingRate);
AudioProfile(audio_format_t format,
@ -49,14 +49,6 @@ public:
}
bool supportsRate(uint32_t rate) const { return mSamplingRates.count(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.empty(); }
bool hasValidChannels() const { return !mChannelMasks.empty(); }
@ -72,11 +64,11 @@ public:
bool isDynamic() { return mIsDynamicFormat || mIsDynamicChannels || mIsDynamicRate; }
void dump(String8 *dst, int spaces) const;
void dump(std::string *dst, int spaces) const;
private:
String8 mName;
audio_format_t mFormat;
std::string mName;
audio_format_t mFormat; // The format for an audio profile should only be set when initialized.
ChannelMaskSet mChannelMasks;
SampleRateSet mSamplingRates;
@ -85,35 +77,16 @@ private:
bool mIsDynamicRate = false;
};
class AudioProfileVector : public std::vector<sp<AudioProfile> >
class AudioProfileVectorBase : public std::vector<sp<AudioProfile> >
{
public:
ssize_t add(const sp<AudioProfile> &profile);
// 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<AudioProfile> &profileToAdd);
void appendProfiles(const AudioProfileVector& audioProfiles) {
insert(end(), audioProfiles.begin(), audioProfiles.end());
}
virtual ~AudioProfileVectorBase() = default;
virtual ssize_t add(const sp<AudioProfile> &profile);
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;
void clearProfiles();
// Assuming that this profile vector contains input profiles,
// find the best matching config from 'outputProfiles', according to
// the given preferences for audio formats and channel masks.
// Note: std::vectors are used because specialized containers for formats
// and channels can be sorted and use their own ordering.
status_t findBestMatchingOutputConfig(const AudioProfileVector& outputProfiles,
const std::vector<audio_format_t>& preferredFormats, // order: most pref -> least pref
const std::vector<audio_channel_mask_t>& preferredOutputChannels,
bool preferHigherSamplingRates,
audio_config_base *bestOutputConfig) const;
// If the profile is dynamic format and has valid format, it will be removed when doing
// clearProfiles(). Otherwise, AudioProfile::clear() will be called.
virtual void clearProfiles();
sp<AudioProfile> getFirstValidProfile() const;
sp<AudioProfile> getFirstValidProfileFor(audio_format_t format) const;
@ -121,22 +94,13 @@ public:
FormatVector getSupportedFormats() const;
bool hasDynamicChannelsFor(audio_format_t format) const;
bool hasDynamicFormat() const { return getProfileFor(gDynamicFormat) != 0; }
bool hasDynamicFormat() const;
bool hasDynamicProfile() const;
bool hasDynamicRateFor(audio_format_t format) const;
// One audio profile will be added for each format supported by Audio HAL
void setFormats(const FormatVector &formats);
void dump(String8 *dst, int spaces) const;
private:
sp<AudioProfile> getProfileFor(audio_format_t format) const;
void setSampleRatesFor(const SampleRateSet &sampleRates, audio_format_t format);
void setChannelsFor(const ChannelMaskSet &channelMasks, audio_format_t format);
virtual void dump(std::string *dst, int spaces) const;
};
bool operator == (const AudioProfile &left, const AudioProfile &right);
} // namespace android
#endif

@ -29,6 +29,7 @@
#include <AudioPolicyMix.h>
#include <EffectDescriptor.h>
#include <SoundTriggerSession.h>
#include <media/AudioProfile.h>
namespace android {
@ -118,9 +119,9 @@ public:
mSource = "AudioPolicyConfig::setDefault";
mEngineLibraryNameSuffix = kDefaultEngineLibraryNameSuffix;
mDefaultOutputDevice = new DeviceDescriptor(AUDIO_DEVICE_OUT_SPEAKER);
mDefaultOutputDevice->addAudioProfile(AudioProfile::createFullDynamic());
mDefaultOutputDevice->addAudioProfile(AudioProfile::createFullDynamic(gDynamicFormat));
sp<DeviceDescriptor> defaultInputDevice = new DeviceDescriptor(AUDIO_DEVICE_IN_BUILTIN_MIC);
defaultInputDevice->addAudioProfile(AudioProfile::createFullDynamic());
defaultInputDevice->addAudioProfile(AudioProfile::createFullDynamic(gDynamicFormat));
sp<AudioProfile> micProfile = new AudioProfile(
AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_MONO, 8000);
defaultInputDevice->addAudioProfile(micProfile);

@ -16,126 +16,53 @@
#pragma once
#include <media/AudioContainers.h>
#include <media/AudioProfile.h>
#include <system/audio.h>
#include <utils/RefBase.h>
#include <utils/String8.h>
#include "policy.h"
namespace android {
class AudioProfile : public virtual RefBase
{
class AudioProfileVector : public AudioProfileVectorBase {
public:
static sp<AudioProfile> createFullDynamic();
AudioProfile(audio_format_t format, audio_channel_mask_t channelMasks, uint32_t samplingRate);
AudioProfile(audio_format_t format,
const ChannelMaskSet &channelMasks,
const SampleRateSet &samplingRateCollection);
audio_format_t getFormat() const { return mFormat; }
const ChannelMaskSet &getChannels() const { return mChannelMasks; }
const SampleRateSet &getSampleRates() const { return mSamplingRates; }
void setChannels(const ChannelMaskSet &channelMasks);
void setSampleRates(const SampleRateSet &sampleRates);
void clear();
bool isValid() const { return hasValidFormat() && hasValidRates() && hasValidChannels(); }
bool supportsChannels(audio_channel_mask_t channels) const
{
return mChannelMasks.count(channels) != 0;
}
bool supportsRate(uint32_t rate) const { return mSamplingRates.count(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;
virtual ~AudioProfileVector() = default;
bool hasValidFormat() const { return mFormat != AUDIO_FORMAT_DEFAULT; }
bool hasValidRates() const { return !mSamplingRates.empty(); }
bool hasValidChannels() const { return !mChannelMasks.empty(); }
ssize_t add(const sp<AudioProfile> &profile) override;
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(String8 *dst, int spaces) const;
private:
String8 mName;
audio_format_t mFormat;
ChannelMaskSet mChannelMasks;
SampleRateSet mSamplingRates;
bool mIsDynamicFormat = false;
bool mIsDynamicChannels = false;
bool mIsDynamicRate = false;
};
class AudioProfileVector : public std::vector<sp<AudioProfile> >
{
public:
ssize_t add(const sp<AudioProfile> &profile);
// 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<AudioProfile> &profileToAdd);
void appendProfiles(const AudioProfileVector& audioProfiles) {
void appendProfiles(const AudioProfileVectorBase& audioProfiles) {
insert(end(), audioProfiles.begin(), audioProfiles.end());
}
status_t checkExactProfile(uint32_t samplingRate, audio_channel_mask_t channelMask,
status_t checkExactProfile(const uint32_t samplingRate,
audio_channel_mask_t channelMask,
audio_format_t format) const;
status_t checkCompatibleProfile(uint32_t &samplingRate, audio_channel_mask_t &channelMask,
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;
void clearProfiles();
// Assuming that this profile vector contains input profiles,
// find the best matching config from 'outputProfiles', according to
// the given preferences for audio formats and channel masks.
// Note: std::vectors are used because specialized containers for formats
// and channels can be sorted and use their own ordering.
status_t findBestMatchingOutputConfig(const AudioProfileVector& outputProfiles,
const std::vector<audio_format_t>& preferredFormats, // order: most pref -> least pref
const std::vector<audio_channel_mask_t>& preferredOutputChannels,
status_t findBestMatchingOutputConfig(
const AudioProfileVector &outputProfiles,
const std::vector<audio_format_t> &preferredFormats, // order: most pref -> least pref
const std::vector<audio_channel_mask_t> &preferredOutputChannels,
bool preferHigherSamplingRates,
audio_config_base *bestOutputConfig) const;
sp<AudioProfile> getFirstValidProfile() const;
sp<AudioProfile> getFirstValidProfileFor(audio_format_t format) const;
bool hasValidProfile() const { return getFirstValidProfile() != 0; }
FormatVector getSupportedFormats() const;
bool hasDynamicChannelsFor(audio_format_t format) const;
bool hasDynamicFormat() const { return getProfileFor(gDynamicFormat) != 0; }
bool hasDynamicProfile() const;
bool hasDynamicRateFor(audio_format_t format) const;
// One audio profile will be added for each format supported by Audio HAL
void setFormats(const FormatVector &formats);
void dump(String8 *dst, int spaces) const;
private:
sp<AudioProfile> getProfileFor(audio_format_t format) const;
void setSampleRatesFor(const SampleRateSet &sampleRates, audio_format_t format);
void setChannelsFor(const ChannelMaskSet &channelMasks, audio_format_t format);
};
bool operator == (const AudioProfile &left, const AudioProfile &right);
} // namespace android
} // namespace android

@ -18,6 +18,7 @@
#include "AudioPort.h"
#include "DeviceDescriptor.h"
#include "policy.h"
#include <utils/String8.h>
#include <system/audio.h>

@ -342,7 +342,9 @@ void AudioPort::dump(String8 *dst, int spaces, bool verbose) const
dst->appendFormat("%*s- name: %s\n", spaces, "", mName.string());
}
if (verbose) {
mProfiles.dump(dst, spaces);
std::string profilesStr;
mProfiles.dump(&profilesStr, spaces);
dst->append(profilesStr.c_str());
if (mGains.size() != 0) {
dst->appendFormat("%*s- gains:\n", spaces, "");

@ -28,93 +28,29 @@
#include "AudioPort.h"
#include "AudioProfileVector.h"
#include "HwModule.h"
#include "TypeConverter.h"
#include "policy.h"
namespace android {
bool operator == (const AudioProfile &left, const AudioProfile &compareTo)
status_t checkExact(const sp<AudioProfile> &audioProfile, uint32_t samplingRate,
audio_channel_mask_t channelMask, audio_format_t format)
{
return (left.getFormat() == compareTo.getFormat()) &&
(left.getChannels() == compareTo.getChannels()) &&
(left.getSampleRates() == compareTo.getSampleRates());
}
static AudioProfile* createFullDynamicImpl()
{
AudioProfile* dynamicProfile = new AudioProfile(gDynamicFormat,
ChannelMaskSet(), SampleRateSet());
dynamicProfile->setDynamicFormat(true);
dynamicProfile->setDynamicChannels(true);
dynamicProfile->setDynamicRate(true);
return dynamicProfile;
}
// static
sp<AudioProfile> AudioProfile::createFullDynamic()
{
static sp<AudioProfile> dynamicProfile = createFullDynamicImpl();
return dynamicProfile;
}
AudioProfile::AudioProfile(audio_format_t format,
audio_channel_mask_t channelMasks,
uint32_t samplingRate) :
mName(String8("")),
mFormat(format)
{
mChannelMasks.insert(channelMasks);
mSamplingRates.insert(samplingRate);
}
AudioProfile::AudioProfile(audio_format_t format,
const ChannelMaskSet &channelMasks,
const SampleRateSet &samplingRateCollection) :
mName(String8("")),
mFormat(format),
mChannelMasks(channelMasks),
mSamplingRates(samplingRateCollection) {}
void AudioProfile::setChannels(const ChannelMaskSet &channelMasks)
{
if (mIsDynamicChannels) {
mChannelMasks = channelMasks;
}
}
void AudioProfile::setSampleRates(const SampleRateSet &sampleRates)
{
if (mIsDynamicRate) {
mSamplingRates = sampleRates;
}
}
void AudioProfile::clear()
{
if (mIsDynamicChannels) {
mChannelMasks.clear();
}
if (mIsDynamicRate) {
mSamplingRates.clear();
}
}
status_t AudioProfile::checkExact(uint32_t samplingRate, audio_channel_mask_t channelMask,
audio_format_t format) const
{
if (audio_formats_match(format, mFormat) &&
supportsChannels(channelMask) &&
supportsRate(samplingRate)) {
if (audio_formats_match(format, audioProfile->getFormat()) &&
audioProfile->supportsChannels(channelMask) &&
audioProfile->supportsRate(samplingRate)) {
return NO_ERROR;
}
return BAD_VALUE;
}
status_t AudioProfile::checkCompatibleSamplingRate(uint32_t samplingRate,
uint32_t &updatedSamplingRate) const
status_t checkCompatibleSamplingRate(const sp<AudioProfile> &audioProfile,
uint32_t samplingRate,
uint32_t &updatedSamplingRate)
{
ALOG_ASSERT(samplingRate > 0);
if (mSamplingRates.empty()) {
const SampleRateSet sampleRates = audioProfile->getSampleRates();
if (sampleRates.empty()) {
updatedSamplingRate = samplingRate;
return NO_ERROR;
}
@ -122,17 +58,17 @@ status_t AudioProfile::checkCompatibleSamplingRate(uint32_t samplingRate,
// Search for the closest supported sampling rate that is above (preferred)
// or below (acceptable) the desired sampling rate, within a permitted ratio.
// The sampling rates are sorted in ascending order.
auto desiredRate = mSamplingRates.lower_bound(samplingRate);
auto desiredRate = sampleRates.lower_bound(samplingRate);
// Prefer to down-sample from a higher sampling rate, as we get the desired frequency spectrum.
if (desiredRate != mSamplingRates.end()) {
if (desiredRate != sampleRates.end()) {
if (*desiredRate / AUDIO_RESAMPLER_DOWN_RATIO_MAX <= samplingRate) {
updatedSamplingRate = *desiredRate;
return NO_ERROR;
}
}
// But if we have to up-sample from a lower sampling rate, that's OK.
if (desiredRate != mSamplingRates.begin()) {
if (desiredRate != sampleRates.begin()) {
uint32_t candidate = *(--desiredRate);
if (candidate * AUDIO_RESAMPLER_UP_RATIO_MAX >= samplingRate) {
updatedSamplingRate = candidate;
@ -143,12 +79,14 @@ status_t AudioProfile::checkCompatibleSamplingRate(uint32_t samplingRate,
return BAD_VALUE;
}
status_t AudioProfile::checkCompatibleChannelMask(audio_channel_mask_t channelMask,
audio_channel_mask_t &updatedChannelMask,
audio_port_type_t portType,
audio_port_role_t portRole) const
status_t checkCompatibleChannelMask(const sp<AudioProfile> &audioProfile,
audio_channel_mask_t channelMask,
audio_channel_mask_t &updatedChannelMask,
audio_port_type_t portType,
audio_port_role_t portRole)
{
if (mChannelMasks.empty()) {
const ChannelMaskSet channelMasks = audioProfile->getChannels();
if (channelMasks.empty()) {
updatedChannelMask = channelMask;
return NO_ERROR;
}
@ -157,7 +95,7 @@ status_t AudioProfile::checkCompatibleChannelMask(audio_channel_mask_t channelMa
== AUDIO_CHANNEL_REPRESENTATION_INDEX;
const uint32_t channelCount = audio_channel_count_from_in_mask(channelMask);
int bestMatch = 0;
for (const auto &supported : mChannelMasks) {
for (const auto &supported : channelMasks) {
if (supported == channelMask) {
// Exact matches always taken.
updatedChannelMask = channelMask;
@ -235,37 +173,6 @@ status_t AudioProfile::checkCompatibleChannelMask(audio_channel_mask_t channelMa
return bestMatch > 0 ? NO_ERROR : BAD_VALUE;
}
void AudioProfile::dump(String8 *dst, int spaces) const
{
dst->appendFormat("%s%s%s\n", mIsDynamicFormat ? "[dynamic format]" : "",
mIsDynamicChannels ? "[dynamic channels]" : "",
mIsDynamicRate ? "[dynamic rates]" : "");
if (mName.length() != 0) {
dst->appendFormat("%*s- name: %s\n", spaces, "", mName.string());
}
std::string formatLiteral;
if (FormatConverter::toString(mFormat, formatLiteral)) {
dst->appendFormat("%*s- format: %s\n", spaces, "", formatLiteral.c_str());
}
if (!mSamplingRates.empty()) {
dst->appendFormat("%*s- sampling rates:", spaces, "");
for (auto it = mSamplingRates.begin(); it != mSamplingRates.end();) {
dst->appendFormat("%d", *it);
dst->append(++it == mSamplingRates.end() ? "" : ", ");
}
dst->append("\n");
}
if (!mChannelMasks.empty()) {
dst->appendFormat("%*s- channel masks:", spaces, "");
for (auto it = mChannelMasks.begin(); it != mChannelMasks.end();) {
dst->appendFormat("0x%04x", *it);
dst->append(++it == mChannelMasks.end() ? "" : ", ");
}
dst->append("\n");
}
}
ssize_t AudioProfileVector::add(const sp<AudioProfile> &profile)
{
ssize_t index = size();
@ -311,7 +218,7 @@ ssize_t AudioProfileVector::addProfileFromHal(const sp<AudioProfile> &profileToA
return add(profileToAdd);
}
status_t AudioProfileVector::checkExactProfile(uint32_t samplingRate,
status_t AudioProfileVector::checkExactProfile(const uint32_t samplingRate,
audio_channel_mask_t channelMask,
audio_format_t format) const
{
@ -320,7 +227,7 @@ status_t AudioProfileVector::checkExactProfile(uint32_t samplingRate,
}
for (const auto& profile : *this) {
if (profile->checkExact(samplingRate, channelMask, format) == NO_ERROR) {
if (checkExact(profile, samplingRate, channelMask, format) == NO_ERROR) {
return NO_ERROR;
}
}
@ -353,9 +260,9 @@ status_t AudioProfileVector::checkCompatibleProfile(uint32_t &samplingRate,
// rate and channels as well
audio_channel_mask_t updatedChannels;
uint32_t updatedRate;
if (profile->checkCompatibleChannelMask(channelMask, updatedChannels,
portType, portRole) == NO_ERROR &&
profile->checkCompatibleSamplingRate(samplingRate, updatedRate) == NO_ERROR) {
if (checkCompatibleChannelMask(profile, channelMask, updatedChannels,
portType, portRole) == NO_ERROR &&
checkCompatibleSamplingRate(profile, samplingRate, updatedRate) == NO_ERROR) {
// for inexact checks we take the first linear pcm format due to sorting.
format = formatToCompare;
channelMask = updatedChannels;
@ -367,18 +274,6 @@ status_t AudioProfileVector::checkCompatibleProfile(uint32_t &samplingRate,
return BAD_VALUE;
}
void AudioProfileVector::clearProfiles()
{
for (auto it = begin(); it != end();) {
if ((*it)->isDynamicFormat() && (*it)->hasValidFormat()) {
it = erase(it);
} else {
(*it)->clear();
++it;
}
}
}
// Returns an intersection between two possibly unsorted vectors and the contents of 'order'.
// The result is ordered according to 'order'.
template<typename T, typename Order>
@ -449,67 +344,6 @@ status_t AudioProfileVector::findBestMatchingOutputConfig(const AudioProfileVect
return BAD_VALUE;
}
sp<AudioProfile> AudioProfileVector::getFirstValidProfile() const
{
for (const auto &profile : *this) {
if (profile->isValid()) {
return profile;
}
}
return nullptr;
}
sp<AudioProfile> AudioProfileVector::getFirstValidProfileFor(audio_format_t format) const
{
for (const auto &profile : *this) {
if (profile->isValid() && profile->getFormat() == format) {
return profile;
}
}
return nullptr;
}
FormatVector AudioProfileVector::getSupportedFormats() const
{
FormatVector supportedFormats;
for (const auto &profile : *this) {
if (profile->hasValidFormat()) {
supportedFormats.push_back(profile->getFormat());
}
}
return supportedFormats;
}
bool AudioProfileVector::hasDynamicChannelsFor(audio_format_t format) const
{
for (const auto &profile : *this) {
if (profile->getFormat() == format && profile->isDynamicChannels()) {
return true;
}
}
return false;
}
bool AudioProfileVector::hasDynamicProfile() const
{
for (const auto &profile : *this) {
if (profile->isDynamic()) {
return true;
}
}
return false;
}
bool AudioProfileVector::hasDynamicRateFor(audio_format_t format) const
{
for (const auto &profile : *this) {
if (profile->getFormat() == format && profile->isDynamicRate()) {
return true;
}
}
return false;
}
void AudioProfileVector::setFormats(const FormatVector &formats)
{
// Only allow to change the format of dynamic profile
@ -528,15 +362,6 @@ void AudioProfileVector::setFormats(const FormatVector &formats)
}
}
void AudioProfileVector::dump(String8 *dst, int spaces) const
{
dst->appendFormat("%*s- Profiles:\n", spaces, "");
for (size_t i = 0; i < size(); i++) {
dst->appendFormat("%*sProfile %zu:", spaces + 4, "", i);
at(i)->dump(dst, spaces + 8);
}
}
sp<AudioProfile> AudioProfileVector::getProfileFor(audio_format_t format) const
{
for (const auto &profile : *this) {

@ -438,7 +438,7 @@ Return<MixPortTraits::Element> MixPortTraits::deserialize(const xmlNode *child,
return Status::fromStatusT(status);
}
if (profiles.empty()) {
profiles.add(AudioProfile::createFullDynamic());
profiles.add(AudioProfile::createFullDynamic(gDynamicFormat));
}
mixPort->setAudioProfiles(profiles);
@ -522,7 +522,7 @@ Return<DevicePortTraits::Element> DevicePortTraits::deserialize(const xmlNode *c
return Status::fromStatusT(status);
}
if (profiles.empty()) {
profiles.add(AudioProfile::createFullDynamic());
profiles.add(AudioProfile::createFullDynamic(gDynamicFormat));
}
deviceDesc->setAudioProfiles(profiles);

Loading…
Cancel
Save