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/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index 0de3559..d35cfe3 100644
--- a/media/libaudioclient/AudioTrack.cpp
+++ b/media/libaudioclient/AudioTrack.cpp
@@ -184,6 +184,7 @@
mPreviousSchedulingGroup(SP_DEFAULT),
mPausedPosition(0),
mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE),
+ mVolumeShaperId(VolumeShaper::kSystemIdMax),
mPortId(AUDIO_PORT_HANDLE_NONE)
{
mAttributes.content_type = AUDIO_CONTENT_TYPE_UNKNOWN;
@@ -556,7 +557,7 @@
mFramesWritten = 0;
mFramesWrittenServerOffset = 0;
mFramesWrittenAtRestore = -1; // -1 is a unique initializer.
-
+ mVolumeHandler = new VolumeHandler(mSampleRate);
return NO_ERROR;
}
@@ -2310,6 +2311,40 @@
return mAudioTrack->setParameters(keyValuePairs);
}
+VolumeShaper::Status AudioTrack::applyVolumeShaper(
+ const sp<VolumeShaper::Configuration>& configuration,
+ const sp<VolumeShaper::Operation>& operation)
+{
+ AutoMutex lock(mLock);
+ if (configuration->getType() == VolumeShaper::Configuration::TYPE_SCALE) {
+ const int id = configuration->getId();
+ LOG_ALWAYS_FATAL_IF(id >= VolumeShaper::kSystemIdMax || id < -1,
+ "id must be -1 or a system id (less than kSystemIdMax)");
+ if (id == -1) {
+ // if not a system id, reassign to a unique id
+ configuration->setId(mVolumeShaperId);
+ ALOGD("setting id to %d", mVolumeShaperId);
+ // increment and avoid signed overflow.
+ if (mVolumeShaperId == INT32_MAX) {
+ mVolumeShaperId = VolumeShaper::kSystemIdMax;
+ } else {
+ ++mVolumeShaperId;
+ }
+ }
+ }
+ VolumeShaper::Status status = mAudioTrack->applyVolumeShaper(configuration, operation);
+ // TODO: For restoration purposes, record successful creation and termination.
+ return status;
+}
+
+sp<VolumeShaper::State> AudioTrack::getVolumeShaperState(int id)
+{
+ // TODO: To properly restore the AudioTrack
+ // we will need to save the last state in AudioTrackShared.
+ AutoMutex lock(mLock);
+ return mAudioTrack->getVolumeShaperState(id);
+}
+
status_t AudioTrack::getTimestamp(ExtendedTimestamp *timestamp)
{
if (timestamp == nullptr) {
diff --git a/media/libaudioclient/IAudioTrack.cpp b/media/libaudioclient/IAudioTrack.cpp
index 89e0fcc..79e864d 100644
--- a/media/libaudioclient/IAudioTrack.cpp
+++ b/media/libaudioclient/IAudioTrack.cpp
@@ -39,6 +39,8 @@
SET_PARAMETERS,
GET_TIMESTAMP,
SIGNAL,
+ APPLY_VOLUME_SHAPER,
+ GET_VOLUME_SHAPER_STATE,
};
class BpAudioTrack : public BpInterface<IAudioTrack>
@@ -143,6 +145,52 @@
data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor());
remote()->transact(SIGNAL, data, &reply);
}
+
+ virtual VolumeShaper::Status applyVolumeShaper(
+ const sp<VolumeShaper::Configuration>& configuration,
+ const sp<VolumeShaper::Operation>& operation) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor());
+
+ status_t status = configuration.get() == nullptr
+ ? data.writeInt32(0)
+ : data.writeInt32(1)
+ ?: configuration->writeToParcel(&data);
+ if (status != NO_ERROR) {
+ return VolumeShaper::Status(status);
+ }
+
+ status = operation.get() == nullptr
+ ? status = data.writeInt32(0)
+ : data.writeInt32(1)
+ ?: operation->writeToParcel(&data);
+ if (status != NO_ERROR) {
+ return VolumeShaper::Status(status);
+ }
+
+ int32_t remoteVolumeShaperStatus;
+ status = remote()->transact(APPLY_VOLUME_SHAPER, data, &reply)
+ ?: reply.readInt32(&remoteVolumeShaperStatus);
+
+ return VolumeShaper::Status(status ?: remoteVolumeShaperStatus);
+ }
+
+ virtual sp<VolumeShaper::State> getVolumeShaperState(int id) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor());
+
+ data.writeInt32(id);
+ status_t status = remote()->transact(GET_VOLUME_SHAPER_STATE, data, &reply);
+ if (status != NO_ERROR) {
+ return nullptr;
+ }
+ sp<VolumeShaper::State> state = new VolumeShaper::State;
+ status = state->readFromParcel(reply);
+ if (status != NO_ERROR) {
+ return nullptr;
+ }
+ return state;
+ }
};
IMPLEMENT_META_INTERFACE(AudioTrack, "android.media.IAudioTrack");
@@ -206,6 +254,40 @@
signal();
return NO_ERROR;
} break;
+ case APPLY_VOLUME_SHAPER: {
+ CHECK_INTERFACE(IAudioTrack, data, reply);
+ sp<VolumeShaper::Configuration> configuration;
+ sp<VolumeShaper::Operation> operation;
+
+ int32_t present;
+ status_t status = data.readInt32(&present);
+ if (status == NO_ERROR && present != 0) {
+ configuration = new VolumeShaper::Configuration();
+ status = configuration->readFromParcel(data);
+ }
+ status = status ?: data.readInt32(&present);
+ if (status == NO_ERROR && present != 0) {
+ operation = new VolumeShaper::Operation();
+ status = operation->readFromParcel(data);
+ }
+ if (status == NO_ERROR) {
+ status = (status_t)applyVolumeShaper(configuration, operation);
+ }
+ reply->writeInt32(status);
+ return NO_ERROR;
+ } break;
+ case GET_VOLUME_SHAPER_STATE: {
+ CHECK_INTERFACE(IAudioTrack, data, reply);
+ int id;
+ status_t status = data.readInt32(&id);
+ if (status == NO_ERROR) {
+ sp<VolumeShaper::State> state = getVolumeShaperState(id);
+ if (state.get() != nullptr) {
+ status = state->writeToParcel(reply);
+ }
+ }
+ return NO_ERROR;
+ } break;
default:
return BBinder::onTransact(code, data, reply, flags);
}