audio policy: introduction of AudioProfile

In order to be able to declare the possible sample
specifications for an Audio Port (a given format, a list of
sample rates, a list of channels), a new object AudioProfile is
introduced.

Change-Id: Ie3ca3400f05984e7b4132fc7ba90020eb4d998c7
Signed-off-by: François Gaffie <francois.gaffie@intel.com>
diff --git a/services/audiopolicy/common/include/policy.h b/services/audiopolicy/common/include/policy.h
index 1a1cbb2..34984f9 100755
--- a/services/audiopolicy/common/include/policy.h
+++ b/services/audiopolicy/common/include/policy.h
@@ -18,9 +18,7 @@
 
 #include <system/audio.h>
 
-static const uint32_t gDynamicRate = 0;
 static const audio_format_t gDynamicFormat = AUDIO_FORMAT_DEFAULT;
-static const audio_channel_mask_t gDynamicChannelMask = AUDIO_CHANNEL_NONE;
 
 // For mixed output and inputs, the policy will use max mixer sampling rates.
 // Do not limit sampling rate otherwise
diff --git a/services/audiopolicy/common/managerdefinitions/Android.mk b/services/audiopolicy/common/managerdefinitions/Android.mk
index d3df3ef..dffeb7e 100644
--- a/services/audiopolicy/common/managerdefinitions/Android.mk
+++ b/services/audiopolicy/common/managerdefinitions/Android.mk
@@ -9,6 +9,7 @@
     src/HwModule.cpp \
     src/IOProfile.cpp \
     src/AudioPort.cpp \
+    src/AudioProfile.cpp \
     src/AudioPolicyMix.cpp \
     src/AudioPatch.cpp \
     src/AudioInputDescriptor.cpp \
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h
index 5ff0396..20c0e36 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h
@@ -99,9 +99,8 @@
         sp<OutputProfile> outProfile;
         outProfile = new OutputProfile(String8("primary"));
         outProfile->attach(module);
-        outProfile->mSamplingRates.add(44100);
-        outProfile->mFormats.add(AUDIO_FORMAT_PCM_16_BIT);
-        outProfile->mChannelMasks.add(AUDIO_CHANNEL_OUT_STEREO);
+        outProfile->addAudioProfile(
+                new AudioProfile(AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO, 44100));
         outProfile->addSupportedDevice(mDefaultOutputDevices);
         outProfile->setFlags(AUDIO_OUTPUT_FLAG_PRIMARY);
         module->mOutputProfiles.add(outProfile);
@@ -109,9 +108,8 @@
         sp<InputProfile> inProfile;
         inProfile = new InputProfile(String8("primary"));
         inProfile->attach(module);
-        inProfile->mSamplingRates.add(8000);
-        inProfile->mFormats.add(AUDIO_FORMAT_PCM_16_BIT);
-        inProfile->mChannelMasks.add(AUDIO_CHANNEL_IN_MONO);
+        inProfile->addAudioProfile(
+                new AudioProfile(AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_MONO, 8000));
         inProfile->addSupportedDevice(defaultInputDevice);
         module->mInputProfiles.add(inProfile);
 
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPort.h b/services/audiopolicy/common/managerdefinitions/include/AudioPort.h
index 5666920..9aaaddf 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioPort.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioPort.h
@@ -16,6 +16,7 @@
 
 #pragma once
 
+#include "AudioProfile.h"
 #include <utils/String8.h>
 #include <utils/Vector.h>
 #include <utils/RefBase.h>
@@ -57,42 +58,44 @@
     virtual void toAudioPort(struct audio_port *port) const;
 
     virtual void importAudioPort(const sp<AudioPort> port);
-    void clearCapabilities();
+    void clearCapabilities() { mProfiles.clearProfiles(); }
 
-    void setSupportedFormats(const Vector <audio_format_t> &formats);
-    void setSupportedSamplingRates(const Vector <uint32_t> &sampleRates)
-    {
-        mSamplingRates = sampleRates;
-    }
-    void setSupportedChannelMasks(const Vector <audio_channel_mask_t> &channelMasks)
-    {
-        mChannelMasks = channelMasks;
-    }
+    void addAudioProfile(const sp<AudioProfile> &profile) { mProfiles.add(profile); }
+
+    void setAudioProfiles(const AudioProfileVector &profiles) { mProfiles = profiles; }
+    AudioProfileVector &getAudioProfiles() { return mProfiles; }
+
+    bool hasValidAudioProfile() const { return mProfiles.hasValidProfile(); }
+
+    bool hasDynamicAudioProfile() const { return mProfiles.hasDynamicProfile(); }
 
     // searches for an exact match
-    status_t checkExactSamplingRate(uint32_t samplingRate) const;
-    // searches for a compatible match, and returns the best match via updatedSamplingRate
-    status_t checkCompatibleSamplingRate(uint32_t samplingRate,
-            uint32_t *updatedSamplingRate) const;
-    // searches for an exact match
-    status_t checkExactChannelMask(audio_channel_mask_t channelMask) const;
-    // searches for a compatible match, currently implemented for input channel masks only
-    status_t checkCompatibleChannelMask(audio_channel_mask_t channelMask,
-            audio_channel_mask_t *updatedChannelMask) const;
+    status_t checkExactAudioProfile(uint32_t samplingRate,
+                                    audio_channel_mask_t channelMask,
+                                    audio_format_t format) const
+    {
+        return mProfiles.checkExactProfile(samplingRate, channelMask, format);
+    }
 
-    status_t checkExactFormat(audio_format_t format) const;
-    // searches for a compatible match, currently implemented for input formats only
-    status_t checkCompatibleFormat(audio_format_t format, audio_format_t *updatedFormat) const;
+    // searches for a compatible match, currently implemented for input
+    // parameters are input|output, returned value is the best match.
+    status_t checkCompatibleAudioProfile(uint32_t &samplingRate,
+                                         audio_channel_mask_t &channelMask,
+                                         audio_format_t &format) const
+    {
+        return mProfiles.checkCompatibleProfile(samplingRate, channelMask, format, mType, mRole);
+    }
+
+    void clearAudioProfiles() { return mProfiles.clearProfiles(); }
+
     status_t checkGain(const struct audio_gain_config *gainConfig, int index) const;
 
-    uint32_t pickSamplingRate() const;
-    audio_channel_mask_t pickChannelMask() const;
-    audio_format_t pickFormat() const;
+    void pickAudioProfile(uint32_t &samplingRate,
+                          audio_channel_mask_t &channelMask,
+                          audio_format_t &format) const;
 
     static const audio_format_t sPcmFormatCompareTable[];
-    static int compareFormats(const audio_format_t *format1, const audio_format_t *format2) {
-        return compareFormats(*format1, *format2);
-    }
+
     static int compareFormats(audio_format_t format1, audio_format_t format2);
 
     audio_module_handle_t getModuleHandle() const;
@@ -105,23 +108,27 @@
                 ((mType == AUDIO_PORT_TYPE_MIX) && (mRole == AUDIO_PORT_ROLE_SINK));
     }
 
-    void dump(int fd, int spaces) const;
+    inline bool isDirectOutput() const
+    {
+        return (mType == AUDIO_PORT_TYPE_MIX) && (mRole == AUDIO_PORT_ROLE_SOURCE) &&
+                (mFlags & (AUDIO_OUTPUT_FLAG_DIRECT | AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD));
+    }
+
+    void dump(int fd, int spaces, bool verbose = true) const;
     void log(const char* indent) const;
 
-    // by convention, "0' in the first entry in mSamplingRates, mChannelMasks or mFormats
-    // indicates the supported parameters should be read from the output stream
-    // after it is opened for the first time
-    Vector <uint32_t> mSamplingRates; // supported sampling rates
-    Vector <audio_channel_mask_t> mChannelMasks; // supported channel masks
-    Vector <audio_format_t> mFormats; // supported audio formats
     AudioGainCollection mGains; // gain controllers
     sp<HwModule> mModule;                 // audio HW module exposing this I/O stream
 
 private:
+    void pickChannelMask(audio_channel_mask_t &channelMask, const ChannelsVector &channelMasks) const;
+    void pickSamplingRate(uint32_t &rate,const SampleRateVector &samplingRates) const;
+
     String8           mName;
     audio_port_type_t mType;
     audio_port_role_t mRole;
     uint32_t mFlags; // attribute flags mask (e.g primary output, direct output...).
+    AudioProfileVector mProfiles; // AudioProfiles supported by this port (format, Rates, Channels)
     static volatile int32_t mNextUniqueId;
 };
 
@@ -132,9 +139,9 @@
     virtual ~AudioPortConfig() {}
 
     status_t applyAudioPortConfig(const struct audio_port_config *config,
-            struct audio_port_config *backupConfig = NULL);
+                                  struct audio_port_config *backupConfig = NULL);
     virtual void toAudioPortConfig(struct audio_port_config *dstConfig,
-            const struct audio_port_config *srcConfig = NULL) const = 0;
+                                   const struct audio_port_config *srcConfig = NULL) const = 0;
     virtual sp<AudioPort> getAudioPort() const = 0;
     uint32_t mSamplingRate;
     audio_format_t mFormat;
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioProfile.h b/services/audiopolicy/common/managerdefinitions/include/AudioProfile.h
new file mode 100644
index 0000000..9780dc6
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioProfile.h
@@ -0,0 +1,353 @@
+/*
+ * 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 <utils/String8.h>
+#include <utils/SortedVector.h>
+#include <utils/RefBase.h>
+#include <utils/Errors.h>
+#include <system/audio.h>
+#include <cutils/config_utils.h>
+
+namespace android {
+
+typedef SortedVector<uint32_t> SampleRateVector;
+typedef SortedVector<audio_channel_mask_t> ChannelsVector;
+typedef Vector<audio_format_t> FormatVector;
+
+template <typename T>
+bool operator == (const SortedVector<T> &left, const SortedVector<T> &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<sp<AudioProfile> >
+{
+public:
+    ssize_t add(const sp<AudioProfile> &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<AudioProfile> &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<AudioProfile> &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<AudioProfile> 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<AudioProfile> 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<AudioProfile> 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<AudioProfile> dynamicFormatProfile = getProfileFor(gDynamicFormat);
+        if (dynamicFormatProfile == 0) {
+            return;
+        }
+        clearProfiles();
+        for (size_t i = 0; i < formats.size(); i++) {
+            sp<AudioProfile> profile = new AudioProfile(formats[i],
+                                                        dynamicFormatProfile->getChannels(),
+                                                        dynamicFormatProfile->getSampleRates());
+            profile->setDynamicFormat(true);
+            profile->setDynamicChannels(dynamicFormatProfile->isDynamicChannels());
+            profile->setDynamicRate(dynamicFormatProfile->isDynamicRate());
+            add(profile);
+        }
+    }
+
+    void setSampleRatesFor(const SampleRateVector &sampleRates, audio_format_t format)
+    {
+        for (size_t i = 0; i < size(); i++) {
+            sp<AudioProfile> profile = itemAt(i);
+            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 setChannelsFor(const ChannelsVector &channelMasks, audio_format_t format)
+    {
+        for (size_t i = 0; i < size(); i++) {
+            sp<AudioProfile> profile = itemAt(i);
+            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;
+            }
+        }
+    }
+
+    void clearProfiles()
+    {
+        for (size_t i = size(); i != 0; ) {
+            sp<AudioProfile> 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:
+    sp<AudioProfile> 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<AudioProfile> *profile1, const sp<AudioProfile> *profile2);
+};
+
+bool operator == (const AudioProfile &left, const AudioProfile &right);
+
+}; // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/ConfigParsingUtils.h b/services/audiopolicy/common/managerdefinitions/include/ConfigParsingUtils.h
index 1eddab9..ab23105 100644
--- a/services/audiopolicy/common/managerdefinitions/include/ConfigParsingUtils.h
+++ b/services/audiopolicy/common/managerdefinitions/include/ConfigParsingUtils.h
@@ -45,8 +45,7 @@
     static void loadAudioPortGains(cnode *root, AudioPort &audioPort);
     static void loadDeviceDescriptorGains(cnode *root, sp<DeviceDescriptor> &deviceDesc);
     static status_t loadHwModuleDevice(cnode *root, DeviceVector &devices);
-    static status_t loadHwModuleInput(cnode *root, sp<HwModule> &module);
-    static status_t loadHwModuleOutput(cnode *root, sp<HwModule> &module);
+    static status_t loadHwModuleProfile(cnode *root, sp<HwModule> &module, audio_port_role_t role);
     static void loadDevicesFromTag(const char *tag, DeviceVector &devices,
                             const DeviceVector &declaredDevices);
     static void loadHwModules(cnode *root, HwModuleCollection &hwModules,
diff --git a/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
index 3f43963..8ece51b 100644
--- a/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
@@ -50,7 +50,7 @@
     virtual void importAudioPort(const sp<AudioPort> port);
 
     audio_port_handle_t getId() const;
-    status_t dump(int fd, int spaces, int index) const;
+    status_t dump(int fd, int spaces, int index, bool verbose = true) const;
     void log() const;
 
     String8 mAddress;
@@ -85,7 +85,7 @@
 
     audio_policy_dev_state_t getDeviceConnectionState(const sp<DeviceDescriptor> &devDesc) const;
 
-    status_t dump(int fd, const String8 &direction) const;
+    status_t dump(int fd, const String8 &tag, int spaces = 0, bool verbose = true) const;
 
 private:
     void refreshTypes();
diff --git a/services/audiopolicy/common/managerdefinitions/include/TypeConverter.h b/services/audiopolicy/common/managerdefinitions/include/TypeConverter.h
index 9b96770..14e2ecc 100644
--- a/services/audiopolicy/common/managerdefinitions/include/TypeConverter.h
+++ b/services/audiopolicy/common/managerdefinitions/include/TypeConverter.h
@@ -27,14 +27,10 @@
 
 namespace android {
 
-#define DYNAMIC_VALUE_TAG "dynamic" // special value for "channel_masks", "sampling_rates" and
-                                    // "formats" in outputs descriptors indicating that supported
-                                    // values should be queried after opening the output.
-
 struct SampleRateTraits
 {
     typedef uint32_t Type;
-    typedef Vector<Type> Collection;
+    typedef SortedVector<Type> Collection;
 };
 struct DeviceTraits
 {
@@ -59,7 +55,7 @@
 struct ChannelTraits
 {
     typedef audio_channel_mask_t Type;
-    typedef Vector<Type> Collection;
+    typedef SortedVector<Type> Collection;
 };
 struct OutputChannelTraits : public ChannelTraits {};
 struct InputChannelTraits : public ChannelTraits {};
@@ -139,50 +135,27 @@
                                                             const char *del = "|")
 {
     SampleRateTraits::Collection samplingRateCollection;
-    // by convention, "0' in the first entry in mSamplingRates indicates the supported sampling
-    // rates should be read from the output stream after it is opened for the first time
-    if (samplingRates == DYNAMIC_VALUE_TAG) {
-        samplingRateCollection.add(gDynamicRate);
-    } else {
-        collectionFromString<SampleRateTraits>(samplingRates, samplingRateCollection, del);
-    }
+    collectionFromString<SampleRateTraits>(samplingRates, samplingRateCollection, del);
     return samplingRateCollection;
 }
 
 static FormatTraits::Collection formatsFromString(const std::string &formats, const char *del = "|")
 {
     FormatTraits::Collection formatCollection;
-    // by convention, "0' in the first entry in mFormats indicates the supported formats
-    // should be read from the output stream after it is opened for the first time
-    if (formats == DYNAMIC_VALUE_TAG) {
-        formatCollection.add(gDynamicFormat);
-    } else {
-        FormatConverter::collectionFromString(formats, formatCollection, del);
-    }
+    FormatConverter::collectionFromString(formats, formatCollection, del);
     return formatCollection;
 }
 
 static audio_format_t formatFromString(const std::string &literalFormat)
 {
     audio_format_t format;
-    // by convention, "0' in the first entry in literalFormat indicates the supported formats
-    // should be read from the output stream after it is opened for the first time
-    if (literalFormat == DYNAMIC_VALUE_TAG) {
-        return gDynamicFormat;
-    } else {
-        FormatConverter::fromString(literalFormat, format);
-    }
+    FormatConverter::fromString(literalFormat, format);
     return format;
 }
 
 static audio_channel_mask_t channelMaskFromString(const std::string &literalChannels)
 {
     audio_channel_mask_t channels;
-    // by convention, "0' in the first entry in literalChannels indicates the supported channels
-    // should be read from the output stream after it is opened for the first time
-    if (literalChannels == DYNAMIC_VALUE_TAG) {
-        return gDynamicChannelMask;
-    }
     if (!OutputChannelConverter::fromString(literalChannels, channels) ||
             !InputChannelConverter::fromString(literalChannels, channels)) {
         return AUDIO_CHANNEL_INVALID;
@@ -194,13 +167,9 @@
                                                         const char *del = "|")
 {
     ChannelTraits::Collection channelMaskCollection;
-    if (channels == DYNAMIC_VALUE_TAG) {
-        channelMaskCollection.add(gDynamicChannelMask);
-    } else {
-        OutputChannelConverter::collectionFromString(channels, channelMaskCollection, del);
-        InputChannelConverter::collectionFromString(channels, channelMaskCollection, del);
-        ChannelIndexConverter::collectionFromString(channels, channelMaskCollection, del);
-    }
+    OutputChannelConverter::collectionFromString(channels, channelMaskCollection, del);
+    InputChannelConverter::collectionFromString(channels, channelMaskCollection, del);
+    ChannelIndexConverter::collectionFromString(channels, channelMaskCollection, del);
     return channelMaskCollection;
 }
 
@@ -208,12 +177,8 @@
                                                                   const char *del = "|")
 {
     InputChannelTraits::Collection inputChannelMaskCollection;
-    if (inChannels == DYNAMIC_VALUE_TAG) {
-        inputChannelMaskCollection.add(gDynamicChannelMask);
-    } else {
-        InputChannelConverter::collectionFromString(inChannels, inputChannelMaskCollection, del);
-        ChannelIndexConverter::collectionFromString(inChannels, inputChannelMaskCollection, del);
-    }
+    InputChannelConverter::collectionFromString(inChannels, inputChannelMaskCollection, del);
+    ChannelIndexConverter::collectionFromString(inChannels, inputChannelMaskCollection, del);
     return inputChannelMaskCollection;
 }
 
@@ -221,14 +186,8 @@
                                                                     const char *del = "|")
 {
     OutputChannelTraits::Collection outputChannelMaskCollection;
-    // by convention, "0' in the first entry in mChannelMasks indicates the supported channel
-    // masks should be read from the output stream after it is opened for the first time
-    if (outChannels == DYNAMIC_VALUE_TAG) {
-        outputChannelMaskCollection.add(gDynamicChannelMask);
-    } else {
-        OutputChannelConverter::collectionFromString(outChannels, outputChannelMaskCollection, del);
-        ChannelIndexConverter::collectionFromString(outChannels, outputChannelMaskCollection, del);
-    }
+    OutputChannelConverter::collectionFromString(outChannels, outputChannelMaskCollection, del);
+    ChannelIndexConverter::collectionFromString(outChannels, outputChannelMaskCollection, del);
     return outputChannelMaskCollection;
 }
 
diff --git a/services/audiopolicy/common/managerdefinitions/include/audio_policy_conf.h b/services/audiopolicy/common/managerdefinitions/include/audio_policy_conf.h
index aac9e4d..0a27947 100644
--- a/services/audiopolicy/common/managerdefinitions/include/audio_policy_conf.h
+++ b/services/audiopolicy/common/managerdefinitions/include/audio_policy_conf.h
@@ -65,3 +65,7 @@
 #define GAIN_STEP_VALUE "step_value_mB"
 #define GAIN_MIN_RAMP_MS "min_ramp_ms"
 #define GAIN_MAX_RAMP_MS "max_ramp_ms"
+
+#define DYNAMIC_VALUE_TAG "dynamic" // special value for "channel_masks", "sampling_rates" and
+                                    // "formats" in outputs descriptors indicating that supported
+                                    // values should be queried after opening the output.
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
index 76470c5..9b6469c 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
@@ -32,9 +32,7 @@
       mProfile(profile), mId(0)
 {
     if (profile != NULL) {
-        mSamplingRate = profile->pickSamplingRate();
-        mFormat = profile->pickFormat();
-        mChannelMask = profile->pickChannelMask();
+        profile->pickAudioProfile(mSamplingRate, mChannelMask, mFormat);
         if (profile->mGains.size() > 0) {
             profile->mGains[0]->getDefaultConfig(&mGain);
         }
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
index 223fe80..5d0f03f 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
@@ -47,9 +47,7 @@
         mStrategyMutedByDevice[i] = false;
     }
     if (port != NULL) {
-        mSamplingRate = port->pickSamplingRate();
-        mFormat = port->pickFormat();
-        mChannelMask = port->pickChannelMask();
+        port->pickAudioProfile(mSamplingRate, mChannelMask, mFormat);
         if (port->mGains.size() > 0) {
             port->mGains[0]->getDefaultConfig(&mGain);
         }
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp
index 1713095..cde0923 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp
@@ -16,7 +16,6 @@
 
 #define LOG_TAG "APM::AudioPort"
 //#define LOG_NDEBUG 0
-#include <media/AudioResamplerPublic.h>
 #include "TypeConverter.h"
 #include "AudioPort.h"
 #include "HwModule.h"
@@ -68,420 +67,165 @@
 
 void AudioPort::toAudioPort(struct audio_port *port) const
 {
+    // TODO: update this function once audio_port structure reflects the new profile definition.
+    // For compatibility reason: flatening the AudioProfile into audio_port structure.
+    SortedVector<audio_format_t> flatenedFormats;
+    SampleRateVector flatenedRates;
+    ChannelsVector flatenedChannels;
+    for (size_t profileIndex = 0; profileIndex < mProfiles.size(); profileIndex++) {
+        if (mProfiles[profileIndex]->isValid()) {
+            audio_format_t formatToExport = mProfiles[profileIndex]->getFormat();
+            const SampleRateVector &ratesToExport = mProfiles[profileIndex]->getSampleRates();
+            const ChannelsVector &channelsToExport = mProfiles[profileIndex]->getChannels();
+
+            if (flatenedFormats.indexOf(formatToExport) < 0) {
+                flatenedFormats.add(formatToExport);
+            }
+            for (size_t rateIndex = 0; rateIndex < ratesToExport.size(); rateIndex++) {
+                uint32_t rate = ratesToExport[rateIndex];
+                if (flatenedRates.indexOf(rate) < 0) {
+                    flatenedRates.add(rate);
+                }
+            }
+            for (size_t chanIndex = 0; chanIndex < channelsToExport.size(); chanIndex++) {
+                audio_channel_mask_t channels = channelsToExport[chanIndex];
+                if (flatenedChannels.indexOf(channels) < 0) {
+                    flatenedChannels.add(channels);
+                }
+            }
+            if (flatenedRates.size() > AUDIO_PORT_MAX_SAMPLING_RATES ||
+                    flatenedChannels.size() > AUDIO_PORT_MAX_CHANNEL_MASKS ||
+                    flatenedFormats.size() > AUDIO_PORT_MAX_FORMATS) {
+                ALOGE("%s: bailing out: cannot export profiles to port config", __FUNCTION__);
+                return;
+            }
+        }
+    }
     port->role = mRole;
     port->type = mType;
     strlcpy(port->name, mName, AUDIO_PORT_MAX_NAME_LEN);
-    unsigned int i;
-    for (i = 0; i < mSamplingRates.size() && i < AUDIO_PORT_MAX_SAMPLING_RATES; i++) {
-        if (mSamplingRates[i] != 0) {
-            port->sample_rates[i] = mSamplingRates[i];
-        }
+    port->num_sample_rates = flatenedRates.size();
+    port->num_channel_masks = flatenedChannels.size();
+    port->num_formats = flatenedFormats.size();
+    for (size_t i = 0; i < flatenedRates.size(); i++) {
+        port->sample_rates[i] = flatenedRates[i];
     }
-    port->num_sample_rates = i;
-    for (i = 0; i < mChannelMasks.size() && i < AUDIO_PORT_MAX_CHANNEL_MASKS; i++) {
-        if (mChannelMasks[i] != 0) {
-            port->channel_masks[i] = mChannelMasks[i];
-        }
+    for (size_t i = 0; i < flatenedChannels.size(); i++) {
+        port->channel_masks[i] = flatenedChannels[i];
     }
-    port->num_channel_masks = i;
-    for (i = 0; i < mFormats.size() && i < AUDIO_PORT_MAX_FORMATS; i++) {
-        if (mFormats[i] != 0) {
-            port->formats[i] = mFormats[i];
-        }
+    for (size_t i = 0; i < flatenedFormats.size(); i++) {
+        port->formats[i] = flatenedFormats[i];
     }
-    port->num_formats = i;
 
     ALOGV("AudioPort::toAudioPort() num gains %zu", mGains.size());
 
+    uint32_t i;
     for (i = 0; i < mGains.size() && i < AUDIO_PORT_MAX_GAINS; i++) {
         port->gains[i] = mGains[i]->getGain();
     }
     port->num_gains = i;
 }
 
-void AudioPort::importAudioPort(const sp<AudioPort> port) {
-    for (size_t k = 0 ; k < port->mSamplingRates.size() ; k++) {
-        const uint32_t rate = port->mSamplingRates.itemAt(k);
-        if (rate != 0) { // skip "dynamic" rates
-            bool hasRate = false;
-            for (size_t l = 0 ; l < mSamplingRates.size() ; l++) {
-                if (rate == mSamplingRates.itemAt(l)) {
-                    hasRate = true;
+void AudioPort::importAudioPort(const sp<AudioPort> port)
+{
+    size_t indexToImport;
+    for (indexToImport = 0; indexToImport < port->mProfiles.size(); indexToImport++) {
+        const sp<AudioProfile> &profileToImport = port->mProfiles[indexToImport];
+        if (profileToImport->isValid()) {
+            // Import only valid port, i.e. valid format, non empty rates and channels masks
+            bool hasSameProfile = false;
+            for (size_t profileIndex = 0; profileIndex < mProfiles.size(); profileIndex++) {
+                if (*mProfiles[profileIndex] == *profileToImport) {
+                    // never import a profile twice
+                    hasSameProfile = true;
                     break;
                 }
             }
-            if (!hasRate) { // never import a sampling rate twice
-                mSamplingRates.add(rate);
+            if (hasSameProfile) { // never import a same profile twice
+                continue;
             }
-        }
-    }
-    for (size_t k = 0 ; k < port->mChannelMasks.size() ; k++) {
-        const audio_channel_mask_t mask = port->mChannelMasks.itemAt(k);
-        if (mask != 0) { // skip "dynamic" masks
-            bool hasMask = false;
-            for (size_t l = 0 ; l < mChannelMasks.size() ; l++) {
-                if (mask == mChannelMasks.itemAt(l)) {
-                    hasMask = true;
-                    break;
-                }
-            }
-            if (!hasMask) { // never import a channel mask twice
-                mChannelMasks.add(mask);
-            }
-        }
-    }
-    for (size_t k = 0 ; k < port->mFormats.size() ; k++) {
-        const audio_format_t format = port->mFormats.itemAt(k);
-        if (format != 0) { // skip "dynamic" formats
-            bool hasFormat = false;
-            for (size_t l = 0 ; l < mFormats.size() ; l++) {
-                if (format == mFormats.itemAt(l)) {
-                    hasFormat = true;
-                    break;
-                }
-            }
-            if (!hasFormat) { // never import a format twice
-                mFormats.add(format);
-            }
+            addAudioProfile(profileToImport);
         }
     }
 }
 
-void AudioPort::clearCapabilities() {
-    mChannelMasks.clear();
-    mFormats.clear();
-    mSamplingRates.clear();
-}
-
-void AudioPort::setSupportedFormats(const Vector <audio_format_t> &formats)
+void AudioPort::pickSamplingRate(uint32_t &pickedRate,const SampleRateVector &samplingRates) const
 {
-    mFormats = formats;
-    // 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);
-    // }
-    mFormats.sort(compareFormats);
-}
-
-status_t AudioPort::checkExactSamplingRate(uint32_t samplingRate) const
-{
-    if (mSamplingRates.isEmpty()) {
-        return NO_ERROR;
-    }
-
-    for (size_t i = 0; i < mSamplingRates.size(); i ++) {
-        if (mSamplingRates[i] == samplingRate) {
-            return NO_ERROR;
-        }
-    }
-    return BAD_VALUE;
-}
-
-status_t AudioPort::checkCompatibleSamplingRate(uint32_t samplingRate,
-        uint32_t *updatedSamplingRate) const
-{
-    if (mSamplingRates.isEmpty()) {
-        if (updatedSamplingRate != NULL) {
-            *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 do not need to be sorted in ascending order.
-    ssize_t maxBelow = -1;
-    ssize_t minAbove = -1;
-    uint32_t candidate;
-    for (size_t i = 0; i < mSamplingRates.size(); i++) {
-        candidate = mSamplingRates[i];
-        if (candidate == samplingRate) {
-            if (updatedSamplingRate != NULL) {
-                *updatedSamplingRate = candidate;
-            }
-            return NO_ERROR;
-        }
-        // candidate < desired
-        if (candidate < samplingRate) {
-            if (maxBelow < 0 || candidate > mSamplingRates[maxBelow]) {
-                maxBelow = i;
-            }
-        // candidate > desired
-        } else {
-            if (minAbove < 0 || candidate < mSamplingRates[minAbove]) {
-                minAbove = i;
-            }
-        }
-    }
-
-    // Prefer to down-sample from a higher sampling rate, as we get the desired frequency spectrum.
-    if (minAbove >= 0) {
-        candidate = mSamplingRates[minAbove];
-        if (candidate / AUDIO_RESAMPLER_DOWN_RATIO_MAX <= samplingRate) {
-            if (updatedSamplingRate != NULL) {
-                *updatedSamplingRate = candidate;
-            }
-            return NO_ERROR;
-        }
-    }
-    // But if we have to up-sample from a lower sampling rate, that's OK.
-    if (maxBelow >= 0) {
-        candidate = mSamplingRates[maxBelow];
-        if (candidate * AUDIO_RESAMPLER_UP_RATIO_MAX >= samplingRate) {
-            if (updatedSamplingRate != NULL) {
-                *updatedSamplingRate = candidate;
-            }
-            return NO_ERROR;
-        }
-    }
-    // leave updatedSamplingRate unmodified
-    return BAD_VALUE;
-}
-
-status_t AudioPort::checkExactChannelMask(audio_channel_mask_t channelMask) const
-{
-    if (mChannelMasks.isEmpty()) {
-        return NO_ERROR;
-    }
-
-    for (size_t i = 0; i < mChannelMasks.size(); i++) {
-        if (mChannelMasks[i] == channelMask) {
-            return NO_ERROR;
-        }
-    }
-    return BAD_VALUE;
-}
-
-status_t AudioPort::checkCompatibleChannelMask(audio_channel_mask_t channelMask,
-        audio_channel_mask_t *updatedChannelMask) const
-{
-    if (mChannelMasks.isEmpty()) {
-        if (updatedChannelMask != NULL) {
-            *updatedChannelMask = channelMask;
-        }
-        return NO_ERROR;
-    }
-
-    const bool isRecordThread = mType == AUDIO_PORT_TYPE_MIX && mRole == AUDIO_PORT_ROLE_SINK;
-    const bool isIndex = audio_channel_mask_get_representation(channelMask)
-            == AUDIO_CHANNEL_REPRESENTATION_INDEX;
-    int bestMatch = 0;
-    for (size_t i = 0; i < mChannelMasks.size(); i ++) {
-        audio_channel_mask_t supported = mChannelMasks[i];
-        if (supported == channelMask) {
-            // Exact matches always taken.
-            if (updatedChannelMask != NULL) {
-                *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.
-            //
-            // 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);
-            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 << audio_channel_count_from_in_mask(supported)) - 1 ;
-                match = __builtin_popcount(
-                        audio_channel_mask_get_bits(channelMask) & equivalentBits);
-            } else if (!isIndex && isSupportedIndex) {
-                const uint32_t equivalentBits =
-                        (1 << audio_channel_count_from_in_mask(channelMask)) - 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;
-                if (updatedChannelMask != NULL) {
-                    *updatedChannelMask = supported;
-                } else {
-                    return NO_ERROR; // any match will do in this case.
-                }
-            }
-        }
-    }
-    return bestMatch > 0 ? NO_ERROR : BAD_VALUE;
-}
-
-status_t AudioPort::checkExactFormat(audio_format_t format) const
-{
-    if (mFormats.isEmpty()) {
-        return NO_ERROR;
-    }
-
-    for (size_t i = 0; i < mFormats.size(); i ++) {
-        if (mFormats[i] == format) {
-            return NO_ERROR;
-        }
-    }
-    return BAD_VALUE;
-}
-
-status_t AudioPort::checkCompatibleFormat(audio_format_t format, audio_format_t *updatedFormat)
-        const
-{
-    if (mFormats.isEmpty()) {
-        if (updatedFormat != NULL) {
-            *updatedFormat = format;
-        }
-        return NO_ERROR;
-    }
-
-    const bool checkInexact = // when port is input and format is linear pcm
-            mType == AUDIO_PORT_TYPE_MIX && mRole == AUDIO_PORT_ROLE_SINK
-            && audio_is_linear_pcm(format);
-
-    // iterate from best format to worst format (reverse order)
-    for (ssize_t i = mFormats.size() - 1; i >= 0 ; --i) {
-        if (mFormats[i] == format ||
-                (checkInexact
-                        && mFormats[i] != AUDIO_FORMAT_DEFAULT
-                        && audio_is_linear_pcm(mFormats[i]))) {
-            // for inexact checks we take the first linear pcm format due to sorting.
-            if (updatedFormat != NULL) {
-                *updatedFormat = mFormats[i];
-            }
-            return NO_ERROR;
-        }
-    }
-    return BAD_VALUE;
-}
-
-uint32_t AudioPort::pickSamplingRate() const
-{
-    // special case for uninitialized dynamic profile
-    if (mSamplingRates.size() == 1 && mSamplingRates[0] == 0) {
-        return 0;
-    }
-
+    pickedRate = 0;
     // For direct outputs, pick minimum sampling rate: this helps ensuring that the
     // channel count / sampling rate combination chosen will be supported by the connected
     // sink
-    if ((mType == AUDIO_PORT_TYPE_MIX) && (mRole == AUDIO_PORT_ROLE_SOURCE) &&
-            (mFlags & (AUDIO_OUTPUT_FLAG_DIRECT | AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD))) {
+    if (isDirectOutput()) {
         uint32_t samplingRate = UINT_MAX;
-        for (size_t i = 0; i < mSamplingRates.size(); i ++) {
-            if ((mSamplingRates[i] < samplingRate) && (mSamplingRates[i] > 0)) {
-                samplingRate = mSamplingRates[i];
+        for (size_t i = 0; i < samplingRates.size(); i ++) {
+            if ((samplingRates[i] < samplingRate) && (samplingRates[i] > 0)) {
+                samplingRate = samplingRates[i];
             }
         }
-        return (samplingRate == UINT_MAX) ? 0 : samplingRate;
-    }
+        pickedRate = (samplingRate == UINT_MAX) ? 0 : samplingRate;
+    } else {
+        uint32_t maxRate = MAX_MIXER_SAMPLING_RATE;
 
-    uint32_t samplingRate = 0;
-    uint32_t maxRate = MAX_MIXER_SAMPLING_RATE;
-
-    // For mixed output and inputs, use max mixer sampling rates. Do not
-    // limit sampling rate otherwise
-    // For inputs, also see checkCompatibleSamplingRate().
-    if (mType != AUDIO_PORT_TYPE_MIX) {
-        maxRate = UINT_MAX;
-    }
-    // TODO: should mSamplingRates[] be ordered in terms of our preference
-    // and we return the first (and hence most preferred) match?  This is of concern if
-    // we want to choose 96kHz over 192kHz for USB driver stability or resource constraints.
-    for (size_t i = 0; i < mSamplingRates.size(); i ++) {
-        if ((mSamplingRates[i] > samplingRate) && (mSamplingRates[i] <= maxRate)) {
-            samplingRate = mSamplingRates[i];
+        // For mixed output and inputs, use max mixer sampling rates. Do not
+        // limit sampling rate otherwise
+        // For inputs, also see checkCompatibleSamplingRate().
+        if (mType != AUDIO_PORT_TYPE_MIX) {
+            maxRate = UINT_MAX;
+        }
+        // TODO: should mSamplingRates[] be ordered in terms of our preference
+        // and we return the first (and hence most preferred) match?  This is of concern if
+        // we want to choose 96kHz over 192kHz for USB driver stability or resource constraints.
+        for (size_t i = 0; i < samplingRates.size(); i ++) {
+            if ((samplingRates[i] > pickedRate) && (samplingRates[i] <= maxRate)) {
+                pickedRate = samplingRates[i];
+            }
         }
     }
-    return samplingRate;
 }
 
-audio_channel_mask_t AudioPort::pickChannelMask() const
+void AudioPort::pickChannelMask(audio_channel_mask_t &pickedChannelMask,
+                                const ChannelsVector &channelMasks) const
 {
-    // special case for uninitialized dynamic profile
-    if (mChannelMasks.size() == 1 && mChannelMasks[0] == 0) {
-        return AUDIO_CHANNEL_NONE;
-    }
-    audio_channel_mask_t channelMask = AUDIO_CHANNEL_NONE;
-
+    pickedChannelMask = AUDIO_CHANNEL_NONE;
     // For direct outputs, pick minimum channel count: this helps ensuring that the
     // channel count / sampling rate combination chosen will be supported by the connected
     // sink
-    if ((mType == AUDIO_PORT_TYPE_MIX) && (mRole == AUDIO_PORT_ROLE_SOURCE) &&
-            (mFlags & (AUDIO_OUTPUT_FLAG_DIRECT | AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD))) {
+    if (isDirectOutput()) {
         uint32_t channelCount = UINT_MAX;
-        for (size_t i = 0; i < mChannelMasks.size(); i ++) {
+        for (size_t i = 0; i < channelMasks.size(); i ++) {
             uint32_t cnlCount;
             if (useInputChannelMask()) {
-                cnlCount = audio_channel_count_from_in_mask(mChannelMasks[i]);
+                cnlCount = audio_channel_count_from_in_mask(channelMasks[i]);
             } else {
-                cnlCount = audio_channel_count_from_out_mask(mChannelMasks[i]);
+                cnlCount = audio_channel_count_from_out_mask(channelMasks[i]);
             }
             if ((cnlCount < channelCount) && (cnlCount > 0)) {
-                channelMask = mChannelMasks[i];
+                pickedChannelMask = channelMasks[i];
                 channelCount = cnlCount;
             }
         }
-        return channelMask;
-    }
+    } else {
+        uint32_t channelCount = 0;
+        uint32_t maxCount = MAX_MIXER_CHANNEL_COUNT;
 
-    uint32_t channelCount = 0;
-    uint32_t maxCount = MAX_MIXER_CHANNEL_COUNT;
-
-    // For mixed output and inputs, use max mixer channel count. Do not
-    // limit channel count otherwise
-    if (mType != AUDIO_PORT_TYPE_MIX) {
-        maxCount = UINT_MAX;
-    }
-    for (size_t i = 0; i < mChannelMasks.size(); i ++) {
-        uint32_t cnlCount;
-        if (useInputChannelMask()) {
-            cnlCount = audio_channel_count_from_in_mask(mChannelMasks[i]);
-        } else {
-            cnlCount = audio_channel_count_from_out_mask(mChannelMasks[i]);
+        // For mixed output and inputs, use max mixer channel count. Do not
+        // limit channel count otherwise
+        if (mType != AUDIO_PORT_TYPE_MIX) {
+            maxCount = UINT_MAX;
         }
-        if ((cnlCount > channelCount) && (cnlCount <= maxCount)) {
-            channelMask = mChannelMasks[i];
-            channelCount = cnlCount;
+        for (size_t i = 0; i < channelMasks.size(); i ++) {
+            uint32_t cnlCount;
+            if (useInputChannelMask()) {
+                cnlCount = audio_channel_count_from_in_mask(channelMasks[i]);
+            } else {
+                cnlCount = audio_channel_count_from_out_mask(channelMasks[i]);
+            }
+            if ((cnlCount > channelCount) && (cnlCount <= maxCount)) {
+                pickedChannelMask = channelMasks[i];
+                channelCount = cnlCount;
+            }
         }
     }
-    return channelMask;
 }
 
 /* format in order of increasing preference */
@@ -494,8 +238,7 @@
         AUDIO_FORMAT_PCM_FLOAT,
 };
 
-int AudioPort::compareFormats(audio_format_t format1,
-                                                  audio_format_t format2)
+int AudioPort::compareFormats(audio_format_t format1, audio_format_t format2)
 {
     // NOTE: AUDIO_FORMAT_INVALID is also considered not PCM and will be compared equal to any
     // compressed format and better than any PCM format. This is by design of pickFormat()
@@ -525,36 +268,49 @@
     return index1 - index2;
 }
 
-audio_format_t AudioPort::pickFormat() const
+void AudioPort::pickAudioProfile(uint32_t &samplingRate,
+                                 audio_channel_mask_t &channelMask,
+                                 audio_format_t &format) const
 {
-    // special case for uninitialized dynamic profile
-    if (mFormats.size() == 1 && mFormats[0] == 0) {
-        return AUDIO_FORMAT_DEFAULT;
-    }
+    format = AUDIO_FORMAT_DEFAULT;
+    samplingRate = 0;
+    channelMask = AUDIO_CHANNEL_NONE;
 
-    audio_format_t format = AUDIO_FORMAT_DEFAULT;
-    audio_format_t bestFormat =
-            AudioPort::sPcmFormatCompareTable[
-                ARRAY_SIZE(AudioPort::sPcmFormatCompareTable) - 1];
-    // For mixed output and inputs, use best mixer output format. Do not
-    // limit format otherwise
-    if ((mType != AUDIO_PORT_TYPE_MIX) ||
-            ((mRole == AUDIO_PORT_ROLE_SOURCE) &&
-             (((mFlags & (AUDIO_OUTPUT_FLAG_DIRECT | AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD)) != 0)))) {
+    // special case for uninitialized dynamic profile
+    if (!mProfiles.hasValidProfile()) {
+        return;
+    }
+    audio_format_t bestFormat = sPcmFormatCompareTable[ARRAY_SIZE(sPcmFormatCompareTable) - 1];
+    // For mixed output and inputs, use best mixer output format.
+    // Do not limit format otherwise
+    if ((mType != AUDIO_PORT_TYPE_MIX) || isDirectOutput()) {
         bestFormat = AUDIO_FORMAT_INVALID;
     }
 
-    for (size_t i = 0; i < mFormats.size(); i ++) {
-        if ((compareFormats(mFormats[i], format) > 0) &&
-                (compareFormats(mFormats[i], bestFormat) <= 0)) {
-            format = mFormats[i];
+    for (size_t i = 0; i < mProfiles.size(); i ++) {
+        if (!mProfiles[i]->isValid()) {
+            continue;
+        }
+        audio_format_t formatToCompare = mProfiles[i]->getFormat();
+        if ((compareFormats(formatToCompare, format) > 0) &&
+                (compareFormats(formatToCompare, bestFormat) <= 0)) {
+            uint32_t pickedSamplingRate = 0;
+            audio_channel_mask_t pickedChannelMask = AUDIO_CHANNEL_NONE;
+            pickChannelMask(pickedChannelMask, mProfiles[i]->getChannels());
+            pickSamplingRate(pickedSamplingRate, mProfiles[i]->getSampleRates());
+
+            if (formatToCompare != AUDIO_FORMAT_DEFAULT && pickedChannelMask != AUDIO_CHANNEL_NONE
+                    && pickedSamplingRate != 0) {
+                format = formatToCompare;
+                channelMask = pickedChannelMask;
+                samplingRate = pickedSamplingRate;
+                // TODO: shall we return on the first one or still trying to pick a better Profile?
+            }
         }
     }
-    return format;
 }
 
-status_t AudioPort::checkGain(const struct audio_gain_config *gainConfig,
-                                                  int index) const
+status_t AudioPort::checkGain(const struct audio_gain_config *gainConfig, int index) const
 {
     if (index < 0 || (size_t)index >= mGains.size()) {
         return BAD_VALUE;
@@ -562,7 +318,7 @@
     return mGains[index]->checkConfig(gainConfig);
 }
 
-void AudioPort::dump(int fd, int spaces) const
+void AudioPort::dump(int fd, int spaces, bool verbose) const
 {
     const size_t SIZE = 256;
     char buffer[SIZE];
@@ -571,66 +327,17 @@
     if (mName.length() != 0) {
         snprintf(buffer, SIZE, "%*s- name: %s\n", spaces, "", mName.string());
         result.append(buffer);
+        write(fd, result.string(), result.size());
     }
+    if (verbose) {
+        mProfiles.dump(fd, spaces);
 
-    if (mSamplingRates.size() != 0) {
-        snprintf(buffer, SIZE, "%*s- sampling rates: ", spaces, "");
-        result.append(buffer);
-        for (size_t i = 0; i < mSamplingRates.size(); i++) {
-            if (i == 0 && mSamplingRates[i] == 0) {
-                snprintf(buffer, SIZE, "Dynamic");
-            } else {
-                snprintf(buffer, SIZE, "%d", mSamplingRates[i]);
+        if (mGains.size() != 0) {
+            snprintf(buffer, SIZE, "%*s- gains:\n", spaces, "");
+            write(fd, buffer, strlen(buffer) + 1);
+            for (size_t i = 0; i < mGains.size(); i++) {
+                mGains[i]->dump(fd, spaces + 2, i);
             }
-            result.append(buffer);
-            result.append(i == (mSamplingRates.size() - 1) ? "" : ", ");
-        }
-        result.append("\n");
-    }
-
-    if (mChannelMasks.size() != 0) {
-        snprintf(buffer, SIZE, "%*s- channel masks: ", spaces, "");
-        result.append(buffer);
-        for (size_t i = 0; i < mChannelMasks.size(); i++) {
-            ALOGV("AudioPort::dump mChannelMasks %zu %08x", i, mChannelMasks[i]);
-
-            if (i == 0 && mChannelMasks[i] == 0) {
-                snprintf(buffer, SIZE, "Dynamic");
-            } else {
-                snprintf(buffer, SIZE, "0x%04x", mChannelMasks[i]);
-            }
-            result.append(buffer);
-            result.append(i == (mChannelMasks.size() - 1) ? "" : ", ");
-        }
-        result.append("\n");
-    }
-
-    if (mFormats.size() != 0) {
-        snprintf(buffer, SIZE, "%*s- formats: ", spaces, "");
-        result.append(buffer);
-        for (size_t i = 0; i < mFormats.size(); i++) {
-            std::string formatLiteral;
-            bool success = FormatConverter::toString(mFormats[i], formatLiteral);
-            if (i == 0 && !success) {
-                snprintf(buffer, SIZE, "Dynamic");
-            } else {
-                if (!success) {
-                    snprintf(buffer, SIZE, "%#x", mFormats[i]);
-                } else {
-                    snprintf(buffer, SIZE, "%s", formatLiteral.c_str());
-                }
-            }
-            result.append(buffer);
-            result.append(i == (mFormats.size() - 1) ? "" : ", ");
-        }
-        result.append("\n");
-    }
-    write(fd, result.string(), result.size());
-    if (mGains.size() != 0) {
-        snprintf(buffer, SIZE, "%*s- gains:\n", spaces, "");
-        write(fd, buffer, strlen(buffer) + 1);
-        for (size_t i = 0; i < mGains.size(); i++) {
-            mGains[i]->dump(fd, spaces + 2, i);
         }
     }
 }
@@ -650,9 +357,8 @@
     mGain.index = -1;
 }
 
-status_t AudioPortConfig::applyAudioPortConfig(
-                                                        const struct audio_port_config *config,
-                                                        struct audio_port_config *backupConfig)
+status_t AudioPortConfig::applyAudioPortConfig(const struct audio_port_config *config,
+                                               struct audio_port_config *backupConfig)
 {
     struct audio_port_config localBackupConfig;
     status_t status = NO_ERROR;
@@ -665,25 +371,19 @@
         status = NO_INIT;
         goto exit;
     }
+    status = audioport->checkExactAudioProfile(config->sample_rate,
+                                               config->channel_mask,
+                                               config->format);
+    if (status != NO_ERROR) {
+        goto exit;
+    }
     if (config->config_mask & AUDIO_PORT_CONFIG_SAMPLE_RATE) {
-        status = audioport->checkExactSamplingRate(config->sample_rate);
-        if (status != NO_ERROR) {
-            goto exit;
-        }
         mSamplingRate = config->sample_rate;
     }
     if (config->config_mask & AUDIO_PORT_CONFIG_CHANNEL_MASK) {
-        status = audioport->checkExactChannelMask(config->channel_mask);
-        if (status != NO_ERROR) {
-            goto exit;
-        }
         mChannelMask = config->channel_mask;
     }
     if (config->config_mask & AUDIO_PORT_CONFIG_FORMAT) {
-        status = audioport->checkExactFormat(config->format);
-        if (status != NO_ERROR) {
-            goto exit;
-        }
         mFormat = config->format;
     }
     if (config->config_mask & AUDIO_PORT_CONFIG_GAIN) {
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioProfile.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioProfile.cpp
new file mode 100644
index 0000000..c599665
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioProfile.cpp
@@ -0,0 +1,288 @@
+/*
+ * 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::AudioProfile"
+//#define LOG_NDEBUG 0
+
+#include "AudioProfile.h"
+#include "AudioPort.h"
+#include "HwModule.h"
+#include "AudioGain.h"
+#include <utils/SortedVector.h>
+#include "TypeConverter.h"
+#include <media/AudioResamplerPublic.h>
+#include <algorithm>
+
+namespace android {
+
+status_t AudioProfile::checkExact(uint32_t samplingRate, audio_channel_mask_t channelMask,
+                                  audio_format_t format) const
+{
+    if (format == mFormat &&
+            (mChannelMasks.isEmpty() || supportsChannels(channelMask)) &&
+            (mSamplingRates.isEmpty() || supportsRate(samplingRate))) {
+        return NO_ERROR;
+    }
+    return BAD_VALUE;
+}
+
+template <typename T>
+bool operator == (const SortedVector<T> &left, const SortedVector<T> &right)
+{
+    if (left.size() != right.size()) {
+        return false;
+    }
+    for(size_t index = 0; index < right.size(); index++) {
+        if (left[index] != right[index]) {
+            return false;
+        }
+    }
+    return true;
+}
+
+bool operator == (const AudioProfile &left, const AudioProfile &compareTo)
+{
+    return (left.getFormat() == compareTo.getFormat()) &&
+            (left.getChannels() == compareTo.getChannels()) &&
+            (left.getSampleRates() == compareTo.getSampleRates());
+}
+
+status_t AudioProfile::checkCompatibleSamplingRate(uint32_t samplingRate,
+                                                   uint32_t &updatedSamplingRate) const
+{
+    if (mSamplingRates.isEmpty()) {
+        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.
+    size_t orderOfDesiredRate = mSamplingRates.orderOf(samplingRate);
+
+    // Prefer to down-sample from a higher sampling rate, as we get the desired frequency spectrum.
+    if (orderOfDesiredRate < mSamplingRates.size()) {
+        uint32_t candidate = mSamplingRates[orderOfDesiredRate];
+        if (candidate / AUDIO_RESAMPLER_DOWN_RATIO_MAX <= samplingRate) {
+            updatedSamplingRate = candidate;
+            return NO_ERROR;
+        }
+    }
+    // But if we have to up-sample from a lower sampling rate, that's OK.
+    if (orderOfDesiredRate != 0) {
+        uint32_t candidate = mSamplingRates[orderOfDesiredRate - 1];
+        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.isEmpty()) {
+        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;
+    int bestMatch = 0;
+    for (size_t i = 0; i < mChannelMasks.size(); i ++) {
+        audio_channel_mask_t supported = mChannelMasks[i];
+        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.
+            //
+            // 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);
+            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 << audio_channel_count_from_in_mask(supported)) - 1 ;
+                match = __builtin_popcount(
+                        audio_channel_mask_get_bits(channelMask) & equivalentBits);
+            } else if (!isIndex && isSupportedIndex) {
+                const uint32_t equivalentBits =
+                        (1 << audio_channel_count_from_in_mask(channelMask)) - 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(int fd, int spaces) const
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+
+    snprintf(buffer, SIZE, "%s%s%s\n", mIsDynamicFormat ? "[dynamic format]" : "",
+             mIsDynamicChannels ? "[dynamic channels]" : "",
+             mIsDynamicRate ? "[dynamic rates]" : "");
+    result.append(buffer);
+    if (mName.length() != 0) {
+        snprintf(buffer, SIZE, "%*s- name: %s\n", spaces, "", mName.string());
+        result.append(buffer);
+    }
+    std::string formatLiteral;
+    if (FormatConverter::toString(mFormat, formatLiteral)) {
+        snprintf(buffer, SIZE, "%*s- format: %s\n", spaces, "", formatLiteral.c_str());
+        result.append(buffer);
+    }
+    if (!mSamplingRates.isEmpty()) {
+        snprintf(buffer, SIZE, "%*s- sampling rates:", spaces, "");
+        result.append(buffer);
+        for (size_t i = 0; i < mSamplingRates.size(); i++) {
+            snprintf(buffer, SIZE, "%d", mSamplingRates[i]);
+            result.append(buffer);
+            result.append(i == (mSamplingRates.size() - 1) ? "" : ", ");
+        }
+        result.append("\n");
+    }
+
+    if (!mChannelMasks.isEmpty()) {
+        snprintf(buffer, SIZE, "%*s- channel masks:", spaces, "");
+        result.append(buffer);
+        for (size_t i = 0; i < mChannelMasks.size(); i++) {
+            snprintf(buffer, SIZE, "0x%04x", mChannelMasks[i]);
+            result.append(buffer);
+            result.append(i == (mChannelMasks.size() - 1) ? "" : ", ");
+        }
+        result.append("\n");
+    }
+    write(fd, result.string(), result.size());
+}
+
+status_t AudioProfileVector::checkExactProfile(uint32_t samplingRate,
+                                               audio_channel_mask_t channelMask,
+                                               audio_format_t format) const
+{
+    if (isEmpty()) {
+        return NO_ERROR;
+    }
+
+    for (size_t i = 0; i < size(); i++) {
+        const sp<AudioProfile> profile = itemAt(i);
+        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 (isEmpty()) {
+        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 = itemAt(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;
+}
+
+int AudioProfileVector::compareFormats(const sp<AudioProfile> *profile1,
+                                       const sp<AudioProfile> *profile2)
+{
+    return AudioPort::compareFormats((*profile1)->getFormat(), (*profile2)->getFormat());
+}
+
+}; // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/ConfigParsingUtils.cpp b/services/audiopolicy/common/managerdefinitions/src/ConfigParsingUtils.cpp
index 786c4e8..b187857 100644
--- a/services/audiopolicy/common/managerdefinitions/src/ConfigParsingUtils.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/ConfigParsingUtils.cpp
@@ -135,9 +135,15 @@
             deviceDesc->mAddress = String8((char *)node->value);
         } else if (strcmp(node->name, CHANNELS_TAG) == 0) {
             if (audio_is_input_device(type)) {
-                deviceDesc->setSupportedChannelMasks(inputChannelMasksFromString(node->value));
+                deviceDesc->addAudioProfile(
+                        new AudioProfile(gDynamicFormat,
+                                         inputChannelMasksFromString(node->value),
+                                         SampleRateVector()));
             } else {
-                deviceDesc->setSupportedChannelMasks(outputChannelMasksFromString(node->value));
+                deviceDesc->addAudioProfile(
+                        new AudioProfile(gDynamicFormat,
+                                         outputChannelMasksFromString(node->value),
+                                         SampleRateVector()));
             }
         } else if (strcmp(node->name, GAINS_TAG) == 0) {
             loadDeviceDescriptorGains(node, deviceDesc);
@@ -153,95 +159,74 @@
 }
 
 //static
-status_t ConfigParsingUtils::loadHwModuleInput(cnode *root, sp<HwModule> &module)
+status_t ConfigParsingUtils::loadHwModuleProfile(cnode *root, sp<HwModule> &module,
+                                                 audio_port_role_t role)
 {
     cnode *node = root->first_child;
 
-    sp<InputProfile> profile = new InputProfile(String8(root->name));
+    sp<IOProfile> profile = new IOProfile(String8(root->name), role);
+
+    AudioProfileVector audioProfiles;
+    SampleRateVector sampleRates;
+    ChannelsVector channels;
+    FormatVector formats;
 
     while (node) {
-        if (strcmp(node->name, SAMPLING_RATES_TAG) == 0) {
-            profile->setSupportedSamplingRates(samplingRatesFromString(node->value));
-        } else if (strcmp(node->name, FORMATS_TAG) == 0) {
-            profile->setSupportedFormats(formatsFromString(node->value));
-        } else if (strcmp(node->name, CHANNELS_TAG) == 0) {
-            profile->setSupportedChannelMasks(inputChannelMasksFromString(node->value));
+        if (strcmp(node->name, FORMATS_TAG) == 0 &&
+                strcmp(node->value, DYNAMIC_VALUE_TAG) != 0) {
+            formats = formatsFromString(node->value);
+        } else if (strcmp(node->name, SAMPLING_RATES_TAG) == 0 &&
+                  strcmp(node->value, DYNAMIC_VALUE_TAG) != 0) {
+            collectionFromString<SampleRateTraits>(node->value, sampleRates);
+        } else if (strcmp(node->name, CHANNELS_TAG) == 0 &&
+                   strcmp(node->value, DYNAMIC_VALUE_TAG) != 0) {
+            if (role == AUDIO_PORT_ROLE_SINK) {
+                channels = inputChannelMasksFromString(node->value);
+            } else {
+                channels = outputChannelMasksFromString(node->value);
+            }
         } else if (strcmp(node->name, DEVICES_TAG) == 0) {
             DeviceVector devices;
             loadDevicesFromTag(node->value, devices, module->getDeclaredDevices());
             profile->setSupportedDevices(devices);
         } else if (strcmp(node->name, FLAGS_TAG) == 0) {
-            profile->setFlags(InputFlagConverter::maskFromString(node->value));
+            if (role == AUDIO_PORT_ROLE_SINK) {
+                profile->setFlags(InputFlagConverter::maskFromString(node->value));
+            } else {
+                profile->setFlags(ConfigParsingUtils::parseOutputFlagNames(node->value));
+            }
         } else if (strcmp(node->name, GAINS_TAG) == 0) {
             loadAudioPortGains(node, *profile);
         }
         node = node->next;
     }
-    ALOGW_IF(profile->getSupportedDevices().isEmpty(),
-            "loadInput() invalid supported devices");
-    ALOGW_IF(profile->mChannelMasks.size() == 0,
-            "loadInput() invalid supported channel masks");
-    ALOGW_IF(profile->mSamplingRates.size() == 0,
-            "loadInput() invalid supported sampling rates");
-    ALOGW_IF(profile->mFormats.size() == 0,
-            "loadInput() invalid supported formats");
-    if (!profile->getSupportedDevices().isEmpty() &&
-            (profile->mChannelMasks.size() != 0) &&
-            (profile->mSamplingRates.size() != 0) &&
-            (profile->mFormats.size() != 0)) {
-
-        ALOGV("loadInput() adding input Supported Devices %04x",
-              profile->getSupportedDevices().types());
-        return module->addInputProfile(profile);
+    if (formats.isEmpty()) {
+        sp<AudioProfile> profileToAdd = new AudioProfile(gDynamicFormat, channels, sampleRates);
+        profileToAdd->setDynamicFormat(true);
+        profileToAdd->setDynamicChannels(channels.isEmpty());
+        profileToAdd->setDynamicRate(sampleRates.isEmpty());
+        audioProfiles.add(profileToAdd);
     } else {
-        return BAD_VALUE;
-    }
-}
-
-//static
-status_t ConfigParsingUtils::loadHwModuleOutput(cnode *root, sp<HwModule> &module)
-{
-    cnode *node = root->first_child;
-
-    sp<OutputProfile> profile = new OutputProfile(String8(root->name));
-
-    while (node) {
-        if (strcmp(node->name, SAMPLING_RATES_TAG) == 0) {
-            profile->setSupportedSamplingRates(samplingRatesFromString(node->value));
-        } else if (strcmp(node->name, FORMATS_TAG) == 0) {
-            profile->setSupportedFormats(formatsFromString(node->value));
-        } else if (strcmp(node->name, CHANNELS_TAG) == 0) {
-            profile->setSupportedChannelMasks(outputChannelMasksFromString(node->value));
-        } else if (strcmp(node->name, DEVICES_TAG) == 0) {
-            DeviceVector devices;
-            loadDevicesFromTag(node->value, devices, module->getDeclaredDevices());
-            profile->setSupportedDevices(devices);
-        } else if (strcmp(node->name, FLAGS_TAG) == 0) {
-            profile->setFlags(ConfigParsingUtils::parseOutputFlagNames(node->value));
-        } else if (strcmp(node->name, GAINS_TAG) == 0) {
-            loadAudioPortGains(node, *profile);
+        for (size_t i = 0; i < formats.size(); i++) {
+            // For compatibility reason, for each format, creates a profile with the same
+            // collection of rate and channels.
+            sp<AudioProfile> profileToAdd = new AudioProfile(formats[i], channels, sampleRates);
+            profileToAdd->setDynamicFormat(formats[i] == gDynamicFormat);
+            profileToAdd->setDynamicChannels(channels.isEmpty());
+            profileToAdd->setDynamicRate(sampleRates.isEmpty());
+            audioProfiles.add(profileToAdd);
         }
-        node = node->next;
     }
-    ALOGW_IF(profile->getSupportedDevices().isEmpty(),
-            "loadOutput() invalid supported devices");
-    ALOGW_IF(profile->mChannelMasks.size() == 0,
-            "loadOutput() invalid supported channel masks");
-    ALOGW_IF(profile->mSamplingRates.size() == 0,
-            "loadOutput() invalid supported sampling rates");
-    ALOGW_IF(profile->mFormats.size() == 0,
-            "loadOutput() invalid supported formats");
-    if (!profile->getSupportedDevices().isEmpty() &&
-            (profile->mChannelMasks.size() != 0) &&
-            (profile->mSamplingRates.size() != 0) &&
-            (profile->mFormats.size() != 0)) {
-
-        ALOGV("loadOutput() adding output Supported Devices %04x, mFlags %04x",
-              profile->getSupportedDevices().types(), profile->getFlags());
-        return module->addOutputProfile(profile);
-    } else {
-        return BAD_VALUE;
+    profile->setAudioProfiles(audioProfiles);
+    ALOGW_IF(!profile->hasSupportedDevices(), "load%s() invalid supported devices",
+             role == AUDIO_PORT_ROLE_SINK ? "Input" : "Output");
+    if (profile->hasSupportedDevices()) {
+        ALOGV("load%s() adding Supported Devices %04x, mFlags %04x",
+              role == AUDIO_PORT_ROLE_SINK ? "Input" : "Output",
+              profile->getSupportedDevicesType(), profile->getFlags());
+        return module->addProfile(profile);
     }
+    return BAD_VALUE;
 }
 
 //static
@@ -268,7 +253,7 @@
         node = node->first_child;
         while (node) {
             ALOGV("loadHwModule() loading output %s", node->name);
-            status_t tmpStatus = loadHwModuleOutput(node, module);
+            status_t tmpStatus = loadHwModuleProfile(node, module, AUDIO_PORT_ROLE_SOURCE);
             if (status == NAME_NOT_FOUND || status == NO_ERROR) {
                 status = tmpStatus;
             }
@@ -280,7 +265,7 @@
         node = node->first_child;
         while (node) {
             ALOGV("loadHwModule() loading input %s", node->name);
-            status_t tmpStatus = loadHwModuleInput(node, module);
+            status_t tmpStatus = loadHwModuleProfile(node, module, AUDIO_PORT_ROLE_SINK);
             if (status == NAME_NOT_FOUND || status == NO_ERROR) {
                 status = tmpStatus;
             }
diff --git a/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
index f7ddb35..d752485 100644
--- a/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
@@ -207,15 +207,18 @@
     return device;
 }
 
-status_t DeviceVector::dump(int fd, const String8 &direction) const
+status_t DeviceVector::dump(int fd, const String8 &tag, int spaces, bool verbose) const
 {
+    if (isEmpty()) {
+        return NO_ERROR;
+    }
     const size_t SIZE = 256;
     char buffer[SIZE];
 
-    snprintf(buffer, SIZE, "\n Available %s devices:\n", direction.string());
+    snprintf(buffer, SIZE, "%*s %s devices:\n", spaces, "", tag.string());
     write(fd, buffer, strlen(buffer));
     for (size_t i = 0; i < size(); i++) {
-        itemAt(i)->dump(fd, 2, i);
+        itemAt(i)->dump(fd, spaces + 4, i, verbose);
     }
     return NO_ERROR;
 }
@@ -263,12 +266,10 @@
 
 void DeviceDescriptor::importAudioPort(const sp<AudioPort> port) {
     AudioPort::importAudioPort(port);
-    mSamplingRate = port->pickSamplingRate();
-    mFormat = port->pickFormat();
-    mChannelMask = port->pickChannelMask();
+    port->pickAudioProfile(mSamplingRate, mChannelMask, mFormat);
 }
 
-status_t DeviceDescriptor::dump(int fd, int spaces, int index) const
+status_t DeviceDescriptor::dump(int fd, int spaces, int index, bool verbose) const
 {
     const size_t SIZE = 256;
     char buffer[SIZE];
@@ -290,7 +291,7 @@
         result.append(buffer);
     }
     write(fd, result.string(), result.size());
-    AudioPort::dump(fd, spaces);
+    AudioPort::dump(fd, spaces, verbose);
 
     return NO_ERROR;
 }
diff --git a/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp b/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
index 8b11361..dce0890 100644
--- a/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
@@ -43,13 +43,12 @@
 }
 
 status_t HwModule::addOutputProfile(String8 name, const audio_config_t *config,
-                                                  audio_devices_t device, String8 address)
+                                    audio_devices_t device, String8 address)
 {
     sp<IOProfile> profile = new OutputProfile(name);
 
-    profile->mSamplingRates.add(config->sample_rate);
-    profile->mChannelMasks.add(config->channel_mask);
-    profile->mFormats.add(config->format);
+    profile->addAudioProfile(new AudioProfile(config->format, config->channel_mask,
+                                              config->sample_rate));
 
     sp<DeviceDescriptor> devDesc = new DeviceDescriptor(device);
     devDesc->mAddress = address;
@@ -105,13 +104,11 @@
 }
 
 status_t HwModule::addInputProfile(String8 name, const audio_config_t *config,
-                                                  audio_devices_t device, String8 address)
+                                   audio_devices_t device, String8 address)
 {
     sp<IOProfile> profile = new InputProfile(name);
-
-    profile->mSamplingRates.add(config->sample_rate);
-    profile->mChannelMasks.add(config->channel_mask);
-    profile->mFormats.add(config->format);
+    profile->addAudioProfile(new AudioProfile(config->format, config->channel_mask,
+                                              config->sample_rate));
 
     sp<DeviceDescriptor> devDesc = new DeviceDescriptor(device);
     devDesc->mAddress = address;
@@ -165,12 +162,7 @@
             mInputProfiles[i]->dump(fd);
         }
     }
-    if (mDeclaredDevices.size()) {
-        write(fd, "  - devices:\n", strlen("  - devices:\n"));
-        for (size_t i = 0; i < mDeclaredDevices.size(); i++) {
-            mDeclaredDevices[i]->dump(fd, 4, i);
-        }
-    }
+    mDeclaredDevices.dump(fd, String8("Declared"),  2, true);
 }
 
 sp <HwModule> HwModuleCollection::getModuleFromName(const char *name) const
diff --git a/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp b/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp
index d41d239..fe38f54 100644
--- a/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp
@@ -20,6 +20,7 @@
 #include "IOProfile.h"
 #include "HwModule.h"
 #include "AudioGain.h"
+#include "TypeConverter.h"
 
 namespace android {
 
@@ -63,37 +64,25 @@
         }
     }
 
-    if (samplingRate == 0) {
-         return false;
-    }
-    uint32_t myUpdatedSamplingRate = samplingRate;
-    if (isPlaybackThread && checkExactSamplingRate(samplingRate) != NO_ERROR) {
-         return false;
-    }
-    if (isRecordThread && checkCompatibleSamplingRate(samplingRate, &myUpdatedSamplingRate) !=
-            NO_ERROR) {
+    if (samplingRate == 0 || !audio_is_valid_format(format) ||
+            (isPlaybackThread && (!audio_is_output_channel(channelMask))) ||
+            (isRecordThread && (!audio_is_input_channel(channelMask)))) {
          return false;
     }
 
-    if (!audio_is_valid_format(format)) {
-        return false;
-    }
-    if (isPlaybackThread && checkExactFormat(format) != NO_ERROR) {
-        return false;
-    }
     audio_format_t myUpdatedFormat = format;
-    if (isRecordThread && checkCompatibleFormat(format, &myUpdatedFormat) != NO_ERROR) {
-        return false;
-    }
-
-    if (isPlaybackThread && (!audio_is_output_channel(channelMask) ||
-            checkExactChannelMask(channelMask) != NO_ERROR)) {
-        return false;
-    }
     audio_channel_mask_t myUpdatedChannelMask = channelMask;
-    if (isRecordThread && (!audio_is_input_channel(channelMask) ||
-            checkCompatibleChannelMask(channelMask, &myUpdatedChannelMask) != NO_ERROR)) {
-        return false;
+    uint32_t myUpdatedSamplingRate = samplingRate;
+    if (isRecordThread)
+    {
+        if (checkCompatibleAudioProfile(
+                myUpdatedSamplingRate, myUpdatedChannelMask, myUpdatedFormat) != NO_ERROR) {
+            return false;
+        }
+    } else {
+        if (checkExactAudioProfile(samplingRate, channelMask, format) != NO_ERROR) {
+            return false;
+        }
     }
 
     if (isPlaybackThread && (getFlags() & flags) != flags) {
@@ -130,37 +119,13 @@
 
     snprintf(buffer, SIZE, "    - flags: 0x%04x\n", getFlags());
     result.append(buffer);
-    snprintf(buffer, SIZE, "    - devices:\n");
-    result.append(buffer);
     write(fd, result.string(), result.size());
-    for (size_t i = 0; i < mSupportedDevices.size(); i++) {
-        mSupportedDevices[i]->dump(fd, 6, i);
-    }
+    mSupportedDevices.dump(fd, String8("- Supported"), 2, false);
 }
 
 void IOProfile::log()
 {
-    const size_t SIZE = 256;
-    char buffer[SIZE];
-    String8 result;
-
-    ALOGV("    - sampling rates: ");
-    for (size_t i = 0; i < mSamplingRates.size(); i++) {
-        ALOGV("  %d", mSamplingRates[i]);
-    }
-
-    ALOGV("    - channel masks: ");
-    for (size_t i = 0; i < mChannelMasks.size(); i++) {
-        ALOGV("  0x%04x", mChannelMasks[i]);
-    }
-
-    ALOGV("    - formats: ");
-    for (size_t i = 0; i < mFormats.size(); i++) {
-        ALOGV("  0x%08x", mFormats[i]);
-    }
-
-    ALOGV("    - devices: 0x%04x\n", mSupportedDevices.types());
-    ALOGV("    - flags: 0x%04x\n", getFlags());
+    // @TODO: forward log to AudioPort
 }
 
 }; // namespace android
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 322e599..11dabae 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -2091,8 +2091,8 @@
 
     write(fd, result.string(), result.size());
 
-    mAvailableOutputDevices.dump(fd, String8("output"));
-    mAvailableInputDevices.dump(fd, String8("input"));
+    mAvailableOutputDevices.dump(fd, String8("Available output"));
+    mAvailableInputDevices.dump(fd, String8("Available input"));
     mHwModules.dump(fd);
     mOutputs.dump(fd);
     mInputs.dump(fd);
@@ -3502,55 +3502,14 @@
                     mpClientInterface->setParameters(output, String8(param));
                     free(param);
                 }
-
-                // Here is where we step through and resolve any "dynamic" fields
-                String8 reply;
-                char *value;
-                if (profile->mSamplingRates[0] == 0) {
-                    reply = mpClientInterface->getParameters(output,
-                                            String8(AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES));
-                    ALOGV("checkOutputsForDevice() supported sampling rates %s",
-                              reply.string());
-                    value = strpbrk((char *)reply.string(), "=");
-                    if (value != NULL) {
-                        profile->setSupportedSamplingRates(samplingRatesFromString(value + 1));
-                    }
-                }
-                if (profile->mFormats[0] == AUDIO_FORMAT_DEFAULT) {
-                    reply = mpClientInterface->getParameters(output,
-                                                   String8(AUDIO_PARAMETER_STREAM_SUP_FORMATS));
-                    ALOGV("checkOutputsForDevice() supported formats %s",
-                              reply.string());
-                    value = strpbrk((char *)reply.string(), "=");
-                    if (value != NULL) {
-                        profile->setSupportedFormats(formatsFromString(value + 1));
-                    }
-                }
-                if (profile->mChannelMasks[0] == 0) {
-                    reply = mpClientInterface->getParameters(output,
-                                                  String8(AUDIO_PARAMETER_STREAM_SUP_CHANNELS));
-                    ALOGV("checkOutputsForDevice() supported channel masks %s",
-                              reply.string());
-                    value = strpbrk((char *)reply.string(), "=");
-                    if (value != NULL) {
-                        profile->setSupportedChannelMasks(outputChannelMasksFromString(value + 1));
-                    }
-                }
-                if (((profile->mSamplingRates[0] == 0) &&
-                         (profile->mSamplingRates.size() < 2)) ||
-                     ((profile->mFormats[0] == AUDIO_FORMAT_DEFAULT) &&
-                         (profile->mFormats.size() < 2)) ||
-                     ((profile->mChannelMasks[0] == 0) &&
-                         (profile->mChannelMasks.size() < 2))) {
+                updateAudioProfiles(output, profile->getAudioProfiles());
+                if (!profile->hasValidAudioProfile()) {
                     ALOGW("checkOutputsForDevice() missing param");
                     mpClientInterface->closeOutput(output);
                     output = AUDIO_IO_HANDLE_NONE;
-                } else if (profile->mSamplingRates[0] == 0 || profile->mFormats[0] == 0 ||
-                            profile->mChannelMasks[0] == 0) {
+                } else if (profile->hasDynamicAudioProfile()) {
                     mpClientInterface->closeOutput(output);
-                    config.sample_rate = profile->pickSamplingRate();
-                    config.channel_mask = profile->pickChannelMask();
-                    config.format = profile->pickFormat();
+                    profile->pickAudioProfile(config.sample_rate, config.channel_mask, config.format);
                     config.offload_info.sample_rate = config.sample_rate;
                     config.offload_info.channel_mask = config.channel_mask;
                     config.offload_info.format = config.format;
@@ -3674,18 +3633,7 @@
                 if (profile->supportDevice(device)) {
                     ALOGV("checkOutputsForDevice(): "
                             "clearing direct output profile %zu on module %zu", j, i);
-                    if (profile->mSamplingRates[0] == 0) {
-                        profile->mSamplingRates.clear();
-                        profile->mSamplingRates.add(0);
-                    }
-                    if (profile->mFormats[0] == AUDIO_FORMAT_DEFAULT) {
-                        profile->mFormats.clear();
-                        profile->mFormats.add(AUDIO_FORMAT_DEFAULT);
-                    }
-                    if (profile->mChannelMasks[0] == 0) {
-                        profile->mChannelMasks.clear();
-                        profile->mChannelMasks.add(0);
-                    }
+                    profile->clearAudioProfiles();
                 }
             }
         }
@@ -3791,42 +3739,8 @@
                     mpClientInterface->setParameters(input, String8(param));
                     free(param);
                 }
-
-                // Here is where we step through and resolve any "dynamic" fields
-                String8 reply;
-                char *value;
-                if (profile->mSamplingRates[0] == 0) {
-                    reply = mpClientInterface->getParameters(input,
-                                            String8(AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES));
-                    ALOGV("checkInputsForDevice() direct input sup sampling rates %s",
-                              reply.string());
-                    value = strpbrk((char *)reply.string(), "=");
-                    if (value != NULL) {
-                        profile->setSupportedSamplingRates(samplingRatesFromString(value + 1));
-                    }
-                }
-                if (profile->mFormats[0] == AUDIO_FORMAT_DEFAULT) {
-                    reply = mpClientInterface->getParameters(input,
-                                                   String8(AUDIO_PARAMETER_STREAM_SUP_FORMATS));
-                    ALOGV("checkInputsForDevice() direct input sup formats %s", reply.string());
-                    value = strpbrk((char *)reply.string(), "=");
-                    if (value != NULL) {
-                        profile->setSupportedFormats(formatsFromString(value + 1));
-                    }
-                }
-                if (profile->mChannelMasks[0] == 0) {
-                    reply = mpClientInterface->getParameters(input,
-                                                  String8(AUDIO_PARAMETER_STREAM_SUP_CHANNELS));
-                    ALOGV("checkInputsForDevice() direct input sup channel masks %s",
-                              reply.string());
-                    value = strpbrk((char *)reply.string(), "=");
-                    if (value != NULL) {
-                        profile->setSupportedChannelMasks(inputChannelMasksFromString(value + 1));
-                    }
-                }
-                if (((profile->mSamplingRates[0] == 0) && (profile->mSamplingRates.size() < 2)) ||
-                     ((profile->mFormats[0] == 0) && (profile->mFormats.size() < 2)) ||
-                     ((profile->mChannelMasks[0] == 0) && (profile->mChannelMasks.size() < 2))) {
+                updateAudioProfiles(input, profile->getAudioProfiles());
+                if (!profile->hasValidAudioProfile()) {
                     ALOGW("checkInputsForDevice() direct input missing param");
                     mpClientInterface->closeInput(input);
                     input = AUDIO_IO_HANDLE_NONE;
@@ -3877,18 +3791,7 @@
                 if (profile->supportDevice(device)) {
                     ALOGV("checkInputsForDevice(): clearing direct input profile %zu on module %zu",
                           profile_index, module_index);
-                    if (profile->mSamplingRates[0] == 0) {
-                        profile->mSamplingRates.clear();
-                        profile->mSamplingRates.add(0);
-                    }
-                    if (profile->mFormats[0] == AUDIO_FORMAT_DEFAULT) {
-                        profile->mFormats.clear();
-                        profile->mFormats.add(AUDIO_FORMAT_DEFAULT);
-                    }
-                    if (profile->mChannelMasks[0] == 0) {
-                        profile->mChannelMasks.clear();
-                        profile->mChannelMasks.add(0);
-                    }
+                    profile->clearAudioProfiles();
                 }
             }
         }
@@ -5148,5 +5051,51 @@
     }
 }
 
+void AudioPolicyManager::updateAudioProfiles(audio_io_handle_t ioHandle,
+                                             AudioProfileVector &profiles)
+{
+    String8 reply;
+    char *value;
+    // Format MUST be checked first to update the list of AudioProfile
+    if (profiles.hasDynamicFormat()) {
+        reply = mpClientInterface->getParameters(ioHandle,
+                                                 String8(AUDIO_PARAMETER_STREAM_SUP_FORMATS));
+        ALOGV("%s: supported formats %s", __FUNCTION__, reply.string());
+        value = strpbrk((char *)reply.string(), "=");
+        if (value == NULL) {
+            ALOGE("%s: failed to retrieve format, bailing out", __FUNCTION__);
+            return;
+        }
+        profiles.setFormats(formatsFromString(value + 1));
+    }
+    const FormatVector &supportedFormats = profiles.getSupportedFormats();
+
+    for(size_t formatIndex = 0; formatIndex < supportedFormats.size(); formatIndex++) {
+        audio_format_t format = supportedFormats[formatIndex];
+        AudioParameter requestedParameters;
+        requestedParameters.addInt(String8(AUDIO_PARAMETER_STREAM_FORMAT), format);
+
+        if (profiles.hasDynamicRateFor(format)) {
+            reply = mpClientInterface->getParameters(ioHandle,
+                                                     requestedParameters.toString() + ";" +
+                                                     AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES);
+            ALOGV("%s: supported sampling rates %s", __FUNCTION__, reply.string());
+            value = strpbrk((char *)reply.string(), "=");
+            if (value != NULL) {
+                profiles.setSampleRatesFor(samplingRatesFromString(value + 1), format);
+            }
+        }
+        if (profiles.hasDynamicChannelsFor(format)) {
+            reply = mpClientInterface->getParameters(ioHandle,
+                                                     requestedParameters.toString() + ";" +
+                                                     AUDIO_PARAMETER_STREAM_SUP_CHANNELS);
+            ALOGV("%s: supported channel masks %s", __FUNCTION__, reply.string());
+            value = strpbrk((char *)reply.string(), "=");
+            if (value != NULL) {
+                profiles.setChannelsFor(channelMasksFromString(value + 1), format);
+            }
+        }
+    }
+}
 
 }; // namespace android
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index 38cf67b..59163ca 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -587,6 +587,9 @@
         // Audio Policy Engine Interface.
         AudioPolicyManagerInterface *mEngine;
 private:
+        // If any, resolve any "dynamic" fields of an Audio Profiles collection
+        void updateAudioProfiles(audio_io_handle_t ioHandle, AudioProfileVector &profiles);
+
         // updates device caching and output for streams that can influence the
         //    routing of notifications
         void handleNotificationRoutingForStream(audio_stream_type_t stream);