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 #define LOG_TAG "AudioFlinger::PatchCommandThread"
19 //#define LOG_NDEBUG 0
20 
21 #include "PatchCommandThread.h"
22 
23 #include <utils/Log.h>
24 
25 namespace android {
26 
27 constexpr char kPatchCommandThreadName[] = "AudioFlinger_PatchCommandThread";
28 
~PatchCommandThread()29 PatchCommandThread::~PatchCommandThread() {
30     exit();
31 
32     audio_utils::lock_guard _l(mutex());
33     mCommands.clear();
34 }
35 
onFirstRef()36 void PatchCommandThread::onFirstRef() {
37     run(kPatchCommandThreadName, ANDROID_PRIORITY_AUDIO);
38 }
39 
addListener(const sp<PatchCommandListener> & listener)40 void PatchCommandThread::addListener(const sp<PatchCommandListener>& listener) {
41     ALOGV("%s add listener %p", __func__, static_cast<void*>(listener.get()));
42     audio_utils::lock_guard _l(listenerMutex());
43     mListeners.emplace_back(listener);
44 }
45 
createAudioPatch(audio_patch_handle_t handle,const IAfPatchPanel::Patch & patch)46 void PatchCommandThread::createAudioPatch(audio_patch_handle_t handle,
47         const IAfPatchPanel::Patch& patch) {
48     ALOGV("%s handle %d mHalHandle %d num sinks %d device sink %08x",
49             __func__, handle, patch.mHalHandle,
50             patch.mAudioPatch.num_sinks,
51             patch.mAudioPatch.num_sinks > 0 ? patch.mAudioPatch.sinks[0].ext.device.type : 0);
52 
53     createAudioPatchCommand(handle, patch);
54 }
55 
releaseAudioPatch(audio_patch_handle_t handle)56 void PatchCommandThread::releaseAudioPatch(audio_patch_handle_t handle) {
57     ALOGV("%s", __func__);
58     releaseAudioPatchCommand(handle);
59 }
60 
updateAudioPatch(audio_patch_handle_t oldHandle,audio_patch_handle_t newHandle,const IAfPatchPanel::Patch & patch)61 void PatchCommandThread::updateAudioPatch(audio_patch_handle_t oldHandle,
62         audio_patch_handle_t newHandle, const IAfPatchPanel::Patch& patch) {
63     ALOGV("%s handle %d mHalHandle %d num sinks %d device sink %08x",
64             __func__, oldHandle, patch.mHalHandle,
65             patch.mAudioPatch.num_sinks,
66             patch.mAudioPatch.num_sinks > 0 ? patch.mAudioPatch.sinks[0].ext.device.type : 0);
67 
68     updateAudioPatchCommand(oldHandle, newHandle, patch);
69 }
70 
threadLoop()71 bool PatchCommandThread::threadLoop()
72 {
73     audio_utils::unique_lock _l(mutex());
74 
75     while (!exitPending()) {
76         while (!mCommands.empty() && !exitPending()) {
77             const sp<Command> command = mCommands.front();
78             mCommands.pop_front();
79             _l.unlock();
80 
81             std::vector<wp<PatchCommandListener>> listenersCopy;
82             {
83                 audio_utils::lock_guard _ll(listenerMutex());
84                 listenersCopy = mListeners;
85             }
86 
87             switch (command->mCommand) {
88                 case CREATE_AUDIO_PATCH: {
89                     const auto data = (CreateAudioPatchData*) command->mData.get();
90                     ALOGV("%s processing create audio patch handle %d",
91                           __func__,
92                           data->mHandle);
93 
94                     for (const auto& listener : listenersCopy) {
95                         auto spListener = listener.promote();
96                         if (spListener) {
97                             spListener->onCreateAudioPatch(data->mHandle, data->mPatch);
98                         }
99                     }
100                 }
101                     break;
102                 case RELEASE_AUDIO_PATCH: {
103                     const auto data = (ReleaseAudioPatchData*) command->mData.get();
104                     ALOGV("%s processing release audio patch handle %d",
105                           __func__,
106                           data->mHandle);
107 
108                     for (const auto& listener : listenersCopy) {
109                         auto spListener = listener.promote();
110                         if (spListener) {
111                             spListener->onReleaseAudioPatch(data->mHandle);
112                         }
113                     }
114                 }
115                     break;
116                 case UPDATE_AUDIO_PATCH: {
117                     const auto data = (UpdateAudioPatchData*) command->mData.get();
118                     ALOGV("%s processing update audio patch old handle %d new handle %d",
119                           __func__,
120                           data->mOldHandle, data->mNewHandle);
121 
122                     for (const auto& listener : listenersCopy) {
123                         auto spListener = listener.promote();
124                         if (spListener) {
125                             spListener->onUpdateAudioPatch(data->mOldHandle,
126                                     data->mNewHandle, data->mPatch);
127                         }
128                     }
129                 }
130                     break;
131                 default:
132                     ALOGW("%s unknown command %d", __func__, command->mCommand);
133                     break;
134             }
135             _l.lock();
136         }
137 
138         // At this stage we have either an empty command queue or the first command in the queue
139         // has a finite delay. So unless we are exiting it is safe to wait.
140         if (!exitPending()) {
141             ALOGV("%s going to sleep", __func__);
142             mWaitWorkCV.wait(_l);
143         }
144     }
145     return false;
146 }
147 
sendCommand(const sp<Command> & command)148 void PatchCommandThread::sendCommand(const sp<Command>& command) {
149     audio_utils::lock_guard _l(mutex());
150     mCommands.emplace_back(command);
151     mWaitWorkCV.notify_one();
152 }
153 
createAudioPatchCommand(audio_patch_handle_t handle,const IAfPatchPanel::Patch & patch)154 void PatchCommandThread::createAudioPatchCommand(
155         audio_patch_handle_t handle, const IAfPatchPanel::Patch& patch) {
156     auto command = sp<Command>::make(CREATE_AUDIO_PATCH,
157                                      new CreateAudioPatchData(handle, patch));
158     ALOGV("%s adding create patch handle %d mHalHandle %d.",
159           __func__,
160           handle,
161           patch.mHalHandle);
162     sendCommand(command);
163 }
164 
releaseAudioPatchCommand(audio_patch_handle_t handle)165 void PatchCommandThread::releaseAudioPatchCommand(audio_patch_handle_t handle) {
166     sp<Command> command =
167         sp<Command>::make(RELEASE_AUDIO_PATCH, new ReleaseAudioPatchData(handle));
168     ALOGV("%s adding release patch", __func__);
169     sendCommand(command);
170 }
171 
updateAudioPatchCommand(audio_patch_handle_t oldHandle,audio_patch_handle_t newHandle,const IAfPatchPanel::Patch & patch)172 void PatchCommandThread::updateAudioPatchCommand(
173         audio_patch_handle_t oldHandle, audio_patch_handle_t newHandle,
174         const IAfPatchPanel::Patch& patch) {
175     sp<Command> command = sp<Command>::make(UPDATE_AUDIO_PATCH,
176                                            new UpdateAudioPatchData(oldHandle, newHandle, patch));
177     ALOGV("%s adding update patch old handle %d new handle %d mHalHandle %d.",
178             __func__, oldHandle, newHandle, patch.mHalHandle);
179     sendCommand(command);
180 }
181 
exit()182 void PatchCommandThread::exit() {
183     ALOGV("%s", __func__);
184     {
185         audio_utils::lock_guard _l(mutex());
186         requestExit();
187         mWaitWorkCV.notify_one();
188     }
189     // Note that we can call it from the thread loop if all other references have been released
190     // but it will safely return WOULD_BLOCK in this case
191     requestExitAndWait();
192 }
193 
194 }  // namespace android
195