Merge "Add getDirectProfilesForAttributes"
diff --git a/media/libaudioclient/AudioSystem.cpp b/media/libaudioclient/AudioSystem.cpp
index b3c82787..86139c7 100644
--- a/media/libaudioclient/AudioSystem.cpp
+++ b/media/libaudioclient/AudioSystem.cpp
@@ -2314,6 +2314,28 @@
     return NO_ERROR;
 }
 
+status_t AudioSystem::getDirectProfilesForAttributes(const audio_attributes_t* attr,
+                                                std::vector<audio_profile>* audioProfiles) {
+    if (attr == nullptr) {
+        return BAD_VALUE;
+    }
+
+    const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+    if (aps == 0) {
+        return PERMISSION_DENIED;
+    }
+
+    media::AudioAttributesInternal attrAidl = VALUE_OR_RETURN_STATUS(
+            legacy2aidl_audio_attributes_t_AudioAttributesInternal(*attr));
+
+    std::vector<media::audio::common::AudioProfile> audioProfilesAidl;
+    RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
+            aps->getDirectProfilesForAttributes(attrAidl, &audioProfilesAidl)));
+    *audioProfiles = VALUE_OR_RETURN_STATUS(convertContainer<std::vector<audio_profile>>(
+                    audioProfilesAidl, aidl2legacy_AudioProfile_audio_profile, false /*isInput*/));
+
+    return NO_ERROR;
+}
 
 class CaptureStateListenerImpl : public media::BnCaptureStateListener,
                                  public IBinder::DeathRecipient {
diff --git a/media/libaudioclient/aidl/android/media/IAudioPolicyService.aidl b/media/libaudioclient/aidl/android/media/IAudioPolicyService.aidl
index 7895ae3..b1a9d94 100644
--- a/media/libaudioclient/aidl/android/media/IAudioPolicyService.aidl
+++ b/media/libaudioclient/aidl/android/media/IAudioPolicyService.aidl
@@ -48,6 +48,7 @@
 import android.media.audio.common.AudioDeviceDescription;
 import android.media.audio.common.AudioFormatDescription;
 import android.media.audio.common.AudioMode;
+import android.media.audio.common.AudioProfile;
 import android.media.audio.common.AudioOffloadInfo;
 import android.media.audio.common.AudioSource;
 import android.media.audio.common.AudioStreamType;
@@ -381,6 +382,12 @@
     /**
      * Query how the direct playback is currently supported on the device.
      */
-     AudioDirectMode getDirectPlaybackSupport(in AudioAttributesInternal attr,
+    AudioDirectMode getDirectPlaybackSupport(in AudioAttributesInternal attr,
                                               in AudioConfig config);
+
+    /**
+     * Query audio profiles available for direct playback on the current output device(s)
+     * for the specified audio attributes.
+     */
+    AudioProfile[] getDirectProfilesForAttributes(in AudioAttributesInternal attr);
 }
diff --git a/media/libaudioclient/include/media/AidlConversionUtil.h b/media/libaudioclient/include/media/AidlConversionUtil.h
index dfabd55..227d823 100644
--- a/media/libaudioclient/include/media/AidlConversionUtil.h
+++ b/media/libaudioclient/include/media/AidlConversionUtil.h
@@ -123,6 +123,21 @@
 }
 
 /**
+ * A generic template that helps convert containers of convertible types
+ * using an item conversion function with an additional parameter.
+ */
+template<typename OutputContainer, typename InputContainer, typename Func, typename Parameter>
+ConversionResult<OutputContainer>
+convertContainer(const InputContainer& input, const Func& itemConversion, const Parameter& param) {
+    OutputContainer output;
+    auto ins = std::inserter(output, output.begin());
+    for (const auto& item : input) {
+        *ins = VALUE_OR_RETURN(itemConversion(item, param));
+    }
+    return output;
+}
+
+/**
  * A generic template that helps to "zip" two input containers of the same size
  * into a single vector of converted types. The conversion function must
  * thus accept two arguments.
diff --git a/media/libaudioclient/include/media/AudioSystem.h b/media/libaudioclient/include/media/AudioSystem.h
index 11eb070..09127fb 100644
--- a/media/libaudioclient/include/media/AudioSystem.h
+++ b/media/libaudioclient/include/media/AudioSystem.h
@@ -550,6 +550,16 @@
                                              audio_direct_mode_t *directMode);
 
 
+    /**
+     * Query which direct audio profiles are available for the specified audio attributes.
+     * @param attr audio attributes describing the playback use case
+     * @param audioProfiles out: a vector of audio profiles
+     * @return NO_ERROR in case of success, DEAD_OBJECT, NO_INIT, BAD_VALUE, PERMISSION_DENIED
+     *         in case of error.
+     */
+    static status_t getDirectProfilesForAttributes(const audio_attributes_t* attr,
+                                            std::vector<audio_profile>* audioProfiles);
+
     // A listener for capture state changes.
     class CaptureStateListener : public virtual RefBase {
     public:
diff --git a/media/libaudiofoundation/AudioProfile.cpp b/media/libaudiofoundation/AudioProfile.cpp
index 9a67bb7..734fa9c 100644
--- a/media/libaudiofoundation/AudioProfile.cpp
+++ b/media/libaudiofoundation/AudioProfile.cpp
@@ -154,6 +154,26 @@
 
 ConversionResult<AudioProfile::Aidl>
 AudioProfile::toParcelable(bool isInput) const {
+    media::audio::common::AudioProfile parcelable = VALUE_OR_RETURN(toCommonParcelable(isInput));
+    media::AudioProfileSys parcelableSys;
+    parcelableSys.isDynamicFormat = mIsDynamicFormat;
+    parcelableSys.isDynamicChannels = mIsDynamicChannels;
+    parcelableSys.isDynamicRate = mIsDynamicRate;
+    return std::make_pair(parcelable, parcelableSys);
+}
+
+ConversionResult<sp<AudioProfile>> AudioProfile::fromParcelable(
+        const AudioProfile::Aidl& aidl, bool isInput) {
+    sp<AudioProfile> legacy = VALUE_OR_RETURN(fromCommonParcelable(aidl.first, isInput));
+    const auto& parcelableSys = aidl.second;
+    legacy->mIsDynamicFormat = parcelableSys.isDynamicFormat;
+    legacy->mIsDynamicChannels = parcelableSys.isDynamicChannels;
+    legacy->mIsDynamicRate = parcelableSys.isDynamicRate;
+    return legacy;
+}
+
+ConversionResult<media::audio::common::AudioProfile>
+AudioProfile::toCommonParcelable(bool isInput) const {
     media::audio::common::AudioProfile parcelable;
     parcelable.name = mName;
     parcelable.format = VALUE_OR_RETURN(
@@ -164,44 +184,35 @@
     // of using 'legacy2aidl_audio_profile_AudioProfile' from AidlConversion.
     parcelable.channelMasks = VALUE_OR_RETURN(
             convertContainer<std::vector<AudioChannelLayout>>(
-                    mChannelMasks,
-                    [isInput](audio_channel_mask_t m) {
-                        return legacy2aidl_audio_channel_mask_t_AudioChannelLayout(m, isInput);
-                    }));
+            mChannelMasks,
+            [isInput](audio_channel_mask_t m) {
+                return legacy2aidl_audio_channel_mask_t_AudioChannelLayout(m, isInput);
+            }));
     parcelable.sampleRates = VALUE_OR_RETURN(
             convertContainer<std::vector<int32_t>>(mSamplingRates,
                                                    convertIntegral<int32_t, uint32_t>));
     parcelable.encapsulationType = VALUE_OR_RETURN(
             legacy2aidl_audio_encapsulation_type_t_AudioEncapsulationType(mEncapsulationType));
-    media::AudioProfileSys parcelableSys;
-    parcelableSys.isDynamicFormat = mIsDynamicFormat;
-    parcelableSys.isDynamicChannels = mIsDynamicChannels;
-    parcelableSys.isDynamicRate = mIsDynamicRate;
-    return std::make_pair(parcelable, parcelableSys);
+    return parcelable;
 }
 
-ConversionResult<sp<AudioProfile>> AudioProfile::fromParcelable(
-        const AudioProfile::Aidl& aidl, bool isInput) {
+ConversionResult<sp<AudioProfile>> AudioProfile::fromCommonParcelable(
+        const media::audio::common::AudioProfile& aidl, bool isInput) {
     sp<AudioProfile> legacy = new AudioProfile();
-    const auto& parcelable = aidl.first;
-    legacy->mName = parcelable.name;
+    legacy->mName = aidl.name;
     legacy->mFormat = VALUE_OR_RETURN(
-            aidl2legacy_AudioFormatDescription_audio_format_t(parcelable.format));
+            aidl2legacy_AudioFormatDescription_audio_format_t(aidl.format));
     legacy->mChannelMasks = VALUE_OR_RETURN(
-            convertContainer<ChannelMaskSet>(parcelable.channelMasks,
-                    [isInput](const AudioChannelLayout& l) {
-                        return aidl2legacy_AudioChannelLayout_audio_channel_mask_t(l, isInput);
-                    }));
+            convertContainer<ChannelMaskSet>(aidl.channelMasks,
+            [isInput](const AudioChannelLayout& l) {
+                return aidl2legacy_AudioChannelLayout_audio_channel_mask_t(l, isInput);
+            }));
     legacy->mSamplingRates = VALUE_OR_RETURN(
-            convertContainer<SampleRateSet>(parcelable.sampleRates,
+            convertContainer<SampleRateSet>(aidl.sampleRates,
                                             convertIntegral<uint32_t, int32_t>));
     legacy->mEncapsulationType = VALUE_OR_RETURN(
             aidl2legacy_AudioEncapsulationType_audio_encapsulation_type_t(
-                    parcelable.encapsulationType));
-    const auto& parcelableSys = aidl.second;
-    legacy->mIsDynamicFormat = parcelableSys.isDynamicFormat;
-    legacy->mIsDynamicChannels = parcelableSys.isDynamicChannels;
-    legacy->mIsDynamicRate = parcelableSys.isDynamicRate;
+                    aidl.encapsulationType));
     return legacy;
 }
 
@@ -215,6 +226,16 @@
     return legacy->toParcelable(isInput);
 }
 
+ConversionResult<sp<AudioProfile>>
+aidl2legacy_AudioProfile_common(const media::audio::common::AudioProfile& aidl, bool isInput) {
+    return AudioProfile::fromCommonParcelable(aidl, isInput);
+}
+
+ConversionResult<media::audio::common::AudioProfile>
+legacy2aidl_AudioProfile_common(const sp<AudioProfile>& legacy, bool isInput) {
+    return legacy->toCommonParcelable(isInput);
+}
+
 ssize_t AudioProfileVector::add(const sp<AudioProfile> &profile)
 {
     ssize_t index = size();
diff --git a/media/libaudiofoundation/include/media/AudioProfile.h b/media/libaudiofoundation/include/media/AudioProfile.h
index d7cddb7..c3a0fb2 100644
--- a/media/libaudiofoundation/include/media/AudioProfile.h
+++ b/media/libaudiofoundation/include/media/AudioProfile.h
@@ -85,6 +85,11 @@
     static ConversionResult<sp<AudioProfile>> fromParcelable(
             const Aidl& aidl, bool isInput);
 
+    ConversionResult<media::audio::common::AudioProfile>
+            toCommonParcelable(bool isInput) const;
+    static ConversionResult<sp<AudioProfile>> fromCommonParcelable(
+        const media::audio::common::AudioProfile& aidl, bool isInput);
+
 private:
 
     std::string  mName;
@@ -108,6 +113,11 @@
 ConversionResult<AudioProfile::Aidl>
 legacy2aidl_AudioProfile(const sp<AudioProfile>& legacy, bool isInput);
 
+ConversionResult<sp<AudioProfile>>
+aidl2legacy_AudioProfile_common(const media::audio::common::AudioProfile& aidl, bool isInput);
+ConversionResult<media::audio::common::AudioProfile>
+legacy2aidl_AudioProfile_common(const sp<AudioProfile>& legacy, bool isInput);
+
 class AudioProfileVector : public std::vector<sp<AudioProfile>>
 {
 public:
diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h
index f6f3b9a..ea958f5 100644
--- a/services/audiopolicy/AudioPolicyInterface.h
+++ b/services/audiopolicy/AudioPolicyInterface.h
@@ -404,8 +404,11 @@
      */
     virtual audio_direct_mode_t getDirectPlaybackSupport(const audio_attributes_t *attr,
                                                          const audio_config_t *config) = 0;
-};
 
+    // retrieves the list of available direct audio profiles for the given audio attributes
+    virtual status_t getDirectProfilesForAttributes(const audio_attributes_t* attr,
+                                                    AudioProfileVector& audioProfiles) = 0;
+};
 
 // Audio Policy client Interface
 class AudioPolicyClientInterface
diff --git a/services/audiopolicy/fuzzer/audiopolicy_fuzzer.cpp b/services/audiopolicy/fuzzer/audiopolicy_fuzzer.cpp
index 654e4bf..dff36e2 100644
--- a/services/audiopolicy/fuzzer/audiopolicy_fuzzer.cpp
+++ b/services/audiopolicy/fuzzer/audiopolicy_fuzzer.cpp
@@ -30,6 +30,7 @@
 #include <libxml/parser.h>
 #include <libxml/xinclude.h>
 #include <media/AudioPolicy.h>
+#include <media/AudioProfile.h>
 #include <media/PatchBuilder.h>
 #include <media/RecordingActivityTracker.h>
 
@@ -842,6 +843,7 @@
     void process() override;
 
     void fuzzGetDirectPlaybackSupport();
+    void fuzzGetDirectProfilesForAttributes();
 
    protected:
     void setDeviceConnectionState();
@@ -909,11 +911,25 @@
     }
 }
 
+void AudioPolicyManagerFuzzerDeviceConnection::fuzzGetDirectProfilesForAttributes() {
+    const uint32_t numTestCases = mFdp->ConsumeIntegralInRange<uint32_t>(1, 10);
+    for (int i = 0; i < numTestCases; ++i) {
+        AudioProfileVector audioProfiles;
+        audio_attributes_t attr = AUDIO_ATTRIBUTES_INITIALIZER;
+        attr.content_type = getValueFromVector<audio_content_type_t>(mFdp, kAudioContentTypes);
+        attr.usage = getValueFromVector<audio_usage_t>(mFdp, kAudioUsages);
+        attr.source = getValueFromVector<audio_source_t>(mFdp, kAudioSources);
+        attr.flags = getValueFromVector<audio_flags_mask_t>(mFdp, kAudioFlagMasks);
+        mManager->getDirectProfilesForAttributes(&attr, audioProfiles);
+    }
+}
+
 void AudioPolicyManagerFuzzerDeviceConnection::process() {
     if (initialize()) {
         setDeviceConnectionState();
         explicitlyRoutingAfterConnection();
         fuzzGetDirectPlaybackSupport();
+        fuzzGetDirectProfilesForAttributes();
         fuzzPatchCreation();
     }
 }
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index ee2c0f7..48176da 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -3833,6 +3833,47 @@
     return directMode;
 }
 
+status_t AudioPolicyManager::getDirectProfilesForAttributes(const audio_attributes_t* attr,
+                                                AudioProfileVector& audioProfilesVector) {
+    AudioDeviceTypeAddrVector devices;
+    status_t status = getDevicesForAttributes(*attr, &devices);
+    if (status != OK) {
+        return status;
+    }
+    ALOGV("%s: found %zu output devices for attributes.", __func__, devices.size());
+    if (devices.empty()) {
+        return OK; // no output devices for the attributes
+    }
+
+    for (const auto& hwModule : mHwModules) {
+        for (const auto& curProfile : hwModule->getOutputProfiles()) {
+            if (!curProfile->asAudioPort()->isDirectOutput()) {
+                continue;
+            }
+            // Allow only profiles that support all the available and routed devices
+            DeviceVector supportedDevices = curProfile->getSupportedDevices();
+            if (supportedDevices.getDevicesFromDeviceTypeAddrVec(devices).size()
+                    != devices.size()) {
+                continue;
+            }
+
+            const auto audioProfiles = curProfile->asAudioPort()->getAudioProfiles();
+            ALOGV("%s: found direct profile (%s) with %zu audio profiles.",
+                __func__, curProfile->getTagName().c_str(), audioProfiles.size());
+            for (const auto& audioProfile : audioProfiles) {
+                if (audioProfile->isValid() && !audioProfilesVector.contains(audioProfile)
+                // TODO - why do we have same PCM format with both dynamic and non dynamic format
+                    && audioProfile->isDynamicFormat()) {
+                    ALOGV("%s: adding audio profile with encoding (%d).",
+                        __func__, audioProfile->getFormat());
+                    audioProfilesVector.add(audioProfile);
+                }
+            }
+        }
+    }
+    return NO_ERROR;
+}
+
 status_t AudioPolicyManager::listAudioPorts(audio_port_role_t role,
                                             audio_port_type_t type,
                                             unsigned int *num_ports,
@@ -6305,6 +6346,7 @@
     return devices.types();
 }
 
+// TODO - consider MSD routes b/214971780
 status_t AudioPolicyManager::getDevicesForAttributes(
         const audio_attributes_t &attr, AudioDeviceTypeAddrVector *devices) {
     if (devices == nullptr) {
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index dd69295..b4fc4d4 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -371,6 +371,9 @@
         virtual audio_direct_mode_t getDirectPlaybackSupport(const audio_attributes_t *attr,
                                                              const audio_config_t *config);
 
+        virtual status_t getDirectProfilesForAttributes(const audio_attributes_t* attr,
+                                                         AudioProfileVector& audioProfiles);
+
         bool isCallScreenModeSupported() override;
 
         void onNewAudioModulesAvailable() override;
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index a30768a..3929e55 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -2372,4 +2372,24 @@
     return Status::ok();
 }
 
+Status AudioPolicyService::getDirectProfilesForAttributes(
+                                const media::AudioAttributesInternal& attrAidl,
+                                std::vector<media::audio::common::AudioProfile>* _aidl_return) {
+   if (mAudioPolicyManager == nullptr) {
+        return binderStatusFromStatusT(NO_INIT);
+    }
+    audio_attributes_t attr = VALUE_OR_RETURN_BINDER_STATUS(
+            aidl2legacy_AudioAttributesInternal_audio_attributes_t(attrAidl));
+    AudioProfileVector audioProfiles;
+
+    Mutex::Autolock _l(mLock);
+    RETURN_IF_BINDER_ERROR(binderStatusFromStatusT(
+            mAudioPolicyManager->getDirectProfilesForAttributes(&attr, audioProfiles)));
+    *_aidl_return = VALUE_OR_RETURN_BINDER_STATUS(
+            convertContainer<std::vector<media::audio::common::AudioProfile>>(
+                audioProfiles, legacy2aidl_AudioProfile_common, false /*isInput*/));
+
+    return Status::ok();
+}
+
 } // namespace android
diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h
index 84b1e50..ba28857 100644
--- a/services/audiopolicy/service/AudioPolicyService.h
+++ b/services/audiopolicy/service/AudioPolicyService.h
@@ -276,6 +276,9 @@
                                             const AudioConfig& config,
                                             media::AudioDirectMode* _aidl_return) override;
 
+    binder::Status getDirectProfilesForAttributes(const media::AudioAttributesInternal& attr,
+                        std::vector<media::audio::common::AudioProfile>* _aidl_return) override;
+
     status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) override;
 
     // IBinder::DeathRecipient
diff --git a/services/audiopolicy/tests/AudioPolicyTestManager.h b/services/audiopolicy/tests/AudioPolicyTestManager.h
index 9d0d558..ff06937 100644
--- a/services/audiopolicy/tests/AudioPolicyTestManager.h
+++ b/services/audiopolicy/tests/AudioPolicyTestManager.h
@@ -34,6 +34,7 @@
     using AudioPolicyManager::setMsdOutputPatches;
     using AudioPolicyManager::getAudioPatches;
     using AudioPolicyManager::getDirectPlaybackSupport;
+    using AudioPolicyManager::getDirectProfilesForAttributes;
     uint32_t getAudioPortGeneration() const { return mAudioPortGeneration; }
 };