Support setting preferred mixer attributes for USB devices.
This is part of USB audio improvement. With setting mixer attributes,
apps will be able to choose the best mixer attributes for their
playback. This can help improve latency and audio experience.
Bug: 239435816
Test: atest AudioManagerTest
Test: atest audiopolicy_tests
Test: Manually
Change-Id: Ifd1e8e35f94dab309eabe879d20ae0358038a4bf
diff --git a/media/libaudioclient/Android.bp b/media/libaudioclient/Android.bp
index df3dec7..b82754c 100644
--- a/media/libaudioclient/Android.bp
+++ b/media/libaudioclient/Android.bp
@@ -392,6 +392,8 @@
srcs: [
"aidl/android/media/AudioAttributesEx.aidl",
"aidl/android/media/AudioMix.aidl",
+ "aidl/android/media/AudioMixerAttributesInternal.aidl",
+ "aidl/android/media/AudioMixerBehavior.aidl",
"aidl/android/media/AudioMixCallbackFlag.aidl",
"aidl/android/media/AudioMixMatchCriterion.aidl",
"aidl/android/media/AudioMixMatchCriterionValue.aidl",
diff --git a/media/libaudioclient/AudioSystem.cpp b/media/libaudioclient/AudioSystem.cpp
index fa9239f..7309cad 100644
--- a/media/libaudioclient/AudioSystem.cpp
+++ b/media/libaudioclient/AudioSystem.cpp
@@ -34,6 +34,7 @@
#include <system/audio.h>
#include <android/media/GetInputForAttrResponse.h>
+#include <android/media/AudioMixerAttributesInternal.h>
#define VALUE_OR_RETURN_BINDER_STATUS(x) \
({ auto _tmp = (x); \
@@ -2538,6 +2539,84 @@
return af->getAAudioHardwareBurstMinUsec();
}
+status_t AudioSystem::getSupportedMixerAttributes(
+ audio_port_handle_t portId, std::vector<audio_mixer_attributes_t> *mixerAttrs) {
+ const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+ if (aps == nullptr) {
+ return PERMISSION_DENIED;
+ }
+
+ int32_t portIdAidl = VALUE_OR_RETURN_STATUS(legacy2aidl_audio_port_handle_t_int32_t(portId));
+ std::vector<media::AudioMixerAttributesInternal> _aidlReturn;
+ RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
+ aps->getSupportedMixerAttributes(portIdAidl, &_aidlReturn)));
+ *mixerAttrs = VALUE_OR_RETURN_STATUS(
+ convertContainer<std::vector<audio_mixer_attributes_t>>(
+ _aidlReturn,
+ aidl2legacy_AudioMixerAttributesInternal_audio_mixer_attributes_t));
+ return OK;
+}
+
+status_t AudioSystem::setPreferredMixerAttributes(const audio_attributes_t *attr,
+ audio_port_handle_t portId,
+ uid_t uid,
+ const audio_mixer_attributes_t *mixerAttr) {
+ const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+ if (aps == nullptr) {
+ return PERMISSION_DENIED;
+ }
+
+ media::AudioAttributesInternal attrAidl = VALUE_OR_RETURN_STATUS(
+ legacy2aidl_audio_attributes_t_AudioAttributesInternal(*attr));
+ media::AudioMixerAttributesInternal mixerAttrAidl = VALUE_OR_RETURN_STATUS(
+ legacy2aidl_audio_mixer_attributes_t_AudioMixerAttributesInternal(*mixerAttr));
+ int32_t uidAidl = VALUE_OR_RETURN_STATUS(legacy2aidl_uid_t_int32_t(uid));
+ int32_t portIdAidl = VALUE_OR_RETURN_STATUS(legacy2aidl_audio_port_handle_t_int32_t(portId));
+
+ return statusTFromBinderStatus(
+ aps->setPreferredMixerAttributes(attrAidl, portIdAidl, uidAidl, mixerAttrAidl));
+}
+
+status_t AudioSystem::getPreferredMixerAttributes(
+ const audio_attributes_t *attr,
+ audio_port_handle_t portId,
+ std::optional<audio_mixer_attributes_t> *mixerAttr) {
+ const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+ if (aps == nullptr) {
+ return PERMISSION_DENIED;
+ }
+
+ media::AudioAttributesInternal attrAidl = VALUE_OR_RETURN_STATUS(
+ legacy2aidl_audio_attributes_t_AudioAttributesInternal(*attr));
+ int32_t portIdAidl = VALUE_OR_RETURN_STATUS(legacy2aidl_audio_port_handle_t_int32_t(portId));
+ std::optional<media::AudioMixerAttributesInternal> _aidlReturn;
+ RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
+ aps->getPreferredMixerAttributes(attrAidl, portIdAidl, &_aidlReturn)));
+
+ if (_aidlReturn.has_value()) {
+ *mixerAttr = VALUE_OR_RETURN_STATUS(
+ aidl2legacy_AudioMixerAttributesInternal_audio_mixer_attributes_t(
+ _aidlReturn.value()));
+ }
+ return NO_ERROR;
+}
+
+status_t AudioSystem::clearPreferredMixerAttributes(const audio_attributes_t *attr,
+ audio_port_handle_t portId,
+ uid_t uid) {
+ const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+ if (aps == nullptr) {
+ return PERMISSION_DENIED;
+ }
+
+ media::AudioAttributesInternal attrAidl = VALUE_OR_RETURN_STATUS(
+ legacy2aidl_audio_attributes_t_AudioAttributesInternal(*attr));
+ int32_t uidAidl = VALUE_OR_RETURN_STATUS(legacy2aidl_uid_t_int32_t(uid));
+ int32_t portIdAidl = VALUE_OR_RETURN_STATUS(legacy2aidl_audio_port_handle_t_int32_t(portId));
+ return statusTFromBinderStatus(
+ aps->clearPreferredMixerAttributes(attrAidl, portIdAidl, uidAidl));
+}
+
// ---------------------------------------------------------------------------
int AudioSystem::AudioPolicyServiceClient::addAudioPortCallback(
diff --git a/media/libaudioclient/PolicyAidlConversion.cpp b/media/libaudioclient/PolicyAidlConversion.cpp
index 4423eb6..3790000 100644
--- a/media/libaudioclient/PolicyAidlConversion.cpp
+++ b/media/libaudioclient/PolicyAidlConversion.cpp
@@ -472,4 +472,47 @@
return unexpected(BAD_VALUE);
}
+ConversionResult<audio_mixer_behavior_t>
+aidl2legacy_AudioMixerBehavior_audio_mixer_behavior_t(media::AudioMixerBehavior aidl) {
+ switch (aidl) {
+ case media::AudioMixerBehavior::DEFAULT:
+ return AUDIO_MIXER_BEHAVIOR_DEFAULT;
+ case media::AudioMixerBehavior::INVALID:
+ return AUDIO_MIXER_BEHAVIOR_INVALID;
+ }
+ return unexpected(BAD_VALUE);
+}
+ConversionResult<media::AudioMixerBehavior>
+legacy2aidl_audio_mixer_behavior_t_AudioMixerBehavior(audio_mixer_behavior_t legacy) {
+ switch (legacy) {
+ case AUDIO_MIXER_BEHAVIOR_DEFAULT:
+ return media::AudioMixerBehavior::DEFAULT;
+ case AUDIO_MIXER_BEHAVIOR_INVALID:
+ return media::AudioMixerBehavior::INVALID;
+ }
+ return unexpected(BAD_VALUE);
+}
+
+ConversionResult<audio_mixer_attributes_t>
+aidl2legacy_AudioMixerAttributesInternal_audio_mixer_attributes_t(
+ const media::AudioMixerAttributesInternal& aidl) {
+ audio_mixer_attributes_t legacy = AUDIO_MIXER_ATTRIBUTES_INITIALIZER;
+ legacy.config = VALUE_OR_RETURN(
+ aidl2legacy_AudioConfigBase_audio_config_base_t(aidl.config, false /*isInput*/));
+ legacy.mixer_behavior = VALUE_OR_RETURN(
+ aidl2legacy_AudioMixerBehavior_audio_mixer_behavior_t(aidl.mixerBehavior));
+ return legacy;
+}
+ConversionResult<media::AudioMixerAttributesInternal>
+legacy2aidl_audio_mixer_attributes_t_AudioMixerAttributesInternal(
+ const audio_mixer_attributes& legacy) {
+ media::AudioMixerAttributesInternal aidl;
+ aidl.config = VALUE_OR_RETURN(
+ legacy2aidl_audio_config_base_t_AudioConfigBase(legacy.config, false /*isInput*/));
+ aidl.mixerBehavior = VALUE_OR_RETURN(
+ legacy2aidl_audio_mixer_behavior_t_AudioMixerBehavior(legacy.mixer_behavior));
+ return aidl;
+}
+
+
} // namespace android
diff --git a/media/libaudioclient/aidl/android/media/AudioMixerAttributesInternal.aidl b/media/libaudioclient/aidl/android/media/AudioMixerAttributesInternal.aidl
new file mode 100644
index 0000000..ed25060
--- /dev/null
+++ b/media/libaudioclient/aidl/android/media/AudioMixerAttributesInternal.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+
+package android.media;
+
+import android.media.AudioMixerBehavior;
+import android.media.audio.common.AudioConfigBase;
+
+/**
+ * This class is used to contains information about audio mixer.
+ * The "Internal" suffix of this type name is to disambiguate it from the
+ * android.media.AudioMixerAttributes SDK type.
+ *
+ * {@hide}
+ */
+parcelable AudioMixerAttributesInternal {
+ AudioConfigBase config;
+ AudioMixerBehavior mixerBehavior;
+}
diff --git a/media/libaudioclient/aidl/android/media/AudioMixerBehavior.aidl b/media/libaudioclient/aidl/android/media/AudioMixerBehavior.aidl
new file mode 100644
index 0000000..0c0c070
--- /dev/null
+++ b/media/libaudioclient/aidl/android/media/AudioMixerBehavior.aidl
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+
+package android.media;
+
+/**
+ * Defines the mixer behavior that can be used when setting mixer attributes.
+ */
+@Backing(type="int")
+enum AudioMixerBehavior {
+ /**
+ * The mixer behavior is invalid.
+ */
+ INVALID = -1,
+ /**
+ * The mixer behavior that follows platform default behavior, which is mixing audio from
+ * different sources.
+ */
+ DEFAULT = 0,
+}
diff --git a/media/libaudioclient/aidl/android/media/IAudioPolicyService.aidl b/media/libaudioclient/aidl/android/media/IAudioPolicyService.aidl
index 24b59bf..e0db8f9 100644
--- a/media/libaudioclient/aidl/android/media/IAudioPolicyService.aidl
+++ b/media/libaudioclient/aidl/android/media/IAudioPolicyService.aidl
@@ -22,6 +22,7 @@
import android.media.AudioAttributesInternal;
import android.media.AudioDirectMode;
import android.media.AudioMix;
+import android.media.AudioMixerAttributesInternal;
import android.media.AudioOffloadMode;
import android.media.AudioPatch;
import android.media.AudioPolicyDeviceState;
@@ -391,6 +392,60 @@
*/
AudioProfile[] getDirectProfilesForAttributes(in AudioAttributesInternal attr);
+ /**
+ * Return a list of AudioMixerAttributes that can be used to set preferred mixer attributes
+ * for the given device.
+ */
+ AudioMixerAttributesInternal[] getSupportedMixerAttributes(
+ int /* audio_port_handle_t */ portId);
+
+ /**
+ * Set preferred mixer attributes for a given device on a given audio attributes.
+ * When conflicting requests are received, the last request will be honored.
+ * The preferred mixer attributes can only be set when 1) the usage is media, 2) the
+ * given device is currently available, 3) the given device is usb device, 4) the given mixer
+ * attributes is supported by the given device.
+ *
+ * @param attr the audio attributes whose mixer attributes should be set.
+ * @param portId the port id of the device to be routed.
+ * @param uid the uid of the request client. The uid will be used to recognize the ownership for
+ * the preferred mixer attributes. All the playback with same audio attributes from
+ * the same uid will be attached to the mixer with the preferred attributes if the
+ * playback is routed to the given device.
+ * @param mixerAttr the preferred mixer attributes.
+ */
+ void setPreferredMixerAttributes(in AudioAttributesInternal attr,
+ int /* audio_port_handle_t */ portId,
+ int /* uid_t */ uid,
+ in AudioMixerAttributesInternal mixerAttr);
+
+ /**
+ * Get preferred mixer attributes for a given device on a given audio attributes.
+ * Null will be returned if there is no preferred mixer attributes set or it has
+ * been cleared.
+ *
+ * @param attr the audio attributes whose mixer attributes should be set.
+ * @param portId the port id of the device to be routed.
+ */
+ @nullable AudioMixerAttributesInternal getPreferredMixerAttributes(
+ in AudioAttributesInternal attr,
+ int /* audio_port_handle_t */ portId);
+
+ /**
+ * Clear preferred mixer attributes for a given device on a given audio attributes that
+ * is previously set via setPreferredMixerAttributes.
+ *
+ * @param attr the audio attributes whose mixer attributes should be set.
+ * @param portId the port id of the device to be routed.
+ * @param uid the uid of the request client. The uid is used to identify the ownership for the
+ * preferred mixer attributes. The preferred mixer attributes will only be cleared
+ * if the uid is the same as the owner of current preferred mixer attributes.
+ */
+ void clearPreferredMixerAttributes(in AudioAttributesInternal attr,
+ int /* audio_port_handle_t */ portId,
+ int /* uid_t */ uid);
+
+
// When adding a new method, please review and update
// AudioPolicyService.cpp AudioPolicyService::onTransact()
// AudioPolicyService.cpp IAUDIOPOLICYSERVICE_BINDER_METHOD_MACRO_LIST
diff --git a/media/libaudioclient/include/media/AudioSystem.h b/media/libaudioclient/include/media/AudioSystem.h
index a5feb3d..507802d 100644
--- a/media/libaudioclient/include/media/AudioSystem.h
+++ b/media/libaudioclient/include/media/AudioSystem.h
@@ -619,6 +619,19 @@
static status_t getSupportedLatencyModes(audio_io_handle_t output,
std::vector<audio_latency_mode_t>* modes);
+ static status_t getSupportedMixerAttributes(audio_port_handle_t portId,
+ std::vector<audio_mixer_attributes_t> *mixerAttrs);
+ static status_t setPreferredMixerAttributes(const audio_attributes_t *attr,
+ audio_port_handle_t portId,
+ uid_t uid,
+ const audio_mixer_attributes_t *mixerAttr);
+ static status_t getPreferredMixerAttributes(const audio_attributes_t* attr,
+ audio_port_handle_t portId,
+ std::optional<audio_mixer_attributes_t>* mixerAttr);
+ static status_t clearPreferredMixerAttributes(const audio_attributes_t* attr,
+ audio_port_handle_t portId,
+ uid_t uid);
+
// A listener for capture state changes.
class CaptureStateListener : public virtual RefBase {
public:
diff --git a/media/libaudioclient/include/media/PolicyAidlConversion.h b/media/libaudioclient/include/media/PolicyAidlConversion.h
index 54e778e..ed9ddd6 100644
--- a/media/libaudioclient/include/media/PolicyAidlConversion.h
+++ b/media/libaudioclient/include/media/PolicyAidlConversion.h
@@ -22,6 +22,8 @@
#include <system/audio.h>
#include <android/media/AudioMix.h>
+#include <android/media/AudioMixerAttributesInternal.h>
+#include <android/media/AudioMixerBehavior.h>
#include <android/media/AudioMixCallbackFlag.h>
#include <android/media/AudioMixRouteFlag.h>
#include <android/media/AudioMixType.h>
@@ -102,4 +104,16 @@
ConversionResult<media::AudioOffloadMode>
legacy2aidl_audio_offload_mode_t_AudioOffloadMode(audio_offload_mode_t legacy);
+ConversionResult<audio_mixer_behavior_t>
+aidl2legacy_AudioMixerBehavior_audio_mixer_behavior_t(media::AudioMixerBehavior aidl);
+ConversionResult<media::AudioMixerBehavior>
+legacy2aidl_audio_mixer_behavior_t_AudioMixerBehavior(audio_mixer_behavior_t legacy);
+
+ConversionResult<audio_mixer_attributes_t>
+aidl2legacy_AudioMixerAttributesInternal_audio_mixer_attributes_t(
+ const media::AudioMixerAttributesInternal& aidl);
+ConversionResult<media::AudioMixerAttributesInternal>
+legacy2aidl_audio_mixer_attributes_t_AudioMixerAttributesInternal(
+ const audio_mixer_attributes_t& legacy);
+
} // namespace android
diff --git a/media/libaudiofoundation/include/media/AudioContainers.h b/media/libaudiofoundation/include/media/AudioContainers.h
index b6e6c84..bce131c 100644
--- a/media/libaudiofoundation/include/media/AudioContainers.h
+++ b/media/libaudiofoundation/include/media/AudioContainers.h
@@ -31,6 +31,7 @@
using DeviceTypeSet = std::set<audio_devices_t>;
using FormatSet = std::set<audio_format_t>;
using SampleRateSet = std::set<uint32_t>;
+using MixerBehaviorSet = std::set<audio_mixer_behavior_t>;
using FormatVector = std::vector<audio_format_t>;
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index acbbe48..e06d2cd 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -2732,7 +2732,11 @@
}
// abort if start is rejected by audio policy manager
if (status != NO_ERROR) {
- return PERMISSION_DENIED;
+ // Do not replace the error if it is DEAD_OBJECT. When this happens, it indicates
+ // current playback thread is reopened, which may happen when clients set preferred
+ // mixer configuration. Returning DEAD_OBJECT will make the client restore track
+ // immediately.
+ return status == DEAD_OBJECT ? status : PERMISSION_DENIED;
}
#ifdef ADD_BATTERY_DATA
// to track the speaker usage
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 5d6caba..6493e2a 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -1116,10 +1116,10 @@
mObservedUnderruns = playbackThread->getFastTrackUnderruns(mFastIndex);
}
status = playbackThread->addTrack_l(this);
- if (status == INVALID_OPERATION || status == PERMISSION_DENIED) {
+ if (status == INVALID_OPERATION || status == PERMISSION_DENIED || status == DEAD_OBJECT) {
triggerEvents(AudioSystem::SYNC_EVENT_PRESENTATION_COMPLETE);
// restore previous state if start was rejected by policy manager
- if (status == PERMISSION_DENIED) {
+ if (status == PERMISSION_DENIED || status == DEAD_OBJECT) {
mState = state;
}
}
diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h
index b85382e..9c4ab80 100644
--- a/services/audiopolicy/AudioPolicyInterface.h
+++ b/services/audiopolicy/AudioPolicyInterface.h
@@ -407,6 +407,20 @@
// 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;
+
+ virtual status_t getSupportedMixerAttributes(
+ audio_port_handle_t portId, std::vector<audio_mixer_attributes_t>& mixerAttrs) = 0;
+ virtual status_t setPreferredMixerAttributes(
+ const audio_attributes_t* attr,
+ audio_port_handle_t portId,
+ uid_t uid,
+ const audio_mixer_attributes_t* mixerAttributes) = 0;
+ virtual status_t getPreferredMixerAttributes(const audio_attributes_t* attr,
+ audio_port_handle_t portId,
+ audio_mixer_attributes_t* mixerAttributes) = 0;
+ virtual status_t clearPreferredMixerAttributes(const audio_attributes_t* attr,
+ audio_port_handle_t portId,
+ uid_t uid) = 0;
};
// Audio Policy client Interface
diff --git a/services/audiopolicy/common/include/policy.h b/services/audiopolicy/common/include/policy.h
index 3d3e0cf..de8e77f 100644
--- a/services/audiopolicy/common/include/policy.h
+++ b/services/audiopolicy/common/include/policy.h
@@ -246,3 +246,16 @@
}
}
}
+
+/**
+ * Indicates if two given audio output flags are considered as matched, which means that
+ * 1) the `supersetFlags` and `subsetFlags` both contain or both don't contain must match flags and
+ * 2) `supersetFlags` contains all flags from `subsetFlags`.
+ */
+static inline bool audio_output_flags_is_subset(audio_output_flags_t supersetFlags,
+ audio_output_flags_t subsetFlags,
+ uint32_t mustMatchFlags)
+{
+ return ((supersetFlags ^ subsetFlags) & mustMatchFlags) == AUDIO_OUTPUT_FLAG_NONE
+ && (supersetFlags & subsetFlags) == subsetFlags;
+}
diff --git a/services/audiopolicy/common/managerdefinitions/Android.bp b/services/audiopolicy/common/managerdefinitions/Android.bp
index 1f23ae3..92a5628 100644
--- a/services/audiopolicy/common/managerdefinitions/Android.bp
+++ b/services/audiopolicy/common/managerdefinitions/Android.bp
@@ -24,6 +24,7 @@
"src/HwModule.cpp",
"src/IOProfile.cpp",
"src/PolicyAudioPort.cpp",
+ "src/PreferredMixerAttributesInfo.cpp",
"src/Serializer.cpp",
"src/SoundTriggerSession.cpp",
"src/TypeConverter.cpp",
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
index 75fa595..9bece23 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
@@ -440,6 +440,8 @@
void setTracksInvalidatedStatusByStrategy(product_strategy_t strategy);
+ bool isConfigurationMatched(const audio_config_base_t& config, audio_output_flags_t flags);
+
const sp<IOProfile> mProfile; // I/O profile this output derives from
audio_io_handle_t mIoHandle; // output handle
uint32_t mLatency; //
diff --git a/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
index 4adc920..80e098b 100644
--- a/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
@@ -183,6 +183,10 @@
return isSingleDeviceType(mDeviceTypes, deviceType);
}
+ bool onlyContainsDevice(const sp<DeviceDescriptor>& item) const {
+ return this->size() == 1 && contains(item);
+ }
+
bool contains(const sp<DeviceDescriptor>& item) const { return indexOf(item) >= 0; }
/**
diff --git a/services/audiopolicy/common/managerdefinitions/include/IOProfile.h b/services/audiopolicy/common/managerdefinitions/include/IOProfile.h
index 37443ab..084399d 100644
--- a/services/audiopolicy/common/managerdefinitions/include/IOProfile.h
+++ b/services/audiopolicy/common/managerdefinitions/include/IOProfile.h
@@ -35,10 +35,7 @@
class IOProfile : public AudioPort, public PolicyAudioPort
{
public:
- IOProfile(const std::string &name, audio_port_role_t role)
- : AudioPort(name, AUDIO_PORT_TYPE_MIX, role),
- curOpenCount(0),
- curActiveCount(0) {}
+ IOProfile(const std::string &name, audio_port_role_t role);
virtual ~IOProfile() = default;
@@ -66,6 +63,14 @@
if (getRole() == AUDIO_PORT_ROLE_SINK && (flags & AUDIO_INPUT_FLAG_MMAP_NOIRQ) != 0) {
maxActiveCount = 0;
}
+ if (getRole() == AUDIO_PORT_ROLE_SOURCE) {
+ mMixerBehaviors.clear();
+ mMixerBehaviors.insert(AUDIO_MIXER_BEHAVIOR_DEFAULT);
+ }
+ }
+
+ const MixerBehaviorSet& getMixerBehaviors() const {
+ return mMixerBehaviors;
}
/**
@@ -212,6 +217,8 @@
return false;
}
+ void toSupportedMixerAttributes(std::vector<audio_mixer_attributes_t>* mixerAttributes) const;
+
// Number of streams currently opened for this profile.
uint32_t curOpenCount;
// Number of streams currently active for this profile. This is not the number of active clients
@@ -220,6 +227,8 @@
private:
DeviceVector mSupportedDevices; // supported devices: this input/output can be routed from/to
+
+ MixerBehaviorSet mMixerBehaviors;
};
class InputProfile : public IOProfile
diff --git a/services/audiopolicy/common/managerdefinitions/include/PreferredMixerAttributesInfo.h b/services/audiopolicy/common/managerdefinitions/include/PreferredMixerAttributesInfo.h
new file mode 100644
index 0000000..9472481
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/include/PreferredMixerAttributesInfo.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2022 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 <map>
+
+#include <utils/RefBase.h>
+
+#include "AudioRoute.h"
+#include "HwModule.h"
+#include "IOProfile.h"
+
+namespace android {
+
+class PreferredMixerAttributesInfo : public RefBase {
+public:
+ PreferredMixerAttributesInfo(uid_t uid, audio_port_handle_t devicePortId,
+ const sp<IOProfile>& profile, audio_output_flags_t flags,
+ const audio_mixer_attributes_t& mixerAttributes)
+ : mDevicePortId(devicePortId), mUid(uid), mProfile(profile),
+ mOutputFlags(flags), mMixerAttributes(mixerAttributes) { }
+
+ audio_port_handle_t getDeviceId() const { return mDevicePortId; }
+ const audio_config_base_t& getConfigBase() const { return mMixerAttributes.config; }
+ uid_t getUid() const { return mUid; }
+ int getActiveClientCount() const { return mActiveClientsCount; }
+ const sp<IOProfile> getProfile() const { return mProfile; };
+ audio_output_flags_t getFlags() const { return mOutputFlags; }
+ const audio_mixer_attributes_t& getMixerAttributes() const { return mMixerAttributes; }
+
+ void increaseActiveClient() { mActiveClientsCount++; }
+ void decreaseActiveClient() { mActiveClientsCount--; }
+
+ void dump(String8 *dst);
+
+private:
+ const audio_port_handle_t mDevicePortId;
+ const uid_t mUid;
+ const sp<IOProfile> mProfile;
+ const audio_output_flags_t mOutputFlags;
+ const audio_mixer_attributes_t mMixerAttributes;
+ int mActiveClientsCount = 0;
+};
+
+} // namespace android
\ No newline at end of file
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
index 8eefe77..0b3ba4d 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
@@ -26,6 +26,7 @@
#include "Volume.h"
#include "HwModule.h"
#include "TypeConverter.h"
+#include "policy.h"
#include <media/AudioGain.h>
#include <media/AudioParameter.h>
#include <media/AudioPolicy.h>
@@ -311,6 +312,9 @@
if (extraInfo != nullptr) {
allExtraInfo.appendFormat("%s; ", extraInfo);
}
+ if (mProfile != nullptr) {
+ allExtraInfo.appendFormat("IOProfile name:%s; ", mProfile->getName().c_str());
+ }
std::string flagsLiteral = toString(mFlags);
allExtraInfo.appendFormat("Latency: %d; 0x%04x", mLatency, mFlags);
if (!flagsLiteral.empty()) {
@@ -931,6 +935,16 @@
return false;
}
+bool SwAudioOutputDescriptor::isConfigurationMatched(const audio_config_base_t &config,
+ audio_output_flags_t flags) {
+ const uint32_t mustMatchOutputFlags =
+ AUDIO_OUTPUT_FLAG_DIRECT|AUDIO_OUTPUT_FLAG_HW_AV_SYNC|AUDIO_OUTPUT_FLAG_MMAP_NOIRQ;
+ return audio_output_flags_is_subset(AudioOutputDescriptor::mFlags, flags, mustMatchOutputFlags)
+ && mSamplingRate == config.sample_rate
+ && mChannelMask == config.channel_mask
+ && mFormat == config.format;
+}
+
void SwAudioOutputCollection::dump(String8 *dst) const
{
dst->appendFormat("\n Outputs (%zu):\n", size());
diff --git a/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp b/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp
index 7b4cecf..98d7d59 100644
--- a/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp
@@ -24,6 +24,15 @@
namespace android {
+IOProfile::IOProfile(const std::string &name, audio_port_role_t role)
+ : AudioPort(name, AUDIO_PORT_TYPE_MIX, role),
+ curOpenCount(0),
+ curActiveCount(0) {
+ if (role == AUDIO_PORT_ROLE_SOURCE) {
+ mMixerBehaviors.insert(AUDIO_MIXER_BEHAVIOR_DEFAULT);
+ }
+}
+
bool IOProfile::isCompatibleProfile(const DeviceVector &devices,
uint32_t samplingRate,
uint32_t *updatedSamplingRate,
@@ -105,8 +114,10 @@
const uint32_t mustMatchOutputFlags =
AUDIO_OUTPUT_FLAG_DIRECT|AUDIO_OUTPUT_FLAG_HW_AV_SYNC|AUDIO_OUTPUT_FLAG_MMAP_NOIRQ;
- if (isPlaybackThread && (((getFlags() ^ flags) & mustMatchOutputFlags)
- || (getFlags() & flags) != flags)) {
+ if (isPlaybackThread &&
+ !audio_output_flags_is_subset((audio_output_flags_t)getFlags(),
+ (audio_output_flags_t)flags,
+ mustMatchOutputFlags)) {
return false;
}
// The only input flag that is allowed to be different is the fast flag.
@@ -132,6 +143,34 @@
return device == deviceDesc && deviceDesc->hasCurrentEncodedFormat(); }) == 1;
}
+void IOProfile::toSupportedMixerAttributes(
+ std::vector<audio_mixer_attributes_t> *mixerAttributes) const {
+ if (!hasDynamicAudioProfile()) {
+ // The mixer attributes is only supported when there is a dynamic profile.
+ return;
+ }
+ for (const auto& profile : mProfiles) {
+ if (!profile->isValid()) {
+ continue;
+ }
+ for (const auto sampleRate : profile->getSampleRates()) {
+ for (const auto channelMask : profile->getChannels()) {
+ const audio_config_base_t config = {
+ .format = profile->getFormat(),
+ .sample_rate = sampleRate,
+ .channel_mask = channelMask
+ };
+ for (const auto mixerBehavior : mMixerBehaviors) {
+ mixerAttributes->push_back({
+ .config = config,
+ .mixer_behavior = mixerBehavior
+ });
+ }
+ }
+ }
+ }
+}
+
void IOProfile::dump(String8 *dst, int spaces) const
{
String8 extraInfo;
diff --git a/services/audiopolicy/common/managerdefinitions/src/PreferredMixerAttributesInfo.cpp b/services/audiopolicy/common/managerdefinitions/src/PreferredMixerAttributesInfo.cpp
new file mode 100644
index 0000000..edb2c6d
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/src/PreferredMixerAttributesInfo.cpp
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "PreferredMixerAttributesInfo.h"
+
+namespace android {
+
+void PreferredMixerAttributesInfo::dump(String8 *dst) {
+ dst->appendFormat("device port ID: %d; owner uid: %d; profile name: %s; flags: %#x; "
+ "sample rate: %u; channel mask: %#x; format: %#x; mixer behavior: %d; "
+ "active clients count: %d\n",
+ mDevicePortId, mUid, mProfile->getName().c_str(), mOutputFlags,
+ mMixerAttributes.config.sample_rate, mMixerAttributes.config.channel_mask,
+ mMixerAttributes.config.format, mMixerAttributes.mixer_behavior,
+ mActiveClientsCount);
+}
+
+} // namespace android
\ No newline at end of file
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 4c8aec7..959dd4f 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -260,6 +260,9 @@
// remove device from mReportedFormatsMap cache
mReportedFormatsMap.erase(device);
+ // remove preferred mixer configurations
+ mPreferredMixerAttrInfos.erase(device->getId());
+
} break;
default:
@@ -1270,8 +1273,19 @@
}
}
if (*output == AUDIO_IO_HANDLE_NONE) {
+ sp<PreferredMixerAttributesInfo> info = nullptr;
+ if (outputDevices.size() == 1) {
+ info = getPreferredMixerAttributesInfo(
+ outputDevices.itemAt(0)->getId(),
+ mEngine->getProductStrategyForAttributes(*resultAttr));
+ if (info != nullptr && info->getUid() != uid && info->getActiveClientCount() == 0) {
+ // Only use preferred mixer when the requested uid matched or
+ // there is active client on preferred mixer.
+ info = nullptr;
+ }
+ }
*output = getOutputForDevices(outputDevices, session, resultAttr, config,
- flags, isSpatialized, resultAttr->flags & AUDIO_FLAG_MUTE_HAPTIC);
+ flags, isSpatialized, info, resultAttr->flags & AUDIO_FLAG_MUTE_HAPTIC);
}
if (*output == AUDIO_IO_HANDLE_NONE) {
AudioProfileVector profiles;
@@ -1482,6 +1496,7 @@
const audio_config_t *config,
audio_output_flags_t *flags,
bool *isSpatialized,
+ sp<PreferredMixerAttributesInfo> prefMixerConfigInfo,
bool forceMutingHaptic)
{
audio_io_handle_t output = AUDIO_IO_HANDLE_NONE;
@@ -1557,11 +1572,36 @@
// get which output is suitable for the specified stream. The actual
// routing change will happen when startOutput() will be called
SortedVector<audio_io_handle_t> outputs = getOutputsForDevices(devices, mOutputs);
-
- // at this stage we should ignore the DIRECT flag as no direct output could be found earlier
- *flags = (audio_output_flags_t)(*flags & ~AUDIO_OUTPUT_FLAG_DIRECT);
- output = selectOutput(
- outputs, *flags, config->format, channelMask, config->sample_rate, session);
+ if (prefMixerConfigInfo != nullptr) {
+ for (audio_io_handle_t outputHandle : outputs) {
+ sp<SwAudioOutputDescriptor> outputDesc = mOutputs.valueFor(outputHandle);
+ if (outputDesc->mProfile == prefMixerConfigInfo->getProfile()) {
+ output = outputHandle;
+ break;
+ }
+ }
+ if (output == AUDIO_IO_HANDLE_NONE) {
+ // No output open with the preferred profile. Open a new one.
+ audio_config_t config = AUDIO_CONFIG_INITIALIZER;
+ config.channel_mask = prefMixerConfigInfo->getConfigBase().channel_mask;
+ config.sample_rate = prefMixerConfigInfo->getConfigBase().sample_rate;
+ config.format = prefMixerConfigInfo->getConfigBase().format;
+ sp<SwAudioOutputDescriptor> preferredOutput = openOutputWithProfileAndDevice(
+ prefMixerConfigInfo->getProfile(), devices, nullptr /*mixerConfig*/,
+ &config, prefMixerConfigInfo->getFlags());
+ if (preferredOutput == nullptr) {
+ ALOGE("%s failed to open output with preferred mixer config", __func__);
+ } else {
+ output = preferredOutput->mIoHandle;
+ }
+ }
+ } else {
+ // at this stage we should ignore the DIRECT flag as no direct output could be
+ // found earlier
+ *flags = (audio_output_flags_t) (*flags & ~AUDIO_OUTPUT_FLAG_DIRECT);
+ output = selectOutput(
+ outputs, *flags, config->format, channelMask, config->sample_rate, session);
+ }
}
ALOGW_IF((output == 0), "getOutputForDevices() could not find output for stream %d, "
"sampling rate %d, format %#x, channels %#x, flags %#x",
@@ -2015,6 +2055,33 @@
outputDesc->stop();
return status;
}
+
+ // If the client is the first one active on preferred mixer parameters, reopen the output
+ // if the current mixer parameters doesn't match the preferred one.
+ if (outputDesc->devices().size() == 1) {
+ sp<PreferredMixerAttributesInfo> info = getPreferredMixerAttributesInfo(
+ outputDesc->devices()[0]->getId(), client->strategy());
+ if (info != nullptr && info->getUid() == client->uid()) {
+ if (info->getActiveClientCount() == 0 && !outputDesc->isConfigurationMatched(
+ info->getConfigBase(), info->getFlags())) {
+ stopSource(outputDesc, client);
+ outputDesc->stop();
+ audio_config_t config = AUDIO_CONFIG_INITIALIZER;
+ config.channel_mask = info->getConfigBase().channel_mask;
+ config.sample_rate = info->getConfigBase().sample_rate;
+ config.format = info->getConfigBase().format;
+ status_t status = reopenOutput(outputDesc, &config, info->getFlags(), __func__);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ // Intentionally return error to let the client side resending request for
+ // creating and starting.
+ return DEAD_OBJECT;
+ }
+ info->increaseActiveClient();
+ }
+ }
+
if (delayMs != 0) {
usleep(delayMs * 1000);
}
@@ -2267,6 +2334,19 @@
if (status == NO_ERROR ) {
outputDesc->stop();
+ } else {
+ return status;
+ }
+
+ if (outputDesc->devices().size() == 1) {
+ sp<PreferredMixerAttributesInfo> info = getPreferredMixerAttributesInfo(
+ outputDesc->devices()[0]->getId(), client->strategy());
+ if (info != nullptr && info->getUid() == client->uid()) {
+ info->decreaseActiveClient();
+ if (info->getActiveClientCount() == 0) {
+ reopenOutput(outputDesc, nullptr /*config*/, AUDIO_OUTPUT_FLAG_NONE, __func__);
+ }
+ }
}
return status;
}
@@ -3892,6 +3972,15 @@
dst->appendFormat(" - uid=%d flag_mask=%#x\n", policy.first, policy.second);
}
+ dst->appendFormat(" Preferred mixer audio configuration:\n");
+ for (const auto it : mPreferredMixerAttrInfos) {
+ dst->appendFormat(" - device port id: %d\n", it.first);
+ for (const auto preferredMixerInfoIt : it.second) {
+ dst->appendFormat(" - strategy: %d; ", preferredMixerInfoIt.first);
+ preferredMixerInfoIt.second->dump(dst);
+ }
+ }
+
dst->appendFormat("\nPolicy Engine dump:\n");
mEngine->dump(dst);
}
@@ -4122,6 +4211,172 @@
AUDIO_OUTPUT_FLAG_DIRECT /*flags*/, false /*isInput*/);
}
+status_t AudioPolicyManager::getSupportedMixerAttributes(
+ audio_port_handle_t portId, std::vector<audio_mixer_attributes_t> &mixerAttrs) {
+ ALOGV("%s, portId=%d", __func__, portId);
+ sp<DeviceDescriptor> deviceDescriptor = mAvailableOutputDevices.getDeviceFromId(portId);
+ if (deviceDescriptor == nullptr) {
+ ALOGE("%s the requested device is currently unavailable", __func__);
+ return BAD_VALUE;
+ }
+ for (const auto& hwModule : mHwModules) {
+ for (const auto& curProfile : hwModule->getOutputProfiles()) {
+ if (curProfile->supportsDevice(deviceDescriptor)) {
+ curProfile->toSupportedMixerAttributes(&mixerAttrs);
+ }
+ }
+ }
+ return NO_ERROR;
+}
+
+status_t AudioPolicyManager::setPreferredMixerAttributes(
+ const audio_attributes_t *attr,
+ audio_port_handle_t portId,
+ uid_t uid,
+ const audio_mixer_attributes_t *mixerAttributes) {
+ ALOGV("%s, attr=%s, mixerAttributes={format=%#x, channelMask=%#x, samplingRate=%u, "
+ "mixerBehavior=%d}, uid=%d, portId=%u",
+ __func__, toString(*attr).c_str(), mixerAttributes->config.format,
+ mixerAttributes->config.channel_mask, mixerAttributes->config.sample_rate,
+ mixerAttributes->mixer_behavior, uid, portId);
+ if (attr->usage != AUDIO_USAGE_MEDIA) {
+ ALOGE("%s failed, only media is allowed, the given usage is %d", __func__, attr->usage);
+ return BAD_VALUE;
+ }
+ sp<DeviceDescriptor> deviceDescriptor = mAvailableOutputDevices.getDeviceFromId(portId);
+ if (deviceDescriptor == nullptr) {
+ ALOGE("%s the requested device is currently unavailable", __func__);
+ return BAD_VALUE;
+ }
+ if (!audio_is_usb_out_device(deviceDescriptor->type())) {
+ ALOGE("%s(%d), type=%d, is not a usb output device",
+ __func__, portId, deviceDescriptor->type());
+ return BAD_VALUE;
+ }
+
+ audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE;
+ audio_flags_to_audio_output_flags(attr->flags, &flags);
+ flags = (audio_output_flags_t) (flags |
+ audio_output_flags_from_mixer_behavior(mixerAttributes->mixer_behavior));
+ sp<IOProfile> profile = nullptr;
+ DeviceVector devices(deviceDescriptor);
+ for (const auto& hwModule : mHwModules) {
+ for (const auto& curProfile : hwModule->getOutputProfiles()) {
+ if (curProfile->hasDynamicAudioProfile()
+ && curProfile->isCompatibleProfile(devices,
+ mixerAttributes->config.sample_rate,
+ nullptr /*updatedSamplingRate*/,
+ mixerAttributes->config.format,
+ nullptr /*updatedFormat*/,
+ mixerAttributes->config.channel_mask,
+ nullptr /*updatedChannelMask*/,
+ flags,
+ false /*exactMatchRequiredForInputFlags*/)) {
+ profile = curProfile;
+ break;
+ }
+ }
+ }
+ if (profile == nullptr) {
+ ALOGE("%s, there is no compatible profile found", __func__);
+ return BAD_VALUE;
+ }
+
+ sp<PreferredMixerAttributesInfo> mixerAttrInfo =
+ sp<PreferredMixerAttributesInfo>::make(
+ uid, portId, profile, flags, *mixerAttributes);
+ const product_strategy_t strategy = mEngine->getProductStrategyForAttributes(*attr);
+ mPreferredMixerAttrInfos[portId][strategy] = mixerAttrInfo;
+
+ // If 1) there is any client from the preferred mixer configuration owner that is currently
+ // active and matches the strategy and 2) current output is on the preferred device and the
+ // mixer configuration doesn't match the preferred one, reopen output with preferred mixer
+ // configuration.
+ std::vector<audio_io_handle_t> outputsToReopen;
+ for (size_t i = 0; i < mOutputs.size(); i++) {
+ const auto output = mOutputs.valueAt(i);
+ if (output->mProfile == profile && output->devices().onlyContainsDevice(deviceDescriptor)
+ && !output->isConfigurationMatched(mixerAttributes->config, flags)) {
+ for (const auto& client : output->getActiveClients()) {
+ if (client->uid() == uid && client->strategy() == strategy) {
+ client->setIsInvalid();
+ outputsToReopen.push_back(output->mIoHandle);
+ }
+ }
+ }
+ }
+ audio_config_t config = AUDIO_CONFIG_INITIALIZER;
+ config.sample_rate = mixerAttributes->config.sample_rate;
+ config.channel_mask = mixerAttributes->config.channel_mask;
+ config.format = mixerAttributes->config.format;
+ for (const auto output : outputsToReopen) {
+ reopenOutput(mOutputs.valueFor(output), &config, flags, __func__);
+ }
+
+ return NO_ERROR;
+}
+
+sp<PreferredMixerAttributesInfo> AudioPolicyManager::getPreferredMixerAttributesInfo(
+ audio_port_handle_t devicePortId, product_strategy_t strategy) {
+ auto it = mPreferredMixerAttrInfos.find(devicePortId);
+ if (it == mPreferredMixerAttrInfos.end()) {
+ return nullptr;
+ }
+ auto mixerAttrInfoIt = it->second.find(strategy);
+ if (mixerAttrInfoIt == it->second.end()) {
+ return nullptr;
+ }
+ return mixerAttrInfoIt->second;
+}
+
+status_t AudioPolicyManager::getPreferredMixerAttributes(
+ const audio_attributes_t *attr,
+ audio_port_handle_t portId,
+ audio_mixer_attributes_t* mixerAttributes) {
+ sp<PreferredMixerAttributesInfo> info = getPreferredMixerAttributesInfo(
+ portId, mEngine->getProductStrategyForAttributes(*attr));
+ if (info == nullptr) {
+ return NAME_NOT_FOUND;
+ }
+ *mixerAttributes = info->getMixerAttributes();
+ return NO_ERROR;
+}
+
+status_t AudioPolicyManager::clearPreferredMixerAttributes(const audio_attributes_t *attr,
+ audio_port_handle_t portId,
+ uid_t uid) {
+ const product_strategy_t strategy = mEngine->getProductStrategyForAttributes(*attr);
+ const auto preferredMixerAttrInfo = getPreferredMixerAttributesInfo(portId, strategy);
+ if (preferredMixerAttrInfo == nullptr) {
+ return NAME_NOT_FOUND;
+ }
+ if (preferredMixerAttrInfo->getUid() != uid) {
+ ALOGE("%s, requested uid=%d, owned uid=%d",
+ __func__, uid, preferredMixerAttrInfo->getUid());
+ return PERMISSION_DENIED;
+ }
+ mPreferredMixerAttrInfos[portId].erase(strategy);
+ if (mPreferredMixerAttrInfos[portId].empty()) {
+ mPreferredMixerAttrInfos.erase(portId);
+ }
+
+ // Reconfig existing output
+ std::vector<audio_io_handle_t> potentialOutputsToReopen;
+ for (size_t i = 0; i < mOutputs.size(); i++) {
+ if (mOutputs.valueAt(i)->mProfile == preferredMixerAttrInfo->getProfile()) {
+ potentialOutputsToReopen.push_back(mOutputs.keyAt(i));
+ }
+ }
+ for (const auto output : potentialOutputsToReopen) {
+ sp<SwAudioOutputDescriptor> desc = mOutputs.valueFor(output);
+ if (desc->isConfigurationMatched(preferredMixerAttrInfo->getConfigBase(),
+ preferredMixerAttrInfo->getFlags())) {
+ reopenOutput(desc, nullptr /*config*/, AUDIO_OUTPUT_FLAG_NONE, __func__);
+ }
+ }
+ return NO_ERROR;
+}
+
status_t AudioPolicyManager::listAudioPorts(audio_port_role_t role,
audio_port_type_t type,
unsigned int *num_ports,
@@ -4186,6 +4441,7 @@
*num_ports += numOutputs;
}
}
+
*generation = curAudioPortGeneration();
ALOGV("listAudioPorts() got %zu ports needed %d", portsWritten, *num_ports);
return NO_ERROR;
@@ -7744,19 +8000,23 @@
sp<SwAudioOutputDescriptor> AudioPolicyManager::openOutputWithProfileAndDevice(
const sp<IOProfile>& profile, const DeviceVector& devices,
- const audio_config_base_t *mixerConfig)
+ const audio_config_base_t *mixerConfig, const audio_config_t *halConfig,
+ audio_output_flags_t flags)
{
for (const auto& device : devices) {
// TODO: This should be checking if the profile supports the device combo.
if (!profile->supportsDevice(device)) {
+ ALOGE("%s profile(%s) doesn't support device %#x", __func__, profile->getName().c_str(),
+ device->type());
return nullptr;
}
}
sp<SwAudioOutputDescriptor> desc = new SwAudioOutputDescriptor(profile, mpClientInterface);
audio_io_handle_t output = AUDIO_IO_HANDLE_NONE;
- status_t status = desc->open(nullptr /* halConfig */, mixerConfig, devices,
- AUDIO_STREAM_DEFAULT, AUDIO_OUTPUT_FLAG_NONE, &output);
+ status_t status = desc->open(halConfig, mixerConfig, devices,
+ AUDIO_STREAM_DEFAULT, flags, &output);
if (status != NO_ERROR) {
+ ALOGE("%s failed to open output %d", __func__, status);
return nullptr;
}
@@ -7774,7 +8034,9 @@
ALOGW("%s() missing param", __func__);
desc->close();
return nullptr;
- } else if (profile->hasDynamicAudioProfile()) {
+ } else if (profile->hasDynamicAudioProfile() && halConfig == nullptr) {
+ // Reopen the output with the best audio profile picked by APM when the profile supports
+ // dynamic audio profile and the hal config is not specified.
desc->close();
output = AUDIO_IO_HANDLE_NONE;
audio_config_t config = AUDIO_CONFIG_INITIALIZER;
@@ -7784,8 +8046,7 @@
config.offload_info.channel_mask = config.channel_mask;
config.offload_info.format = config.format;
- status = desc->open(&config, mixerConfig, devices,
- AUDIO_STREAM_DEFAULT, AUDIO_OUTPUT_FLAG_NONE, &output);
+ status = desc->open(&config, mixerConfig, devices, AUDIO_STREAM_DEFAULT, flags, &output);
if (status != NO_ERROR) {
return nullptr;
}
@@ -7945,4 +8206,19 @@
return NO_ERROR;
}
+status_t AudioPolicyManager::reopenOutput(sp<SwAudioOutputDescriptor> outputDesc,
+ const audio_config_t *config,
+ audio_output_flags_t flags,
+ const char* caller) {
+ closeOutput(outputDesc->mIoHandle);
+ sp<SwAudioOutputDescriptor> preferredOutput = openOutputWithProfileAndDevice(
+ outputDesc->mProfile, outputDesc->devices(), nullptr /*mixerConfig*/, config, flags);
+ if (preferredOutput == nullptr) {
+ ALOGE("%s failed to reopen output device=%d, caller=%s",
+ __func__, outputDesc->devices()[0]->getId(), caller);
+ return BAD_VALUE;
+ }
+ return NO_ERROR;
+}
+
} // namespace android
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index a3600a0..b7a55e9 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -47,6 +47,7 @@
#include <AudioOutputDescriptor.h>
#include <AudioPolicyMix.h>
#include <EffectDescriptor.h>
+#include <PreferredMixerAttributesInfo.h>
#include <SoundTriggerSession.h>
#include "EngineLibrary.h"
#include "TypeConverter.h"
@@ -395,6 +396,21 @@
virtual status_t getDirectProfilesForAttributes(const audio_attributes_t* attr,
AudioProfileVector& audioProfiles);
+ status_t getSupportedMixerAttributes(
+ audio_port_handle_t portId,
+ std::vector<audio_mixer_attributes_t>& mixerAttrs) override;
+ status_t setPreferredMixerAttributes(
+ const audio_attributes_t* attr,
+ audio_port_handle_t portId,
+ uid_t uid,
+ const audio_mixer_attributes_t* mixerAttributes) override;
+ status_t getPreferredMixerAttributes(const audio_attributes_t* attr,
+ audio_port_handle_t portId,
+ audio_mixer_attributes_t* mixerAttributes) override;
+ status_t clearPreferredMixerAttributes(const audio_attributes_t* attr,
+ audio_port_handle_t portId,
+ uid_t uid) override;
+
bool isCallScreenModeSupported() override;
void onNewAudioModulesAvailable() override;
@@ -983,6 +999,10 @@
sp<SourceClientDescriptor> mCallRxSourceClient;
sp<SourceClientDescriptor> mCallTxSourceClient;
+ std::map<audio_port_handle_t,
+ std::map<product_strategy_t,
+ sp<PreferredMixerAttributesInfo>>> mPreferredMixerAttrInfos;
+
// Support for Multi-Stream Decoder (MSD) module
sp<DeviceDescriptor> getMsdAudioInDevice() const;
DeviceVector getMsdAudioOutDevices() const;
@@ -1069,6 +1089,7 @@
const audio_config_t *config,
audio_output_flags_t *flags,
bool *isSpatialized,
+ sp<PreferredMixerAttributesInfo> prefMixerAttrInfo = nullptr,
bool forceMutingHaptic = false);
// Internal method checking if a direct output can be opened matching the requested
@@ -1236,11 +1257,15 @@
* @param[in] profile IOProfile to use as template
* @param[in] devices initial route to apply to this output stream
* @param[in] mixerConfig if not null, use this to configure the mixer
+ * @param[in] halConfig if not null, use this to configure the HAL
+ * @param[in] flags the flags to be used to open the output
* @return an output descriptor for the newly opened stream or null in case of error.
*/
sp<SwAudioOutputDescriptor> openOutputWithProfileAndDevice(
const sp<IOProfile>& profile, const DeviceVector& devices,
- const audio_config_base_t *mixerConfig = nullptr);
+ const audio_config_base_t *mixerConfig = nullptr,
+ const audio_config_t *halConfig = nullptr,
+ audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE);
bool isOffloadPossible(const audio_offload_info_t& offloadInfo,
bool durationIgnored = false);
@@ -1273,6 +1298,13 @@
AudioProfileVector& audioProfiles,
uint32_t flags,
bool isInput);
+
+ sp<PreferredMixerAttributesInfo> getPreferredMixerAttributesInfo(
+ audio_port_handle_t devicePortId, product_strategy_t strategy);
+ status_t reopenOutput(sp<SwAudioOutputDescriptor> outputDesc,
+ const audio_config_t *config,
+ audio_output_flags_t flags,
+ const char* caller);
};
};
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index b576b6d..1088088 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -2365,4 +2365,89 @@
return Status::ok();
}
+Status AudioPolicyService::getSupportedMixerAttributes(
+ int32_t portIdAidl, std::vector<media::AudioMixerAttributesInternal>* _aidl_return) {
+ if (mAudioPolicyManager == nullptr) {
+ return binderStatusFromStatusT(NO_INIT);
+ }
+
+ audio_port_handle_t portId = VALUE_OR_RETURN_BINDER_STATUS(
+ aidl2legacy_int32_t_audio_port_handle_t(portIdAidl));
+
+ std::vector<audio_mixer_attributes_t> mixerAttrs;
+ Mutex::Autolock _l(mLock);
+ RETURN_IF_BINDER_ERROR(
+ binderStatusFromStatusT(mAudioPolicyManager->getSupportedMixerAttributes(
+ portId, mixerAttrs)));
+ *_aidl_return = VALUE_OR_RETURN_BINDER_STATUS(
+ convertContainer<std::vector<media::AudioMixerAttributesInternal>>(
+ mixerAttrs,
+ legacy2aidl_audio_mixer_attributes_t_AudioMixerAttributesInternal));
+ return Status::ok();
+}
+
+Status AudioPolicyService::setPreferredMixerAttributes(
+ const media::AudioAttributesInternal& attrAidl,
+ int32_t portIdAidl,
+ int32_t uidAidl,
+ const media::AudioMixerAttributesInternal& mixerAttrAidl) {
+ if (mAudioPolicyManager == nullptr) {
+ return binderStatusFromStatusT(NO_INIT);
+ }
+
+ audio_attributes_t attr = VALUE_OR_RETURN_BINDER_STATUS(
+ aidl2legacy_AudioAttributesInternal_audio_attributes_t(attrAidl));
+ audio_mixer_attributes_t mixerAttr = VALUE_OR_RETURN_BINDER_STATUS(
+ aidl2legacy_AudioMixerAttributesInternal_audio_mixer_attributes_t(mixerAttrAidl));
+ uid_t uid = VALUE_OR_RETURN_BINDER_STATUS(aidl2legacy_int32_t_uid_t(uidAidl));
+ audio_port_handle_t portId = VALUE_OR_RETURN_BINDER_STATUS(
+ aidl2legacy_int32_t_audio_port_handle_t(portIdAidl));
+
+ Mutex::Autolock _l(mLock);
+ return binderStatusFromStatusT(
+ mAudioPolicyManager->setPreferredMixerAttributes(&attr, portId, uid, &mixerAttr));
+}
+
+Status AudioPolicyService::getPreferredMixerAttributes(
+ const media::AudioAttributesInternal& attrAidl,
+ int32_t portIdAidl,
+ std::optional<media::AudioMixerAttributesInternal>* _aidl_return) {
+ if (mAudioPolicyManager == nullptr) {
+ return binderStatusFromStatusT(NO_INIT);
+ }
+
+ audio_attributes_t attr = VALUE_OR_RETURN_BINDER_STATUS(
+ aidl2legacy_AudioAttributesInternal_audio_attributes_t(attrAidl));
+ audio_port_handle_t portId = VALUE_OR_RETURN_BINDER_STATUS(
+ aidl2legacy_int32_t_audio_port_handle_t(portIdAidl));
+
+ Mutex::Autolock _l(mLock);
+ audio_mixer_attributes_t mixerAttr = AUDIO_MIXER_ATTRIBUTES_INITIALIZER;
+ RETURN_IF_BINDER_ERROR(
+ binderStatusFromStatusT(mAudioPolicyManager->getPreferredMixerAttributes(
+ &attr, portId, &mixerAttr)));
+ *_aidl_return = VALUE_OR_RETURN_BINDER_STATUS(
+ legacy2aidl_audio_mixer_attributes_t_AudioMixerAttributesInternal(mixerAttr));
+ return Status::ok();
+}
+
+Status AudioPolicyService::clearPreferredMixerAttributes(
+ const media::AudioAttributesInternal& attrAidl,
+ int32_t portIdAidl,
+ int32_t uidAidl) {
+ if (mAudioPolicyManager == nullptr) {
+ return binderStatusFromStatusT(NO_INIT);
+ }
+
+ audio_attributes_t attr = VALUE_OR_RETURN_BINDER_STATUS(
+ aidl2legacy_AudioAttributesInternal_audio_attributes_t(attrAidl));
+ uid_t uid = VALUE_OR_RETURN_BINDER_STATUS(aidl2legacy_int32_t_uid_t(uidAidl));
+ audio_port_handle_t portId = VALUE_OR_RETURN_BINDER_STATUS(
+ aidl2legacy_int32_t_audio_port_handle_t(portIdAidl));
+
+ Mutex::Autolock _l(mLock);
+ return binderStatusFromStatusT(
+ mAudioPolicyManager->clearPreferredMixerAttributes(&attr, portId, uid));
+}
+
} // namespace android
diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp
index b87320e..48997db 100644
--- a/services/audiopolicy/service/AudioPolicyService.cpp
+++ b/services/audiopolicy/service/AudioPolicyService.cpp
@@ -155,7 +155,11 @@
BINDER_METHOD_ENTRY(getSpatializer) \
BINDER_METHOD_ENTRY(canBeSpatialized) \
BINDER_METHOD_ENTRY(getDirectPlaybackSupport) \
-BINDER_METHOD_ENTRY(getDirectProfilesForAttributes) \
+BINDER_METHOD_ENTRY(getDirectProfilesForAttributes) \
+BINDER_METHOD_ENTRY(getSupportedMixerAttributes) \
+BINDER_METHOD_ENTRY(setPreferredMixerAttributes) \
+BINDER_METHOD_ENTRY(getPreferredMixerAttributes) \
+BINDER_METHOD_ENTRY(clearPreferredMixerAttributes) \
// singleton for Binder Method Statistics for IAudioPolicyService
static auto& getIAudioPolicyServiceStatistics() {
@@ -1324,7 +1328,9 @@
case TRANSACTION_removeDevicesRoleForCapturePreset:
case TRANSACTION_clearDevicesRoleForCapturePreset:
case TRANSACTION_getDevicesForRoleAndCapturePreset:
- case TRANSACTION_getSpatializer: {
+ case TRANSACTION_getSpatializer:
+ case TRANSACTION_setPreferredMixerAttributes:
+ case TRANSACTION_clearPreferredMixerAttributes: {
if (!isServiceUid(IPCThreadState::self()->getCallingUid())) {
ALOGW("%s: transaction %d received from PID %d unauthorized UID %d",
__func__, code, IPCThreadState::self()->getCallingPid(),
diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h
index 3a7fffa..58af46d 100644
--- a/services/audiopolicy/service/AudioPolicyService.h
+++ b/services/audiopolicy/service/AudioPolicyService.h
@@ -277,6 +277,22 @@
binder::Status getDirectProfilesForAttributes(const media::AudioAttributesInternal& attr,
std::vector<media::audio::common::AudioProfile>* _aidl_return) override;
+ binder::Status getSupportedMixerAttributes(
+ int32_t portId,
+ std::vector<media::AudioMixerAttributesInternal>* _aidl_return) override;
+ binder::Status setPreferredMixerAttributes(
+ const media::AudioAttributesInternal& attr,
+ int32_t portId,
+ int32_t uid,
+ const media::AudioMixerAttributesInternal& mixerAttr) override;
+ binder::Status getPreferredMixerAttributes(
+ const media::AudioAttributesInternal& attr,
+ int32_t portId,
+ std::optional<media::AudioMixerAttributesInternal>* _aidl_return) override;
+ binder::Status clearPreferredMixerAttributes(const media::AudioAttributesInternal& attr,
+ int32_t portId,
+ int32_t uid) override;
+
status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) override;
// IBinder::DeathRecipient
diff --git a/services/audiopolicy/tests/AudioPolicyManagerTestClient.h b/services/audiopolicy/tests/AudioPolicyManagerTestClient.h
index 96f58d2..2a65546 100644
--- a/services/audiopolicy/tests/AudioPolicyManagerTestClient.h
+++ b/services/audiopolicy/tests/AudioPolicyManagerTestClient.h
@@ -131,8 +131,6 @@
size_t getAudioPortListUpdateCount() const { return mAudioPortListUpdateCount; }
- virtual void addSupportedFormat(audio_format_t /* format */) {}
-
void onRoutingUpdated() override {
mRoutingUpdatedUpdateCount++;
}
@@ -178,6 +176,38 @@
return &(*it);
}
+ String8 getParameters(audio_io_handle_t /* ioHandle */, const String8& /* keys*/ ) override {
+ AudioParameter mAudioParameters;
+ std::string formats;
+ for (const auto& f : mSupportedFormats) {
+ if (!formats.empty()) formats += AUDIO_PARAMETER_VALUE_LIST_SEPARATOR;
+ formats += audio_format_to_string(f);
+ }
+ mAudioParameters.add(
+ String8(AudioParameter::keyStreamSupportedFormats),
+ String8(formats.c_str()));
+ mAudioParameters.addInt(String8(AudioParameter::keyStreamSupportedSamplingRates), 48000);
+ std::string channelMasks;
+ for (const auto& cm : mSupportedChannelMasks) {
+ if (audio_channel_mask_is_valid(cm)) {
+ continue;
+ }
+ if (!channelMasks.empty()) channelMasks += AUDIO_PARAMETER_VALUE_LIST_SEPARATOR;
+ channelMasks += audio_channel_mask_to_string(cm);
+ }
+ mAudioParameters.add(
+ String8(AudioParameter::keyStreamSupportedChannels), String8(channelMasks.c_str()));
+ return mAudioParameters.toString();
+ }
+
+ void addSupportedFormat(audio_format_t format) {
+ mSupportedFormats.insert(format);
+ }
+
+ void addSupportedChannelMask(audio_channel_mask_t channelMask) {
+ mSupportedChannelMasks.insert(channelMask);
+ }
+
private:
audio_module_handle_t mNextModuleHandle = AUDIO_MODULE_HANDLE_NONE + 1;
audio_io_handle_t mNextIoHandle = AUDIO_IO_HANDLE_NONE + 1;
@@ -188,6 +218,8 @@
size_t mRoutingUpdatedUpdateCount = 0;
std::vector<struct audio_port_v7> mConnectedDevicePorts;
std::vector<struct audio_port_v7> mDisconnectedDevicePorts;
+ std::set<audio_format_t> mSupportedFormats;
+ std::set<audio_channel_mask_t> mSupportedChannelMasks;
};
} // namespace android
diff --git a/services/audiopolicy/tests/AudioPolicyManagerTestClientForHdmi.h b/services/audiopolicy/tests/AudioPolicyManagerTestClientForHdmi.h
deleted file mode 100644
index 7343b9b..0000000
--- a/services/audiopolicy/tests/AudioPolicyManagerTestClientForHdmi.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <map>
-#include <set>
-
-#include <system/audio.h>
-#include <utils/Log.h>
-#include <utils/String8.h>
-
-#include "AudioPolicyTestClient.h"
-
-namespace android {
-
-class AudioPolicyManagerTestClientForHdmi : public AudioPolicyManagerTestClient {
-public:
- String8 getParameters(audio_io_handle_t /* ioHandle */, const String8& /* keys*/ ) override {
- AudioParameter mAudioParameters;
- std::string formats;
- for (const auto& f : mSupportedFormats) {
- if (!formats.empty()) formats += AUDIO_PARAMETER_VALUE_LIST_SEPARATOR;
- formats += audio_format_to_string(f);
- }
- mAudioParameters.add(
- String8(AudioParameter::keyStreamSupportedFormats),
- String8(formats.c_str()));
- mAudioParameters.addInt(String8(AudioParameter::keyStreamSupportedSamplingRates), 48000);
- mAudioParameters.add(String8(AudioParameter::keyStreamSupportedChannels), String8(""));
- return mAudioParameters.toString();
- }
-
- void addSupportedFormat(audio_format_t format) override {
- mSupportedFormats.insert(format);
- }
-
-private:
- std::set<audio_format_t> mSupportedFormats;
-};
-
-} // namespace android
diff --git a/services/audiopolicy/tests/audiopolicymanager_tests.cpp b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
index ba5b6b2..4ad6d7a 100644
--- a/services/audiopolicy/tests/audiopolicymanager_tests.cpp
+++ b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
@@ -35,7 +35,6 @@
#include "AudioPolicyInterface.h"
#include "AudioPolicyManagerTestClient.h"
-#include "AudioPolicyManagerTestClientForHdmi.h"
#include "AudioPolicyTestClient.h"
#include "AudioPolicyTestManager.h"
@@ -982,6 +981,77 @@
}
}
+TEST_F(AudioPolicyManagerTestWithConfigurationFile, PreferredMixerAttributes) {
+ mClient->addSupportedFormat(AUDIO_FORMAT_PCM_16_BIT);
+ mClient->addSupportedChannelMask(AUDIO_CHANNEL_OUT_STEREO);
+ ASSERT_EQ(NO_ERROR, mManager->setDeviceConnectionState(AUDIO_DEVICE_OUT_USB_DEVICE,
+ AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
+ "", "", AUDIO_FORMAT_DEFAULT));
+ auto devices = mManager->getAvailableOutputDevices();
+ audio_port_handle_t maxPortId = 0;
+ audio_port_handle_t speakerPortId;
+ audio_port_handle_t usbPortId;
+ for (auto device : devices) {
+ maxPortId = std::max(maxPortId, device->getId());
+ if (device->type() == AUDIO_DEVICE_OUT_SPEAKER) {
+ speakerPortId = device->getId();
+ } else if (device->type() == AUDIO_DEVICE_OUT_USB_DEVICE) {
+ usbPortId = device->getId();
+ }
+ }
+
+ const uid_t uid = 1234;
+ const uid_t otherUid = 4321;
+ const audio_attributes_t mediaAttr = {
+ .content_type = AUDIO_CONTENT_TYPE_MUSIC,
+ .usage = AUDIO_USAGE_MEDIA,
+ };
+ const audio_attributes_t alarmAttr = {
+ .content_type = AUDIO_CONTENT_TYPE_SONIFICATION,
+ .usage = AUDIO_USAGE_ALARM,
+ };
+
+ std::vector<audio_mixer_attributes_t> mixerAttributes;
+ EXPECT_EQ(NO_ERROR, mManager->getSupportedMixerAttributes(usbPortId, mixerAttributes));
+ for (const auto attrToSet : mixerAttributes) {
+ audio_mixer_attributes_t attrFromQuery = AUDIO_MIXER_ATTRIBUTES_INITIALIZER;
+
+ // The given device is not available
+ EXPECT_EQ(BAD_VALUE,
+ mManager->setPreferredMixerAttributes(
+ &mediaAttr, maxPortId + 1, uid, &attrToSet));
+ // The only allowed device is USB
+ EXPECT_EQ(BAD_VALUE,
+ mManager->setPreferredMixerAttributes(
+ &mediaAttr, speakerPortId, uid, &attrToSet));
+ // The only allowed usage is media
+ EXPECT_EQ(BAD_VALUE,
+ mManager->setPreferredMixerAttributes(&alarmAttr, usbPortId, uid, &attrToSet));
+ // Nothing set yet, must get null when query
+ EXPECT_EQ(NAME_NOT_FOUND,
+ mManager->getPreferredMixerAttributes(&mediaAttr, usbPortId, &attrFromQuery));
+ EXPECT_EQ(NO_ERROR,
+ mManager->setPreferredMixerAttributes(
+ &mediaAttr, usbPortId, uid, &attrToSet));
+ EXPECT_EQ(NO_ERROR,
+ mManager->getPreferredMixerAttributes(&mediaAttr, usbPortId, &attrFromQuery));
+ EXPECT_EQ(attrToSet.config.format, attrFromQuery.config.format);
+ EXPECT_EQ(attrToSet.config.sample_rate, attrFromQuery.config.sample_rate);
+ EXPECT_EQ(attrToSet.config.channel_mask, attrFromQuery.config.channel_mask);
+ EXPECT_EQ(attrToSet.mixer_behavior, attrFromQuery.mixer_behavior);
+ EXPECT_EQ(NAME_NOT_FOUND,
+ mManager->clearPreferredMixerAttributes(&mediaAttr, speakerPortId, uid));
+ EXPECT_EQ(PERMISSION_DENIED,
+ mManager->clearPreferredMixerAttributes(&mediaAttr, usbPortId, otherUid));
+ EXPECT_EQ(NO_ERROR,
+ mManager->clearPreferredMixerAttributes(&mediaAttr, usbPortId, uid));
+ }
+
+ ASSERT_EQ(NO_ERROR, mManager->setDeviceConnectionState(AUDIO_DEVICE_OUT_USB_DEVICE,
+ AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
+ "", "", AUDIO_FORMAT_LDAC));
+}
+
class AudioPolicyManagerTestDynamicPolicy : public AudioPolicyManagerTestWithConfigurationFile {
protected:
void TearDown() override;
@@ -1143,9 +1213,6 @@
std::map<audio_format_t, bool> getSurroundFormatsHelper();
std::vector<audio_format_t> getReportedSurroundFormatsHelper();
std::unordered_set<audio_format_t> getFormatsFromPorts();
- AudioPolicyManagerTestClient* getClient() override {
- return new AudioPolicyManagerTestClientForHdmi;
- }
void TearDown() override;
static const std::string sTvConfig;
diff --git a/services/audiopolicy/tests/resources/test_audio_policy_configuration.xml b/services/audiopolicy/tests/resources/test_audio_policy_configuration.xml
index d342aea..c937d3a 100644
--- a/services/audiopolicy/tests/resources/test_audio_policy_configuration.xml
+++ b/services/audiopolicy/tests/resources/test_audio_policy_configuration.xml
@@ -54,6 +54,7 @@
<profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
samplingRates="8000 16000 32000 48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
</mixPort>
+ <mixPort name="hifi_output" role="source"/>
</mixPorts>
<devicePorts>
<devicePort tagName="Speaker" type="AUDIO_DEVICE_OUT_SPEAKER" role="sink">
@@ -74,6 +75,8 @@
<devicePort tagName="BT A2DP Out" type="AUDIO_DEVICE_OUT_BLUETOOTH_A2DP" role="sink"
encodedFormats="AUDIO_FORMAT_LDAC AUDIO_FORMAT_APTX AUDIO_FORMAT_APTX_HD AUDIO_FORMAT_AAC AUDIO_FORMAT_SBC">
</devicePort>
+ <devicePort tagName="USB Device Out" type="AUDIO_DEVICE_OUT_USB_DEVICE" role="sink">
+ </devicePort>
</devicePorts>
<routes>
<route type="mix" sink="Speaker"
@@ -89,7 +92,9 @@
<route type="mix" sink="mixport_bt_hfp_input"
sources="BT SCO Headset Mic"/>
<route type="mix" sink="BT A2DP Out"
- sources="primary output"/>
+ sources="primary output,hifi_output"/>
+ <route type="mix" sink="USB Device Out"
+ sources="primary output,hifi_output"/>
</routes>
</module>