Effect AIDL: implement IEffect.reopen

- add IEffect.reopen implementation
- now data MQs can update at runtime, sync
  EffectContext access
- add clang thread annotation

Bug: 302036943
Test: atest VtsHalAudioEffectTargetTest
Test: build and test audio effect on Pixel
Change-Id: I3e9fdc2d5eb50b8c1377e0da75573f0eba7ea3f1
Merged-In: I3e9fdc2d5eb50b8c1377e0da75573f0eba7ea3f1
diff --git a/audio/aidl/default/include/effect-impl/EffectContext.h b/audio/aidl/default/include/effect-impl/EffectContext.h
index 89d0c7c..24f3b5d 100644
--- a/audio/aidl/default/include/effect-impl/EffectContext.h
+++ b/audio/aidl/default/include/effect-impl/EffectContext.h
@@ -21,6 +21,7 @@
 #include <Utils.h>
 #include <android-base/logging.h>
 #include <fmq/AidlMessageQueue.h>
+#include <fmq/EventFlag.h>
 
 #include <aidl/android/hardware/audio/effect/BnEffect.h>
 #include "EffectTypes.h"
@@ -36,127 +37,73 @@
             float, ::aidl::android::hardware::common::fmq::SynchronizedReadWrite>
             DataMQ;
 
-    EffectContext(size_t statusDepth, const Parameter::Common& common) {
-        auto& input = common.input;
-        auto& output = common.output;
-
-        LOG_ALWAYS_FATAL_IF(
-                input.base.format.pcm != aidl::android::media::audio::common::PcmType::FLOAT_32_BIT,
-                "inputFormatNotFloat");
-        LOG_ALWAYS_FATAL_IF(output.base.format.pcm !=
-                                    aidl::android::media::audio::common::PcmType::FLOAT_32_BIT,
-                            "outputFormatNotFloat");
-
-        size_t inputChannelCount =
-                ::aidl::android::hardware::audio::common::getChannelCount(input.base.channelMask);
-        LOG_ALWAYS_FATAL_IF(inputChannelCount == 0, "inputChannelCountNotValid");
-        size_t outputChannelCount =
-                ::aidl::android::hardware::audio::common::getChannelCount(output.base.channelMask);
-        LOG_ALWAYS_FATAL_IF(outputChannelCount == 0, "outputChannelCountNotValid");
-
-        mInputFrameSize = ::aidl::android::hardware::audio::common::getFrameSizeInBytes(
-                input.base.format, input.base.channelMask);
-        mOutputFrameSize = ::aidl::android::hardware::audio::common::getFrameSizeInBytes(
-                output.base.format, output.base.channelMask);
-        // in/outBuffer size in float (FMQ data format defined for DataMQ)
-        size_t inBufferSizeInFloat = input.frameCount * mInputFrameSize / sizeof(float);
-        size_t outBufferSizeInFloat = output.frameCount * mOutputFrameSize / sizeof(float);
-
-        // only status FMQ use the EventFlag
-        mStatusMQ = std::make_shared<StatusMQ>(statusDepth, true /*configureEventFlagWord*/);
-        mInputMQ = std::make_shared<DataMQ>(inBufferSizeInFloat);
-        mOutputMQ = std::make_shared<DataMQ>(outBufferSizeInFloat);
-
-        if (!mStatusMQ->isValid() || !mInputMQ->isValid() || !mOutputMQ->isValid()) {
-            LOG(ERROR) << __func__ << " created invalid FMQ";
+    EffectContext(size_t statusDepth, const Parameter::Common& common);
+    virtual ~EffectContext() {
+        if (mEfGroup) {
+            ::android::hardware::EventFlag::deleteEventFlag(&mEfGroup);
         }
-        mWorkBuffer.reserve(std::max(inBufferSizeInFloat, outBufferSizeInFloat));
-        mCommon = common;
     }
-    virtual ~EffectContext() {}
 
-    std::shared_ptr<StatusMQ> getStatusFmq() { return mStatusMQ; }
-    std::shared_ptr<DataMQ> getInputDataFmq() { return mInputMQ; }
-    std::shared_ptr<DataMQ> getOutputDataFmq() { return mOutputMQ; }
+    std::shared_ptr<StatusMQ> getStatusFmq() const;
+    std::shared_ptr<DataMQ> getInputDataFmq() const;
+    std::shared_ptr<DataMQ> getOutputDataFmq() const;
 
-    float* getWorkBuffer() { return static_cast<float*>(mWorkBuffer.data()); }
+    float* getWorkBuffer();
 
     // reset buffer status by abandon input data in FMQ
-    void resetBuffer() {
-        auto buffer = static_cast<float*>(mWorkBuffer.data());
-        std::vector<IEffect::Status> status(mStatusMQ->availableToRead());
-        mInputMQ->read(buffer, mInputMQ->availableToRead());
-    }
+    void resetBuffer();
+    void dupeFmq(IEffect::OpenEffectReturn* effectRet);
+    size_t getInputFrameSize() const;
+    size_t getOutputFrameSize() const;
+    int getSessionId() const;
+    int getIoHandle() const;
 
-    void dupeFmq(IEffect::OpenEffectReturn* effectRet) {
-        if (effectRet) {
-            effectRet->statusMQ = mStatusMQ->dupeDesc();
-            effectRet->inputDataMQ = mInputMQ->dupeDesc();
-            effectRet->outputDataMQ = mOutputMQ->dupeDesc();
-        }
-    }
-    size_t getInputFrameSize() { return mInputFrameSize; }
-    size_t getOutputFrameSize() { return mOutputFrameSize; }
-    int getSessionId() { return mCommon.session; }
-    int getIoHandle() { return mCommon.ioHandle; }
+    virtual void dupeFmqWithReopen(IEffect::OpenEffectReturn* effectRet);
 
     virtual RetCode setOutputDevice(
-            const std::vector<aidl::android::media::audio::common::AudioDeviceDescription>&
-                    device) {
-        mOutputDevice = device;
-        return RetCode::SUCCESS;
-    }
+            const std::vector<aidl::android::media::audio::common::AudioDeviceDescription>& device);
 
     virtual std::vector<aidl::android::media::audio::common::AudioDeviceDescription>
-    getOutputDevice() {
-        return mOutputDevice;
-    }
+    getOutputDevice();
 
-    virtual RetCode setAudioMode(const aidl::android::media::audio::common::AudioMode& mode) {
-        mMode = mode;
-        return RetCode::SUCCESS;
-    }
-    virtual aidl::android::media::audio::common::AudioMode getAudioMode() { return mMode; }
+    virtual RetCode setAudioMode(const aidl::android::media::audio::common::AudioMode& mode);
+    virtual aidl::android::media::audio::common::AudioMode getAudioMode();
 
-    virtual RetCode setAudioSource(const aidl::android::media::audio::common::AudioSource& source) {
-        mSource = source;
-        return RetCode::SUCCESS;
-    }
-    virtual aidl::android::media::audio::common::AudioSource getAudioSource() { return mSource; }
+    virtual RetCode setAudioSource(const aidl::android::media::audio::common::AudioSource& source);
+    virtual aidl::android::media::audio::common::AudioSource getAudioSource();
 
-    virtual RetCode setVolumeStereo(const Parameter::VolumeStereo& volumeStereo) {
-        mVolumeStereo = volumeStereo;
-        return RetCode::SUCCESS;
-    }
-    virtual Parameter::VolumeStereo getVolumeStereo() { return mVolumeStereo; }
+    virtual RetCode setVolumeStereo(const Parameter::VolumeStereo& volumeStereo);
+    virtual Parameter::VolumeStereo getVolumeStereo();
 
-    virtual RetCode setCommon(const Parameter::Common& common) {
-        mCommon = common;
-        LOG(VERBOSE) << __func__ << mCommon.toString();
-        return RetCode::SUCCESS;
-    }
-    virtual Parameter::Common getCommon() {
-        LOG(VERBOSE) << __func__ << mCommon.toString();
-        return mCommon;
-    }
+    virtual RetCode setCommon(const Parameter::Common& common);
+    virtual Parameter::Common getCommon();
+
+    virtual ::android::hardware::EventFlag* getStatusEventFlag();
 
   protected:
-    // common parameters
     size_t mInputFrameSize;
     size_t mOutputFrameSize;
-    Parameter::Common mCommon;
-    std::vector<aidl::android::media::audio::common::AudioDeviceDescription> mOutputDevice;
-    aidl::android::media::audio::common::AudioMode mMode;
-    aidl::android::media::audio::common::AudioSource mSource;
-    Parameter::VolumeStereo mVolumeStereo;
+    size_t mInputChannelCount;
+    size_t mOutputChannelCount;
+    Parameter::Common mCommon = {};
+    std::vector<aidl::android::media::audio::common::AudioDeviceDescription> mOutputDevice = {};
+    aidl::android::media::audio::common::AudioMode mMode =
+            aidl::android::media::audio::common::AudioMode::SYS_RESERVED_INVALID;
+    aidl::android::media::audio::common::AudioSource mSource =
+            aidl::android::media::audio::common::AudioSource::SYS_RESERVED_INVALID;
+    Parameter::VolumeStereo mVolumeStereo = {};
+    RetCode updateIOFrameSize(const Parameter::Common& common);
+    RetCode notifyDataMqUpdate();
 
   private:
     // fmq and buffers
     std::shared_ptr<StatusMQ> mStatusMQ;
     std::shared_ptr<DataMQ> mInputMQ;
     std::shared_ptr<DataMQ> mOutputMQ;
-    // TODO handle effect process input and output
+    // std::shared_ptr<IEffect::OpenEffectReturn> mRet;
     // work buffer set by effect instances, the access and update are in same thread
     std::vector<float> mWorkBuffer;
+
+    ::android::hardware::EventFlag* mEfGroup;
 };
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/include/effect-impl/EffectImpl.h b/audio/aidl/default/include/effect-impl/EffectImpl.h
index 242a268..21f6502 100644
--- a/audio/aidl/default/include/effect-impl/EffectImpl.h
+++ b/audio/aidl/default/include/effect-impl/EffectImpl.h
@@ -49,33 +49,54 @@
     virtual ndk::ScopedAStatus setParameter(const Parameter& param) override;
     virtual ndk::ScopedAStatus getParameter(const Parameter::Id& id, Parameter* param) override;
 
-    virtual ndk::ScopedAStatus setParameterCommon(const Parameter& param);
-    virtual ndk::ScopedAStatus getParameterCommon(const Parameter::Tag& tag, Parameter* param);
+    virtual ndk::ScopedAStatus setParameterCommon(const Parameter& param) REQUIRES(mImplMutex);
+    virtual ndk::ScopedAStatus getParameterCommon(const Parameter::Tag& tag, Parameter* param)
+            REQUIRES(mImplMutex);
 
     /* Methods MUST be implemented by each effect instances */
     virtual ndk::ScopedAStatus getDescriptor(Descriptor* desc) = 0;
-    virtual ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) = 0;
+    virtual ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific)
+            REQUIRES(mImplMutex) = 0;
     virtual ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
-                                                    Parameter::Specific* specific) = 0;
+                                                    Parameter::Specific* specific)
+            REQUIRES(mImplMutex) = 0;
 
     virtual std::string getEffectName() = 0;
-    virtual IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
+    virtual std::shared_ptr<EffectContext> createContext(const Parameter::Common& common)
+            REQUIRES(mImplMutex);
+    virtual RetCode releaseContext() REQUIRES(mImplMutex) = 0;
 
     /**
-     * Effect context methods must be implemented by each effect.
-     * Each effect can derive from EffectContext and define its own context, but must upcast to
-     * EffectContext for EffectImpl to use.
+     * @brief effectProcessImpl is running in worker thread which created in EffectThread.
+     *
+     * EffectThread will make sure effectProcessImpl only be called after startThread() successful
+     * and before stopThread() successful.
+     *
+     * effectProcessImpl implementation must not call any EffectThread interface, otherwise it will
+     * cause deadlock.
+     *
+     * @param in address of input float buffer.
+     * @param out address of output float buffer.
+     * @param samples number of samples to process.
+     * @return IEffect::Status
      */
-    virtual std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) = 0;
-    virtual std::shared_ptr<EffectContext> getContext() = 0;
-    virtual RetCode releaseContext() = 0;
+    virtual IEffect::Status effectProcessImpl(float* in, float* out, int samples) = 0;
+
+    /**
+     * process() get data from data MQs, and call effectProcessImpl() for effect data processing.
+     * Its important for the implementation to use mImplMutex for context synchronization.
+     */
+    void process() override;
 
   protected:
-    State mState = State::INIT;
+    State mState GUARDED_BY(mImplMutex) = State::INIT;
 
     IEffect::Status status(binder_status_t status, size_t consumed, size_t produced);
     void cleanUp();
 
+    std::mutex mImplMutex;
+    std::shared_ptr<EffectContext> mImplContext GUARDED_BY(mImplMutex);
+
     /**
      * Optional CommandId handling methods for effects to override.
      * For CommandId::START, EffectImpl call commandImpl before starting the EffectThread
@@ -83,6 +104,9 @@
      * For CommandId::STOP and CommandId::RESET, EffectImpl call commandImpl after stop the
      * EffectThread processing.
      */
-    virtual ndk::ScopedAStatus commandImpl(CommandId id);
+    virtual ndk::ScopedAStatus commandImpl(CommandId id) REQUIRES(mImplMutex);
+
+    RetCode notifyEventFlag(uint32_t flag);
+    ::android::hardware::EventFlag* mEventFlag;
 };
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/include/effect-impl/EffectThread.h b/audio/aidl/default/include/effect-impl/EffectThread.h
index ae51ef7..3dbb0e6 100644
--- a/audio/aidl/default/include/effect-impl/EffectThread.h
+++ b/audio/aidl/default/include/effect-impl/EffectThread.h
@@ -36,8 +36,7 @@
     virtual ~EffectThread();
 
     // called by effect implementation.
-    RetCode createThread(std::shared_ptr<EffectContext> context, const std::string& name,
-                         int priority = ANDROID_PRIORITY_URGENT_AUDIO);
+    RetCode createThread(const std::string& name, int priority = ANDROID_PRIORITY_URGENT_AUDIO);
     RetCode destroyThread();
     RetCode startThread();
     RetCode stopThread();
@@ -46,32 +45,11 @@
     void threadLoop();
 
     /**
-     * @brief effectProcessImpl is running in worker thread which created in EffectThread.
-     *
-     * Effect implementation should think about concurrency in the implementation if necessary.
-     * Parameter setting usually implemented in context (derived from EffectContext), and some
-     * parameter maybe used in the processing, then effect implementation should consider using a
-     * mutex to protect these parameter.
-     *
-     * EffectThread will make sure effectProcessImpl only be called after startThread() successful
-     * and before stopThread() successful.
-     *
-     * effectProcessImpl implementation must not call any EffectThread interface, otherwise it will
-     * cause deadlock.
-     *
-     * @param in address of input float buffer.
-     * @param out address of output float buffer.
-     * @param samples number of samples to process.
-     * @return IEffect::Status
-     */
-    virtual IEffect::Status effectProcessImpl(float* in, float* out, int samples) = 0;
-
-    /**
      * process() call effectProcessImpl() for effect data processing, it is necessary for the
      * processing to be called under Effect thread mutex mThreadMutex, to avoid the effect state
      * change before/during data processing, and keep the thread and effect state consistent.
      */
-    virtual void process_l() REQUIRES(mThreadMutex);
+    virtual void process() = 0;
 
   private:
     static constexpr int kMaxTaskNameLen = 15;
@@ -80,16 +58,7 @@
     std::condition_variable mCv;
     bool mStop GUARDED_BY(mThreadMutex) = true;
     bool mExit GUARDED_BY(mThreadMutex) = false;
-    std::shared_ptr<EffectContext> mThreadContext GUARDED_BY(mThreadMutex);
 
-    struct EventFlagDeleter {
-        void operator()(::android::hardware::EventFlag* flag) const {
-            if (flag) {
-                ::android::hardware::EventFlag::deleteEventFlag(&flag);
-            }
-        }
-    };
-    std::unique_ptr<::android::hardware::EventFlag, EventFlagDeleter> mEfGroup;
     std::thread mThread;
     int mPriority;
     std::string mName;
diff --git a/audio/aidl/default/include/effect-impl/EffectTypes.h b/audio/aidl/default/include/effect-impl/EffectTypes.h
index 4bda7be..9740d6e 100644
--- a/audio/aidl/default/include/effect-impl/EffectTypes.h
+++ b/audio/aidl/default/include/effect-impl/EffectTypes.h
@@ -46,7 +46,8 @@
     ERROR_NULL_POINTER,      /* NULL pointer */
     ERROR_ALIGNMENT_ERROR,   /* Memory alignment error */
     ERROR_BLOCK_SIZE_EXCEED, /* Maximum block size exceeded */
-    ERROR_EFFECT_LIB_ERROR
+    ERROR_EFFECT_LIB_ERROR,  /* Effect implementation library error */
+    ERROR_EVENT_FLAG_ERROR   /* Error with effect event flags */
 };
 
 static const int INVALID_AUDIO_SESSION_ID = -1;
@@ -67,6 +68,8 @@
             return out << "ERROR_BLOCK_SIZE_EXCEED";
         case RetCode::ERROR_EFFECT_LIB_ERROR:
             return out << "ERROR_EFFECT_LIB_ERROR";
+        case RetCode::ERROR_EVENT_FLAG_ERROR:
+            return out << "ERROR_EVENT_FLAG_ERROR";
     }
 
     return out << "EnumError: " << code;