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