Select first output supporting haptic if orphan haptic effect exist
Bug: 331687139
Test: atest CtsMediaAudioTestCases
Test: Hatptic test app on Pixel
Change-Id: Idcb2bb99f155555976baa0e6ed805ed0b8497baf
Merged-In: Idcb2bb99f155555976baa0e6ed805ed0b8497baf
diff --git a/services/audiopolicy/common/managerdefinitions/include/EffectDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/EffectDescriptor.h
index c2e4b11..b92cd70 100644
--- a/services/audiopolicy/common/managerdefinitions/include/EffectDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/EffectDescriptor.h
@@ -32,11 +32,15 @@
class EffectDescriptor : public RefBase
{
public:
- EffectDescriptor(const effect_descriptor_t *desc, bool isMusicEffect,
- int id, audio_io_handle_t io, audio_session_t session) :
- mId(id), mIo(io), mSession(session), mEnabled(false), mSuspended(false),
- mIsMusicEffect(isMusicEffect)
- {
+ EffectDescriptor(const effect_descriptor_t* desc, bool isMusicEffect, int id,
+ audio_io_handle_t io, audio_session_t session)
+ : mId(id),
+ mIo(io),
+ mIsOrphan(io == AUDIO_IO_HANDLE_NONE),
+ mSession(session),
+ mEnabled(false),
+ mSuspended(false),
+ mIsMusicEffect(isMusicEffect) {
memcpy (&mDesc, desc, sizeof(effect_descriptor_t));
}
@@ -95,11 +99,22 @@
* @return ioHandle if found, AUDIO_IO_HANDLE_NONE otherwise.
*/
audio_io_handle_t getIoForSession(audio_session_t sessionId,
- const effect_uuid_t *effectType = nullptr);
- bool hasOrphansForSession(audio_session_t sessionId);
+ const effect_uuid_t *effectType = nullptr) const;
+ bool hasOrphansForSession(audio_session_t sessionId) const;
EffectDescriptorCollection getOrphanEffectsForSession(audio_session_t sessionId) const;
void dump(String8 *dst, int spaces = 0, bool verbose = true) const;
+ /**
+ * @brief Checks if there is at least one orphan effect with given sessionId and effect type
+ * uuid.
+ * @param sessionId Session ID.
+ * @param effectType Effect type UUID, the implementation will be same as hasOrphansForSession
+ * if null.
+ * @return True if there is an orphan effect for given sessionId and type UUID, false otherwise.
+ */
+ bool hasOrphanEffectsForSessionAndType(audio_session_t sessionId,
+ const effect_uuid_t* effectType) const;
+
private:
status_t setEffectEnabled(const sp<EffectDescriptor> &effectDesc, bool enabled);
diff --git a/services/audiopolicy/common/managerdefinitions/src/EffectDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/EffectDescriptor.cpp
index c85df0f..7971b61 100644
--- a/services/audiopolicy/common/managerdefinitions/src/EffectDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/EffectDescriptor.cpp
@@ -210,7 +210,7 @@
}
}
-bool EffectDescriptorCollection::hasOrphansForSession(audio_session_t sessionId)
+bool EffectDescriptorCollection::hasOrphansForSession(audio_session_t sessionId) const
{
for (size_t i = 0; i < size(); ++i) {
sp<EffectDescriptor> effect = valueAt(i);
@@ -221,6 +221,22 @@
return false;
}
+bool EffectDescriptorCollection::hasOrphanEffectsForSessionAndType(
+ audio_session_t sessionId, const effect_uuid_t* effectType) const {
+ if (effectType == nullptr) {
+ return hasOrphansForSession(sessionId);
+ }
+
+ for (size_t i = 0; i < size(); ++i) {
+ sp<EffectDescriptor> effect = valueAt(i);
+ if (effect->mIsOrphan && effect->mSession == sessionId &&
+ memcmp(&effect->mDesc.type, effectType, sizeof(effect_uuid_t)) == 0) {
+ return true;
+ }
+ }
+ return false;
+}
+
EffectDescriptorCollection EffectDescriptorCollection::getOrphanEffectsForSession(
audio_session_t sessionId) const
{
@@ -235,7 +251,7 @@
}
audio_io_handle_t EffectDescriptorCollection::getIoForSession(audio_session_t sessionId,
- const effect_uuid_t *effectType)
+ const effect_uuid_t *effectType) const
{
for (size_t i = 0; i < size(); ++i) {
sp<EffectDescriptor> effect = valueAt(i);
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 8ef76c6..f767522 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -2069,6 +2069,8 @@
// matching criteria values in priority order for best matching output so far
std::vector<uint32_t> bestMatchCriteria(8, 0);
+ const bool hasOrphanHaptic =
+ mEffects.hasOrphanEffectsForSessionAndType(sessionId, FX_IID_HAPTICGENERATOR);
const uint32_t channelCount = audio_channel_count_from_out_mask(channelMask);
const uint32_t hapticChannelCount = audio_channel_count_from_out_mask(
channelMask & AUDIO_CHANNEL_HAPTIC_ALL);
@@ -2089,13 +2091,20 @@
// When using haptic output, same audio format and sample rate are required.
const uint32_t outputHapticChannelCount = audio_channel_count_from_out_mask(
outputDesc->getChannelMask() & AUDIO_CHANNEL_HAPTIC_ALL);
- if ((hapticChannelCount == 0) != (outputHapticChannelCount == 0)) {
+ // skip if haptic channel specified but output does not support it, or output support haptic
+ // but there is no haptic channel requested AND no orphan haptic effect exist
+ if ((hapticChannelCount != 0 && outputHapticChannelCount == 0) ||
+ (hapticChannelCount == 0 && outputHapticChannelCount != 0 && !hasOrphanHaptic)) {
continue;
}
- if (outputHapticChannelCount >= hapticChannelCount
- && format == outputDesc->getFormat()
- && samplingRate == outputDesc->getSamplingRate()) {
- currentMatchCriteria[0] = outputHapticChannelCount;
+ // In the case of audio-coupled-haptic playback, there is no format conversion and
+ // resampling in the framework, same format/channel/sampleRate for client and the output
+ // thread is required. In the case of HapticGenerator effect, do not require format
+ // matching.
+ if ((outputHapticChannelCount >= hapticChannelCount && format == outputDesc->getFormat() &&
+ samplingRate == outputDesc->getSamplingRate()) ||
+ (hapticChannelCount == 0 && hasOrphanHaptic)) {
+ currentMatchCriteria[0] = outputHapticChannelCount;
}
// functional flags match