Refactor AudioEffect callback to interface
Refactor AudioEffect callback from static function pointer
with pointer args to callback interface.
- Removes need for event enum, user cookie, and opaque arg
ptr.
- Replace effect_callback_t with IAudioEffectCallback listener
interface for separate notifications for each event type.
- Duplicate set/constructor methods to provide for incremental
refactor.
- LegacyCallbackWrapper to wrap legacy_callback_t consuming methods
- Retain wp<IAudioTrackCallback> to refcount and avoid ownership
cycles.
Related-to: Id75c8866bdfa528d37cf1f93e41e917568c4a147
Bug: 199156212
Test: Compiles. To be verified.
Change-Id: I6e49abd463196c1e89f3ca0578e9cd84c5a7f89e
diff --git a/media/libaudioclient/AudioEffect.cpp b/media/libaudioclient/AudioEffect.cpp
index 62f863d..16ae246 100644
--- a/media/libaudioclient/AudioEffect.cpp
+++ b/media/libaudioclient/AudioEffect.cpp
@@ -61,8 +61,7 @@
status_t AudioEffect::set(const effect_uuid_t *type,
const effect_uuid_t *uuid,
int32_t priority,
- effect_callback_t cbf,
- void* user,
+ const wp<IAudioEffectCallback>& callback,
audio_session_t sessionId,
audio_io_handle_t io,
const AudioDeviceTypeAddr& device,
@@ -73,7 +72,7 @@
sp<IMemory> cblk;
int enabled;
- ALOGV("set %p mUserData: %p uuid: %p timeLow %08x", this, user, type, type ? type->timeLow : 0);
+ ALOGV("set %p uuid: %p timeLow %08x", this, type, type ? type->timeLow : 0);
if (mIEffect != 0) {
ALOGW("Effect already in use");
@@ -96,9 +95,8 @@
}
mProbe = probe;
mPriority = priority;
- mCbf = cbf;
- mUserData = user;
mSessionId = sessionId;
+ mCallback = callback;
memset(&mDescriptor, 0, sizeof(effect_descriptor_t));
mDescriptor.type = *(type != NULL ? type : EFFECT_UUID_NULL);
@@ -184,11 +182,60 @@
return mStatus;
}
+namespace {
+class LegacyCallbackWrapper : public AudioEffect::IAudioEffectCallback {
+ public:
+ LegacyCallbackWrapper(AudioEffect::legacy_callback_t callback, void* user):
+ mCallback(callback), mUser(user) {}
+ private:
+ void onControlStatusChanged(bool isGranted) override {
+ mCallback(AudioEffect::EVENT_CONTROL_STATUS_CHANGED, mUser, &isGranted);
+ }
+
+ void onEnableStatusChanged(bool isEnabled) override {
+ mCallback(AudioEffect::EVENT_ENABLE_STATUS_CHANGED, mUser, &isEnabled);
+ }
+
+ void onParameterChanged(std::vector<uint8_t> param) override {
+ mCallback(AudioEffect::EVENT_PARAMETER_CHANGED, mUser, param.data());
+ }
+
+ void onError(status_t errorCode) override {
+ mCallback(AudioEffect::EVENT_ERROR, mUser, &errorCode);
+ }
+
+ void onFramesProcessed(int32_t framesProcessed) override {
+ mCallback(AudioEffect::EVENT_FRAMES_PROCESSED, mUser, &framesProcessed);
+ }
+
+ const AudioEffect::legacy_callback_t mCallback;
+ void* const mUser;
+};
+} // namespace
+
+status_t AudioEffect::set(const effect_uuid_t *type,
+ const effect_uuid_t *uuid,
+ int32_t priority,
+ legacy_callback_t cbf,
+ void* user,
+ audio_session_t sessionId,
+ audio_io_handle_t io,
+ const AudioDeviceTypeAddr& device,
+ bool probe,
+ bool notifyFramesProcessed)
+{
+ if (cbf != nullptr) {
+ mLegacyWrapper = sp<LegacyCallbackWrapper>::make(cbf, user);
+ } else if (user != nullptr) {
+ LOG_ALWAYS_FATAL("%s: User provided without callback", __func__);
+ }
+ return set(type, uuid, priority, mLegacyWrapper, sessionId, io, device, probe,
+ notifyFramesProcessed);
+}
status_t AudioEffect::set(const char *typeStr,
const char *uuidStr,
int32_t priority,
- effect_callback_t cbf,
- void* user,
+ const wp<IAudioEffectCallback>& callback,
audio_session_t sessionId,
audio_io_handle_t io,
const AudioDeviceTypeAddr& device,
@@ -210,11 +257,29 @@
pUuid = &uuid;
}
- return set(pType, pUuid, priority, cbf, user, sessionId, io,
+ return set(pType, pUuid, priority, callback, sessionId, io,
device, probe, notifyFramesProcessed);
}
-
+status_t AudioEffect::set(const char *typeStr,
+ const char *uuidStr,
+ int32_t priority,
+ legacy_callback_t cbf,
+ void* user,
+ audio_session_t sessionId,
+ audio_io_handle_t io,
+ const AudioDeviceTypeAddr& device,
+ bool probe,
+ bool notifyFramesProcessed)
+{
+ if (cbf != nullptr) {
+ mLegacyWrapper = sp<LegacyCallbackWrapper>::make(cbf, user);
+ } else if (user != nullptr) {
+ LOG_ALWAYS_FATAL("%s: User provided without callback", __func__);
+ }
+ return set(typeStr, uuidStr, priority, mLegacyWrapper, sessionId, io, device, probe,
+ notifyFramesProcessed);
+}
AudioEffect::~AudioEffect()
{
ALOGV("Destructor %p", this);
@@ -468,9 +533,9 @@
{
ALOGW("IEffect died");
mStatus = DEAD_OBJECT;
- if (mCbf != NULL) {
- status_t status = DEAD_OBJECT;
- mCbf(EVENT_ERROR, mUserData, &status);
+ auto cb = mCallback.promote();
+ if (cb != nullptr) {
+ cb->onError(mStatus);
}
mIEffect.clear();
}
@@ -479,8 +544,8 @@
void AudioEffect::controlStatusChanged(bool controlGranted)
{
- ALOGV("controlStatusChanged %p control %d callback %p mUserData %p", this, controlGranted, mCbf,
- mUserData);
+ auto cb = mCallback.promote();
+ ALOGV("controlStatusChanged %p control %d callback %p", this, controlGranted, cb.get());
if (controlGranted) {
if (mStatus == ALREADY_EXISTS) {
mStatus = NO_ERROR;
@@ -490,18 +555,19 @@
mStatus = ALREADY_EXISTS;
}
}
- if (mCbf != NULL) {
- mCbf(EVENT_CONTROL_STATUS_CHANGED, mUserData, &controlGranted);
+ if (cb != nullptr) {
+ cb->onControlStatusChanged(controlGranted);
}
}
void AudioEffect::enableStatusChanged(bool enabled)
{
- ALOGV("enableStatusChanged %p enabled %d mCbf %p", this, enabled, mCbf);
+ auto cb = mCallback.promote();
+ ALOGV("enableStatusChanged %p enabled %d mCallback %p", this, enabled, cb.get());
if (mStatus == ALREADY_EXISTS) {
mEnabled = enabled;
- if (mCbf != NULL) {
- mCbf(EVENT_ENABLE_STATUS_CHANGED, mUserData, &enabled);
+ if (cb != nullptr) {
+ cb->onEnableStatusChanged(enabled);
}
}
}
@@ -513,19 +579,20 @@
if (cmdData.empty() || replyData.empty()) {
return;
}
-
- if (mCbf != NULL && cmdCode == EFFECT_CMD_SET_PARAM) {
+ auto cb = mCallback.promote();
+ if (cb != nullptr && cmdCode == EFFECT_CMD_SET_PARAM) {
std::vector<uint8_t> cmdDataCopy(cmdData);
effect_param_t* cmd = reinterpret_cast<effect_param_t *>(cmdDataCopy.data());
cmd->status = *reinterpret_cast<const int32_t *>(replyData.data());
- mCbf(EVENT_PARAMETER_CHANGED, mUserData, cmd);
+ cb->onParameterChanged(std::move(cmdDataCopy));
}
}
void AudioEffect::framesProcessed(int32_t frames)
{
- if (mCbf != NULL) {
- mCbf(EVENT_FRAMES_PROCESSED, mUserData, &frames);
+ auto cb = mCallback.promote();
+ if (cb != nullptr) {
+ cb->onFramesProcessed(frames);
}
}
diff --git a/media/libaudioclient/include/media/AudioEffect.h b/media/libaudioclient/include/media/AudioEffect.h
index ee262f3..56884a3 100644
--- a/media/libaudioclient/include/media/AudioEffect.h
+++ b/media/libaudioclient/include/media/AudioEffect.h
@@ -277,7 +277,7 @@
static status_t removeStreamDefaultEffect(audio_unique_id_t id);
/*
- * Events used by callback function (effect_callback_t).
+ * Events used by callback function (legacy_callback_t).
*/
enum event_type {
EVENT_CONTROL_STATUS_CHANGED = 0,
@@ -287,6 +287,47 @@
EVENT_FRAMES_PROCESSED = 4,
};
+ class IAudioEffectCallback : public virtual RefBase {
+ friend AudioEffect;
+ protected:
+ /* The event is received when an application loses or
+ * gains the control of the effect engine. Loss of control happens
+ * if another application requests the use of the engine by creating an AudioEffect for
+ * the same effect type but with a higher priority. Control is returned when the
+ * application having the control deletes its AudioEffect object.
+ * @param isGranted: True if control has been granted. False if stolen.
+ */
+ virtual void onControlStatusChanged([[maybe_unused]] bool isGranted) {}
+
+ /* The event is received by all applications not having the
+ * control of the effect engine when the effect is enabled or disabled.
+ * @param isEnabled: True if enabled. False if disabled.
+ */
+ virtual void onEnableStatusChanged([[maybe_unused]] bool isEnabled) {}
+
+ /* The event is received by all applications not having the
+ * control of the effect engine when an effect parameter is changed.
+ * @param param: A vector containing the raw bytes of a effect_param_type containing
+ * raw data representing a param type, value pair.
+ */
+ // TODO pass an AIDL parcel instead of effect_param_type
+ virtual void onParameterChanged([[maybe_unused]] std::vector<uint8_t> param) {}
+
+ /* The event is received when the binder connection to the mediaserver
+ * is no longer valid. Typically the server has been killed.
+ * @param errorCode: A code representing the type of error.
+ */
+ virtual void onError([[maybe_unused]] status_t errorCode) {}
+
+
+ /* The event is received when the audio server has processed a block of
+ * data.
+ * @param framesProcessed: The number of frames the audio server has
+ * processed.
+ */
+ virtual void onFramesProcessed([[maybe_unused]] int32_t framesProcessed) {}
+ };
+
/* Callback function notifying client application of a change in effect engine state or
* configuration.
* An effect engine can be shared by several applications but only one has the control
@@ -315,7 +356,7 @@
* - EVENT_ERROR: status_t indicating the error (DEAD_OBJECT when media server dies).
*/
- typedef void (*effect_callback_t)(int32_t event, void* user, void *info);
+ typedef void (*legacy_callback_t)(int32_t event, void* user, void *info);
/* Constructor.
@@ -360,7 +401,7 @@
* priority: requested priority for effect control: the priority level corresponds to the
* value of priority parameter: negative values indicate lower priorities, positive values
* higher priorities, 0 being the normal priority.
- * cbf: optional callback function (see effect_callback_t)
+ * cbf: optional callback function (see legacy_callback_t)
* user: pointer to context for use by the callback receiver.
* sessionId: audio session this effect is associated to.
* If equal to AUDIO_SESSION_OUTPUT_MIX, the effect will be global to
@@ -383,10 +424,20 @@
* - NO_INIT: audio flinger or audio hardware not initialized
*/
status_t set(const effect_uuid_t *type,
- const effect_uuid_t *uuid = NULL,
+ const effect_uuid_t *uuid = nullptr,
int32_t priority = 0,
- effect_callback_t cbf = NULL,
- void* user = NULL,
+ const wp<IAudioEffectCallback>& callback = nullptr,
+ audio_session_t sessionId = AUDIO_SESSION_OUTPUT_MIX,
+ audio_io_handle_t io = AUDIO_IO_HANDLE_NONE,
+ const AudioDeviceTypeAddr& device = {},
+ bool probe = false,
+ bool notifyFramesProcessed = false);
+
+ status_t set(const effect_uuid_t *type,
+ const effect_uuid_t *uuid,
+ int32_t priority,
+ legacy_callback_t cbf,
+ void* user,
audio_session_t sessionId = AUDIO_SESSION_OUTPUT_MIX,
audio_io_handle_t io = AUDIO_IO_HANDLE_NONE,
const AudioDeviceTypeAddr& device = {},
@@ -396,10 +447,21 @@
* Same as above but with type and uuid specified by character strings.
*/
status_t set(const char *typeStr,
- const char *uuidStr = NULL,
+ const char *uuidStr = nullptr,
int32_t priority = 0,
- effect_callback_t cbf = NULL,
- void* user = NULL,
+ const wp<IAudioEffectCallback>& callback = nullptr,
+ audio_session_t sessionId = AUDIO_SESSION_OUTPUT_MIX,
+ audio_io_handle_t io = AUDIO_IO_HANDLE_NONE,
+ const AudioDeviceTypeAddr& device = {},
+ bool probe = false,
+ bool notifyFramesProcessed = false);
+
+
+ status_t set(const char *typeStr,
+ const char *uuidStr,
+ int32_t priority,
+ legacy_callback_t cbf,
+ void* user,
audio_session_t sessionId = AUDIO_SESSION_OUTPUT_MIX,
audio_io_handle_t io = AUDIO_IO_HANDLE_NONE,
const AudioDeviceTypeAddr& device = {},
@@ -535,18 +597,19 @@
protected:
android::content::AttributionSourceState mClientAttributionSource; // source for app op checks.
- bool mEnabled = false; // enable state
- audio_session_t mSessionId = AUDIO_SESSION_OUTPUT_MIX; // audio session ID
- int32_t mPriority = 0; // priority for effect control
- status_t mStatus = NO_INIT; // effect status
- bool mProbe = false; // effect created in probe mode: all commands
- // are no ops because mIEffect is NULL
- effect_callback_t mCbf = nullptr; // callback function for status, control and
- // parameter changes notifications
- void* mUserData = nullptr;// client context for callback function
- effect_descriptor_t mDescriptor = {}; // effect descriptor
- int32_t mId = -1; // system wide unique effect engine instance ID
- Mutex mLock; // Mutex for mEnabled access
+ bool mEnabled = false; // enable state
+ audio_session_t mSessionId = AUDIO_SESSION_OUTPUT_MIX; // audio session ID
+ int32_t mPriority = 0; // priority for effect control
+ status_t mStatus = NO_INIT; // effect status
+ bool mProbe = false; // effect created in probe mode: all commands
+ // are no ops because mIEffect is nullptr
+
+ wp<IAudioEffectCallback> mCallback = nullptr; // callback interface for status, control and
+ // parameter changes notifications
+ sp<IAudioEffectCallback> mLegacyWrapper = nullptr;
+ effect_descriptor_t mDescriptor = {}; // effect descriptor
+ int32_t mId = -1; // system wide unique effect engine instance ID
+ Mutex mLock; // Mutex for mEnabled access
// IEffectClient