VolumeShaper: Initial implementation
The VolumeShaper is used to apply a volume
envelope to an AudioTrack or a MediaPlayer.
Test: CTS
Bug: 30920125
Bug: 31015569
Change-Id: I42e2f13bd6879299dc780e60d143c2d465483a44
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index e97d1ed..fa4f68a 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -54,6 +54,7 @@
#include <media/AudioMixer.h>
#include <media/ExtendedAudioBufferProvider.h>
#include <media/LinearMap.h>
+#include <media/VolumeShaper.h>
#include "FastCapture.h"
#include "FastMixer.h"
@@ -506,6 +507,10 @@
virtual void pause();
virtual status_t attachAuxEffect(int effectId);
virtual status_t setParameters(const String8& keyValuePairs);
+ virtual VolumeShaper::Status applyVolumeShaper(
+ const sp<VolumeShaper::Configuration>& configuration,
+ const sp<VolumeShaper::Operation>& operation) override;
+ virtual sp<VolumeShaper::State> getVolumeShaperState(int id) override;
virtual status_t getTimestamp(AudioTimestamp& timestamp);
virtual void signal(); // signal playback thread for a change in control block
diff --git a/services/audioflinger/PlaybackTracks.h b/services/audioflinger/PlaybackTracks.h
index 27e4627..02cac38 100644
--- a/services/audioflinger/PlaybackTracks.h
+++ b/services/audioflinger/PlaybackTracks.h
@@ -76,6 +76,13 @@
virtual bool isFastTrack() const { return (mFlags & AUDIO_OUTPUT_FLAG_FAST) != 0; }
+// implement volume handling.
+ VolumeShaper::Status applyVolumeShaper(
+ const sp<VolumeShaper::Configuration>& configuration,
+ const sp<VolumeShaper::Operation>& operation);
+sp<VolumeShaper::State> getVolumeShaperState(int id);
+ sp<VolumeHandler> getVolumeHandler() { return mVolumeHandler; }
+
protected:
// for numerous
friend class PlaybackThread;
@@ -153,6 +160,8 @@
ExtendedTimestamp mSinkTimestamp;
+ sp<VolumeHandler> mVolumeHandler; // handles multiple VolumeShaper configs and operations
+
private:
// The following fields are only for fast tracks, and should be in a subclass
int mFastIndex; // index within FastMixerState::mFastTracks[];
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index a1d81f9..3ba7881 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -4114,7 +4114,11 @@
}
// cache the combined master volume and stream type volume for fast mixer; this
// lacks any synchronization or barrier so VolumeProvider may read a stale value
- track->mCachedVolume = masterVolume * mStreamTypes[track->streamType()].volume;
+ const float vh = track->getVolumeHandler()->getVolume(
+ track->mAudioTrackServerProxy->framesReleased());
+ track->mCachedVolume = masterVolume
+ * mStreamTypes[track->streamType()].volume
+ * vh;
++fastTracks;
} else {
// was it previously active?
@@ -4256,9 +4260,11 @@
ALOGV("Track right volume out of range: %.3g", vrf);
vrf = GAIN_FLOAT_UNITY;
}
- // now apply the master volume and stream type volume
- vlf *= v;
- vrf *= v;
+ const float vh = track->getVolumeHandler()->getVolume(
+ track->mAudioTrackServerProxy->framesReleased());
+ // now apply the master volume and stream type volume and shaper volume
+ vlf *= v * vh;
+ vrf *= v * vh;
// assuming master volume and stream type volume each go up to 1.0,
// then derive vl and vr as U8.24 versions for the effect chain
const float scaleto8_24 = MAX_GAIN_INT * MAX_GAIN_INT;
@@ -4743,6 +4749,15 @@
float typeVolume = mStreamTypes[track->streamType()].volume;
float v = mMasterVolume * typeVolume;
sp<AudioTrackServerProxy> proxy = track->mAudioTrackServerProxy;
+
+ if (audio_is_linear_pcm(mFormat) && !usesHwAvSync()) {
+ const float vh = track->getVolumeHandler()->getVolume(
+ track->mAudioTrackServerProxy->framesReleased());
+ v *= vh;
+ } else {
+ // TODO: implement volume scaling in HW
+ }
+
gain_minifloat_packed_t vlr = proxy->getVolumeLR();
left = float_from_gain(gain_minifloat_unpack_left(vlr));
if (left > GAIN_FLOAT_UNITY) {
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index f2dd884..b772b5e 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -312,6 +312,16 @@
return mTrack->setParameters(keyValuePairs);
}
+VolumeShaper::Status AudioFlinger::TrackHandle::applyVolumeShaper(
+ const sp<VolumeShaper::Configuration>& configuration,
+ const sp<VolumeShaper::Operation>& operation) {
+ return mTrack->applyVolumeShaper(configuration, operation);
+}
+
+sp<VolumeShaper::State> AudioFlinger::TrackHandle::getVolumeShaperState(int id) {
+ return mTrack->getVolumeShaperState(id);
+}
+
status_t AudioFlinger::TrackHandle::getTimestamp(AudioTimestamp& timestamp)
{
return mTrack->getTimestamp(timestamp);
@@ -362,6 +372,7 @@
mAuxEffectId(0), mHasVolumeController(false),
mPresentationCompleteFrames(0),
mFrameMap(16 /* sink-frame-to-track-frame map memory */),
+ mVolumeHandler(new VolumeHandler(sampleRate)),
// mSinkTimestamp
mFastIndex(-1),
mCachedVolume(1.0),
@@ -874,6 +885,24 @@
}
}
+VolumeShaper::Status AudioFlinger::PlaybackThread::Track::applyVolumeShaper(
+ const sp<VolumeShaper::Configuration>& configuration,
+ const sp<VolumeShaper::Operation>& operation)
+{
+ // Note: We don't check if Thread exists.
+
+ // mVolumeHandler is thread-safe.
+ return mVolumeHandler->applyVolumeShaper(configuration, operation);
+}
+
+sp<VolumeShaper::State> AudioFlinger::PlaybackThread::Track::getVolumeShaperState(int id)
+{
+ // Note: We don't check if Thread exists.
+
+ // mVolumeHandler is thread safe.
+ return mVolumeHandler->getVolumeShaperState(id);
+}
+
status_t AudioFlinger::PlaybackThread::Track::getTimestamp(AudioTimestamp& timestamp)
{
if (!isOffloaded() && !isDirect()) {