Add getDirectProfilesForAttributes
Allows any app to query AudioManager on the available direct
AudioProfiles for the specified AudioAttributes. Only the active paths
that will be actually used to output sound are returned.
go/audio-route-t
Bug: 190810951
Bug: 202253203
Test: atest android.media.audio.cts.DirectAudioProfilesForAttributesTest
Test: audiopolicy_fuzzer
Change-Id: Idf3f6ddc9896301fa9e546b1221844853473b3e6
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: