Refactor the PatchCommandThread for reuse.

Extract the CommandThread into PatchCommandThread and make it reusable
for other components interested in PatchPanel changes.

Test: manual
Bug: 252776298
Change-Id: I16db5341543328b4a84be238aa7c1b5804dfe7c9
diff --git a/services/audioflinger/PatchCommandThread.h b/services/audioflinger/PatchCommandThread.h
new file mode 100644
index 0000000..b7853f0
--- /dev/null
+++ b/services/audioflinger/PatchCommandThread.h
@@ -0,0 +1,102 @@
+/*
+**
+** Copyright 2022, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#ifndef INCLUDING_FROM_AUDIOFLINGER_H
+    #error This header file should only be included from AudioFlinger.h
+#endif
+
+class Command;
+
+// Thread to execute create and release patch commands asynchronously. This is needed because
+// PatchPanel::createAudioPatch and releaseAudioPatch are executed from audio policy service
+// with mutex locked and effect management requires to call back into audio policy service
+class PatchCommandThread : public Thread {
+public:
+
+    enum {
+        CREATE_AUDIO_PATCH,
+        RELEASE_AUDIO_PATCH,
+    };
+
+    class PatchCommandListener : public virtual RefBase {
+    public:
+        virtual void onCreateAudioPatch(audio_patch_handle_t handle,
+                                        const PatchPanel::Patch& patch) = 0;
+        virtual void onReleaseAudioPatch(audio_patch_handle_t handle) = 0;
+    };
+
+    PatchCommandThread() : Thread(false /* canCallJava */) {}
+    ~PatchCommandThread() override;
+
+    void addListener(const sp<PatchCommandListener>& listener);
+
+    void createAudioPatch(audio_patch_handle_t handle, const PatchPanel::Patch& patch);
+    void releaseAudioPatch(audio_patch_handle_t handle);
+
+    // Thread virtuals
+    void onFirstRef() override;
+    bool threadLoop() override;
+
+    void exit();
+
+    void createAudioPatchCommand(audio_patch_handle_t handle,
+            const PatchPanel::Patch& patch);
+    void releaseAudioPatchCommand(audio_patch_handle_t handle);
+
+private:
+    class CommandData;
+
+    // Command type received from the PatchPanel
+    class Command: public RefBase {
+    public:
+        Command() = default;
+        Command(int command, const sp<CommandData>& data)
+            : mCommand(command), mData(data) {}
+
+        const int mCommand = -1;
+        const sp<CommandData> mData;
+    };
+
+    class CommandData: public RefBase {};
+
+    class CreateAudioPatchData : public CommandData {
+    public:
+        CreateAudioPatchData(audio_patch_handle_t handle, const PatchPanel::Patch& patch)
+            :   mHandle(handle), mPatch(patch) {}
+
+        const audio_patch_handle_t mHandle;
+        const PatchPanel::Patch mPatch;
+    };
+
+    class ReleaseAudioPatchData : public CommandData {
+    public:
+        ReleaseAudioPatchData(audio_patch_handle_t handle)
+            :   mHandle(handle) {}
+
+        audio_patch_handle_t mHandle;
+    };
+
+    void sendCommand(const sp<Command>& command);
+
+    std::string mThreadName;
+    std::mutex mLock;
+    std::condition_variable mWaitWorkCV;
+    std::deque<sp<Command>> mCommands GUARDED_BY(mLock); // list of pending commands
+
+    std::mutex mListenerLock;
+    std::vector<wp<PatchCommandListener>> mListeners GUARDED_BY(mListenerLock);
+};