Apply intensity control for haptic data.
Use the same logic in VibrationEffect.scale to control the intensity of
haptic playback in audio framework. Note that as the maximum amplitude
of vibrator is 255, convert the haptic data to pcm_8_bit before doing
scaling.
Test: Manually
Change-Id: I6136d27c9255a215834b6e3092aa8ad696fbae04
diff --git a/media/libaudioclient/include/media/AudioMixer.h b/media/libaudioclient/include/media/AudioMixer.h
index 3ae7104..fbbbd11 100644
--- a/media/libaudioclient/include/media/AudioMixer.h
+++ b/media/libaudioclient/include/media/AudioMixer.h
@@ -80,6 +80,7 @@
MIXER_CHANNEL_MASK = 0x4006, // Channel mask for mixer output
// for haptic
HAPTIC_ENABLED = 0x4007, // Set haptic data from this track should be played or not.
+ HAPTIC_INTENSITY = 0x4008, // Set the intensity to play haptic data.
// for target RESAMPLE
SAMPLE_RATE = 0x4100, // Configure sample rate conversion on this track name;
// parameter 'value' is the new sample rate in Hz.
@@ -102,6 +103,31 @@
// parameter 'value' is a pointer to the new playback rate.
};
+ enum { // Haptic intensity, should keep consistent with VibratorService
+ HAPTIC_SCALE_VERY_LOW = -2,
+ HAPTIC_SCALE_LOW = -1,
+ HAPTIC_SCALE_NONE = 0,
+ HAPTIC_SCALE_HIGH = 1,
+ HAPTIC_SCALE_VERY_HIGH = 2,
+ };
+ typedef int32_t haptic_intensity_t;
+ static constexpr float HAPTIC_SCALE_VERY_LOW_RATIO = 2 / 3;
+ static constexpr float HAPTIC_SCALE_LOW_RATIO = 3 / 4;
+ static const CONSTEXPR float HAPTIC_MAX_AMPLITUDE_FLOAT = 1.0f;
+
+ static inline bool isValidHapticIntensity(haptic_intensity_t hapticIntensity) {
+ switch (hapticIntensity) {
+ case HAPTIC_SCALE_VERY_LOW:
+ case HAPTIC_SCALE_LOW:
+ case HAPTIC_SCALE_NONE:
+ case HAPTIC_SCALE_HIGH:
+ case HAPTIC_SCALE_VERY_HIGH:
+ return true;
+ default:
+ return false;
+ }
+ }
+
AudioMixer(size_t frameCount, uint32_t sampleRate)
: mSampleRate(sampleRate)
, mFrameCount(frameCount) {
@@ -147,6 +173,7 @@
}
}
(this->*mHook)();
+ processHapticData();
}
size_t getUnreleasedFrames(int name) const;
@@ -364,6 +391,7 @@
// Haptic
bool mHapticPlaybackEnabled;
+ haptic_intensity_t mHapticIntensity;
audio_channel_mask_t mHapticChannelMask;
uint32_t mHapticChannelCount;
audio_channel_mask_t mMixerHapticChannelMask;
@@ -374,6 +402,37 @@
uint32_t mAdjustNonDestructiveOutChannelCount;
bool mKeepContractedChannels;
+ float getHapticScaleGamma() const {
+ // Need to keep consistent with the value in VibratorService.
+ switch (mHapticIntensity) {
+ case HAPTIC_SCALE_VERY_LOW:
+ return 2.0f;
+ case HAPTIC_SCALE_LOW:
+ return 1.5f;
+ case HAPTIC_SCALE_HIGH:
+ return 0.5f;
+ case HAPTIC_SCALE_VERY_HIGH:
+ return 0.25f;
+ default:
+ return 1.0f;
+ }
+ }
+
+ float getHapticMaxAmplitudeRatio() const {
+ // Need to keep consistent with the value in VibratorService.
+ switch (mHapticIntensity) {
+ case HAPTIC_SCALE_VERY_LOW:
+ return HAPTIC_SCALE_VERY_LOW_RATIO;
+ case HAPTIC_SCALE_LOW:
+ return HAPTIC_SCALE_LOW_RATIO;
+ case HAPTIC_SCALE_NONE:
+ case HAPTIC_SCALE_HIGH:
+ case HAPTIC_SCALE_VERY_HIGH:
+ default:
+ return 1.0f;
+ }
+ }
+
private:
// hooks
void track__genericResample(int32_t* out, size_t numFrames, int32_t* temp, int32_t* aux);
@@ -410,6 +469,8 @@
template <int MIXTYPE, typename TO, typename TI, typename TA>
void process__noResampleOneTrack();
+ void processHapticData();
+
static process_hook_t getProcessHook(int processType, uint32_t channelCount,
audio_format_t mixerInFormat, audio_format_t mixerOutFormat);
diff --git a/media/libaudioprocessing/AudioMixer.cpp b/media/libaudioprocessing/AudioMixer.cpp
index 86711de..86777d6 100644
--- a/media/libaudioprocessing/AudioMixer.cpp
+++ b/media/libaudioprocessing/AudioMixer.cpp
@@ -167,6 +167,7 @@
t->mPlaybackRate = AUDIO_PLAYBACK_RATE_DEFAULT;
// haptic
t->mHapticPlaybackEnabled = false;
+ t->mHapticIntensity = HAPTIC_SCALE_NONE;
t->mMixerHapticChannelMask = AUDIO_CHANNEL_NONE;
t->mMixerHapticChannelCount = 0;
t->mAdjustInChannelCount = t->channelCount + t->mHapticChannelCount;
@@ -717,6 +718,12 @@
track->prepareForAdjustChannels();
}
} break;
+ case HAPTIC_INTENSITY: {
+ const haptic_intensity_t hapticIntensity = static_cast<haptic_intensity_t>(valueInt);
+ if (track->mHapticIntensity != hapticIntensity) {
+ track->mHapticIntensity = hapticIntensity;
+ }
+ } break;
default:
LOG_ALWAYS_FATAL("setParameter track: bad param %d", param);
}
@@ -1846,6 +1853,40 @@
}
}
+void AudioMixer::processHapticData()
+{
+ // Need to keep consistent with VibrationEffect.scale(int, float, int)
+ for (const auto &pair : mGroups) {
+ // process by group of tracks with same output main buffer.
+ const auto &group = pair.second;
+ for (const int name : group) {
+ const std::shared_ptr<Track> &t = mTracks[name];
+ if (t->mHapticPlaybackEnabled) {
+ size_t sampleCount = mFrameCount * t->mMixerHapticChannelCount;
+ float gamma = t->getHapticScaleGamma();
+ float maxAmplitudeRatio = t->getHapticMaxAmplitudeRatio();
+ uint8_t* buffer = (uint8_t*)pair.first + mFrameCount * audio_bytes_per_frame(
+ t->mMixerChannelCount, t->mMixerFormat);
+ switch (t->mMixerFormat) {
+ // Mixer format should be AUDIO_FORMAT_PCM_FLOAT.
+ case AUDIO_FORMAT_PCM_FLOAT: {
+ float* fout = (float*) buffer;
+ for (size_t i = 0; i < sampleCount; i++) {
+ float mul = fout[i] >= 0 ? 1.0 : -1.0;
+ fout[i] = powf(fabsf(fout[i] / HAPTIC_MAX_AMPLITUDE_FLOAT), gamma)
+ * maxAmplitudeRatio * HAPTIC_MAX_AMPLITUDE_FLOAT * mul;
+ }
+ } break;
+ default:
+ LOG_ALWAYS_FATAL("bad mMixerFormat: %#x", t->mMixerFormat);
+ break;
+ }
+ break;
+ }
+ }
+ }
+}
+
/* This track hook is called to do resampling then mixing,
* pulling from the track's upstream AudioBufferProvider.
*
diff --git a/services/audioflinger/FastMixer.cpp b/services/audioflinger/FastMixer.cpp
index f328577..ca0d749 100644
--- a/services/audioflinger/FastMixer.cpp
+++ b/services/audioflinger/FastMixer.cpp
@@ -295,6 +295,8 @@
(void *)(uintptr_t)mSinkChannelMask);
mMixer->setParameter(name, AudioMixer::TRACK, AudioMixer::HAPTIC_ENABLED,
(void *)(uintptr_t)fastTrack->mHapticPlaybackEnabled);
+ mMixer->setParameter(name, AudioMixer::TRACK, AudioMixer::HAPTIC_INTENSITY,
+ (void *)(uintptr_t)fastTrack->mHapticIntensity);
mMixer->enable(name);
}
mGenerations[i] = fastTrack->mGeneration;
@@ -333,6 +335,8 @@
(void *)(uintptr_t)mSinkChannelMask);
mMixer->setParameter(name, AudioMixer::TRACK, AudioMixer::HAPTIC_ENABLED,
(void *)(uintptr_t)fastTrack->mHapticPlaybackEnabled);
+ mMixer->setParameter(name, AudioMixer::TRACK, AudioMixer::HAPTIC_INTENSITY,
+ (void *)(uintptr_t)fastTrack->mHapticIntensity);
// already enabled
}
mGenerations[i] = fastTrack->mGeneration;
diff --git a/services/audioflinger/FastMixerState.h b/services/audioflinger/FastMixerState.h
index 9d2a733..c27f2b7 100644
--- a/services/audioflinger/FastMixerState.h
+++ b/services/audioflinger/FastMixerState.h
@@ -19,6 +19,7 @@
#include <audio_utils/minifloat.h>
#include <system/audio.h>
+#include <media/AudioMixer.h>
#include <media/ExtendedAudioBufferProvider.h>
#include <media/nbaio/NBAIO.h>
#include <media/nblog/NBLog.h>
@@ -48,6 +49,8 @@
audio_format_t mFormat; // track format
int mGeneration; // increment when any field is assigned
bool mHapticPlaybackEnabled = false; // haptic playback is enabled or not
+ AudioMixer::haptic_intensity_t mHapticIntensity = AudioMixer::HAPTIC_SCALE_NONE; // intensity of
+ // haptic data
};
// Represents a single state of the fast mixer
diff --git a/services/audioflinger/PlaybackTracks.h b/services/audioflinger/PlaybackTracks.h
index d9f570d..8aeae7d 100644
--- a/services/audioflinger/PlaybackTracks.h
+++ b/services/audioflinger/PlaybackTracks.h
@@ -119,6 +119,14 @@
void setHapticPlaybackEnabled(bool hapticPlaybackEnabled) {
mHapticPlaybackEnabled = hapticPlaybackEnabled;
}
+ /** Return at what intensity to play haptics, used in mixer. */
+ AudioMixer::haptic_intensity_t getHapticIntensity() const { return mHapticIntensity; }
+ /** Set intensity of haptic playback, should be set after querying vibrator service. */
+ void setHapticIntensity(AudioMixer::haptic_intensity_t hapticIntensity) {
+ if (AudioMixer::isValidHapticIntensity(hapticIntensity)) {
+ mHapticIntensity = hapticIntensity;
+ }
+ }
protected:
// for numerous
@@ -197,6 +205,8 @@
sp<media::VolumeHandler> mVolumeHandler; // handles multiple VolumeShaper configs and operations
bool mHapticPlaybackEnabled = false; // indicates haptic playback enabled or not
+ // intensity to play haptic data
+ AudioMixer::haptic_intensity_t mHapticIntensity = AudioMixer::HAPTIC_SCALE_NONE;
private:
// The following fields are only for fast tracks, and should be in a subclass
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 9f838a3..c8480c3 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -4615,6 +4615,7 @@
fastTrack->mChannelMask = track->mChannelMask;
fastTrack->mFormat = track->mFormat;
fastTrack->mHapticPlaybackEnabled = track->getHapticPlaybackEnabled();
+ fastTrack->mHapticIntensity = track->getHapticIntensity();
fastTrack->mGeneration++;
state->mTrackMask |= 1 << j;
didModify = true;
@@ -4937,6 +4938,10 @@
trackId,
AudioMixer::TRACK,
AudioMixer::HAPTIC_ENABLED, (void *)(uintptr_t)track->getHapticPlaybackEnabled());
+ mAudioMixer->setParameter(
+ trackId,
+ AudioMixer::TRACK,
+ AudioMixer::HAPTIC_INTENSITY, (void *)(uintptr_t)track->getHapticIntensity());
// reset retry count
track->mRetryCount = kMaxTrackRetries;