| /* |
| ** |
| ** 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. |
| */ |
| |
| #pragma once |
| |
| #include "IAfPatchPanel.h" |
| |
| #include <utils/RefBase.h> // avoid transitive dependency |
| #include <utils/Thread.h> // avoid transitive dependency |
| |
| #include <deque> |
| #include <mutex> // avoid transitive dependency |
| |
| namespace android { |
| |
| class Command; |
| |
| // Thread to execute create and release patch commands asynchronously. This is needed because |
| // IAfPatchPanel::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, |
| UPDATE_AUDIO_PATCH, |
| }; |
| |
| class PatchCommandListener : public virtual RefBase { |
| public: |
| virtual void onCreateAudioPatch(audio_patch_handle_t handle, |
| const IAfPatchPanel::Patch& patch) = 0; |
| virtual void onReleaseAudioPatch(audio_patch_handle_t handle) = 0; |
| virtual void onUpdateAudioPatch(audio_patch_handle_t oldHandle, |
| audio_patch_handle_t newHandle, |
| const IAfPatchPanel::Patch& patch) = 0; |
| }; |
| |
| PatchCommandThread() : Thread(false /* canCallJava */) {} |
| ~PatchCommandThread() override; |
| |
| void addListener(const sp<PatchCommandListener>& listener) |
| EXCLUDES_PatchCommandThread_ListenerMutex; |
| |
| void createAudioPatch(audio_patch_handle_t handle, const IAfPatchPanel::Patch& patch) |
| EXCLUDES_PatchCommandThread_Mutex; |
| void releaseAudioPatch(audio_patch_handle_t handle) EXCLUDES_PatchCommandThread_Mutex; |
| void updateAudioPatch(audio_patch_handle_t oldHandle, audio_patch_handle_t newHandle, |
| const IAfPatchPanel::Patch& patch) EXCLUDES_PatchCommandThread_Mutex; |
| |
| // Thread virtuals |
| void onFirstRef() override; |
| bool threadLoop() override; |
| |
| void exit(); |
| |
| void createAudioPatchCommand(audio_patch_handle_t handle, |
| const IAfPatchPanel::Patch& patch) EXCLUDES_PatchCommandThread_Mutex; |
| void releaseAudioPatchCommand(audio_patch_handle_t handle) EXCLUDES_PatchCommandThread_Mutex; |
| void updateAudioPatchCommand(audio_patch_handle_t oldHandle, audio_patch_handle_t newHandle, |
| const IAfPatchPanel::Patch& patch) EXCLUDES_PatchCommandThread_Mutex; |
| |
| 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 IAfPatchPanel::Patch& patch) |
| : mHandle(handle), mPatch(patch) {} |
| |
| const audio_patch_handle_t mHandle; |
| const IAfPatchPanel::Patch mPatch; |
| }; |
| |
| class ReleaseAudioPatchData : public CommandData { |
| public: |
| explicit ReleaseAudioPatchData(audio_patch_handle_t handle) |
| : mHandle(handle) {} |
| |
| audio_patch_handle_t mHandle; |
| }; |
| |
| class UpdateAudioPatchData : public CommandData { |
| public: |
| UpdateAudioPatchData(audio_patch_handle_t oldHandle, |
| audio_patch_handle_t newHandle, |
| const IAfPatchPanel::Patch& patch) |
| : mOldHandle(oldHandle), mNewHandle(newHandle), mPatch(patch) {} |
| |
| const audio_patch_handle_t mOldHandle; |
| const audio_patch_handle_t mNewHandle; |
| const IAfPatchPanel::Patch mPatch; |
| }; |
| |
| void sendCommand(const sp<Command>& command) EXCLUDES_PatchCommandThread_Mutex; |
| |
| audio_utils::mutex& mutex() const RETURN_CAPABILITY(audio_utils::PatchCommandThread_Mutex) { |
| return mMutex; |
| } |
| audio_utils::mutex& listenerMutex() const |
| RETURN_CAPABILITY(audio_utils::PatchCommandThread_ListenerMutex) { |
| return mListenerMutex; |
| } |
| |
| mutable audio_utils::mutex mMutex{audio_utils::MutexOrder::kPatchCommandThread_Mutex}; |
| audio_utils::condition_variable mWaitWorkCV; |
| std::deque<sp<Command>> mCommands GUARDED_BY(mutex()); // list of pending commands |
| |
| mutable audio_utils::mutex mListenerMutex{ |
| audio_utils::MutexOrder::kPatchCommandThread_ListenerMutex}; |
| std::vector<wp<PatchCommandListener>> mListeners GUARDED_BY(listenerMutex()); |
| }; |
| |
| } // namespace android |