Merge changes from topic "libaudiohal_audiohalversion"
* changes:
Update AudioFlinger with AudioHalVersionInfo
Update libaudiohal with AudioHalVersionInfo
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/media/libheif/HeifDecoderImpl.cpp b/media/libheif/HeifDecoderImpl.cpp
index 691eede..7c78900 100644
--- a/media/libheif/HeifDecoderImpl.cpp
+++ b/media/libheif/HeifDecoderImpl.cpp
@@ -518,7 +518,6 @@
{
Mutex::Autolock _l(mRetrieverLock);
weakRetriever = mRetriever;
- mRetriever.clear();
}
for (size_t i = 1; i < mNumSlices; i++) {
@@ -551,6 +550,12 @@
}
}
// Hold on to mDataSource in case the client wants to redecode.
+
+ {
+ Mutex::Autolock _l(mRetrieverLock);
+ mRetriever.clear();
+ }
+
return false;
}
@@ -660,7 +665,10 @@
mFrameDecoded = true;
// Aggressively clear to avoid holding on to resources
- mRetriever.clear();
+ {
+ Mutex::Autolock _l(mRetrieverLock);
+ mRetriever.clear();
+ }
// Hold on to mDataSource in case the client wants to redecode.
return true;
diff --git a/media/libmediametrics/include/MediaMetricsConstants.h b/media/libmediametrics/include/MediaMetricsConstants.h
index 27f987d..ba3df59 100644
--- a/media/libmediametrics/include/MediaMetricsConstants.h
+++ b/media/libmediametrics/include/MediaMetricsConstants.h
@@ -72,6 +72,7 @@
// Keys are strings used for MediaMetrics Item Keys
#define AMEDIAMETRICS_KEY_AUDIO_FLINGER AMEDIAMETRICS_KEY_PREFIX_AUDIO "flinger"
+#define AMEDIAMETRICS_KEY_AUDIO_MIDI AMEDIAMETRICS_KEY_PREFIX_AUDIO "midi"
#define AMEDIAMETRICS_KEY_AUDIO_POLICY AMEDIAMETRICS_KEY_PREFIX_AUDIO "policy"
// Error keys
@@ -124,9 +125,13 @@
#define AMEDIAMETRICS_PROP_CHANNELMASK "channelMask" // int32
#define AMEDIAMETRICS_PROP_CHANNELMASKS "channelMasks" // string with channelMask values
// separated by |.
+#define AMEDIAMETRICS_PROP_CLOSEDCOUNT "closedCount" // int32 (MIDI)
#define AMEDIAMETRICS_PROP_CONTENTTYPE "contentType" // string attributes (AudioTrack)
#define AMEDIAMETRICS_PROP_CUMULATIVETIMENS "cumulativeTimeNs" // int64_t playback/record time
// since start
+#define AMEDIAMETRICS_PROP_DEVICEDISCONNECTED "deviceDisconnected" // string true/false (MIDI)
+#define AMEDIAMETRICS_PROP_DEVICEID "deviceId" // int32 device id (MIDI)
+
// DEVICE values are averaged since starting on device
#define AMEDIAMETRICS_PROP_DEVICELATENCYMS "deviceLatencyMs" // double - avg latency time
#define AMEDIAMETRICS_PROP_DEVICESTARTUPMS "deviceStartupMs" // double - avg startup time
@@ -150,12 +155,15 @@
#define AMEDIAMETRICS_PROP_FLAGS "flags"
#define AMEDIAMETRICS_PROP_FRAMECOUNT "frameCount" // int32
+#define AMEDIAMETRICS_PROP_HARDWARETYPE "hardwareType" // int32 (MIDI)
#define AMEDIAMETRICS_PROP_HASHEADTRACKER "hasHeadTracker" // string true/false
#define AMEDIAMETRICS_PROP_HEADTRACKERENABLED "headTrackerEnabled" // string true/false
#define AMEDIAMETRICS_PROP_HEADTRACKINGMODES "headTrackingModes" // string |, like modes.
#define AMEDIAMETRICS_PROP_INPUTDEVICES "inputDevices" // string value
+#define AMEDIAMETRICS_PROP_INPUTPORTCOUNT "inputPortCount" // int32 (MIDI)
#define AMEDIAMETRICS_PROP_INTERNALTRACKID "internalTrackId" // int32
#define AMEDIAMETRICS_PROP_INTERVALCOUNT "intervalCount" // int32
+#define AMEDIAMETRICS_PROP_ISSHARED "isShared" // string true/false (MIDI)
#define AMEDIAMETRICS_PROP_LATENCYMS "latencyMs" // double value
#define AMEDIAMETRICS_PROP_LEVELS "levels" // string | with levels
#define AMEDIAMETRICS_PROP_LOGSESSIONID "logSessionId" // hex string, "" none
@@ -165,7 +173,9 @@
#define AMEDIAMETRICS_PROP_MODES "modes" // string | with modes
#define AMEDIAMETRICS_PROP_NAME "name" // string value
#define AMEDIAMETRICS_PROP_ORIGINALFLAGS "originalFlags" // int32
+#define AMEDIAMETRICS_PROP_OPENEDCOUNT "openedCount" // int32 (MIDI)
#define AMEDIAMETRICS_PROP_OUTPUTDEVICES "outputDevices" // string value
+#define AMEDIAMETRICS_PROP_OUTPUTPORTCOUNT "outputPortCount" // int32 (MIDI)
#define AMEDIAMETRICS_PROP_PERFORMANCEMODE "performanceMode" // string value, "none", lowLatency"
#define AMEDIAMETRICS_PROP_PLAYBACK_PITCH "playback.pitch" // double value (AudioTrack)
#define AMEDIAMETRICS_PROP_PLAYBACK_SPEED "playback.speed" // double value (AudioTrack)
@@ -194,6 +204,13 @@
// Treated as "debug" information.
#define AMEDIAMETRICS_PROP_STREAMTYPE "streamType" // string (AudioTrack)
+#define AMEDIAMETRICS_PROP_SUPPORTSMIDIUMP "supportsMidiUmp" // string true/false (MIDI).
+ // Universal MIDI Packets is a new
+ // format to transport packets.
+ // Raw byte streams are used if this
+ // is false.
+#define AMEDIAMETRICS_PROP_TOTALINPUTBYTES "totalInputBytes" // int32 (MIDI)
+#define AMEDIAMETRICS_PROP_TOTALOUTPUTBYTES "totalOutputBytes" // int32 (MIDI)
#define AMEDIAMETRICS_PROP_THREADID "threadId" // int32 value io handle
#define AMEDIAMETRICS_PROP_THROTTLEMS "throttleMs" // double
#define AMEDIAMETRICS_PROP_TRACKID "trackId" // int32 port id of track/record
@@ -202,6 +219,7 @@
#define AMEDIAMETRICS_PROP_UNDERRUN "underrun" // int32
#define AMEDIAMETRICS_PROP_UNDERRUNFRAMES "underrunFrames" // int64_t from Thread
#define AMEDIAMETRICS_PROP_USAGE "usage" // string attributes (ATrack)
+#define AMEDIAMETRICS_PROP_USINGALSA "usingAlsa" // string true/false (MIDI)
#define AMEDIAMETRICS_PROP_VOICEVOLUME "voiceVolume" // double (audio.flinger)
#define AMEDIAMETRICS_PROP_VOLUME_LEFT "volume.left" // double (AudioTrack)
#define AMEDIAMETRICS_PROP_VOLUME_RIGHT "volume.right" // double (AudioTrack)
@@ -226,6 +244,7 @@
#define AMEDIAMETRICS_PROP_EVENT_VALUE_CREATE "create"
#define AMEDIAMETRICS_PROP_EVENT_VALUE_CREATEAUDIOPATCH "createAudioPatch"
#define AMEDIAMETRICS_PROP_EVENT_VALUE_CTOR "ctor"
+#define AMEDIAMETRICS_PROP_EVENT_VALUE_DEVICECLOSED "deviceClosed" // MIDI
#define AMEDIAMETRICS_PROP_EVENT_VALUE_DISCONNECT "disconnect"
#define AMEDIAMETRICS_PROP_EVENT_VALUE_DTOR "dtor"
#define AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAAUDIOSTREAM "endAAudioStream" // AAudioStream
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index cced6b5..f3ef39e 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -354,8 +354,11 @@
}
//static
-Mutex MediaCodec::ResourceManagerServiceProxy::sLockCookies;
-std::set<void*> MediaCodec::ResourceManagerServiceProxy::sCookies;
+// these are no_destroy to keep them from being destroyed at process exit
+// where some thread calls exit() while other threads are still running.
+// see b/194783918
+[[clang::no_destroy]] Mutex MediaCodec::ResourceManagerServiceProxy::sLockCookies;
+[[clang::no_destroy]] std::set<void*> MediaCodec::ResourceManagerServiceProxy::sCookies;
//static
void MediaCodec::ResourceManagerServiceProxy::addCookie(void* cookie) {
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>
diff --git a/services/mediametrics/AudioAnalytics.cpp b/services/mediametrics/AudioAnalytics.cpp
index 119bb6c..7af6c41 100644
--- a/services/mediametrics/AudioAnalytics.cpp
+++ b/services/mediametrics/AudioAnalytics.cpp
@@ -269,6 +269,24 @@
"enabled",
};
+static constexpr const char * const MidiDeviceCloseFields[] {
+ "mediametrics_midi_device_close_reported",
+ "uid",
+ "midi_device_id",
+ "input_port_count",
+ "output_port_count",
+ "device_type",
+ "is_shared",
+ "supports_ump",
+ "using_alsa",
+ "duration_ns",
+ "opened_count",
+ "closed_count",
+ "device_disconnected",
+ "total_input_bytes",
+ "total_output_bytes",
+};
+
/**
* printFields is a helper method that prints the fields and corresponding values
* in a human readable style.
@@ -497,6 +515,15 @@
[this](const std::shared_ptr<const android::mediametrics::Item> &item){
mSpatializer.onEvent(item);
}));
+
+ // Handle MIDI
+ mActions.addAction(
+ AMEDIAMETRICS_KEY_AUDIO_MIDI "." AMEDIAMETRICS_PROP_EVENT,
+ std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_DEVICECLOSED),
+ std::make_shared<AnalyticsActions::Function>(
+ [this](const std::shared_ptr<const android::mediametrics::Item> &item) {
+ mMidiLogging.onEvent(item);
+ }));
}
AudioAnalytics::~AudioAnalytics()
@@ -1710,6 +1737,127 @@
return { s, n };
}
+void AudioAnalytics::MidiLogging::onEvent(
+ const std::shared_ptr<const android::mediametrics::Item> &item) const {
+ const std::string& key = item->getKey();
+
+ const auto uid = item->getUid();
+
+ int32_t deviceId = -1;
+ mAudioAnalytics.mAnalyticsState->timeMachine().get(
+ key, AMEDIAMETRICS_PROP_DEVICEID, &deviceId);
+
+ int32_t inputPortCount = -1;
+ mAudioAnalytics.mAnalyticsState->timeMachine().get(
+ key, AMEDIAMETRICS_PROP_INPUTPORTCOUNT, &inputPortCount);
+
+ int32_t outputPortCount = -1;
+ mAudioAnalytics.mAnalyticsState->timeMachine().get(
+ key, AMEDIAMETRICS_PROP_OUTPUTPORTCOUNT, &outputPortCount);
+
+ int32_t hardwareType = -1;
+ mAudioAnalytics.mAnalyticsState->timeMachine().get(
+ key, AMEDIAMETRICS_PROP_HARDWARETYPE, &hardwareType);
+
+ std::string isSharedString;
+ mAudioAnalytics.mAnalyticsState->timeMachine().get(
+ key, AMEDIAMETRICS_PROP_ISSHARED, &isSharedString);
+ const bool isShared = (isSharedString == "true");
+
+ std::string supportsMidiUmpString;
+ mAudioAnalytics.mAnalyticsState->timeMachine().get(
+ key, AMEDIAMETRICS_PROP_SUPPORTSMIDIUMP, &supportsMidiUmpString);
+ const bool supportsMidiUmp = (supportsMidiUmpString == "true");
+
+ std::string usingAlsaString;
+ mAudioAnalytics.mAnalyticsState->timeMachine().get(
+ key, AMEDIAMETRICS_PROP_USINGALSA, &usingAlsaString);
+ const bool usingAlsa = (usingAlsaString == "true");
+
+ int64_t durationNs = -1;
+ mAudioAnalytics.mAnalyticsState->timeMachine().get(
+ key, AMEDIAMETRICS_PROP_DURATIONNS, &durationNs);
+
+ int32_t openedCount = -1;
+ mAudioAnalytics.mAnalyticsState->timeMachine().get(
+ key, AMEDIAMETRICS_PROP_OPENEDCOUNT, &openedCount);
+
+ int32_t closedCount = -1;
+ mAudioAnalytics.mAnalyticsState->timeMachine().get(
+ key, AMEDIAMETRICS_PROP_CLOSEDCOUNT, &closedCount);
+
+ std::string deviceDisconnectedString;
+ mAudioAnalytics.mAnalyticsState->timeMachine().get(
+ key, AMEDIAMETRICS_PROP_DEVICEDISCONNECTED, &deviceDisconnectedString);
+ const bool deviceDisconnected = (deviceDisconnectedString == "true");
+
+ int32_t totalInputBytes = -1;
+ mAudioAnalytics.mAnalyticsState->timeMachine().get(
+ key, AMEDIAMETRICS_PROP_TOTALINPUTBYTES, &totalInputBytes);
+
+ int32_t totalOutputBytes = -1;
+ mAudioAnalytics.mAnalyticsState->timeMachine().get(
+ key, AMEDIAMETRICS_PROP_TOTALOUTPUTBYTES, &totalOutputBytes);
+
+ LOG(LOG_LEVEL) << "key:" << key
+ << " uid:" << uid
+ << " id:" << deviceId
+ << " input_port_count:" << inputPortCount
+ << " output_port_count:" << outputPortCount
+ << " device_type:" << hardwareType
+ << " is_shared:" << isSharedString
+ << " supports_ump:" << supportsMidiUmpString
+ << " using_alsa:" << usingAlsaString
+ << " duration_opened_ms:" << durationNs
+ << " opened_count:" << openedCount
+ << " closed_count:" << closedCount
+ << " device_disconnected:" << deviceDisconnectedString
+ << " total_input_bytes:" << totalInputBytes
+ << " total_output_bytes:" << totalOutputBytes;
+
+ if (mAudioAnalytics.mDeliverStatistics) {
+ const auto result = sendToStatsd(
+ CONDITION(stats::media_metrics::MEDIAMETRICS_MIDI_DEVICE_CLOSE_REPORTED)
+ , uid
+ , deviceId
+ , inputPortCount
+ , outputPortCount
+ , hardwareType
+ , isShared
+ , supportsMidiUmp
+ , usingAlsa
+ , durationNs
+ , openedCount
+ , closedCount
+ , deviceDisconnected
+ , totalInputBytes
+ , totalOutputBytes);
+ std::stringstream ss;
+ ss << "result:" << result;
+ const auto fieldsStr = printFields(MidiDeviceCloseFields,
+ CONDITION(stats::media_metrics::MEDIAMETRICS_MIDI_DEVICE_CLOSE_REPORTED)
+ , uid
+ , deviceId
+ , inputPortCount
+ , outputPortCount
+ , hardwareType
+ , isShared
+ , supportsMidiUmp
+ , usingAlsa
+ , durationNs
+ , openedCount
+ , closedCount
+ , deviceDisconnected
+ , totalInputBytes
+ , totalOutputBytes);
+ ss << " " << fieldsStr;
+ std::string str = ss.str();
+ ALOGV("%s: statsd %s", __func__, str.c_str());
+ mAudioAnalytics.mStatsdLog->log(
+ stats::media_metrics::MEDIAMETRICS_MIDI_DEVICE_CLOSE_REPORTED, str);
+ }
+}
+
// This method currently suppresses the name.
std::string AudioAnalytics::getDeviceNamesFromOutputDevices(std::string_view devices) const {
std::string deviceNames;
diff --git a/services/mediametrics/include/mediametricsservice/AudioAnalytics.h b/services/mediametrics/include/mediametricsservice/AudioAnalytics.h
index 82e928e..f0a4ac8 100644
--- a/services/mediametrics/include/mediametricsservice/AudioAnalytics.h
+++ b/services/mediametrics/include/mediametricsservice/AudioAnalytics.h
@@ -363,6 +363,20 @@
SimpleLog mSimpleLog GUARDED_BY(mLock) {64};
} mSpatializer{*this};
+ // MidiLogging collects info whenever a MIDI device is closed.
+ class MidiLogging {
+ public:
+ explicit MidiLogging(AudioAnalytics &audioAnalytics)
+ : mAudioAnalytics(audioAnalytics) {}
+
+ void onEvent(
+ const std::shared_ptr<const android::mediametrics::Item> &item) const;
+
+ private:
+
+ AudioAnalytics &mAudioAnalytics;
+ } mMidiLogging{*this};
+
AudioPowerUsage mAudioPowerUsage;
};