1 /*
2 **
3 ** Copyright 2022, The Android Open Source Project
4 **
5 ** Licensed under the Apache License, Version 2.0 (the "License");
6 ** you may not use this file except in compliance with the License.
7 ** You may obtain a copy of the License at
8 **
9 **     http://www.apache.org/licenses/LICENSE-2.0
10 **
11 ** Unless required by applicable law or agreed to in writing, software
12 ** distributed under the License is distributed on an "AS IS" BASIS,
13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 ** See the License for the specific language governing permissions and
15 ** limitations under the License.
16 */
17 
18 #pragma once
19 
20 #include "IAfPatchPanel.h"
21 
22 #include <utils/RefBase.h>  // avoid transitive dependency
23 #include <utils/Thread.h>  // avoid transitive dependency
24 
25 #include <deque>
26 #include <mutex>  // avoid transitive dependency
27 
28 namespace android {
29 
30 class Command;
31 
32 // Thread to execute create and release patch commands asynchronously. This is needed because
33 // IAfPatchPanel::createAudioPatch and releaseAudioPatch are executed from audio policy service
34 // with mutex locked and effect management requires to call back into audio policy service
35 class PatchCommandThread : public Thread {
36 public:
37 
38     enum {
39         CREATE_AUDIO_PATCH,
40         RELEASE_AUDIO_PATCH,
41         UPDATE_AUDIO_PATCH,
42     };
43 
44     class PatchCommandListener : public virtual RefBase {
45     public:
46         virtual void onCreateAudioPatch(audio_patch_handle_t handle,
47                                         const IAfPatchPanel::Patch& patch) = 0;
48         virtual void onReleaseAudioPatch(audio_patch_handle_t handle) = 0;
49         virtual void onUpdateAudioPatch(audio_patch_handle_t oldHandle,
50                                         audio_patch_handle_t newHandle,
51                                         const IAfPatchPanel::Patch& patch) = 0;
52     };
53 
PatchCommandThread()54     PatchCommandThread() : Thread(false /* canCallJava */) {}
55     ~PatchCommandThread() override;
56 
57     void addListener(const sp<PatchCommandListener>& listener)
58             EXCLUDES_PatchCommandThread_ListenerMutex;
59 
60     void createAudioPatch(audio_patch_handle_t handle, const IAfPatchPanel::Patch& patch)
61             EXCLUDES_PatchCommandThread_Mutex;
62     void releaseAudioPatch(audio_patch_handle_t handle) EXCLUDES_PatchCommandThread_Mutex;
63     void updateAudioPatch(audio_patch_handle_t oldHandle, audio_patch_handle_t newHandle,
64             const IAfPatchPanel::Patch& patch) EXCLUDES_PatchCommandThread_Mutex;
65 
66     // Thread virtuals
67     void onFirstRef() override;
68     bool threadLoop() override;
69 
70     void exit();
71 
72     void createAudioPatchCommand(audio_patch_handle_t handle,
73             const IAfPatchPanel::Patch& patch) EXCLUDES_PatchCommandThread_Mutex;
74     void releaseAudioPatchCommand(audio_patch_handle_t handle) EXCLUDES_PatchCommandThread_Mutex;
75     void updateAudioPatchCommand(audio_patch_handle_t oldHandle, audio_patch_handle_t newHandle,
76             const IAfPatchPanel::Patch& patch) EXCLUDES_PatchCommandThread_Mutex;
77 
78 private:
79     class CommandData;
80 
81     // Command type received from the PatchPanel
82     class Command: public RefBase {
83     public:
84         Command() = default;
Command(int command,const sp<CommandData> & data)85         Command(int command, const sp<CommandData>& data)
86             : mCommand(command), mData(data) {}
87 
88         const int mCommand = -1;
89         const sp<CommandData> mData;
90     };
91 
92     class CommandData: public RefBase {};
93 
94     class CreateAudioPatchData : public CommandData {
95     public:
CreateAudioPatchData(audio_patch_handle_t handle,const IAfPatchPanel::Patch & patch)96         CreateAudioPatchData(audio_patch_handle_t handle, const IAfPatchPanel::Patch& patch)
97             :   mHandle(handle), mPatch(patch) {}
98 
99         const audio_patch_handle_t mHandle;
100         const IAfPatchPanel::Patch mPatch;
101     };
102 
103     class ReleaseAudioPatchData : public CommandData {
104     public:
ReleaseAudioPatchData(audio_patch_handle_t handle)105         explicit ReleaseAudioPatchData(audio_patch_handle_t handle)
106             :   mHandle(handle) {}
107 
108         audio_patch_handle_t mHandle;
109     };
110 
111     class UpdateAudioPatchData : public CommandData {
112     public:
UpdateAudioPatchData(audio_patch_handle_t oldHandle,audio_patch_handle_t newHandle,const IAfPatchPanel::Patch & patch)113         UpdateAudioPatchData(audio_patch_handle_t oldHandle,
114                              audio_patch_handle_t newHandle,
115                              const IAfPatchPanel::Patch& patch)
116             :   mOldHandle(oldHandle), mNewHandle(newHandle), mPatch(patch) {}
117 
118         const audio_patch_handle_t mOldHandle;
119         const audio_patch_handle_t mNewHandle;
120         const IAfPatchPanel::Patch mPatch;
121     };
122 
123     void sendCommand(const sp<Command>& command) EXCLUDES_PatchCommandThread_Mutex;
124 
mutex()125     audio_utils::mutex& mutex() const RETURN_CAPABILITY(audio_utils::PatchCommandThread_Mutex) {
126         return mMutex;
127     }
listenerMutex()128     audio_utils::mutex& listenerMutex() const
129             RETURN_CAPABILITY(audio_utils::PatchCommandThread_ListenerMutex) {
130         return mListenerMutex;
131     }
132 
133     mutable audio_utils::mutex mMutex{audio_utils::MutexOrder::kPatchCommandThread_Mutex};
134     audio_utils::condition_variable mWaitWorkCV;
135     std::deque<sp<Command>> mCommands GUARDED_BY(mutex()); // list of pending commands
136 
137     mutable audio_utils::mutex mListenerMutex{
138             audio_utils::MutexOrder::kPatchCommandThread_ListenerMutex};
139     std::vector<wp<PatchCommandListener>> mListeners GUARDED_BY(listenerMutex());
140 };
141 
142 }  // namespace android
143