Force selecting haptic supported thread when creating HapticGenerator.
HapticGenerator is the haptic-generating effect, which will generate
haptic data based on audio data. As haptic data will be truncated on
non-haptic supported thread, HapticGenerator makes sense only on haptic
supported thread. In that case, force selecting haptic supported thread
when creating HapticGenerator. If there is no thread supporting haptics
channel, return a failure.
Bug: 136490803
Test: make, manually
Change-Id: I865d211c613c793d75d23f5d10c9a01d294fdc36
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index c252d77..b6a50a5 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -1243,6 +1243,11 @@
return BAD_VALUE;
}
}
+
+ if (EffectModule::isHapticGenerator(&desc->type)) {
+ ALOGE("%s(): HapticGenerator is not supported in RecordThread", __func__);
+ return BAD_VALUE;
+ }
return NO_ERROR;
}
@@ -1262,6 +1267,12 @@
return NO_ERROR;
}
+ if (EffectModule::isHapticGenerator(&desc->type) && mHapticChannelCount == 0) {
+ ALOGW("%s: thread doesn't support haptic playback while the effect is HapticGenerator",
+ __func__);
+ return BAD_VALUE;
+ }
+
switch (mType) {
case MIXER: {
#ifndef MULTICHANNEL_EFFECT_CHAIN
@@ -2527,8 +2538,10 @@
track->sharedBuffer() != 0 ? Track::FS_FILLED : Track::FS_FILLING;
}
- if ((track->channelMask() & AUDIO_CHANNEL_HAPTIC_ALL) != AUDIO_CHANNEL_NONE
- && mHapticChannelMask != AUDIO_CHANNEL_NONE) {
+ sp<EffectChain> chain = getEffectChain_l(track->sessionId());
+ if (mHapticChannelMask != AUDIO_CHANNEL_NONE
+ && ((track->channelMask() & AUDIO_CHANNEL_HAPTIC_ALL) != AUDIO_CHANNEL_NONE
+ || (chain != nullptr && chain->containsHapticGeneratingEffect_l()))) {
// Unlock due to VibratorService will lock for this call and will
// call Tracks.mute/unmute which also require thread's lock.
mLock.unlock();
@@ -2549,7 +2562,6 @@
track->mResetDone = false;
track->mPresentationCompleteFrames = 0;
mActiveTracks.add(track);
- sp<EffectChain> chain = getEffectChain_l(track->sessionId());
if (chain != 0) {
ALOGV("addTrack_l() starting track on chain %p for session %d", chain.get(),
track->sessionId());
@@ -3732,9 +3744,15 @@
// Determine which session to pick up haptic data.
// This must be done under the same lock as prepareTracks_l().
+ // The haptic data from the effect is at a higher priority than the one from track.
// TODO: Write haptic data directly to sink buffer when mixing.
if (mHapticChannelCount > 0 && effectChains.size() > 0) {
for (const auto& track : mActiveTracks) {
+ sp<EffectChain> effectChain = getEffectChain_l(track->sessionId());
+ if (effectChain != nullptr && effectChain->containsHapticGeneratingEffect_l()) {
+ activeHapticSessionId = track->sessionId();
+ break;
+ }
if (track->getHapticPlaybackEnabled()) {
activeHapticSessionId = track->sessionId();
break;
@@ -4104,8 +4122,9 @@
// remove from our tracks vector
removeTrack_l(track);
}
- if ((track->channelMask() & AUDIO_CHANNEL_HAPTIC_ALL) != AUDIO_CHANNEL_NONE
- && mHapticChannelCount > 0) {
+ if (mHapticChannelCount > 0 &&
+ ((track->channelMask() & AUDIO_CHANNEL_HAPTIC_ALL) != AUDIO_CHANNEL_NONE
+ || (chain != nullptr && chain->containsHapticGeneratingEffect_l()))) {
mLock.unlock();
// Unlock due to VibratorService will lock for this call and will
// call Tracks.mute/unmute which also require thread's lock.
@@ -9393,6 +9412,11 @@
return BAD_VALUE;
}
+ if (EffectModule::isHapticGenerator(&desc->type)) {
+ ALOGE("%s(): HapticGenerator is not supported for MmapThread", __func__);
+ return BAD_VALUE;
+ }
+
return NO_ERROR;
}