Preparation for moving AudioProfile to libaudiofoundation.

Copy AudioProfile from audio policy to libaudiofoundation. Note that
AudioProfile in libaudiofoundation has not been added into the make
file as it needs some more change to make it work. Doing this just to
make a cleaner diff for later change.
Rename AudioProfile in managerdefinitions folder as AudioProfileVector
since AudioProfile will be moved to libaudiofoundation.

Bug: 135621476
Test: make
Change-Id: I13ac067317648bbfd8d3960d16a1ea56ded83011
gugelfrei
jiabin 5 years ago
parent 34bbfc447a
commit e46870e935

@ -0,0 +1,142 @@
/*
* 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.
*/
#if 0
#pragma once
#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
{
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;
bool hasValidFormat() const { return mFormat != AUDIO_FORMAT_DEFAULT; }
bool hasValidRates() const { return !mSamplingRates.empty(); }
bool hasValidChannels() const { return !mChannelMasks.empty(); }
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) {
insert(end(), audioProfiles.begin(), audioProfiles.end());
}
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;
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
#endif

@ -8,7 +8,7 @@ cc_library_static {
"src/AudioPatch.cpp",
"src/AudioPolicyMix.cpp",
"src/AudioPort.cpp",
"src/AudioProfile.cpp",
"src/AudioProfileVector.cpp",
"src/AudioRoute.cpp",
"src/ClientDescriptor.cpp",
"src/DeviceDescriptor.cpp",

@ -17,7 +17,7 @@
#pragma once
#include "AudioCollections.h"
#include "AudioProfile.h"
#include "AudioProfileVector.h"
#include "HandleGenerator.h"
#include <media/AudioGain.h>
#include <utils/String8.h>

@ -0,0 +1,587 @@
/*
* 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.
*/
#include <algorithm>
#include <set>
#include <string>
#define LOG_TAG "APM::AudioProfile"
//#define LOG_NDEBUG 0
#include <media/AudioContainers.h>
#include <media/AudioResamplerPublic.h>
#include <utils/Errors.h>
#include "AudioPort.h"
#include "AudioProfileVector.h"
#include "HwModule.h"
#include "TypeConverter.h"
namespace android {
bool operator == (const AudioProfile &left, const AudioProfile &compareTo)
{
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)) {
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
{
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();
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()
{
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>
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
{
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
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)
{
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;
}
}
}
void AudioProfileVector::setChannelsFor(const ChannelMaskSet &channelMasks, audio_format_t format)
{
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;
}
}
}
} // namespace android

@ -38,7 +38,7 @@
#include <AudioPolicyConfig.h>
#include <AudioPort.h>
#include <AudioPatch.h>
#include <AudioProfile.h>
#include <AudioProfileVector.h>
#include <DeviceDescriptor.h>
#include <IOProfile.h>
#include <HwModule.h>

Loading…
Cancel
Save